net, sched: convert Qdisc.refcnt from atomic_t to refcount_t
authorReshetova, Elena <elena.reshetova@intel.com>
Tue, 4 Jul 2017 12:53:07 +0000 (15:53 +0300)
committerDavid S. Miller <davem@davemloft.net>
Tue, 4 Jul 2017 21:35:16 +0000 (22:35 +0100)
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>
include/net/sch_generic.h
net/sched/sch_api.c
net/sched/sch_generic.c

index 368850194c94bd751750c40194efd262f10015c0..1c123e2b2415797e7d32a0248df817cb9fbcb0c9 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/percpu.h>
 #include <linux/dynamic_queue_limits.h>
 #include <linux/list.h>
+#include <linux/refcount.h>
 #include <net/gen_stats.h>
 #include <net/rtnetlink.h>
 
@@ -95,7 +96,7 @@ struct Qdisc {
        struct sk_buff          *skb_bad_txq;
        struct rcu_head         rcu_head;
        int                     padded;
-       atomic_t                refcnt;
+       refcount_t              refcnt;
 
        spinlock_t              busylock ____cacheline_aligned_in_smp;
 };
index 43b94c7b69bdb0d25d10a79c05e789a2388888da..bd24a550e0f9f114598f4a398d6efd4c72672f50 100644 (file)
@@ -839,7 +839,7 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent,
 
                        old = dev_graft_qdisc(dev_queue, new);
                        if (new && i > 0)
-                               atomic_inc(&new->refcnt);
+                               refcount_inc(&new->refcnt);
 
                        if (!ingress)
                                qdisc_destroy(old);
@@ -850,7 +850,7 @@ skip:
                        notify_and_destroy(net, skb, n, classid,
                                           dev->qdisc, new);
                        if (new && !new->ops->attach)
-                               atomic_inc(&new->refcnt);
+                               refcount_inc(&new->refcnt);
                        dev->qdisc = new ? : &noop_qdisc;
 
                        if (new && new->ops->attach)
@@ -1259,7 +1259,7 @@ replay:
                                if (q == p ||
                                    (p && check_loop(q, p, 0)))
                                        return -ELOOP;
-                               atomic_inc(&q->refcnt);
+                               refcount_inc(&q->refcnt);
                                goto graft;
                        } else {
                                if (!q)
@@ -1374,7 +1374,7 @@ static int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid,
        tcm->tcm_ifindex = qdisc_dev(q)->ifindex;
        tcm->tcm_parent = clid;
        tcm->tcm_handle = q->handle;
-       tcm->tcm_info = atomic_read(&q->refcnt);
+       tcm->tcm_info = refcount_read(&q->refcnt);
        if (nla_put_string(skb, TCA_KIND, q->ops->id))
                goto nla_put_failure;
        if (q->ops->dump && q->ops->dump(q, skb) < 0)
index 52a2c55f6d9eb29ec1de3135596fe5a1529ebf23..57ba406f1437323a4ba172d52f14a8b687b86708 100644 (file)
@@ -633,7 +633,7 @@ struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue,
        sch->dequeue = ops->dequeue;
        sch->dev_queue = dev_queue;
        dev_hold(dev);
-       atomic_set(&sch->refcnt, 1);
+       refcount_set(&sch->refcnt, 1);
 
        return sch;
 errout:
@@ -701,7 +701,7 @@ void qdisc_destroy(struct Qdisc *qdisc)
        const struct Qdisc_ops  *ops = qdisc->ops;
 
        if (qdisc->flags & TCQ_F_BUILTIN ||
-           !atomic_dec_and_test(&qdisc->refcnt))
+           !refcount_dec_and_test(&qdisc->refcnt))
                return;
 
 #ifdef CONFIG_NET_SCHED
@@ -739,7 +739,7 @@ struct Qdisc *dev_graft_qdisc(struct netdev_queue *dev_queue,
        spin_lock_bh(root_lock);
 
        /* Prune old scheduler */
-       if (oqdisc && atomic_read(&oqdisc->refcnt) <= 1)
+       if (oqdisc && refcount_read(&oqdisc->refcnt) <= 1)
                qdisc_reset(oqdisc);
 
        /* ... and graft new one */
@@ -785,7 +785,7 @@ static void attach_default_qdiscs(struct net_device *dev)
            dev->priv_flags & IFF_NO_QUEUE) {
                netdev_for_each_tx_queue(dev, attach_one_default_qdisc, NULL);
                dev->qdisc = txq->qdisc_sleeping;
-               atomic_inc(&dev->qdisc->refcnt);
+               refcount_inc(&dev->qdisc->refcnt);
        } else {
                qdisc = qdisc_create_dflt(txq, &mq_qdisc_ops, TC_H_ROOT);
                if (qdisc) {