From owner-svn-src-head@FreeBSD.ORG Tue Sep 28 11:32:17 2010 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id AAC86106566B; Tue, 28 Sep 2010 11:32:17 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 9927C8FC16; Tue, 28 Sep 2010 11:32:17 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id o8SBWHaV073215; Tue, 28 Sep 2010 11:32:17 GMT (envelope-from kib@svn.freebsd.org) Received: (from kib@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id o8SBWHMA073213; Tue, 28 Sep 2010 11:32:17 GMT (envelope-from kib@svn.freebsd.org) Message-Id: <201009281132.o8SBWHMA073213@svn.freebsd.org> From: Konstantin Belousov Date: Tue, 28 Sep 2010 11:32:17 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r213246 - head/sys/compat/linprocfs X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 28 Sep 2010 11:32:17 -0000 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 #include #include +#include #include #include #include @@ -96,6 +97,10 @@ __FBSDID("$FreeBSD$"); #include #endif /* __i386__ || __amd64__ */ +#ifdef COMPAT_FREEBSD32 +#include +#endif + #ifdef COMPAT_LINUX32 /* XXX */ #include #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); }