|
Michal Kubecek |
ee14e7 |
From: "Reshetova, Elena" <elena.reshetova@intel.com>
|
|
Michal Kubecek |
ee14e7 |
Date: Fri, 30 Jun 2017 13:07:54 +0300
|
|
Michal Kubecek |
ee14e7 |
Subject: net: convert inet_peer.refcnt from atomic_t to refcount_t
|
|
Michal Kubecek |
ee14e7 |
Patch-mainline: v4.13-rc1
|
|
Michal Kubecek |
ee14e7 |
Git-commit: 1cc9a98b59ba92fece1277f76aa43e05f34936a6
|
|
Michal Kubecek |
ee14e7 |
References: bsc#1061739
|
|
Michal Kubecek |
ee14e7 |
|
|
Michal Kubecek |
ee14e7 |
refcount_t type and corresponding API should be
|
|
Michal Kubecek |
ee14e7 |
used instead of atomic_t when the variable is used as
|
|
Michal Kubecek |
ee14e7 |
a reference counter. This allows to avoid accidental
|
|
Michal Kubecek |
ee14e7 |
refcounter overflows that might lead to use-after-free
|
|
Michal Kubecek |
ee14e7 |
situations.
|
|
Michal Kubecek |
ee14e7 |
This conversion requires overall +1 on the whole
|
|
Michal Kubecek |
ee14e7 |
refcounting scheme.
|
|
Michal Kubecek |
ee14e7 |
|
|
Michal Kubecek |
ee14e7 |
Signed-off-by: Elena Reshetova <elena.reshetova@intel.com>
|
|
Michal Kubecek |
ee14e7 |
Signed-off-by: Hans Liljestrand <ishkamiel@gmail.com>
|
|
Michal Kubecek |
ee14e7 |
Signed-off-by: Kees Cook <keescook@chromium.org>
|
|
Michal Kubecek |
ee14e7 |
Signed-off-by: David Windsor <dwindsor@gmail.com>
|
|
Michal Kubecek |
ee14e7 |
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
Michal Kubecek |
ee14e7 |
Acked-by: Michal Kubecek <mkubecek@suse.cz>
|
|
Michal Kubecek |
ee14e7 |
|
|
Michal Kubecek |
ee14e7 |
---
|
|
Michal Kubecek |
ee14e7 |
include/net/inetpeer.h | 4 ++--
|
|
Michal Kubecek |
ee14e7 |
net/ipv4/inetpeer.c | 18 +++++++++---------
|
|
Michal Kubecek |
ee14e7 |
2 files changed, 11 insertions(+), 11 deletions(-)
|
|
Michal Kubecek |
ee14e7 |
|
|
Michal Kubecek |
ee14e7 |
diff --git a/include/net/inetpeer.h b/include/net/inetpeer.h
|
|
Michal Kubecek |
ee14e7 |
index 235c7811a86a..f2a215fc78e4 100644
|
|
Michal Kubecek |
ee14e7 |
--- a/include/net/inetpeer.h
|
|
Michal Kubecek |
ee14e7 |
+++ b/include/net/inetpeer.h
|
|
Michal Kubecek |
ee14e7 |
@@ -46,7 +46,7 @@ struct inet_peer {
|
|
Michal Kubecek |
ee14e7 |
struct rcu_head gc_rcu;
|
|
Michal Kubecek |
ee14e7 |
};
|
|
Michal Kubecek |
ee14e7 |
/*
|
|
Michal Kubecek |
ee14e7 |
- * Once inet_peer is queued for deletion (refcnt == -1), following field
|
|
Michal Kubecek |
ee14e7 |
+ * Once inet_peer is queued for deletion (refcnt == 0), following field
|
|
Michal Kubecek |
ee14e7 |
* is not available: rid
|
|
Michal Kubecek |
ee14e7 |
* We can share memory with rcu_head to help keep inet_peer small.
|
|
Michal Kubecek |
ee14e7 |
*/
|
|
Michal Kubecek |
ee14e7 |
@@ -60,7 +60,7 @@ struct inet_peer {
|
|
Michal Kubecek |
ee14e7 |
|
|
Michal Kubecek |
ee14e7 |
/* following fields might be frequently dirtied */
|
|
Michal Kubecek |
ee14e7 |
__u32 dtime; /* the time of last use of not referenced entries */
|
|
Michal Kubecek |
ee14e7 |
- atomic_t refcnt;
|
|
Michal Kubecek |
ee14e7 |
+ refcount_t refcnt;
|
|
Michal Kubecek |
ee14e7 |
};
|
|
Michal Kubecek |
ee14e7 |
|
|
Michal Kubecek |
ee14e7 |
struct inet_peer_base {
|
|
Michal Kubecek |
ee14e7 |
diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c
|
|
Michal Kubecek |
ee14e7 |
index 86fa45809540..c5a117cc6619 100644
|
|
Michal Kubecek |
ee14e7 |
--- a/net/ipv4/inetpeer.c
|
|
Michal Kubecek |
ee14e7 |
+++ b/net/ipv4/inetpeer.c
|
|
Michal Kubecek |
ee14e7 |
@@ -115,7 +115,7 @@ static void inetpeer_gc_worker(struct work_struct *work)
|
|
Michal Kubecek |
ee14e7 |
|
|
Michal Kubecek |
ee14e7 |
n = list_entry(p->gc_list.next, struct inet_peer, gc_list);
|
|
Michal Kubecek |
ee14e7 |
|
|
Michal Kubecek |
ee14e7 |
- if (!atomic_read(&p->refcnt)) {
|
|
Michal Kubecek |
ee14e7 |
+ if (refcount_read(&p->refcnt) == 1) {
|
|
Michal Kubecek |
ee14e7 |
list_del(&p->gc_list);
|
|
Michal Kubecek |
ee14e7 |
kmem_cache_free(peer_cachep, p);
|
|
Michal Kubecek |
ee14e7 |
}
|
|
Michal Kubecek |
ee14e7 |
@@ -202,10 +202,11 @@ static struct inet_peer *lookup_rcu(const struct inetpeer_addr *daddr,
|
|
Michal Kubecek |
ee14e7 |
int cmp = inetpeer_addr_cmp(daddr, &u->daddr);
|
|
Michal Kubecek |
ee14e7 |
if (cmp == 0) {
|
|
Michal Kubecek |
ee14e7 |
/* Before taking a reference, check if this entry was
|
|
Michal Kubecek |
ee14e7 |
- * deleted (refcnt=-1)
|
|
Michal Kubecek |
ee14e7 |
+ * deleted (refcnt=0)
|
|
Michal Kubecek |
ee14e7 |
*/
|
|
Michal Kubecek |
ee14e7 |
- if (!atomic_add_unless(&u->refcnt, 1, -1))
|
|
Michal Kubecek |
ee14e7 |
+ if (!refcount_inc_not_zero(&u->refcnt)) {
|
|
Michal Kubecek |
ee14e7 |
u = NULL;
|
|
Michal Kubecek |
ee14e7 |
+ }
|
|
Michal Kubecek |
ee14e7 |
return u;
|
|
Michal Kubecek |
ee14e7 |
}
|
|
Michal Kubecek |
ee14e7 |
if (cmp == -1)
|
|
Michal Kubecek |
ee14e7 |
@@ -382,11 +383,10 @@ static int inet_peer_gc(struct inet_peer_base *base,
|
|
Michal Kubecek |
ee14e7 |
while (stackptr > stack) {
|
|
Michal Kubecek |
ee14e7 |
stackptr--;
|
|
Michal Kubecek |
ee14e7 |
p = rcu_deref_locked(**stackptr, base);
|
|
Michal Kubecek |
ee14e7 |
- if (atomic_read(&p->refcnt) == 0) {
|
|
Michal Kubecek |
ee14e7 |
+ if (refcount_read(&p->refcnt) == 1) {
|
|
Michal Kubecek |
ee14e7 |
smp_rmb();
|
|
Michal Kubecek |
ee14e7 |
delta = (__u32)jiffies - p->dtime;
|
|
Michal Kubecek |
ee14e7 |
- if (delta >= ttl &&
|
|
Michal Kubecek |
ee14e7 |
- atomic_cmpxchg(&p->refcnt, 0, -1) == 0) {
|
|
Michal Kubecek |
ee14e7 |
+ if (delta >= ttl && refcount_dec_if_one(&p->refcnt)) {
|
|
Michal Kubecek |
ee14e7 |
p->gc_next = gchead;
|
|
Michal Kubecek |
ee14e7 |
gchead = p;
|
|
Michal Kubecek |
ee14e7 |
}
|
|
Michal Kubecek |
ee14e7 |
@@ -432,7 +432,7 @@ struct inet_peer *inet_getpeer(struct inet_peer_base *base,
|
|
Michal Kubecek |
ee14e7 |
relookup:
|
|
Michal Kubecek |
ee14e7 |
p = lookup(daddr, stack, base);
|
|
Michal Kubecek |
ee14e7 |
if (p != peer_avl_empty) {
|
|
Michal Kubecek |
ee14e7 |
- atomic_inc(&p->refcnt);
|
|
Michal Kubecek |
ee14e7 |
+ refcount_inc(&p->refcnt);
|
|
Michal Kubecek |
ee14e7 |
write_sequnlock_bh(&base->lock);
|
|
Michal Kubecek |
ee14e7 |
return p;
|
|
Michal Kubecek |
ee14e7 |
}
|
|
Michal Kubecek |
ee14e7 |
@@ -444,7 +444,7 @@ struct inet_peer *inet_getpeer(struct inet_peer_base *base,
|
|
Michal Kubecek |
ee14e7 |
p = create ? kmem_cache_alloc(peer_cachep, GFP_ATOMIC) : NULL;
|
|
Michal Kubecek |
ee14e7 |
if (p) {
|
|
Michal Kubecek |
ee14e7 |
p->daddr = *daddr;
|
|
Michal Kubecek |
ee14e7 |
- atomic_set(&p->refcnt, 1);
|
|
Michal Kubecek |
ee14e7 |
+ refcount_set(&p->refcnt, 2);
|
|
Michal Kubecek |
ee14e7 |
atomic_set(&p->rid, 0);
|
|
Michal Kubecek |
ee14e7 |
p->metrics[RTAX_LOCK-1] = INETPEER_METRICS_NEW;
|
|
Michal Kubecek |
ee14e7 |
p->rate_tokens = 0;
|
|
Michal Kubecek |
ee14e7 |
@@ -468,7 +468,7 @@ void inet_putpeer(struct inet_peer *p)
|
|
Michal Kubecek |
ee14e7 |
{
|
|
Michal Kubecek |
ee14e7 |
p->dtime = (__u32)jiffies;
|
|
Michal Kubecek |
ee14e7 |
smp_mb__before_atomic();
|
|
Michal Kubecek |
ee14e7 |
- atomic_dec(&p->refcnt);
|
|
Michal Kubecek |
ee14e7 |
+ refcount_dec(&p->refcnt);
|
|
Michal Kubecek |
ee14e7 |
}
|
|
Michal Kubecek |
ee14e7 |
EXPORT_SYMBOL_GPL(inet_putpeer);
|
|
Michal Kubecek |
ee14e7 |
|
|
Michal Kubecek |
ee14e7 |
--
|
|
Michal Kubecek |
ee14e7 |
2.14.2
|
|
Michal Kubecek |
ee14e7 |
|