diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2008-04-22 05:31:30 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2008-04-25 09:23:59 -0400 |
commit | 3b1253880b7a9e6db54b943b2d40bcf2202f58ab (patch) | |
tree | 5301be7b4d4310faa8db5a0d027b81421e36570e /kernel/fork.c | |
parent | fd8328be874f4190a811c58cd4778ec2c74d2c05 (diff) |
[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/fork.c')
-rw-r--r-- | kernel/fork.c | 54 |
1 files changed, 24 insertions, 30 deletions
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) | |||
840 | return 0; | 840 | return 0; |
841 | } | 841 | } |
842 | 842 | ||
843 | /* | ||
844 | * Helper to unshare the files of the current task. | ||
845 | * We don't want to expose copy_files internals to | ||
846 | * the exec layer of the kernel. | ||
847 | */ | ||
848 | |||
849 | int unshare_files(void) | ||
850 | { | ||
851 | struct files_struct *files = current->files; | ||
852 | struct files_struct *newf; | ||
853 | int error = 0; | ||
854 | |||
855 | BUG_ON(!files); | ||
856 | |||
857 | /* This can race but the race causes us to copy when we don't | ||
858 | need to and drop the copy */ | ||
859 | if(atomic_read(&files->count) == 1) | ||
860 | { | ||
861 | atomic_inc(&files->count); | ||
862 | return 0; | ||
863 | } | ||
864 | newf = dup_fd(files, &error); | ||
865 | if (newf) { | ||
866 | task_lock(current); | ||
867 | current->files = newf; | ||
868 | task_unlock(current); | ||
869 | } | ||
870 | return error; | ||
871 | } | ||
872 | |||
873 | static int copy_sighand(unsigned long clone_flags, struct task_struct *tsk) | 843 | static int copy_sighand(unsigned long clone_flags, struct task_struct *tsk) |
874 | { | 844 | { |
875 | struct sighand_struct *sig; | 845 | struct sighand_struct *sig; |
@@ -1807,3 +1777,27 @@ bad_unshare_cleanup_thread: | |||
1807 | bad_unshare_out: | 1777 | bad_unshare_out: |
1808 | return err; | 1778 | return err; |
1809 | } | 1779 | } |
1780 | |||
1781 | /* | ||
1782 | * Helper to unshare the files of the current task. | ||
1783 | * We don't want to expose copy_files internals to | ||
1784 | * the exec layer of the kernel. | ||
1785 | */ | ||
1786 | |||
1787 | int unshare_files(struct files_struct **displaced) | ||
1788 | { | ||
1789 | struct task_struct *task = current; | ||
1790 | struct files_struct *copy; | ||
1791 | int error; | ||
1792 | |||
1793 | error = unshare_fd(CLONE_FILES, ©); | ||
1794 | if (error || !copy) { | ||
1795 | *displaced = NULL; | ||
1796 | return error; | ||
1797 | } | ||
1798 | *displaced = task->files; | ||
1799 | task_lock(task); | ||
1800 | task->files = copy; | ||
1801 | task_unlock(task); | ||
1802 | return 0; | ||
1803 | } | ||