Author: kib
Date: Tue Sep 28 11:32:17 2010
New Revision: 213246
URL: http://svn.freebsd.org/changeset/base/213246

Log:
  In linprocfs_doargv():
  - handle compat32 processes;
  - remove the checks for copied in addresses to belong into valid
    usermode range, proc_rwmem() does this;
  - simplify loop reading single string, limit the total amount of strings
    collected by ARG_MAX bytes;
  - correctly add '\0' at the end of each copied string;
  - fix style.
  
  In linprocfs_doprocenviron():
  - unlock the process before calling copyin code [1]. The process is held
    by pseudofs.
  
  In linprocfs_doproccmdline:
  - use linprocfs_doargv() to handle !curproc case for which p_args is not 
cached.
  
  Reported by:          plulnet [1]
  Tested by:            pluknet
  Approved by:          des (linprocfs maintainer, previous
                                version of the patch)
  MFC after:            3 weeks

Modified:
  head/sys/compat/linprocfs/linprocfs.c

Modified: head/sys/compat/linprocfs/linprocfs.c
==============================================================================
--- head/sys/compat/linprocfs/linprocfs.c       Tue Sep 28 09:07:00 2010        
(r213245)
+++ head/sys/compat/linprocfs/linprocfs.c       Tue Sep 28 11:32:17 2010        
(r213246)
@@ -61,6 +61,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/mutex.h>
 #include <sys/namei.h>
 #include <sys/proc.h>
+#include <sys/ptrace.h>
 #include <sys/resourcevar.h>
 #include <sys/sbuf.h>
 #include <sys/sem.h>
@@ -96,6 +97,10 @@ __FBSDID("$FreeBSD$");
 #include <machine/md_var.h>
 #endif /* __i386__ || __amd64__ */
 
+#ifdef COMPAT_FREEBSD32
+#include <compat/freebsd32/freebsd32_util.h>
+#endif
+
 #ifdef COMPAT_LINUX32                          /* XXX */
 #include <machine/../linux32/linux.h>
 #else
@@ -886,78 +891,24 @@ linprocfs_doprocroot(PFS_FILL_ARGS)
        return (0);
 }
 
-/*
- * Filler function for proc/pid/cmdline
- */
-static int
-linprocfs_doproccmdline(PFS_FILL_ARGS)
-{
-       struct ps_strings pstr;
-       char **ps_argvstr;
-       int error, i;
-
-       /*
-        * If we are using the ps/cmdline caching, use that.  Otherwise
-        * revert back to the old way which only implements full cmdline
-        * for the currept process and just p->p_comm for all other
-        * processes.
-        * Note that if the argv is no longer available, we deliberately
-        * don't fall back on p->p_comm or return an error: the authentic
-        * Linux behaviour is to return zero-length in this case.
-        */
-
-       PROC_LOCK(p);
-       if (p->p_args && p_cansee(td, p) == 0) {
-               sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
-               PROC_UNLOCK(p);
-       } else if (p != td->td_proc) {
-               PROC_UNLOCK(p);
-               sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm);
-       } else {
-               PROC_UNLOCK(p);
-               error = copyin((void *)p->p_sysent->sv_psstrings, &pstr,
-                   sizeof(pstr));
-               if (error)
-                       return (error);
-               if (pstr.ps_nargvstr > ARG_MAX)
-                       return (E2BIG);
-               ps_argvstr = malloc(pstr.ps_nargvstr * sizeof(char *),
-                   M_TEMP, M_WAITOK);
-               error = copyin((void *)pstr.ps_argvstr, ps_argvstr,
-                   pstr.ps_nargvstr * sizeof(char *));
-               if (error) {
-                       free(ps_argvstr, M_TEMP);
-                       return (error);
-               }
-               for (i = 0; i < pstr.ps_nargvstr; i++) {
-                       sbuf_copyin(sb, ps_argvstr[i], 0);
-                       sbuf_printf(sb, "%c", '\0');
-               }
-               free(ps_argvstr, M_TEMP);
-       }
-
-       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 *))
+    void (*resolver)(const struct ps_strings, u_long *, int *))
 {
        struct iovec iov;
        struct uio tmp_uio;
        struct ps_strings pss;
-       int ret, i, n_elements, found_end;
-       u_long addr;
-       char* env_vector[MAX_ARGV_STR];
+       int ret, i, n_elements, elm_len;
+       u_long addr, pbegin;
+       char **env_vector, *envp;
        char env_string[UIO_CHUNK_SZ];
-       char *pbegin;
-
-
+#ifdef COMPAT_FREEBSD32
+       struct freebsd32_ps_strings pss32;
+       uint32_t *env_vector32;
+#endif
 
 #define        UIO_HELPER(uio, iov, base, len, cnt, offset, sz, flg, rw, td)   
\
 do {                                                                   \
@@ -972,62 +923,108 @@ do {                                                     
                \
        uio.uio_td = (td);                                              \
 } while (0)
 
-       UIO_HELPER(tmp_uio, iov, &pss, sizeof(struct ps_strings), 1,
-           (off_t)(p->p_sysent->sv_psstrings), sizeof(struct ps_strings),
-           UIO_SYSSPACE, UIO_READ, td);
+       env_vector = malloc(sizeof(char *) * MAX_ARGV_STR, M_TEMP, M_WAITOK);
 
-       ret = proc_rwmem(p, &tmp_uio);
-       if (ret != 0)
-               return ret;
+#ifdef COMPAT_FREEBSD32
+       env_vector32 = NULL;
+       if ((p->p_sysent->sv_flags & SV_ILP32) != 0) {
+               env_vector32 = malloc(sizeof(*env_vector32) * MAX_ARGV_STR,
+                   M_TEMP, M_WAITOK);
+               elm_len = sizeof(int32_t);
+               envp = (char *)env_vector32;
+
+               UIO_HELPER(tmp_uio, iov, &pss32, sizeof(pss32), 1,
+                   (off_t)(p->p_sysent->sv_psstrings),
+                   sizeof(pss32), UIO_SYSSPACE, UIO_READ, td);
+               ret = proc_rwmem(p, &tmp_uio);
+               if (ret != 0)
+                       goto done;
+               pss.ps_argvstr = PTRIN(pss32.ps_argvstr);
+               pss.ps_nargvstr = pss32.ps_nargvstr;
+               pss.ps_envstr = PTRIN(pss32.ps_envstr);
+               pss.ps_nenvstr = pss32.ps_nenvstr;
+       } else {
+#endif
+               elm_len = sizeof(char *);
+               envp = (char *)env_vector;
+
+               UIO_HELPER(tmp_uio, iov, &pss, sizeof(pss), 1,
+                   (off_t)(p->p_sysent->sv_psstrings),
+                   sizeof(pss), UIO_SYSSPACE, UIO_READ, td);
+               ret = proc_rwmem(p, &tmp_uio);
+               if (ret != 0)
+                       goto done;
+#ifdef COMPAT_FREEBSD32
+       }
+#endif
 
        /* Get the array address and the number of elements */
        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) {
-               /* What error code should we return? */
-               return 0;
+       if (n_elements > MAX_ARGV_STR) {
+               ret = E2BIG;
+               goto done;
        }
 
-       UIO_HELPER(tmp_uio, iov, env_vector, MAX_ARGV_STR, 1,
+       UIO_HELPER(tmp_uio, iov, envp, n_elements * elm_len, 1,
            (vm_offset_t)(addr), iov.iov_len, UIO_SYSSPACE, UIO_READ, td);
-
        ret = proc_rwmem(p, &tmp_uio);
        if (ret != 0)
-               return ret;
+               goto done;
+#ifdef COMPAT_FREEBSD32
+       if (env_vector32 != NULL) {
+               for (i = 0; i < n_elements; i++)
+                       env_vector[i] = PTRIN(env_vector32[i]);
+       }
+#endif
 
        /* Now we can iterate through the list of strings */
        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);
-
+               pbegin = (vm_offset_t)env_vector[i];
+               for (;;) {
+                       UIO_HELPER(tmp_uio, iov, env_string, sizeof(env_string),
+                           1, pbegin, iov.iov_len, UIO_SYSSPACE, UIO_READ, td);
                        ret = proc_rwmem(p, &tmp_uio);
                        if (ret != 0)
-                               return ret;
+                               goto done;
 
                        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;
+                               /*
+                                * We didn't find the end of the string.
+                                * Add the string to the buffer and move
+                                * the pointer.  But do not allow strings
+                                * of unlimited length.
+                                */
+                               sbuf_bcat(sb, env_string, UIO_CHUNK_SZ);
+                               if (sbuf_len(sb) >= ARG_MAX) {
+                                       ret = E2BIG;
+                                       goto done;
+                               }
+                               pbegin += UIO_CHUNK_SZ;
                        } else {
-                           found_end = 1;
+                               sbuf_cat(sb, env_string);
+                               break;
                        }
                }
-               sbuf_printf(sb, "%s", env_string);
+               sbuf_bcat(sb, "", 1);
        }
-
 #undef UIO_HELPER
 
-       return (0);
+done:
+       free(env_vector, M_TEMP);
+#ifdef COMPAT_FREEBSD32
+       free(env_vector32, M_TEMP);
+#endif
+       return (ret);
+}
+
+static void
+ps_string_argv(const struct ps_strings ps, u_long *addr, int *n)
+{
+
+       *addr = (u_long) ps.ps_argvstr;
+       *n = ps.ps_nargvstr;
 }
 
 static void
@@ -1039,6 +1036,30 @@ ps_string_env(const struct ps_strings ps
 }
 
 /*
+ * Filler function for proc/pid/cmdline
+ */
+static int
+linprocfs_doproccmdline(PFS_FILL_ARGS)
+{
+       int ret;
+
+       PROC_LOCK(p);
+       if ((ret = p_cansee(td, p)) != 0) {
+               PROC_UNLOCK(p);
+               return (ret);
+       }
+       if (p->p_args != NULL) {
+               sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
+               PROC_UNLOCK(p);
+               return (0);
+       }
+       PROC_UNLOCK(p);
+
+       ret = linprocfs_doargv(td, p, sb, ps_string_argv);
+       return (ret);
+}
+
+/*
  * Filler function for proc/pid/environ
  */
 static int
@@ -1047,14 +1068,13 @@ linprocfs_doprocenviron(PFS_FILL_ARGS)
        int ret;
 
        PROC_LOCK(p);
-
        if ((ret = p_cansee(td, p)) != 0) {
                PROC_UNLOCK(p);
-               return ret;
+               return (ret);
        }
+       PROC_UNLOCK(p);
 
        ret = linprocfs_doargv(td, p, sb, ps_string_env);
-       PROC_UNLOCK(p);
        return (ret);
 }
 
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to