Skip to content

Commit 7b93640

Browse files
ereshetovadavem330
authored andcommitted
net, sched: convert Qdisc.refcnt from atomic_t to refcount_t
refcount_t type and corresponding API should be used instead of atomic_t when the variable is used as a reference counter. This allows to avoid accidental refcounter overflows that might lead to use-after-free situations. Signed-off-by: Elena Reshetova <elena.reshetova@intel.com> Signed-off-by: Hans Liljestrand <ishkamiel@gmail.com> Signed-off-by: Kees Cook <keescook@chromium.org> Signed-off-by: David Windsor <dwindsor@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent edcd927 commit 7b93640

File tree

3 files changed

+10
-9
lines changed

3 files changed

+10
-9
lines changed

include/net/sch_generic.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <linux/percpu.h>
1010
#include <linux/dynamic_queue_limits.h>
1111
#include <linux/list.h>
12+
#include <linux/refcount.h>
1213
#include <net/gen_stats.h>
1314
#include <net/rtnetlink.h>
1415

@@ -95,7 +96,7 @@ struct Qdisc {
9596
struct sk_buff *skb_bad_txq;
9697
struct rcu_head rcu_head;
9798
int padded;
98-
atomic_t refcnt;
99+
refcount_t refcnt;
99100

100101
spinlock_t busylock ____cacheline_aligned_in_smp;
101102
};

net/sched/sch_api.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -839,7 +839,7 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent,
839839

840840
old = dev_graft_qdisc(dev_queue, new);
841841
if (new && i > 0)
842-
atomic_inc(&new->refcnt);
842+
refcount_inc(&new->refcnt);
843843

844844
if (!ingress)
845845
qdisc_destroy(old);
@@ -850,7 +850,7 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent,
850850
notify_and_destroy(net, skb, n, classid,
851851
dev->qdisc, new);
852852
if (new && !new->ops->attach)
853-
atomic_inc(&new->refcnt);
853+
refcount_inc(&new->refcnt);
854854
dev->qdisc = new ? : &noop_qdisc;
855855

856856
if (new && new->ops->attach)
@@ -1259,7 +1259,7 @@ static int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n,
12591259
if (q == p ||
12601260
(p && check_loop(q, p, 0)))
12611261
return -ELOOP;
1262-
atomic_inc(&q->refcnt);
1262+
refcount_inc(&q->refcnt);
12631263
goto graft;
12641264
} else {
12651265
if (!q)
@@ -1374,7 +1374,7 @@ static int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid,
13741374
tcm->tcm_ifindex = qdisc_dev(q)->ifindex;
13751375
tcm->tcm_parent = clid;
13761376
tcm->tcm_handle = q->handle;
1377-
tcm->tcm_info = atomic_read(&q->refcnt);
1377+
tcm->tcm_info = refcount_read(&q->refcnt);
13781378
if (nla_put_string(skb, TCA_KIND, q->ops->id))
13791379
goto nla_put_failure;
13801380
if (q->ops->dump && q->ops->dump(q, skb) < 0)

net/sched/sch_generic.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -633,7 +633,7 @@ struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue,
633633
sch->dequeue = ops->dequeue;
634634
sch->dev_queue = dev_queue;
635635
dev_hold(dev);
636-
atomic_set(&sch->refcnt, 1);
636+
refcount_set(&sch->refcnt, 1);
637637

638638
return sch;
639639
errout:
@@ -701,7 +701,7 @@ void qdisc_destroy(struct Qdisc *qdisc)
701701
const struct Qdisc_ops *ops = qdisc->ops;
702702

703703
if (qdisc->flags & TCQ_F_BUILTIN ||
704-
!atomic_dec_and_test(&qdisc->refcnt))
704+
!refcount_dec_and_test(&qdisc->refcnt))
705705
return;
706706

707707
#ifdef CONFIG_NET_SCHED
@@ -739,7 +739,7 @@ struct Qdisc *dev_graft_qdisc(struct netdev_queue *dev_queue,
739739
spin_lock_bh(root_lock);
740740

741741
/* Prune old scheduler */
742-
if (oqdisc && atomic_read(&oqdisc->refcnt) <= 1)
742+
if (oqdisc && refcount_read(&oqdisc->refcnt) <= 1)
743743
qdisc_reset(oqdisc);
744744

745745
/* ... and graft new one */
@@ -785,7 +785,7 @@ static void attach_default_qdiscs(struct net_device *dev)
785785
dev->priv_flags & IFF_NO_QUEUE) {
786786
netdev_for_each_tx_queue(dev, attach_one_default_qdisc, NULL);
787787
dev->qdisc = txq->qdisc_sleeping;
788-
atomic_inc(&dev->qdisc->refcnt);
788+
refcount_inc(&dev->qdisc->refcnt);
789789
} else {
790790
qdisc = qdisc_create_dflt(txq, &mq_qdisc_ops, TC_H_ROOT);
791791
if (qdisc) {

0 commit comments

Comments
 (0)