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.reshet...@intel.com>
Signed-off-by: Hans Liljestrand <ishkam...@gmail.com>
Signed-off-by: Kees Cook <keesc...@chromium.org>
Signed-off-by: David Windsor <dwind...@gmail.com>
---
 include/net/sch_generic.h | 3 ++-
 net/sched/sch_api.c       | 8 ++++----
 net/sched/sch_generic.c   | 8 ++++----
 3 files changed, 10 insertions(+), 9 deletions(-)

diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index 3688501..1c123e2 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -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;
 };
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index 43b94c7..bd24a55 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -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 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc 
*parent,
                        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 @@ static int tc_modify_qdisc(struct sk_buff *skb, struct 
nlmsghdr *n,
                                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)
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 52a2c55..57ba406 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -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) {
-- 
2.7.4

--
To unsubscribe from this list: send the line "unsubscribe linux-hams" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to