svn commit: r291961 - in head: share/man/man9 sys/arm/arm sys/cddl/contrib/opensolaris/uts/intel/dtrace sys/cddl/contrib/opensolaris/uts/powerpc/dtrace sys/kern sys/mips/mips sys/sys

Mark Johnston markj at FreeBSD.org
Mon Dec 7 21:33:17 UTC 2015


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;


More information about the svn-src-head mailing list