kernel: convert css_set.refcount from atomic_t to refcount_t
authorElena Reshetova <elena.reshetova@intel.com>
Wed, 8 Mar 2017 08:00:40 +0000 (10:00 +0200)
committerTejun Heo <tj@kernel.org>
Wed, 8 Mar 2017 22:46:03 +0000 (17:46 -0500)
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: Tejun Heo <tj@kernel.org>
include/linux/cgroup-defs.h
kernel/cgroup/cgroup-internal.h
kernel/cgroup/cgroup-v1.c
kernel/cgroup/cgroup.c

index 6a3f850cababb6f96130503014d83d256f2b9213..c74b78ecd5831d26d7a971059e42d6a8a50a14d4 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/wait.h>
 #include <linux/mutex.h>
 #include <linux/rcupdate.h>
+#include <linux/refcount.h>
 #include <linux/percpu-refcount.h>
 #include <linux/percpu-rwsem.h>
 #include <linux/workqueue.h>
@@ -156,7 +157,7 @@ struct css_set {
        struct cgroup_subsys_state *subsys[CGROUP_SUBSYS_COUNT];
 
        /* reference count */
-       atomic_t refcount;
+       refcount_t refcount;
 
        /* the default cgroup associated with this css_set */
        struct cgroup *dfl_cgrp;
index 9203bfb0560399af9611bd40516758ab01076cba..4567f12b02e95f6a955c74c62b4e15aa68307773 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/kernfs.h>
 #include <linux/workqueue.h>
 #include <linux/list.h>
+#include <linux/refcount.h>
 
 /*
  * A cgroup can be associated with multiple css_sets as different tasks may
@@ -134,7 +135,7 @@ static inline void put_css_set(struct css_set *cset)
         * can see it. Similar to atomic_dec_and_lock(), but for an
         * rwlock
         */
-       if (atomic_add_unless(&cset->refcount, -1, 1))
+       if (refcount_dec_not_one(&cset->refcount))
                return;
 
        spin_lock_irqsave(&css_set_lock, flags);
@@ -147,7 +148,7 @@ static inline void put_css_set(struct css_set *cset)
  */
 static inline void get_css_set(struct css_set *cset)
 {
-       atomic_inc(&cset->refcount);
+       refcount_inc(&cset->refcount);
 }
 
 bool cgroup_ssid_enabled(int ssid);
index 56eba9caa632adcc118114d8aa55cbab00895495..c4a68c438fde24fb5b76df9f1fab5f967201a770 100644 (file)
@@ -346,7 +346,7 @@ static int cgroup_task_count(const struct cgroup *cgrp)
 
        spin_lock_irq(&css_set_lock);
        list_for_each_entry(link, &cgrp->cset_links, cset_link)
-               count += atomic_read(&link->cset->refcount);
+               count += refcount_read(&link->cset->refcount);
        spin_unlock_irq(&css_set_lock);
        return count;
 }
@@ -1286,7 +1286,7 @@ static u64 current_css_set_refcount_read(struct cgroup_subsys_state *css,
        u64 count;
 
        rcu_read_lock();
-       count = atomic_read(&task_css_set(current)->refcount);
+       count = refcount_read(&task_css_set(current)->refcount);
        rcu_read_unlock();
        return count;
 }
index 8ee78688e36dd6004f100556f78d38cf16277ef1..b1cc1c306668cc8058181a609e0a2836873aa4b9 100644 (file)
@@ -554,7 +554,7 @@ EXPORT_SYMBOL_GPL(of_css);
  * haven't been created.
  */
 struct css_set init_css_set = {
-       .refcount               = ATOMIC_INIT(1),
+       .refcount               = REFCOUNT_INIT(1),
        .tasks                  = LIST_HEAD_INIT(init_css_set.tasks),
        .mg_tasks               = LIST_HEAD_INIT(init_css_set.mg_tasks),
        .task_iters             = LIST_HEAD_INIT(init_css_set.task_iters),
@@ -724,7 +724,7 @@ void put_css_set_locked(struct css_set *cset)
 
        lockdep_assert_held(&css_set_lock);
 
-       if (!atomic_dec_and_test(&cset->refcount))
+       if (!refcount_dec_and_test(&cset->refcount))
                return;
 
        /* This css_set is dead. unlink it and release cgroup and css refs */
@@ -977,7 +977,7 @@ static struct css_set *find_css_set(struct css_set *old_cset,
                return NULL;
        }
 
-       atomic_set(&cset->refcount, 1);
+       refcount_set(&cset->refcount, 1);
        INIT_LIST_HEAD(&cset->tasks);
        INIT_LIST_HEAD(&cset->mg_tasks);
        INIT_LIST_HEAD(&cset->task_iters);