|
|
Message-Id: <1477757996-22468-2-git-send-email-dwindsor@gmail.com>
Date: Sat, 29 Oct 2016 12:19:52 -0400
From: David Windsor <dwindsor@...il.com>
To: kernel-hardening@...ts.openwall.com
Cc: keescook@...omium.org,
elena.reshetova@...el.com,
ishkamiel@...il.com,
takahiro.akashi@...aro.org,
colin@...dal.org,
dwindsor@...il.com
Subject: [RFC PATCH 1/5] fs: add overflow protection to struct fs_struct.users
Change type of struct fs_struct.users to atomic_t. This enables overflow
protection: when CONFIG_HARDENED_ATOMIC is enabled, atomic_t variables
cannot be overflowed.
The copyright for the original PAX_REFCOUNT code:
- all REFCOUNT code in general: PaX Team <pageexec@...email.hu>
- various false positive fixes: Mathias Krause <minipli@...glemail.com>
---
fs/exec.c | 2 +-
fs/fs_struct.c | 8 ++++----
fs/namespace.c | 2 +-
fs/proc/task_nommu.c | 2 +-
include/linux/fs_struct.h | 2 +-
kernel/fork.c | 6 +++---
kernel/user_namespace.c | 2 +-
7 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/fs/exec.c b/fs/exec.c
index 4e497b9..ad79491 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1429,7 +1429,7 @@ static void check_unsafe_exec(struct linux_binprm *bprm)
}
rcu_read_unlock();
- if (p->fs->users > n_fs)
+ if (atomic_read(&p->fs->users) > n_fs)
bprm->unsafe |= LSM_UNSAFE_SHARE;
else
p->fs->in_exec = 1;
diff --git a/fs/fs_struct.c b/fs/fs_struct.c
index 7dca743..697c96e 100644
--- a/fs/fs_struct.c
+++ b/fs/fs_struct.c
@@ -99,7 +99,7 @@ void exit_fs(struct task_struct *tsk)
task_lock(tsk);
spin_lock(&fs->lock);
tsk->fs = NULL;
- kill = !--fs->users;
+ kill = !atomic_dec_return(&fs->users);
spin_unlock(&fs->lock);
task_unlock(tsk);
if (kill)
@@ -112,7 +112,7 @@ struct fs_struct *copy_fs_struct(struct fs_struct *old)
struct fs_struct *fs = kmem_cache_alloc(fs_cachep, GFP_KERNEL);
/* We don't need to lock fs - think why ;-) */
if (fs) {
- fs->users = 1;
+ atomic_set(&fs->users, 1);
fs->in_exec = 0;
spin_lock_init(&fs->lock);
seqcount_init(&fs->seq);
@@ -139,7 +139,7 @@ int unshare_fs_struct(void)
task_lock(current);
spin_lock(&fs->lock);
- kill = !--fs->users;
+ kill = !atomic_dec_return(&fs->users);
current->fs = new_fs;
spin_unlock(&fs->lock);
task_unlock(current);
@@ -159,7 +159,7 @@ EXPORT_SYMBOL(current_umask);
/* to be mentioned only in INIT_TASK */
struct fs_struct init_fs = {
- .users = 1,
+ .users = ATOMIC_INIT(1),
.lock = __SPIN_LOCK_UNLOCKED(init_fs.lock),
.seq = SEQCNT_ZERO(init_fs.seq),
.umask = 0022,
diff --git a/fs/namespace.c b/fs/namespace.c
index 5d205f9..66a0b99 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -3394,7 +3394,7 @@ static int mntns_install(struct nsproxy *nsproxy, struct ns_common *ns)
!ns_capable(current_user_ns(), CAP_SYS_ADMIN))
return -EPERM;
- if (fs->users != 1)
+ if (atomic_read(&fs->users) != 1)
return -EINVAL;
get_mnt_ns(mnt_ns);
diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c
index 3717562..b318930 100644
--- a/fs/proc/task_nommu.c
+++ b/fs/proc/task_nommu.c
@@ -51,7 +51,7 @@ void task_mem(struct seq_file *m, struct mm_struct *mm)
else
bytes += kobjsize(mm);
- if (current->fs && current->fs->users > 1)
+ if (current->fs && atomic_read(¤t->fs->users) > 1)
sbytes += kobjsize(current->fs);
else
bytes += kobjsize(current->fs);
diff --git a/include/linux/fs_struct.h b/include/linux/fs_struct.h
index 0efc3e6..e0e1e5f 100644
--- a/include/linux/fs_struct.h
+++ b/include/linux/fs_struct.h
@@ -6,7 +6,7 @@
#include <linux/seqlock.h>
struct fs_struct {
- int users;
+ atomic_t users;
spinlock_t lock;
seqcount_t seq;
int umask;
diff --git a/kernel/fork.c b/kernel/fork.c
index 623259f..f06f356 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1203,7 +1203,7 @@ static int copy_fs(unsigned long clone_flags, struct task_struct *tsk)
spin_unlock(&fs->lock);
return -EAGAIN;
}
- fs->users++;
+ atomic_inc(&fs->users);
spin_unlock(&fs->lock);
return 0;
}
@@ -2129,7 +2129,7 @@ static int unshare_fs(unsigned long unshare_flags, struct fs_struct **new_fsp)
return 0;
/* don't need lock here; in the worst case we'll do useless copy */
- if (fs->users == 1)
+ if (atomic_read(&fs->users) == 1)
return 0;
*new_fsp = copy_fs_struct(fs);
@@ -2242,7 +2242,7 @@ SYSCALL_DEFINE1(unshare, unsigned long, unshare_flags)
fs = current->fs;
spin_lock(&fs->lock);
current->fs = new_fs;
- if (--fs->users)
+ if (atomic_dec_return(&fs->users))
new_fs = NULL;
else
new_fs = fs;
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
index 86b7854..8fbc98b 100644
--- a/kernel/user_namespace.c
+++ b/kernel/user_namespace.c
@@ -1034,7 +1034,7 @@ static int userns_install(struct nsproxy *nsproxy, struct ns_common *ns)
if (!thread_group_empty(current))
return -EINVAL;
- if (current->fs->users != 1)
+ if (atomic_read(¤t->fs->users) != 1)
return -EINVAL;
if (!ns_capable(user_ns, CAP_SYS_ADMIN))
--
2.7.4
Powered by blists - more mailing lists
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.