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 <[email protected]>
Signed-off-by: Hans Liljestrand <[email protected]>
Signed-off-by: Kees Cook <[email protected]>
Signed-off-by: David Windsor <[email protected]>
---
 fs/kernfs/dir.c        | 12 +++++-------
 include/linux/kernfs.h |  3 ++-
 2 files changed, 7 insertions(+), 8 deletions(-)

diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index db5900aaa..2a07de1 100644
--- a/fs/kernfs/dir.c
+++ b/fs/kernfs/dir.c
@@ -489,10 +489,8 @@ static void kernfs_drain(struct kernfs_node *kn)
  */
 void kernfs_get(struct kernfs_node *kn)
 {
-       if (kn) {
-               WARN_ON(!atomic_read(&kn->count));
-               atomic_inc(&kn->count);
-       }
+       if (kn)
+               refcount_inc(&kn->count);
 }
 EXPORT_SYMBOL_GPL(kernfs_get);
 
@@ -507,7 +505,7 @@ void kernfs_put(struct kernfs_node *kn)
        struct kernfs_node *parent;
        struct kernfs_root *root;
 
-       if (!kn || !atomic_dec_and_test(&kn->count))
+       if (!kn || !refcount_dec_and_test(&kn->count))
                return;
        root = kernfs_root(kn);
  repeat:
@@ -538,7 +536,7 @@ void kernfs_put(struct kernfs_node *kn)
 
        kn = parent;
        if (kn) {
-               if (atomic_dec_and_test(&kn->count))
+               if (refcount_dec_and_test(&kn->count))
                        goto repeat;
        } else {
                /* just released the root kn, free @root too */
@@ -635,7 +633,7 @@ static struct kernfs_node *__kernfs_new_node(struct 
kernfs_root *root,
                goto err_out2;
        kn->ino = ret;
 
-       atomic_set(&kn->count, 1);
+       refcount_set(&kn->count, 1);
        atomic_set(&kn->active, KN_DEACTIVATED_BIAS);
        RB_CLEAR_NODE(&kn->rb);
 
diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h
index a9b11b8..baabbaf 100644
--- a/include/linux/kernfs.h
+++ b/include/linux/kernfs.h
@@ -15,6 +15,7 @@
 #include <linux/lockdep.h>
 #include <linux/rbtree.h>
 #include <linux/atomic.h>
+#include <linux/refcount.h>
 #include <linux/wait.h>
 
 struct file;
@@ -105,7 +106,7 @@ struct kernfs_elem_attr {
  * active reference.
  */
 struct kernfs_node {
-       atomic_t                count;
+       refcount_t              count;
        atomic_t                active;
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
        struct lockdep_map      dep_map;
-- 
2.7.4

Reply via email to