[PATCH] net/ipv6: Convert from atomic_t to refcount_t on ip6_flowlabel->users

Xiyu Yang xiyuyang19 at fudan.edu.cn
Mon Jul 19 01:35:06 PDT 2021


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 at fudan.edu.cn>
Signed-off-by: Xin Tan <tanxin.ctf at gmail.com>
---
 include/net/ipv6.h       |  5 +++--
 net/ipv6/ip6_flowlabel.c | 18 +++++++++---------
 2 files changed, 12 insertions(+), 11 deletions(-)

diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index f2d0ecc257bb..de9ba310c7be 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -9,6 +9,7 @@
 #ifndef _NET_IPV6_H
 #define _NET_IPV6_H
 
+#include <linux/refcount.h>
 #include <linux/ipv6.h>
 #include <linux/hardirq.h>
 #include <linux/jhash.h>
@@ -313,7 +314,7 @@ enum flowlabel_reflect {
 struct ip6_flowlabel {
 	struct ip6_flowlabel __rcu *next;
 	__be32			label;
-	atomic_t		users;
+	refcount_t		users;
 	struct in6_addr		dst;
 	struct ipv6_txoptions	*opt;
 	unsigned long		linger;
@@ -417,7 +418,7 @@ bool ip6_autoflowlabel(struct net *net, const struct ipv6_pinfo *np);
 static inline void fl6_sock_release(struct ip6_flowlabel *fl)
 {
 	if (fl)
-		atomic_dec(&fl->users);
+		refcount_dec(&fl->users);
 }
 
 void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info);
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c
index aa673a6a7e43..d0a7f099fedb 100644
--- a/net/ipv6/ip6_flowlabel.c
+++ b/net/ipv6/ip6_flowlabel.c
@@ -88,7 +88,7 @@ static struct ip6_flowlabel *fl_lookup(struct net *net, __be32 label)
 
 	rcu_read_lock_bh();
 	fl = __fl_lookup(net, label);
-	if (fl && !atomic_inc_not_zero(&fl->users))
+	if (fl && !refcount_inc_not_zero(&fl->users))
 		fl = NULL;
 	rcu_read_unlock_bh();
 	return fl;
@@ -128,7 +128,7 @@ static void fl_release(struct ip6_flowlabel *fl)
 	spin_lock_bh(&ip6_fl_lock);
 
 	fl->lastuse = jiffies;
-	if (atomic_dec_and_test(&fl->users)) {
+	if (refcount_dec_and_test(&fl->users)) {
 		unsigned long ttd = fl->lastuse + fl->linger;
 		if (time_after(ttd, fl->expires))
 			fl->expires = ttd;
@@ -160,7 +160,7 @@ static void ip6_fl_gc(struct timer_list *unused)
 		flp = &fl_ht[i];
 		while ((fl = rcu_dereference_protected(*flp,
 						       lockdep_is_held(&ip6_fl_lock))) != NULL) {
-			if (atomic_read(&fl->users) == 0) {
+			if (refcount_read(&fl->users) == 0) {
 				unsigned long ttd = fl->lastuse + fl->linger;
 				if (time_after(ttd, fl->expires))
 					fl->expires = ttd;
@@ -198,7 +198,7 @@ static void __net_exit ip6_fl_purge(struct net *net)
 		while ((fl = rcu_dereference_protected(*flp,
 						       lockdep_is_held(&ip6_fl_lock))) != NULL) {
 			if (net_eq(fl->fl_net, net) &&
-			    atomic_read(&fl->users) == 0) {
+			    refcount_read(&fl->users) == 0) {
 				*flp = fl->next;
 				fl_free(fl);
 				atomic_dec(&fl_size);
@@ -238,7 +238,7 @@ static struct ip6_flowlabel *fl_intern(struct net *net,
 		 */
 		lfl = __fl_lookup(net, fl->label);
 		if (lfl) {
-			atomic_inc(&lfl->users);
+			refcount_inc(&lfl->users);
 			spin_unlock_bh(&ip6_fl_lock);
 			return lfl;
 		}
@@ -267,7 +267,7 @@ struct ip6_flowlabel *__fl6_sock_lookup(struct sock *sk, __be32 label)
 	for_each_sk_fl_rcu(np, sfl) {
 		struct ip6_flowlabel *fl = sfl->fl;
 
-		if (fl->label == label && atomic_inc_not_zero(&fl->users)) {
+		if (fl->label == label && refcount_inc_not_zero(&fl->users)) {
 			fl->lastuse = jiffies;
 			rcu_read_unlock_bh();
 			return fl;
@@ -435,7 +435,7 @@ fl_create(struct net *net, struct sock *sk, struct in6_flowlabel_req *freq,
 		goto done;
 	}
 	fl->dst = freq->flr_dst;
-	atomic_set(&fl->users, 1);
+	refcount_set(&fl->users, 1);
 	switch (fl->share) {
 	case IPV6_FL_S_EXCL:
 	case IPV6_FL_S_ANY:
@@ -647,7 +647,7 @@ static int ipv6_flowlabel_get(struct sock *sk, struct in6_flowlabel_req *freq,
 					goto done;
 				}
 				fl1 = sfl->fl;
-				if (!atomic_inc_not_zero(&fl1->users))
+				if (!refcount_inc_not_zero(&fl1->users))
 					fl1 = NULL;
 				break;
 			}
@@ -845,7 +845,7 @@ static int ip6fl_seq_show(struct seq_file *seq, void *v)
 			    ((fl->share == IPV6_FL_S_USER) ?
 			     from_kuid_munged(seq_user_ns(seq), fl->owner.uid) :
 			     0)),
-			   atomic_read(&fl->users),
+			   refcount_read(&fl->users),
 			   fl->linger/HZ,
 			   (long)(fl->expires - jiffies)/HZ,
 			   &fl->dst,
-- 
2.7.4




More information about the linux-arm-kernel mailing list