diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2008-04-22 05:11:59 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2008-04-25 09:23:53 -0400 |
commit | fd8328be874f4190a811c58cd4778ec2c74d2c05 (patch) | |
tree | b44ae8e99ce96a1a4739b04d4d1a23c40ab8b163 /fs | |
parent | 6b335d9c80d7f3c2a3f6545f664ae9007a0f3821 (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.c | 23 | ||||
-rw-r--r-- | fs/binfmt_misc.c | 18 | ||||
-rw-r--r-- | fs/binfmt_som.c | 10 | ||||
-rw-r--r-- | fs/exec.c | 34 |
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); |
1017 | out_free_file: | 999 | out_free_file: |
1018 | sys_close(elf_exec_fileno); | 1000 | sys_close(elf_exec_fileno); |
1019 | out_free_fh: | ||
1020 | if (files) | ||
1021 | reset_files_struct(current, files); | ||
1022 | out_free_ph: | 1001 | out_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; |
@@ -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 | ||
1037 | mmap_failed: | ||
1038 | reset_files_struct(current, files); | ||
1039 | out: | 1025 | out: |
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: | |||
1363 | out_kfree: | 1362 | out_kfree: |
1364 | kfree(bprm); | 1363 | kfree(bprm); |
1365 | 1364 | ||
1365 | out_files: | ||
1366 | if (files) | ||
1367 | reset_files_struct(current, files); | ||
1366 | out_ret: | 1368 | out_ret: |
1367 | return retval; | 1369 | return retval; |
1368 | } | 1370 | } |