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/cachefiles/bind.c      |  2 +-
 fs/cachefiles/interface.c | 18 +++++++++---------
 fs/cachefiles/internal.h  |  3 ++-
 fs/cachefiles/namei.c     |  2 +-
 4 files changed, 13 insertions(+), 12 deletions(-)

diff --git a/fs/cachefiles/bind.c b/fs/cachefiles/bind.c
index 3ff867f..341864e 100644
--- a/fs/cachefiles/bind.c
+++ b/fs/cachefiles/bind.c
@@ -109,7 +109,7 @@ static int cachefiles_daemon_add_cache(struct 
cachefiles_cache *cache)
 
        ASSERTCMP(fsdef->backer, ==, NULL);
 
-       atomic_set(&fsdef->usage, 1);
+       refcount_set(&fsdef->usage, 1);
        fsdef->type = FSCACHE_COOKIE_TYPE_INDEX;
 
        _debug("- fsdef %p", fsdef);
diff --git a/fs/cachefiles/interface.c b/fs/cachefiles/interface.c
index e7f16a7..d3f87c3 100644
--- a/fs/cachefiles/interface.c
+++ b/fs/cachefiles/interface.c
@@ -51,7 +51,7 @@ static struct fscache_object *cachefiles_alloc_object(
        ASSERTCMP(object->backer, ==, NULL);
 
        BUG_ON(test_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags));
-       atomic_set(&object->usage, 1);
+       refcount_set(&object->usage, 1);
 
        fscache_object_init(&object->fscache, cookie, &cache->cache);
 
@@ -182,13 +182,13 @@ struct fscache_object *cachefiles_grab_object(struct 
fscache_object *_object)
        struct cachefiles_object *object =
                container_of(_object, struct cachefiles_object, fscache);
 
-       _enter("{OBJ%x,%d}", _object->debug_id, atomic_read(&object->usage));
+       _enter("{OBJ%x,%d}", _object->debug_id, refcount_read(&object->usage));
 
 #ifdef CACHEFILES_DEBUG_SLAB
-       ASSERT((atomic_read(&object->usage) & 0xffff0000) != 0x6b6b0000);
+       ASSERT((refcount_read(&object->usage) & 0xffff0000) != 0x6b6b0000);
 #endif
 
-       atomic_inc(&object->usage);
+       refcount_inc(&object->usage);
        return &object->fscache;
 }
 
@@ -261,13 +261,13 @@ static void cachefiles_drop_object(struct fscache_object 
*_object)
        object = container_of(_object, struct cachefiles_object, fscache);
 
        _enter("{OBJ%x,%d}",
-              object->fscache.debug_id, atomic_read(&object->usage));
+              object->fscache.debug_id, refcount_read(&object->usage));
 
        cache = container_of(object->fscache.cache,
                             struct cachefiles_cache, cache);
 
 #ifdef CACHEFILES_DEBUG_SLAB
-       ASSERT((atomic_read(&object->usage) & 0xffff0000) != 0x6b6b0000);
+       ASSERT((refcount_read(&object->usage) & 0xffff0000) != 0x6b6b0000);
 #endif
 
        /* We need to tidy the object up if we did in fact manage to open it.
@@ -319,16 +319,16 @@ static void cachefiles_put_object(struct fscache_object 
*_object)
        object = container_of(_object, struct cachefiles_object, fscache);
 
        _enter("{OBJ%x,%d}",
-              object->fscache.debug_id, atomic_read(&object->usage));
+              object->fscache.debug_id, refcount_read(&object->usage));
 
 #ifdef CACHEFILES_DEBUG_SLAB
-       ASSERT((atomic_read(&object->usage) & 0xffff0000) != 0x6b6b0000);
+       ASSERT((refcount_read(&object->usage) & 0xffff0000) != 0x6b6b0000);
 #endif
 
        ASSERTIFCMP(object->fscache.parent,
                    object->fscache.parent->n_children, >, 0);
 
-       if (atomic_dec_and_test(&object->usage)) {
+       if (refcount_dec_and_test(&object->usage)) {
                _debug("- kill object OBJ%x", object->fscache.debug_id);
 
                ASSERT(!test_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags));
diff --git a/fs/cachefiles/internal.h b/fs/cachefiles/internal.h
index cd1effe..61771e6 100644
--- a/fs/cachefiles/internal.h
+++ b/fs/cachefiles/internal.h
@@ -21,6 +21,7 @@
 #include <linux/wait.h>
 #include <linux/workqueue.h>
 #include <linux/security.h>
+#include <linux/refcount.h>
 
 struct cachefiles_cache;
 struct cachefiles_object;
@@ -43,7 +44,7 @@ struct cachefiles_object {
        loff_t                          i_size;         /* object size */
        unsigned long                   flags;
 #define CACHEFILES_OBJECT_ACTIVE       0               /* T if marked active */
-       atomic_t                        usage;          /* object usage count */
+       refcount_t                      usage;          /* object usage count */
        uint8_t                         type;           /* object type */
        uint8_t                         new;            /* T if object new */
        spinlock_t                      work_lock;
diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c
index 41df8a2..e3bc512 100644
--- a/fs/cachefiles/namei.c
+++ b/fs/cachefiles/namei.c
@@ -197,7 +197,7 @@ static int cachefiles_mark_object_active(struct 
cachefiles_cache *cache,
                cachefiles_printk_object(object, xobject);
                BUG();
        }
-       atomic_inc(&xobject->usage);
+       refcount_inc(&xobject->usage);
        write_unlock(&cache->active_lock);
 
        if (test_bit(CACHEFILES_OBJECT_ACTIVE, &xobject->flags)) {
-- 
2.7.4

Reply via email to