Modify DTRACEHIOC_ADDDOF to copy the DOF section from the target process.
r281257 added support for lazyload mode by allowing dtrace(1) to register a DOF section on behalf of a traced process. This was implemented by having libdtrace copy the DOF section into a heap-allocated buffer and passing its address to the ioctl handler. However, DTrace uses the DOF section address as a lookup key in certain cases, so the ioctl handler should be given the target process' DOF section address instead. This change modifies the ADDDOF handler to copy the DOF section in from the target process, rather than from dtrace(1).
This commit is contained in:
parent
711fbd17ec
commit
6e0f204c3f
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=291962
@ -571,12 +571,6 @@ dt_pid_usdt_mapping(void *data, const prmap_t *pmp, const char *oname)
|
||||
prsyminfo_t sip;
|
||||
dof_helper_t dh;
|
||||
GElf_Half e_type;
|
||||
#ifdef __FreeBSD__
|
||||
dof_hdr_t hdr;
|
||||
size_t sz;
|
||||
uint64_t dofmax;
|
||||
void *dof;
|
||||
#endif
|
||||
const char *mname;
|
||||
const char *syms[] = { "___SUNW_dof", "__SUNW_dof" };
|
||||
int i, fd = -1;
|
||||
@ -606,61 +600,25 @@ dt_pid_usdt_mapping(void *data, const prmap_t *pmp, const char *oname)
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
dh.dofhp_addr = (e_type == ET_EXEC) ? 0 : pmp->pr_vaddr;
|
||||
if (Pread(P, &hdr, sizeof (hdr), sym.st_value) !=
|
||||
sizeof (hdr)) {
|
||||
dt_dprintf("read of DOF header failed\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
sz = sizeof(dofmax);
|
||||
if (sysctlbyname("kern.dtrace.dof_maxsize", &dofmax, &sz,
|
||||
NULL, 0) != 0) {
|
||||
dt_dprintf("failed to read dof_maxsize: %s\n",
|
||||
strerror(errno));
|
||||
continue;
|
||||
}
|
||||
if (dofmax < hdr.dofh_loadsz) {
|
||||
dt_dprintf("DOF load size exceeds maximum\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((dof = malloc(hdr.dofh_loadsz)) == NULL)
|
||||
return (-1);
|
||||
|
||||
if (Pread(P, dof, hdr.dofh_loadsz, sym.st_value) !=
|
||||
hdr.dofh_loadsz) {
|
||||
free(dof);
|
||||
dt_dprintf("read of DOF section failed\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
dh.dofhp_dof = (uintptr_t)dof;
|
||||
dh.dofhp_pid = proc_getpid(P);
|
||||
|
||||
dt_pid_objname(dh.dofhp_mod, sizeof (dh.dofhp_mod),
|
||||
sip.prs_lmid, mname);
|
||||
|
||||
if (fd == -1 &&
|
||||
(fd = open("/dev/dtrace/helper", O_RDWR, 0)) < 0) {
|
||||
dt_dprintf("open of helper device failed: %s\n",
|
||||
strerror(errno));
|
||||
free(dof);
|
||||
return (-1); /* errno is set for us */
|
||||
}
|
||||
|
||||
if (ioctl(fd, DTRACEHIOC_ADDDOF, &dh, sizeof (dh)) < 0)
|
||||
dt_dprintf("DOF was rejected for %s\n", dh.dofhp_mod);
|
||||
|
||||
free(dof);
|
||||
#else
|
||||
dh.dofhp_dof = sym.st_value;
|
||||
dh.dofhp_addr = (e_type == ET_EXEC) ? 0 : pmp->pr_vaddr;
|
||||
|
||||
dt_pid_objname(dh.dofhp_mod, sizeof (dh.dofhp_mod),
|
||||
sip.prs_lmid, mname);
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
dh.dofhp_pid = proc_getpid(P);
|
||||
|
||||
if (fd == -1 &&
|
||||
(fd = open("/dev/dtrace/helper", O_RDWR, 0)) < 0) {
|
||||
dt_dprintf("open of helper device failed: %s\n",
|
||||
strerror(errno));
|
||||
return (-1); /* errno is set for us */
|
||||
}
|
||||
|
||||
if (ioctl(fd, DTRACEHIOC_ADDDOF, &dh, sizeof (dh)) < 0)
|
||||
dt_dprintf("DOF was rejected for %s\n", dh.dofhp_mod);
|
||||
#else
|
||||
if (fd == -1 &&
|
||||
(fd = pr_open(P, "/dev/dtrace/helper", O_RDWR, 0)) < 0) {
|
||||
dt_dprintf("pr_open of helper device failed: %s\n",
|
||||
|
@ -120,13 +120,17 @@
|
||||
#include <sys/kdb.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/rwlock.h>
|
||||
#include <sys/sx.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#include <sys/dtrace_bsd.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "dtrace_cddl.h"
|
||||
#include "dtrace_debug.c"
|
||||
#endif
|
||||
@ -13030,9 +13034,60 @@ dtrace_dof_copyin(uintptr_t uarg, int *errp)
|
||||
return (dof);
|
||||
}
|
||||
|
||||
#ifndef illumos
|
||||
#ifdef __FreeBSD__
|
||||
static dof_hdr_t *
|
||||
dtrace_dof_copyin_proc(struct proc *p, uintptr_t uarg, int *errp)
|
||||
{
|
||||
dof_hdr_t hdr, *dof;
|
||||
struct thread *td;
|
||||
size_t loadsz;
|
||||
|
||||
ASSERT(!MUTEX_HELD(&dtrace_lock));
|
||||
|
||||
td = curthread;
|
||||
|
||||
/*
|
||||
* First, we're going to copyin() the sizeof (dof_hdr_t).
|
||||
*/
|
||||
if (proc_readmem(td, p, uarg, &hdr, sizeof(hdr)) != sizeof(hdr)) {
|
||||
dtrace_dof_error(NULL, "failed to copyin DOF header");
|
||||
*errp = EFAULT;
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Now we'll allocate the entire DOF and copy it in -- provided
|
||||
* that the length isn't outrageous.
|
||||
*/
|
||||
if (hdr.dofh_loadsz >= dtrace_dof_maxsize) {
|
||||
dtrace_dof_error(&hdr, "load size exceeds maximum");
|
||||
*errp = E2BIG;
|
||||
return (NULL);
|
||||
}
|
||||
loadsz = (size_t)hdr.dofh_loadsz;
|
||||
|
||||
if (loadsz < sizeof (hdr)) {
|
||||
dtrace_dof_error(&hdr, "invalid load size");
|
||||
*errp = EINVAL;
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
dof = kmem_alloc(loadsz, KM_SLEEP);
|
||||
|
||||
if (proc_readmem(td, p, uarg, dof, loadsz) != loadsz ||
|
||||
dof->dofh_loadsz != loadsz) {
|
||||
kmem_free(dof, hdr.dofh_loadsz);
|
||||
*errp = EFAULT;
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
return (dof);
|
||||
}
|
||||
|
||||
static __inline uchar_t
|
||||
dtrace_dof_char(char c) {
|
||||
dtrace_dof_char(char c)
|
||||
{
|
||||
|
||||
switch (c) {
|
||||
case '0':
|
||||
case '1':
|
||||
@ -13063,7 +13118,7 @@ dtrace_dof_char(char c) {
|
||||
/* Should not reach here. */
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
#endif /* __FreeBSD__ */
|
||||
|
||||
static dof_hdr_t *
|
||||
dtrace_dof_property(const char *name)
|
||||
@ -15967,31 +16022,23 @@ dtrace_helper_provider_validate(dof_hdr_t *dof, dof_sec_t *sec)
|
||||
}
|
||||
|
||||
static int
|
||||
#ifdef __FreeBSD__
|
||||
dtrace_helper_slurp(dof_hdr_t *dof, dof_helper_t *dhp, struct proc *p)
|
||||
#else
|
||||
dtrace_helper_slurp(dof_hdr_t *dof, dof_helper_t *dhp)
|
||||
#endif
|
||||
{
|
||||
dtrace_helpers_t *help;
|
||||
dtrace_vstate_t *vstate;
|
||||
dtrace_enabling_t *enab = NULL;
|
||||
#ifndef __FreeBSD__
|
||||
proc_t *p = curproc;
|
||||
#endif
|
||||
int i, gen, rv, nhelpers = 0, nprovs = 0, destroy = 1;
|
||||
uintptr_t daddr = (uintptr_t)dof;
|
||||
|
||||
ASSERT(MUTEX_HELD(&dtrace_lock));
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
if (dhp->dofhp_pid != p->p_pid) {
|
||||
if ((p = pfind(dhp->dofhp_pid)) == NULL)
|
||||
return (-1);
|
||||
if (!P_SHOULDSTOP(p) ||
|
||||
(p->p_flag & P_TRACED) == 0 ||
|
||||
p->p_pptr->p_pid != curproc->p_pid) {
|
||||
PROC_UNLOCK(p);
|
||||
return (-1);
|
||||
}
|
||||
PROC_UNLOCK(p);
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((help = p->p_dtrace_helpers) == NULL)
|
||||
help = dtrace_helpers_create(p);
|
||||
|
||||
|
@ -32,25 +32,47 @@ static int
|
||||
dtrace_ioctl_helper(struct cdev *dev, u_long cmd, caddr_t addr, int flags,
|
||||
struct thread *td)
|
||||
{
|
||||
dof_helper_t *dhp = NULL;
|
||||
dof_hdr_t *dof = NULL;
|
||||
struct proc *p;
|
||||
dof_helper_t *dhp;
|
||||
dof_hdr_t *dof;
|
||||
int rval;
|
||||
|
||||
dhp = NULL;
|
||||
dof = NULL;
|
||||
rval = 0;
|
||||
switch (cmd) {
|
||||
case DTRACEHIOC_ADDDOF:
|
||||
dhp = (dof_helper_t *)addr;
|
||||
/* XXX all because dofhp_dof is 64 bit */
|
||||
addr = (caddr_t)(vm_offset_t)dhp->dofhp_dof;
|
||||
addr = (caddr_t)(uintptr_t)dhp->dofhp_dof;
|
||||
/* FALLTHROUGH */
|
||||
case DTRACEHIOC_ADD:
|
||||
dof = dtrace_dof_copyin((intptr_t)addr, &rval);
|
||||
p = curproc;
|
||||
if (p->p_pid == dhp->dofhp_pid) {
|
||||
dof = dtrace_dof_copyin((uintptr_t)addr, &rval);
|
||||
} else {
|
||||
p = pfind(dhp->dofhp_pid);
|
||||
if (p == NULL)
|
||||
return (EINVAL);
|
||||
if (!P_SHOULDSTOP(p) ||
|
||||
(p->p_flag & P_TRACED|P_WEXIT) == 0 ||
|
||||
p->p_pptr != curproc) {
|
||||
PROC_UNLOCK(p);
|
||||
return (EINVAL);
|
||||
}
|
||||
_PHOLD(p);
|
||||
PROC_UNLOCK(p);
|
||||
dof = dtrace_dof_copyin_proc(p, (uintptr_t)addr, &rval);
|
||||
}
|
||||
|
||||
if (dof == NULL)
|
||||
return (rval);
|
||||
if (dof == NULL) {
|
||||
if (p != curproc)
|
||||
PRELE(p);
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_enter(&dtrace_lock);
|
||||
if ((rval = dtrace_helper_slurp((dof_hdr_t *)dof, dhp)) != -1) {
|
||||
if (dhp) {
|
||||
if ((rval = dtrace_helper_slurp(dof, dhp, p)) != -1) {
|
||||
if (dhp != NULL) {
|
||||
dhp->dofhp_gen = rval;
|
||||
copyout(dhp, addr, sizeof(*dhp));
|
||||
}
|
||||
@ -59,19 +81,19 @@ dtrace_ioctl_helper(struct cdev *dev, u_long cmd, caddr_t addr, int flags,
|
||||
rval = EINVAL;
|
||||
}
|
||||
mutex_exit(&dtrace_lock);
|
||||
|
||||
return (rval);
|
||||
if (p != curproc)
|
||||
PRELE(p);
|
||||
break;
|
||||
case DTRACEHIOC_REMOVE:
|
||||
mutex_enter(&dtrace_lock);
|
||||
rval = dtrace_helper_destroygen(NULL, (int)*addr);
|
||||
rval = dtrace_helper_destroygen(NULL, *(int *)(uintptr_t)addr);
|
||||
mutex_exit(&dtrace_lock);
|
||||
|
||||
return (rval);
|
||||
break;
|
||||
default:
|
||||
rval = ENOTTY;
|
||||
break;
|
||||
}
|
||||
|
||||
return (ENOTTY);
|
||||
return (rval);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
|
Loading…
Reference in New Issue
Block a user