aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2008-04-22 05:11:59 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2008-04-25 09:23:53 -0400
commitfd8328be874f4190a811c58cd4778ec2c74d2c05 (patch)
treeb44ae8e99ce96a1a4739b04d4d1a23c40ab8b163 /fs
parent6b335d9c80d7f3c2a3f6545f664ae9007a0f3821 (diff)
[PATCH] sanitize handling of shared descriptor tables in failing execve()
* unshare_files() can fail; doing it after irreversible actions is wrong and de_thread() is certainly irreversible. * since we do it unconditionally anyway, we might as well do it in do_execve() and save ourselves the PITA in binfmt handlers, etc. * while we are at it, binfmt_som actually leaked files_struct on failure. As a side benefit, unshare_files(), put_files_struct() and reset_files_struct() become unexported. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs')
-rw-r--r--fs/binfmt_elf.c23
-rw-r--r--fs/binfmt_misc.c18
-rw-r--r--fs/binfmt_som.c10
-rw-r--r--fs/exec.c34
4 files changed, 20 insertions, 65 deletions
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 5e1a4fb5cacb..9924581df6f6 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -543,7 +543,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
543 unsigned long interp_load_addr = 0; 543 unsigned long interp_load_addr = 0;
544 unsigned long start_code, end_code, start_data, end_data; 544 unsigned long start_code, end_code, start_data, end_data;
545 unsigned long reloc_func_desc = 0; 545 unsigned long reloc_func_desc = 0;
546 struct files_struct *files;
547 int executable_stack = EXSTACK_DEFAULT; 546 int executable_stack = EXSTACK_DEFAULT;
548 unsigned long def_flags = 0; 547 unsigned long def_flags = 0;
549 struct { 548 struct {
@@ -593,20 +592,9 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
593 goto out_free_ph; 592 goto out_free_ph;
594 } 593 }
595 594
596 files = current->files; /* Refcounted so ok */
597 retval = unshare_files();
598 if (retval < 0)
599 goto out_free_ph;
600 if (files == current->files) {
601 put_files_struct(files);
602 files = NULL;
603 }
604
605 /* exec will make our files private anyway, but for the a.out
606 loader stuff we need to do it earlier */
607 retval = get_unused_fd(); 595 retval = get_unused_fd();
608 if (retval < 0) 596 if (retval < 0)
609 goto out_free_fh; 597 goto out_free_ph;
610 get_file(bprm->file); 598 get_file(bprm->file);
611 fd_install(elf_exec_fileno = retval, bprm->file); 599 fd_install(elf_exec_fileno = retval, bprm->file);
612 600
@@ -728,12 +716,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
728 if (retval) 716 if (retval)
729 goto out_free_dentry; 717 goto out_free_dentry;
730 718
731 /* Discard our unneeded old files struct */
732 if (files) {
733 put_files_struct(files);
734 files = NULL;
735 }
736
737 /* OK, This is the point of no return */ 719 /* OK, This is the point of no return */
738 current->flags &= ~PF_FORKNOEXEC; 720 current->flags &= ~PF_FORKNOEXEC;
739 current->mm->def_flags = def_flags; 721 current->mm->def_flags = def_flags;
@@ -1016,9 +998,6 @@ out_free_interp:
1016 kfree(elf_interpreter); 998 kfree(elf_interpreter);
1017out_free_file: 999out_free_file:
1018 sys_close(elf_exec_fileno); 1000 sys_close(elf_exec_fileno);
1019out_free_fh:
1020 if (files)
1021 reset_files_struct(current, files);
1022out_free_ph: 1001out_free_ph:
1023 kfree(elf_phdata); 1002 kfree(elf_phdata);
1024 goto out; 1003 goto out;
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
index b53c7e5f41bb..dbf0ac0523de 100644
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c
@@ -110,7 +110,6 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
110 char *iname_addr = iname; 110 char *iname_addr = iname;
111 int retval; 111 int retval;
112 int fd_binary = -1; 112 int fd_binary = -1;
113 struct files_struct *files = NULL;
114 113
115 retval = -ENOEXEC; 114 retval = -ENOEXEC;
116 if (!enabled) 115 if (!enabled)
@@ -133,21 +132,13 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
133 132
134 if (fmt->flags & MISC_FMT_OPEN_BINARY) { 133 if (fmt->flags & MISC_FMT_OPEN_BINARY) {
135 134
136 files = current->files;
137 retval = unshare_files();
138 if (retval < 0)
139 goto _ret;
140 if (files == current->files) {
141 put_files_struct(files);
142 files = NULL;
143 }
144 /* if the binary should be opened on behalf of the 135 /* if the binary should be opened on behalf of the
145 * interpreter than keep it open and assign descriptor 136 * interpreter than keep it open and assign descriptor
146 * to it */ 137 * to it */
147 fd_binary = get_unused_fd(); 138 fd_binary = get_unused_fd();
148 if (fd_binary < 0) { 139 if (fd_binary < 0) {
149 retval = fd_binary; 140 retval = fd_binary;
150 goto _unshare; 141 goto _ret;
151 } 142 }
152 fd_install(fd_binary, bprm->file); 143 fd_install(fd_binary, bprm->file);
153 144
@@ -205,10 +196,6 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
205 if (retval < 0) 196 if (retval < 0)
206 goto _error; 197 goto _error;
207 198
208 if (files) {
209 put_files_struct(files);
210 files = NULL;
211 }
212_ret: 199_ret:
213 return retval; 200 return retval;
214_error: 201_error:
@@ -216,9 +203,6 @@ _error:
216 sys_close(fd_binary); 203 sys_close(fd_binary);
217 bprm->interp_flags = 0; 204 bprm->interp_flags = 0;
218 bprm->interp_data = 0; 205 bprm->interp_data = 0;
219_unshare:
220 if (files)
221 reset_files_struct(current, files);
222 goto _ret; 206 goto _ret;
223} 207}
224 208
diff --git a/fs/binfmt_som.c b/fs/binfmt_som.c
index 14c63527c762..fdc36bfd6a7b 100644
--- a/fs/binfmt_som.c
+++ b/fs/binfmt_som.c
@@ -194,7 +194,6 @@ load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs)
194 unsigned long som_entry; 194 unsigned long som_entry;
195 struct som_hdr *som_ex; 195 struct som_hdr *som_ex;
196 struct som_exec_auxhdr *hpuxhdr; 196 struct som_exec_auxhdr *hpuxhdr;
197 struct files_struct *files;
198 197
199 /* Get the exec-header */ 198 /* Get the exec-header */
200 som_ex = (struct som_hdr *) bprm->buf; 199 som_ex = (struct som_hdr *) bprm->buf;
@@ -221,15 +220,6 @@ load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs)
221 goto out_free; 220 goto out_free;
222 } 221 }
223 222
224 files = current->files; /* Refcounted so ok */
225 retval = unshare_files();
226 if (retval < 0)
227 goto out_free;
228 if (files == current->files) {
229 put_files_struct(files);
230 files = NULL;
231 }
232
233 retval = get_unused_fd(); 223 retval = get_unused_fd();
234 if (retval < 0) 224 if (retval < 0)
235 goto out_free; 225 goto out_free;
diff --git a/fs/exec.c b/fs/exec.c
index 54a0a557b678..475543002f13 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -953,7 +953,6 @@ int flush_old_exec(struct linux_binprm * bprm)
953{ 953{
954 char * name; 954 char * name;
955 int i, ch, retval; 955 int i, ch, retval;
956 struct files_struct *files;
957 char tcomm[sizeof(current->comm)]; 956 char tcomm[sizeof(current->comm)];
958 957
959 /* 958 /*
@@ -965,26 +964,15 @@ int flush_old_exec(struct linux_binprm * bprm)
965 goto out; 964 goto out;
966 965
967 /* 966 /*
968 * Make sure we have private file handles. Ask the
969 * fork helper to do the work for us and the exit
970 * helper to do the cleanup of the old one.
971 */
972 files = current->files; /* refcounted so safe to hold */
973 retval = unshare_files();
974 if (retval)
975 goto out;
976 /*
977 * Release all of the old mmap stuff 967 * Release all of the old mmap stuff
978 */ 968 */
979 retval = exec_mmap(bprm->mm); 969 retval = exec_mmap(bprm->mm);
980 if (retval) 970 if (retval)
981 goto mmap_failed; 971 goto out;
982 972
983 bprm->mm = NULL; /* We're using it now */ 973 bprm->mm = NULL; /* We're using it now */
984 974
985 /* This is the point of no return */ 975 /* This is the point of no return */
986 put_files_struct(files);
987
988 current->sas_ss_sp = current->sas_ss_size = 0; 976 current->sas_ss_sp = current->sas_ss_size = 0;
989 977
990 if (current->euid == current->uid && current->egid == current->gid) 978 if (current->euid == current->uid && current->egid == current->gid)
@@ -1034,8 +1022,6 @@ int flush_old_exec(struct linux_binprm * bprm)
1034 1022
1035 return 0; 1023 return 0;
1036 1024
1037mmap_failed:
1038 reset_files_struct(current, files);
1039out: 1025out:
1040 return retval; 1026 return retval;
1041} 1027}
@@ -1283,12 +1269,23 @@ int do_execve(char * filename,
1283 struct linux_binprm *bprm; 1269 struct linux_binprm *bprm;
1284 struct file *file; 1270 struct file *file;
1285 unsigned long env_p; 1271 unsigned long env_p;
1272 struct files_struct *files;
1286 int retval; 1273 int retval;
1287 1274
1275 files = current->files;
1276 retval = unshare_files();
1277 if (retval)
1278 goto out_ret;
1279
1280 if (files == current->files) {
1281 put_files_struct(files);
1282 files = NULL;
1283 }
1284
1288 retval = -ENOMEM; 1285 retval = -ENOMEM;
1289 bprm = kzalloc(sizeof(*bprm), GFP_KERNEL); 1286 bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);
1290 if (!bprm) 1287 if (!bprm)
1291 goto out_ret; 1288 goto out_files;
1292 1289
1293 file = open_exec(filename); 1290 file = open_exec(filename);
1294 retval = PTR_ERR(file); 1291 retval = PTR_ERR(file);
@@ -1343,6 +1340,8 @@ int do_execve(char * filename,
1343 security_bprm_free(bprm); 1340 security_bprm_free(bprm);
1344 acct_update_integrals(current); 1341 acct_update_integrals(current);
1345 kfree(bprm); 1342 kfree(bprm);
1343 if (files)
1344 put_files_struct(files);
1346 return retval; 1345 return retval;
1347 } 1346 }
1348 1347
@@ -1363,6 +1362,9 @@ out_file:
1363out_kfree: 1362out_kfree:
1364 kfree(bprm); 1363 kfree(bprm);
1365 1364
1365out_files:
1366 if (files)
1367 reset_files_struct(current, files);
1366out_ret: 1368out_ret:
1367 return retval; 1369 return retval;
1368} 1370}