[PATCH] net/ipv6: Convert from atomic_t to refcount_t on ip6_flowlabel->users
From: Xiyu Yang <hidden>
Date: 2021-07-19 08:38:02
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 <redacted> Signed-off-by: Xin Tan <redacted> --- 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
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel