kern/54604: Made 'ps -e' procfs-independent [PATCH].

Pawel Jakub Dawidek nick at garage.freebsd.pl
Fri Jul 18 00:40:29 PDT 2003


>Number:         54604
>Category:       kern
>Synopsis:       Made 'ps -e' procfs-independent [PATCH].
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Fri Jul 18 00:40:07 PDT 2003
>Closed-Date:
>Last-Modified:
>Originator:     Pawel Jakub Dawidek
>Release:        FreeBSD 5.1-CURRENT i386
>Organization:
>Environment:
System:	FreeBSD czort.hell.none FreeBSD 5.1-CURRENT i386
osreldate: 501102

	
>Description:
	For now, 'ps -e' depends on procfs. With this patch environment
	variables are stored as arguments and could be fetched via sysctls
	kern.proc.env.<PID>. By default kern.ps_envsopen sysctl is set to 0,
	but it should be save to set it to 1. I'm using pargs_ref_lock to
	protect environments reference count also, I think there is no need to
	create new mutex and duplicate existing functions (pargs_*). While I'm
	here, removed 'extern int ps_showallprocs' - there is no such variable
	in FreeBSD 5.x.

>How-To-Repeat:
	Try to run 'ps -e' without procfs mounted.
>Fix:
Patch against FreeBSD 5.1-CURRENT, kern.osreldate: 501102.

diff -upr /usr/src/bin/ps/ps.c src/bin/ps/ps.c
--- /usr/src/bin/ps/ps.c	Tue Jul  1 11:23:22 2003
+++ src/bin/ps/ps.c	Fri Jul 18 09:11:09 2003
@@ -568,7 +568,7 @@ saveuser(KINFO *ki)
 	} else {
 		ki->ki_args = NULL;
 	}
-	if (needenv && UREADOK(ki)) {
+	if (needenv && (UREADOK(ki) || (ki->ki_p->ki_envs != NULL))) {
 		ki->ki_env = strdup(fmt(kvm_getenvv, ki, (char *)NULL, 0));
 	} else if (needenv) {
 		ki->ki_env = malloc(3);
diff -upr /usr/src/lib/libkvm/kvm_proc.c src/lib/libkvm/kvm_proc.c
--- /usr/src/lib/libkvm/kvm_proc.c	Tue Jul  1 11:27:05 2003
+++ src/lib/libkvm/kvm_proc.c	Fri Jul 18 09:10:07 2003
@@ -188,6 +188,7 @@ kvm_proclist(kd, what, arg, p, bp, maxcn
 		kp->ki_addr = proc.p_uarea;
 		/* kp->ki_kstack = proc.p_thread.td_kstack; XXXKSE */
 		kp->ki_args = proc.p_args;
+		kp->ki_envs = proc.p_envs;
 		kp->ki_tracep = proc.p_tracevp;
 		kp->ki_textvp = proc.p_textvp;
 		kp->ki_fd = proc.p_fd;
@@ -834,13 +835,14 @@ kvm_doargv(kd, kp, nchr, info)
 }
 
 /*
- * Get the command args.  This code is now machine independent.
+ * Get the command args or envs.  This code is now machine independent.
  */
-char **
-kvm_getargv(kd, kp, nchr)
+static char **
+kvm_getargvenvv(kd, kp, nchr, args)
 	kvm_t *kd;
 	const struct kinfo_proc *kp;
 	int nchr;
+	int args;	/* 1 for args, 0 for envs */
 {
 	int oid[4];
 	int i;
@@ -858,8 +860,13 @@ kvm_getargv(kd, kp, nchr)
 
 	if (!buflen) {
 		bufsz = sizeof(buflen);
-		i = sysctlbyname("kern.ps_arg_cache_limit", 
-		    &buflen, &bufsz, NULL, 0);
+		if (args) {
+			i = sysctlbyname("kern.ps_arg_cache_limit", &buflen,
+			    &bufsz, NULL, 0);
+		} else {
+			i = sysctlbyname("kern.ps_env_cache_limit", &buflen,
+			    &bufsz, NULL, 0);
+		}
 		if (i == -1) {
 			buflen = 0;
 		} else {
@@ -873,7 +880,7 @@ kvm_getargv(kd, kp, nchr)
 	if (buf != NULL) {
 		oid[0] = CTL_KERN;
 		oid[1] = KERN_PROC;
-		oid[2] = KERN_PROC_ARGS;
+		oid[2] = args ? KERN_PROC_ARGS : KERN_PROC_ENVS;
 		oid[3] = kp->ki_pid;
 		bufsz = buflen;
 		i = sysctl(oid, 4, buf, &bufsz, 0, 0);
@@ -895,7 +902,17 @@ kvm_getargv(kd, kp, nchr)
 	}
 	if (kp->ki_flag & P_SYSTEM)
 		return (NULL);
-	return (kvm_doargv(kd, kp, nchr, ps_str_a));
+	return (kvm_doargv(kd, kp, nchr, args ? ps_str_a : ps_str_e));
+}
+
+char **
+kvm_getargv(kd, kp, nchr)
+	kvm_t *kd;
+	const struct kinfo_proc *kp;
+	int nchr;
+{
+
+	return (kvm_getargvenvv(kd, kp, nchr, 1));
 }
 
 char **
@@ -904,7 +921,8 @@ kvm_getenvv(kd, kp, nchr)
 	const struct kinfo_proc *kp;
 	int nchr;
 {
-	return (kvm_doargv(kd, kp, nchr, ps_str_e));
+
+	return (kvm_getargvenvv(kd, kp, nchr, 0));
 }
 
 /*
diff -upr /usr/src/sys/compat/linprocfs/linprocfs.c src/sys/compat/linprocfs/linprocfs.c
--- /usr/src/sys/compat/linprocfs/linprocfs.c	Tue Jul  1 11:28:26 2003
+++ src/sys/compat/linprocfs/linprocfs.c	Fri Jul 18 00:09:38 2003
@@ -721,7 +721,15 @@ linprocfs_doproccmdline(PFS_FILL_ARGS)
 static int
 linprocfs_doprocenviron(PFS_FILL_ARGS)
 {
-	sbuf_printf(sb, "doprocenviron\n%c", '\0');
+
+	PROC_LOCK(p);
+	if (p->p_envs != NULL && (ps_envsopen || !p_cansee(td, p))) {
+		sbuf_bcpy(sb, p->p_envs->ar_envs, p->p_envs->ar_length);
+		PROC_UNLOCK(p);
+	} else {
+		PROC_UNLOCK(p);
+		sbuf_printf(sb, "doprocenviron\n%c", '\0');
+	}
 
 	return (0);
 }
diff -upr /usr/src/sys/compat/svr4/svr4_misc.c src/sys/compat/svr4/svr4_misc.c
--- /usr/src/sys/compat/svr4/svr4_misc.c	Tue Jul  1 11:28:26 2003
+++ src/sys/compat/svr4/svr4_misc.c	Thu Jul 17 22:08:13 2003
@@ -1343,9 +1343,10 @@ loop:
 			q->p_ucred = NULL;
 
 			/*
-			 * Remove unused arguments
+			 * Remove unused arguments and environment variables
 			 */
 			pargs_drop(q->p_args);
+			pargs_drop(q->p_envs);
 			PROC_UNLOCK(q);
 
 			/*
diff -upr /usr/src/sys/kern/kern_exec.c src/sys/kern/kern_exec.c
--- /usr/src/sys/kern/kern_exec.c	Thu Jul 17 21:56:44 2003
+++ src/sys/kern/kern_exec.c	Fri Jul 18 09:14:05 2003
@@ -95,8 +95,17 @@ u_long ps_arg_cache_limit = PAGE_SIZE / 
 SYSCTL_ULONG(_kern, OID_AUTO, ps_arg_cache_limit, CTLFLAG_RW, 
     &ps_arg_cache_limit, 0, "");
 
+u_long ps_env_cache_limit = PAGE_SIZE / 4;
+SYSCTL_ULONG(_kern, OID_AUTO, ps_env_cache_limit, CTLFLAG_RW, 
+    &ps_env_cache_limit, 0, "");
+
 int ps_argsopen = 1;
-SYSCTL_INT(_kern, OID_AUTO, ps_argsopen, CTLFLAG_RW, &ps_argsopen, 0, "");
+SYSCTL_INT(_kern, OID_AUTO, ps_argsopen, CTLFLAG_RW, &ps_argsopen, 0,
+    "get/set arguments/proctitle");
+
+int ps_envsopen = 0;
+SYSCTL_INT(_kern, OID_AUTO, ps_envsopen, CTLFLAG_RW, &ps_envsopen, 0,
+    "get/set environment variables");
 
 #ifdef __ia64__
 /* XXX HACK */
@@ -159,11 +168,12 @@ kern_execve(td, fname, argv, envv, mac_p
 	struct ucred *newcred = NULL, *oldcred;
 	struct uidinfo *euip;
 	register_t *stack_base;
-	int error, len, i;
+	int error, len, i, argslen, envslen;
 	struct image_params image_params, *imgp;
 	struct vattr attr;
 	int (*img_first)(struct image_params *);
 	struct pargs *oldargs = NULL, *newargs = NULL;
+	struct pargs *oldenvs = NULL, *newenvs = NULL;
 	struct sigacts *oldsigacts, *newsigacts;
 #ifdef KTRACE
 	struct vnode *tracevp = NULL;
@@ -393,9 +403,12 @@ interpret:
 	 */
 	newcred = crget();
 	euip = uifind(attr.va_uid);
-	i = imgp->endargs - imgp->stringbase;
-	if (ps_arg_cache_limit >= i + sizeof(struct pargs))
-		newargs = pargs_alloc(i);
+	argslen = imgp->endargs - imgp->startargs;
+	if (ps_arg_cache_limit >= argslen + sizeof(struct pargs))
+		newargs = pargs_alloc(argslen);
+	envslen = imgp->endenvs - imgp->startenvs;
+	if (ps_env_cache_limit >= envslen + sizeof(struct pargs))
+		newenvs = pargs_alloc(envslen);
 
 	/* close files on exec */
 	fdcloseexec(td);
@@ -577,11 +590,22 @@ interpret:
 	p->p_args = NULL;
 
 	/* Cache arguments if they fit inside our allowance */
-	if (ps_arg_cache_limit >= i + sizeof(struct pargs)) {
-		bcopy(imgp->stringbase, newargs->ar_args, i);
+	if (ps_arg_cache_limit >= argslen + sizeof(struct pargs)) {
+		bcopy(imgp->startargs, newargs->ar_args, argslen);
 		p->p_args = newargs;
 		newargs = NULL;
 	}
+
+	/* Free any previous environment cache */
+	oldenvs = p->p_envs;
+	p->p_envs = NULL;
+
+	/* Cache environment variables if they fit inside our allowance */
+	if (ps_env_cache_limit >= envslen + sizeof(struct pargs)) {
+		bcopy(imgp->startenvs, newenvs->ar_envs, envslen);
+		p->p_envs = newenvs;
+		newenvs = NULL;
+	}
 	PROC_UNLOCK(p);
 
 	/* Set values passed into the program in registers. */
@@ -618,6 +642,10 @@ done1:
 		pargs_drop(oldargs);
 	if (newargs != NULL)
 		pargs_drop(newargs);
+	if (oldenvs != NULL)
+		pargs_drop(oldenvs);
+	if (newenvs != NULL)
+		pargs_drop(newenvs);
 	if (oldsigacts != NULL)
 		sigacts_free(oldsigacts);
 
@@ -959,6 +987,8 @@ exec_extract_strings(imgp)
 			imgp->envc++;
 		}
 	}
+
+	imgp->endenvs = imgp->stringp;
 
 	return (0);
 }
diff -upr /usr/src/sys/kern/kern_fork.c src/sys/kern/kern_fork.c
--- /usr/src/sys/kern/kern_fork.c	Tue Jul  1 11:29:30 2003
+++ src/sys/kern/kern_fork.c	Thu Jul 17 22:56:39 2003
@@ -511,6 +511,7 @@ again:
 	td2->td_ucred = crhold(p2->p_ucred);	/* XXXKSE */
 
 	pargs_hold(p2->p_args);
+	pargs_hold(p2->p_envs);
 
 	if (flags & RFSIGSHARE) {
 		p2->p_sigacts = sigacts_hold(p1->p_sigacts);
diff -upr /usr/src/sys/kern/kern_proc.c src/sys/kern/kern_proc.c
--- /usr/src/sys/kern/kern_proc.c	Tue Jul  1 11:29:30 2003
+++ src/sys/kern/kern_proc.c	Fri Jul 18 09:13:38 2003
@@ -643,6 +643,7 @@ fill_kinfo_thread(struct thread *td, str
 	PROC_LOCK_ASSERT(p, MA_OWNED);
 	kp->ki_addr =/* p->p_addr; */0; /* XXXKSE */
 	kp->ki_args = p->p_args;
+	kp->ki_envs = p->p_envs;
 	kp->ki_textvp = p->p_textvp;
 #ifdef KTRACE
 	kp->ki_tracep = p->p_tracevp;
@@ -1092,9 +1093,12 @@ sysctl_kern_proc_args(SYSCTL_HANDLER_ARG
 	if (!p)
 		return (0);
 
-	if ((!ps_argsopen) && p_cansee(curthread, p)) {
-		PROC_UNLOCK(p);
-		return (0);
+	if (p_cansee(curthread, p)) {
+		if ((oidp->oid_number == KERN_PROC_ARGS && !ps_argsopen) ||
+		    (oidp->oid_number == KERN_PROC_ENVS && !ps_envsopen)) {
+			PROC_UNLOCK(p);
+			return (0);
+		}
 	}
 
 	if (req->newptr && curproc != p) {
@@ -1102,7 +1106,10 @@ sysctl_kern_proc_args(SYSCTL_HANDLER_ARG
 		return (EPERM);
 	}
 
-	pa = p->p_args;
+	if (oidp->oid_number == KERN_PROC_ARGS)
+		pa = p->p_args;
+	else /* if (oidp->oid_number == KERN_PROC_ENVS) */
+		pa = p->p_envs;
 	pargs_hold(pa);
 	PROC_UNLOCK(p);
 	if (req->oldptr != NULL && pa != NULL)
@@ -1111,8 +1118,13 @@ sysctl_kern_proc_args(SYSCTL_HANDLER_ARG
 	if (error != 0 || req->newptr == NULL)
 		return (error);
 
-	if (req->newlen + sizeof(struct pargs) > ps_arg_cache_limit)
-		return (ENOMEM);
+	if (oidp->oid_number == KERN_PROC_ARGS) {
+		if (req->newlen + sizeof(struct pargs) > ps_arg_cache_limit)
+			return (ENOMEM);
+	} else /* if (oidp->oid_number == KERN_PROC_ENVS) */ {
+		if (req->newlen + sizeof(struct pargs) > ps_env_cache_limit)
+			return (ENOMEM);
+	}
 	newpa = pargs_alloc(req->newlen);
 	error = SYSCTL_IN(req, newpa->ar_args, req->newlen);
 	if (error != 0) {
@@ -1120,8 +1132,13 @@ sysctl_kern_proc_args(SYSCTL_HANDLER_ARG
 		return (error);
 	}
 	PROC_LOCK(p);
-	pa = p->p_args;
-	p->p_args = newpa;
+	if (oidp->oid_number == KERN_PROC_ARGS) {
+		pa = p->p_args;
+		p->p_args = newpa;
+	} else /* if (oidp->oid_number == KERN_PROC_ENVS) */ {
+		pa = p->p_envs;
+		p->p_envs = newpa;
+	}
 	PROC_UNLOCK(p);
 	pargs_drop(pa);
 	return (0);
@@ -1152,3 +1169,6 @@ SYSCTL_NODE(_kern_proc, KERN_PROC_PROC, 
 
 SYSCTL_NODE(_kern_proc, KERN_PROC_ARGS, args, CTLFLAG_RW | CTLFLAG_ANYBODY,
 	sysctl_kern_proc_args, "Process argument list");
+
+SYSCTL_NODE(_kern_proc, KERN_PROC_ENVS, envs, CTLFLAG_RW | CTLFLAG_ANYBODY,
+	sysctl_kern_proc_args, "Process environment variable list");
diff -upr /usr/src/sys/sys/imgact.h src/sys/sys/imgact.h
--- /usr/src/sys/sys/imgact.h	Tue Nov  5 18:51:55 2002
+++ src/sys/sys/imgact.h	Thu Jul 17 21:35:42 2003
@@ -53,8 +53,11 @@ struct image_params {
 	struct vattr *attr;	/* attributes of file */
 	const char *image_header; /* head of file to exec */
 	char *stringbase;	/* base address of tmp string storage */
+#define	startargs	stringbase
 	char *stringp;		/* current 'end' pointer of tmp strings */
 	char *endargs;		/* end of argv vector */
+#define	startenvs	endargs
+	char *endenvs;		/* end of envv 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 -upr /usr/src/sys/sys/proc.h src/sys/sys/proc.h
--- /usr/src/sys/sys/proc.h	Sat Jun 28 10:29:04 2003
+++ src/sys/sys/proc.h	Fri Jul 18 00:27:07 2003
@@ -109,6 +109,7 @@ struct pargs {
 	u_int	ar_ref;		/* Reference count. */
 	u_int	ar_length;	/* Length. */
 	u_char	ar_args[1];	/* Arguments. */
+#define	ar_envs	ar_args
 };
 
 /*-
@@ -590,6 +591,7 @@ struct proc {
 	struct pgrp	*p_pgrp;	/* (c + e) Pointer to process group. */
 	struct sysentvec *p_sysent;	/* (b) Syscall dispatch info. */
 	struct pargs	*p_args;	/* (c) Process arguments. */
+	struct pargs	*p_envs;	/* (c) Process environment variables. */
 	rlim_t		p_cpulimit;	/* (j) Current CPU limit in seconds. */
 /* End area that is copied on creation. */
 #define	p_endcopy	p_xstat
@@ -808,8 +810,9 @@ extern int hogticks;			/* Limit on kerne
 extern int nprocs, maxproc;		/* Current and max number of procs. */
 extern int maxprocperuid;		/* Max procs per uid. */
 extern u_long ps_arg_cache_limit;
+extern u_long ps_env_cache_limit;
 extern int ps_argsopen;
-extern int ps_showallprocs;
+extern int ps_envsopen;
 extern int sched_quantum;		/* Scheduling quantum in ticks. */
 
 LIST_HEAD(proclist, proc);
diff -upr /usr/src/sys/sys/sysctl.h src/sys/sys/sysctl.h
--- /usr/src/sys/sys/sysctl.h	Thu Jul 17 21:55:26 2003
+++ src/sys/sys/sysctl.h	Thu Jul 17 21:59:09 2003
@@ -412,7 +412,8 @@ TAILQ_HEAD(sysctl_ctx_list, sysctl_ctx_e
 #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 */
-#define	KERN_PROC_PROC		8	/* only return procs */
+#define	KERN_PROC_ENVS		8	/* get/set environment variables */
+#define	KERN_PROC_PROC		9	/* only return procs */
 
 /*
  * KERN_IPC identifiers
diff -upr /usr/src/sys/sys/user.h src/sys/sys/user.h
--- /usr/src/sys/sys/user.h	Tue May 13 22:36:02 2003
+++ src/sys/sys/user.h	Fri Jul 18 00:42:04 2003
@@ -160,7 +160,8 @@ struct kinfo_proc {
 	long	ki_tdflags;		/* XXXKSE kthread flag */
 	struct	pcb *ki_pcb;		/* kernel virtual addr of pcb */
 	void	*ki_kstack;		/* kernel virtual addr of stack */
-	long	ki_spare[22];		/* spare constants */
+	struct	pargs *ki_envs;		/* address of environment variables */
+	long	ki_spare[21];		/* spare constants */
 };
 void fill_kinfo_proc(struct proc *, struct kinfo_proc *);
 
>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list