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