Page MenuHomeFreeBSD

D4245.id10751.diff
No OneTemporary

D4245.id10751.diff

Index: share/man/man9/Makefile
===================================================================
--- share/man/man9/Makefile
+++ share/man/man9/Makefile
@@ -239,6 +239,7 @@
printf.9 \
prison_check.9 \
priv.9 \
+ proc_rwmem.9 \
pseudofs.9 \
psignal.9 \
random.9 \
@@ -1339,6 +1340,8 @@
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
Index: share/man/man9/proc_rwmem.9
===================================================================
--- /dev/null
+++ share/man/man9/proc_rwmem.9
@@ -0,0 +1,110 @@
+.\"
+.\" Copyright (c) 2015 Mark Johnston <markj@FreeBSD.org>
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd December 4, 2015
+.Dt PROC_RWMEM 9
+.Os
+.Sh NAME
+.Nm proc_rwmem ,
+.Nm proc_readmem ,
+.Nm proc_writemem
+.Nd read from or write to a process address space
+.Sh SYNOPSIS
+.In sys/types.h
+.In sys/ptrace.h
+.Ft int
+.Fn proc_rwmem "struct proc *p" "struct uio *uio"
+.Ft ssize_t
+.Fo proc_readmem
+.Fa "struct thread *td" "struct proc *p" "vm_offset_t va" "void *buf"
+.Fa "size_t len"
+.Fc
+.Ft ssize_t
+.Fo proc_writemem
+.Fa "struct thread *td" "struct proc *p" "vm_offset_t va" "void *buf"
+.Fa "size_t len"
+.Fc
+.Sh DESCRIPTION
+These functions are used to read to or write from the address space of the
+process
+.Fa p .
+The
+.Fn proc_rwmem
+function requires the caller to specify the I/O parameters using a
+.Vt "struct uio" ,
+described in
+.Xr uio 9 .
+The
+.Fn proc_readmem
+and
+.Fn proc_writemem
+functions provide a simpler, less general interface which allows the caller to
+read into or write the kernel buffer
+.Fa buf
+of size
+.Fa len
+from or to the memory at offset
+.Fa va
+in the address space of
+.Fa p .
+The operation is performed on behalf of thread
+.Fa td ,
+which will most often be the current thread.
+.Pp
+These functions may sleep and thus may not be called with any non-sleepable
+locks held.
+The process
+.Fa p
+must be held by the caller using
+.Xr PHOLD 9 .
+.Sh RETURN VALUES
+The
+.Fn proc_rwmem
+function returns
+.Dv 0
+on success.
+.Dv EFAULT
+is returned if the specified user address is invalid, and
+.Dv ENOMEM
+is returned if the target pages could not be faulted in due to a resource
+shortage.
+.Pp
+The
+.Fn proc_readmem
+and
+.Fn proc_writemem
+functions return the number of bytes read or written, respectively.
+This may be smaller than the number of bytes requested, for example if the
+request spans multiple pages in the process address space and one of them after
+the first is not mapped.
+Otherwise, -1 is returned.
+.Sh SEE ALSO
+.Xr copyin 9 ,
+.Xr locking 9 ,
+.Xr PHOLD 9 ,
+.Xr uio 9
+.Sh AUTHORS
+This manual page was written by
+.An Mark Johnston Aq Mt markj@FreeBSD.org .
Index: sys/arm/arm/machdep.c
===================================================================
--- sys/arm/arm/machdep.c
+++ sys/arm/arm/machdep.c
@@ -591,41 +591,21 @@
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
Index: sys/cddl/contrib/opensolaris/uts/intel/dtrace/fasttrap_isa.c
===================================================================
--- sys/cddl/contrib/opensolaris/uts/intel/dtrace/fasttrap_isa.c
+++ sys/cddl/contrib/opensolaris/uts/intel/dtrace/fasttrap_isa.c
@@ -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;
-
- 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;
+ ssize_t n;
+
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
Index: sys/cddl/contrib/opensolaris/uts/powerpc/dtrace/fasttrap_isa.c
===================================================================
--- sys/cddl/contrib/opensolaris/uts/powerpc/dtrace/fasttrap_isa.c
+++ sys/cddl/contrib/opensolaris/uts/powerpc/dtrace/fasttrap_isa.c
@@ -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;
-
- 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;
+ ssize_t n;
+
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
Index: sys/kern/kern_proc.c
===================================================================
--- sys/kern/kern_proc.c
+++ sys/kern/kern_proc.c
@@ -1526,50 +1526,20 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
* 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 @@
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;
Index: sys/kern/sys_process.c
===================================================================
--- sys/kern/sys_process.c
+++ sys/kern/sys_process.c
@@ -252,6 +252,7 @@
* from exiting out from under us until this operation completes.
*/
PROC_ASSERT_HELD(p);
+ PROC_LOCK_ASSERT(p, MA_NOTOWNED);
/*
* The map we want...
@@ -328,6 +329,49 @@
}
static int
+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);
+}
+
+int
+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));
+}
+
+int
+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)
{
struct vattr vattr;
@@ -644,7 +688,7 @@
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 @@
break;
}
- write = 0;
if (req == PT_TRACE_ME) {
p = td->td_proc;
PROC_LOCK(p);
@@ -1033,46 +1076,28 @@
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;
Index: sys/mips/mips/pm_machdep.c
===================================================================
--- sys/mips/mips/pm_machdep.c
+++ sys/mips/mips/pm_machdep.c
@@ -214,39 +214,19 @@
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->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->proc, addr, &v, sizeof(v)) != sizeof(v))
+ return (ENOMEM);
+ return (0);
}
int
Index: sys/sys/ptrace.h
===================================================================
--- sys/sys/ptrace.h
+++ sys/sys/ptrace.h
@@ -166,6 +166,10 @@
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);
+int proc_readmem(struct thread *_td, struct proc *_p, vm_offset_t _va,
+ void *_buf, size_t _len);
+int proc_writemem(struct thread *_td, struct proc *_p, vm_offset_t _va,
+ void *_buf, size_t _len);
#ifdef COMPAT_FREEBSD32
struct reg32;
struct fpreg32;

File Metadata

Mime Type
text/plain
Expires
Thu, Feb 5, 5:39 PM (21 h, 5 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28443323
Default Alt Text
D4245.id10751.diff (17 KB)

Event Timeline