diff options
Diffstat (limited to 'usr/src/uts/common/os/exec.c')
-rw-r--r-- | usr/src/uts/common/os/exec.c | 160 |
1 files changed, 132 insertions, 28 deletions
diff --git a/usr/src/uts/common/os/exec.c b/usr/src/uts/common/os/exec.c index d663f27ca0..0f9e4ea6dd 100644 --- a/usr/src/uts/common/os/exec.c +++ b/usr/src/uts/common/os/exec.c @@ -24,7 +24,7 @@ */ /* Copyright (c) 1988 AT&T */ -/* All Rights Reserved */ +/* All Rights Reserved */ /* * Copyright 2019 Joyent, Inc. * Copyright 2022 Oxide Computer Company @@ -102,6 +102,7 @@ uint_t auxv_hwcap32_3 = 0; /* 32-bit version of auxv_hwcap3 */ #endif #define PSUIDFLAGS (SNOCD|SUGID) +#define RANDOM_LEN 16 /* 16 bytes for AT_RANDOM aux entry */ /* * These are consumed within the specific exec modules, but are defined here @@ -268,8 +269,10 @@ exec_common(const char *fname, const char **argp, const char **envp, * only if the pathname does not contain a "/" the resolved path * points to a file in the current working (attribute) directory. */ - if ((p->p_user.u_cdir->v_flag & V_XATTRDIR) != 0 && + mutex_enter(&p->p_lock); + if ((PTOU(p)->u_cdir->v_flag & V_XATTRDIR) != 0 && strchr(resolvepn.pn_path, '/') == NULL) { + mutex_exit(&p->p_lock); if (dir != NULL) VN_RELE(dir); error = EACCES; @@ -278,6 +281,7 @@ exec_common(const char *fname, const char **argp, const char **envp, VN_RELE(vp); goto out; } + mutex_exit(&p->p_lock); bzero(exec_file, MAXCOMLEN+1); (void) strncpy(exec_file, pn.pn_path, MAXCOMLEN); @@ -325,14 +329,43 @@ exec_common(const char *fname, const char **argp, const char **envp, ua.argp = argp; ua.envp = envp; - /* If necessary, brand this process before we start the exec. */ - if (brandme) - brand_setbrand(p); + /* If necessary, brand this process/lwp before we start the exec. */ + if (brandme) { + void *brand_data = NULL; + + /* + * Process branding may fail if multiple LWPs are present and + * holdlwps() cannot complete successfully. + */ + error = brand_setbrand(p, B_TRUE); + + if (error == 0 && BROP(p)->b_lwpdata_alloc != NULL) { + brand_data = BROP(p)->b_lwpdata_alloc(p); + if (brand_data == NULL) { + error = 1; + } + } + + if (error == 0) { + mutex_enter(&p->p_lock); + BROP(p)->b_initlwp(lwp, brand_data); + mutex_exit(&p->p_lock); + } else { + VN_RELE(vp); + if (dir != NULL) { + VN_RELE(dir); + } + pn_free(&resolvepn); + goto fail; + } + } if ((error = gexec(&vp, &ua, &args, NULL, 0, &execsz, - exec_file, p->p_cred, brand_action)) != 0) { - if (brandme) - brand_clearbrand(p, B_FALSE); + exec_file, p->p_cred, &brand_action)) != 0) { + if (brandme) { + BROP(p)->b_freelwp(lwp); + brand_clearbrand(p, B_TRUE); + } VN_RELE(vp); if (dir != NULL) VN_RELE(dir); @@ -364,7 +397,7 @@ exec_common(const char *fname, const char **argp, const char **envp, /* * Clear contract template state */ - lwp_ctmpl_clear(lwp); + lwp_ctmpl_clear(lwp, B_TRUE); /* * Save the directory in which we found the executable for expanding @@ -388,6 +421,8 @@ exec_common(const char *fname, const char **argp, const char **envp, * pending held signals remain held, so don't clear t_hold. */ mutex_enter(&p->p_lock); + DTRACE_PROBE3(oldcontext__set, klwp_t *, lwp, + uintptr_t, lwp->lwp_oldcontext, uintptr_t, 0); lwp->lwp_oldcontext = 0; lwp->lwp_ustack = 0; lwp->lwp_old_stk_ctl = 0; @@ -447,8 +482,10 @@ exec_common(const char *fname, const char **argp, const char **envp, TRACE_2(TR_FAC_PROC, TR_PROC_EXEC, "proc_exec:p %p up %p", p, up); /* Unbrand ourself if necessary. */ - if (PROC_IS_BRANDED(p) && (brand_action == EBA_NATIVE)) + if (PROC_IS_BRANDED(p) && (brand_action == EBA_NATIVE)) { + BROP(p)->b_freelwp(lwp); brand_clearbrand(p, B_FALSE); + } setregs(&args); @@ -572,7 +609,7 @@ gexec( size_t *execsz, caddr_t exec_file, struct cred *cred, - int brand_action) + int *brand_action) { struct vnode *vp, *execvp = NULL; proc_t *pp = ttoproc(curthread); @@ -893,8 +930,14 @@ gexec( if (pp->p_plist || (pp->p_proc_flag & P_PR_TRACE)) args->traceinval = 1; } - if (pp->p_proc_flag & P_PR_PTRACE) + + /* + * If legacy ptrace is enabled, generate the SIGTRAP. + */ + if (pp->p_proc_flag & P_PR_PTRACE) { psignal(pp, SIGTRAP); + } + if (args->traceinval) prinvalidate(&pp->p_user); } @@ -1558,6 +1601,27 @@ stk_add(uarg_t *args, const char *sp, enum uio_seg segflg) return (0); } +/* + * Add a fixed size byte array to the stack (only from kernel space). + */ +static int +stk_byte_add(uarg_t *args, const uint8_t *sp, size_t len) +{ + int error; + + if (STK_AVAIL(args) < sizeof (int)) + return (E2BIG); + *--args->stk_offp = args->stk_strp - args->stk_base; + + if (len > STK_AVAIL(args)) + return (E2BIG); + bcopy(sp, args->stk_strp, len); + + args->stk_strp += len; + + return (0); +} + static int stk_getptr(uarg_t *args, char *src, char **dst) { @@ -1594,6 +1658,7 @@ stk_copyin(execa_t *uap, uarg_t *args, intpdata_t *intp, void **auxvpp) size_t size, pad; char *argv = (char *)uap->argp; char *envp = (char *)uap->envp; + uint8_t rdata[RANDOM_LEN]; /* * Copy interpreter's name and argument to argv[0] and argv[1]. @@ -1650,7 +1715,9 @@ stk_copyin(execa_t *uap, uarg_t *args, intpdata_t *intp, void **auxvpp) } } argc = (int *)(args->stk_base + args->stk_size) - args->stk_offp; - args->arglen = args->stk_strp - args->stk_base; + args->argstrlen = args->stk_strp - args->stk_base; + + const char *envstr = args->stk_strp; /* * Add environ[] strings to the stack. @@ -1672,12 +1739,15 @@ stk_copyin(execa_t *uap, uarg_t *args, intpdata_t *intp, void **auxvpp) envp += ptrsize; } } + + args->envstrlen = args->stk_strp - envstr; args->na = (int *)(args->stk_base + args->stk_size) - args->stk_offp; args->ne = args->na - argc; /* - * Add AT_SUN_PLATFORM, AT_SUN_EXECNAME, AT_SUN_BRANDNAME, and - * AT_SUN_EMULATOR strings to the stack. + * Add AT_SUN_PLATFORM, AT_SUN_EXECNAME, AT_SUN_BRANDNAME, + * AT_SUN_BRAND_NROOT, and AT_SUN_EMULATOR strings, as well as AT_RANDOM + * array, to the stack. */ if (auxvpp != NULL && *auxvpp != NULL) { if ((error = stk_add(args, platform, UIO_SYSSPACE)) != 0) @@ -1690,6 +1760,20 @@ stk_copyin(execa_t *uap, uarg_t *args, intpdata_t *intp, void **auxvpp) if (args->emulator != NULL && (error = stk_add(args, args->emulator, UIO_SYSSPACE)) != 0) return (error); + + /* + * For the AT_RANDOM aux vector we provide 16 bytes of random + * data. + */ + (void) random_get_pseudo_bytes(rdata, sizeof (rdata)); + + if ((error = stk_byte_add(args, rdata, sizeof (rdata))) != 0) + return (error); + + if (args->brand_nroot != NULL && + (error = stk_add(args, args->brand_nroot, + UIO_SYSSPACE)) != 0) + return (error); } /* @@ -1746,46 +1830,53 @@ stk_copyout(uarg_t *args, char *usrstack, void **auxvpp, user_t *up) */ if (stk_putptr(args, usp, (char *)(uintptr_t)argc)) return (-1); + usp += ptrsize; /* - * Add argc space (ptrsize) to usp and record argv for /proc. + * For the benefit of /proc, record the user address of the argv[] array + * as well as the start of the argv string space (argv[0]). */ - up->u_argv = (uintptr_t)(usp += ptrsize); + up->u_argv = (uintptr_t)usp; + up->u_argvstrs = (uintptr_t)(&ustrp[*(offp - 1)]); + up->u_argvstrsize = args->argstrlen; /* - * Put the argv[] pointers on the stack. + * Put the argv[] pointers on the stack, including a NULL terminator. */ for (i = 0; i < argc; i++, usp += ptrsize) if (stk_putptr(args, usp, &ustrp[*--offp])) return (-1); + usp += ptrsize; /* * Copy arguments to u_psargs. */ - pslen = MIN(args->arglen, PSARGSZ) - 1; + pslen = MIN(args->argstrlen, PSARGSZ) - 1; for (i = 0; i < pslen; i++) up->u_psargs[i] = (kstrp[i] == '\0' ? ' ' : kstrp[i]); while (i < PSARGSZ) up->u_psargs[i++] = '\0'; /* - * Add space for argv[]'s NULL terminator (ptrsize) to usp and - * record envp for /proc. + * For the benefit of /proc, record the user address of the envp[] array + * as well as the start of the envp string space (envp[0]). */ - up->u_envp = (uintptr_t)(usp += ptrsize); + up->u_envp = (uintptr_t)usp; + up->u_envstrs = (uintptr_t)(&ustrp[*(offp - 1)]); + up->u_envstrsize = args->envstrlen; /* - * Put the envp[] pointers on the stack. + * Put the envp[] pointers on the stack, including a NULL terminator. */ for (i = 0; i < envc; i++, usp += ptrsize) if (stk_putptr(args, usp, &ustrp[*--offp])) return (-1); + usp += ptrsize; /* - * Add space for envp[]'s NULL terminator (ptrsize) to usp and - * remember where the stack ends, which is also where auxv begins. + * Remember where the stack ends, which is also where auxv begins. */ - args->stackend = usp += ptrsize; + args->stackend = usp; /* * Put all the argv[], envp[], and auxv strings on the stack. @@ -1796,7 +1887,7 @@ stk_copyout(uarg_t *args, char *usrstack, void **auxvpp, user_t *up) /* * Fill in the aux vector now that we know the user stack addresses * for the AT_SUN_PLATFORM, AT_SUN_EXECNAME, AT_SUN_BRANDNAME and - * AT_SUN_EMULATOR strings. + * AT_SUN_EMULATOR strings, as well as the AT_RANDOM array. */ if (auxvpp != NULL && *auxvpp != NULL) { if (args->to_model == DATAMODEL_NATIVE) { @@ -1809,6 +1900,11 @@ stk_copyout(uarg_t *args, char *usrstack, void **auxvpp, user_t *up) if (args->emulator != NULL) ADDAUX(*a, AT_SUN_EMULATOR, (long)&ustrp[*--offp]) + ADDAUX(*a, AT_RANDOM, (long)&ustrp[*--offp]) + if (args->brand_nroot != NULL) { + ADDAUX(*a, + AT_SUN_BRAND_NROOT, (long)&ustrp[*--offp]) + } } else { auxv32_t **a = (auxv32_t **)auxvpp; ADDAUX(*a, @@ -1821,6 +1917,11 @@ stk_copyout(uarg_t *args, char *usrstack, void **auxvpp, user_t *up) if (args->emulator != NULL) ADDAUX(*a, AT_SUN_EMULATOR, (int)(uintptr_t)&ustrp[*--offp]) + ADDAUX(*a, AT_RANDOM, (int)(uintptr_t)&ustrp[*--offp]) + if (args->brand_nroot != NULL) { + ADDAUX(*a, AT_SUN_BRAND_NROOT, + (int)(uintptr_t)&ustrp[*--offp]) + } } } @@ -1964,6 +2065,9 @@ exec_args(execa_t *uap, uarg_t *args, intpdata_t *intp, void **auxvpp) usrstack = (char *)USRSTACK32; } + if (args->maxstack != 0 && (uintptr_t)usrstack > args->maxstack) + usrstack = (char *)args->maxstack; + ASSERT(P2PHASE((uintptr_t)usrstack, args->stk_align) == 0); #if defined(__sparc) @@ -2059,7 +2163,7 @@ exec_args(execa_t *uap, uarg_t *args, intpdata_t *intp, void **auxvpp) delete_itimer_realprof(); if (AU_AUDITING()) - audit_exec(args->stk_base, args->stk_base + args->arglen, + audit_exec(args->stk_base, args->stk_base + args->argstrlen, args->na - args->ne, args->ne, args->pfcred); /* |