Print this page

        

@@ -19,11 +19,11 @@
  * CDDL HEADER END
  */
 
 /*
  * 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.
  * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
  * Copyright 2022 MNX Cloud, Inc.
  * Copyright 2023 Oxide Computer Company
  */

@@ -169,12 +169,16 @@
                 "path" },
         { PR_CTDIR,     27 * sizeof (prdirent_t), sizeof (prdirent_t),
                 "contracts" },
         { PR_SECFLAGS,  28 * sizeof (prdirent_t), sizeof (prdirent_t),
                 "secflags" },
+        { PR_ARGV,      29 * sizeof (prdirent_t), sizeof (prdirent_t),
+                "argv" },
+        { PR_CMDLINE,   30 * sizeof (prdirent_t), sizeof (prdirent_t),
+                "cmdline" },
 #if defined(__x86)
-        { PR_LDT,       29 * sizeof (prdirent_t), sizeof (prdirent_t),
+        { PR_LDT,       31 * sizeof (prdirent_t), sizeof (prdirent_t),
                 "ldt" },
 #endif
 };
 
 #define NPIDDIRFILES    (sizeof (piddir) / sizeof (piddir[0]) - 2)

@@ -591,10 +595,11 @@
         pr_read_map(), pr_read_rmap(), pr_read_xmap(),
         pr_read_cred(), pr_read_sigact(), pr_read_auxv(),
 #if defined(__x86)
         pr_read_ldt(),
 #endif
+        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(),
         pr_read_xregs(), pr_read_priv(),
         pr_read_spymaster(), pr_read_secflags(),

@@ -621,10 +626,12 @@
         pr_read_sigact,         /* /proc/<pid>/sigact                   */
         pr_read_auxv,           /* /proc/<pid>/auxv                     */
 #if defined(__x86)
         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                 */
         pr_read_watch,          /* /proc/<pid>/watch                    */
         pr_read_inval,          /* /proc/<pid>/cwd                      */

@@ -687,10 +694,80 @@
 
         return (error);
 }
 
 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;
+
+        /*
+         * Allocate a scratch buffer for collection of the process arguments.
+         */
+        args = kmem_alloc(asz, KM_SLEEP);
+
+        ASSERT(pnp->pr_type == PR_ARGV);
+
+        if ((error = prlock(pnp, ZNO)) != 0) {
+                kmem_free(args, asz);
+                return (error);
+        }
+
+        if ((error = prreadargv(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_as(prnode_t *pnp, uio_t *uiop)
 {
         int error;
 
         ASSERT(pnp->pr_type == PR_AS);

@@ -1928,10 +2005,12 @@
         pr_read_sigact_32,      /* /proc/<pid>/sigact                   */
         pr_read_auxv_32,        /* /proc/<pid>/auxv                     */
 #if defined(__x86)
         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                 */
         pr_read_watch_32,       /* /proc/<pid>/watch                    */
         pr_read_inval,          /* /proc/<pid>/cwd                      */

@@ -2856,10 +2935,107 @@
 #else
         return (pr_read_function[pnp->pr_type](pnp, uiop, cr));
 #endif
 }
 
+/*
+ * We make pr_write_psinfo_fname() somewhat simpler by asserting at compile
+ * time that PRFNSZ has the same definition as MAXCOMLEN.
+ */
+#if PRFNSZ != MAXCOMLEN
+#error PRFNSZ/MAXCOMLEN mismatch
+#endif
+
+static int
+pr_write_psinfo_fname(prnode_t *pnp, uio_t *uiop)
+{
+        char fname[PRFNSZ];
+        int offset = offsetof(psinfo_t, pr_fname), error;
+
+#ifdef _SYSCALL32_IMPL
+        if (curproc->p_model != DATAMODEL_LP64)
+                offset = offsetof(psinfo32_t, pr_fname);
+#endif
+
+        /*
+         * If this isn't a write to pr_fname (or if the size doesn't match
+         * PRFNSZ) return.
+         */
+        if (uiop->uio_offset != offset || uiop->uio_resid != PRFNSZ)
+                return (0);
+
+        if ((error = uiomove(fname, PRFNSZ, UIO_WRITE, uiop)) != 0)
+                return (error);
+
+        fname[PRFNSZ - 1] = '\0';
+
+        if ((error = prlock(pnp, ZNO)) != 0)
+                return (error);
+
+        bcopy(fname, pnp->pr_common->prc_proc->p_user.u_comm, PRFNSZ);
+
+        prunlock(pnp);
+
+        return (0);
+}
+
+/*
+ * We make pr_write_psinfo_psargs() somewhat simpler by asserting at compile
+ * time that PRARGSZ has the same definition as PSARGSZ.
+ */
+#if PRARGSZ != PSARGSZ
+#error PRARGSZ/PSARGSZ mismatch
+#endif
+
+static int
+pr_write_psinfo_psargs(prnode_t *pnp, uio_t *uiop)
+{
+        char psargs[PRARGSZ];
+        int offset = offsetof(psinfo_t, pr_psargs), error;
+
+#ifdef _SYSCALL32_IMPL
+        if (curproc->p_model != DATAMODEL_LP64)
+                offset = offsetof(psinfo32_t, pr_psargs);
+#endif
+
+        /*
+         * If this isn't a write to pr_psargs (or if the size doesn't match
+         * PRARGSZ) return.
+         */
+        if (uiop->uio_offset != offset || uiop->uio_resid != PRARGSZ)
+                return (0);
+
+        if ((error = uiomove(psargs, PRARGSZ, UIO_WRITE, uiop)) != 0)
+                return (error);
+
+        psargs[PRARGSZ - 1] = '\0';
+
+        if ((error = prlock(pnp, ZNO)) != 0)
+                return (error);
+
+        bcopy(psargs, pnp->pr_common->prc_proc->p_user.u_psargs, PRARGSZ);
+
+        prunlock(pnp);
+
+        return (0);
+}
+
+int
+pr_write_psinfo(prnode_t *pnp, uio_t *uiop)
+{
+        int error;
+
+        if ((error = pr_write_psinfo_fname(pnp, uiop)) != 0)
+                return (error);
+
+        if ((error = pr_write_psinfo_psargs(pnp, uiop)) != 0)
+                return (error);
+
+        return (0);
+}
+
+
 /* Note we intentionally don't handle partial writes/updates. */
 static int
 pr_write_lwpname(prnode_t *pnp, uio_t *uiop)
 {
         kthread_t *t = NULL;

@@ -2982,10 +3158,13 @@
                  */
                 if (error == EINTR)
                         uiop->uio_resid = resid;
                 return (error);
 
+        case PR_PSINFO:
+                return (pr_write_psinfo(pnp, uiop));
+
         case PR_LWPNAME:
                 return (pr_write_lwpname(pnp, uiop));
 
         default:
                 return ((vp->v_type == VDIR)? EISDIR : EBADF);

@@ -3311,10 +3490,17 @@
                     PR_OBJSIZE(struct sigaction32, struct sigaction);
                 break;
         case PR_AUXV:
                 vap->va_size = __KERN_NAUXV_IMPL * PR_OBJSIZE(auxv32_t, auxv_t);
                 break;
+        case PR_ARGV:
+                if ((p->p_flag & SSYS) || p->p_as == &kas) {
+                        vap->va_size = PSARGSZ;
+                } else {
+                        vap->va_size = PRMAXARGVLEN;
+                }
+                break;
 #if defined(__x86)
         case PR_LDT:
                 mutex_exit(&p->p_lock);
                 mutex_enter(&p->p_ldtlock);
                 vap->va_size = prnldt(p) * sizeof (struct ssd);

@@ -3433,10 +3619,11 @@
                         vap->va_size = 0;
                 break;
 #endif
         case PR_CTL:
         case PR_LWPCTL:
+        case PR_CMDLINE:
         default:
                 vap->va_size = 0;
                 break;
         }
 

@@ -3487,10 +3674,12 @@
         case PR_LWPDIR:
         case PR_LWPIDDIR:
         case PR_USAGE:
         case PR_LUSAGE:
         case PR_LWPUSAGE:
+        case PR_ARGV:
+        case PR_CMDLINE:
                 p = pr_p_lock(pnp);
                 mutex_exit(&pr_pidlock);
                 if (p == NULL)
                         return (ENOENT);
                 prunlock(pnp);

@@ -3572,10 +3761,12 @@
         pr_lookup_notdir,       /* /proc/<pid>/sigact                   */
         pr_lookup_notdir,       /* /proc/<pid>/auxv                     */
 #if defined(__x86)
         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                 */
         pr_lookup_notdir,       /* /proc/<pid>/watch                    */
         pr_lookup_notdir,       /* /proc/<pid>/cwd                      */

@@ -4902,20 +5093,22 @@
         case PR_PIDFILE:
         case PR_LWPIDFILE:
                 pnp->pr_mode = 0600;    /* read-write by owner only */
                 break;
 
+        case PR_PSINFO:
         case PR_LWPNAME:
                 pnp->pr_mode = 0644;    /* readable by all + owner can write */
                 break;
 
-        case PR_PSINFO:
         case PR_LPSINFO:
         case PR_LWPSINFO:
         case PR_USAGE:
         case PR_LUSAGE:
         case PR_LWPUSAGE:
+        case PR_ARGV:
+        case PR_CMDLINE:
                 pnp->pr_mode = 0444;    /* read-only by all */
                 break;
 
         default:
                 pnp->pr_mode = 0400;    /* read-only by owner only */

@@ -5019,10 +5212,12 @@
         pr_readdir_notdir,      /* /proc/<pid>/sigact                   */
         pr_readdir_notdir,      /* /proc/<pid>/auxv                     */
 #if defined(__x86)
         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                 */
         pr_readdir_notdir,      /* /proc/<pid>/watch                    */
         pr_readdir_notdir,      /* /proc/<pid>/cwd                      */

@@ -5172,10 +5367,12 @@
                         switch (dirp->d_ino) {
                         case PR_PIDDIR:
                         case PR_PROCDIR:
                         case PR_PSINFO:
                         case PR_USAGE:
+                        case PR_ARGV:
+                        case PR_CMDLINE:
                                 break;
                         default:
                                 continue;
                         }
                 }