diff options
author | James Morris <jmorris@namei.org> | 2009-05-08 11:56:47 +0400 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2009-05-08 11:56:47 +0400 |
commit | d254117099d711f215e62427f55dfb8ebd5ad011 (patch) | |
tree | 0848ff8dd74314fec14a86497f8d288c86ba7c65 /fs/exec.c | |
parent | 07ff7a0b187f3951788f64ae1f30e8109bc8e9eb (diff) | |
parent | 8c9ed899b44c19e81859fbb0e9d659fe2f8630fc (diff) | |
download | linux-d254117099d711f215e62427f55dfb8ebd5ad011.tar.xz |
Merge branch 'master' into next
Diffstat (limited to 'fs/exec.c')
-rw-r--r-- | fs/exec.c | 47 |
1 files changed, 33 insertions, 14 deletions
diff --git a/fs/exec.c b/fs/exec.c index c5128fbc9165..639177b0eeac 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -53,6 +53,7 @@ #include <linux/tracehook.h> #include <linux/kmod.h> #include <linux/fsnotify.h> +#include <linux/fs_struct.h> #include <asm/uaccess.h> #include <asm/mmu_context.h> @@ -68,17 +69,18 @@ int suid_dumpable = 0; static LIST_HEAD(formats); static DEFINE_RWLOCK(binfmt_lock); -int register_binfmt(struct linux_binfmt * fmt) +int __register_binfmt(struct linux_binfmt * fmt, int insert) { if (!fmt) return -EINVAL; write_lock(&binfmt_lock); - list_add(&fmt->lh, &formats); + insert ? list_add(&fmt->lh, &formats) : + list_add_tail(&fmt->lh, &formats); write_unlock(&binfmt_lock); return 0; } -EXPORT_SYMBOL(register_binfmt); +EXPORT_SYMBOL(__register_binfmt); void unregister_binfmt(struct linux_binfmt * fmt) { @@ -1056,28 +1058,35 @@ EXPORT_SYMBOL(install_exec_creds); * - the caller must hold current->cred_exec_mutex to protect against * PTRACE_ATTACH */ -void check_unsafe_exec(struct linux_binprm *bprm) +int check_unsafe_exec(struct linux_binprm *bprm) { struct task_struct *p = current, *t; - unsigned long flags; - unsigned n_fs, n_sighand; + unsigned n_fs; + int res = 0; bprm->unsafe = tracehook_unsafe_exec(p); n_fs = 1; - n_sighand = 1; - lock_task_sighand(p, &flags); + write_lock(&p->fs->lock); + rcu_read_lock(); for (t = next_thread(p); t != p; t = next_thread(t)) { if (t->fs == p->fs) n_fs++; - n_sighand++; } + rcu_read_unlock(); - if (atomic_read(&p->fs->count) > n_fs || - atomic_read(&p->sighand->count) > n_sighand) + if (p->fs->users > n_fs) { bprm->unsafe |= LSM_UNSAFE_SHARE; + } else { + res = -EAGAIN; + if (!p->fs->in_exec) { + p->fs->in_exec = 1; + res = 1; + } + } + write_unlock(&p->fs->lock); - unlock_task_sighand(p, &flags); + return res; } /* @@ -1276,6 +1285,7 @@ int do_execve(char * filename, struct linux_binprm *bprm; struct file *file; struct files_struct *displaced; + bool clear_in_exec; int retval; retval = unshare_files(&displaced); @@ -1296,12 +1306,16 @@ int do_execve(char * filename, bprm->cred = prepare_exec_creds(); if (!bprm->cred) goto out_unlock; - check_unsafe_exec(bprm); + + retval = check_unsafe_exec(bprm); + if (retval < 0) + goto out_unlock; + clear_in_exec = retval; file = open_exec(filename); retval = PTR_ERR(file); if (IS_ERR(file)) - goto out_unlock; + goto out_unmark; sched_exec(); @@ -1344,6 +1358,7 @@ int do_execve(char * filename, goto out; /* execve succeeded */ + current->fs->in_exec = 0; current->in_execve = 0; mutex_unlock(¤t->cred_exec_mutex); acct_update_integrals(current); @@ -1362,6 +1377,10 @@ out_file: fput(bprm->file); } +out_unmark: + if (clear_in_exec) + current->fs->in_exec = 0; + out_unlock: current->in_execve = 0; mutex_unlock(¤t->cred_exec_mutex); |