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]>
---
 drivers/staging/lustre/lustre/llite/llite_lib.c |  2 +-
 fs/cifs/cifsfs.c                                |  2 +-
 fs/devpts/inode.c                               |  2 +-
 fs/gfs2/super.c                                 |  2 +-
 fs/kernfs/mount.c                               |  2 +-
 fs/namespace.c                                  |  4 ++--
 fs/nfs/super.c                                  |  4 ++--
 fs/super.c                                      | 10 +++++-----
 include/linux/fs.h                              |  3 ++-
 9 files changed, 16 insertions(+), 15 deletions(-)

diff --git a/drivers/staging/lustre/lustre/llite/llite_lib.c 
b/drivers/staging/lustre/lustre/llite/llite_lib.c
index b229cbc..46d7b2a 100644
--- a/drivers/staging/lustre/lustre/llite/llite_lib.c
+++ b/drivers/staging/lustre/lustre/llite/llite_lib.c
@@ -1995,7 +1995,7 @@ void ll_umount_begin(struct super_block *sb)
        struct l_wait_info lwi;
 
        CDEBUG(D_VFSTRACE, "VFS Op: superblock %p count %d active %d\n", sb,
-              sb->s_count, atomic_read(&sb->s_active));
+              sb->s_count, refcount_read(&sb->s_active));
 
        obd = class_exp2obd(sbi->ll_md_exp);
        if (!obd) {
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 15e1db8..73d29b7 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -101,7 +101,7 @@ cifs_sb_active(struct super_block *sb)
        struct cifs_sb_info *server = CIFS_SB(sb);
 
        if (atomic_inc_return(&server->active) == 1)
-               atomic_inc(&sb->s_active);
+               refcount_inc(&sb->s_active);
 }
 
 void
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
index 108df2e..fba89ab 100644
--- a/fs/devpts/inode.c
+++ b/fs/devpts/inode.c
@@ -164,7 +164,7 @@ struct pts_fs_info *devpts_acquire(struct file *filp)
        /*
         * pty code needs to hold extra references in case of last /dev/tty 
close
         */
-       atomic_inc(&sb->s_active);
+       refcount_inc(&sb->s_active);
        result = DEVPTS_SB(sb);
 
 out:
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
index e3ee387..49af2ef 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -954,7 +954,7 @@ void gfs2_freeze_func(struct work_struct *work)
        struct gfs2_sbd *sdp = container_of(work, struct gfs2_sbd, 
sd_freeze_work);
        struct super_block *sb = sdp->sd_vfs;
 
-       atomic_inc(&sb->s_active);
+       refcount_inc(&sb->s_active);
        error = gfs2_glock_nq_init(sdp->sd_freeze_gl, LM_ST_SHARED, 0,
                                   &freeze_gh);
        if (error) {
diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c
index d5b149a..8d61bcf 100644
--- a/fs/kernfs/mount.c
+++ b/fs/kernfs/mount.c
@@ -319,7 +319,7 @@ struct super_block *kernfs_pin_sb(struct kernfs_root *root, 
const void *ns)
        list_for_each_entry(info, &root->supers, node) {
                if (info->ns == ns) {
                        sb = info->sb;
-                       if (!atomic_inc_not_zero(&info->sb->s_active))
+                       if (!refcount_inc_not_zero(&info->sb->s_active))
                                sb = ERR_PTR(-EINVAL);
                        break;
                }
diff --git a/fs/namespace.c b/fs/namespace.c
index 85cc8ca..9a6107f 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1051,7 +1051,7 @@ static struct mount *clone_mnt(struct mount *old, struct 
dentry *root,
            (!(flag & CL_EXPIRE) || list_empty(&old->mnt_expire)))
                mnt->mnt.mnt_flags |= MNT_LOCKED;
 
-       atomic_inc(&sb->s_active);
+       refcount_inc(&sb->s_active);
        mnt->mnt.mnt_sb = sb;
        mnt->mnt.mnt_root = dget(root);
        mnt->mnt_mountpoint = mnt->mnt.mnt_root;
@@ -3015,7 +3015,7 @@ struct dentry *mount_subtree(struct vfsmount *mnt, const 
char *name)
 
        /* trade a vfsmount reference for active sb one */
        s = path.mnt->mnt_sb;
-       atomic_inc(&s->s_active);
+       refcount_inc(&s->s_active);
        mntput(path.mnt);
        /* lock the sucker */
        down_write(&s->s_umount);
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 6bca178..58e4b51 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -412,10 +412,10 @@ bool nfs_sb_active(struct super_block *sb)
 {
        struct nfs_server *server = NFS_SB(sb);
 
-       if (!atomic_inc_not_zero(&sb->s_active))
+       if (!refcount_inc_not_zero(&sb->s_active))
                return false;
        if (atomic_inc_return(&server->active) != 1)
-               atomic_dec(&sb->s_active);
+               refcount_dec(&sb->s_active);
        return true;
 }
 EXPORT_SYMBOL_GPL(nfs_sb_active);
diff --git a/fs/super.c b/fs/super.c
index b8b6a08..7e1511c 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -240,7 +240,7 @@ static struct super_block *alloc_super(struct 
file_system_type *type, int flags,
         */
        down_write_nested(&s->s_umount, SINGLE_DEPTH_NESTING);
        s->s_count = 1;
-       atomic_set(&s->s_active, 1);
+       refcount_set(&s->s_active, 1);
        mutex_init(&s->s_vfs_rename_mutex);
        lockdep_set_class(&s->s_vfs_rename_mutex, &type->s_vfs_rename_key);
        mutex_init(&s->s_dquot.dqio_mutex);
@@ -303,7 +303,7 @@ static void put_super(struct super_block *sb)
 void deactivate_locked_super(struct super_block *s)
 {
        struct file_system_type *fs = s->s_type;
-       if (atomic_dec_and_test(&s->s_active)) {
+       if (refcount_dec_and_test(&s->s_active)) {
                cleancache_invalidate_fs(s);
                unregister_shrinker(&s->s_shrink);
                fs->kill_sb(s);
@@ -335,7 +335,7 @@ EXPORT_SYMBOL(deactivate_locked_super);
  */
 void deactivate_super(struct super_block *s)
 {
-        if (!atomic_add_unless(&s->s_active, -1, 1)) {
+       if (!refcount_dec_not_one(&s->s_active)) {
                down_write(&s->s_umount);
                deactivate_locked_super(s);
        }
@@ -361,7 +361,7 @@ static int grab_super(struct super_block *s) 
__releases(sb_lock)
        s->s_count++;
        spin_unlock(&sb_lock);
        down_write(&s->s_umount);
-       if ((s->s_flags & MS_BORN) && atomic_inc_not_zero(&s->s_active)) {
+       if ((s->s_flags & MS_BORN) && refcount_inc_not_zero(&s->s_active)) {
                put_super(s);
                return 1;
        }
@@ -1385,7 +1385,7 @@ int freeze_super(struct super_block *sb)
 {
        int ret;
 
-       atomic_inc(&sb->s_active);
+       refcount_inc(&sb->s_active);
        down_write(&sb->s_umount);
        if (sb->s_writers.frozen != SB_UNFROZEN) {
                deactivate_locked_super(sb);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 79fc59b..6b83a08 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -31,6 +31,7 @@
 #include <linux/workqueue.h>
 #include <linux/percpu-rwsem.h>
 #include <linux/delayed_call.h>
+#include <linux/refcount.h>
 
 #include <asm/byteorder.h>
 #include <uapi/linux/fs.h>
@@ -1308,7 +1309,7 @@ struct super_block {
        struct dentry           *s_root;
        struct rw_semaphore     s_umount;
        int                     s_count;
-       atomic_t                s_active;
+       refcount_t              s_active;
 #ifdef CONFIG_SECURITY
        void                    *s_security;
 #endif
-- 
2.7.4

Reply via email to