summaryrefslogtreecommitdiff
path: root/usr/src/uts/common
diff options
context:
space:
mode:
authorJohn Levon <john.levon@joyent.com>2019-09-12 20:26:08 +0000
committerJohn Levon <john.levon@joyent.com>2019-09-12 20:26:08 +0000
commitc6dd2307128aa25ac346f7818440cd5cfd1f7221 (patch)
tree9bda47db825ca7697580de5510764735b0748431 /usr/src/uts/common
parent1cc6f4c0fcc857bd86b9a8234d9ff75d5a6b9384 (diff)
downloadillumos-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.c2
-rw-r--r--usr/src/uts/common/brand/lx/os/lx_misc.c71
-rw-r--r--usr/src/uts/common/brand/lx/procfs/lx_prvnops.c104
-rw-r--r--usr/src/uts/common/brand/lx/sys/lx_brand.h15
-rw-r--r--usr/src/uts/common/brand/lx/sys/lx_misc.h3
-rw-r--r--usr/src/uts/common/contract/process.c8
-rw-r--r--usr/src/uts/common/fs/proc/prargv.c103
-rw-r--r--usr/src/uts/common/fs/proc/prdata.h4
-rw-r--r--usr/src/uts/common/fs/proc/prvnops.c64
-rw-r--r--usr/src/uts/common/os/exec.c39
-rw-r--r--usr/src/uts/common/os/zone.c6
-rw-r--r--usr/src/uts/common/sys/exec.h3
-rw-r--r--usr/src/uts/common/sys/procfs.h6
-rw-r--r--usr/src/uts/common/sys/user.h6
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 */
/*