diff options
author | markj <markj@FreeBSD.org> | 2015-12-07 21:33:15 +0000 |
---|---|---|
committer | markj <markj@FreeBSD.org> | 2015-12-07 21:33:15 +0000 |
commit | f734f97f4eae5074772d9168c3337517648369ad (patch) | |
tree | 395bb015ca7c3a283ed4a6f10d9206628be6e3f3 /sys/kern/sys_process.c | |
parent | 7f1d362dac9d67803ca7ba38b1e2fd8ff43ae14f (diff) | |
download | FreeBSD-src-f734f97f4eae5074772d9168c3337517648369ad.zip FreeBSD-src-f734f97f4eae5074772d9168c3337517648369ad.tar.gz |
Add helper functions proc_readmem() and proc_writemem().
These helper functions can be used to read in or write a buffer from or to
an arbitrary process' address space. Without them, this can only be done
using proc_rwmem(), which requires the caller to fill out a uio. This is
onerous and results in code duplication; the new functions provide a simpler
interface which is sufficient for most existing callers of proc_rwmem().
This change also adds a manual page for proc_rwmem() and the new functions.
Reviewed by: jhb, kib
Differential Revision: https://reviews.freebsd.org/D4245
Diffstat (limited to 'sys/kern/sys_process.c')
-rw-r--r-- | sys/kern/sys_process.c | 103 |
1 files changed, 64 insertions, 39 deletions
diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c index 8976941..732d754 100644 --- a/sys/kern/sys_process.c +++ b/sys/kern/sys_process.c @@ -252,6 +252,7 @@ proc_rwmem(struct proc *p, struct uio *uio) * from exiting out from under us until this operation completes. */ PROC_ASSERT_HELD(p); + PROC_LOCK_ASSERT(p, MA_NOTOWNED); /* * The map we want... @@ -327,6 +328,49 @@ proc_rwmem(struct proc *p, struct uio *uio) 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 ptrace_vm_entry(struct thread *td, struct proc *p, struct ptrace_vm_entry *pve) { @@ -644,7 +688,7 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data) struct thread *td2 = NULL, *td3; struct ptrace_io_desc *piod = NULL; struct ptrace_lwpinfo *pl; - int error, write, tmp, num; + int error, num, tmp; int proctree_locked = 0; lwpid_t tid = 0, *buf; #ifdef COMPAT_FREEBSD32 @@ -674,7 +718,6 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data) break; } - write = 0; if (req == PT_TRACE_ME) { p = td->td_proc; PROC_LOCK(p); @@ -1033,46 +1076,28 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data) case PT_WRITE_I: case PT_WRITE_D: td2->td_dbgflags |= TDB_USERWR; - write = 1; - /* FALLTHROUGH */ + PROC_UNLOCK(p); + error = 0; + if (proc_writemem(td, p, (off_t)(uintptr_t)addr, &data, + sizeof(int)) != sizeof(int)) + error = ENOMEM; + else + CTR3(KTR_PTRACE, "PT_WRITE: pid %d: %p <= %#x", + p->p_pid, addr, data); + PROC_LOCK(p); + break; + case PT_READ_I: case PT_READ_D: PROC_UNLOCK(p); - tmp = 0; - /* write = 0 set above */ - iov.iov_base = write ? (caddr_t)&data : (caddr_t)&tmp; - iov.iov_len = sizeof(int); - uio.uio_iov = &iov; - 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", - p->p_pid, addr, data); - else - CTR3(KTR_PTRACE, "PT_READ: pid %d: %p >= %#x", - p->p_pid, addr, tmp); - } + error = tmp = 0; + if (proc_readmem(td, p, (off_t)(uintptr_t)addr, &tmp, + sizeof(int)) != sizeof(int)) + error = ENOMEM; + else + CTR3(KTR_PTRACE, "PT_READ: pid %d: %p >= %#x", + p->p_pid, addr, tmp); + td->td_retval[0] = tmp; PROC_LOCK(p); break; |