Author: markj
Date: Mon Dec  7 21:33:15 2015
New Revision: 291961
URL: https://svnweb.freebsd.org/changeset/base/291961

Log:
  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

Modified:
  head/share/man/man9/Makefile
  head/sys/arm/arm/machdep.c
  head/sys/cddl/contrib/opensolaris/uts/intel/dtrace/fasttrap_isa.c
  head/sys/cddl/contrib/opensolaris/uts/powerpc/dtrace/fasttrap_isa.c
  head/sys/kern/kern_proc.c
  head/sys/kern/sys_process.c
  head/sys/mips/mips/pm_machdep.c
  head/sys/sys/ptrace.h

Modified: head/share/man/man9/Makefile
==============================================================================
--- head/share/man/man9/Makefile        Mon Dec  7 21:04:27 2015        
(r291960)
+++ head/share/man/man9/Makefile        Mon Dec  7 21:33:15 2015        
(r291961)
@@ -239,6 +239,7 @@ MAN=        accept_filter.9 \
        printf.9 \
        prison_check.9 \
        priv.9 \
+       proc_rwmem.9 \
        pseudofs.9 \
        psignal.9 \
        random.9 \
@@ -1340,6 +1341,8 @@ MLINKS+=printf.9 log.9 \
        printf.9 uprintf.9
 MLINKS+=priv.9 priv_check.9 \
        priv.9 priv_check_cred.9
+MLINKS+=proc_rwmem.9 proc_readmem.9 \
+       proc_rwmem.9 proc_writemem.9
 MLINKS+=psignal.9 gsignal.9 \
        psignal.9 pgsignal.9 \
        psignal.9 tdsignal.9

Modified: head/sys/arm/arm/machdep.c
==============================================================================
--- head/sys/arm/arm/machdep.c  Mon Dec  7 21:04:27 2015        (r291960)
+++ head/sys/arm/arm/machdep.c  Mon Dec  7 21:33:15 2015        (r291961)
@@ -598,41 +598,21 @@ set_dbregs(struct thread *td, struct dbr
 
 
 static int
-ptrace_read_int(struct thread *td, vm_offset_t addr, u_int32_t *v)
+ptrace_read_int(struct thread *td, vm_offset_t addr, uint32_t *v)
 {
-       struct iovec iov;
-       struct uio uio;
 
-       PROC_LOCK_ASSERT(td->td_proc, MA_NOTOWNED);
-       iov.iov_base = (caddr_t) v;
-       iov.iov_len = sizeof(u_int32_t);
-       uio.uio_iov = &iov;
-       uio.uio_iovcnt = 1;
-       uio.uio_offset = (off_t)addr;
-       uio.uio_resid = sizeof(u_int32_t);
-       uio.uio_segflg = UIO_SYSSPACE;
-       uio.uio_rw = UIO_READ;
-       uio.uio_td = td;
-       return proc_rwmem(td->td_proc, &uio);
+       if (proc_readmem(td, td->td_proc, addr, v, sizeof(*v)) != sizeof(*v))
+               return (ENOMEM);
+       return (0);
 }
 
 static int
-ptrace_write_int(struct thread *td, vm_offset_t addr, u_int32_t v)
+ptrace_write_int(struct thread *td, vm_offset_t addr, uint32_t v)
 {
-       struct iovec iov;
-       struct uio uio;
 
-       PROC_LOCK_ASSERT(td->td_proc, MA_NOTOWNED);
-       iov.iov_base = (caddr_t) &v;
-       iov.iov_len = sizeof(u_int32_t);
-       uio.uio_iov = &iov;
-       uio.uio_iovcnt = 1;
-       uio.uio_offset = (off_t)addr;
-       uio.uio_resid = sizeof(u_int32_t);
-       uio.uio_segflg = UIO_SYSSPACE;
-       uio.uio_rw = UIO_WRITE;
-       uio.uio_td = td;
-       return proc_rwmem(td->td_proc, &uio);
+       if (proc_writemem(td, td->td_proc, addr, &v, sizeof(v)) != sizeof(v))
+               return (ENOMEM);
+       return (0);
 }
 
 static u_int

Modified: head/sys/cddl/contrib/opensolaris/uts/intel/dtrace/fasttrap_isa.c
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/intel/dtrace/fasttrap_isa.c   Mon Dec 
 7 21:04:27 2015        (r291960)
+++ head/sys/cddl/contrib/opensolaris/uts/intel/dtrace/fasttrap_isa.c   Mon Dec 
 7 21:33:15 2015        (r291961)
@@ -60,43 +60,31 @@
 #include <sys/ptrace.h>
 
 static int
-proc_ops(int op, proc_t *p, void *kaddr, off_t uaddr, size_t len)
+uread(proc_t *p, void *kaddr, size_t len, uintptr_t uaddr)
 {
-       struct iovec iov;
-       struct uio uio;
+       ssize_t n;
 
-       iov.iov_base = kaddr;
-       iov.iov_len = len;
-       uio.uio_offset = uaddr;
-       uio.uio_iov = &iov;
-       uio.uio_resid = len;
-       uio.uio_iovcnt = 1;
-       uio.uio_segflg = UIO_SYSSPACE;
-       uio.uio_td = curthread;
-       uio.uio_rw = op;
        PHOLD(p);
-       if (proc_rwmem(p, &uio) != 0) {
-               PRELE(p);
-               return (-1);
-       }
+       n = proc_readmem(curthread, p, uaddr, kaddr, len);
        PRELE(p);
-
+       if (n != len)
+               return (ENOMEM);
        return (0);
 }
 
 static int
-uread(proc_t *p, void *kaddr, size_t len, uintptr_t uaddr)
-{
-
-       return (proc_ops(UIO_READ, p, kaddr, uaddr, len));
-}
-
-static int
 uwrite(proc_t *p, void *kaddr, size_t len, uintptr_t uaddr)
 {
+       ssize_t n;
 
-       return (proc_ops(UIO_WRITE, p, kaddr, uaddr, len));
+       PHOLD(p);
+       n = proc_writemem(curthread, p, uaddr, kaddr, len);
+       PRELE(p);
+       if (n != len)
+               return (ENOMEM);
+       return (0);
 }
+
 #endif /* illumos */
 #ifdef __i386__
 #define        r_rax   r_eax

Modified: head/sys/cddl/contrib/opensolaris/uts/powerpc/dtrace/fasttrap_isa.c
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/powerpc/dtrace/fasttrap_isa.c Mon Dec 
 7 21:04:27 2015        (r291960)
+++ head/sys/cddl/contrib/opensolaris/uts/powerpc/dtrace/fasttrap_isa.c Mon Dec 
 7 21:33:15 2015        (r291961)
@@ -43,44 +43,30 @@
 #define OP_RA(x) (((x) & 0x001F0000) >> 16)
 #define OP_RB(x) (((x) & 0x0000F100) >> 11)
 
-
 static int
-proc_ops(int op, proc_t *p, void *kaddr, off_t uaddr, size_t len)
+uread(proc_t *p, void *kaddr, size_t len, uintptr_t uaddr)
 {
-       struct iovec iov;
-       struct uio uio;
+       ssize_t n;
 
-       iov.iov_base = kaddr;
-       iov.iov_len = len;
-       uio.uio_offset = uaddr;
-       uio.uio_iov = &iov;
-       uio.uio_resid = len;
-       uio.uio_iovcnt = 1;
-       uio.uio_segflg = UIO_SYSSPACE;
-       uio.uio_td = curthread;
-       uio.uio_rw = op;
        PHOLD(p);
-       if (proc_rwmem(p, &uio) != 0) {
-               PRELE(p);
-               return (-1);
-       }
+       n = proc_readmem(curthread, p, uaddr, kaddr, len);
        PRELE(p);
-
+       if (n <= 0 || n < len)
+               return (ENOMEM);
        return (0);
 }
 
 static int
-uread(proc_t *p, void *kaddr, size_t len, uintptr_t uaddr)
-{
-
-       return (proc_ops(UIO_READ, p, kaddr, uaddr, len));
-}
-
-static int
 uwrite(proc_t *p, void *kaddr, size_t len, uintptr_t uaddr)
 {
+       ssize_t n;
 
-       return (proc_ops(UIO_WRITE, p, kaddr, uaddr, len));
+       PHOLD(p);
+       n = proc_writemem(curthread, p, uaddr, kaddr, len);
+       PRELE(p);
+       if (n <= 0 || n < len)
+               return (ENOMEM);
+       return (0);
 }
 
 int

Modified: head/sys/kern/kern_proc.c
==============================================================================
--- head/sys/kern/kern_proc.c   Mon Dec  7 21:04:27 2015        (r291960)
+++ head/sys/kern/kern_proc.c   Mon Dec  7 21:33:15 2015        (r291961)
@@ -1526,50 +1526,20 @@ pargs_drop(struct pargs *pa)
 }
 
 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,
     size_t len)
 {
-       size_t i;
-       int error;
+       ssize_t n;
 
-       error = proc_read_mem(td, p, (vm_offset_t)sptr, buf, len);
        /*
-        * Reading the chunk may validly return EFAULT if the string is shorter
-        * than the chunk and is aligned at the end of the page, assuming the
-        * next page is not mapped.  So if EFAULT is returned do a fallback to
-        * one byte read loop.
+        * This may return a short read if the string is shorter than the chunk
+        * and is aligned at the end of the page, and the following page is not
+        * mapped.
         */
-       if (error == EFAULT) {
-               for (i = 0; i < len; i++, buf++, sptr++) {
-                       error = proc_read_mem(td, p, (vm_offset_t)sptr, buf, 1);
-                       if (error != 0)
-                               return (error);
-                       if (*buf == '\0')
-                               break;
-               }
-               error = 0;
-       }
-       return (error);
+       n = proc_readmem(td, p, (vm_offset_t)sptr, buf, len);
+       if (n <= 0)
+               return (ENOMEM);
+       return (0);
 }
 
 #define PROC_AUXV_MAX  256     /* Safety limit on auxv size. */
@@ -1593,10 +1563,10 @@ get_proc_vector32(struct thread *td, str
        size_t vsize, size;
        int i, error;
 
-       error = proc_read_mem(td, p, (vm_offset_t)(p->p_sysent->sv_psstrings),
-           &pss, sizeof(pss));
-       if (error != 0)
-               return (error);
+       error = 0;
+       if (proc_readmem(td, p, (vm_offset_t)p->p_sysent->sv_psstrings, &pss,
+           sizeof(pss)) != sizeof(pss))
+               return (ENOMEM);
        switch (type) {
        case PROC_ARG:
                vptr = (vm_offset_t)PTRIN(pss.ps_argvstr);
@@ -1618,9 +1588,9 @@ get_proc_vector32(struct thread *td, str
                if (vptr % 4 != 0)
                        return (ENOEXEC);
                for (ptr = vptr, i = 0; i < PROC_AUXV_MAX; i++) {
-                       error = proc_read_mem(td, p, ptr, &aux, sizeof(aux));
-                       if (error != 0)
-                               return (error);
+                       if (proc_readmem(td, p, ptr, &aux, sizeof(aux)) !=
+                           sizeof(aux))
+                               return (ENOMEM);
                        if (aux.a_type == AT_NULL)
                                break;
                        ptr += sizeof(aux);
@@ -1635,9 +1605,10 @@ get_proc_vector32(struct thread *td, str
                return (EINVAL);
        }
        proc_vector32 = malloc(size, M_TEMP, M_WAITOK);
-       error = proc_read_mem(td, p, vptr, proc_vector32, size);
-       if (error != 0)
+       if (proc_readmem(td, p, vptr, proc_vector32, size) != size) {
+               error = ENOMEM;
                goto done;
+       }
        if (type == PROC_AUX) {
                *proc_vectorp = (char **)proc_vector32;
                *vsizep = vsize;
@@ -1663,16 +1634,15 @@ get_proc_vector(struct thread *td, struc
        vm_offset_t vptr, ptr;
        char **proc_vector;
        size_t vsize, size;
-       int error, i;
+       int i;
 
 #ifdef COMPAT_FREEBSD32
        if (SV_PROC_FLAG(p, SV_ILP32) != 0)
                return (get_proc_vector32(td, p, proc_vectorp, vsizep, type));
 #endif
-       error = proc_read_mem(td, p, (vm_offset_t)(p->p_sysent->sv_psstrings),
-           &pss, sizeof(pss));
-       if (error != 0)
-               return (error);
+       if (proc_readmem(td, p, (vm_offset_t)p->p_sysent->sv_psstrings, &pss,
+           sizeof(pss)) != sizeof(pss))
+               return (ENOMEM);
        switch (type) {
        case PROC_ARG:
                vptr = (vm_offset_t)pss.ps_argvstr;
@@ -1709,9 +1679,9 @@ get_proc_vector(struct thread *td, struc
                 * to the allocated proc_vector.
                 */
                for (ptr = vptr, i = 0; i < PROC_AUXV_MAX; i++) {
-                       error = proc_read_mem(td, p, ptr, &aux, sizeof(aux));
-                       if (error != 0)
-                               return (error);
+                       if (proc_readmem(td, p, ptr, &aux, sizeof(aux)) !=
+                           sizeof(aux))
+                               return (ENOMEM);
                        if (aux.a_type == AT_NULL)
                                break;
                        ptr += sizeof(aux);
@@ -1732,12 +1702,9 @@ get_proc_vector(struct thread *td, struc
                return (EINVAL); /* In case we are built without INVARIANTS. */
        }
        proc_vector = malloc(size, M_TEMP, M_WAITOK);
-       if (proc_vector == NULL)
-               return (ENOMEM);
-       error = proc_read_mem(td, p, vptr, proc_vector, size);
-       if (error != 0) {
+       if (proc_readmem(td, p, vptr, proc_vector, size) != size) {
                free(proc_vector, M_TEMP);
-               return (error);
+               return (ENOMEM);
        }
        *proc_vectorp = proc_vector;
        *vsizep = vsize;

Modified: head/sys/kern/sys_process.c
==============================================================================
--- head/sys/kern/sys_process.c Mon Dec  7 21:04:27 2015        (r291960)
+++ head/sys/kern/sys_process.c Mon Dec  7 21:33:15 2015        (r291961)
@@ -252,6 +252,7 @@ proc_rwmem(struct proc *p, struct uio *u
         * 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 *u
        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, 
        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, 
                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, 
        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;
 

Modified: head/sys/mips/mips/pm_machdep.c
==============================================================================
--- head/sys/mips/mips/pm_machdep.c     Mon Dec  7 21:04:27 2015        
(r291960)
+++ head/sys/mips/mips/pm_machdep.c     Mon Dec  7 21:33:15 2015        
(r291961)
@@ -214,39 +214,19 @@ ptrace_set_pc(struct thread *td, unsigne
 static int
 ptrace_read_int(struct thread *td, off_t addr, int *v)
 {
-       struct iovec iov;
-       struct uio uio;
 
-       PROC_LOCK_ASSERT(td->td_proc, MA_NOTOWNED);
-       iov.iov_base = (caddr_t) v;
-       iov.iov_len = sizeof(int);
-       uio.uio_iov = &iov;
-       uio.uio_iovcnt = 1;
-       uio.uio_offset = (off_t)addr;
-       uio.uio_resid = sizeof(int);
-       uio.uio_segflg = UIO_SYSSPACE;
-       uio.uio_rw = UIO_READ;
-       uio.uio_td = td;
-       return proc_rwmem(td->td_proc, &uio);
+       if (proc_readmem(td, td->td_proc, addr, v, sizeof(*v)) != sizeof(*v))
+               return (ENOMEM);
+       return (0);
 }
 
 static int
 ptrace_write_int(struct thread *td, off_t addr, int v)
 {
-       struct iovec iov;
-       struct uio uio;
 
-       PROC_LOCK_ASSERT(td->td_proc, MA_NOTOWNED);
-       iov.iov_base = (caddr_t) &v;
-       iov.iov_len = sizeof(int);
-       uio.uio_iov = &iov;
-       uio.uio_iovcnt = 1;
-       uio.uio_offset = (off_t)addr;
-       uio.uio_resid = sizeof(int);
-       uio.uio_segflg = UIO_SYSSPACE;
-       uio.uio_rw = UIO_WRITE;
-       uio.uio_td = td;
-       return proc_rwmem(td->td_proc, &uio);
+       if (proc_writemem(td, td->td_proc, addr, &v, sizeof(v)) != sizeof(v))
+               return (ENOMEM);
+       return (0);
 }
 
 int

Modified: head/sys/sys/ptrace.h
==============================================================================
--- head/sys/sys/ptrace.h       Mon Dec  7 21:04:27 2015        (r291960)
+++ head/sys/sys/ptrace.h       Mon Dec  7 21:33:15 2015        (r291961)
@@ -166,6 +166,10 @@ int        proc_read_dbregs(struct thread *_td,
 int    proc_write_dbregs(struct thread *_td, struct dbreg *_dbreg);
 int    proc_sstep(struct thread *_td);
 int    proc_rwmem(struct proc *_p, struct uio *_uio);
+ssize_t        proc_readmem(struct thread *_td, struct proc *_p, vm_offset_t 
_va,
+           void *_buf, size_t _len);
+ssize_t        proc_writemem(struct thread *_td, struct proc *_p, vm_offset_t 
_va,
+           void *_buf, size_t _len);
 #ifdef COMPAT_FREEBSD32
 struct reg32;
 struct fpreg32;
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "[email protected]"

Reply via email to