Changeset View
Changeset View
Standalone View
Standalone View
head/sys/kern/sys_process.c
Show First 20 Lines • Show All 246 Lines • ▼ Show 20 Lines | proc_rwmem(struct proc *p, struct uio *uio) | ||||
int error, fault_flags, page_offset, writing; | int error, fault_flags, page_offset, writing; | ||||
/* | /* | ||||
* Assert that someone has locked this vmspace. (Should be | * Assert that someone has locked this vmspace. (Should be | ||||
* curthread but we can't assert that.) This keeps the process | * curthread but we can't assert that.) This keeps the process | ||||
* from exiting out from under us until this operation completes. | * from exiting out from under us until this operation completes. | ||||
*/ | */ | ||||
PROC_ASSERT_HELD(p); | PROC_ASSERT_HELD(p); | ||||
PROC_LOCK_ASSERT(p, MA_NOTOWNED); | |||||
/* | /* | ||||
* The map we want... | * The map we want... | ||||
*/ | */ | ||||
map = &p->p_vmspace->vm_map; | map = &p->p_vmspace->vm_map; | ||||
/* | /* | ||||
* If we are writing, then we request vm_fault() to create a private | * If we are writing, then we request vm_fault() to create a private | ||||
▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | do { | ||||
vm_page_unhold(m); | vm_page_unhold(m); | ||||
vm_page_unlock(m); | vm_page_unlock(m); | ||||
} while (error == 0 && uio->uio_resid > 0); | } while (error == 0 && uio->uio_resid > 0); | ||||
return (error); | return (error); | ||||
} | } | ||||
static ssize_t | |||||
proc_iop(struct thread *td, struct proc *p, vm_offset_t va, void *buf, | |||||
size_t len, enum uio_rw rw) | |||||
{ | |||||
struct iovec iov; | |||||
struct uio uio; | |||||
ssize_t slen; | |||||
int error; | |||||
MPASS(len < SSIZE_MAX); | |||||
slen = (ssize_t)len; | |||||
iov.iov_base = (caddr_t)buf; | |||||
iov.iov_len = len; | |||||
uio.uio_iov = &iov; | |||||
uio.uio_iovcnt = 1; | |||||
uio.uio_offset = va; | |||||
uio.uio_resid = slen; | |||||
uio.uio_segflg = UIO_SYSSPACE; | |||||
uio.uio_rw = rw; | |||||
uio.uio_td = td; | |||||
error = proc_rwmem(p, &uio); | |||||
if (uio.uio_resid == slen) | |||||
return (-1); | |||||
return (slen - uio.uio_resid); | |||||
} | |||||
ssize_t | |||||
proc_readmem(struct thread *td, struct proc *p, vm_offset_t va, void *buf, | |||||
size_t len) | |||||
{ | |||||
return (proc_iop(td, p, va, buf, len, UIO_READ)); | |||||
} | |||||
ssize_t | |||||
proc_writemem(struct thread *td, struct proc *p, vm_offset_t va, void *buf, | |||||
size_t len) | |||||
{ | |||||
return (proc_iop(td, p, va, buf, len, UIO_WRITE)); | |||||
} | |||||
static int | static int | ||||
ptrace_vm_entry(struct thread *td, struct proc *p, struct ptrace_vm_entry *pve) | ptrace_vm_entry(struct thread *td, struct proc *p, struct ptrace_vm_entry *pve) | ||||
{ | { | ||||
struct vattr vattr; | struct vattr vattr; | ||||
vm_map_t map; | vm_map_t map; | ||||
vm_map_entry_t entry; | vm_map_entry_t entry; | ||||
vm_object_t obj, tobj, lobj; | vm_object_t obj, tobj, lobj; | ||||
struct vmspace *vm; | struct vmspace *vm; | ||||
▲ Show 20 Lines • Show All 301 Lines • ▼ Show 20 Lines | |||||
kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data) | kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data) | ||||
{ | { | ||||
struct iovec iov; | struct iovec iov; | ||||
struct uio uio; | struct uio uio; | ||||
struct proc *curp, *p, *pp; | struct proc *curp, *p, *pp; | ||||
struct thread *td2 = NULL, *td3; | struct thread *td2 = NULL, *td3; | ||||
struct ptrace_io_desc *piod = NULL; | struct ptrace_io_desc *piod = NULL; | ||||
struct ptrace_lwpinfo *pl; | struct ptrace_lwpinfo *pl; | ||||
int error, write, tmp, num; | int error, num, tmp; | ||||
int proctree_locked = 0; | int proctree_locked = 0; | ||||
lwpid_t tid = 0, *buf; | lwpid_t tid = 0, *buf; | ||||
#ifdef COMPAT_FREEBSD32 | #ifdef COMPAT_FREEBSD32 | ||||
int wrap32 = 0, safe = 0; | int wrap32 = 0, safe = 0; | ||||
struct ptrace_io_desc32 *piod32 = NULL; | struct ptrace_io_desc32 *piod32 = NULL; | ||||
struct ptrace_lwpinfo32 *pl32 = NULL; | struct ptrace_lwpinfo32 *pl32 = NULL; | ||||
struct ptrace_lwpinfo plr; | struct ptrace_lwpinfo plr; | ||||
#endif | #endif | ||||
Show All 13 Lines | #endif | ||||
case PT_DETACH: | case PT_DETACH: | ||||
sx_xlock(&proctree_lock); | sx_xlock(&proctree_lock); | ||||
proctree_locked = 1; | proctree_locked = 1; | ||||
break; | break; | ||||
default: | default: | ||||
break; | break; | ||||
} | } | ||||
write = 0; | |||||
if (req == PT_TRACE_ME) { | if (req == PT_TRACE_ME) { | ||||
p = td->td_proc; | p = td->td_proc; | ||||
PROC_LOCK(p); | PROC_LOCK(p); | ||||
} else { | } else { | ||||
if (pid <= PID_MAX) { | if (pid <= PID_MAX) { | ||||
if ((p = pfind(pid)) == NULL) { | if ((p = pfind(pid)) == NULL) { | ||||
if (proctree_locked) | if (proctree_locked) | ||||
sx_xunlock(&proctree_lock); | sx_xunlock(&proctree_lock); | ||||
▲ Show 20 Lines • Show All 342 Lines • ▼ Show 20 Lines | if ((p->p_flag & (P_STOPPED_SIG | P_STOPPED_TRACE)) != 0) { | ||||
if (data) | if (data) | ||||
kern_psignal(p, data); | kern_psignal(p, data); | ||||
} | } | ||||
break; | break; | ||||
case PT_WRITE_I: | case PT_WRITE_I: | ||||
case PT_WRITE_D: | case PT_WRITE_D: | ||||
td2->td_dbgflags |= TDB_USERWR; | td2->td_dbgflags |= TDB_USERWR; | ||||
write = 1; | |||||
/* FALLTHROUGH */ | |||||
case PT_READ_I: | |||||
case PT_READ_D: | |||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
tmp = 0; | error = 0; | ||||
/* write = 0 set above */ | if (proc_writemem(td, p, (off_t)(uintptr_t)addr, &data, | ||||
iov.iov_base = write ? (caddr_t)&data : (caddr_t)&tmp; | sizeof(int)) != sizeof(int)) | ||||
iov.iov_len = sizeof(int); | error = ENOMEM; | ||||
uio.uio_iov = &iov; | else | ||||
uio.uio_iovcnt = 1; | |||||
uio.uio_offset = (off_t)(uintptr_t)addr; | |||||
uio.uio_resid = sizeof(int); | |||||
uio.uio_segflg = UIO_SYSSPACE; /* i.e.: the uap */ | |||||
uio.uio_rw = write ? UIO_WRITE : UIO_READ; | |||||
uio.uio_td = td; | |||||
error = proc_rwmem(p, &uio); | |||||
if (uio.uio_resid != 0) { | |||||
/* | |||||
* XXX proc_rwmem() doesn't currently return ENOSPC, | |||||
* so I think write() can bogusly return 0. | |||||
* XXX what happens for short writes? We don't want | |||||
* to write partial data. | |||||
* XXX proc_rwmem() returns EPERM for other invalid | |||||
* addresses. Convert this to EINVAL. Does this | |||||
* clobber returns of EPERM for other reasons? | |||||
*/ | |||||
if (error == 0 || error == ENOSPC || error == EPERM) | |||||
error = EINVAL; /* EOF */ | |||||
} | |||||
if (!write) | |||||
td->td_retval[0] = tmp; | |||||
if (error == 0) { | |||||
if (write) | |||||
CTR3(KTR_PTRACE, "PT_WRITE: pid %d: %p <= %#x", | CTR3(KTR_PTRACE, "PT_WRITE: pid %d: %p <= %#x", | ||||
p->p_pid, addr, data); | p->p_pid, addr, data); | ||||
PROC_LOCK(p); | |||||
break; | |||||
case PT_READ_I: | |||||
case PT_READ_D: | |||||
PROC_UNLOCK(p); | |||||
error = tmp = 0; | |||||
if (proc_readmem(td, p, (off_t)(uintptr_t)addr, &tmp, | |||||
sizeof(int)) != sizeof(int)) | |||||
error = ENOMEM; | |||||
else | else | ||||
CTR3(KTR_PTRACE, "PT_READ: pid %d: %p >= %#x", | CTR3(KTR_PTRACE, "PT_READ: pid %d: %p >= %#x", | ||||
p->p_pid, addr, tmp); | p->p_pid, addr, tmp); | ||||
} | td->td_retval[0] = tmp; | ||||
PROC_LOCK(p); | PROC_LOCK(p); | ||||
break; | break; | ||||
case PT_IO: | case PT_IO: | ||||
#ifdef COMPAT_FREEBSD32 | #ifdef COMPAT_FREEBSD32 | ||||
if (wrap32) { | if (wrap32) { | ||||
piod32 = addr; | piod32 = addr; | ||||
iov.iov_base = (void *)(uintptr_t)piod32->piod_addr; | iov.iov_base = (void *)(uintptr_t)piod32->piod_addr; | ||||
▲ Show 20 Lines • Show All 261 Lines • Show Last 20 Lines |