aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2008-04-22 05:31:30 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2008-04-25 09:23:59 -0400
commit3b1253880b7a9e6db54b943b2d40bcf2202f58ab (patch)
tree5301be7b4d4310faa8db5a0d027b81421e36570e
parentfd8328be874f4190a811c58cd4778ec2c74d2c05 (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>
-rw-r--r--fs/exec.c18
-rw-r--r--include/linux/file.h3
-rw-r--r--include/linux/fs.h3
-rw-r--r--kernel/exit.c3
-rw-r--r--kernel/fork.c54
5 files changed, 34 insertions, 47 deletions
diff --git a/fs/exec.c b/fs/exec.c
index 475543002f13..b152029f18f6 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1269,19 +1269,13 @@ int do_execve(char * filename,
1269 struct linux_binprm *bprm; 1269 struct linux_binprm *bprm;
1270 struct file *file; 1270 struct file *file;
1271 unsigned long env_p; 1271 unsigned long env_p;
1272 struct files_struct *files; 1272 struct files_struct *displaced;
1273 int retval; 1273 int retval;
1274 1274
1275 files = current->files; 1275 retval = unshare_files(&displaced);
1276 retval = unshare_files();
1277 if (retval) 1276 if (retval)
1278 goto out_ret; 1277 goto out_ret;
1279 1278
1280 if (files == current->files) {
1281 put_files_struct(files);
1282 files = NULL;
1283 }
1284
1285 retval = -ENOMEM; 1279 retval = -ENOMEM;
1286 bprm = kzalloc(sizeof(*bprm), GFP_KERNEL); 1280 bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);
1287 if (!bprm) 1281 if (!bprm)
@@ -1340,8 +1334,8 @@ int do_execve(char * filename,
1340 security_bprm_free(bprm); 1334 security_bprm_free(bprm);
1341 acct_update_integrals(current); 1335 acct_update_integrals(current);
1342 kfree(bprm); 1336 kfree(bprm);
1343 if (files) 1337 if (displaced)
1344 put_files_struct(files); 1338 put_files_struct(displaced);
1345 return retval; 1339 return retval;
1346 } 1340 }
1347 1341
@@ -1363,8 +1357,8 @@ out_kfree:
1363 kfree(bprm); 1357 kfree(bprm);
1364 1358
1365out_files: 1359out_files:
1366 if (files) 1360 if (displaced)
1367 reset_files_struct(current, files); 1361 reset_files_struct(displaced);
1368out_ret: 1362out_ret:
1369 return retval; 1363 return retval;
1370} 1364}
diff --git a/include/linux/file.h b/include/linux/file.h
index 653477021e4c..69baf5a4f0a5 100644
--- a/include/linux/file.h
+++ b/include/linux/file.h
@@ -117,7 +117,8 @@ struct task_struct;
117 117
118struct files_struct *get_files_struct(struct task_struct *); 118struct files_struct *get_files_struct(struct task_struct *);
119void put_files_struct(struct files_struct *fs); 119void put_files_struct(struct files_struct *fs);
120void reset_files_struct(struct task_struct *, struct files_struct *); 120void reset_files_struct(struct files_struct *);
121int unshare_files(struct files_struct **);
121 122
122extern struct kmem_cache *files_cachep; 123extern struct kmem_cache *files_cachep;
123 124
diff --git a/include/linux/fs.h b/include/linux/fs.h
index ad41d0bbcb4d..e057438a05ad 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2033,9 +2033,6 @@ static inline ino_t parent_ino(struct dentry *dentry)
2033 return res; 2033 return res;
2034} 2034}
2035 2035
2036/* kernel/fork.c */
2037extern int unshare_files(void);
2038
2039/* Transaction based IO helpers */ 2036/* Transaction based IO helpers */
2040 2037
2041/* 2038/*
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)
507 } 507 }
508} 508}
509 509
510void reset_files_struct(struct task_struct *tsk, struct files_struct *files) 510void reset_files_struct(struct files_struct *files)
511{ 511{
512 struct task_struct *tsk = current;
512 struct files_struct *old; 513 struct files_struct *old;
513 514
514 old = tsk->files; 515 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)
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
849int 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
873static int copy_sighand(unsigned long clone_flags, struct task_struct *tsk) 843static 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:
1807bad_unshare_out: 1777bad_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
1787int 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, &copy);
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}