diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/compat.c | 14 | ||||
-rw-r--r-- | fs/exec.c | 10 | ||||
-rw-r--r-- | fs/internal.h | 2 | ||||
-rw-r--r-- | fs/proc/base.c | 50 |
4 files changed, 32 insertions, 44 deletions
diff --git a/fs/compat.c b/fs/compat.c index 5e374aad33f..55efdfebdf5 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -1420,12 +1420,17 @@ int compat_do_execve(char * filename, { struct linux_binprm *bprm; struct file *file; + struct files_struct *displaced; int retval; + retval = unshare_files(&displaced); + if (retval) + goto out_ret; + retval = -ENOMEM; bprm = kzalloc(sizeof(*bprm), GFP_KERNEL); if (!bprm) - goto out_ret; + goto out_files; retval = mutex_lock_interruptible(¤t->cred_exec_mutex); if (retval < 0) @@ -1436,7 +1441,7 @@ int compat_do_execve(char * filename, bprm->cred = prepare_exec_creds(); if (!bprm->cred) goto out_unlock; - check_unsafe_exec(bprm, current->files); + check_unsafe_exec(bprm); file = open_exec(filename); retval = PTR_ERR(file); @@ -1487,6 +1492,8 @@ int compat_do_execve(char * filename, mutex_unlock(¤t->cred_exec_mutex); acct_update_integrals(current); free_bprm(bprm); + if (displaced) + put_files_struct(displaced); return retval; out: @@ -1506,6 +1513,9 @@ out_unlock: out_free: free_bprm(bprm); +out_files: + if (displaced) + reset_files_struct(displaced); out_ret: return retval; } diff --git a/fs/exec.c b/fs/exec.c index b9f1c144b7a..c5128fbc916 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1056,28 +1056,24 @@ 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, struct files_struct *files) +void check_unsafe_exec(struct linux_binprm *bprm) { struct task_struct *p = current, *t; unsigned long flags; - unsigned n_fs, n_files, n_sighand; + unsigned n_fs, n_sighand; bprm->unsafe = tracehook_unsafe_exec(p); n_fs = 1; - n_files = 1; n_sighand = 1; lock_task_sighand(p, &flags); for (t = next_thread(p); t != p; t = next_thread(t)) { if (t->fs == p->fs) n_fs++; - if (t->files == files) - n_files++; n_sighand++; } if (atomic_read(&p->fs->count) > n_fs || - atomic_read(&p->files->count) > n_files || atomic_read(&p->sighand->count) > n_sighand) bprm->unsafe |= LSM_UNSAFE_SHARE; @@ -1300,7 +1296,7 @@ int do_execve(char * filename, bprm->cred = prepare_exec_creds(); if (!bprm->cred) goto out_unlock; - check_unsafe_exec(bprm, displaced); + check_unsafe_exec(bprm); file = open_exec(filename); retval = PTR_ERR(file); diff --git a/fs/internal.h b/fs/internal.h index 0d8ac497b3d..53af885f173 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -43,7 +43,7 @@ extern void __init chrdev_init(void); /* * exec.c */ -extern void check_unsafe_exec(struct linux_binprm *, struct files_struct *); +extern void check_unsafe_exec(struct linux_binprm *); /* * namespace.c diff --git a/fs/proc/base.c b/fs/proc/base.c index aef6d55b7de..e0afd326b68 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -146,15 +146,22 @@ static unsigned int pid_entry_count_dirs(const struct pid_entry *entries, return count; } -static struct fs_struct *get_fs_struct(struct task_struct *task) +static int get_fs_path(struct task_struct *task, struct path *path, bool root) { struct fs_struct *fs; + int result = -ENOENT; + task_lock(task); fs = task->fs; - if(fs) - atomic_inc(&fs->count); + if (fs) { + read_lock(&fs->lock); + *path = root ? fs->root : fs->pwd; + path_get(path); + read_unlock(&fs->lock); + result = 0; + } task_unlock(task); - return fs; + return result; } static int get_nr_threads(struct task_struct *tsk) @@ -172,42 +179,24 @@ static int get_nr_threads(struct task_struct *tsk) static int proc_cwd_link(struct inode *inode, struct path *path) { struct task_struct *task = get_proc_task(inode); - struct fs_struct *fs = NULL; int result = -ENOENT; if (task) { - fs = get_fs_struct(task); + result = get_fs_path(task, path, 0); put_task_struct(task); } - if (fs) { - read_lock(&fs->lock); - *path = fs->pwd; - path_get(&fs->pwd); - read_unlock(&fs->lock); - result = 0; - put_fs_struct(fs); - } return result; } static int proc_root_link(struct inode *inode, struct path *path) { struct task_struct *task = get_proc_task(inode); - struct fs_struct *fs = NULL; int result = -ENOENT; if (task) { - fs = get_fs_struct(task); + result = get_fs_path(task, path, 1); put_task_struct(task); } - if (fs) { - read_lock(&fs->lock); - *path = fs->root; - path_get(&fs->root); - read_unlock(&fs->lock); - result = 0; - put_fs_struct(fs); - } return result; } @@ -596,7 +585,6 @@ static int mounts_open_common(struct inode *inode, struct file *file, struct task_struct *task = get_proc_task(inode); struct nsproxy *nsp; struct mnt_namespace *ns = NULL; - struct fs_struct *fs = NULL; struct path root; struct proc_mounts *p; int ret = -EINVAL; @@ -610,22 +598,16 @@ static int mounts_open_common(struct inode *inode, struct file *file, get_mnt_ns(ns); } rcu_read_unlock(); - if (ns) - fs = get_fs_struct(task); + if (ns && get_fs_path(task, &root, 1) == 0) + ret = 0; put_task_struct(task); } if (!ns) goto err; - if (!fs) + if (ret) goto err_put_ns; - read_lock(&fs->lock); - root = fs->root; - path_get(&root); - read_unlock(&fs->lock); - put_fs_struct(fs); - ret = -ENOMEM; p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL); if (!p) |