diff options
-rw-r--r-- | bin/ps/ps.c | 2 | ||||
-rw-r--r-- | lib/libc/gen/setproctitle.c | 9 | ||||
-rw-r--r-- | lib/libkvm/kvm_proc.c | 48 | ||||
-rw-r--r-- | lib/libutil/setproctitle.c | 9 | ||||
-rw-r--r-- | sys/kern/kern_exec.c | 23 | ||||
-rw-r--r-- | sys/kern/kern_exit.c | 6 | ||||
-rw-r--r-- | sys/kern/kern_fork.c | 3 | ||||
-rw-r--r-- | sys/kern/kern_proc.c | 56 | ||||
-rw-r--r-- | sys/sys/imgact.h | 1 | ||||
-rw-r--r-- | sys/sys/proc.h | 16 | ||||
-rw-r--r-- | sys/sys/sysctl.h | 1 |
11 files changed, 171 insertions, 3 deletions
diff --git a/bin/ps/ps.c b/bin/ps/ps.c index 305d4c7..72828bb 100644 --- a/bin/ps/ps.c +++ b/bin/ps/ps.c @@ -520,7 +520,7 @@ saveuser(ki) /* * save arguments if needed */ - if (needcomm && UREADOK(ki)) { + if (needcomm && (UREADOK(ki) || (KI_PROC(ki)->p_args != NULL))) { ki->ki_args = fmt(kvm_getargv, ki, KI_PROC(ki)->p_comm, MAXCOMLEN); } else if (needcomm) { diff --git a/lib/libc/gen/setproctitle.c b/lib/libc/gen/setproctitle.c index a5cf234..36c21db 100644 --- a/lib/libc/gen/setproctitle.c +++ b/lib/libc/gen/setproctitle.c @@ -29,6 +29,7 @@ #include <stdio.h> #include <string.h> #include <stdlib.h> +#include <unistd.h> /* * Older FreeBSD 2.0, 2.1 and 2.2 had different ps_strings structures and @@ -74,6 +75,7 @@ setproctitle(fmt, va_alist) va_list ap; size_t len; unsigned long ul_ps_strings; + int oid[4]; #if defined(__STDC__) va_start(ap, fmt); @@ -103,6 +105,13 @@ setproctitle(fmt, va_alist) va_end(ap); + /* Set the title into the kernel cached command line */ + oid[0] = CTL_KERN; + oid[1] = KERN_PROC; + oid[2] = KERN_PROC_ARGS; + oid[3] = getpid(); + sysctl(oid, 4, 0, 0, buf, strlen(buf) + 1); + if (ps_strings == NULL) { len = sizeof(ul_ps_strings); if (sysctlbyname("kern.ps_strings", &ul_ps_strings, &len, NULL, diff --git a/lib/libkvm/kvm_proc.c b/lib/libkvm/kvm_proc.c index 9543fee..feba974 100644 --- a/lib/libkvm/kvm_proc.c +++ b/lib/libkvm/kvm_proc.c @@ -33,6 +33,8 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + * + * $FreeBSD$ */ #if defined(LIBC_SCCS) && !defined(lint) @@ -666,6 +668,52 @@ kvm_getargv(kd, kp, nchr) const struct kinfo_proc *kp; int nchr; { + int oid[4]; + int i, l; + static int buflen; + static char *buf, *p; + static char **bufp; + static int argc; + + if (!buflen) { + l = sizeof(buflen); + i = sysctlbyname("kern.ps_arg_cache_limit", + &buflen, &l, NULL, 0); + if (i == -1) { + buflen == 0; + } else { + buf = malloc(buflen); + if (buf == NULL) + buflen = 0; + argc = 32; + bufp = malloc(sizeof(char *) * argc); + } + } + if (buf != NULL) { + oid[0] = CTL_KERN; + oid[1] = KERN_PROC; + oid[2] = KERN_PROC_ARGS; + oid[3] = kp->kp_proc.p_pid; + l = buflen; + i = sysctl(oid, 4, buf, &l, 0, 0); + if (i == 0 && l > 0) { + i = 0; + p = buf; + do { + bufp[i++] = p; + p += strlen(p) + 1; + if (i >= argc) { + argc += argc; + bufp = realloc(bufp, + sizeof(char *) * argc); + } + } while (p < buf + l); + bufp[i++] = 0; + return (bufp); + } + } + if (kp->kp_proc.p_flag & P_SYSTEM) + return (NULL); return (kvm_doargv(kd, kp, nchr, ps_str_a)); } diff --git a/lib/libutil/setproctitle.c b/lib/libutil/setproctitle.c index a5cf234..36c21db 100644 --- a/lib/libutil/setproctitle.c +++ b/lib/libutil/setproctitle.c @@ -29,6 +29,7 @@ #include <stdio.h> #include <string.h> #include <stdlib.h> +#include <unistd.h> /* * Older FreeBSD 2.0, 2.1 and 2.2 had different ps_strings structures and @@ -74,6 +75,7 @@ setproctitle(fmt, va_alist) va_list ap; size_t len; unsigned long ul_ps_strings; + int oid[4]; #if defined(__STDC__) va_start(ap, fmt); @@ -103,6 +105,13 @@ setproctitle(fmt, va_alist) va_end(ap); + /* Set the title into the kernel cached command line */ + oid[0] = CTL_KERN; + oid[1] = KERN_PROC; + oid[2] = KERN_PROC_ARGS; + oid[3] = getpid(); + sysctl(oid, 4, 0, 0, buf, strlen(buf) + 1); + if (ps_strings == NULL) { len = sizeof(ul_ps_strings); if (sysctlbyname("kern.ps_strings", &ul_ps_strings, &len, NULL, diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index 35aa228..900da01 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -63,6 +63,8 @@ #include <machine/reg.h> +MALLOC_DEFINE(M_PARGS, "proc-args", "Process arguments"); + static long *exec_copyout_strings __P((struct image_params *)); static long ps_strings = PS_STRINGS; @@ -71,6 +73,10 @@ SYSCTL_LONG(_kern, KERN_PS_STRINGS, ps_strings, CTLFLAG_RD, &ps_strings, ""); static long usrstack = USRSTACK; SYSCTL_LONG(_kern, KERN_USRSTACK, usrstack, CTLFLAG_RD, &usrstack, ""); +u_long ps_arg_cache_limit = PAGE_SIZE / 16; +SYSCTL_LONG(_kern, OID_AUTO, ps_arg_cache_limit, CTLFLAG_RW, + &ps_arg_cache_limit, ""); + /* * Each of the items is a pointer to a `const struct execsw', hence the * double pointer here. @@ -316,6 +322,21 @@ interpret: setregs(p, imgp->entry_addr, (u_long)(uintptr_t)stack_base, imgp->ps_strings); + /* Free any previous argument cache */ + if (p->p_args && --p->p_args->ar_ref == 0) + FREE(p->p_args, M_PARGS); + p->p_args = NULL; + + /* Cache arguments if they fit inside our allowance */ + i = imgp->endargs - imgp->stringbase; + if (ps_arg_cache_limit >= i + sizeof(struct pargs)) { + MALLOC(p->p_args, struct pargs *, sizeof(struct pargs) + i, + M_PARGS, M_WAITOK); + p->p_args->ar_ref = 1; + p->p_args->ar_length = i; + bcopy(imgp->stringbase, p->p_args->ar_args, i); + } + exec_fail_dealloc: /* @@ -511,6 +532,8 @@ exec_extract_strings(imgp) } } + imgp->endargs = imgp->stringp; + /* * extract environment strings */ diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index 6fe2171..6c00e43 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -494,6 +494,12 @@ loop: } /* + * Remove unused arguments + */ + if (p->p_args && --p->p_args->ar_ref == 0) + FREE(p->p_args, M_PARGS); + + /* * Finally finished with old proc entry. * Unlink it from its process group and free it. */ diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index 0fbe915..9268592 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -337,6 +337,9 @@ again: p2->p_flag |= P_JAILED; } + if (p2->p_args) + p2->p_args->ar_ref++; + if (flags & RFSIGSHARE) { p2->p_procsig = p1->p_procsig; p2->p_procsig->ps_refcnt++; diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c index d420821..4c3ee1c 100644 --- a/sys/kern/kern_proc.c +++ b/sys/kern/kern_proc.c @@ -38,8 +38,8 @@ #include <sys/systm.h> #include <sys/kernel.h> #include <sys/sysctl.h> -#include <sys/proc.h> #include <sys/malloc.h> +#include <sys/proc.h> #include <sys/filedesc.h> #include <sys/tty.h> #include <sys/signalvar.h> @@ -609,6 +609,57 @@ sysctl_kern_proc SYSCTL_HANDLER_ARGS return (0); } +/* + * This sysctl allows a process to retrieve the argument list or process + * title for another process without groping around in the address space + * of the other process. It also allow a process to set its own "process + * title to a string of its own choice. + */ +static int +sysctl_kern_proc_args SYSCTL_HANDLER_ARGS +{ + int *name = (int*) arg1; + u_int namelen = arg2; + struct proc *p; + struct pargs *pa; + int error = 0; + + if (namelen != 1) + return (EINVAL); + + p = pfind((pid_t)name[0]); + if (!p) + return (0); + + if (!PRISON_CHECK(curproc, p)) + return (0); + + if (req->newptr && curproc != p) + return (EPERM); + + if (req->oldptr && p->p_args != NULL) + error = SYSCTL_OUT(req, p->p_args->ar_args, p->p_args->ar_length); + if (req->newptr == NULL) + return (error); + + if (p->p_args && --p->p_args->ar_ref == 0) + FREE(p->p_args, M_PARGS); + p->p_args = NULL; + + if (req->newlen + sizeof(struct pargs) > ps_arg_cache_limit) + return (error); + + MALLOC(pa, struct pargs *, sizeof(struct pargs) + req->newlen, + M_PARGS, M_WAITOK); + pa->ar_ref = 1; + pa->ar_length = req->newlen; + error = SYSCTL_IN(req, pa->ar_args, req->newlen); + if (!error) + p->p_args = pa; + else + FREE(pa, M_PARGS); + return (error); +} SYSCTL_NODE(_kern, KERN_PROC, proc, CTLFLAG_RD, 0, "Process table"); @@ -629,3 +680,6 @@ SYSCTL_NODE(_kern_proc, KERN_PROC_RUID, ruid, CTLFLAG_RD, SYSCTL_NODE(_kern_proc, KERN_PROC_PID, pid, CTLFLAG_RD, sysctl_kern_proc, "Process table"); + +SYSCTL_NODE(_kern_proc, KERN_PROC_ARGS, args, CTLFLAG_RW, + sysctl_kern_proc_args, "Return process argument"); diff --git a/sys/sys/imgact.h b/sys/sys/imgact.h index ec147ba..83ed79c 100644 --- a/sys/sys/imgact.h +++ b/sys/sys/imgact.h @@ -44,6 +44,7 @@ struct image_params { const char *image_header; /* head of file to exec */ char *stringbase; /* base address of tmp string storage */ char *stringp; /* current 'end' pointer of tmp strings */ + char *endargs; /* end of argv vector */ int stringspace; /* space left in tmp string storage area */ int argc, envc; /* count of argument and environment strings */ char *argv0; /* Replacement for argv[0] when interpreting */ diff --git a/sys/sys/proc.h b/sys/sys/proc.h index 8144a46..9373d5d 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -98,6 +98,16 @@ struct pasleep { }; /* + * pargs, used to hold a copy of the command line, if it had a sane + * length + */ +struct pargs { + u_int ar_ref; /* Reference count */ + u_int ar_length; /* Length */ + u_char ar_args[0]; /* Arguments */ +}; + +/* * Description of a process. * * This structure contains the information needed to manage a thread of @@ -211,7 +221,8 @@ struct proc { struct sysentvec *p_sysent; /* System call dispatch information. */ struct rtprio p_rtprio; /* Realtime priority. */ - struct prison *p_prison; + struct prison *p_prison; + struct pargs *p_args; /* End area that is copied on creation. */ #define p_endcopy p_addr struct user *p_addr; /* Kernel virtual addr of u-area (PROC ONLY). */ @@ -299,6 +310,7 @@ struct pcred { MALLOC_DECLARE(M_SESSION); MALLOC_DECLARE(M_SUBPROC); MALLOC_DECLARE(M_ZOMBIE); +MALLOC_DECLARE(M_PARGS); #endif /* flags for suser_xxx() */ @@ -371,6 +383,8 @@ extern int whichqs; /* Bit mask summary of non-empty Q's. */ extern int whichrtqs; /* Bit mask summary of non-empty Q's. */ extern int whichidqs; /* Bit mask summary of non-empty Q's. */ +extern u_long ps_arg_cache_limit; + struct proc *pfind __P((pid_t)); /* Find process by id. */ struct pgrp *pgfind __P((pid_t)); /* Find process group by id. */ diff --git a/sys/sys/sysctl.h b/sys/sys/sysctl.h index d8564dd..bea866e 100644 --- a/sys/sys/sysctl.h +++ b/sys/sys/sysctl.h @@ -317,6 +317,7 @@ void sysctl_unregister_oid(struct sysctl_oid *oidp); #define KERN_PROC_TTY 4 /* by controlling tty */ #define KERN_PROC_UID 5 /* by effective uid */ #define KERN_PROC_RUID 6 /* by real uid */ +#define KERN_PROC_ARGS 7 /* get/set arguments/proctitle */ /* * KERN_IPC identifiers |