diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2008-04-22 11:31:30 +0200 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2008-04-25 15:23:59 +0200 |
commit | 3b1253880b7a9e6db54b943b2d40bcf2202f58ab (patch) | |
tree | 5301be7b4d4310faa8db5a0d027b81421e36570e /kernel | |
parent | [PATCH] sanitize handling of shared descriptor tables in failing execve() (diff) | |
download | linux-3b1253880b7a9e6db54b943b2d40bcf2202f58ab.tar.xz linux-3b1253880b7a9e6db54b943b2d40bcf2202f58ab.zip |
[PATCH] sanitize unshare_files/reset_files_struct
* let unshare_files() give caller the displaced files_struct
* don't bother with grabbing reference only to drop it in the
caller if it hadn't been shared in the first place
* in that form unshare_files() is trivially implemented via
unshare_fd(), so we eliminate the duplicate logics in fork.c
* reset_files_struct() is not just only called for current;
it will break the system if somebody ever calls it for anything
else (we can't modify ->files of somebody else). Lose the
task_struct * argument.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/exit.c | 3 | ||||
-rw-r--r-- | kernel/fork.c | 54 |
2 files changed, 26 insertions, 31 deletions
diff --git a/kernel/exit.c b/kernel/exit.c index 3d320003cc03..97f609f574b1 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -507,8 +507,9 @@ void put_files_struct(struct files_struct *files) } } -void reset_files_struct(struct task_struct *tsk, struct files_struct *files) +void reset_files_struct(struct files_struct *files) { + struct task_struct *tsk = current; struct files_struct *old; old = tsk->files; diff --git a/kernel/fork.c b/kernel/fork.c index 2fc11f2e2b21..efb618fc8ffe 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -840,36 +840,6 @@ static int copy_io(unsigned long clone_flags, struct task_struct *tsk) return 0; } -/* - * Helper to unshare the files of the current task. - * We don't want to expose copy_files internals to - * the exec layer of the kernel. - */ - -int unshare_files(void) -{ - struct files_struct *files = current->files; - struct files_struct *newf; - int error = 0; - - BUG_ON(!files); - - /* This can race but the race causes us to copy when we don't - need to and drop the copy */ - if(atomic_read(&files->count) == 1) - { - atomic_inc(&files->count); - return 0; - } - newf = dup_fd(files, &error); - if (newf) { - task_lock(current); - current->files = newf; - task_unlock(current); - } - return error; -} - static int copy_sighand(unsigned long clone_flags, struct task_struct *tsk) { struct sighand_struct *sig; @@ -1807,3 +1777,27 @@ bad_unshare_cleanup_thread: bad_unshare_out: return err; } + +/* + * Helper to unshare the files of the current task. + * We don't want to expose copy_files internals to + * the exec layer of the kernel. + */ + +int unshare_files(struct files_struct **displaced) +{ + struct task_struct *task = current; + struct files_struct *copy; + int error; + + error = unshare_fd(CLONE_FILES, ©); + if (error || !copy) { + *displaced = NULL; + return error; + } + *displaced = task->files; + task_lock(task); + task->files = copy; + task_unlock(task); + return 0; +} |