Changeset View
Changeset View
Standalone View
Standalone View
head/sys/kern/kern_proc.c
Show First 20 Lines • Show All 1,520 Lines • ▼ Show 20 Lines | pargs_drop(struct pargs *pa) | ||||
if (pa == NULL) | if (pa == NULL) | ||||
return; | return; | ||||
if (refcount_release(&pa->ar_ref)) | if (refcount_release(&pa->ar_ref)) | ||||
pargs_free(pa); | pargs_free(pa); | ||||
} | } | ||||
static int | static int | ||||
proc_read_mem(struct thread *td, struct proc *p, vm_offset_t offset, void* buf, | |||||
size_t len) | |||||
{ | |||||
struct iovec iov; | |||||
struct uio uio; | |||||
iov.iov_base = (caddr_t)buf; | |||||
iov.iov_len = len; | |||||
uio.uio_iov = &iov; | |||||
uio.uio_iovcnt = 1; | |||||
uio.uio_offset = offset; | |||||
uio.uio_resid = (ssize_t)len; | |||||
uio.uio_segflg = UIO_SYSSPACE; | |||||
uio.uio_rw = UIO_READ; | |||||
uio.uio_td = td; | |||||
return (proc_rwmem(p, &uio)); | |||||
} | |||||
static int | |||||
proc_read_string(struct thread *td, struct proc *p, const char *sptr, char *buf, | proc_read_string(struct thread *td, struct proc *p, const char *sptr, char *buf, | ||||
size_t len) | size_t len) | ||||
{ | { | ||||
size_t i; | ssize_t n; | ||||
int error; | |||||
error = proc_read_mem(td, p, (vm_offset_t)sptr, buf, len); | |||||
/* | /* | ||||
* Reading the chunk may validly return EFAULT if the string is shorter | * This may return a short read if the string is shorter than the chunk | ||||
* than the chunk and is aligned at the end of the page, assuming the | * and is aligned at the end of the page, and the following page is not | ||||
* next page is not mapped. So if EFAULT is returned do a fallback to | * mapped. | ||||
* one byte read loop. | |||||
*/ | */ | ||||
if (error == EFAULT) { | n = proc_readmem(td, p, (vm_offset_t)sptr, buf, len); | ||||
for (i = 0; i < len; i++, buf++, sptr++) { | if (n <= 0) | ||||
error = proc_read_mem(td, p, (vm_offset_t)sptr, buf, 1); | return (ENOMEM); | ||||
if (error != 0) | return (0); | ||||
return (error); | |||||
if (*buf == '\0') | |||||
break; | |||||
} | } | ||||
error = 0; | |||||
} | |||||
return (error); | |||||
} | |||||
#define PROC_AUXV_MAX 256 /* Safety limit on auxv size. */ | #define PROC_AUXV_MAX 256 /* Safety limit on auxv size. */ | ||||
enum proc_vector_type { | enum proc_vector_type { | ||||
PROC_ARG, | PROC_ARG, | ||||
PROC_ENV, | PROC_ENV, | ||||
PROC_AUX, | PROC_AUX, | ||||
}; | }; | ||||
#ifdef COMPAT_FREEBSD32 | #ifdef COMPAT_FREEBSD32 | ||||
static int | static int | ||||
get_proc_vector32(struct thread *td, struct proc *p, char ***proc_vectorp, | get_proc_vector32(struct thread *td, struct proc *p, char ***proc_vectorp, | ||||
size_t *vsizep, enum proc_vector_type type) | size_t *vsizep, enum proc_vector_type type) | ||||
{ | { | ||||
struct freebsd32_ps_strings pss; | struct freebsd32_ps_strings pss; | ||||
Elf32_Auxinfo aux; | Elf32_Auxinfo aux; | ||||
vm_offset_t vptr, ptr; | vm_offset_t vptr, ptr; | ||||
uint32_t *proc_vector32; | uint32_t *proc_vector32; | ||||
char **proc_vector; | char **proc_vector; | ||||
size_t vsize, size; | size_t vsize, size; | ||||
int i, error; | int i, error; | ||||
error = proc_read_mem(td, p, (vm_offset_t)(p->p_sysent->sv_psstrings), | error = 0; | ||||
&pss, sizeof(pss)); | if (proc_readmem(td, p, (vm_offset_t)p->p_sysent->sv_psstrings, &pss, | ||||
if (error != 0) | sizeof(pss)) != sizeof(pss)) | ||||
return (error); | return (ENOMEM); | ||||
switch (type) { | switch (type) { | ||||
case PROC_ARG: | case PROC_ARG: | ||||
vptr = (vm_offset_t)PTRIN(pss.ps_argvstr); | vptr = (vm_offset_t)PTRIN(pss.ps_argvstr); | ||||
vsize = pss.ps_nargvstr; | vsize = pss.ps_nargvstr; | ||||
if (vsize > ARG_MAX) | if (vsize > ARG_MAX) | ||||
return (ENOEXEC); | return (ENOEXEC); | ||||
size = vsize * sizeof(int32_t); | size = vsize * sizeof(int32_t); | ||||
break; | break; | ||||
case PROC_ENV: | case PROC_ENV: | ||||
vptr = (vm_offset_t)PTRIN(pss.ps_envstr); | vptr = (vm_offset_t)PTRIN(pss.ps_envstr); | ||||
vsize = pss.ps_nenvstr; | vsize = pss.ps_nenvstr; | ||||
if (vsize > ARG_MAX) | if (vsize > ARG_MAX) | ||||
return (ENOEXEC); | return (ENOEXEC); | ||||
size = vsize * sizeof(int32_t); | size = vsize * sizeof(int32_t); | ||||
break; | break; | ||||
case PROC_AUX: | case PROC_AUX: | ||||
vptr = (vm_offset_t)PTRIN(pss.ps_envstr) + | vptr = (vm_offset_t)PTRIN(pss.ps_envstr) + | ||||
(pss.ps_nenvstr + 1) * sizeof(int32_t); | (pss.ps_nenvstr + 1) * sizeof(int32_t); | ||||
if (vptr % 4 != 0) | if (vptr % 4 != 0) | ||||
return (ENOEXEC); | return (ENOEXEC); | ||||
for (ptr = vptr, i = 0; i < PROC_AUXV_MAX; i++) { | for (ptr = vptr, i = 0; i < PROC_AUXV_MAX; i++) { | ||||
error = proc_read_mem(td, p, ptr, &aux, sizeof(aux)); | if (proc_readmem(td, p, ptr, &aux, sizeof(aux)) != | ||||
if (error != 0) | sizeof(aux)) | ||||
return (error); | return (ENOMEM); | ||||
if (aux.a_type == AT_NULL) | if (aux.a_type == AT_NULL) | ||||
break; | break; | ||||
ptr += sizeof(aux); | ptr += sizeof(aux); | ||||
} | } | ||||
if (aux.a_type != AT_NULL) | if (aux.a_type != AT_NULL) | ||||
return (ENOEXEC); | return (ENOEXEC); | ||||
vsize = i + 1; | vsize = i + 1; | ||||
size = vsize * sizeof(aux); | size = vsize * sizeof(aux); | ||||
break; | break; | ||||
default: | default: | ||||
KASSERT(0, ("Wrong proc vector type: %d", type)); | KASSERT(0, ("Wrong proc vector type: %d", type)); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
proc_vector32 = malloc(size, M_TEMP, M_WAITOK); | proc_vector32 = malloc(size, M_TEMP, M_WAITOK); | ||||
error = proc_read_mem(td, p, vptr, proc_vector32, size); | if (proc_readmem(td, p, vptr, proc_vector32, size) != size) { | ||||
if (error != 0) | error = ENOMEM; | ||||
goto done; | goto done; | ||||
} | |||||
if (type == PROC_AUX) { | if (type == PROC_AUX) { | ||||
*proc_vectorp = (char **)proc_vector32; | *proc_vectorp = (char **)proc_vector32; | ||||
*vsizep = vsize; | *vsizep = vsize; | ||||
return (0); | return (0); | ||||
} | } | ||||
proc_vector = malloc(vsize * sizeof(char *), M_TEMP, M_WAITOK); | proc_vector = malloc(vsize * sizeof(char *), M_TEMP, M_WAITOK); | ||||
for (i = 0; i < (int)vsize; i++) | for (i = 0; i < (int)vsize; i++) | ||||
proc_vector[i] = PTRIN(proc_vector32[i]); | proc_vector[i] = PTRIN(proc_vector32[i]); | ||||
Show All 9 Lines | |||||
get_proc_vector(struct thread *td, struct proc *p, char ***proc_vectorp, | get_proc_vector(struct thread *td, struct proc *p, char ***proc_vectorp, | ||||
size_t *vsizep, enum proc_vector_type type) | size_t *vsizep, enum proc_vector_type type) | ||||
{ | { | ||||
struct ps_strings pss; | struct ps_strings pss; | ||||
Elf_Auxinfo aux; | Elf_Auxinfo aux; | ||||
vm_offset_t vptr, ptr; | vm_offset_t vptr, ptr; | ||||
char **proc_vector; | char **proc_vector; | ||||
size_t vsize, size; | size_t vsize, size; | ||||
int error, i; | int i; | ||||
#ifdef COMPAT_FREEBSD32 | #ifdef COMPAT_FREEBSD32 | ||||
if (SV_PROC_FLAG(p, SV_ILP32) != 0) | if (SV_PROC_FLAG(p, SV_ILP32) != 0) | ||||
return (get_proc_vector32(td, p, proc_vectorp, vsizep, type)); | return (get_proc_vector32(td, p, proc_vectorp, vsizep, type)); | ||||
#endif | #endif | ||||
error = proc_read_mem(td, p, (vm_offset_t)(p->p_sysent->sv_psstrings), | if (proc_readmem(td, p, (vm_offset_t)p->p_sysent->sv_psstrings, &pss, | ||||
&pss, sizeof(pss)); | sizeof(pss)) != sizeof(pss)) | ||||
if (error != 0) | return (ENOMEM); | ||||
return (error); | |||||
switch (type) { | switch (type) { | ||||
case PROC_ARG: | case PROC_ARG: | ||||
vptr = (vm_offset_t)pss.ps_argvstr; | vptr = (vm_offset_t)pss.ps_argvstr; | ||||
vsize = pss.ps_nargvstr; | vsize = pss.ps_nargvstr; | ||||
if (vsize > ARG_MAX) | if (vsize > ARG_MAX) | ||||
return (ENOEXEC); | return (ENOEXEC); | ||||
size = vsize * sizeof(char *); | size = vsize * sizeof(char *); | ||||
break; | break; | ||||
Show All 20 Lines | #endif | ||||
/* | /* | ||||
* We count the array size reading the aux vectors from the | * We count the array size reading the aux vectors from the | ||||
* stack until AT_NULL vector is returned. So (to keep the code | * stack until AT_NULL vector is returned. So (to keep the code | ||||
* simple) we read the process stack twice: the first time here | * simple) we read the process stack twice: the first time here | ||||
* to find the size and the second time when copying the vectors | * to find the size and the second time when copying the vectors | ||||
* to the allocated proc_vector. | * to the allocated proc_vector. | ||||
*/ | */ | ||||
for (ptr = vptr, i = 0; i < PROC_AUXV_MAX; i++) { | for (ptr = vptr, i = 0; i < PROC_AUXV_MAX; i++) { | ||||
error = proc_read_mem(td, p, ptr, &aux, sizeof(aux)); | if (proc_readmem(td, p, ptr, &aux, sizeof(aux)) != | ||||
if (error != 0) | sizeof(aux)) | ||||
return (error); | return (ENOMEM); | ||||
if (aux.a_type == AT_NULL) | if (aux.a_type == AT_NULL) | ||||
break; | break; | ||||
ptr += sizeof(aux); | ptr += sizeof(aux); | ||||
} | } | ||||
/* | /* | ||||
* If the PROC_AUXV_MAX entries are iterated over, and we have | * If the PROC_AUXV_MAX entries are iterated over, and we have | ||||
* not reached AT_NULL, it is most likely we are reading wrong | * not reached AT_NULL, it is most likely we are reading wrong | ||||
* data: either the process doesn't have auxv array or data has | * data: either the process doesn't have auxv array or data has | ||||
* been modified. Return the error in this case. | * been modified. Return the error in this case. | ||||
*/ | */ | ||||
if (aux.a_type != AT_NULL) | if (aux.a_type != AT_NULL) | ||||
return (ENOEXEC); | return (ENOEXEC); | ||||
vsize = i + 1; | vsize = i + 1; | ||||
size = vsize * sizeof(aux); | size = vsize * sizeof(aux); | ||||
break; | break; | ||||
default: | default: | ||||
KASSERT(0, ("Wrong proc vector type: %d", type)); | KASSERT(0, ("Wrong proc vector type: %d", type)); | ||||
return (EINVAL); /* In case we are built without INVARIANTS. */ | return (EINVAL); /* In case we are built without INVARIANTS. */ | ||||
} | } | ||||
proc_vector = malloc(size, M_TEMP, M_WAITOK); | proc_vector = malloc(size, M_TEMP, M_WAITOK); | ||||
if (proc_vector == NULL) | if (proc_readmem(td, p, vptr, proc_vector, size) != size) { | ||||
return (ENOMEM); | |||||
error = proc_read_mem(td, p, vptr, proc_vector, size); | |||||
if (error != 0) { | |||||
free(proc_vector, M_TEMP); | free(proc_vector, M_TEMP); | ||||
return (error); | return (ENOMEM); | ||||
} | } | ||||
*proc_vectorp = proc_vector; | *proc_vectorp = proc_vector; | ||||
*vsizep = vsize; | *vsizep = vsize; | ||||
return (0); | return (0); | ||||
} | } | ||||
#define GET_PS_STRINGS_CHUNK_SZ 256 /* Chunk size (bytes) for ps_strings operations. */ | #define GET_PS_STRINGS_CHUNK_SZ 256 /* Chunk size (bytes) for ps_strings operations. */ | ||||
▲ Show 20 Lines • Show All 1,341 Lines • Show Last 20 Lines |