[PATCH 4/5] fs: convert super_block.s_active from atomic_t to refcount_t
From: Elena Reshetova
Date: Wed Mar 01 2017 - 05:46:21 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>
---
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