[PATCH 01/10] fs, kernfs: convert kernfs_node.count from atomic_t to refcount_t

From: Elena Reshetova
Date: Thu Mar 02 2017 - 05:46:46 EST


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@xxxxxxxxx>
Signed-off-by: Hans Liljestrand <ishkamiel@xxxxxxxxx>
Signed-off-by: Kees Cook <keescook@xxxxxxxxxxxx>
Signed-off-by: David Windsor <dwindsor@xxxxxxxxx>
---
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