When getting the program argument or environement string, we previously
assumed that all the strings were stored in a row, separated by NUL chars, at the address pointed bu argv[0] (or envp[0]). This was wrong: if the program changed argvs[0], we still read the first string correctly, but the next strings did contain unexpected data. The fix: read the whole argv (or envp) array, then copy the string one by one, using their addresses in argv (or agrp)
This commit is contained in:
parent
ed679e385b
commit
bdfbd98ac1
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: init_sysctl.c,v 1.83 2006/09/08 20:58:57 elad Exp $ */
|
||||
/* $NetBSD: init_sysctl.c,v 1.84 2006/09/10 05:46:02 manu Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2003 The NetBSD Foundation, Inc.
|
||||
|
@ -37,7 +37,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: init_sysctl.c,v 1.83 2006/09/08 20:58:57 elad Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: init_sysctl.c,v 1.84 2006/09/10 05:46:02 manu Exp $");
|
||||
|
||||
#include "opt_sysv.h"
|
||||
#include "opt_multiprocessor.h"
|
||||
|
@ -2334,13 +2334,13 @@ sysctl_kern_proc_args(SYSCTLFN_ARGS)
|
|||
{
|
||||
struct ps_strings pss;
|
||||
struct proc *p;
|
||||
size_t len, upper_bound, xlen, i;
|
||||
size_t len, i;
|
||||
struct uio auio;
|
||||
struct iovec aiov;
|
||||
vaddr_t argv;
|
||||
pid_t pid;
|
||||
int nargv, type, error;
|
||||
char *arg;
|
||||
char **argv = NULL;
|
||||
char *tmp;
|
||||
struct vmspace *vmspace;
|
||||
vaddr_t psstr_addr;
|
||||
|
@ -2468,41 +2468,56 @@ sysctl_kern_proc_args(SYSCTLFN_ARGS)
|
|||
return (EINVAL);
|
||||
}
|
||||
|
||||
auio.uio_offset = (off_t)(unsigned long)tmp;
|
||||
aiov.iov_base = &argv;
|
||||
aiov.iov_len = sizeof(argv);
|
||||
#ifdef COMPAT_NETBSD32
|
||||
if (p->p_flag & P_32)
|
||||
len = sizeof(netbsd32_charp) * nargv;
|
||||
else
|
||||
#endif
|
||||
len = sizeof(char *) * nargv;
|
||||
|
||||
argv = malloc(len, M_TEMP, M_WAITOK);
|
||||
|
||||
aiov.iov_base = argv;
|
||||
aiov.iov_len = len;
|
||||
auio.uio_iov = &aiov;
|
||||
auio.uio_iovcnt = 1;
|
||||
auio.uio_resid = sizeof(argv);
|
||||
auio.uio_offset = (off_t)(unsigned long)tmp;
|
||||
auio.uio_resid = len;
|
||||
auio.uio_rw = UIO_READ;
|
||||
UIO_SETUP_SYSSPACE(&auio);
|
||||
error = uvm_io(&vmspace->vm_map, &auio);
|
||||
if (error)
|
||||
goto done;
|
||||
|
||||
#ifdef COMPAT_NETBSD32
|
||||
/*
|
||||
* Here we get a 32 bit pointer that has to be converted,
|
||||
* otherwise we get garbage in the 32 higher bits
|
||||
* Now copy each string.
|
||||
*/
|
||||
if (p->p_flag & P_32)
|
||||
argv = (vaddr_t)NETBSD32PTR64(argv);
|
||||
#endif
|
||||
len = 0; /* bytes written to user buffer */
|
||||
for (i = 0; i < nargv; i++) {
|
||||
int finished = 0;
|
||||
vaddr_t base;
|
||||
size_t xlen;
|
||||
int j;
|
||||
|
||||
#ifdef COMPAT_NETBSD32
|
||||
if (p->p_flag & P_32) {
|
||||
netbsd32_charp *argv32;
|
||||
|
||||
argv32 = (netbsd32_charp *)argv;
|
||||
|
||||
base = (vaddr_t)NETBSD32PTR64(argv32[i]);
|
||||
} else
|
||||
#endif
|
||||
base = (vaddr_t)argv[i];
|
||||
|
||||
while (!finished) {
|
||||
xlen = PAGE_SIZE - (base & PAGE_MASK);
|
||||
|
||||
/*
|
||||
* Now copy in the actual argument vector, one page at a time,
|
||||
* since we don't know how long the vector is (though, we do
|
||||
* know how many NUL-terminated strings are in the vector).
|
||||
*/
|
||||
len = 0;
|
||||
upper_bound = *oldlenp;
|
||||
for (; nargv != 0 && len < upper_bound; len += xlen) {
|
||||
aiov.iov_base = arg;
|
||||
aiov.iov_len = PAGE_SIZE;
|
||||
auio.uio_iov = &aiov;
|
||||
auio.uio_iovcnt = 1;
|
||||
auio.uio_offset = argv + len;
|
||||
xlen = PAGE_SIZE - ((argv + len) & PAGE_MASK);
|
||||
auio.uio_offset = base;
|
||||
auio.uio_resid = xlen;
|
||||
auio.uio_rw = UIO_READ;
|
||||
UIO_SETUP_SYSSPACE(&auio);
|
||||
|
@ -2510,30 +2525,39 @@ sysctl_kern_proc_args(SYSCTLFN_ARGS)
|
|||
if (error)
|
||||
goto done;
|
||||
|
||||
for (i = 0; i < xlen && nargv != 0; i++) {
|
||||
if (arg[i] == '\0')
|
||||
nargv--; /* one full string */
|
||||
/* Look for the end of the string */
|
||||
for (j = 0; j < xlen; j++) {
|
||||
if (arg[j] == '\0') {
|
||||
xlen = j + 1;
|
||||
finished = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure we don't copyout past the end of the user's
|
||||
* buffer.
|
||||
*/
|
||||
if (len + i > upper_bound)
|
||||
i = upper_bound - len;
|
||||
/* Check for user buffer overflow */
|
||||
if (len + xlen > *oldlenp) {
|
||||
finished = 1;
|
||||
if (len > *oldlenp)
|
||||
xlen = 0;
|
||||
else
|
||||
xlen = *oldlenp - len;
|
||||
}
|
||||
|
||||
error = copyout(arg, (char *)oldp + len, i);
|
||||
/* Copyout the page */
|
||||
error = copyout(arg, (char *)oldp + len, xlen);
|
||||
if (error)
|
||||
break;
|
||||
goto done;
|
||||
|
||||
if (nargv == 0) {
|
||||
len += i;
|
||||
break;
|
||||
len += xlen;
|
||||
base += xlen;
|
||||
}
|
||||
}
|
||||
*oldlenp = len;
|
||||
|
||||
done:
|
||||
if (argv != NULL)
|
||||
free(argv, M_TEMP);
|
||||
|
||||
uvmspace_free(vmspace);
|
||||
|
||||
free(arg, M_TEMP);
|
||||
|
|
Loading…
Reference in New Issue