kern/148646: Implementation of the "environ" file for the linprocfs

Fernando fernando.apesteguia at gmail.com
Thu Jul 15 16:50:05 UTC 2010


>Number:         148646
>Category:       kern
>Synopsis:       Implementation of the "environ" file for the linprocfs
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Thu Jul 15 16:50:04 UTC 2010
>Closed-Date:
>Last-Modified:
>Originator:     Fernando
>Release:        8.0-RELEASE-p2
>Organization:
Open Sistemas
>Environment:
FreeBSD beastie 8.0-RELEASE-p2 FreeBSD 8.0-RELEASE-p2 #4: Thu Mar  4 19:31:02 CET 2010     root at beastie:/usr/obj/usr/src/sys/APEKERNEL  amd64

>Description:
The current version of linprocfs returns the string "doprocenviron".

The patch attached below tries to implement the "environ" file that can be found under /proc/<PID>/ in a Linux procfs. The patch tries to be consistent with lib/libkvm/kvm_proc.c

It was tested on a 8.0-RELEASE-p2 amd64 and on a 8.0-RELEASE i386 running on qemu.

>How-To-Repeat:
Just cat /compat/linux/proc/<PID>/environ
>Fix:
The attached patch could be an initial solution.

Patch attached with submission follows:

--- /sys/compat/linprocfs/linprocfs.c	2010-07-14 17:56:23.000000000 +0200
+++ linprocfs.c	2010-07-14 17:42:04.000000000 +0200
@@ -933,15 +933,130 @@
 	return (0);
 }
 
+extern int proc_rwmem(struct proc *p, struct uio *uio);
+
+#define MAX_ARGV_STR	512	/* Max number of argv-like strings */
+#define UIO_CHUNK_SZ	256	/* Max chunk size (bytes) for uiomove */
+
+static int
+linprocfs_doargv(struct thread *td, struct proc *p, struct sbuf *sb,
+    void (*resolver)(const struct ps_strings *, u_long *, int *))
+{
+	int ret, i, n_elements;
+	char *buff;
+	char* env_vector[MAX_ARGV_STR];
+	char env_string[UIO_CHUNK_SZ];
+	u_long addr;
+	struct iovec iov;
+	struct uio tmp_uio;
+	struct ps_strings *pss;
+
+	buff = malloc(sizeof(struct ps_strings), M_TEMP, M_WAITOK);
+
+
+#define	UIO_HELPER(uio, iov, base, len, iovcnt, 			\
+	offset, resid, segflg, rw, td)	do {				\
+					iov.iov_base = (caddr_t) base; 	\
+					iov.iov_len = len; 		\
+					uio.uio_iov = &iov; 		\
+					uio.uio_iovcnt = iovcnt; 	\
+					uio.uio_offset = (off_t) offset;\
+					uio.uio_resid = resid; 		\
+					uio.uio_segflg = segflg; 	\
+					uio.uio_rw = rw; 		\
+					uio.uio_td = td;		\
+} while (0)
+
+	PROC_LOCK(p);
+
+	UIO_HELPER(tmp_uio, iov, buff, sizeof(struct ps_strings),
+	    1, (off_t)(p->p_sysent->sv_psstrings),
+	    sizeof(struct ps_strings), UIO_SYSSPACE, UIO_READ, td);
+	ret = proc_rwmem(p, &tmp_uio);
+	if (ret != 0)
+		return ret;
+
+	pss = (struct ps_strings *)(buff);
+
+	resolver(pss, &addr, &n_elements);
+
+	/* Consistent with lib/libkvm/kvm_proc.c */
+	if (n_elements > MAX_ARGV_STR || 
+			(u_long)addr < VM_MIN_ADDRESS || 
+			(u_long)addr >= VM_MAXUSER_ADDRESS) {
+		PROC_UNLOCK(p);
+		/* What error code should we return? */
+		return 0;
+	}
+	
+ 	UIO_HELPER(tmp_uio, iov, env_vector, MAX_ARGV_STR, 1,
+	    (vm_offset_t)(addr), iov.iov_len, UIO_SYSSPACE, UIO_READ, td);
+	ret = proc_rwmem(p, &tmp_uio);
+	if (ret != 0)
+		return ret;
+
+	/* Now we can iterate through the list of strings */
+	int found_end = 0;
+	char *pbegin;
+	for (i = 0; i < n_elements; i++) {
+		found_end = 0;
+		pbegin = env_vector[i];
+		while(!found_end) {
+			UIO_HELPER(tmp_uio, iov, env_string, sizeof(env_string),
+			    1, (vm_offset_t) pbegin, iov.iov_len, UIO_SYSSPACE, UIO_READ, td);
+			ret = proc_rwmem(p, &tmp_uio);
+			if (ret != 0)
+				return ret;
+
+			if (!strvalid(env_string, UIO_CHUNK_SZ)) {
+				/* 
+				 * We didn't find the end of the string 
+				 * Add the string to the buffer and move
+				 * the pointer
+				 */
+				sbuf_bcat(sb, env_string, UIO_CHUNK_SZ);
+				pbegin = &(*pbegin) + UIO_CHUNK_SZ;
+			} else {
+				found_end = 1;
+			}
+		}
+		sbuf_printf(sb, "%s", env_string);
+	}
+
+	PROC_UNLOCK(p);
+#undef UIO_HELPER
+
+
+	free(buff, M_TEMP);
+
+	return (0);
+}
+
+static void
+ps_string_env(const struct ps_strings *ps, u_long *addr, int *n)
+{
+
+	*addr = (u_long) ps->ps_envstr;
+	*n = ps->ps_nenvstr;
+}
+		
 /*
  * Filler function for proc/pid/environ
  */
 static int
 linprocfs_doprocenviron(PFS_FILL_ARGS)
 {
+	int ret;
 
-	sbuf_printf(sb, "doprocenviron\n%c", '\0');
-	return (0);
+	PROC_LOCK(p);
+	if ((ret = p_cansee(td, p)) != 0) {
+		PROC_UNLOCK(p);
+		return ret;
+	}
+
+
+	PROC_UNLOCK(p);
+	return (linprocfs_doargv(td, p, sb, ps_string_env));
 }
 
 /*


>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list