Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'exec-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace

Pull execve updates from Eric Biederman:
"Last cycle for the Nth time I ran into bugs and quality of
implementation issues related to exec that could not be easily be
fixed because of the way exec is implemented. So I have been digging
into exec and cleanup up what I can.

I don't think I have exec sorted out enough to fix the issues I
started with but I have made some headway this cycle with 4 sets of
changes.

- promised cleanups after introducing exec_update_mutex

- trivial cleanups for exec

- control flow simplifications

- remove the recomputation of bprm->cred

The net result is code that is a bit easier to understand and work
with and a decrease in the number of lines of code (if you don't count
the added tests)"

* 'exec-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace: (24 commits)
exec: Compute file based creds only once
exec: Add a per bprm->file version of per_clear
binfmt_elf_fdpic: fix execfd build regression
selftests/exec: Add binfmt_script regression test
exec: Remove recursion from search_binary_handler
exec: Generic execfd support
exec/binfmt_script: Don't modify bprm->buf and then return -ENOEXEC
exec: Move the call of prepare_binprm into search_binary_handler
exec: Allow load_misc_binary to call prepare_binprm unconditionally
exec: Convert security_bprm_set_creds into security_bprm_repopulate_creds
exec: Factor security_bprm_creds_for_exec out of security_bprm_set_creds
exec: Teach prepare_exec_creds how exec treats uids & gids
exec: Set the point of no return sooner
exec: Move handling of the point of no return to the top level
exec: Run sync_mm_rss before taking exec_update_mutex
exec: Fix spelling of search_binary_handler in a comment
exec: Move the comment from above de_thread to above unshare_sighand
exec: Rename flush_old_exec begin_new_exec
exec: Move most of setup_new_exec into flush_old_exec
exec: In setup_new_exec cache current in the local variable me
...

+501 -387
+1 -1
Documentation/trace/ftrace.rst
··· 1524 1524 => remove_vma 1525 1525 => exit_mmap 1526 1526 => mmput 1527 - => flush_old_exec 1527 + => begin_new_exec 1528 1528 => load_elf_binary 1529 1529 => search_binary_handler 1530 1530 => __do_execve_file.isra.32
+2 -9
arch/alpha/kernel/binfmt_loader.c
··· 19 19 if (bprm->loader) 20 20 return -ENOEXEC; 21 21 22 - allow_write_access(bprm->file); 23 - fput(bprm->file); 24 - bprm->file = NULL; 25 - 26 22 loader = bprm->vma->vm_end - sizeof(void *); 27 23 28 24 file = open_exec("/sbin/loader"); ··· 29 33 /* Remember if the application is TASO. */ 30 34 bprm->taso = eh->ah.entry < 0x100000000UL; 31 35 32 - bprm->file = file; 36 + bprm->interpreter = file; 33 37 bprm->loader = loader; 34 - retval = prepare_binprm(bprm); 35 - if (retval < 0) 36 - return retval; 37 - return search_binary_handler(bprm); 38 + return 0; 38 39 } 39 40 40 41 static struct linux_binfmt loader_format = {
+1 -3
arch/x86/ia32/ia32_aout.c
··· 131 131 return -ENOMEM; 132 132 133 133 /* Flush all traces of the currently running executable */ 134 - retval = flush_old_exec(bprm); 134 + retval = begin_new_exec(bprm); 135 135 if (retval) 136 136 return retval; 137 137 ··· 155 155 retval = setup_arg_pages(bprm, IA32_STACK_TOP, EXSTACK_DEFAULT); 156 156 if (retval < 0) 157 157 return retval; 158 - 159 - install_exec_creds(bprm); 160 158 161 159 if (N_MAGIC(ex) == OMAGIC) { 162 160 unsigned long text_addr, map_size;
+1 -2
fs/binfmt_aout.c
··· 151 151 return -ENOMEM; 152 152 153 153 /* Flush all traces of the currently running executable */ 154 - retval = flush_old_exec(bprm); 154 + retval = begin_new_exec(bprm); 155 155 if (retval) 156 156 return retval; 157 157 ··· 174 174 if (retval < 0) 175 175 return retval; 176 176 177 - install_exec_creds(bprm); 178 177 179 178 if (N_MAGIC(ex) == OMAGIC) { 180 179 unsigned long text_addr, map_size;
+3 -4
fs/binfmt_elf.c
··· 279 279 NEW_AUX_ENT(AT_BASE_PLATFORM, 280 280 (elf_addr_t)(unsigned long)u_base_platform); 281 281 } 282 - if (bprm->interp_flags & BINPRM_FLAGS_EXECFD) { 283 - NEW_AUX_ENT(AT_EXECFD, bprm->interp_data); 282 + if (bprm->have_execfd) { 283 + NEW_AUX_ENT(AT_EXECFD, bprm->execfd); 284 284 } 285 285 #undef NEW_AUX_ENT 286 286 /* AT_NULL is zero; clear the rest too */ ··· 975 975 goto out_free_dentry; 976 976 977 977 /* Flush all traces of the currently running executable */ 978 - retval = flush_old_exec(bprm); 978 + retval = begin_new_exec(bprm); 979 979 if (retval) 980 980 goto out_free_dentry; 981 981 ··· 989 989 current->flags |= PF_RANDOMIZE; 990 990 991 991 setup_new_exec(bprm); 992 - install_exec_creds(bprm); 993 992 994 993 /* Do this so that we can load the interpreter, if need be. We will 995 994 change some of these later */
+4 -5
fs/binfmt_elf_fdpic.c
··· 338 338 interp_params.flags |= ELF_FDPIC_FLAG_CONSTDISP; 339 339 340 340 /* flush all traces of the currently running executable */ 341 - retval = flush_old_exec(bprm); 341 + retval = begin_new_exec(bprm); 342 342 if (retval) 343 343 goto error; 344 344 ··· 434 434 current->mm->start_stack = current->mm->start_brk + stack_size; 435 435 #endif 436 436 437 - install_exec_creds(bprm); 438 437 if (create_elf_fdpic_tables(bprm, current->mm, 439 438 &exec_params, &interp_params) < 0) 440 439 goto error; ··· 588 589 nitems = 1 + DLINFO_ITEMS + (k_platform ? 1 : 0) + 589 590 (k_base_platform ? 1 : 0) + AT_VECTOR_SIZE_ARCH; 590 591 591 - if (bprm->interp_flags & BINPRM_FLAGS_EXECFD) 592 + if (bprm->have_execfd) 592 593 nitems++; 593 594 594 595 csp = sp; ··· 628 629 (elf_addr_t) (unsigned long) u_base_platform); 629 630 } 630 631 631 - if (bprm->interp_flags & BINPRM_FLAGS_EXECFD) { 632 + if (bprm->have_execfd) { 632 633 nr = 0; 633 634 csp -= 2 * sizeof(unsigned long); 634 - NEW_AUX_ENT(AT_EXECFD, bprm->interp_data); 635 + NEW_AUX_ENT(AT_EXECFD, bprm->execfd); 635 636 } 636 637 637 638 nr = 0;
+2 -11
fs/binfmt_em86.c
··· 48 48 if (bprm->interp_flags & BINPRM_FLAGS_PATH_INACCESSIBLE) 49 49 return -ENOENT; 50 50 51 - allow_write_access(bprm->file); 52 - fput(bprm->file); 53 - bprm->file = NULL; 54 - 55 51 /* Unlike in the script case, we don't have to do any hairy 56 52 * parsing to find our interpreter... it's hardcoded! 57 53 */ ··· 85 89 if (IS_ERR(file)) 86 90 return PTR_ERR(file); 87 91 88 - bprm->file = file; 89 - 90 - retval = prepare_binprm(bprm); 91 - if (retval < 0) 92 - return retval; 93 - 94 - return search_binary_handler(bprm); 92 + bprm->interpreter = file; 93 + return 0; 95 94 } 96 95 97 96 static struct linux_binfmt em86_format = {
+1 -3
fs/binfmt_flat.c
··· 534 534 535 535 /* Flush all traces of the currently running executable */ 536 536 if (id == 0) { 537 - ret = flush_old_exec(bprm); 537 + ret = begin_new_exec(bprm); 538 538 if (ret) 539 539 goto err; 540 540 ··· 962 962 return -EFAULT; 963 963 } 964 964 } 965 - 966 - install_exec_creds(bprm); 967 965 968 966 set_binfmt(&flat_format); 969 967
+10 -59
fs/binfmt_misc.c
··· 134 134 Node *fmt; 135 135 struct file *interp_file = NULL; 136 136 int retval; 137 - int fd_binary = -1; 138 137 139 138 retval = -ENOEXEC; 140 139 if (!enabled) ··· 159 160 goto ret; 160 161 } 161 162 162 - if (fmt->flags & MISC_FMT_OPEN_BINARY) { 163 + if (fmt->flags & MISC_FMT_OPEN_BINARY) 164 + bprm->have_execfd = 1; 163 165 164 - /* if the binary should be opened on behalf of the 165 - * interpreter than keep it open and assign descriptor 166 - * to it 167 - */ 168 - fd_binary = get_unused_fd_flags(0); 169 - if (fd_binary < 0) { 170 - retval = fd_binary; 171 - goto ret; 172 - } 173 - fd_install(fd_binary, bprm->file); 174 - 175 - /* if the binary is not readable than enforce mm->dumpable=0 176 - regardless of the interpreter's permissions */ 177 - would_dump(bprm, bprm->file); 178 - 179 - allow_write_access(bprm->file); 180 - bprm->file = NULL; 181 - 182 - /* mark the bprm that fd should be passed to interp */ 183 - bprm->interp_flags |= BINPRM_FLAGS_EXECFD; 184 - bprm->interp_data = fd_binary; 185 - 186 - } else { 187 - allow_write_access(bprm->file); 188 - fput(bprm->file); 189 - bprm->file = NULL; 190 - } 191 166 /* make argv[1] be the path to the binary */ 192 167 retval = copy_strings_kernel(1, &bprm->interp, bprm); 193 168 if (retval < 0) 194 - goto error; 169 + goto ret; 195 170 bprm->argc++; 196 171 197 172 /* add the interp as argv[0] */ 198 173 retval = copy_strings_kernel(1, &fmt->interpreter, bprm); 199 174 if (retval < 0) 200 - goto error; 175 + goto ret; 201 176 bprm->argc++; 202 177 203 178 /* Update interp in case binfmt_script needs it. */ 204 179 retval = bprm_change_interp(fmt->interpreter, bprm); 205 180 if (retval < 0) 206 - goto error; 181 + goto ret; 207 182 208 183 if (fmt->flags & MISC_FMT_OPEN_FILE) { 209 184 interp_file = file_clone_open(fmt->interp_file); ··· 188 215 } 189 216 retval = PTR_ERR(interp_file); 190 217 if (IS_ERR(interp_file)) 191 - goto error; 218 + goto ret; 192 219 193 - bprm->file = interp_file; 194 - if (fmt->flags & MISC_FMT_CREDENTIALS) { 195 - loff_t pos = 0; 220 + bprm->interpreter = interp_file; 221 + if (fmt->flags & MISC_FMT_CREDENTIALS) 222 + bprm->execfd_creds = 1; 196 223 197 - /* 198 - * No need to call prepare_binprm(), it's already been 199 - * done. bprm->buf is stale, update from interp_file. 200 - */ 201 - memset(bprm->buf, 0, BINPRM_BUF_SIZE); 202 - retval = kernel_read(bprm->file, bprm->buf, BINPRM_BUF_SIZE, 203 - &pos); 204 - } else 205 - retval = prepare_binprm(bprm); 206 - 207 - if (retval < 0) 208 - goto error; 209 - 210 - retval = search_binary_handler(bprm); 211 - if (retval < 0) 212 - goto error; 213 - 224 + retval = 0; 214 225 ret: 215 226 dput(fmt->dentry); 216 227 return retval; 217 - error: 218 - if (fd_binary > 0) 219 - ksys_close(fd_binary); 220 - bprm->interp_flags = 0; 221 - bprm->interp_data = 0; 222 - goto ret; 223 228 } 224 229 225 230 /* Command parsers */
+35 -47
fs/binfmt_script.c
··· 16 16 #include <linux/fs.h> 17 17 18 18 static inline bool spacetab(char c) { return c == ' ' || c == '\t'; } 19 - static inline char *next_non_spacetab(char *first, const char *last) 19 + static inline const char *next_non_spacetab(const char *first, const char *last) 20 20 { 21 21 for (; first <= last; first++) 22 22 if (!spacetab(*first)) 23 23 return first; 24 24 return NULL; 25 25 } 26 - static inline char *next_terminator(char *first, const char *last) 26 + static inline const char *next_terminator(const char *first, const char *last) 27 27 { 28 28 for (; first <= last; first++) 29 29 if (spacetab(*first) || !*first) ··· 33 33 34 34 static int load_script(struct linux_binprm *bprm) 35 35 { 36 - const char *i_arg, *i_name; 37 - char *cp, *buf_end; 36 + const char *i_name, *i_sep, *i_arg, *i_end, *buf_end; 38 37 struct file *file; 39 38 int retval; 40 39 41 40 /* Not ours to exec if we don't start with "#!". */ 42 41 if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!')) 43 42 return -ENOEXEC; 44 - 45 - /* 46 - * If the script filename will be inaccessible after exec, typically 47 - * because it is a "/dev/fd/<fd>/.." path against an O_CLOEXEC fd, give 48 - * up now (on the assumption that the interpreter will want to load 49 - * this file). 50 - */ 51 - if (bprm->interp_flags & BINPRM_FLAGS_PATH_INACCESSIBLE) 52 - return -ENOENT; 53 - 54 - /* Release since we are not mapping a binary into memory. */ 55 - allow_write_access(bprm->file); 56 - fput(bprm->file); 57 - bprm->file = NULL; 58 43 59 44 /* 60 45 * This section handles parsing the #! line into separate ··· 56 71 * parse them on its own. 57 72 */ 58 73 buf_end = bprm->buf + sizeof(bprm->buf) - 1; 59 - cp = strnchr(bprm->buf, sizeof(bprm->buf), '\n'); 60 - if (!cp) { 61 - cp = next_non_spacetab(bprm->buf + 2, buf_end); 62 - if (!cp) 74 + i_end = strnchr(bprm->buf, sizeof(bprm->buf), '\n'); 75 + if (!i_end) { 76 + i_end = next_non_spacetab(bprm->buf + 2, buf_end); 77 + if (!i_end) 63 78 return -ENOEXEC; /* Entire buf is spaces/tabs */ 64 79 /* 65 80 * If there is no later space/tab/NUL we must assume the 66 81 * interpreter path is truncated. 67 82 */ 68 - if (!next_terminator(cp, buf_end)) 83 + if (!next_terminator(i_end, buf_end)) 69 84 return -ENOEXEC; 70 - cp = buf_end; 85 + i_end = buf_end; 71 86 } 72 - /* NUL-terminate the buffer and any trailing spaces/tabs. */ 73 - *cp = '\0'; 74 - while (cp > bprm->buf) { 75 - cp--; 76 - if ((*cp == ' ') || (*cp == '\t')) 77 - *cp = '\0'; 78 - else 79 - break; 80 - } 81 - for (cp = bprm->buf+2; (*cp == ' ') || (*cp == '\t'); cp++); 82 - if (*cp == '\0') 87 + /* Trim any trailing spaces/tabs from i_end */ 88 + while (spacetab(i_end[-1])) 89 + i_end--; 90 + 91 + /* Skip over leading spaces/tabs */ 92 + i_name = next_non_spacetab(bprm->buf+2, i_end); 93 + if (!i_name || (i_name == i_end)) 83 94 return -ENOEXEC; /* No interpreter name found */ 84 - i_name = cp; 95 + 96 + /* Is there an optional argument? */ 85 97 i_arg = NULL; 86 - for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++) 87 - /* nothing */ ; 88 - while ((*cp == ' ') || (*cp == '\t')) 89 - *cp++ = '\0'; 90 - if (*cp) 91 - i_arg = cp; 98 + i_sep = next_terminator(i_name, i_end); 99 + if (i_sep && (*i_sep != '\0')) 100 + i_arg = next_non_spacetab(i_sep, i_end); 101 + 102 + /* 103 + * If the script filename will be inaccessible after exec, typically 104 + * because it is a "/dev/fd/<fd>/.." path against an O_CLOEXEC fd, give 105 + * up now (on the assumption that the interpreter will want to load 106 + * this file). 107 + */ 108 + if (bprm->interp_flags & BINPRM_FLAGS_PATH_INACCESSIBLE) 109 + return -ENOENT; 110 + 92 111 /* 93 112 * OK, we've parsed out the interpreter name and 94 113 * (optional) argument. ··· 110 121 if (retval < 0) 111 122 return retval; 112 123 bprm->argc++; 124 + *((char *)i_end) = '\0'; 113 125 if (i_arg) { 126 + *((char *)i_sep) = '\0'; 114 127 retval = copy_strings_kernel(1, &i_arg, bprm); 115 128 if (retval < 0) 116 129 return retval; ··· 133 142 if (IS_ERR(file)) 134 143 return PTR_ERR(file); 135 144 136 - bprm->file = file; 137 - retval = prepare_binprm(bprm); 138 - if (retval < 0) 139 - return retval; 140 - return search_binary_handler(bprm); 145 + bprm->interpreter = file; 146 + return 0; 141 147 } 142 148 143 149 static struct linux_binfmt script_format = {
+173 -143
fs/exec.c
··· 72 72 73 73 #include <trace/events/sched.h> 74 74 75 + static int bprm_creds_from_file(struct linux_binprm *bprm); 76 + 75 77 int suid_dumpable = 0; 76 78 77 79 static LIST_HEAD(formats); ··· 1053 1051 tsk = current; 1054 1052 old_mm = current->mm; 1055 1053 exec_mm_release(tsk, old_mm); 1054 + if (old_mm) 1055 + sync_mm_rss(old_mm); 1056 1056 1057 1057 ret = mutex_lock_killable(&tsk->signal->exec_update_mutex); 1058 1058 if (ret) 1059 1059 return ret; 1060 1060 1061 1061 if (old_mm) { 1062 - sync_mm_rss(old_mm); 1063 1062 /* 1064 1063 * Make sure that if there is a core dump in progress 1065 1064 * for the old mm, we get out and die instead of going ··· 1096 1093 return 0; 1097 1094 } 1098 1095 1099 - /* 1100 - * This function makes sure the current process has its own signal table, 1101 - * so that flush_signal_handlers can later reset the handlers without 1102 - * disturbing other processes. (Other processes might share the signal 1103 - * table via the CLONE_SIGHAND option to clone().) 1104 - */ 1105 1096 static int de_thread(struct task_struct *tsk) 1106 1097 { 1107 1098 struct signal_struct *sig = tsk->signal; ··· 1233 1236 } 1234 1237 1235 1238 1239 + /* 1240 + * This function makes sure the current process has its own signal table, 1241 + * so that flush_signal_handlers can later reset the handlers without 1242 + * disturbing other processes. (Other processes might share the signal 1243 + * table via the CLONE_SIGHAND option to clone().) 1244 + */ 1236 1245 static int unshare_sighand(struct task_struct *me) 1237 1246 { 1238 1247 struct sighand_struct *oldsighand = me->sighand; ··· 1295 1292 * Calling this is the point of no return. None of the failures will be 1296 1293 * seen by userspace since either the process is already taking a fatal 1297 1294 * signal (via de_thread() or coredump), or will have SEGV raised 1298 - * (after exec_mmap()) by search_binary_handlers (see below). 1295 + * (after exec_mmap()) by search_binary_handler (see below). 1299 1296 */ 1300 - int flush_old_exec(struct linux_binprm * bprm) 1297 + int begin_new_exec(struct linux_binprm * bprm) 1301 1298 { 1302 1299 struct task_struct *me = current; 1303 1300 int retval; 1301 + 1302 + /* Once we are committed compute the creds */ 1303 + retval = bprm_creds_from_file(bprm); 1304 + if (retval) 1305 + return retval; 1306 + 1307 + /* 1308 + * Ensure all future errors are fatal. 1309 + */ 1310 + bprm->point_of_no_return = true; 1304 1311 1305 1312 /* 1306 1313 * Make this the only thread in the thread group. ··· 1326 1313 */ 1327 1314 set_mm_exe_file(bprm->mm, bprm->file); 1328 1315 1316 + /* If the binary is not readable then enforce mm->dumpable=0 */ 1329 1317 would_dump(bprm, bprm->file); 1318 + if (bprm->have_execfd) 1319 + would_dump(bprm, bprm->executable); 1330 1320 1331 1321 /* 1332 1322 * Release all of the old mmap stuff ··· 1339 1323 if (retval) 1340 1324 goto out; 1341 1325 1342 - /* 1343 - * After setting bprm->called_exec_mmap (to mark that current is 1344 - * using the prepared mm now), we have nothing left of the original 1345 - * process. If anything from here on returns an error, the check 1346 - * in search_binary_handler() will SEGV current. 1347 - */ 1348 - bprm->called_exec_mmap = 1; 1349 1326 bprm->mm = NULL; 1350 1327 1351 1328 #ifdef CONFIG_POSIX_TIMERS ··· 1351 1342 */ 1352 1343 retval = unshare_sighand(me); 1353 1344 if (retval) 1354 - goto out; 1345 + goto out_unlock; 1355 1346 1356 1347 set_fs(USER_DS); 1357 1348 me->flags &= ~(PF_RANDOMIZE | PF_FORKNOEXEC | PF_KTHREAD | ··· 1366 1357 * undergoing exec(2). 1367 1358 */ 1368 1359 do_close_on_exec(me->files); 1360 + 1361 + if (bprm->secureexec) { 1362 + /* Make sure parent cannot signal privileged process. */ 1363 + me->pdeath_signal = 0; 1364 + 1365 + /* 1366 + * For secureexec, reset the stack limit to sane default to 1367 + * avoid bad behavior from the prior rlimits. This has to 1368 + * happen before arch_pick_mmap_layout(), which examines 1369 + * RLIMIT_STACK, but after the point of no return to avoid 1370 + * needing to clean up the change on failure. 1371 + */ 1372 + if (bprm->rlim_stack.rlim_cur > _STK_LIM) 1373 + bprm->rlim_stack.rlim_cur = _STK_LIM; 1374 + } 1375 + 1376 + me->sas_ss_sp = me->sas_ss_size = 0; 1377 + 1378 + /* 1379 + * Figure out dumpability. Note that this checking only of current 1380 + * is wrong, but userspace depends on it. This should be testing 1381 + * bprm->secureexec instead. 1382 + */ 1383 + if (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP || 1384 + !(uid_eq(current_euid(), current_uid()) && 1385 + gid_eq(current_egid(), current_gid()))) 1386 + set_dumpable(current->mm, suid_dumpable); 1387 + else 1388 + set_dumpable(current->mm, SUID_DUMP_USER); 1389 + 1390 + perf_event_exec(); 1391 + __set_task_comm(me, kbasename(bprm->filename), true); 1392 + 1393 + /* An exec changes our domain. We are no longer part of the thread 1394 + group */ 1395 + WRITE_ONCE(me->self_exec_id, me->self_exec_id + 1); 1396 + flush_signal_handlers(me, 0); 1397 + 1398 + /* 1399 + * install the new credentials for this executable 1400 + */ 1401 + security_bprm_committing_creds(bprm); 1402 + 1403 + commit_creds(bprm->cred); 1404 + bprm->cred = NULL; 1405 + 1406 + /* 1407 + * Disable monitoring for regular users 1408 + * when executing setuid binaries. Must 1409 + * wait until new credentials are committed 1410 + * by commit_creds() above 1411 + */ 1412 + if (get_dumpable(me->mm) != SUID_DUMP_USER) 1413 + perf_event_exit_task(me); 1414 + /* 1415 + * cred_guard_mutex must be held at least to this point to prevent 1416 + * ptrace_attach() from altering our determination of the task's 1417 + * credentials; any time after this it may be unlocked. 1418 + */ 1419 + security_bprm_committed_creds(bprm); 1420 + 1421 + /* Pass the opened binary to the interpreter. */ 1422 + if (bprm->have_execfd) { 1423 + retval = get_unused_fd_flags(0); 1424 + if (retval < 0) 1425 + goto out_unlock; 1426 + fd_install(retval, bprm->executable); 1427 + bprm->executable = NULL; 1428 + bprm->execfd = retval; 1429 + } 1369 1430 return 0; 1370 1431 1432 + out_unlock: 1433 + mutex_unlock(&me->signal->exec_update_mutex); 1371 1434 out: 1372 1435 return retval; 1373 1436 } 1374 - EXPORT_SYMBOL(flush_old_exec); 1437 + EXPORT_SYMBOL(begin_new_exec); 1375 1438 1376 1439 void would_dump(struct linux_binprm *bprm, struct file *file) 1377 1440 { ··· 1468 1387 1469 1388 void setup_new_exec(struct linux_binprm * bprm) 1470 1389 { 1471 - /* 1472 - * Once here, prepare_binrpm() will not be called any more, so 1473 - * the final state of setuid/setgid/fscaps can be merged into the 1474 - * secureexec flag. 1475 - */ 1476 - bprm->secureexec |= bprm->cap_elevated; 1390 + /* Setup things that can depend upon the personality */ 1391 + struct task_struct *me = current; 1477 1392 1478 - if (bprm->secureexec) { 1479 - /* Make sure parent cannot signal privileged process. */ 1480 - current->pdeath_signal = 0; 1481 - 1482 - /* 1483 - * For secureexec, reset the stack limit to sane default to 1484 - * avoid bad behavior from the prior rlimits. This has to 1485 - * happen before arch_pick_mmap_layout(), which examines 1486 - * RLIMIT_STACK, but after the point of no return to avoid 1487 - * needing to clean up the change on failure. 1488 - */ 1489 - if (bprm->rlim_stack.rlim_cur > _STK_LIM) 1490 - bprm->rlim_stack.rlim_cur = _STK_LIM; 1491 - } 1492 - 1493 - arch_pick_mmap_layout(current->mm, &bprm->rlim_stack); 1494 - 1495 - current->sas_ss_sp = current->sas_ss_size = 0; 1496 - 1497 - /* 1498 - * Figure out dumpability. Note that this checking only of current 1499 - * is wrong, but userspace depends on it. This should be testing 1500 - * bprm->secureexec instead. 1501 - */ 1502 - if (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP || 1503 - !(uid_eq(current_euid(), current_uid()) && 1504 - gid_eq(current_egid(), current_gid()))) 1505 - set_dumpable(current->mm, suid_dumpable); 1506 - else 1507 - set_dumpable(current->mm, SUID_DUMP_USER); 1393 + arch_pick_mmap_layout(me->mm, &bprm->rlim_stack); 1508 1394 1509 1395 arch_setup_new_exec(); 1510 - perf_event_exec(); 1511 - __set_task_comm(current, kbasename(bprm->filename), true); 1512 1396 1513 1397 /* Set the new mm task size. We have to do that late because it may 1514 1398 * depend on TIF_32BIT which is only updated in flush_thread() on 1515 1399 * some architectures like powerpc 1516 1400 */ 1517 - current->mm->task_size = TASK_SIZE; 1518 - 1519 - /* An exec changes our domain. We are no longer part of the thread 1520 - group */ 1521 - WRITE_ONCE(current->self_exec_id, current->self_exec_id + 1); 1522 - flush_signal_handlers(current, 0); 1401 + me->mm->task_size = TASK_SIZE; 1402 + mutex_unlock(&me->signal->exec_update_mutex); 1403 + mutex_unlock(&me->signal->cred_guard_mutex); 1523 1404 } 1524 1405 EXPORT_SYMBOL(setup_new_exec); 1525 1406 ··· 1497 1454 1498 1455 /* 1499 1456 * Prepare credentials and lock ->cred_guard_mutex. 1500 - * install_exec_creds() commits the new creds and drops the lock. 1457 + * setup_new_exec() commits the new creds and drops the lock. 1501 1458 * Or, if exec fails before, free_bprm() should release ->cred and 1502 1459 * and unlock. 1503 1460 */ ··· 1518 1475 { 1519 1476 free_arg_pages(bprm); 1520 1477 if (bprm->cred) { 1521 - if (bprm->called_exec_mmap) 1522 - mutex_unlock(&current->signal->exec_update_mutex); 1523 1478 mutex_unlock(&current->signal->cred_guard_mutex); 1524 1479 abort_creds(bprm->cred); 1525 1480 } ··· 1525 1484 allow_write_access(bprm->file); 1526 1485 fput(bprm->file); 1527 1486 } 1487 + if (bprm->executable) 1488 + fput(bprm->executable); 1528 1489 /* If a binfmt changed the interp, free it. */ 1529 1490 if (bprm->interp != bprm->filename) 1530 1491 kfree(bprm->interp); ··· 1544 1501 return 0; 1545 1502 } 1546 1503 EXPORT_SYMBOL(bprm_change_interp); 1547 - 1548 - /* 1549 - * install the new credentials for this executable 1550 - */ 1551 - void install_exec_creds(struct linux_binprm *bprm) 1552 - { 1553 - security_bprm_committing_creds(bprm); 1554 - 1555 - commit_creds(bprm->cred); 1556 - bprm->cred = NULL; 1557 - 1558 - /* 1559 - * Disable monitoring for regular users 1560 - * when executing setuid binaries. Must 1561 - * wait until new credentials are committed 1562 - * by commit_creds() above 1563 - */ 1564 - if (get_dumpable(current->mm) != SUID_DUMP_USER) 1565 - perf_event_exit_task(current); 1566 - /* 1567 - * cred_guard_mutex must be held at least to this point to prevent 1568 - * ptrace_attach() from altering our determination of the task's 1569 - * credentials; any time after this it may be unlocked. 1570 - */ 1571 - security_bprm_committed_creds(bprm); 1572 - mutex_unlock(&current->signal->exec_update_mutex); 1573 - mutex_unlock(&current->signal->cred_guard_mutex); 1574 - } 1575 - EXPORT_SYMBOL(install_exec_creds); 1576 1504 1577 1505 /* 1578 1506 * determine how safe it is to execute the proposed program ··· 1582 1568 spin_unlock(&p->fs->lock); 1583 1569 } 1584 1570 1585 - static void bprm_fill_uid(struct linux_binprm *bprm) 1571 + static void bprm_fill_uid(struct linux_binprm *bprm, struct file *file) 1586 1572 { 1573 + /* Handle suid and sgid on files */ 1587 1574 struct inode *inode; 1588 1575 unsigned int mode; 1589 1576 kuid_t uid; 1590 1577 kgid_t gid; 1591 1578 1592 - /* 1593 - * Since this can be called multiple times (via prepare_binprm), 1594 - * we must clear any previous work done when setting set[ug]id 1595 - * bits from any earlier bprm->file uses (for example when run 1596 - * first for a setuid script then again for its interpreter). 1597 - */ 1598 - bprm->cred->euid = current_euid(); 1599 - bprm->cred->egid = current_egid(); 1600 - 1601 - if (!mnt_may_suid(bprm->file->f_path.mnt)) 1579 + if (!mnt_may_suid(file->f_path.mnt)) 1602 1580 return; 1603 1581 1604 1582 if (task_no_new_privs(current)) 1605 1583 return; 1606 1584 1607 - inode = bprm->file->f_path.dentry->d_inode; 1585 + inode = file->f_path.dentry->d_inode; 1608 1586 mode = READ_ONCE(inode->i_mode); 1609 1587 if (!(mode & (S_ISUID|S_ISGID))) 1610 1588 return; ··· 1627 1621 } 1628 1622 1629 1623 /* 1624 + * Compute brpm->cred based upon the final binary. 1625 + */ 1626 + static int bprm_creds_from_file(struct linux_binprm *bprm) 1627 + { 1628 + /* Compute creds based on which file? */ 1629 + struct file *file = bprm->execfd_creds ? bprm->executable : bprm->file; 1630 + 1631 + bprm_fill_uid(bprm, file); 1632 + return security_bprm_creds_from_file(bprm, file); 1633 + } 1634 + 1635 + /* 1630 1636 * Fill the binprm structure from the inode. 1631 - * Check permissions, then read the first BINPRM_BUF_SIZE bytes 1637 + * Read the first BINPRM_BUF_SIZE bytes 1632 1638 * 1633 1639 * This may be called multiple times for binary chains (scripts for example). 1634 1640 */ 1635 - int prepare_binprm(struct linux_binprm *bprm) 1641 + static int prepare_binprm(struct linux_binprm *bprm) 1636 1642 { 1637 - int retval; 1638 1643 loff_t pos = 0; 1639 - 1640 - bprm_fill_uid(bprm); 1641 - 1642 - /* fill in binprm security blob */ 1643 - retval = security_bprm_set_creds(bprm); 1644 - if (retval) 1645 - return retval; 1646 - bprm->called_set_creds = 1; 1647 1644 1648 1645 memset(bprm->buf, 0, BINPRM_BUF_SIZE); 1649 1646 return kernel_read(bprm->file, bprm->buf, BINPRM_BUF_SIZE, &pos); 1650 1647 } 1651 - 1652 - EXPORT_SYMBOL(prepare_binprm); 1653 1648 1654 1649 /* 1655 1650 * Arguments are '\0' separated strings found at the location bprm->p ··· 1697 1690 /* 1698 1691 * cycle the list of binary formats handler, until one recognizes the image 1699 1692 */ 1700 - int search_binary_handler(struct linux_binprm *bprm) 1693 + static int search_binary_handler(struct linux_binprm *bprm) 1701 1694 { 1702 1695 bool need_retry = IS_ENABLED(CONFIG_MODULES); 1703 1696 struct linux_binfmt *fmt; 1704 1697 int retval; 1705 1698 1706 - /* This allows 4 levels of binfmt rewrites before failing hard. */ 1707 - if (bprm->recursion_depth > 5) 1708 - return -ELOOP; 1699 + retval = prepare_binprm(bprm); 1700 + if (retval < 0) 1701 + return retval; 1709 1702 1710 1703 retval = security_bprm_check(bprm); 1711 1704 if (retval) ··· 1719 1712 continue; 1720 1713 read_unlock(&binfmt_lock); 1721 1714 1722 - bprm->recursion_depth++; 1723 1715 retval = fmt->load_binary(bprm); 1724 - bprm->recursion_depth--; 1725 1716 1726 1717 read_lock(&binfmt_lock); 1727 1718 put_binfmt(fmt); 1728 - if (retval < 0 && bprm->called_exec_mmap) { 1729 - /* we got to flush_old_exec() and failed after it */ 1730 - read_unlock(&binfmt_lock); 1731 - force_sigsegv(SIGSEGV); 1732 - return retval; 1733 - } 1734 - if (retval != -ENOEXEC || !bprm->file) { 1719 + if (bprm->point_of_no_return || (retval != -ENOEXEC)) { 1735 1720 read_unlock(&binfmt_lock); 1736 1721 return retval; 1737 1722 } ··· 1742 1743 1743 1744 return retval; 1744 1745 } 1745 - EXPORT_SYMBOL(search_binary_handler); 1746 1746 1747 1747 static int exec_binprm(struct linux_binprm *bprm) 1748 1748 { 1749 1749 pid_t old_pid, old_vpid; 1750 - int ret; 1750 + int ret, depth; 1751 1751 1752 1752 /* Need to fetch pid before load_binary changes it */ 1753 1753 old_pid = current->pid; ··· 1754 1756 old_vpid = task_pid_nr_ns(current, task_active_pid_ns(current->parent)); 1755 1757 rcu_read_unlock(); 1756 1758 1757 - ret = search_binary_handler(bprm); 1758 - if (ret >= 0) { 1759 - audit_bprm(bprm); 1760 - trace_sched_process_exec(current, old_pid, bprm); 1761 - ptrace_event(PTRACE_EVENT_EXEC, old_vpid); 1762 - proc_exec_connector(current); 1759 + /* This allows 4 levels of binfmt rewrites before failing hard. */ 1760 + for (depth = 0;; depth++) { 1761 + struct file *exec; 1762 + if (depth > 5) 1763 + return -ELOOP; 1764 + 1765 + ret = search_binary_handler(bprm); 1766 + if (ret < 0) 1767 + return ret; 1768 + if (!bprm->interpreter) 1769 + break; 1770 + 1771 + exec = bprm->file; 1772 + bprm->file = bprm->interpreter; 1773 + bprm->interpreter = NULL; 1774 + 1775 + allow_write_access(exec); 1776 + if (unlikely(bprm->have_execfd)) { 1777 + if (bprm->executable) { 1778 + fput(exec); 1779 + return -ENOEXEC; 1780 + } 1781 + bprm->executable = exec; 1782 + } else 1783 + fput(exec); 1763 1784 } 1764 1785 1765 - return ret; 1786 + audit_bprm(bprm); 1787 + trace_sched_process_exec(current, old_pid, bprm); 1788 + ptrace_event(PTRACE_EVENT_EXEC, old_vpid); 1789 + proc_exec_connector(current); 1790 + return 0; 1766 1791 } 1767 1792 1768 1793 /* ··· 1878 1857 if (retval < 0) 1879 1858 goto out; 1880 1859 1881 - retval = prepare_binprm(bprm); 1882 - if (retval < 0) 1860 + /* Set the unchanging part of bprm->cred */ 1861 + retval = security_bprm_creds_for_exec(bprm); 1862 + if (retval) 1883 1863 goto out; 1884 1864 1885 1865 retval = copy_strings_kernel(1, &bprm->filename, bprm); ··· 1915 1893 return retval; 1916 1894 1917 1895 out: 1896 + /* 1897 + * If past the point of no return ensure the the code never 1898 + * returns to the userspace process. Use an existing fatal 1899 + * signal if present otherwise terminate the process with 1900 + * SIGSEGV. 1901 + */ 1902 + if (bprm->point_of_no_return && !fatal_signal_pending(current)) 1903 + force_sigsegv(SIGSEGV); 1918 1904 if (bprm->mm) { 1919 1905 acct_arg_size(bprm, 0); 1920 1906 mmput(bprm->mm);
+15 -30
include/linux/binfmts.h
··· 26 26 unsigned long p; /* current top of mem */ 27 27 unsigned long argmin; /* rlimit marker for copy_strings() */ 28 28 unsigned int 29 + /* Should an execfd be passed to userspace? */ 30 + have_execfd:1, 31 + 32 + /* Use the creds of a script (see binfmt_misc) */ 33 + execfd_creds:1, 29 34 /* 30 - * True after the bprm_set_creds hook has been called once 31 - * (multiple calls can be made via prepare_binprm() for 32 - * binfmt_script/misc). 33 - */ 34 - called_set_creds:1, 35 - /* 36 - * True if most recent call to the commoncaps bprm_set_creds 37 - * hook (due to multiple prepare_binprm() calls from the 38 - * binfmt_script/misc handlers) resulted in elevated 39 - * privileges. 40 - */ 41 - cap_elevated:1, 42 - /* 43 - * Set by bprm_set_creds hook to indicate a privilege-gaining 44 - * exec has happened. Used to sanitize execution environment 45 - * and to set AT_SECURE auxv for glibc. 35 + * Set by bprm_creds_for_exec hook to indicate a 36 + * privilege-gaining exec has happened. Used to set 37 + * AT_SECURE auxv for glibc. 46 38 */ 47 39 secureexec:1, 48 40 /* 49 - * Set by flush_old_exec, when exec_mmap has been called. 50 - * This is past the point of no return, when the 51 - * exec_update_mutex has been taken. 41 + * Set when errors can no longer be returned to the 42 + * original userspace. 52 43 */ 53 - called_exec_mmap:1; 44 + point_of_no_return:1; 54 45 #ifdef __alpha__ 55 46 unsigned int taso:1; 56 47 #endif 57 - unsigned int recursion_depth; /* only for search_binary_handler() */ 48 + struct file * executable; /* Executable to pass to the interpreter */ 49 + struct file * interpreter; 58 50 struct file * file; 59 51 struct cred *cred; /* new credentials */ 60 52 int unsafe; /* how unsafe this exec is (mask of LSM_UNSAFE_*) */ ··· 57 65 of the time same as filename, but could be 58 66 different for binfmt_{misc,script} */ 59 67 unsigned interp_flags; 60 - unsigned interp_data; 68 + int execfd; /* File descriptor of the executable */ 61 69 unsigned long loader, exec; 62 70 63 71 struct rlimit rlim_stack; /* Saved RLIMIT_STACK used during exec. */ ··· 67 75 68 76 #define BINPRM_FLAGS_ENFORCE_NONDUMP_BIT 0 69 77 #define BINPRM_FLAGS_ENFORCE_NONDUMP (1 << BINPRM_FLAGS_ENFORCE_NONDUMP_BIT) 70 - 71 - /* fd of the binary should be passed to the interpreter */ 72 - #define BINPRM_FLAGS_EXECFD_BIT 1 73 - #define BINPRM_FLAGS_EXECFD (1 << BINPRM_FLAGS_EXECFD_BIT) 74 78 75 79 /* filename of the binary will be inaccessible after exec */ 76 80 #define BINPRM_FLAGS_PATH_INACCESSIBLE_BIT 2 ··· 111 123 112 124 extern void unregister_binfmt(struct linux_binfmt *); 113 125 114 - extern int prepare_binprm(struct linux_binprm *); 115 126 extern int __must_check remove_arg_zero(struct linux_binprm *); 116 - extern int search_binary_handler(struct linux_binprm *); 117 - extern int flush_old_exec(struct linux_binprm * bprm); 127 + extern int begin_new_exec(struct linux_binprm * bprm); 118 128 extern void setup_new_exec(struct linux_binprm * bprm); 119 129 extern void finalize_exec(struct linux_binprm *bprm); 120 130 extern void would_dump(struct linux_binprm *, struct file *); ··· 132 146 extern int bprm_change_interp(const char *interp, struct linux_binprm *bprm); 133 147 extern int copy_strings_kernel(int argc, const char *const *argv, 134 148 struct linux_binprm *bprm); 135 - extern void install_exec_creds(struct linux_binprm *bprm); 136 149 extern void set_binfmt(struct linux_binfmt *new); 137 150 extern ssize_t read_code(struct file *, unsigned long, loff_t, size_t); 138 151
+2 -1
include/linux/lsm_hook_defs.h
··· 49 49 LSM_HOOK(int, 0, settime, const struct timespec64 *ts, 50 50 const struct timezone *tz) 51 51 LSM_HOOK(int, 0, vm_enough_memory, struct mm_struct *mm, long pages) 52 - LSM_HOOK(int, 0, bprm_set_creds, struct linux_binprm *bprm) 52 + LSM_HOOK(int, 0, bprm_creds_for_exec, struct linux_binprm *bprm) 53 + LSM_HOOK(int, 0, bprm_creds_from_file, struct linux_binprm *bprm, struct file *file) 53 54 LSM_HOOK(int, 0, bprm_check_security, struct linux_binprm *bprm) 54 55 LSM_HOOK(void, LSM_RET_VOID, bprm_committing_creds, struct linux_binprm *bprm) 55 56 LSM_HOOK(void, LSM_RET_VOID, bprm_committed_creds, struct linux_binprm *bprm)
+32 -24
include/linux/lsm_hooks.h
··· 34 34 * 35 35 * Security hooks for program execution operations. 36 36 * 37 - * @bprm_set_creds: 38 - * Save security information in the bprm->security field, typically based 39 - * on information about the bprm->file, for later use by the apply_creds 40 - * hook. This hook may also optionally check permissions (e.g. for 41 - * transitions between security domains). 42 - * This hook may be called multiple times during a single execve, e.g. for 43 - * interpreters. The hook can tell whether it has already been called by 44 - * checking to see if @bprm->security is non-NULL. If so, then the hook 45 - * may decide either to retain the security information saved earlier or 46 - * to replace it. The hook must set @bprm->secureexec to 1 if a "secure 47 - * exec" has happened as a result of this hook call. The flag is used to 48 - * indicate the need for a sanitized execution environment, and is also 49 - * passed in the ELF auxiliary table on the initial stack to indicate 50 - * whether libc should enable secure mode. 37 + * @bprm_creds_for_exec: 38 + * If the setup in prepare_exec_creds did not setup @bprm->cred->security 39 + * properly for executing @bprm->file, update the LSM's portion of 40 + * @bprm->cred->security to be what commit_creds needs to install for the 41 + * new program. This hook may also optionally check permissions 42 + * (e.g. for transitions between security domains). 43 + * The hook must set @bprm->secureexec to 1 if AT_SECURE should be set to 44 + * request libc enable secure mode. 45 + * @bprm contains the linux_binprm structure. 46 + * Return 0 if the hook is successful and permission is granted. 47 + * @bprm_creds_from_file: 48 + * If @file is setpcap, suid, sgid or otherwise marked to change 49 + * privilege upon exec, update @bprm->cred to reflect that change. 50 + * This is called after finding the binary that will be executed. 51 + * without an interpreter. This ensures that the credentials will not 52 + * be derived from a script that the binary will need to reopen, which 53 + * when reopend may end up being a completely different file. This 54 + * hook may also optionally check permissions (e.g. for transitions 55 + * between security domains). 56 + * The hook must set @bprm->secureexec to 1 if AT_SECURE should be set to 57 + * request libc enable secure mode. 58 + * The hook must add to @bprm->per_clear any personality flags that 59 + * should be cleared from current->personality. 51 60 * @bprm contains the linux_binprm structure. 52 61 * Return 0 if the hook is successful and permission is granted. 53 62 * @bprm_check_security: 54 63 * This hook mediates the point when a search for a binary handler will 55 - * begin. It allows a check the @bprm->security value which is set in the 56 - * preceding set_creds call. The primary difference from set_creds is 57 - * that the argv list and envp list are reliably available in @bprm. This 58 - * hook may be called multiple times during a single execve; and in each 59 - * pass set_creds is called first. 64 + * begin. It allows a check against the @bprm->cred->security value 65 + * which was set in the preceding creds_for_exec call. The argv list and 66 + * envp list are reliably available in @bprm. This hook may be called 67 + * multiple times during a single execve. 60 68 * @bprm contains the linux_binprm structure. 61 69 * Return 0 if the hook is successful and permission is granted. 62 70 * @bprm_committing_creds: 63 71 * Prepare to install the new security attributes of a process being 64 72 * transformed by an execve operation, based on the old credentials 65 73 * pointed to by @current->cred and the information set in @bprm->cred by 66 - * the bprm_set_creds hook. @bprm points to the linux_binprm structure. 67 - * This hook is a good place to perform state changes on the process such 68 - * as closing open file descriptors to which access will no longer be 69 - * granted when the attributes are changed. This is called immediately 70 - * before commit_creds(). 74 + * the bprm_creds_for_exec hook. @bprm points to the linux_binprm 75 + * structure. This hook is a good place to perform state changes on the 76 + * process such as closing open file descriptors to which access will no 77 + * longer be granted when the attributes are changed. This is called 78 + * immediately before commit_creds(). 71 79 * @bprm_committed_creds: 72 80 * Tidy up after the installation of the new security attributes of a 73 81 * process being transformed by an execve operation. The new credentials
+11 -4
include/linux/security.h
··· 140 140 const kernel_cap_t *effective, 141 141 const kernel_cap_t *inheritable, 142 142 const kernel_cap_t *permitted); 143 - extern int cap_bprm_set_creds(struct linux_binprm *bprm); 143 + extern int cap_bprm_creds_from_file(struct linux_binprm *bprm, struct file *file); 144 144 extern int cap_inode_setxattr(struct dentry *dentry, const char *name, 145 145 const void *value, size_t size, int flags); 146 146 extern int cap_inode_removexattr(struct dentry *dentry, const char *name); ··· 276 276 int security_syslog(int type); 277 277 int security_settime64(const struct timespec64 *ts, const struct timezone *tz); 278 278 int security_vm_enough_memory_mm(struct mm_struct *mm, long pages); 279 - int security_bprm_set_creds(struct linux_binprm *bprm); 279 + int security_bprm_creds_for_exec(struct linux_binprm *bprm); 280 + int security_bprm_creds_from_file(struct linux_binprm *bprm, struct file *file); 280 281 int security_bprm_check(struct linux_binprm *bprm); 281 282 void security_bprm_committing_creds(struct linux_binprm *bprm); 282 283 void security_bprm_committed_creds(struct linux_binprm *bprm); ··· 570 569 return __vm_enough_memory(mm, pages, cap_vm_enough_memory(mm, pages)); 571 570 } 572 571 573 - static inline int security_bprm_set_creds(struct linux_binprm *bprm) 572 + static inline int security_bprm_creds_for_exec(struct linux_binprm *bprm) 574 573 { 575 - return cap_bprm_set_creds(bprm); 574 + return 0; 575 + } 576 + 577 + static inline int security_bprm_creds_from_file(struct linux_binprm *bprm, 578 + struct file *file) 579 + { 580 + return cap_bprm_creds_from_file(bprm, file); 576 581 } 577 582 578 583 static inline int security_bprm_check(struct linux_binprm *bprm)
+3
kernel/cred.c
··· 315 315 new->process_keyring = NULL; 316 316 #endif 317 317 318 + new->suid = new->fsuid = new->euid; 319 + new->sgid = new->fsgid = new->egid; 320 + 318 321 return new; 319 322 } 320 323
+1 -1
kernel/events/core.c
··· 12220 12220 * When a child task exits, feed back event values to parent events. 12221 12221 * 12222 12222 * Can be called with exec_update_mutex held when called from 12223 - * install_exec_creds(). 12223 + * setup_new_exec(). 12224 12224 */ 12225 12225 void perf_event_exit_task(struct task_struct *child) 12226 12226 {
+2 -5
security/apparmor/domain.c
··· 854 854 } 855 855 856 856 /** 857 - * apparmor_bprm_set_creds - set the new creds on the bprm struct 857 + * apparmor_bprm_creds_for_exec - Update the new creds on the bprm struct 858 858 * @bprm: binprm for the exec (NOT NULL) 859 859 * 860 860 * Returns: %0 or error on failure 861 861 * 862 862 * TODO: once the other paths are done see if we can't refactor into a fn 863 863 */ 864 - int apparmor_bprm_set_creds(struct linux_binprm *bprm) 864 + int apparmor_bprm_creds_for_exec(struct linux_binprm *bprm) 865 865 { 866 866 struct aa_task_ctx *ctx; 867 867 struct aa_label *label, *new = NULL; ··· 874 874 file_inode(bprm->file)->i_uid, 875 875 file_inode(bprm->file)->i_mode 876 876 }; 877 - 878 - if (bprm->called_set_creds) 879 - return 0; 880 877 881 878 ctx = task_ctx(current); 882 879 AA_BUG(!cred_label(bprm->cred));
+1 -1
security/apparmor/include/domain.h
··· 30 30 struct aa_label *x_table_lookup(struct aa_profile *profile, u32 xindex, 31 31 const char **name); 32 32 33 - int apparmor_bprm_set_creds(struct linux_binprm *bprm); 33 + int apparmor_bprm_creds_for_exec(struct linux_binprm *bprm); 34 34 35 35 void aa_free_domain_entries(struct aa_domain *domain); 36 36 int aa_change_hat(const char *hats[], int count, u64 token, int flags);
+1 -1
security/apparmor/lsm.c
··· 1232 1232 LSM_HOOK_INIT(cred_prepare, apparmor_cred_prepare), 1233 1233 LSM_HOOK_INIT(cred_transfer, apparmor_cred_transfer), 1234 1234 1235 - LSM_HOOK_INIT(bprm_set_creds, apparmor_bprm_set_creds), 1235 + LSM_HOOK_INIT(bprm_creds_for_exec, apparmor_bprm_creds_for_exec), 1236 1236 LSM_HOOK_INIT(bprm_committing_creds, apparmor_bprm_committing_creds), 1237 1237 LSM_HOOK_INIT(bprm_committed_creds, apparmor_bprm_committed_creds), 1238 1238
+12 -11
security/commoncap.c
··· 647 647 * its xattrs and, if present, apply them to the proposed credentials being 648 648 * constructed by execve(). 649 649 */ 650 - static int get_file_caps(struct linux_binprm *bprm, bool *effective, bool *has_fcap) 650 + static int get_file_caps(struct linux_binprm *bprm, struct file *file, 651 + bool *effective, bool *has_fcap) 651 652 { 652 653 int rc = 0; 653 654 struct cpu_vfs_cap_data vcaps; ··· 658 657 if (!file_caps_enabled) 659 658 return 0; 660 659 661 - if (!mnt_may_suid(bprm->file->f_path.mnt)) 660 + if (!mnt_may_suid(file->f_path.mnt)) 662 661 return 0; 663 662 664 663 /* ··· 666 665 * explicit that capability bits are limited to s_user_ns and its 667 666 * descendants. 668 667 */ 669 - if (!current_in_userns(bprm->file->f_path.mnt->mnt_sb->s_user_ns)) 668 + if (!current_in_userns(file->f_path.mnt->mnt_sb->s_user_ns)) 670 669 return 0; 671 670 672 - rc = get_vfs_caps_from_disk(bprm->file->f_path.dentry, &vcaps); 671 + rc = get_vfs_caps_from_disk(file->f_path.dentry, &vcaps); 673 672 if (rc < 0) { 674 673 if (rc == -EINVAL) 675 674 printk(KERN_NOTICE "Invalid argument reading file caps for %s\n", ··· 798 797 } 799 798 800 799 /** 801 - * cap_bprm_set_creds - Set up the proposed credentials for execve(). 800 + * cap_bprm_creds_from_file - Set up the proposed credentials for execve(). 802 801 * @bprm: The execution parameters, including the proposed creds 802 + * @file: The file to pull the credentials from 803 803 * 804 804 * Set up the proposed credentials for a new execution context being 805 805 * constructed by execve(). The proposed creds in @bprm->cred is altered, 806 806 * which won't take effect immediately. Returns 0 if successful, -ve on error. 807 807 */ 808 - int cap_bprm_set_creds(struct linux_binprm *bprm) 808 + int cap_bprm_creds_from_file(struct linux_binprm *bprm, struct file *file) 809 809 { 810 + /* Process setpcap binaries and capabilities for uid 0 */ 810 811 const struct cred *old = current_cred(); 811 812 struct cred *new = bprm->cred; 812 813 bool effective = false, has_fcap = false, is_setid; 813 814 int ret; 814 815 kuid_t root_uid; 815 816 816 - new->cap_ambient = old->cap_ambient; 817 817 if (WARN_ON(!cap_ambient_invariant_ok(old))) 818 818 return -EPERM; 819 819 820 - ret = get_file_caps(bprm, &effective, &has_fcap); 820 + ret = get_file_caps(bprm, file, &effective, &has_fcap); 821 821 if (ret < 0) 822 822 return ret; 823 823 ··· 887 885 return -EPERM; 888 886 889 887 /* Check for privilege-elevated exec. */ 890 - bprm->cap_elevated = 0; 891 888 if (is_setid || 892 889 (!__is_real(root_uid, new) && 893 890 (effective || 894 891 __cap_grew(permitted, ambient, new)))) 895 - bprm->cap_elevated = 1; 892 + bprm->secureexec = 1; 896 893 897 894 return 0; 898 895 } ··· 1348 1347 LSM_HOOK_INIT(ptrace_traceme, cap_ptrace_traceme), 1349 1348 LSM_HOOK_INIT(capget, cap_capget), 1350 1349 LSM_HOOK_INIT(capset, cap_capset), 1351 - LSM_HOOK_INIT(bprm_set_creds, cap_bprm_set_creds), 1350 + LSM_HOOK_INIT(bprm_creds_from_file, cap_bprm_creds_from_file), 1352 1351 LSM_HOOK_INIT(inode_need_killpriv, cap_inode_need_killpriv), 1353 1352 LSM_HOOK_INIT(inode_killpriv, cap_inode_killpriv), 1354 1353 LSM_HOOK_INIT(inode_getsecurity, cap_inode_getsecurity),
+7 -2
security/security.c
··· 823 823 return __vm_enough_memory(mm, pages, cap_sys_admin); 824 824 } 825 825 826 - int security_bprm_set_creds(struct linux_binprm *bprm) 826 + int security_bprm_creds_for_exec(struct linux_binprm *bprm) 827 827 { 828 - return call_int_hook(bprm_set_creds, 0, bprm); 828 + return call_int_hook(bprm_creds_for_exec, 0, bprm); 829 + } 830 + 831 + int security_bprm_creds_from_file(struct linux_binprm *bprm, struct file *file) 832 + { 833 + return call_int_hook(bprm_creds_from_file, 0, bprm, file); 829 834 } 830 835 831 836 int security_bprm_check(struct linux_binprm *bprm)
+3 -5
security/selinux/hooks.c
··· 2286 2286 return -EACCES; 2287 2287 } 2288 2288 2289 - static int selinux_bprm_set_creds(struct linux_binprm *bprm) 2289 + static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm) 2290 2290 { 2291 2291 const struct task_security_struct *old_tsec; 2292 2292 struct task_security_struct *new_tsec; ··· 2297 2297 2298 2298 /* SELinux context only depends on initial program or script and not 2299 2299 * the script interpreter */ 2300 - if (bprm->called_set_creds) 2301 - return 0; 2302 2300 2303 2301 old_tsec = selinux_cred(current_cred()); 2304 2302 new_tsec = selinux_cred(bprm->cred); ··· 6403 6405 /* Permission checking based on the specified context is 6404 6406 performed during the actual operation (execve, 6405 6407 open/mkdir/...), when we know the full context of the 6406 - operation. See selinux_bprm_set_creds for the execve 6408 + operation. See selinux_bprm_creds_for_exec for the execve 6407 6409 checks and may_create for the file creation checks. The 6408 6410 operation will then fail if the context is not permitted. */ 6409 6411 tsec = selinux_cred(new); ··· 6932 6934 6933 6935 LSM_HOOK_INIT(netlink_send, selinux_netlink_send), 6934 6936 6935 - LSM_HOOK_INIT(bprm_set_creds, selinux_bprm_set_creds), 6937 + LSM_HOOK_INIT(bprm_creds_for_exec, selinux_bprm_creds_for_exec), 6936 6938 LSM_HOOK_INIT(bprm_committing_creds, selinux_bprm_committing_creds), 6937 6939 LSM_HOOK_INIT(bprm_committed_creds, selinux_bprm_committed_creds), 6938 6940
+3 -6
security/smack/smack_lsm.c
··· 887 887 */ 888 888 889 889 /** 890 - * smack_bprm_set_creds - set creds for exec 890 + * smack_bprm_creds_for_exec - Update bprm->cred if needed for exec 891 891 * @bprm: the exec information 892 892 * 893 893 * Returns 0 if it gets a blob, -EPERM if exec forbidden and -ENOMEM otherwise 894 894 */ 895 - static int smack_bprm_set_creds(struct linux_binprm *bprm) 895 + static int smack_bprm_creds_for_exec(struct linux_binprm *bprm) 896 896 { 897 897 struct inode *inode = file_inode(bprm->file); 898 898 struct task_smack *bsp = smack_cred(bprm->cred); 899 899 struct inode_smack *isp; 900 900 struct superblock_smack *sbsp; 901 901 int rc; 902 - 903 - if (bprm->called_set_creds) 904 - return 0; 905 902 906 903 isp = smack_inode(inode); 907 904 if (isp->smk_task == NULL || isp->smk_task == bsp->smk_task) ··· 4581 4584 LSM_HOOK_INIT(sb_statfs, smack_sb_statfs), 4582 4585 LSM_HOOK_INIT(sb_set_mnt_opts, smack_set_mnt_opts), 4583 4586 4584 - LSM_HOOK_INIT(bprm_set_creds, smack_bprm_set_creds), 4587 + LSM_HOOK_INIT(bprm_creds_for_exec, smack_bprm_creds_for_exec), 4585 4588 4586 4589 LSM_HOOK_INIT(inode_alloc_security, smack_inode_alloc_security), 4587 4590 LSM_HOOK_INIT(inode_init_security, smack_inode_init_security),
+3 -9
security/tomoyo/tomoyo.c
··· 63 63 64 64 #ifndef CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER 65 65 /** 66 - * tomoyo_bprm_set_creds - Target for security_bprm_set_creds(). 66 + * tomoyo_bprm_for_exec - Target for security_bprm_creds_for_exec(). 67 67 * 68 68 * @bprm: Pointer to "struct linux_binprm". 69 69 * 70 70 * Returns 0. 71 71 */ 72 - static int tomoyo_bprm_set_creds(struct linux_binprm *bprm) 72 + static int tomoyo_bprm_creds_for_exec(struct linux_binprm *bprm) 73 73 { 74 - /* 75 - * Do only if this function is called for the first time of an execve 76 - * operation. 77 - */ 78 - if (bprm->called_set_creds) 79 - return 0; 80 74 /* 81 75 * Load policy if /sbin/tomoyo-init exists and /sbin/init is requested 82 76 * for the first time. ··· 533 539 LSM_HOOK_INIT(task_alloc, tomoyo_task_alloc), 534 540 LSM_HOOK_INIT(task_free, tomoyo_task_free), 535 541 #ifndef CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER 536 - LSM_HOOK_INIT(bprm_set_creds, tomoyo_bprm_set_creds), 542 + LSM_HOOK_INIT(bprm_creds_for_exec, tomoyo_bprm_creds_for_exec), 537 543 #endif 538 544 LSM_HOOK_INIT(bprm_check_security, tomoyo_bprm_check_security), 539 545 LSM_HOOK_INIT(file_fcntl, tomoyo_file_fcntl),
+1
tools/testing/selftests/exec/Makefile
··· 3 3 CFLAGS += -Wno-nonnull 4 4 CFLAGS += -D_GNU_SOURCE 5 5 6 + TEST_PROGS := binfmt_script 6 7 TEST_GEN_PROGS := execveat 7 8 TEST_GEN_FILES := execveat.symlink execveat.denatured script subdir 8 9 # Makefile is a run-time dependency, since it's accessed by the execveat test
+171
tools/testing/selftests/exec/binfmt_script
··· 1 + #!/usr/bin/env python3 2 + # SPDX-License-Identifier: GPL-2.0 3 + # 4 + # Test that truncation of bprm->buf doesn't cause unexpected execs paths, along 5 + # with various other pathological cases. 6 + import os, subprocess 7 + 8 + # Relevant commits 9 + # 10 + # b5372fe5dc84 ("exec: load_script: Do not exec truncated interpreter path") 11 + # 6eb3c3d0a52d ("exec: increase BINPRM_BUF_SIZE to 256") 12 + 13 + # BINPRM_BUF_SIZE 14 + SIZE=256 15 + 16 + NAME_MAX=int(subprocess.check_output(["getconf", "NAME_MAX", "."])) 17 + 18 + test_num=0 19 + 20 + code='''#!/usr/bin/perl 21 + print "Executed interpreter! Args:\n"; 22 + print "0 : '$0'\n"; 23 + $counter = 1; 24 + foreach my $a (@ARGV) { 25 + print "$counter : '$a'\n"; 26 + $counter++; 27 + } 28 + ''' 29 + 30 + ## 31 + # test - produce a binfmt_script hashbang line for testing 32 + # 33 + # @size: bytes for bprm->buf line, including hashbang but not newline 34 + # @good: whether this script is expected to execute correctly 35 + # @hashbang: the special 2 bytes for running binfmt_script 36 + # @leading: any leading whitespace before the executable path 37 + # @root: start of executable pathname 38 + # @target: end of executable pathname 39 + # @arg: bytes following the executable pathname 40 + # @fill: character to fill between @root and @target to reach @size bytes 41 + # @newline: character to use as newline, not counted towards @size 42 + # ... 43 + def test(name, size, good=True, leading="", root="./", target="/perl", 44 + fill="A", arg="", newline="\n", hashbang="#!"): 45 + global test_num, tests, NAME_MAX 46 + test_num += 1 47 + if test_num > tests: 48 + raise ValueError("more binfmt_script tests than expected! (want %d, expected %d)" 49 + % (test_num, tests)) 50 + 51 + middle = "" 52 + remaining = size - len(hashbang) - len(leading) - len(root) - len(target) - len(arg) 53 + # The middle of the pathname must not exceed NAME_MAX 54 + while remaining >= NAME_MAX: 55 + middle += fill * (NAME_MAX - 1) 56 + middle += '/' 57 + remaining -= NAME_MAX 58 + middle += fill * remaining 59 + 60 + dirpath = root + middle 61 + binary = dirpath + target 62 + if len(target): 63 + os.makedirs(dirpath, mode=0o755, exist_ok=True) 64 + open(binary, "w").write(code) 65 + os.chmod(binary, 0o755) 66 + 67 + buf=hashbang + leading + root + middle + target + arg + newline 68 + if len(newline) > 0: 69 + buf += 'echo this is not really perl\n' 70 + 71 + script = "binfmt_script-%s" % (name) 72 + open(script, "w").write(buf) 73 + os.chmod(script, 0o755) 74 + 75 + proc = subprocess.Popen(["./%s" % (script)], shell=True, 76 + stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 77 + stdout = proc.communicate()[0] 78 + 79 + if proc.returncode == 0 and b'Executed interpreter' in stdout: 80 + if good: 81 + print("ok %d - binfmt_script %s (successful good exec)" 82 + % (test_num, name)) 83 + else: 84 + print("not ok %d - binfmt_script %s succeeded when it should have failed" 85 + % (test_num, name)) 86 + else: 87 + if good: 88 + print("not ok %d - binfmt_script %s failed when it should have succeeded (rc:%d)" 89 + % (test_num, name, proc.returncode)) 90 + else: 91 + print("ok %d - binfmt_script %s (correctly failed bad exec)" 92 + % (test_num, name)) 93 + 94 + # Clean up crazy binaries 95 + os.unlink(script) 96 + if len(target): 97 + elements = binary.split('/') 98 + os.unlink(binary) 99 + elements.pop() 100 + while len(elements) > 1: 101 + os.rmdir("/".join(elements)) 102 + elements.pop() 103 + 104 + tests=27 105 + print("TAP version 1.3") 106 + print("1..%d" % (tests)) 107 + 108 + ### FAIL (8 tests) 109 + 110 + # Entire path is well past the BINFMT_BUF_SIZE. 111 + test(name="too-big", size=SIZE+80, good=False) 112 + # Path is right at max size, making it impossible to tell if it was truncated. 113 + test(name="exact", size=SIZE, good=False) 114 + # Same as above, but with leading whitespace. 115 + test(name="exact-space", size=SIZE, good=False, leading=" ") 116 + # Huge buffer of only whitespace. 117 + test(name="whitespace-too-big", size=SIZE+71, good=False, root="", 118 + fill=" ", target="") 119 + # A good path, but it gets truncated due to leading whitespace. 120 + test(name="truncated", size=SIZE+17, good=False, leading=" " * 19) 121 + # Entirely empty except for #! 122 + test(name="empty", size=2, good=False, root="", 123 + fill="", target="", newline="") 124 + # Within size, but entirely spaces 125 + test(name="spaces", size=SIZE-1, good=False, root="", fill=" ", 126 + target="", newline="") 127 + # Newline before binary. 128 + test(name="newline-prefix", size=SIZE-1, good=False, leading="\n", 129 + root="", fill=" ", target="") 130 + 131 + ### ok (19 tests) 132 + 133 + # The original test case that was broken by commit: 134 + # 8099b047ecc4 ("exec: load_script: don't blindly truncate shebang string") 135 + test(name="test.pl", size=439, leading=" ", 136 + root="./nix/store/bwav8kz8b3y471wjsybgzw84mrh4js9-perl-5.28.1/bin", 137 + arg=" -I/nix/store/x6yyav38jgr924nkna62q3pkp0dgmzlx-perl5.28.1-File-Slurp-9999.25/lib/perl5/site_perl -I/nix/store/ha8v67sl8dac92r9z07vzr4gv1y9nwqz-perl5.28.1-Net-DBus-1.1.0/lib/perl5/site_perl -I/nix/store/dcrkvnjmwh69ljsvpbdjjdnqgwx90a9d-perl5.28.1-XML-Parser-2.44/lib/perl5/site_perl -I/nix/store/rmji88k2zz7h4zg97385bygcydrf2q8h-perl5.28.1-XML-Twig-3.52/lib/perl5/site_perl") 138 + # One byte under size, leaving newline visible. 139 + test(name="one-under", size=SIZE-1) 140 + # Two bytes under size, leaving newline visible. 141 + test(name="two-under", size=SIZE-2) 142 + # Exact size, but trailing whitespace visible instead of newline 143 + test(name="exact-trunc-whitespace", size=SIZE, arg=" ") 144 + # Exact size, but trailing space and first arg char visible instead of newline. 145 + test(name="exact-trunc-arg", size=SIZE, arg=" f") 146 + # One bute under, with confirmed non-truncated arg since newline now visible. 147 + test(name="one-under-full-arg", size=SIZE-1, arg=" f") 148 + # Short read buffer by one byte. 149 + test(name="one-under-no-nl", size=SIZE-1, newline="") 150 + # Short read buffer by half buffer size. 151 + test(name="half-under-no-nl", size=int(SIZE/2), newline="") 152 + # One byte under with whitespace arg. leaving wenline visible. 153 + test(name="one-under-trunc-arg", size=SIZE-1, arg=" ") 154 + # One byte under with whitespace leading. leaving wenline visible. 155 + test(name="one-under-leading", size=SIZE-1, leading=" ") 156 + # One byte under with whitespace leading and as arg. leaving newline visible. 157 + test(name="one-under-leading-trunc-arg", size=SIZE-1, leading=" ", arg=" ") 158 + # Same as above, but with 2 bytes under 159 + test(name="two-under-no-nl", size=SIZE-2, newline="") 160 + test(name="two-under-trunc-arg", size=SIZE-2, arg=" ") 161 + test(name="two-under-leading", size=SIZE-2, leading=" ") 162 + test(name="two-under-leading-trunc-arg", size=SIZE-2, leading=" ", arg=" ") 163 + # Same as above, but with buffer half filled 164 + test(name="two-under-no-nl", size=int(SIZE/2), newline="") 165 + test(name="two-under-trunc-arg", size=int(SIZE/2), arg=" ") 166 + test(name="two-under-leading", size=int(SIZE/2), leading=" ") 167 + test(name="two-under-lead-trunc-arg", size=int(SIZE/2), leading=" ", arg=" ") 168 + 169 + if test_num != tests: 170 + raise ValueError("fewer binfmt_script tests than expected! (ran %d, expected %d" 171 + % (test_num, tests))