diff options
author | John Levon <john.levon@joyent.com> | 2019-09-12 20:26:08 +0000 |
---|---|---|
committer | John Levon <john.levon@joyent.com> | 2019-09-12 20:26:08 +0000 |
commit | c6dd2307128aa25ac346f7818440cd5cfd1f7221 (patch) | |
tree | 9bda47db825ca7697580de5510764735b0748431 /usr/src/uts/common | |
parent | 1cc6f4c0fcc857bd86b9a8234d9ff75d5a6b9384 (diff) | |
download | illumos-joyent-c6dd2307128aa25ac346f7818440cd5cfd1f7221.tar.gz |
OS-7931 ::refstr would be useful
OS-7932 ::ps -s could show service FMRIs
OS-7934 ptree could show service FMRIs
OS-3513 ptools should see more process arguments
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Jason King <jason.king@joyent.com>
Approved by: Jerry Jelinek <jerry.jelinek@joyent.com>
Diffstat (limited to 'usr/src/uts/common')
-rw-r--r-- | usr/src/uts/common/brand/lx/os/lx_brand.c | 2 | ||||
-rw-r--r-- | usr/src/uts/common/brand/lx/os/lx_misc.c | 71 | ||||
-rw-r--r-- | usr/src/uts/common/brand/lx/procfs/lx_prvnops.c | 104 | ||||
-rw-r--r-- | usr/src/uts/common/brand/lx/sys/lx_brand.h | 15 | ||||
-rw-r--r-- | usr/src/uts/common/brand/lx/sys/lx_misc.h | 3 | ||||
-rw-r--r-- | usr/src/uts/common/contract/process.c | 8 | ||||
-rw-r--r-- | usr/src/uts/common/fs/proc/prargv.c | 103 | ||||
-rw-r--r-- | usr/src/uts/common/fs/proc/prdata.h | 4 | ||||
-rw-r--r-- | usr/src/uts/common/fs/proc/prvnops.c | 64 | ||||
-rw-r--r-- | usr/src/uts/common/os/exec.c | 39 | ||||
-rw-r--r-- | usr/src/uts/common/os/zone.c | 6 | ||||
-rw-r--r-- | usr/src/uts/common/sys/exec.h | 3 | ||||
-rw-r--r-- | usr/src/uts/common/sys/procfs.h | 6 | ||||
-rw-r--r-- | usr/src/uts/common/sys/user.h | 6 |
14 files changed, 213 insertions, 221 deletions
diff --git a/usr/src/uts/common/brand/lx/os/lx_brand.c b/usr/src/uts/common/brand/lx/os/lx_brand.c index 83fbd6adb7..b6038fca07 100644 --- a/usr/src/uts/common/brand/lx/os/lx_brand.c +++ b/usr/src/uts/common/brand/lx/os/lx_brand.c @@ -379,8 +379,6 @@ lx_setbrand(proc_t *p) { /* Send SIGCHLD to parent by default when child exits */ ptolxproc(p)->l_signal = stol_signo[SIGCHLD]; - - lx_read_argv_bounds(p); } /* ARGSUSED */ diff --git a/usr/src/uts/common/brand/lx/os/lx_misc.c b/usr/src/uts/common/brand/lx/os/lx_misc.c index b73e7f430a..726c3c7915 100644 --- a/usr/src/uts/common/brand/lx/os/lx_misc.c +++ b/usr/src/uts/common/brand/lx/os/lx_misc.c @@ -135,11 +135,6 @@ lx_exec() lx_restore(lwp); kpreempt_enable(); - /* Grab the updated argv bounds */ - mutex_enter(&p->p_lock); - lx_read_argv_bounds(p); - mutex_exit(&p->p_lock); - /* * The exec syscall doesn't return (so we don't call lx_syscall_return) * but for our ptrace emulation we need to do this so that a tracer @@ -1058,72 +1053,6 @@ stol_ksiginfo32_copyout(k_siginfo_t *sip, void *ulxsip) } #endif -/* - * Linux uses the original bounds of the argv array when determining the - * contents of /proc/<pid/cmdline. We mimic those bounds using argv[0] and - * envp[0] as the beginning and end, respectively. - */ -void -lx_read_argv_bounds(proc_t *p) -{ - user_t *up = PTOU(p); - lx_proc_data_t *pd = ptolxproc(p); - uintptr_t addr_arg = up->u_argv; - uintptr_t addr_env = up->u_envp; - uintptr_t arg_start = 0, env_start = 0, env_end = 0; - int i = 0; - - VERIFY(pd != NULL); - VERIFY(MUTEX_HELD(&p->p_lock)); - - /* - * Use AT_SUN_PLATFORM in the aux vector to find the end of the envp - * strings. - */ - for (i = 0; i < __KERN_NAUXV_IMPL; i++) { - if (up->u_auxv[i].a_type == AT_SUN_PLATFORM) { - env_end = (uintptr_t)up->u_auxv[i].a_un.a_val; - } - } - - /* - * If we come through here for a kernel process (zsched), which happens - * with our cgroupfs when we fork the release agent, then u_argv and - * u_envp will be NULL. While this won't cause a failure, it does - * cause a lot of overhead when the fuword causes a fault, which leads - * to a large amount of stack growth and anonymous memory allocation, - * all of which is pointless since the first page can't be mapped. - */ - if (addr_arg != (uintptr_t)NULL || addr_env != (uintptr_t)NULL) { - mutex_exit(&p->p_lock); -#if defined(_LP64) - if (p->p_model != DATAMODEL_NATIVE) { - uint32_t buf32; - if (fuword32((void *)addr_arg, &buf32) == 0) { - arg_start = (uintptr_t)buf32; - } - if (fuword32((void *)addr_env, &buf32) == 0) { - env_start = (uintptr_t)buf32; - } - } else -#endif /* defined(_LP64) */ - { - ulong_t buf; - if (fulword((void *)addr_arg, &buf) == 0) { - arg_start = (uintptr_t)buf; - } - if (fulword((void *)addr_env, &buf) == 0) { - env_start = (uintptr_t)buf; - } - } - mutex_enter(&p->p_lock); - } - - pd->l_args_start = arg_start; - pd->l_envs_start = env_start; - pd->l_envs_end = env_end; -} - /* Given an LX LWP, determine where user register state is stored. */ lx_regs_location_t lx_regs_location(lx_lwp_data_t *lwpd, void **ucp, boolean_t for_write) diff --git a/usr/src/uts/common/brand/lx/procfs/lx_prvnops.c b/usr/src/uts/common/brand/lx/procfs/lx_prvnops.c index bcfdd346da..90e8fbe4d5 100644 --- a/usr/src/uts/common/brand/lx/procfs/lx_prvnops.c +++ b/usr/src/uts/common/brand/lx/procfs/lx_prvnops.c @@ -83,10 +83,11 @@ #include <sys/socketvar.h> #include <fs/sockfs/socktpi.h> #include <sys/random.h> +#include <sys/procfs.h> /* Dependent on procfs */ extern kthread_t *prchoose(proc_t *); -extern int prreadargv(proc_t *, char *, size_t, size_t *); +extern int prreadcmdline(proc_t *, char *, size_t, size_t *); extern int prreadenvv(proc_t *, char *, size_t, size_t *); extern int prreadbuf(proc_t *, uintptr_t, uint8_t *, size_t, size_t *); @@ -332,10 +333,9 @@ extern swrand_stats_t swrand_stats; #define FOURGB 4294967295ULL /* - * The maximum length of the concatenation of argument vector strings we - * will return to the user via the branded procfs. Likewise for the env vector. + * The maximum length of the concatenation of env vector strings we + * will return to the user via the branded procfs. */ -int lxpr_maxargvlen = 4096; int lxpr_maxenvvlen = 4096; /* @@ -1501,77 +1501,6 @@ lxpr_read_pid_cgroup(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf) lxpr_uiobuf_printf(uiobuf, "1:name=systemd:/\n"); } -static void -lxpr_copy_cmdline(proc_t *p, lx_proc_data_t *pd, lxpr_uiobuf_t *uiobuf) -{ - uio_t *uiop = uiobuf->uiop; - char *buf = uiobuf->buffer; - int bsz = uiobuf->buffsize; - boolean_t env_overflow = B_FALSE; - uintptr_t pos = pd->l_args_start + uiop->uio_offset; - uintptr_t estart = pd->l_envs_start; - uintptr_t eend = pd->l_envs_end; - size_t chunk, copied; - int err = 0; - - /* Do not bother with data beyond the end of the envp strings area. */ - if (pos > eend) { - return; - } - mutex_exit(&p->p_lock); - - /* - * If the starting or ending bounds are outside the argv strings area, - * check to see if the process has overwritten the terminating NULL. - * If not, no data needs to be copied from oustide the argv area. - */ - if (pos >= estart || (pos + uiop->uio_resid) >= estart) { - uint8_t term; - if (uread(p, &term, sizeof (term), estart - 1) != 0) { - err = EFAULT; - } else if (term != 0) { - env_overflow = B_TRUE; - } - } - - /* Data between astart and estart-1 can be copied freely. */ - while (pos < estart && uiop->uio_resid > 0 && err == 0) { - chunk = MIN(estart - pos, uiop->uio_resid); - chunk = MIN(chunk, bsz); - - if (prreadbuf(p, pos, (uint8_t *)buf, chunk, &copied) != 0 || - copied != chunk) { - err = EFAULT; - break; - } - err = uiomove(buf, copied, UIO_READ, uiop); - pos += copied; - } - - /* - * Onward from estart, data is copied as a contiguous string. To - * protect env data from potential snooping, only one buffer-sized copy - * is allowed to avoid complex seek logic. - */ - if (err == 0 && env_overflow && pos == estart && uiop->uio_resid > 0) { - chunk = MIN(eend - pos, uiop->uio_resid); - chunk = MIN(chunk, bsz); - if (prreadbuf(p, pos, (uint8_t *)buf, chunk, &copied) == 0) { - int len = strnlen(buf, copied); - if (len > 0) { - err = uiomove(buf, len, UIO_READ, uiop); - } - } - } - - uiobuf->error = err; - /* reset any uiobuf state */ - uiobuf->pos = uiobuf->buffer; - uiobuf->beg = 0; - - mutex_enter(&p->p_lock); -} - /* * lxpr_read_pid_cmdline(): read argument vector from process */ @@ -1580,8 +1509,8 @@ lxpr_read_pid_cmdline(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf) { proc_t *p; char *buf; - size_t asz = lxpr_maxargvlen, sz; - lx_proc_data_t *pd; + size_t asz = PRMAXARGVLEN, sz; + int r; ASSERT(lxpnp->lxpr_type == LXPR_PID_CMDLINE || lxpnp->lxpr_type == LXPR_PID_TID_CMDLINE); @@ -1594,23 +1523,16 @@ lxpr_read_pid_cmdline(lxpr_node_t *lxpnp, lxpr_uiobuf_t *uiobuf) return; } - if ((pd = ptolxproc(p)) != NULL && pd->l_args_start != 0 && - pd->l_envs_start != 0 && pd->l_envs_end != 0) { - /* Use Linux-style argv bounds if possible. */ - lxpr_copy_cmdline(p, pd, uiobuf); - lxpr_unlock(p); - } else { - int r; + r = prreadcmdline(p, buf, asz, &sz); - r = prreadargv(p, buf, asz, &sz); - lxpr_unlock(p); + lxpr_unlock(p); - if (r != 0) { - lxpr_uiobuf_seterr(uiobuf, EINVAL); - } else { - lxpr_uiobuf_write(uiobuf, buf, sz); - } + if (r != 0) { + lxpr_uiobuf_seterr(uiobuf, EINVAL); + } else { + lxpr_uiobuf_write(uiobuf, buf, sz); } + kmem_free(buf, asz); } diff --git a/usr/src/uts/common/brand/lx/sys/lx_brand.h b/usr/src/uts/common/brand/lx/sys/lx_brand.h index 9c1579cc82..90d87d78a8 100644 --- a/usr/src/uts/common/brand/lx/sys/lx_brand.h +++ b/usr/src/uts/common/brand/lx/sys/lx_brand.h @@ -24,7 +24,7 @@ */ /* - * Copyright 2018 Joyent, Inc. + * Copyright 2019 Joyent, Inc. */ #ifndef _LX_BRAND_H @@ -132,8 +132,8 @@ typedef enum lx_ptrace_options { } lx_ptrace_options_t; #define LX_PTRACE_O_ALL \ - (LX_PTRACE_O_TRACESYSGOOD | LX_PTRACE_O_TRACEFORK | \ - LX_PTRACE_O_TRACEVFORK | LX_PTRACE_O_TRACECLONE | \ + (LX_PTRACE_O_TRACESYSGOOD | LX_PTRACE_O_TRACEFORK | \ + LX_PTRACE_O_TRACEVFORK | LX_PTRACE_O_TRACECLONE | \ LX_PTRACE_O_TRACEEXEC | LX_PTRACE_O_TRACEVFORKDONE | \ LX_PTRACE_O_TRACEEXIT | LX_PTRACE_O_TRACESECCOMP) #endif /* !_ASM */ @@ -344,11 +344,6 @@ typedef struct lx_proc_data { uint_t l_io_ctx_cnt; struct lx_io_ctx **l_io_ctxs; - /* original start/end bounds of arg/env string data */ - uintptr_t l_args_start; - uintptr_t l_envs_start; - uintptr_t l_envs_end; - /* Override zone-wide settings for uname release and version */ char l_uname_release[LX_KERN_RELEASE_MAX]; char l_uname_version[LX_KERN_VERSION_MAX]; @@ -365,7 +360,7 @@ typedef struct lx_proc_data { lx_segmap_t l_remap_anoncache[LX_REMAP_ANONCACHE_NENTRIES]; /* Block all signals to all threads; used during vfork */ - uint_t l_block_all_signals; + uint_t l_block_all_signals; } lx_proc_data_t; #endif /* _KERNEL */ @@ -545,7 +540,7 @@ struct lx_lwp_data { lx_ptrace_accord_t *br_ptrace_tracer; /* accord tracing this LWP */ list_node_t br_ptrace_linkage; /* linkage for lxpa_tracees list */ - ushort_t br_ptrace_whystop; /* stop reason, 0 for no stop */ + ushort_t br_ptrace_whystop; /* stop reason, 0 for no stop */ ushort_t br_ptrace_whatstop; /* stop sub-reason */ int32_t br_ptrace_stopsig; /* stop signal, 0 for no signal */ diff --git a/usr/src/uts/common/brand/lx/sys/lx_misc.h b/usr/src/uts/common/brand/lx/sys/lx_misc.h index 0418d3e9f9..e81a1597f3 100644 --- a/usr/src/uts/common/brand/lx/sys/lx_misc.h +++ b/usr/src/uts/common/brand/lx/sys/lx_misc.h @@ -10,7 +10,7 @@ */ /* - * Copyright 2017 Joyent, Inc. + * Copyright 2019 Joyent, Inc. */ #ifndef _SYS__LX_MISC_H @@ -62,7 +62,6 @@ extern int ltos_at_flag(int, int, boolean_t); #if defined(_SYSCALL32_IMPL) extern int stol_ksiginfo32_copyout(k_siginfo_t *, void *); #endif -extern void lx_read_argv_bounds(proc_t *p); typedef enum lx_regs_location { LX_REG_LOC_UNAVAIL, diff --git a/usr/src/uts/common/contract/process.c b/usr/src/uts/common/contract/process.c index e46cbd3abf..6e43bd7aef 100644 --- a/usr/src/uts/common/contract/process.c +++ b/usr/src/uts/common/contract/process.c @@ -21,7 +21,7 @@ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. - * Copyright 2016 Joyent, Inc. + * Copyright 2019 Joyent, Inc. */ #include <sys/mutex.h> @@ -737,13 +737,11 @@ contract_process_status(contract_t *ct, zone_t *zone, int detail, nvlist_t *nvl, * if we are in a local zone and svc_fmri was inherited from * the global zone, we provide fake svc_fmri and svc_ctid */ - if (local_svc_zone_enter == 0|| + if (local_svc_zone_enter == 0 || zone->zone_uniqid == GLOBAL_ZONEUNIQID) { if (detail > CTD_COMMON) { VERIFY(nvlist_add_int32(nvl, CTPS_SVC_CTID, ctp->conp_svc_ctid) == 0); - } - if (detail == CTD_ALL) { VERIFY(nvlist_add_string(nvl, CTPS_SVC_FMRI, refstr_value(ctp->conp_svc_fmri)) == 0); } @@ -751,8 +749,6 @@ contract_process_status(contract_t *ct, zone_t *zone, int detail, nvlist_t *nvl, if (detail > CTD_COMMON) { VERIFY(nvlist_add_int32(nvl, CTPS_SVC_CTID, local_svc_zone_enter) == 0); - } - if (detail == CTD_ALL) { VERIFY(nvlist_add_string(nvl, CTPS_SVC_FMRI, CT_PR_SVC_FMRI_ZONE_ENTER) == 0); } diff --git a/usr/src/uts/common/fs/proc/prargv.c b/usr/src/uts/common/fs/proc/prargv.c index 40d47598ac..60d098d125 100644 --- a/usr/src/uts/common/fs/proc/prargv.c +++ b/usr/src/uts/common/fs/proc/prargv.c @@ -28,7 +28,7 @@ * returned to the caller via 'rdsz'. */ int -prreadbuf(proc_t *p, uintptr_t ustart, uint8_t *buf, size_t sz, size_t *rdsz) +prreadbuf(proc_t *p, uintptr_t ustart, char *buf, size_t sz, size_t *rdsz) { int error = 0; size_t rem = sz; @@ -63,6 +63,95 @@ prreadbuf(proc_t *p, uintptr_t ustart, uint8_t *buf, size_t sz, size_t *rdsz) return (error); } + +/* + * Effectively a truncating version of copyinstr(). + * + * The resulting string is guaranteed to be truncated to fit within the buffer + * (hence sz == 0 is not supported). The returned size includes the truncating + * NUL. + */ +int +prreadstr(proc_t *p, uintptr_t ustart, char *buf, size_t bufsz, size_t *rdsz) +{ + size_t slen; + int err; + + VERIFY(bufsz != 0); + + if ((err = prreadbuf(p, ustart, buf, bufsz, &slen)) != 0) + return (err); + + slen = strnlen(buf, slen); + + if (slen == bufsz) + slen--; + + buf[slen++] = '\0'; + + if (rdsz != NULL) + *rdsz = slen; + return (0); +} + +/* + * /proc/pid/cmdline: Linux-compatible '\0'-separated process argv. + * + * Unlike /proc/pid/argv, this looks at the exec()-time argv string area, rather + * than starting from the argv[] array. Thus changes to the array are not + * noticed, but direct modifications of the string are visible here. Since it's + * common for applications to expect it, we implement the Linux semantics here. + * + * There is special handling if the process has modified its argv: if the last + * byte of the argv string area is no longer NUL, then we presume that it has + * done setproctitle() or similar, and we should copy it as a single string from + * the start, even though it overflows into the env string area. Note that we + * can't use copyinstr() as that returns ENAMETOOLONG rather than truncating as + * we need. + * + * Otherwise, we provide the argv string area in toto. + */ +int +prreadcmdline(proc_t *p, char *buf, size_t bufsz, size_t *slen) +{ + user_t *up = &p->p_user; + uint8_t term; + int err = 0; + + VERIFY(bufsz == PRMAXARGVLEN); + VERIFY(MUTEX_HELD(&p->p_lock)); + + if ((p->p_flag & SSYS) || p->p_as == &kas || up->u_argvstrsize == 0) { + bcopy(up->u_psargs, buf, MIN(bufsz, sizeof (up->u_psargs))); + buf[bufsz - 1] = '\0'; + *slen = strlen(buf) + 1; + return (0); + } + + VERIFY(up->u_argvstrs != (uintptr_t)NULL); + + mutex_exit(&p->p_lock); + + if (uread(p, &term, sizeof (term), + up->u_argvstrs + up->u_argvstrsize - 1) != 0) { + err = EFAULT; + goto out; + } + + if (term != '\0') { + err = prreadstr(p, up->u_argvstrs, buf, bufsz, slen); + } else { + size_t size = MIN(bufsz, up->u_argvstrsize); + err = prreadbuf(p, up->u_argvstrs, buf, size, slen); + } + +out: + mutex_enter(&p->p_lock); + VERIFY(p->p_proc_flag & P_PR_LOCK); + return (err); +} + + /* * Attempt to read the argument vector (argv) from this process. The caller * must hold the p_lock mutex, and have marked the process P_PR_LOCK (e.g. via @@ -113,8 +202,8 @@ prreadargv(proc_t *p, char *buf, size_t bufsz, size_t *slen) * while we do I/O to avoid deadlock with the clock thread. */ mutex_exit(&p->p_lock); - if ((error = prreadbuf(p, up->u_argv, (uint8_t *)argv, argvsz, - NULL)) != 0) { + if ((error = prreadbuf(p, up->u_argv, (char *)argv, + argvsz, NULL)) != 0) { kmem_free(argv, argvsz); mutex_enter(&p->p_lock); VERIFY(p->p_proc_flag & P_PR_LOCK); @@ -175,7 +264,7 @@ retry: * Read string data for this argument. Leave room * in the buffer for a final NUL terminator. */ - if ((error = prreadbuf(p, arg, (uint8_t *)&buf[pos], trysz, + if ((error = prreadbuf(p, arg, (char *)&buf[pos], trysz, &rdsz)) != 0) { /* * There was a problem reading this string @@ -288,7 +377,7 @@ prreadenvv(proc_t *p, char *buf, size_t bufsz, size_t *slen) for (cnt = 0, tmpp = up->u_envp; cnt < bound; cnt++, tmpp += rdsz) { caddr_t tmp = NULL; - if ((error = prreadbuf(p, tmpp, (uint8_t *)&tmp, rdsz, + if ((error = prreadbuf(p, tmpp, (char *)&tmp, rdsz, NULL)) != 0) { mutex_enter(&p->p_lock); VERIFY(p->p_proc_flag & P_PR_LOCK); @@ -317,7 +406,7 @@ prreadenvv(proc_t *p, char *buf, size_t bufsz, size_t *slen) /* * Extract the env array from the target process. */ - if ((error = prreadbuf(p, up->u_envp, (uint8_t *)envp, envpsz, + if ((error = prreadbuf(p, up->u_envp, (char *)envp, envpsz, NULL)) != 0) { kmem_free(envp, envpsz); mutex_enter(&p->p_lock); @@ -379,7 +468,7 @@ retry: * Read string data for this env var. Leave room * in the buffer for a final NUL terminator. */ - if ((error = prreadbuf(p, ev, (uint8_t *)&buf[pos], trysz, + if ((error = prreadbuf(p, ev, (char *)&buf[pos], trysz, &rdsz)) != 0) { /* * There was a problem reading this string diff --git a/usr/src/uts/common/fs/proc/prdata.h b/usr/src/uts/common/fs/proc/prdata.h index 706e3ad14d..0ed015b9a2 100644 --- a/usr/src/uts/common/fs/proc/prdata.h +++ b/usr/src/uts/common/fs/proc/prdata.h @@ -27,7 +27,7 @@ /* All Rights Reserved */ /* - * Copyright 2018 Joyent, Inc. + * Copyright 2019 Joyent, Inc. */ #ifndef _SYS_PROC_PRDATA_H @@ -124,6 +124,7 @@ typedef enum prnodetype { PR_LDT, /* /proc/<pid>/ldt */ #endif PR_ARGV, /* /proc/<pid>/argv */ + PR_CMDLINE, /* /proc/<pid>/cmdline */ PR_USAGE, /* /proc/<pid>/usage */ PR_LUSAGE, /* /proc/<pid>/lusage */ PR_PAGEDATA, /* /proc/<pid>/pagedata */ @@ -351,6 +352,7 @@ extern void pr_sethold(prnode_t *, sigset_t *); extern void pr_setfault(proc_t *, fltset_t *); extern int prusrio(proc_t *, enum uio_rw, struct uio *, int); extern int prreadargv(proc_t *, char *, size_t, size_t *); +extern int prreadcmdline(proc_t *, char *, size_t, size_t *); extern int prreadenvv(proc_t *, char *, size_t, size_t *); extern int prwritectl(vnode_t *, struct uio *, cred_t *); extern int prlock(prnode_t *, int); diff --git a/usr/src/uts/common/fs/proc/prvnops.c b/usr/src/uts/common/fs/proc/prvnops.c index 657cebf8c2..a9d9fe89ec 100644 --- a/usr/src/uts/common/fs/proc/prvnops.c +++ b/usr/src/uts/common/fs/proc/prvnops.c @@ -21,7 +21,7 @@ /* * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2018, Joyent, Inc. + * Copyright 2019 Joyent, Inc. * Copyright (c) 2017 by Delphix. All rights reserved. */ @@ -98,11 +98,6 @@ struct prdirect { #define PRSDSIZE (sizeof (struct prdirect)) /* - * Maximum length of the /proc/$$/argv file: - */ -int prmaxargvlen = 4096; - -/* * Directory characteristics. */ typedef struct prdirent { @@ -171,12 +166,14 @@ static prdirent_t piddir[] = { "contracts" }, { PR_SECFLAGS, 27 * sizeof (prdirent_t), sizeof (prdirent_t), "secflags" }, + { PR_ARGV, 28 * sizeof (prdirent_t), sizeof (prdirent_t), + "argv" }, + { PR_CMDLINE, 29 * sizeof (prdirent_t), sizeof (prdirent_t), + "cmdline" }, #if defined(__x86) - { PR_LDT, 28 * sizeof (prdirent_t), sizeof (prdirent_t), + { PR_LDT, 30 * sizeof (prdirent_t), sizeof (prdirent_t), "ldt" }, #endif - { PR_ARGV, 28 * sizeof (prdirent_t), sizeof (prdirent_t), - "argv" }, }; #define NPIDDIRFILES (sizeof (piddir) / sizeof (piddir[0]) - 2) @@ -595,7 +592,7 @@ static int pr_read_inval(), pr_read_as(), pr_read_status(), #if defined(__x86) pr_read_ldt(), #endif - pr_read_argv(), + pr_read_argv(), pr_read_cmdline(), pr_read_usage(), pr_read_lusage(), pr_read_pagedata(), pr_read_watch(), pr_read_lwpstatus(), pr_read_lwpsinfo(), pr_read_lwpusage(), pr_read_lwpname(), @@ -626,6 +623,7 @@ static int (*pr_read_function[PR_NFILES])() = { pr_read_ldt, /* /proc/<pid>/ldt */ #endif pr_read_argv, /* /proc/<pid>/argv */ + pr_read_cmdline, /* /proc/<pid>/cmdline */ pr_read_usage, /* /proc/<pid>/usage */ pr_read_lusage, /* /proc/<pid>/lusage */ pr_read_pagedata, /* /proc/<pid>/pagedata */ @@ -690,11 +688,46 @@ pr_uioread(void *base, long count, uio_t *uiop) } static int +pr_read_cmdline(prnode_t *pnp, uio_t *uiop) +{ + char *args; + int error; + size_t asz = PRMAXARGVLEN, sz; + + /* + * Allocate a scratch buffer for collection of the process arguments. + */ + args = kmem_alloc(asz, KM_SLEEP); + + ASSERT(pnp->pr_type == PR_CMDLINE); + + if ((error = prlock(pnp, ZNO)) != 0) { + kmem_free(args, asz); + return (error); + } + + if ((error = prreadcmdline(pnp->pr_common->prc_proc, args, asz, + &sz)) != 0) { + prunlock(pnp); + kmem_free(args, asz); + return (error); + } + + prunlock(pnp); + + error = pr_uioread(args, sz, uiop); + + kmem_free(args, asz); + + return (error); +} + +static int pr_read_argv(prnode_t *pnp, uio_t *uiop) { char *args; int error; - size_t asz = prmaxargvlen, sz; + size_t asz = PRMAXARGVLEN, sz; /* * Allocate a scratch buffer for collection of the process arguments. @@ -1872,6 +1905,7 @@ static int (*pr_read_function_32[PR_NFILES])() = { pr_read_ldt, /* /proc/<pid>/ldt */ #endif pr_read_argv, /* /proc/<pid>/argv */ + pr_read_cmdline, /* /proc/<pid>/cmdline */ pr_read_usage_32, /* /proc/<pid>/usage */ pr_read_lusage_32, /* /proc/<pid>/lusage */ pr_read_pagedata_32, /* /proc/<pid>/pagedata */ @@ -3317,7 +3351,7 @@ prgetattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, if ((p->p_flag & SSYS) || p->p_as == &kas) { vap->va_size = PSARGSZ; } else { - vap->va_size = prmaxargvlen; + vap->va_size = PRMAXARGVLEN; } break; #if defined(__x86) @@ -3442,6 +3476,7 @@ prgetattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, #endif case PR_CTL: case PR_LWPCTL: + case PR_CMDLINE: default: vap->va_size = 0; break; @@ -3497,6 +3532,7 @@ praccess(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct) case PR_LUSAGE: case PR_LWPUSAGE: case PR_ARGV: + case PR_CMDLINE: p = pr_p_lock(pnp); mutex_exit(&pr_pidlock); if (p == NULL) @@ -3583,6 +3619,7 @@ static vnode_t *(*pr_lookup_function[PR_NFILES])() = { pr_lookup_notdir, /* /proc/<pid>/ldt */ #endif pr_lookup_notdir, /* /proc/<pid>/argv */ + pr_lookup_notdir, /* /proc/<pid>/cmdline */ pr_lookup_notdir, /* /proc/<pid>/usage */ pr_lookup_notdir, /* /proc/<pid>/lusage */ pr_lookup_notdir, /* /proc/<pid>/pagedata */ @@ -4871,6 +4908,7 @@ prgetnode(vnode_t *dp, prnodetype_t type) case PR_LUSAGE: case PR_LWPUSAGE: case PR_ARGV: + case PR_CMDLINE: pnp->pr_mode = 0444; /* read-only by all */ break; @@ -4977,6 +5015,7 @@ static int (*pr_readdir_function[PR_NFILES])() = { pr_readdir_notdir, /* /proc/<pid>/ldt */ #endif pr_readdir_notdir, /* /proc/<pid>/argv */ + pr_readdir_notdir, /* /proc/<pid>/cmdline */ pr_readdir_notdir, /* /proc/<pid>/usage */ pr_readdir_notdir, /* /proc/<pid>/lusage */ pr_readdir_notdir, /* /proc/<pid>/pagedata */ @@ -5129,6 +5168,7 @@ pr_readdir_piddir(prnode_t *pnp, uio_t *uiop, int *eofp) case PR_PSINFO: case PR_USAGE: case PR_ARGV: + case PR_CMDLINE: break; default: continue; diff --git a/usr/src/uts/common/os/exec.c b/usr/src/uts/common/os/exec.c index 24b6f0e2eb..62d1e298dd 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. */ @@ -1712,7 +1712,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. @@ -1734,6 +1736,8 @@ 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; @@ -1823,46 +1827,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. @@ -2149,7 +2160,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); /* diff --git a/usr/src/uts/common/os/zone.c b/usr/src/uts/common/os/zone.c index 1db130797c..3d4e7ed7cd 100644 --- a/usr/src/uts/common/os/zone.c +++ b/usr/src/uts/common/os/zone.c @@ -21,7 +21,7 @@ /* * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2019, Joyent, Inc. + * Copyright 2019 Joyent, Inc. * Copyright (c) 2016 by Delphix. All rights reserved. * Copyright 2018 OmniOS Community Edition (OmniOSce) Association. */ @@ -4478,7 +4478,11 @@ zsched(void *arg) bcopy("zsched", PTOU(pp)->u_comm, sizeof ("zsched")); PTOU(pp)->u_argc = 0; PTOU(pp)->u_argv = 0; + PTOU(pp)->u_argvstrs = 0; + PTOU(pp)->u_argvstrsize = 0; PTOU(pp)->u_envp = 0; + PTOU(pp)->u_envstrs = 0; + PTOU(pp)->u_envstrsize = 0; PTOU(pp)->u_commpagep = 0; closeall(P_FINFO(pp)); diff --git a/usr/src/uts/common/sys/exec.h b/usr/src/uts/common/sys/exec.h index 12115b7e27..d66a8dc15d 100644 --- a/usr/src/uts/common/sys/exec.h +++ b/usr/src/uts/common/sys/exec.h @@ -80,7 +80,8 @@ typedef struct uarg { ssize_t na; ssize_t ne; ssize_t nc; - ssize_t arglen; + size_t argstrlen; + size_t envstrlen; char *fname; char *pathname; size_t auxsize; diff --git a/usr/src/uts/common/sys/procfs.h b/usr/src/uts/common/sys/procfs.h index 99da92ab79..b24b2d9da1 100644 --- a/usr/src/uts/common/sys/procfs.h +++ b/usr/src/uts/common/sys/procfs.h @@ -25,7 +25,7 @@ */ /* * Copyright 2012 DEY Storage Systems, Inc. All rights reserved. - * Copyright 2018 Joyent, Inc. + * Copyright 2019 Joyent, Inc. */ #ifndef _SYS_PROCFS_H @@ -271,10 +271,12 @@ typedef struct lwpsinfo { int pr_filler[4]; /* reserved for future use */ } lwpsinfo_t; +#define PRARGSZ 80 /* number of chars of arguments */ +#define PRMAXARGVLEN 4096 /* max len of /proc/%s/argv */ + /* * process ps(1) information file. /proc/<pid>/psinfo */ -#define PRARGSZ 80 /* number of chars of arguments */ typedef struct psinfo { int pr_flag; /* process flags (DEPRECATED; do not use) */ int pr_nlwp; /* number of active lwps in the process */ diff --git a/usr/src/uts/common/sys/user.h b/usr/src/uts/common/sys/user.h index 15b4d0b247..8c424e7bf3 100644 --- a/usr/src/uts/common/sys/user.h +++ b/usr/src/uts/common/sys/user.h @@ -26,7 +26,7 @@ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* - * Copyright (c) 2018, Joyent, Inc. + * Copyright 2019 Joyent, Inc. */ @@ -227,7 +227,11 @@ typedef struct user { char u_psargs[PSARGSZ]; /* arguments from exec */ int u_argc; /* value of argc passed to main() */ uintptr_t u_argv; /* value of argv passed to main() */ + uintptr_t u_argvstrs; /* argv string space pointer */ + size_t u_argvstrsize; /* size of argv string space */ uintptr_t u_envp; /* value of envp passed to main() */ + uintptr_t u_envstrs; /* env string space pointer */ + size_t u_envstrsize; /* size of env string space */ uintptr_t u_commpagep; /* address of mapped comm page */ /* |