lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <1626517014-42631-1-git-send-email-xiyuyang19@fudan.edu.cn>
Date:   Sat, 17 Jul 2021 18:16:54 +0800
From:   Xiyu Yang <xiyuyang19@...an.edu.cn>
To:     Raju Rangoju <rajur@...lsio.com>,
        "David S. Miller" <davem@...emloft.net>,
        Jakub Kicinski <kuba@...nel.org>, netdev@...r.kernel.org,
        linux-kernel@...r.kernel.org
Cc:     yuanxzhang@...an.edu.cn, Xiyu Yang <xiyuyang19@...an.edu.cn>,
        Xin Tan <tanxin.ctf@...il.com>
Subject: [PATCH] cxgb4: Convert from atomic_t to refcount_t on l2t_entry->refcnt

refcount_t type and corresponding API can protect refcounters from
accidental underflow and overflow and further use-after-free situations.

Signed-off-by: Xiyu Yang <xiyuyang19@...an.edu.cn>
Signed-off-by: Xin Tan <tanxin.ctf@...il.com>
---
 drivers/net/ethernet/chelsio/cxgb4/l2t.c | 31 ++++++++++++++++---------------
 drivers/net/ethernet/chelsio/cxgb4/l2t.h |  3 ++-
 2 files changed, 18 insertions(+), 16 deletions(-)

diff --git a/drivers/net/ethernet/chelsio/cxgb4/l2t.c b/drivers/net/ethernet/chelsio/cxgb4/l2t.c
index a10a6862a9a4..cb26a5e315b1 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/l2t.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/l2t.c
@@ -69,7 +69,8 @@ static inline unsigned int vlan_prio(const struct l2t_entry *e)
 
 static inline void l2t_hold(struct l2t_data *d, struct l2t_entry *e)
 {
-	if (atomic_add_return(1, &e->refcnt) == 1)  /* 0 -> 1 transition */
+	refcount_inc(&e->refcnt);
+	if (refcount_read(&e->refcnt) == 1)  /* 0 -> 1 transition */
 		atomic_dec(&d->nfree);
 }
 
@@ -270,10 +271,10 @@ static struct l2t_entry *alloc_l2e(struct l2t_data *d)
 
 	/* there's definitely a free entry */
 	for (e = d->rover, end = &d->l2tab[d->l2t_size]; e != end; ++e)
-		if (atomic_read(&e->refcnt) == 0)
+		if (refcount_read(&e->refcnt) == 0)
 			goto found;
 
-	for (e = d->l2tab; atomic_read(&e->refcnt); ++e)
+	for (e = d->l2tab; refcount_read(&e->refcnt); ++e)
 		;
 found:
 	d->rover = e + 1;
@@ -302,7 +303,7 @@ static struct l2t_entry *find_or_alloc_l2e(struct l2t_data *d, u16 vlan,
 	struct l2t_entry *first_free = NULL;
 
 	for (e = &d->l2tab[0], end = &d->l2tab[d->l2t_size]; e != end; ++e) {
-		if (atomic_read(&e->refcnt) == 0) {
+		if (refcount_read(&e->refcnt) == 0) {
 			if (!first_free)
 				first_free = e;
 		} else {
@@ -352,7 +353,7 @@ static void _t4_l2e_free(struct l2t_entry *e)
 {
 	struct l2t_data *d;
 
-	if (atomic_read(&e->refcnt) == 0) {  /* hasn't been recycled */
+	if (refcount_read(&e->refcnt) == 0) {  /* hasn't been recycled */
 		if (e->neigh) {
 			neigh_release(e->neigh);
 			e->neigh = NULL;
@@ -370,7 +371,7 @@ static void t4_l2e_free(struct l2t_entry *e)
 	struct l2t_data *d;
 
 	spin_lock_bh(&e->lock);
-	if (atomic_read(&e->refcnt) == 0) {  /* hasn't been recycled */
+	if (refcount_read(&e->refcnt) == 0) {  /* hasn't been recycled */
 		if (e->neigh) {
 			neigh_release(e->neigh);
 			e->neigh = NULL;
@@ -385,7 +386,7 @@ static void t4_l2e_free(struct l2t_entry *e)
 
 void cxgb4_l2t_release(struct l2t_entry *e)
 {
-	if (atomic_dec_and_test(&e->refcnt))
+	if (refcount_dec_and_test(&e->refcnt))
 		t4_l2e_free(e);
 }
 EXPORT_SYMBOL(cxgb4_l2t_release);
@@ -441,7 +442,7 @@ struct l2t_entry *cxgb4_l2t_get(struct l2t_data *d, struct neighbour *neigh,
 		if (!addreq(e, addr) && e->ifindex == ifidx &&
 		    e->vlan == vlan && e->lport == lport) {
 			l2t_hold(d, e);
-			if (atomic_read(&e->refcnt) == 1)
+			if (refcount_read(&e->refcnt) == 1)
 				reuse_entry(e, neigh);
 			goto done;
 		}
@@ -458,7 +459,7 @@ struct l2t_entry *cxgb4_l2t_get(struct l2t_data *d, struct neighbour *neigh,
 		e->hash = hash;
 		e->lport = lport;
 		e->v6 = addr_len == 16;
-		atomic_set(&e->refcnt, 1);
+		refcount_set(&e->refcnt, 1);
 		neigh_replace(e, neigh);
 		e->vlan = vlan;
 		e->next = d->l2tab[hash].first;
@@ -520,7 +521,7 @@ void t4_l2t_update(struct adapter *adap, struct neighbour *neigh)
 	for (e = d->l2tab[hash].first; e; e = e->next)
 		if (!addreq(e, addr) && e->ifindex == ifidx) {
 			spin_lock(&e->lock);
-			if (atomic_read(&e->refcnt))
+			if (refcount_read(&e->refcnt))
 				goto found;
 			spin_unlock(&e->lock);
 			break;
@@ -585,12 +586,12 @@ struct l2t_entry *t4_l2t_alloc_switching(struct adapter *adap, u16 vlan,
 	e = find_or_alloc_l2e(d, vlan, port, eth_addr);
 	if (e) {
 		spin_lock(&e->lock);          /* avoid race with t4_l2t_free */
-		if (!atomic_read(&e->refcnt)) {
+		if (!refcount_read(&e->refcnt)) {
 			e->state = L2T_STATE_SWITCHING;
 			e->vlan = vlan;
 			e->lport = port;
 			ether_addr_copy(e->dmac, eth_addr);
-			atomic_set(&e->refcnt, 1);
+			refcount_set(&e->refcnt, 1);
 			ret = write_l2e(adap, e, 0);
 			if (ret < 0) {
 				_t4_l2e_free(e);
@@ -599,7 +600,7 @@ struct l2t_entry *t4_l2t_alloc_switching(struct adapter *adap, u16 vlan,
 				return NULL;
 			}
 		} else {
-			atomic_inc(&e->refcnt);
+			refcount_inc(&e->refcnt);
 		}
 
 		spin_unlock(&e->lock);
@@ -654,7 +655,7 @@ struct l2t_data *t4_init_l2t(unsigned int l2t_start, unsigned int l2t_end)
 		d->l2tab[i].idx = i;
 		d->l2tab[i].state = L2T_STATE_UNUSED;
 		spin_lock_init(&d->l2tab[i].lock);
-		atomic_set(&d->l2tab[i].refcnt, 0);
+		refcount_set(&d->l2tab[i].refcnt, 0);
 		skb_queue_head_init(&d->l2tab[i].arpq);
 	}
 	return d;
@@ -726,7 +727,7 @@ static int l2t_seq_show(struct seq_file *seq, void *v)
 		seq_printf(seq, "%4u %-25s %17pM %4d %u %2u   %c   %5u %s\n",
 			   e->idx + d->l2t_start, ip, e->dmac,
 			   e->vlan & VLAN_VID_MASK, vlan_prio(e), e->lport,
-			   l2e_state(e), atomic_read(&e->refcnt),
+			   l2e_state(e), refcount_read(&e->refcnt),
 			   e->neigh ? e->neigh->dev->name : "");
 		spin_unlock_bh(&e->lock);
 	}
diff --git a/drivers/net/ethernet/chelsio/cxgb4/l2t.h b/drivers/net/ethernet/chelsio/cxgb4/l2t.h
index 340fecb28a13..6914a0e9836b 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/l2t.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/l2t.h
@@ -38,6 +38,7 @@
 #include <linux/spinlock.h>
 #include <linux/if_ether.h>
 #include <linux/atomic.h>
+#include <linux/refcount.h>
 
 #define VLAN_NONE 0xfff
 
@@ -80,7 +81,7 @@ struct l2t_entry {
 	struct l2t_entry *next;     /* next l2t_entry on chain */
 	struct sk_buff_head arpq;   /* packet queue awaiting resolution */
 	spinlock_t lock;
-	atomic_t refcnt;            /* entry reference count */
+	refcount_t refcnt;            /* entry reference count */
 	u16 hash;                   /* hash bucket the entry is on */
 	u16 vlan;                   /* VLAN TCI (id: bits 0-11, prio: 13-15 */
 	u8 v6;                      /* whether entry is for IPv6 */
-- 
2.7.4

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ