mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-01 08:27:59 +00:00
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
This commit is contained in:
parent
15d98d9738
commit
6c82a991c3
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=213246
@ -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
|
||||
@ -1038,6 +1035,30 @@ ps_string_env(const struct ps_strings ps, u_long *addr, int *n)
|
||||
*n = ps.ps_nenvstr;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user