summaryrefslogtreecommitdiffstats
path: root/sys/compat/linprocfs
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2010-09-28 11:32:17 +0000
committerkib <kib@FreeBSD.org>2010-09-28 11:32:17 +0000
commit2fc806f00ce59643ae0e0bb1cc30bbdc77292bf8 (patch)
treeadbb39ae12f518591c9450223c4d883c0a0c1aec /sys/compat/linprocfs
parentb9be4cf50db9068ed760836635f6438d776376ae (diff)
downloadFreeBSD-src-2fc806f00ce59643ae0e0bb1cc30bbdc77292bf8.zip
FreeBSD-src-2fc806f00ce59643ae0e0bb1cc30bbdc77292bf8.tar.gz
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
Diffstat (limited to 'sys/compat/linprocfs')
-rw-r--r--sys/compat/linprocfs/linprocfs.c214
1 files changed, 117 insertions, 97 deletions
diff --git a/sys/compat/linprocfs/linprocfs.c b/sys/compat/linprocfs/linprocfs.c
index c7fe158..76c8c37 100644
--- a/sys/compat/linprocfs/linprocfs.c
+++ b/sys/compat/linprocfs/linprocfs.c
@@ -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, u_long *addr, int *n)
}
/*
+ * 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);
}
OpenPOWER on IntegriCloud