freebsd-src/sys/kern/sys_process.c

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

1702 lines
39 KiB
C
Raw Normal View History

/*-
* SPDX-License-Identifier: BSD-4-Clause
*
* Copyright (c) 1994, Sean Eric Fagan
* All rights reserved.
1994-05-24 10:09:53 +00:00
*
* 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Sean Eric Fagan.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
1994-05-24 10:09:53 +00:00
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1994-05-24 10:09:53 +00:00
* 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 AUTHOR OR CONTRIBUTORS BE LIABLE
1994-05-24 10:09:53 +00:00
* 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.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/ktr.h>
#include <sys/limits.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/reg.h>
#include <sys/syscallsubr.h>
#include <sys/sysent.h>
#include <sys/sysproto.h>
#include <sys/priv.h>
1994-05-24 10:09:53 +00:00
#include <sys/proc.h>
#include <sys/vnode.h>
#include <sys/ptrace.h>
Switch the vm_object mutex to be a rwlock. This will enable in the future further optimizations where the vm_object lock will be held in read mode most of the time the page cache resident pool of pages are accessed for reading purposes. The change is mostly mechanical but few notes are reported: * The KPI changes as follow: - VM_OBJECT_LOCK() -> VM_OBJECT_WLOCK() - VM_OBJECT_TRYLOCK() -> VM_OBJECT_TRYWLOCK() - VM_OBJECT_UNLOCK() -> VM_OBJECT_WUNLOCK() - VM_OBJECT_LOCK_ASSERT(MA_OWNED) -> VM_OBJECT_ASSERT_WLOCKED() (in order to avoid visibility of implementation details) - The read-mode operations are added: VM_OBJECT_RLOCK(), VM_OBJECT_TRYRLOCK(), VM_OBJECT_RUNLOCK(), VM_OBJECT_ASSERT_RLOCKED(), VM_OBJECT_ASSERT_LOCKED() * The vm/vm_pager.h namespace pollution avoidance (forcing requiring sys/mutex.h in consumers directly to cater its inlining functions using VM_OBJECT_LOCK()) imposes that all the vm/vm_pager.h consumers now must include also sys/rwlock.h. * zfs requires a quite convoluted fix to include FreeBSD rwlocks into the compat layer because the name clash between FreeBSD and solaris versions must be avoided. At this purpose zfs redefines the vm_object locking functions directly, isolating the FreeBSD components in specific compat stubs. The KPI results heavilly broken by this commit. Thirdy part ports must be updated accordingly (I can think off-hand of VirtualBox, for example). Sponsored by: EMC / Isilon storage division Reviewed by: jeff Reviewed by: pjd (ZFS specific review) Discussed with: alc Tested by: pho
2013-03-09 02:32:23 +00:00
#include <sys/rwlock.h>
#include <sys/sx.h>
#include <sys/malloc.h>
#include <sys/signalvar.h>
#include <sys/caprights.h>
#include <sys/filedesc.h>
1994-05-24 10:09:53 +00:00
#include <security/audit/audit.h>
#include <vm/vm.h>
#include <vm/pmap.h>
#include <vm/vm_extern.h>
#include <vm/vm_map.h>
#include <vm/vm_kern.h>
#include <vm/vm_object.h>
#include <vm/vm_page.h>
#include <vm/vm_param.h>
#ifdef COMPAT_FREEBSD32
#include <sys/procfs.h>
#endif
/* Assert it's safe to unlock a process, e.g. to allocate working memory */
#define PROC_ASSERT_TRACEREQ(p) MPASS(((p)->p_flag2 & P2_PTRACEREQ) != 0)
/*
* Functions implemented using PROC_ACTION():
*
* proc_read_regs(proc, regs)
* Get the current user-visible register set from the process
* and copy it into the regs structure (<machine/reg.h>).
* The process is stopped at the time read_regs is called.
*
* proc_write_regs(proc, regs)
* Update the current register set from the passed in regs
* structure. Take care to avoid clobbering special CPU
* registers or privileged bits in the PSL.
* Depending on the architecture this may have fix-up work to do,
* especially if the IAR or PCW are modified.
* The process is stopped at the time write_regs is called.
*
* proc_read_fpregs, proc_write_fpregs
* deal with the floating point register set, otherwise as above.
*
* proc_read_dbregs, proc_write_dbregs
* deal with the processor debug register set, otherwise as above.
*
* proc_sstep(proc)
* Arrange for the process to trap after executing a single instruction.
*/
#define PROC_ACTION(action) do { \
int error; \
\
PROC_LOCK_ASSERT(td->td_proc, MA_OWNED); \
if ((td->td_proc->p_flag & P_INMEM) == 0) \
error = EIO; \
else \
error = (action); \
return (error); \
} while (0)
2003-03-19 00:33:38 +00:00
int
proc_read_regs(struct thread *td, struct reg *regs)
{
PROC_ACTION(fill_regs(td, regs));
}
int
proc_write_regs(struct thread *td, struct reg *regs)
{
PROC_ACTION(set_regs(td, regs));
}
int
proc_read_dbregs(struct thread *td, struct dbreg *dbregs)
{
PROC_ACTION(fill_dbregs(td, dbregs));
}
int
proc_write_dbregs(struct thread *td, struct dbreg *dbregs)
{
PROC_ACTION(set_dbregs(td, dbregs));
}
/*
* Ptrace doesn't support fpregs at all, and there are no security holes
* or translations for fpregs, so we can just copy them.
*/
int
proc_read_fpregs(struct thread *td, struct fpreg *fpregs)
{
PROC_ACTION(fill_fpregs(td, fpregs));
}
int
proc_write_fpregs(struct thread *td, struct fpreg *fpregs)
{
PROC_ACTION(set_fpregs(td, fpregs));
}
static struct regset *
proc_find_regset(struct thread *td, int note)
{
struct regset **regsetp, **regset_end, *regset;
struct sysentvec *sv;
sv = td->td_proc->p_sysent;
regsetp = sv->sv_regset_begin;
if (regsetp == NULL)
return (NULL);
regset_end = sv->sv_regset_end;
MPASS(regset_end != NULL);
for (; regsetp < regset_end; regsetp++) {
regset = *regsetp;
if (regset->note != note)
continue;
return (regset);
}
return (NULL);
}
static int
proc_read_regset(struct thread *td, int note, struct iovec *iov)
{
struct regset *regset;
struct proc *p;
void *buf;
size_t size;
int error;
regset = proc_find_regset(td, note);
if (regset == NULL)
return (EINVAL);
if (regset->get == NULL)
return (EINVAL);
size = regset->size;
/*
* The regset is dynamically sized, e.g. the size could change
* depending on the hardware, or may have a per-thread size.
*/
if (size == 0) {
if (!regset->get(regset, td, NULL, &size))
return (EINVAL);
}
if (iov->iov_base == NULL) {
iov->iov_len = size;
if (iov->iov_len == 0)
return (EINVAL);
return (0);
}
/* The length is wrong, return an error */
if (iov->iov_len != size)
return (EINVAL);
error = 0;
p = td->td_proc;
/* Drop the proc lock while allocating the temp buffer */
PROC_ASSERT_TRACEREQ(p);
PROC_UNLOCK(p);
buf = malloc(size, M_TEMP, M_WAITOK);
PROC_LOCK(p);
if (!regset->get(regset, td, buf, &size)) {
error = EINVAL;
} else {
KASSERT(size == regset->size || regset->size == 0,
("%s: Getter function changed the size", __func__));
iov->iov_len = size;
PROC_UNLOCK(p);
error = copyout(buf, iov->iov_base, size);
PROC_LOCK(p);
}
free(buf, M_TEMP);
return (error);
}
static int
proc_write_regset(struct thread *td, int note, struct iovec *iov)
{
struct regset *regset;
struct proc *p;
void *buf;
size_t size;
int error;
regset = proc_find_regset(td, note);
if (regset == NULL)
return (EINVAL);
size = regset->size;
/*
* The regset is dynamically sized, e.g. the size could change
* depending on the hardware, or may have a per-thread size.
*/
if (size == 0) {
if (!regset->get(regset, td, NULL, &size))
return (EINVAL);
}
/* The length is wrong, return an error */
if (iov->iov_len != size)
return (EINVAL);
if (regset->set == NULL)
return (EINVAL);
p = td->td_proc;
/* Drop the proc lock while allocating the temp buffer */
PROC_ASSERT_TRACEREQ(p);
PROC_UNLOCK(p);
buf = malloc(size, M_TEMP, M_WAITOK);
error = copyin(iov->iov_base, buf, size);
PROC_LOCK(p);
if (error == 0) {
if (!regset->set(regset, td, buf, size)) {
error = EINVAL;
}
}
free(buf, M_TEMP);
return (error);
}
#ifdef COMPAT_FREEBSD32
/* For 32 bit binaries, we need to expose the 32 bit regs layouts. */
int
proc_read_regs32(struct thread *td, struct reg32 *regs32)
{
PROC_ACTION(fill_regs32(td, regs32));
}
int
proc_write_regs32(struct thread *td, struct reg32 *regs32)
{
PROC_ACTION(set_regs32(td, regs32));
}
int
proc_read_dbregs32(struct thread *td, struct dbreg32 *dbregs32)
{
PROC_ACTION(fill_dbregs32(td, dbregs32));
}
int
proc_write_dbregs32(struct thread *td, struct dbreg32 *dbregs32)
{
PROC_ACTION(set_dbregs32(td, dbregs32));
}
int
proc_read_fpregs32(struct thread *td, struct fpreg32 *fpregs32)
{
PROC_ACTION(fill_fpregs32(td, fpregs32));
}
int
proc_write_fpregs32(struct thread *td, struct fpreg32 *fpregs32)
{
PROC_ACTION(set_fpregs32(td, fpregs32));
}
#endif
int
proc_sstep(struct thread *td)
{
PROC_ACTION(ptrace_single_step(td));
}
int
proc_rwmem(struct proc *p, struct uio *uio)
{
vm_map_t map;
vm_offset_t pageno; /* page number */
vm_prot_t reqprot;
int error, fault_flags, page_offset, writing;
/*
* Make sure that the process' vmspace remains live.
*/
if (p != curproc)
PROC_ASSERT_HELD(p);
PROC_LOCK_ASSERT(p, MA_NOTOWNED);
/*
* The map we want...
*/
Close some races between procfs/ptrace and exit(2): - Reorder the events in exit(2) slightly so that we trigger the S_EXIT stop event earlier. After we have signalled that, we set P_WEXIT and then wait for any processes with a hold on the vmspace via PHOLD to release it. PHOLD now KASSERT()'s that P_WEXIT is clear when it is invoked, and PRELE now does a wakeup if P_WEXIT is set and p_lock drops to zero. - Change proc_rwmem() to require that the processing read from has its vmspace held via PHOLD by the caller and get rid of all the junk to screw around with the vmspace reference count as we no longer need it. - In ptrace() and pseudofs(), treat a process with P_WEXIT set as if it doesn't exist. - Only do one PHOLD in kern_ptrace() now, and do it earlier so it covers FIX_SSTEP() (since on alpha at least this can end up calling proc_rwmem() to clear an earlier single-step simualted via a breakpoint). We only do one to avoid races. Also, by making the EINVAL error for unknown requests be part of the default: case in the switch, the various switch cases can now just break out to return which removes a _lot_ of duplicated PRELE and proc unlocks, etc. Also, it fixes at least one bug where a LWP ptrace command could return EINVAL with the proc lock still held. - Changed the locking for ptrace_single_step(), ptrace_set_pc(), and ptrace_clear_single_step() to always be called with the proc lock held (it was a mixed bag previously). Alpha and arm have to drop the lock while the mess around with breakpoints, but other archs avoid extra lock release/acquires in ptrace(). I did have to fix a couple of other consumers in kern_kse and a few other places to hold the proc lock and PHOLD. Tested by: ps (1 mostly, but some bits of 2-4 as well) MFC after: 1 week
2006-02-22 18:57:50 +00:00
map = &p->p_vmspace->vm_map;
/*
* If we are writing, then we request vm_fault() to create a private
* copy of each page. Since these copies will not be writeable by the
* process, we must explicity request that they be dirtied.
*/
writing = uio->uio_rw == UIO_WRITE;
reqprot = writing ? VM_PROT_COPY | VM_PROT_READ : VM_PROT_READ;
fault_flags = writing ? VM_FAULT_DIRTY : VM_FAULT_NORMAL;
1995-05-30 08:16:23 +00:00
/*
* Only map in one page at a time. We don't have to, but it
* makes things easier. This way is trivial - right?
*/
do {
vm_offset_t uva;
u_int len;
vm_page_t m;
1995-05-30 08:16:23 +00:00
uva = (vm_offset_t)uio->uio_offset;
/*
* Get the page number of this segment.
*/
pageno = trunc_page(uva);
page_offset = uva - pageno;
/*
* How many bytes to copy
*/
len = min(PAGE_SIZE - page_offset, uio->uio_resid);
/*
* Fault and hold the page on behalf of the process.
*/
Improve MD page fault handlers. Centralize calculation of signal and ucode delivered on unhandled page fault in new function vm_fault_trap(). MD trap_pfault() now almost always uses the signal numbers and error codes calculated in consistent MI way. This introduces the protection fault compatibility sysctls to all non-x86 architectures which did not have that bug, but apparently they were already much more wrong in selecting delivered signals on protection violations. Change the delivered signal for accesses to mapped area after the backing object was truncated. According to POSIX description for mmap(2): The system shall always zero-fill any partial page at the end of an object. Further, the system shall never write out any modified portions of the last page of an object which are beyond its end. References within the address range starting at pa and continuing for len bytes to whole pages following the end of an object shall result in delivery of a SIGBUS signal. An implementation may generate SIGBUS signals when a reference would cause an error in the mapped object, such as out-of-space condition. Adjust according to the description, keeping the existing compatibility code for SIGSEGV/SIGBUS on protection failures. For situations where kernel cannot handle page fault due to resource limit enforcement, SIGBUS with a new error code BUS_OBJERR is delivered. Also, provide a new error code SEGV_PKUERR for SIGSEGV on amd64 due to protection key access violation. vm_fault_hold() is renamed to vm_fault(). Fixed some nits in trap_pfault()s like mis-interpreting Mach errors as errnos. Removed unneeded truncations of the fault addresses reported by hardware. PR: 211924 Reviewed by: alc Discussed with: jilles, markj Sponsored by: The FreeBSD Foundation MFC after: 1 week Differential revision: https://reviews.freebsd.org/D21566
2019-09-27 18:43:36 +00:00
error = vm_fault(map, pageno, reqprot, fault_flags, &m);
if (error != KERN_SUCCESS) {
if (error == KERN_RESOURCE_SHORTAGE)
error = ENOMEM;
else
error = EFAULT;
break;
}
/*
* Now do the i/o move.
*/
error = uiomove_fromphys(&m, page_offset, len, uio);
1995-05-30 08:16:23 +00:00
/* Make the I-cache coherent for breakpoints. */
if (writing && error == 0) {
vm_map_lock_read(map);
if (vm_map_check_protection(map, pageno, pageno +
PAGE_SIZE, VM_PROT_EXECUTE))
vm_sync_icache(map, uva, len);
vm_map_unlock_read(map);
}
/*
* Release the page.
*/
Change synchonization rules for vm_page reference counting. There are several mechanisms by which a vm_page reference is held, preventing the page from being freed back to the page allocator. In particular, holding the page's object lock is sufficient to prevent the page from being freed; holding the busy lock or a wiring is sufficent as well. These references are protected by the page lock, which must therefore be acquired for many per-page operations. This results in false sharing since the page locks are external to the vm_page structures themselves and each lock protects multiple structures. Transition to using an atomically updated per-page reference counter. The object's reference is counted using a flag bit in the counter. A second flag bit is used to atomically block new references via pmap_extract_and_hold() while removing managed mappings of a page. Thus, the reference count of a page is guaranteed not to increase if the page is unbusied, unmapped, and the object's write lock is held. As a consequence of this, the page lock no longer protects a page's identity; operations which move pages between objects are now synchronized solely by the objects' locks. The vm_page_wire() and vm_page_unwire() KPIs are changed. The former requires that either the object lock or the busy lock is held. The latter no longer has a return value and may free the page if it releases the last reference to that page. vm_page_unwire_noq() behaves the same as before; the caller is responsible for checking its return value and freeing or enqueuing the page as appropriate. vm_page_wire_mapped() is introduced for use in pmap_extract_and_hold(). It fails if the page is concurrently being unmapped, typically triggering a fallback to the fault handler. vm_page_wire() no longer requires the page lock and vm_page_unwire() now internally acquires the page lock when releasing the last wiring of a page (since the page lock still protects a page's queue state). In particular, synchronization details are no longer leaked into the caller. The change excises the page lock from several frequently executed code paths. In particular, vm_object_terminate() no longer bounces between page locks as it releases an object's pages, and direct I/O and sendfile(SF_NOCACHE) completions no longer require the page lock. In these latter cases we now get linear scalability in the common scenario where different threads are operating on different files. __FreeBSD_version is bumped. The DRM ports have been updated to accomodate the KPI changes. Reviewed by: jeff (earlier version) Tested by: gallatin (earlier version), pho Sponsored by: Netflix Differential Revision: https://reviews.freebsd.org/D20486
2019-09-09 21:32:42 +00:00
vm_page_unwire(m, PQ_ACTIVE);
} while (error == 0 && uio->uio_resid > 0);
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;
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;
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)
{
struct vattr vattr;
vm_map_t map;
vm_map_entry_t entry;
vm_object_t obj, tobj, lobj;
struct vmspace *vm;
struct vnode *vp;
char *freepath, *fullpath;
u_int pathlen;
int error, index;
error = 0;
obj = NULL;
vm = vmspace_acquire_ref(p);
map = &vm->vm_map;
vm_map_lock_read(map);
do {
KASSERT((map->header.eflags & MAP_ENTRY_IS_SUB_MAP) == 0,
("Submap in map header"));
index = 0;
VM_MAP_ENTRY_FOREACH(entry, map) {
if (index >= pve->pve_entry &&
(entry->eflags & MAP_ENTRY_IS_SUB_MAP) == 0)
break;
index++;
}
if (index < pve->pve_entry) {
error = EINVAL;
break;
}
if (entry == &map->header) {
error = ENOENT;
break;
}
/* We got an entry. */
pve->pve_entry = index + 1;
pve->pve_timestamp = map->timestamp;
pve->pve_start = entry->start;
pve->pve_end = entry->end - 1;
pve->pve_offset = entry->offset;
pve->pve_prot = entry->protection;
/* Backing object's path needed? */
if (pve->pve_pathlen == 0)
break;
pathlen = pve->pve_pathlen;
pve->pve_pathlen = 0;
obj = entry->object.vm_object;
if (obj != NULL)
VM_OBJECT_RLOCK(obj);
} while (0);
vm_map_unlock_read(map);
pve->pve_fsid = VNOVAL;
pve->pve_fileid = VNOVAL;
if (error == 0 && obj != NULL) {
lobj = obj;
for (tobj = obj; tobj != NULL; tobj = tobj->backing_object) {
if (tobj != obj)
VM_OBJECT_RLOCK(tobj);
if (lobj != obj)
VM_OBJECT_RUNLOCK(lobj);
lobj = tobj;
pve->pve_offset += tobj->backing_object_offset;
}
vp = vm_object_vnode(lobj);
if (vp != NULL)
vref(vp);
if (lobj != obj)
VM_OBJECT_RUNLOCK(lobj);
VM_OBJECT_RUNLOCK(obj);
if (vp != NULL) {
freepath = NULL;
fullpath = NULL;
vn_fullpath(vp, &fullpath, &freepath);
vn_lock(vp, LK_SHARED | LK_RETRY);
if (VOP_GETATTR(vp, &vattr, td->td_ucred) == 0) {
pve->pve_fileid = vattr.va_fileid;
pve->pve_fsid = vattr.va_fsid;
}
vput(vp);
if (fullpath != NULL) {
pve->pve_pathlen = strlen(fullpath) + 1;
if (pve->pve_pathlen <= pathlen) {
error = copyout(fullpath, pve->pve_path,
pve->pve_pathlen);
} else
error = ENAMETOOLONG;
}
if (freepath != NULL)
free(freepath, M_TEMP);
}
}
vmspace_free(vm);
if (error == 0)
CTR3(KTR_PTRACE, "PT_VM_ENTRY: pid %d, entry %d, start %p",
p->p_pid, pve->pve_entry, pve->pve_start);
return (error);
}
1994-05-24 10:09:53 +00:00
/*
* Process debugging system call.
*/
#ifndef _SYS_SYSPROTO_H_
1994-05-24 10:09:53 +00:00
struct ptrace_args {
int req;
pid_t pid;
caddr_t addr;
int data;
};
#endif
int
sys_ptrace(struct thread *td, struct ptrace_args *uap)
1994-05-24 10:09:53 +00:00
{
/*
* XXX this obfuscation is to reduce stack usage, but the register
* structs may be too large to put on the stack anyway.
*/
union {
struct ptrace_io_desc piod;
struct ptrace_lwpinfo pl;
struct ptrace_vm_entry pve;
struct ptrace_coredump pc;
struct ptrace_sc_remote sr;
struct dbreg dbreg;
struct fpreg fpreg;
struct reg reg;
struct iovec vec;
syscallarg_t args[nitems(td->td_sa.args)];
struct ptrace_sc_ret psr;
int ptevents;
} r;
syscallarg_t pscr_args[nitems(td->td_sa.args)];
void *addr;
int error;
if (!allow_ptrace)
return (ENOSYS);
error = 0;
AUDIT_ARG_PID(uap->pid);
AUDIT_ARG_CMD(uap->req);
AUDIT_ARG_VALUE(uap->data);
addr = &r;
switch (uap->req) {
case PT_GET_EVENT_MASK:
case PT_LWPINFO:
case PT_GET_SC_ARGS:
case PT_GET_SC_RET:
break;
case PT_GETREGS:
bzero(&r.reg, sizeof(r.reg));
break;
case PT_GETFPREGS:
bzero(&r.fpreg, sizeof(r.fpreg));
break;
case PT_GETDBREGS:
bzero(&r.dbreg, sizeof(r.dbreg));
break;
case PT_GETREGSET:
case PT_SETREGSET:
error = copyin(uap->addr, &r.vec, sizeof(r.vec));
break;
case PT_SETREGS:
error = copyin(uap->addr, &r.reg, sizeof(r.reg));
break;
case PT_SETFPREGS:
error = copyin(uap->addr, &r.fpreg, sizeof(r.fpreg));
break;
case PT_SETDBREGS:
error = copyin(uap->addr, &r.dbreg, sizeof(r.dbreg));
break;
case PT_SET_EVENT_MASK:
if (uap->data != sizeof(r.ptevents))
error = EINVAL;
else
error = copyin(uap->addr, &r.ptevents, uap->data);
break;
case PT_IO:
error = copyin(uap->addr, &r.piod, sizeof(r.piod));
break;
case PT_VM_ENTRY:
error = copyin(uap->addr, &r.pve, sizeof(r.pve));
break;
case PT_COREDUMP:
if (uap->data != sizeof(r.pc))
error = EINVAL;
else
error = copyin(uap->addr, &r.pc, uap->data);
break;
case PT_SC_REMOTE:
if (uap->data != sizeof(r.sr)) {
error = EINVAL;
break;
}
error = copyin(uap->addr, &r.sr, uap->data);
if (error != 0)
break;
if (r.sr.pscr_nargs > nitems(td->td_sa.args)) {
error = EINVAL;
break;
}
error = copyin(r.sr.pscr_args, pscr_args,
sizeof(u_long) * r.sr.pscr_nargs);
if (error != 0)
break;
r.sr.pscr_args = pscr_args;
break;
default:
addr = uap->addr;
break;
}
if (error)
return (error);
error = kern_ptrace(td, uap->req, uap->pid, addr, uap->data);
if (error)
return (error);
switch (uap->req) {
case PT_VM_ENTRY:
error = copyout(&r.pve, uap->addr, sizeof(r.pve));
break;
case PT_IO:
error = copyout(&r.piod, uap->addr, sizeof(r.piod));
break;
case PT_GETREGS:
error = copyout(&r.reg, uap->addr, sizeof(r.reg));
break;
case PT_GETFPREGS:
error = copyout(&r.fpreg, uap->addr, sizeof(r.fpreg));
break;
case PT_GETDBREGS:
error = copyout(&r.dbreg, uap->addr, sizeof(r.dbreg));
break;
case PT_GETREGSET:
error = copyout(&r.vec, uap->addr, sizeof(r.vec));
break;
case PT_GET_EVENT_MASK:
/* NB: The size in uap->data is validated in kern_ptrace(). */
error = copyout(&r.ptevents, uap->addr, uap->data);
break;
case PT_LWPINFO:
/* NB: The size in uap->data is validated in kern_ptrace(). */
error = copyout(&r.pl, uap->addr, uap->data);
break;
case PT_GET_SC_ARGS:
error = copyout(r.args, uap->addr, MIN(uap->data,
sizeof(r.args)));
break;
case PT_GET_SC_RET:
error = copyout(&r.psr, uap->addr, MIN(uap->data,
sizeof(r.psr)));
break;
case PT_SC_REMOTE:
error = copyout(&r.sr.pscr_ret, uap->addr +
offsetof(struct ptrace_sc_remote, pscr_ret),
sizeof(r.sr.pscr_ret));
break;
}
return (error);
}
#ifdef COMPAT_FREEBSD32
/*
* PROC_READ(regs, td2, addr);
* becomes either:
* proc_read_regs(td2, addr);
* or
* proc_read_regs32(td2, addr);
* .. except this is done at runtime. There is an additional
* complication in that PROC_WRITE disallows 32 bit consumers
* from writing to 64 bit address space targets.
*/
#define PROC_READ(w, t, a) wrap32 ? \
proc_read_ ## w ## 32(t, a) : \
proc_read_ ## w (t, a)
#define PROC_WRITE(w, t, a) wrap32 ? \
(safe ? proc_write_ ## w ## 32(t, a) : EINVAL ) : \
proc_write_ ## w (t, a)
#else
#define PROC_READ(w, t, a) proc_read_ ## w (t, a)
#define PROC_WRITE(w, t, a) proc_write_ ## w (t, a)
#endif
When a debugger attaches to the process, SIGSTOP is sent to the target. Due to a way issignal() selects the next signal to deliver and report, if the simultaneous or already pending another signal exists, that signal might be reported by the next waitpid(2) call. This causes minor annoyance for debuggers, which must be prepared to take any signal as the first event, then filter SIGSTOP later. More importantly, for tools like gcore(1), which attach and then detach without processing events, SIGSTOP might leak to be delivered after PT_DETACH. This results in the process being unintentionally stopped after detach, which is fatal for automatic tools. The solution is to force SIGSTOP to be the first signal reported after the attach. Attach code is modified to set P2_PTRACE_FSTP to indicate that the attaching ritual was not yet finished, and issignal() prefers SIGSTOP in that condition. Also, the thread which handles P2_PTRACE_FSTP is made to guarantee to own p_xthread during the first waitpid(2). All that ensures that SIGSTOP is consumed first. Additionally, if P2_PTRACE_FSTP is still set on detach, which means that waitpid(2) was not called at all, SIGSTOP is removed from the queue, ensuring that the process is resumed on detach. In issignal(), when acting on STOPing signals, remove the signal from queue before suspending. Otherwise parallel attach could result in ptracestop() acting on that STOP as if it was the STOP signal from the attach. Then SIGSTOP from attach leaks again. As a minor refactoring, some bits of the common attach code is moved to new helper proc_set_traced(). Reported by: markj Reviewed by: jhb, markj Tested by: pho Sponsored by: The FreeBSD Foundation MFC after: 2 weeks Differential revision: https://reviews.freebsd.org/D7256
2016-07-28 08:41:13 +00:00
void
proc_set_traced(struct proc *p, bool stop)
When a debugger attaches to the process, SIGSTOP is sent to the target. Due to a way issignal() selects the next signal to deliver and report, if the simultaneous or already pending another signal exists, that signal might be reported by the next waitpid(2) call. This causes minor annoyance for debuggers, which must be prepared to take any signal as the first event, then filter SIGSTOP later. More importantly, for tools like gcore(1), which attach and then detach without processing events, SIGSTOP might leak to be delivered after PT_DETACH. This results in the process being unintentionally stopped after detach, which is fatal for automatic tools. The solution is to force SIGSTOP to be the first signal reported after the attach. Attach code is modified to set P2_PTRACE_FSTP to indicate that the attaching ritual was not yet finished, and issignal() prefers SIGSTOP in that condition. Also, the thread which handles P2_PTRACE_FSTP is made to guarantee to own p_xthread during the first waitpid(2). All that ensures that SIGSTOP is consumed first. Additionally, if P2_PTRACE_FSTP is still set on detach, which means that waitpid(2) was not called at all, SIGSTOP is removed from the queue, ensuring that the process is resumed on detach. In issignal(), when acting on STOPing signals, remove the signal from queue before suspending. Otherwise parallel attach could result in ptracestop() acting on that STOP as if it was the STOP signal from the attach. Then SIGSTOP from attach leaks again. As a minor refactoring, some bits of the common attach code is moved to new helper proc_set_traced(). Reported by: markj Reviewed by: jhb, markj Tested by: pho Sponsored by: The FreeBSD Foundation MFC after: 2 weeks Differential revision: https://reviews.freebsd.org/D7256
2016-07-28 08:41:13 +00:00
{
sx_assert(&proctree_lock, SX_XLOCKED);
When a debugger attaches to the process, SIGSTOP is sent to the target. Due to a way issignal() selects the next signal to deliver and report, if the simultaneous or already pending another signal exists, that signal might be reported by the next waitpid(2) call. This causes minor annoyance for debuggers, which must be prepared to take any signal as the first event, then filter SIGSTOP later. More importantly, for tools like gcore(1), which attach and then detach without processing events, SIGSTOP might leak to be delivered after PT_DETACH. This results in the process being unintentionally stopped after detach, which is fatal for automatic tools. The solution is to force SIGSTOP to be the first signal reported after the attach. Attach code is modified to set P2_PTRACE_FSTP to indicate that the attaching ritual was not yet finished, and issignal() prefers SIGSTOP in that condition. Also, the thread which handles P2_PTRACE_FSTP is made to guarantee to own p_xthread during the first waitpid(2). All that ensures that SIGSTOP is consumed first. Additionally, if P2_PTRACE_FSTP is still set on detach, which means that waitpid(2) was not called at all, SIGSTOP is removed from the queue, ensuring that the process is resumed on detach. In issignal(), when acting on STOPing signals, remove the signal from queue before suspending. Otherwise parallel attach could result in ptracestop() acting on that STOP as if it was the STOP signal from the attach. Then SIGSTOP from attach leaks again. As a minor refactoring, some bits of the common attach code is moved to new helper proc_set_traced(). Reported by: markj Reviewed by: jhb, markj Tested by: pho Sponsored by: The FreeBSD Foundation MFC after: 2 weeks Differential revision: https://reviews.freebsd.org/D7256
2016-07-28 08:41:13 +00:00
PROC_LOCK_ASSERT(p, MA_OWNED);
p->p_flag |= P_TRACED;
if (stop)
p->p_flag2 |= P2_PTRACE_FSTP;
When a debugger attaches to the process, SIGSTOP is sent to the target. Due to a way issignal() selects the next signal to deliver and report, if the simultaneous or already pending another signal exists, that signal might be reported by the next waitpid(2) call. This causes minor annoyance for debuggers, which must be prepared to take any signal as the first event, then filter SIGSTOP later. More importantly, for tools like gcore(1), which attach and then detach without processing events, SIGSTOP might leak to be delivered after PT_DETACH. This results in the process being unintentionally stopped after detach, which is fatal for automatic tools. The solution is to force SIGSTOP to be the first signal reported after the attach. Attach code is modified to set P2_PTRACE_FSTP to indicate that the attaching ritual was not yet finished, and issignal() prefers SIGSTOP in that condition. Also, the thread which handles P2_PTRACE_FSTP is made to guarantee to own p_xthread during the first waitpid(2). All that ensures that SIGSTOP is consumed first. Additionally, if P2_PTRACE_FSTP is still set on detach, which means that waitpid(2) was not called at all, SIGSTOP is removed from the queue, ensuring that the process is resumed on detach. In issignal(), when acting on STOPing signals, remove the signal from queue before suspending. Otherwise parallel attach could result in ptracestop() acting on that STOP as if it was the STOP signal from the attach. Then SIGSTOP from attach leaks again. As a minor refactoring, some bits of the common attach code is moved to new helper proc_set_traced(). Reported by: markj Reviewed by: jhb, markj Tested by: pho Sponsored by: The FreeBSD Foundation MFC after: 2 weeks Differential revision: https://reviews.freebsd.org/D7256
2016-07-28 08:41:13 +00:00
p->p_ptevents = PTRACE_DEFAULT;
}
void
ptrace_unsuspend(struct proc *p)
{
PROC_LOCK_ASSERT(p, MA_OWNED);
PROC_SLOCK(p);
p->p_flag &= ~(P_STOPPED_TRACE | P_STOPPED_SIG | P_WAITED);
thread_unsuspend(p);
PROC_SUNLOCK(p);
itimer_proc_continue(p);
kqtimer_proc_continue(p);
}
static int
proc_can_ptrace(struct thread *td, struct proc *p)
{
int error;
PROC_LOCK_ASSERT(p, MA_OWNED);
if ((p->p_flag & P_WEXIT) != 0)
return (ESRCH);
if ((error = p_cansee(td, p)) != 0)
return (error);
if ((error = p_candebug(td, p)) != 0)
return (error);
/* not being traced... */
if ((p->p_flag & P_TRACED) == 0)
return (EPERM);
/* not being traced by YOU */
if (p->p_pptr != td->td_proc)
return (EBUSY);
/* not currently stopped */
if ((p->p_flag & P_STOPPED_TRACE) == 0 ||
p->p_suspcount != p->p_numthreads ||
(p->p_flag & P_WAITED) == 0)
return (EBUSY);
return (0);
}
static struct thread *
ptrace_sel_coredump_thread(struct proc *p)
{
struct thread *td2;
PROC_LOCK_ASSERT(p, MA_OWNED);
MPASS((p->p_flag & P_STOPPED_TRACE) != 0);
FOREACH_THREAD_IN_PROC(p, td2) {
if ((td2->td_dbgflags & TDB_SSWITCH) != 0)
return (td2);
}
return (NULL);
}
int
kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
{
struct iovec iov;
struct uio uio;
struct proc *curp, *p, *pp;
struct thread *td2 = NULL, *td3;
struct ptrace_io_desc *piod = NULL;
struct ptrace_lwpinfo *pl;
struct ptrace_sc_ret *psr;
struct ptrace_sc_remote *pscr;
struct file *fp;
struct ptrace_coredump *pc;
struct thr_coredump_req *tcq;
struct thr_syscall_req *tsr;
int error, num, tmp;
lwpid_t tid = 0, *buf;
#ifdef COMPAT_FREEBSD32
int wrap32 = 0, safe = 0;
#endif
bool proctree_locked, p2_req_set;
curp = td->td_proc;
proctree_locked = false;
p2_req_set = false;
/* Lock proctree before locking the process. */
switch (req) {
case PT_TRACE_ME:
case PT_ATTACH:
case PT_STEP:
case PT_CONTINUE:
case PT_TO_SCE:
case PT_TO_SCX:
case PT_SYSCALL:
case PT_FOLLOW_FORK:
case PT_LWP_EVENTS:
case PT_GET_EVENT_MASK:
case PT_SET_EVENT_MASK:
case PT_DETACH:
case PT_GET_SC_ARGS:
sx_xlock(&proctree_lock);
proctree_locked = true;
break;
default:
break;
}
2003-03-19 00:33:38 +00:00
if (req == PT_TRACE_ME) {
p = td->td_proc;
PROC_LOCK(p);
} else {
if (pid <= PID_MAX) {
if ((p = pfind(pid)) == NULL) {
if (proctree_locked)
sx_xunlock(&proctree_lock);
return (ESRCH);
}
} else {
td2 = tdfind(pid, -1);
if (td2 == NULL) {
if (proctree_locked)
sx_xunlock(&proctree_lock);
return (ESRCH);
}
p = td2->td_proc;
tid = pid;
pid = p->p_pid;
}
}
AUDIT_ARG_PROCESS(p);
Close some races between procfs/ptrace and exit(2): - Reorder the events in exit(2) slightly so that we trigger the S_EXIT stop event earlier. After we have signalled that, we set P_WEXIT and then wait for any processes with a hold on the vmspace via PHOLD to release it. PHOLD now KASSERT()'s that P_WEXIT is clear when it is invoked, and PRELE now does a wakeup if P_WEXIT is set and p_lock drops to zero. - Change proc_rwmem() to require that the processing read from has its vmspace held via PHOLD by the caller and get rid of all the junk to screw around with the vmspace reference count as we no longer need it. - In ptrace() and pseudofs(), treat a process with P_WEXIT set as if it doesn't exist. - Only do one PHOLD in kern_ptrace() now, and do it earlier so it covers FIX_SSTEP() (since on alpha at least this can end up calling proc_rwmem() to clear an earlier single-step simualted via a breakpoint). We only do one to avoid races. Also, by making the EINVAL error for unknown requests be part of the default: case in the switch, the various switch cases can now just break out to return which removes a _lot_ of duplicated PRELE and proc unlocks, etc. Also, it fixes at least one bug where a LWP ptrace command could return EINVAL with the proc lock still held. - Changed the locking for ptrace_single_step(), ptrace_set_pc(), and ptrace_clear_single_step() to always be called with the proc lock held (it was a mixed bag previously). Alpha and arm have to drop the lock while the mess around with breakpoints, but other archs avoid extra lock release/acquires in ptrace(). I did have to fix a couple of other consumers in kern_kse and a few other places to hold the proc lock and PHOLD. Tested by: ps (1 mostly, but some bits of 2-4 as well) MFC after: 1 week
2006-02-22 18:57:50 +00:00
if ((p->p_flag & P_WEXIT) != 0) {
error = ESRCH;
goto fail;
}
if ((error = p_cansee(td, p)) != 0)
goto fail;
if ((error = p_candebug(td, p)) != 0)
goto fail;
/*
* System processes can't be debugged.
*/
if ((p->p_flag & P_SYSTEM) != 0) {
error = EINVAL;
goto fail;
}
2003-03-19 00:33:38 +00:00
if (tid == 0) {
if ((p->p_flag & P_STOPPED_TRACE) != 0) {
KASSERT(p->p_xthread != NULL, ("NULL p_xthread"));
td2 = p->p_xthread;
} else {
td2 = FIRST_THREAD_IN_PROC(p);
}
tid = td2->td_tid;
}
#ifdef COMPAT_FREEBSD32
/*
* Test if we're a 32 bit client and what the target is.
* Set the wrap controls accordingly.
*/
if (SV_CURPROC_FLAG(SV_ILP32)) {
if (SV_PROC_FLAG(td2->td_proc, SV_ILP32))
safe = 1;
wrap32 = 1;
}
#endif
/*
* Permissions check
*/
switch (req) {
case PT_TRACE_ME:
/*
* Always legal, when there is a parent process which
* could trace us. Otherwise, reject.
*/
if ((p->p_flag & P_TRACED) != 0) {
error = EBUSY;
goto fail;
}
if (p->p_pptr == initproc) {
error = EPERM;
goto fail;
}
break;
case PT_ATTACH:
/* Self */
if (p == td->td_proc) {
error = EINVAL;
goto fail;
}
/* Already traced */
if (p->p_flag & P_TRACED) {
error = EBUSY;
goto fail;
}
/* Can't trace an ancestor if you're being traced. */
if (curp->p_flag & P_TRACED) {
for (pp = curp->p_pptr; pp != NULL; pp = pp->p_pptr) {
if (pp == p) {
error = EINVAL;
goto fail;
}
}
}
/* OK */
break;
case PT_CLEARSTEP:
/* Allow thread to clear single step for itself */
if (td->td_tid == tid)
break;
/* FALLTHROUGH */
default:
/*
* Check for ptrace eligibility before waiting for
* holds to drain.
*/
error = proc_can_ptrace(td, p);
if (error != 0)
goto fail;
/*
* Block parallel ptrace requests. Most important, do
* not allow other thread in debugger to continue the
* debuggee until coredump finished.
*/
while ((p->p_flag2 & P2_PTRACEREQ) != 0) {
if (proctree_locked)
sx_xunlock(&proctree_lock);
error = msleep(&p->p_flag2, &p->p_mtx, PPAUSE | PCATCH |
(proctree_locked ? PDROP : 0), "pptrace", 0);
if (proctree_locked) {
sx_xlock(&proctree_lock);
PROC_LOCK(p);
}
if (error == 0 && td2->td_proc != p)
error = ESRCH;
if (error == 0)
error = proc_can_ptrace(td, p);
if (error != 0)
goto fail;
}
/* Ok */
break;
}
/*
* Keep this process around and request parallel ptrace()
* request to wait until we finish this request.
*/
MPASS((p->p_flag2 & P2_PTRACEREQ) == 0);
p->p_flag2 |= P2_PTRACEREQ;
p2_req_set = true;
Close some races between procfs/ptrace and exit(2): - Reorder the events in exit(2) slightly so that we trigger the S_EXIT stop event earlier. After we have signalled that, we set P_WEXIT and then wait for any processes with a hold on the vmspace via PHOLD to release it. PHOLD now KASSERT()'s that P_WEXIT is clear when it is invoked, and PRELE now does a wakeup if P_WEXIT is set and p_lock drops to zero. - Change proc_rwmem() to require that the processing read from has its vmspace held via PHOLD by the caller and get rid of all the junk to screw around with the vmspace reference count as we no longer need it. - In ptrace() and pseudofs(), treat a process with P_WEXIT set as if it doesn't exist. - Only do one PHOLD in kern_ptrace() now, and do it earlier so it covers FIX_SSTEP() (since on alpha at least this can end up calling proc_rwmem() to clear an earlier single-step simualted via a breakpoint). We only do one to avoid races. Also, by making the EINVAL error for unknown requests be part of the default: case in the switch, the various switch cases can now just break out to return which removes a _lot_ of duplicated PRELE and proc unlocks, etc. Also, it fixes at least one bug where a LWP ptrace command could return EINVAL with the proc lock still held. - Changed the locking for ptrace_single_step(), ptrace_set_pc(), and ptrace_clear_single_step() to always be called with the proc lock held (it was a mixed bag previously). Alpha and arm have to drop the lock while the mess around with breakpoints, but other archs avoid extra lock release/acquires in ptrace(). I did have to fix a couple of other consumers in kern_kse and a few other places to hold the proc lock and PHOLD. Tested by: ps (1 mostly, but some bits of 2-4 as well) MFC after: 1 week
2006-02-22 18:57:50 +00:00
_PHOLD(p);
1994-05-24 10:09:53 +00:00
/*
* Actually do the requests
1994-05-24 10:09:53 +00:00
*/
td->td_retval[0] = 0;
switch (req) {
case PT_TRACE_ME:
/* set my trace flag and "owner" so it can read/write me */
proc_set_traced(p, false);
if (p->p_flag & P_PPWAIT)
p->p_flag |= P_PPTRACE;
CTR1(KTR_PTRACE, "PT_TRACE_ME: pid %d", p->p_pid);
Close some races between procfs/ptrace and exit(2): - Reorder the events in exit(2) slightly so that we trigger the S_EXIT stop event earlier. After we have signalled that, we set P_WEXIT and then wait for any processes with a hold on the vmspace via PHOLD to release it. PHOLD now KASSERT()'s that P_WEXIT is clear when it is invoked, and PRELE now does a wakeup if P_WEXIT is set and p_lock drops to zero. - Change proc_rwmem() to require that the processing read from has its vmspace held via PHOLD by the caller and get rid of all the junk to screw around with the vmspace reference count as we no longer need it. - In ptrace() and pseudofs(), treat a process with P_WEXIT set as if it doesn't exist. - Only do one PHOLD in kern_ptrace() now, and do it earlier so it covers FIX_SSTEP() (since on alpha at least this can end up calling proc_rwmem() to clear an earlier single-step simualted via a breakpoint). We only do one to avoid races. Also, by making the EINVAL error for unknown requests be part of the default: case in the switch, the various switch cases can now just break out to return which removes a _lot_ of duplicated PRELE and proc unlocks, etc. Also, it fixes at least one bug where a LWP ptrace command could return EINVAL with the proc lock still held. - Changed the locking for ptrace_single_step(), ptrace_set_pc(), and ptrace_clear_single_step() to always be called with the proc lock held (it was a mixed bag previously). Alpha and arm have to drop the lock while the mess around with breakpoints, but other archs avoid extra lock release/acquires in ptrace(). I did have to fix a couple of other consumers in kern_kse and a few other places to hold the proc lock and PHOLD. Tested by: ps (1 mostly, but some bits of 2-4 as well) MFC after: 1 week
2006-02-22 18:57:50 +00:00
break;
case PT_ATTACH:
/* security check done above */
/*
* It would be nice if the tracing relationship was separate
* from the parent relationship but that would require
* another set of links in the proc struct or for "wait"
* to scan the entire proc table. To make life easier,
* we just re-parent the process we're trying to trace.
* The old parent is remembered so we can put things back
* on a "detach".
*/
proc_set_traced(p, true);
proc_reparent(p, td->td_proc, false);
CTR2(KTR_PTRACE, "PT_ATTACH: pid %d, oppid %d", p->p_pid,
p->p_oppid);
sx_xunlock(&proctree_lock);
proctree_locked = false;
MPASS(p->p_xthread == NULL);
MPASS((p->p_flag & P_STOPPED_TRACE) == 0);
/*
* If already stopped due to a stop signal, clear the
* existing stop before triggering a traced SIGSTOP.
*/
if ((p->p_flag & P_STOPPED_SIG) != 0) {
PROC_SLOCK(p);
p->p_flag &= ~(P_STOPPED_SIG | P_WAITED);
thread_unsuspend(p);
PROC_SUNLOCK(p);
}
kern_psignal(p, SIGSTOP);
break;
case PT_CLEARSTEP:
CTR2(KTR_PTRACE, "PT_CLEARSTEP: tid %d (pid %d)", td2->td_tid,
p->p_pid);
error = ptrace_clear_single_step(td2);
Close some races between procfs/ptrace and exit(2): - Reorder the events in exit(2) slightly so that we trigger the S_EXIT stop event earlier. After we have signalled that, we set P_WEXIT and then wait for any processes with a hold on the vmspace via PHOLD to release it. PHOLD now KASSERT()'s that P_WEXIT is clear when it is invoked, and PRELE now does a wakeup if P_WEXIT is set and p_lock drops to zero. - Change proc_rwmem() to require that the processing read from has its vmspace held via PHOLD by the caller and get rid of all the junk to screw around with the vmspace reference count as we no longer need it. - In ptrace() and pseudofs(), treat a process with P_WEXIT set as if it doesn't exist. - Only do one PHOLD in kern_ptrace() now, and do it earlier so it covers FIX_SSTEP() (since on alpha at least this can end up calling proc_rwmem() to clear an earlier single-step simualted via a breakpoint). We only do one to avoid races. Also, by making the EINVAL error for unknown requests be part of the default: case in the switch, the various switch cases can now just break out to return which removes a _lot_ of duplicated PRELE and proc unlocks, etc. Also, it fixes at least one bug where a LWP ptrace command could return EINVAL with the proc lock still held. - Changed the locking for ptrace_single_step(), ptrace_set_pc(), and ptrace_clear_single_step() to always be called with the proc lock held (it was a mixed bag previously). Alpha and arm have to drop the lock while the mess around with breakpoints, but other archs avoid extra lock release/acquires in ptrace(). I did have to fix a couple of other consumers in kern_kse and a few other places to hold the proc lock and PHOLD. Tested by: ps (1 mostly, but some bits of 2-4 as well) MFC after: 1 week
2006-02-22 18:57:50 +00:00
break;
case PT_SETSTEP:
CTR2(KTR_PTRACE, "PT_SETSTEP: tid %d (pid %d)", td2->td_tid,
p->p_pid);
error = ptrace_single_step(td2);
Close some races between procfs/ptrace and exit(2): - Reorder the events in exit(2) slightly so that we trigger the S_EXIT stop event earlier. After we have signalled that, we set P_WEXIT and then wait for any processes with a hold on the vmspace via PHOLD to release it. PHOLD now KASSERT()'s that P_WEXIT is clear when it is invoked, and PRELE now does a wakeup if P_WEXIT is set and p_lock drops to zero. - Change proc_rwmem() to require that the processing read from has its vmspace held via PHOLD by the caller and get rid of all the junk to screw around with the vmspace reference count as we no longer need it. - In ptrace() and pseudofs(), treat a process with P_WEXIT set as if it doesn't exist. - Only do one PHOLD in kern_ptrace() now, and do it earlier so it covers FIX_SSTEP() (since on alpha at least this can end up calling proc_rwmem() to clear an earlier single-step simualted via a breakpoint). We only do one to avoid races. Also, by making the EINVAL error for unknown requests be part of the default: case in the switch, the various switch cases can now just break out to return which removes a _lot_ of duplicated PRELE and proc unlocks, etc. Also, it fixes at least one bug where a LWP ptrace command could return EINVAL with the proc lock still held. - Changed the locking for ptrace_single_step(), ptrace_set_pc(), and ptrace_clear_single_step() to always be called with the proc lock held (it was a mixed bag previously). Alpha and arm have to drop the lock while the mess around with breakpoints, but other archs avoid extra lock release/acquires in ptrace(). I did have to fix a couple of other consumers in kern_kse and a few other places to hold the proc lock and PHOLD. Tested by: ps (1 mostly, but some bits of 2-4 as well) MFC after: 1 week
2006-02-22 18:57:50 +00:00
break;
case PT_SUSPEND:
CTR2(KTR_PTRACE, "PT_SUSPEND: tid %d (pid %d)", td2->td_tid,
p->p_pid);
td2->td_dbgflags |= TDB_SUSPEND;
ast_sched(td2, TDA_SUSPEND);
Close some races between procfs/ptrace and exit(2): - Reorder the events in exit(2) slightly so that we trigger the S_EXIT stop event earlier. After we have signalled that, we set P_WEXIT and then wait for any processes with a hold on the vmspace via PHOLD to release it. PHOLD now KASSERT()'s that P_WEXIT is clear when it is invoked, and PRELE now does a wakeup if P_WEXIT is set and p_lock drops to zero. - Change proc_rwmem() to require that the processing read from has its vmspace held via PHOLD by the caller and get rid of all the junk to screw around with the vmspace reference count as we no longer need it. - In ptrace() and pseudofs(), treat a process with P_WEXIT set as if it doesn't exist. - Only do one PHOLD in kern_ptrace() now, and do it earlier so it covers FIX_SSTEP() (since on alpha at least this can end up calling proc_rwmem() to clear an earlier single-step simualted via a breakpoint). We only do one to avoid races. Also, by making the EINVAL error for unknown requests be part of the default: case in the switch, the various switch cases can now just break out to return which removes a _lot_ of duplicated PRELE and proc unlocks, etc. Also, it fixes at least one bug where a LWP ptrace command could return EINVAL with the proc lock still held. - Changed the locking for ptrace_single_step(), ptrace_set_pc(), and ptrace_clear_single_step() to always be called with the proc lock held (it was a mixed bag previously). Alpha and arm have to drop the lock while the mess around with breakpoints, but other archs avoid extra lock release/acquires in ptrace(). I did have to fix a couple of other consumers in kern_kse and a few other places to hold the proc lock and PHOLD. Tested by: ps (1 mostly, but some bits of 2-4 as well) MFC after: 1 week
2006-02-22 18:57:50 +00:00
break;
case PT_RESUME:
CTR2(KTR_PTRACE, "PT_RESUME: tid %d (pid %d)", td2->td_tid,
p->p_pid);
td2->td_dbgflags &= ~TDB_SUSPEND;
Close some races between procfs/ptrace and exit(2): - Reorder the events in exit(2) slightly so that we trigger the S_EXIT stop event earlier. After we have signalled that, we set P_WEXIT and then wait for any processes with a hold on the vmspace via PHOLD to release it. PHOLD now KASSERT()'s that P_WEXIT is clear when it is invoked, and PRELE now does a wakeup if P_WEXIT is set and p_lock drops to zero. - Change proc_rwmem() to require that the processing read from has its vmspace held via PHOLD by the caller and get rid of all the junk to screw around with the vmspace reference count as we no longer need it. - In ptrace() and pseudofs(), treat a process with P_WEXIT set as if it doesn't exist. - Only do one PHOLD in kern_ptrace() now, and do it earlier so it covers FIX_SSTEP() (since on alpha at least this can end up calling proc_rwmem() to clear an earlier single-step simualted via a breakpoint). We only do one to avoid races. Also, by making the EINVAL error for unknown requests be part of the default: case in the switch, the various switch cases can now just break out to return which removes a _lot_ of duplicated PRELE and proc unlocks, etc. Also, it fixes at least one bug where a LWP ptrace command could return EINVAL with the proc lock still held. - Changed the locking for ptrace_single_step(), ptrace_set_pc(), and ptrace_clear_single_step() to always be called with the proc lock held (it was a mixed bag previously). Alpha and arm have to drop the lock while the mess around with breakpoints, but other archs avoid extra lock release/acquires in ptrace(). I did have to fix a couple of other consumers in kern_kse and a few other places to hold the proc lock and PHOLD. Tested by: ps (1 mostly, but some bits of 2-4 as well) MFC after: 1 week
2006-02-22 18:57:50 +00:00
break;
case PT_FOLLOW_FORK:
CTR3(KTR_PTRACE, "PT_FOLLOW_FORK: pid %d %s -> %s", p->p_pid,
p->p_ptevents & PTRACE_FORK ? "enabled" : "disabled",
data ? "enabled" : "disabled");
if (data)
p->p_ptevents |= PTRACE_FORK;
else
p->p_ptevents &= ~PTRACE_FORK;
break;
case PT_LWP_EVENTS:
CTR3(KTR_PTRACE, "PT_LWP_EVENTS: pid %d %s -> %s", p->p_pid,
p->p_ptevents & PTRACE_LWP ? "enabled" : "disabled",
data ? "enabled" : "disabled");
if (data)
p->p_ptevents |= PTRACE_LWP;
else
p->p_ptevents &= ~PTRACE_LWP;
break;
case PT_GET_EVENT_MASK:
if (data != sizeof(p->p_ptevents)) {
error = EINVAL;
break;
}
CTR2(KTR_PTRACE, "PT_GET_EVENT_MASK: pid %d mask %#x", p->p_pid,
p->p_ptevents);
*(int *)addr = p->p_ptevents;
break;
case PT_SET_EVENT_MASK:
if (data != sizeof(p->p_ptevents)) {
error = EINVAL;
break;
}
tmp = *(int *)addr;
if ((tmp & ~(PTRACE_EXEC | PTRACE_SCE | PTRACE_SCX |
PTRACE_FORK | PTRACE_LWP | PTRACE_VFORK)) != 0) {
error = EINVAL;
break;
}
CTR3(KTR_PTRACE, "PT_SET_EVENT_MASK: pid %d mask %#x -> %#x",
p->p_pid, p->p_ptevents, tmp);
p->p_ptevents = tmp;
break;
case PT_GET_SC_ARGS:
CTR1(KTR_PTRACE, "PT_GET_SC_ARGS: pid %d", p->p_pid);
if ((td2->td_dbgflags & (TDB_SCE | TDB_SCX)) == 0
#ifdef COMPAT_FREEBSD32
|| (wrap32 && !safe)
#endif
) {
error = EINVAL;
break;
}
bzero(addr, sizeof(td2->td_sa.args));
/* See the explanation in linux_ptrace_get_syscall_info(). */
bcopy(td2->td_sa.args, addr, SV_PROC_ABI(td->td_proc) ==
SV_ABI_LINUX ? sizeof(td2->td_sa.args) :
td2->td_sa.callp->sy_narg * sizeof(syscallarg_t));
break;
case PT_GET_SC_RET:
if ((td2->td_dbgflags & (TDB_SCX)) == 0
#ifdef COMPAT_FREEBSD32
|| (wrap32 && !safe)
#endif
) {
error = EINVAL;
break;
}
psr = addr;
bzero(psr, sizeof(*psr));
psr->sr_error = td2->td_errno;
if (psr->sr_error == 0) {
psr->sr_retval[0] = td2->td_retval[0];
psr->sr_retval[1] = td2->td_retval[1];
}
CTR4(KTR_PTRACE,
"PT_GET_SC_RET: pid %d error %d retval %#lx,%#lx",
p->p_pid, psr->sr_error, psr->sr_retval[0],
psr->sr_retval[1]);
break;
case PT_STEP:
case PT_CONTINUE:
case PT_TO_SCE:
case PT_TO_SCX:
case PT_SYSCALL:
case PT_DETACH:
/* Zero means do not send any signal */
if (data < 0 || data > _SIG_MAXSIG) {
error = EINVAL;
Close some races between procfs/ptrace and exit(2): - Reorder the events in exit(2) slightly so that we trigger the S_EXIT stop event earlier. After we have signalled that, we set P_WEXIT and then wait for any processes with a hold on the vmspace via PHOLD to release it. PHOLD now KASSERT()'s that P_WEXIT is clear when it is invoked, and PRELE now does a wakeup if P_WEXIT is set and p_lock drops to zero. - Change proc_rwmem() to require that the processing read from has its vmspace held via PHOLD by the caller and get rid of all the junk to screw around with the vmspace reference count as we no longer need it. - In ptrace() and pseudofs(), treat a process with P_WEXIT set as if it doesn't exist. - Only do one PHOLD in kern_ptrace() now, and do it earlier so it covers FIX_SSTEP() (since on alpha at least this can end up calling proc_rwmem() to clear an earlier single-step simualted via a breakpoint). We only do one to avoid races. Also, by making the EINVAL error for unknown requests be part of the default: case in the switch, the various switch cases can now just break out to return which removes a _lot_ of duplicated PRELE and proc unlocks, etc. Also, it fixes at least one bug where a LWP ptrace command could return EINVAL with the proc lock still held. - Changed the locking for ptrace_single_step(), ptrace_set_pc(), and ptrace_clear_single_step() to always be called with the proc lock held (it was a mixed bag previously). Alpha and arm have to drop the lock while the mess around with breakpoints, but other archs avoid extra lock release/acquires in ptrace(). I did have to fix a couple of other consumers in kern_kse and a few other places to hold the proc lock and PHOLD. Tested by: ps (1 mostly, but some bits of 2-4 as well) MFC after: 1 week
2006-02-22 18:57:50 +00:00
break;
}
switch (req) {
case PT_STEP:
CTR3(KTR_PTRACE, "PT_STEP: tid %d (pid %d), sig = %d",
td2->td_tid, p->p_pid, data);
error = ptrace_single_step(td2);
Close some races between procfs/ptrace and exit(2): - Reorder the events in exit(2) slightly so that we trigger the S_EXIT stop event earlier. After we have signalled that, we set P_WEXIT and then wait for any processes with a hold on the vmspace via PHOLD to release it. PHOLD now KASSERT()'s that P_WEXIT is clear when it is invoked, and PRELE now does a wakeup if P_WEXIT is set and p_lock drops to zero. - Change proc_rwmem() to require that the processing read from has its vmspace held via PHOLD by the caller and get rid of all the junk to screw around with the vmspace reference count as we no longer need it. - In ptrace() and pseudofs(), treat a process with P_WEXIT set as if it doesn't exist. - Only do one PHOLD in kern_ptrace() now, and do it earlier so it covers FIX_SSTEP() (since on alpha at least this can end up calling proc_rwmem() to clear an earlier single-step simualted via a breakpoint). We only do one to avoid races. Also, by making the EINVAL error for unknown requests be part of the default: case in the switch, the various switch cases can now just break out to return which removes a _lot_ of duplicated PRELE and proc unlocks, etc. Also, it fixes at least one bug where a LWP ptrace command could return EINVAL with the proc lock still held. - Changed the locking for ptrace_single_step(), ptrace_set_pc(), and ptrace_clear_single_step() to always be called with the proc lock held (it was a mixed bag previously). Alpha and arm have to drop the lock while the mess around with breakpoints, but other archs avoid extra lock release/acquires in ptrace(). I did have to fix a couple of other consumers in kern_kse and a few other places to hold the proc lock and PHOLD. Tested by: ps (1 mostly, but some bits of 2-4 as well) MFC after: 1 week
2006-02-22 18:57:50 +00:00
if (error)
goto out;
break;
case PT_CONTINUE:
case PT_TO_SCE:
case PT_TO_SCX:
case PT_SYSCALL:
if (addr != (void *)1) {
error = ptrace_set_pc(td2,
(u_long)(uintfptr_t)addr);
if (error)
goto out;
}
switch (req) {
case PT_TO_SCE:
p->p_ptevents |= PTRACE_SCE;
CTR4(KTR_PTRACE,
"PT_TO_SCE: pid %d, events = %#x, PC = %#lx, sig = %d",
p->p_pid, p->p_ptevents,
(u_long)(uintfptr_t)addr, data);
Close some races between procfs/ptrace and exit(2): - Reorder the events in exit(2) slightly so that we trigger the S_EXIT stop event earlier. After we have signalled that, we set P_WEXIT and then wait for any processes with a hold on the vmspace via PHOLD to release it. PHOLD now KASSERT()'s that P_WEXIT is clear when it is invoked, and PRELE now does a wakeup if P_WEXIT is set and p_lock drops to zero. - Change proc_rwmem() to require that the processing read from has its vmspace held via PHOLD by the caller and get rid of all the junk to screw around with the vmspace reference count as we no longer need it. - In ptrace() and pseudofs(), treat a process with P_WEXIT set as if it doesn't exist. - Only do one PHOLD in kern_ptrace() now, and do it earlier so it covers FIX_SSTEP() (since on alpha at least this can end up calling proc_rwmem() to clear an earlier single-step simualted via a breakpoint). We only do one to avoid races. Also, by making the EINVAL error for unknown requests be part of the default: case in the switch, the various switch cases can now just break out to return which removes a _lot_ of duplicated PRELE and proc unlocks, etc. Also, it fixes at least one bug where a LWP ptrace command could return EINVAL with the proc lock still held. - Changed the locking for ptrace_single_step(), ptrace_set_pc(), and ptrace_clear_single_step() to always be called with the proc lock held (it was a mixed bag previously). Alpha and arm have to drop the lock while the mess around with breakpoints, but other archs avoid extra lock release/acquires in ptrace(). I did have to fix a couple of other consumers in kern_kse and a few other places to hold the proc lock and PHOLD. Tested by: ps (1 mostly, but some bits of 2-4 as well) MFC after: 1 week
2006-02-22 18:57:50 +00:00
break;
case PT_TO_SCX:
p->p_ptevents |= PTRACE_SCX;
CTR4(KTR_PTRACE,
"PT_TO_SCX: pid %d, events = %#x, PC = %#lx, sig = %d",
p->p_pid, p->p_ptevents,
(u_long)(uintfptr_t)addr, data);
break;
case PT_SYSCALL:
p->p_ptevents |= PTRACE_SYSCALL;
CTR4(KTR_PTRACE,
"PT_SYSCALL: pid %d, events = %#x, PC = %#lx, sig = %d",
p->p_pid, p->p_ptevents,
(u_long)(uintfptr_t)addr, data);
break;
case PT_CONTINUE:
CTR3(KTR_PTRACE,
"PT_CONTINUE: pid %d, PC = %#lx, sig = %d",
p->p_pid, (u_long)(uintfptr_t)addr, data);
break;
}
break;
case PT_DETACH:
/*
* Clear P_TRACED before reparenting
* a detached process back to its original
* parent. Otherwise the debugee will be set
* as an orphan of the debugger.
*/
p->p_flag &= ~(P_TRACED | P_WAITED);
/*
* Reset the process parent.
*/
if (p->p_oppid != p->p_pptr->p_pid) {
PROC_LOCK(p->p_pptr);
sigqueue_take(p->p_ksi);
PROC_UNLOCK(p->p_pptr);
pp = proc_realparent(p);
proc_reparent(p, pp, false);
if (pp == initproc)
p->p_sigparent = SIGCHLD;
CTR3(KTR_PTRACE,
"PT_DETACH: pid %d reparented to pid %d, sig %d",
p->p_pid, pp->p_pid, data);
} else {
CTR2(KTR_PTRACE, "PT_DETACH: pid %d, sig %d",
p->p_pid, data);
}
p->p_ptevents = 0;
When a debugger attaches to the process, SIGSTOP is sent to the target. Due to a way issignal() selects the next signal to deliver and report, if the simultaneous or already pending another signal exists, that signal might be reported by the next waitpid(2) call. This causes minor annoyance for debuggers, which must be prepared to take any signal as the first event, then filter SIGSTOP later. More importantly, for tools like gcore(1), which attach and then detach without processing events, SIGSTOP might leak to be delivered after PT_DETACH. This results in the process being unintentionally stopped after detach, which is fatal for automatic tools. The solution is to force SIGSTOP to be the first signal reported after the attach. Attach code is modified to set P2_PTRACE_FSTP to indicate that the attaching ritual was not yet finished, and issignal() prefers SIGSTOP in that condition. Also, the thread which handles P2_PTRACE_FSTP is made to guarantee to own p_xthread during the first waitpid(2). All that ensures that SIGSTOP is consumed first. Additionally, if P2_PTRACE_FSTP is still set on detach, which means that waitpid(2) was not called at all, SIGSTOP is removed from the queue, ensuring that the process is resumed on detach. In issignal(), when acting on STOPing signals, remove the signal from queue before suspending. Otherwise parallel attach could result in ptracestop() acting on that STOP as if it was the STOP signal from the attach. Then SIGSTOP from attach leaks again. As a minor refactoring, some bits of the common attach code is moved to new helper proc_set_traced(). Reported by: markj Reviewed by: jhb, markj Tested by: pho Sponsored by: The FreeBSD Foundation MFC after: 2 weeks Differential revision: https://reviews.freebsd.org/D7256
2016-07-28 08:41:13 +00:00
FOREACH_THREAD_IN_PROC(p, td3) {
if ((td3->td_dbgflags & TDB_FSTP) != 0) {
sigqueue_delete(&td3->td_sigqueue,
SIGSTOP);
}
td3->td_dbgflags &= ~(TDB_XSIG | TDB_FSTP |
TDB_SUSPEND | TDB_BORN);
When a debugger attaches to the process, SIGSTOP is sent to the target. Due to a way issignal() selects the next signal to deliver and report, if the simultaneous or already pending another signal exists, that signal might be reported by the next waitpid(2) call. This causes minor annoyance for debuggers, which must be prepared to take any signal as the first event, then filter SIGSTOP later. More importantly, for tools like gcore(1), which attach and then detach without processing events, SIGSTOP might leak to be delivered after PT_DETACH. This results in the process being unintentionally stopped after detach, which is fatal for automatic tools. The solution is to force SIGSTOP to be the first signal reported after the attach. Attach code is modified to set P2_PTRACE_FSTP to indicate that the attaching ritual was not yet finished, and issignal() prefers SIGSTOP in that condition. Also, the thread which handles P2_PTRACE_FSTP is made to guarantee to own p_xthread during the first waitpid(2). All that ensures that SIGSTOP is consumed first. Additionally, if P2_PTRACE_FSTP is still set on detach, which means that waitpid(2) was not called at all, SIGSTOP is removed from the queue, ensuring that the process is resumed on detach. In issignal(), when acting on STOPing signals, remove the signal from queue before suspending. Otherwise parallel attach could result in ptracestop() acting on that STOP as if it was the STOP signal from the attach. Then SIGSTOP from attach leaks again. As a minor refactoring, some bits of the common attach code is moved to new helper proc_set_traced(). Reported by: markj Reviewed by: jhb, markj Tested by: pho Sponsored by: The FreeBSD Foundation MFC after: 2 weeks Differential revision: https://reviews.freebsd.org/D7256
2016-07-28 08:41:13 +00:00
}
When a debugger attaches to the process, SIGSTOP is sent to the target. Due to a way issignal() selects the next signal to deliver and report, if the simultaneous or already pending another signal exists, that signal might be reported by the next waitpid(2) call. This causes minor annoyance for debuggers, which must be prepared to take any signal as the first event, then filter SIGSTOP later. More importantly, for tools like gcore(1), which attach and then detach without processing events, SIGSTOP might leak to be delivered after PT_DETACH. This results in the process being unintentionally stopped after detach, which is fatal for automatic tools. The solution is to force SIGSTOP to be the first signal reported after the attach. Attach code is modified to set P2_PTRACE_FSTP to indicate that the attaching ritual was not yet finished, and issignal() prefers SIGSTOP in that condition. Also, the thread which handles P2_PTRACE_FSTP is made to guarantee to own p_xthread during the first waitpid(2). All that ensures that SIGSTOP is consumed first. Additionally, if P2_PTRACE_FSTP is still set on detach, which means that waitpid(2) was not called at all, SIGSTOP is removed from the queue, ensuring that the process is resumed on detach. In issignal(), when acting on STOPing signals, remove the signal from queue before suspending. Otherwise parallel attach could result in ptracestop() acting on that STOP as if it was the STOP signal from the attach. Then SIGSTOP from attach leaks again. As a minor refactoring, some bits of the common attach code is moved to new helper proc_set_traced(). Reported by: markj Reviewed by: jhb, markj Tested by: pho Sponsored by: The FreeBSD Foundation MFC after: 2 weeks Differential revision: https://reviews.freebsd.org/D7256
2016-07-28 08:41:13 +00:00
if ((p->p_flag2 & P2_PTRACE_FSTP) != 0) {
sigqueue_delete(&p->p_sigqueue, SIGSTOP);
p->p_flag2 &= ~P2_PTRACE_FSTP;
}
/* should we send SIGCHLD? */
/* childproc_continued(p); */
break;
}
sx_xunlock(&proctree_lock);
proctree_locked = false;
sendsig:
MPASS(!proctree_locked);
/*
Discard the correct thread event reported for a ptrace stop. When multiple threads wish to report a tracing event to a debugger, both threads call ptracestop() and one thread will win the race to be the reporting thread (p->p_xthread). The debugger uses PT_LWPINFO with the process ID to determine which thread / LWP is reporting an event and the details of that event. This event is cleared as a side effect of the subsequent ptrace event that resumed the process (PT_CONTINUE, PT_STEP, etc.). However, ptrace() was clearing the event identified by the LWP ID passed to the resume request even if that wasn't the 'p_xthread'. This could result in clearing an event that had not yet been observed by the debugger and leaving the existing event for 'p_thread' pending so that it was reported a second time. Specifically, if the debugger stopped due to a software breakpoint in one thread, but then switched to another thread that was used to resume (e.g. if the user switched to a different thread and issued a step), the resume request (PT_STEP) cleared a pending event (if any) for the thread being stepped. However, the process immediately stopped and the first thread reported it's breakpoint event a second time. The debugger decremented the PC for "both" breakpoint events which resulted in the PC now pointing into the middle of an instruction (on x86) and a SIGILL fault when the process was resumed a second time. To fix, always clear the pending event for 'p_xthread' when resuming a process. ptrace() still honors the requested LWP ID when enabling single-stepping (PT_STEP) or setting a different PC (PT_CONTINUE). Reported by: GDB testsuite (gdb.threads/continue-pending-status.exp) Reviewed by: kib MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D12794
2017-10-27 03:16:19 +00:00
* Clear the pending event for the thread that just
* reported its event (p_xthread). This may not be
* the thread passed to PT_CONTINUE, PT_STEP, etc. if
* the debugger is resuming a different thread.
*
* Deliver any pending signal via the reporting thread.
Discard the correct thread event reported for a ptrace stop. When multiple threads wish to report a tracing event to a debugger, both threads call ptracestop() and one thread will win the race to be the reporting thread (p->p_xthread). The debugger uses PT_LWPINFO with the process ID to determine which thread / LWP is reporting an event and the details of that event. This event is cleared as a side effect of the subsequent ptrace event that resumed the process (PT_CONTINUE, PT_STEP, etc.). However, ptrace() was clearing the event identified by the LWP ID passed to the resume request even if that wasn't the 'p_xthread'. This could result in clearing an event that had not yet been observed by the debugger and leaving the existing event for 'p_thread' pending so that it was reported a second time. Specifically, if the debugger stopped due to a software breakpoint in one thread, but then switched to another thread that was used to resume (e.g. if the user switched to a different thread and issued a step), the resume request (PT_STEP) cleared a pending event (if any) for the thread being stepped. However, the process immediately stopped and the first thread reported it's breakpoint event a second time. The debugger decremented the PC for "both" breakpoint events which resulted in the PC now pointing into the middle of an instruction (on x86) and a SIGILL fault when the process was resumed a second time. To fix, always clear the pending event for 'p_xthread' when resuming a process. ptrace() still honors the requested LWP ID when enabling single-stepping (PT_STEP) or setting a different PC (PT_CONTINUE). Reported by: GDB testsuite (gdb.threads/continue-pending-status.exp) Reviewed by: kib MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D12794
2017-10-27 03:16:19 +00:00
*/
MPASS(p->p_xthread != NULL);
p->p_xthread->td_dbgflags &= ~TDB_XSIG;
p->p_xthread->td_xsig = data;
p->p_xthread = NULL;
p->p_xsig = data;
/*
* P_WKILLED is insurance that a PT_KILL/SIGKILL
* always works immediately, even if another thread is
* unsuspended first and attempts to handle a
* different signal or if the POSIX.1b style signal
* queue cannot accommodate any new signals.
*/
if (data == SIGKILL)
proc_wkilled(p);
/*
* Unsuspend all threads. To leave a thread
* suspended, use PT_SUSPEND to suspend it before
* continuing the process.
*/
ptrace_unsuspend(p);
Close some races between procfs/ptrace and exit(2): - Reorder the events in exit(2) slightly so that we trigger the S_EXIT stop event earlier. After we have signalled that, we set P_WEXIT and then wait for any processes with a hold on the vmspace via PHOLD to release it. PHOLD now KASSERT()'s that P_WEXIT is clear when it is invoked, and PRELE now does a wakeup if P_WEXIT is set and p_lock drops to zero. - Change proc_rwmem() to require that the processing read from has its vmspace held via PHOLD by the caller and get rid of all the junk to screw around with the vmspace reference count as we no longer need it. - In ptrace() and pseudofs(), treat a process with P_WEXIT set as if it doesn't exist. - Only do one PHOLD in kern_ptrace() now, and do it earlier so it covers FIX_SSTEP() (since on alpha at least this can end up calling proc_rwmem() to clear an earlier single-step simualted via a breakpoint). We only do one to avoid races. Also, by making the EINVAL error for unknown requests be part of the default: case in the switch, the various switch cases can now just break out to return which removes a _lot_ of duplicated PRELE and proc unlocks, etc. Also, it fixes at least one bug where a LWP ptrace command could return EINVAL with the proc lock still held. - Changed the locking for ptrace_single_step(), ptrace_set_pc(), and ptrace_clear_single_step() to always be called with the proc lock held (it was a mixed bag previously). Alpha and arm have to drop the lock while the mess around with breakpoints, but other archs avoid extra lock release/acquires in ptrace(). I did have to fix a couple of other consumers in kern_kse and a few other places to hold the proc lock and PHOLD. Tested by: ps (1 mostly, but some bits of 2-4 as well) MFC after: 1 week
2006-02-22 18:57:50 +00:00
break;
case PT_WRITE_I:
case PT_WRITE_D:
td2->td_dbgflags |= TDB_USERWR;
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);
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;
Close some races between procfs/ptrace and exit(2): - Reorder the events in exit(2) slightly so that we trigger the S_EXIT stop event earlier. After we have signalled that, we set P_WEXIT and then wait for any processes with a hold on the vmspace via PHOLD to release it. PHOLD now KASSERT()'s that P_WEXIT is clear when it is invoked, and PRELE now does a wakeup if P_WEXIT is set and p_lock drops to zero. - Change proc_rwmem() to require that the processing read from has its vmspace held via PHOLD by the caller and get rid of all the junk to screw around with the vmspace reference count as we no longer need it. - In ptrace() and pseudofs(), treat a process with P_WEXIT set as if it doesn't exist. - Only do one PHOLD in kern_ptrace() now, and do it earlier so it covers FIX_SSTEP() (since on alpha at least this can end up calling proc_rwmem() to clear an earlier single-step simualted via a breakpoint). We only do one to avoid races. Also, by making the EINVAL error for unknown requests be part of the default: case in the switch, the various switch cases can now just break out to return which removes a _lot_ of duplicated PRELE and proc unlocks, etc. Also, it fixes at least one bug where a LWP ptrace command could return EINVAL with the proc lock still held. - Changed the locking for ptrace_single_step(), ptrace_set_pc(), and ptrace_clear_single_step() to always be called with the proc lock held (it was a mixed bag previously). Alpha and arm have to drop the lock while the mess around with breakpoints, but other archs avoid extra lock release/acquires in ptrace(). I did have to fix a couple of other consumers in kern_kse and a few other places to hold the proc lock and PHOLD. Tested by: ps (1 mostly, but some bits of 2-4 as well) MFC after: 1 week
2006-02-22 18:57:50 +00:00
PROC_LOCK(p);
break;
case PT_IO:
piod = addr;
iov.iov_base = piod->piod_addr;
iov.iov_len = piod->piod_len;
uio.uio_offset = (off_t)(uintptr_t)piod->piod_offs;
uio.uio_resid = piod->piod_len;
uio.uio_iov = &iov;
uio.uio_iovcnt = 1;
uio.uio_segflg = UIO_USERSPACE;
uio.uio_td = td;
switch (piod->piod_op) {
case PIOD_READ_D:
case PIOD_READ_I:
CTR3(KTR_PTRACE, "PT_IO: pid %d: READ (%p, %#x)",
p->p_pid, (uintptr_t)uio.uio_offset, uio.uio_resid);
uio.uio_rw = UIO_READ;
break;
case PIOD_WRITE_D:
case PIOD_WRITE_I:
CTR3(KTR_PTRACE, "PT_IO: pid %d: WRITE (%p, %#x)",
p->p_pid, (uintptr_t)uio.uio_offset, uio.uio_resid);
td2->td_dbgflags |= TDB_USERWR;
uio.uio_rw = UIO_WRITE;
break;
default:
Close some races between procfs/ptrace and exit(2): - Reorder the events in exit(2) slightly so that we trigger the S_EXIT stop event earlier. After we have signalled that, we set P_WEXIT and then wait for any processes with a hold on the vmspace via PHOLD to release it. PHOLD now KASSERT()'s that P_WEXIT is clear when it is invoked, and PRELE now does a wakeup if P_WEXIT is set and p_lock drops to zero. - Change proc_rwmem() to require that the processing read from has its vmspace held via PHOLD by the caller and get rid of all the junk to screw around with the vmspace reference count as we no longer need it. - In ptrace() and pseudofs(), treat a process with P_WEXIT set as if it doesn't exist. - Only do one PHOLD in kern_ptrace() now, and do it earlier so it covers FIX_SSTEP() (since on alpha at least this can end up calling proc_rwmem() to clear an earlier single-step simualted via a breakpoint). We only do one to avoid races. Also, by making the EINVAL error for unknown requests be part of the default: case in the switch, the various switch cases can now just break out to return which removes a _lot_ of duplicated PRELE and proc unlocks, etc. Also, it fixes at least one bug where a LWP ptrace command could return EINVAL with the proc lock still held. - Changed the locking for ptrace_single_step(), ptrace_set_pc(), and ptrace_clear_single_step() to always be called with the proc lock held (it was a mixed bag previously). Alpha and arm have to drop the lock while the mess around with breakpoints, but other archs avoid extra lock release/acquires in ptrace(). I did have to fix a couple of other consumers in kern_kse and a few other places to hold the proc lock and PHOLD. Tested by: ps (1 mostly, but some bits of 2-4 as well) MFC after: 1 week
2006-02-22 18:57:50 +00:00
error = EINVAL;
goto out;
}
Close some races between procfs/ptrace and exit(2): - Reorder the events in exit(2) slightly so that we trigger the S_EXIT stop event earlier. After we have signalled that, we set P_WEXIT and then wait for any processes with a hold on the vmspace via PHOLD to release it. PHOLD now KASSERT()'s that P_WEXIT is clear when it is invoked, and PRELE now does a wakeup if P_WEXIT is set and p_lock drops to zero. - Change proc_rwmem() to require that the processing read from has its vmspace held via PHOLD by the caller and get rid of all the junk to screw around with the vmspace reference count as we no longer need it. - In ptrace() and pseudofs(), treat a process with P_WEXIT set as if it doesn't exist. - Only do one PHOLD in kern_ptrace() now, and do it earlier so it covers FIX_SSTEP() (since on alpha at least this can end up calling proc_rwmem() to clear an earlier single-step simualted via a breakpoint). We only do one to avoid races. Also, by making the EINVAL error for unknown requests be part of the default: case in the switch, the various switch cases can now just break out to return which removes a _lot_ of duplicated PRELE and proc unlocks, etc. Also, it fixes at least one bug where a LWP ptrace command could return EINVAL with the proc lock still held. - Changed the locking for ptrace_single_step(), ptrace_set_pc(), and ptrace_clear_single_step() to always be called with the proc lock held (it was a mixed bag previously). Alpha and arm have to drop the lock while the mess around with breakpoints, but other archs avoid extra lock release/acquires in ptrace(). I did have to fix a couple of other consumers in kern_kse and a few other places to hold the proc lock and PHOLD. Tested by: ps (1 mostly, but some bits of 2-4 as well) MFC after: 1 week
2006-02-22 18:57:50 +00:00
PROC_UNLOCK(p);
error = proc_rwmem(p, &uio);
piod->piod_len -= uio.uio_resid;
Close some races between procfs/ptrace and exit(2): - Reorder the events in exit(2) slightly so that we trigger the S_EXIT stop event earlier. After we have signalled that, we set P_WEXIT and then wait for any processes with a hold on the vmspace via PHOLD to release it. PHOLD now KASSERT()'s that P_WEXIT is clear when it is invoked, and PRELE now does a wakeup if P_WEXIT is set and p_lock drops to zero. - Change proc_rwmem() to require that the processing read from has its vmspace held via PHOLD by the caller and get rid of all the junk to screw around with the vmspace reference count as we no longer need it. - In ptrace() and pseudofs(), treat a process with P_WEXIT set as if it doesn't exist. - Only do one PHOLD in kern_ptrace() now, and do it earlier so it covers FIX_SSTEP() (since on alpha at least this can end up calling proc_rwmem() to clear an earlier single-step simualted via a breakpoint). We only do one to avoid races. Also, by making the EINVAL error for unknown requests be part of the default: case in the switch, the various switch cases can now just break out to return which removes a _lot_ of duplicated PRELE and proc unlocks, etc. Also, it fixes at least one bug where a LWP ptrace command could return EINVAL with the proc lock still held. - Changed the locking for ptrace_single_step(), ptrace_set_pc(), and ptrace_clear_single_step() to always be called with the proc lock held (it was a mixed bag previously). Alpha and arm have to drop the lock while the mess around with breakpoints, but other archs avoid extra lock release/acquires in ptrace(). I did have to fix a couple of other consumers in kern_kse and a few other places to hold the proc lock and PHOLD. Tested by: ps (1 mostly, but some bits of 2-4 as well) MFC after: 1 week
2006-02-22 18:57:50 +00:00
PROC_LOCK(p);
break;
case PT_KILL:
CTR1(KTR_PTRACE, "PT_KILL: pid %d", p->p_pid);
data = SIGKILL;
goto sendsig; /* in PT_CONTINUE above */
case PT_SETREGS:
CTR2(KTR_PTRACE, "PT_SETREGS: tid %d (pid %d)", td2->td_tid,
p->p_pid);
td2->td_dbgflags |= TDB_USERWR;
error = PROC_WRITE(regs, td2, addr);
Close some races between procfs/ptrace and exit(2): - Reorder the events in exit(2) slightly so that we trigger the S_EXIT stop event earlier. After we have signalled that, we set P_WEXIT and then wait for any processes with a hold on the vmspace via PHOLD to release it. PHOLD now KASSERT()'s that P_WEXIT is clear when it is invoked, and PRELE now does a wakeup if P_WEXIT is set and p_lock drops to zero. - Change proc_rwmem() to require that the processing read from has its vmspace held via PHOLD by the caller and get rid of all the junk to screw around with the vmspace reference count as we no longer need it. - In ptrace() and pseudofs(), treat a process with P_WEXIT set as if it doesn't exist. - Only do one PHOLD in kern_ptrace() now, and do it earlier so it covers FIX_SSTEP() (since on alpha at least this can end up calling proc_rwmem() to clear an earlier single-step simualted via a breakpoint). We only do one to avoid races. Also, by making the EINVAL error for unknown requests be part of the default: case in the switch, the various switch cases can now just break out to return which removes a _lot_ of duplicated PRELE and proc unlocks, etc. Also, it fixes at least one bug where a LWP ptrace command could return EINVAL with the proc lock still held. - Changed the locking for ptrace_single_step(), ptrace_set_pc(), and ptrace_clear_single_step() to always be called with the proc lock held (it was a mixed bag previously). Alpha and arm have to drop the lock while the mess around with breakpoints, but other archs avoid extra lock release/acquires in ptrace(). I did have to fix a couple of other consumers in kern_kse and a few other places to hold the proc lock and PHOLD. Tested by: ps (1 mostly, but some bits of 2-4 as well) MFC after: 1 week
2006-02-22 18:57:50 +00:00
break;
case PT_GETREGS:
CTR2(KTR_PTRACE, "PT_GETREGS: tid %d (pid %d)", td2->td_tid,
p->p_pid);
error = PROC_READ(regs, td2, addr);
Close some races between procfs/ptrace and exit(2): - Reorder the events in exit(2) slightly so that we trigger the S_EXIT stop event earlier. After we have signalled that, we set P_WEXIT and then wait for any processes with a hold on the vmspace via PHOLD to release it. PHOLD now KASSERT()'s that P_WEXIT is clear when it is invoked, and PRELE now does a wakeup if P_WEXIT is set and p_lock drops to zero. - Change proc_rwmem() to require that the processing read from has its vmspace held via PHOLD by the caller and get rid of all the junk to screw around with the vmspace reference count as we no longer need it. - In ptrace() and pseudofs(), treat a process with P_WEXIT set as if it doesn't exist. - Only do one PHOLD in kern_ptrace() now, and do it earlier so it covers FIX_SSTEP() (since on alpha at least this can end up calling proc_rwmem() to clear an earlier single-step simualted via a breakpoint). We only do one to avoid races. Also, by making the EINVAL error for unknown requests be part of the default: case in the switch, the various switch cases can now just break out to return which removes a _lot_ of duplicated PRELE and proc unlocks, etc. Also, it fixes at least one bug where a LWP ptrace command could return EINVAL with the proc lock still held. - Changed the locking for ptrace_single_step(), ptrace_set_pc(), and ptrace_clear_single_step() to always be called with the proc lock held (it was a mixed bag previously). Alpha and arm have to drop the lock while the mess around with breakpoints, but other archs avoid extra lock release/acquires in ptrace(). I did have to fix a couple of other consumers in kern_kse and a few other places to hold the proc lock and PHOLD. Tested by: ps (1 mostly, but some bits of 2-4 as well) MFC after: 1 week
2006-02-22 18:57:50 +00:00
break;
case PT_SETFPREGS:
CTR2(KTR_PTRACE, "PT_SETFPREGS: tid %d (pid %d)", td2->td_tid,
p->p_pid);
td2->td_dbgflags |= TDB_USERWR;
error = PROC_WRITE(fpregs, td2, addr);
Close some races between procfs/ptrace and exit(2): - Reorder the events in exit(2) slightly so that we trigger the S_EXIT stop event earlier. After we have signalled that, we set P_WEXIT and then wait for any processes with a hold on the vmspace via PHOLD to release it. PHOLD now KASSERT()'s that P_WEXIT is clear when it is invoked, and PRELE now does a wakeup if P_WEXIT is set and p_lock drops to zero. - Change proc_rwmem() to require that the processing read from has its vmspace held via PHOLD by the caller and get rid of all the junk to screw around with the vmspace reference count as we no longer need it. - In ptrace() and pseudofs(), treat a process with P_WEXIT set as if it doesn't exist. - Only do one PHOLD in kern_ptrace() now, and do it earlier so it covers FIX_SSTEP() (since on alpha at least this can end up calling proc_rwmem() to clear an earlier single-step simualted via a breakpoint). We only do one to avoid races. Also, by making the EINVAL error for unknown requests be part of the default: case in the switch, the various switch cases can now just break out to return which removes a _lot_ of duplicated PRELE and proc unlocks, etc. Also, it fixes at least one bug where a LWP ptrace command could return EINVAL with the proc lock still held. - Changed the locking for ptrace_single_step(), ptrace_set_pc(), and ptrace_clear_single_step() to always be called with the proc lock held (it was a mixed bag previously). Alpha and arm have to drop the lock while the mess around with breakpoints, but other archs avoid extra lock release/acquires in ptrace(). I did have to fix a couple of other consumers in kern_kse and a few other places to hold the proc lock and PHOLD. Tested by: ps (1 mostly, but some bits of 2-4 as well) MFC after: 1 week
2006-02-22 18:57:50 +00:00
break;
case PT_GETFPREGS:
CTR2(KTR_PTRACE, "PT_GETFPREGS: tid %d (pid %d)", td2->td_tid,
p->p_pid);
error = PROC_READ(fpregs, td2, addr);
Close some races between procfs/ptrace and exit(2): - Reorder the events in exit(2) slightly so that we trigger the S_EXIT stop event earlier. After we have signalled that, we set P_WEXIT and then wait for any processes with a hold on the vmspace via PHOLD to release it. PHOLD now KASSERT()'s that P_WEXIT is clear when it is invoked, and PRELE now does a wakeup if P_WEXIT is set and p_lock drops to zero. - Change proc_rwmem() to require that the processing read from has its vmspace held via PHOLD by the caller and get rid of all the junk to screw around with the vmspace reference count as we no longer need it. - In ptrace() and pseudofs(), treat a process with P_WEXIT set as if it doesn't exist. - Only do one PHOLD in kern_ptrace() now, and do it earlier so it covers FIX_SSTEP() (since on alpha at least this can end up calling proc_rwmem() to clear an earlier single-step simualted via a breakpoint). We only do one to avoid races. Also, by making the EINVAL error for unknown requests be part of the default: case in the switch, the various switch cases can now just break out to return which removes a _lot_ of duplicated PRELE and proc unlocks, etc. Also, it fixes at least one bug where a LWP ptrace command could return EINVAL with the proc lock still held. - Changed the locking for ptrace_single_step(), ptrace_set_pc(), and ptrace_clear_single_step() to always be called with the proc lock held (it was a mixed bag previously). Alpha and arm have to drop the lock while the mess around with breakpoints, but other archs avoid extra lock release/acquires in ptrace(). I did have to fix a couple of other consumers in kern_kse and a few other places to hold the proc lock and PHOLD. Tested by: ps (1 mostly, but some bits of 2-4 as well) MFC after: 1 week
2006-02-22 18:57:50 +00:00
break;
case PT_SETDBREGS:
CTR2(KTR_PTRACE, "PT_SETDBREGS: tid %d (pid %d)", td2->td_tid,
p->p_pid);
td2->td_dbgflags |= TDB_USERWR;
error = PROC_WRITE(dbregs, td2, addr);
Close some races between procfs/ptrace and exit(2): - Reorder the events in exit(2) slightly so that we trigger the S_EXIT stop event earlier. After we have signalled that, we set P_WEXIT and then wait for any processes with a hold on the vmspace via PHOLD to release it. PHOLD now KASSERT()'s that P_WEXIT is clear when it is invoked, and PRELE now does a wakeup if P_WEXIT is set and p_lock drops to zero. - Change proc_rwmem() to require that the processing read from has its vmspace held via PHOLD by the caller and get rid of all the junk to screw around with the vmspace reference count as we no longer need it. - In ptrace() and pseudofs(), treat a process with P_WEXIT set as if it doesn't exist. - Only do one PHOLD in kern_ptrace() now, and do it earlier so it covers FIX_SSTEP() (since on alpha at least this can end up calling proc_rwmem() to clear an earlier single-step simualted via a breakpoint). We only do one to avoid races. Also, by making the EINVAL error for unknown requests be part of the default: case in the switch, the various switch cases can now just break out to return which removes a _lot_ of duplicated PRELE and proc unlocks, etc. Also, it fixes at least one bug where a LWP ptrace command could return EINVAL with the proc lock still held. - Changed the locking for ptrace_single_step(), ptrace_set_pc(), and ptrace_clear_single_step() to always be called with the proc lock held (it was a mixed bag previously). Alpha and arm have to drop the lock while the mess around with breakpoints, but other archs avoid extra lock release/acquires in ptrace(). I did have to fix a couple of other consumers in kern_kse and a few other places to hold the proc lock and PHOLD. Tested by: ps (1 mostly, but some bits of 2-4 as well) MFC after: 1 week
2006-02-22 18:57:50 +00:00
break;
case PT_GETDBREGS:
CTR2(KTR_PTRACE, "PT_GETDBREGS: tid %d (pid %d)", td2->td_tid,
p->p_pid);
error = PROC_READ(dbregs, td2, addr);
Close some races between procfs/ptrace and exit(2): - Reorder the events in exit(2) slightly so that we trigger the S_EXIT stop event earlier. After we have signalled that, we set P_WEXIT and then wait for any processes with a hold on the vmspace via PHOLD to release it. PHOLD now KASSERT()'s that P_WEXIT is clear when it is invoked, and PRELE now does a wakeup if P_WEXIT is set and p_lock drops to zero. - Change proc_rwmem() to require that the processing read from has its vmspace held via PHOLD by the caller and get rid of all the junk to screw around with the vmspace reference count as we no longer need it. - In ptrace() and pseudofs(), treat a process with P_WEXIT set as if it doesn't exist. - Only do one PHOLD in kern_ptrace() now, and do it earlier so it covers FIX_SSTEP() (since on alpha at least this can end up calling proc_rwmem() to clear an earlier single-step simualted via a breakpoint). We only do one to avoid races. Also, by making the EINVAL error for unknown requests be part of the default: case in the switch, the various switch cases can now just break out to return which removes a _lot_ of duplicated PRELE and proc unlocks, etc. Also, it fixes at least one bug where a LWP ptrace command could return EINVAL with the proc lock still held. - Changed the locking for ptrace_single_step(), ptrace_set_pc(), and ptrace_clear_single_step() to always be called with the proc lock held (it was a mixed bag previously). Alpha and arm have to drop the lock while the mess around with breakpoints, but other archs avoid extra lock release/acquires in ptrace(). I did have to fix a couple of other consumers in kern_kse and a few other places to hold the proc lock and PHOLD. Tested by: ps (1 mostly, but some bits of 2-4 as well) MFC after: 1 week
2006-02-22 18:57:50 +00:00
break;
case PT_SETREGSET:
CTR2(KTR_PTRACE, "PT_SETREGSET: tid %d (pid %d)", td2->td_tid,
p->p_pid);
error = proc_write_regset(td2, data, addr);
break;
case PT_GETREGSET:
CTR2(KTR_PTRACE, "PT_GETREGSET: tid %d (pid %d)", td2->td_tid,
p->p_pid);
error = proc_read_regset(td2, data, addr);
break;
case PT_LWPINFO:
if (data <= 0 || data > sizeof(*pl)) {
Close some races between procfs/ptrace and exit(2): - Reorder the events in exit(2) slightly so that we trigger the S_EXIT stop event earlier. After we have signalled that, we set P_WEXIT and then wait for any processes with a hold on the vmspace via PHOLD to release it. PHOLD now KASSERT()'s that P_WEXIT is clear when it is invoked, and PRELE now does a wakeup if P_WEXIT is set and p_lock drops to zero. - Change proc_rwmem() to require that the processing read from has its vmspace held via PHOLD by the caller and get rid of all the junk to screw around with the vmspace reference count as we no longer need it. - In ptrace() and pseudofs(), treat a process with P_WEXIT set as if it doesn't exist. - Only do one PHOLD in kern_ptrace() now, and do it earlier so it covers FIX_SSTEP() (since on alpha at least this can end up calling proc_rwmem() to clear an earlier single-step simualted via a breakpoint). We only do one to avoid races. Also, by making the EINVAL error for unknown requests be part of the default: case in the switch, the various switch cases can now just break out to return which removes a _lot_ of duplicated PRELE and proc unlocks, etc. Also, it fixes at least one bug where a LWP ptrace command could return EINVAL with the proc lock still held. - Changed the locking for ptrace_single_step(), ptrace_set_pc(), and ptrace_clear_single_step() to always be called with the proc lock held (it was a mixed bag previously). Alpha and arm have to drop the lock while the mess around with breakpoints, but other archs avoid extra lock release/acquires in ptrace(). I did have to fix a couple of other consumers in kern_kse and a few other places to hold the proc lock and PHOLD. Tested by: ps (1 mostly, but some bits of 2-4 as well) MFC after: 1 week
2006-02-22 18:57:50 +00:00
error = EINVAL;
break;
}
pl = addr;
bzero(pl, sizeof(*pl));
pl->pl_lwpid = td2->td_tid;
pl->pl_event = PL_EVENT_NONE;
pl->pl_flags = 0;
if (td2->td_dbgflags & TDB_XSIG) {
pl->pl_event = PL_EVENT_SIGNAL;
if (td2->td_si.si_signo != 0 &&
data >= offsetof(struct ptrace_lwpinfo, pl_siginfo)
+ sizeof(pl->pl_siginfo)){
pl->pl_flags |= PL_FLAG_SI;
pl->pl_siginfo = td2->td_si;
}
}
Reorganize syscall entry and leave handling. Extend struct sysvec with three new elements: sv_fetch_syscall_args - the method to fetch syscall arguments from usermode into struct syscall_args. The structure is machine-depended (this might be reconsidered after all architectures are converted). sv_set_syscall_retval - the method to set a return value for usermode from the syscall. It is a generalization of cpu_set_syscall_retval(9) to allow ABIs to override the way to set a return value. sv_syscallnames - the table of syscall names. Use sv_set_syscall_retval in kern_sigsuspend() instead of hardcoding the call to cpu_set_syscall_retval(). The new functions syscallenter(9) and syscallret(9) are provided that use sv_*syscall* pointers and contain the common repeated code from the syscall() implementations for the architecture-specific syscall trap handlers. Syscallenter() fetches arguments, calls syscall implementation from ABI sysent table, and set up return frame. The end of syscall bookkeeping is done by syscallret(). Take advantage of single place for MI syscall handling code and implement ptrace_lwpinfo pl_flags PL_FLAG_SCE, PL_FLAG_SCX and PL_FLAG_EXEC. The SCE and SCX flags notify the debugger that the thread is stopped at syscall entry or return point respectively. The EXEC flag augments SCX and notifies debugger that the process address space was changed by one of exec(2)-family syscalls. The i386, amd64, sparc64, sun4v, powerpc and ia64 syscall()s are changed to use syscallenter()/syscallret(). MIPS and arm are not converted and use the mostly unchanged syscall() implementation. Reviewed by: jhb, marcel, marius, nwhitehorn, stas Tested by: marcel (ia64), marius (sparc64), nwhitehorn (powerpc), stas (mips) MFC after: 1 month
2010-05-23 18:32:02 +00:00
if (td2->td_dbgflags & TDB_SCE)
pl->pl_flags |= PL_FLAG_SCE;
else if (td2->td_dbgflags & TDB_SCX)
pl->pl_flags |= PL_FLAG_SCX;
if (td2->td_dbgflags & TDB_EXEC)
pl->pl_flags |= PL_FLAG_EXEC;
if (td2->td_dbgflags & TDB_FORK) {
pl->pl_flags |= PL_FLAG_FORKED;
pl->pl_child_pid = td2->td_dbg_forked;
if (td2->td_dbgflags & TDB_VFORK)
pl->pl_flags |= PL_FLAG_VFORKED;
} else if ((td2->td_dbgflags & (TDB_SCX | TDB_VFORK)) ==
TDB_VFORK)
pl->pl_flags |= PL_FLAG_VFORK_DONE;
if (td2->td_dbgflags & TDB_CHILD)
pl->pl_flags |= PL_FLAG_CHILD;
if (td2->td_dbgflags & TDB_BORN)
pl->pl_flags |= PL_FLAG_BORN;
if (td2->td_dbgflags & TDB_EXIT)
pl->pl_flags |= PL_FLAG_EXITED;
pl->pl_sigmask = td2->td_sigmask;
pl->pl_siglist = td2->td_siglist;
strcpy(pl->pl_tdname, td2->td_name);
if ((td2->td_dbgflags & (TDB_SCE | TDB_SCX)) != 0) {
pl->pl_syscall_code = td2->td_sa.code;
pl->pl_syscall_narg = td2->td_sa.callp->sy_narg;
} else {
pl->pl_syscall_code = 0;
pl->pl_syscall_narg = 0;
}
CTR6(KTR_PTRACE,
"PT_LWPINFO: tid %d (pid %d) event %d flags %#x child pid %d syscall %d",
td2->td_tid, p->p_pid, pl->pl_event, pl->pl_flags,
pl->pl_child_pid, pl->pl_syscall_code);
Close some races between procfs/ptrace and exit(2): - Reorder the events in exit(2) slightly so that we trigger the S_EXIT stop event earlier. After we have signalled that, we set P_WEXIT and then wait for any processes with a hold on the vmspace via PHOLD to release it. PHOLD now KASSERT()'s that P_WEXIT is clear when it is invoked, and PRELE now does a wakeup if P_WEXIT is set and p_lock drops to zero. - Change proc_rwmem() to require that the processing read from has its vmspace held via PHOLD by the caller and get rid of all the junk to screw around with the vmspace reference count as we no longer need it. - In ptrace() and pseudofs(), treat a process with P_WEXIT set as if it doesn't exist. - Only do one PHOLD in kern_ptrace() now, and do it earlier so it covers FIX_SSTEP() (since on alpha at least this can end up calling proc_rwmem() to clear an earlier single-step simualted via a breakpoint). We only do one to avoid races. Also, by making the EINVAL error for unknown requests be part of the default: case in the switch, the various switch cases can now just break out to return which removes a _lot_ of duplicated PRELE and proc unlocks, etc. Also, it fixes at least one bug where a LWP ptrace command could return EINVAL with the proc lock still held. - Changed the locking for ptrace_single_step(), ptrace_set_pc(), and ptrace_clear_single_step() to always be called with the proc lock held (it was a mixed bag previously). Alpha and arm have to drop the lock while the mess around with breakpoints, but other archs avoid extra lock release/acquires in ptrace(). I did have to fix a couple of other consumers in kern_kse and a few other places to hold the proc lock and PHOLD. Tested by: ps (1 mostly, but some bits of 2-4 as well) MFC after: 1 week
2006-02-22 18:57:50 +00:00
break;
case PT_GETNUMLWPS:
CTR2(KTR_PTRACE, "PT_GETNUMLWPS: pid %d: %d threads", p->p_pid,
p->p_numthreads);
td->td_retval[0] = p->p_numthreads;
Close some races between procfs/ptrace and exit(2): - Reorder the events in exit(2) slightly so that we trigger the S_EXIT stop event earlier. After we have signalled that, we set P_WEXIT and then wait for any processes with a hold on the vmspace via PHOLD to release it. PHOLD now KASSERT()'s that P_WEXIT is clear when it is invoked, and PRELE now does a wakeup if P_WEXIT is set and p_lock drops to zero. - Change proc_rwmem() to require that the processing read from has its vmspace held via PHOLD by the caller and get rid of all the junk to screw around with the vmspace reference count as we no longer need it. - In ptrace() and pseudofs(), treat a process with P_WEXIT set as if it doesn't exist. - Only do one PHOLD in kern_ptrace() now, and do it earlier so it covers FIX_SSTEP() (since on alpha at least this can end up calling proc_rwmem() to clear an earlier single-step simualted via a breakpoint). We only do one to avoid races. Also, by making the EINVAL error for unknown requests be part of the default: case in the switch, the various switch cases can now just break out to return which removes a _lot_ of duplicated PRELE and proc unlocks, etc. Also, it fixes at least one bug where a LWP ptrace command could return EINVAL with the proc lock still held. - Changed the locking for ptrace_single_step(), ptrace_set_pc(), and ptrace_clear_single_step() to always be called with the proc lock held (it was a mixed bag previously). Alpha and arm have to drop the lock while the mess around with breakpoints, but other archs avoid extra lock release/acquires in ptrace(). I did have to fix a couple of other consumers in kern_kse and a few other places to hold the proc lock and PHOLD. Tested by: ps (1 mostly, but some bits of 2-4 as well) MFC after: 1 week
2006-02-22 18:57:50 +00:00
break;
case PT_GETLWPLIST:
CTR3(KTR_PTRACE, "PT_GETLWPLIST: pid %d: data %d, actual %d",
p->p_pid, data, p->p_numthreads);
if (data <= 0) {
Close some races between procfs/ptrace and exit(2): - Reorder the events in exit(2) slightly so that we trigger the S_EXIT stop event earlier. After we have signalled that, we set P_WEXIT and then wait for any processes with a hold on the vmspace via PHOLD to release it. PHOLD now KASSERT()'s that P_WEXIT is clear when it is invoked, and PRELE now does a wakeup if P_WEXIT is set and p_lock drops to zero. - Change proc_rwmem() to require that the processing read from has its vmspace held via PHOLD by the caller and get rid of all the junk to screw around with the vmspace reference count as we no longer need it. - In ptrace() and pseudofs(), treat a process with P_WEXIT set as if it doesn't exist. - Only do one PHOLD in kern_ptrace() now, and do it earlier so it covers FIX_SSTEP() (since on alpha at least this can end up calling proc_rwmem() to clear an earlier single-step simualted via a breakpoint). We only do one to avoid races. Also, by making the EINVAL error for unknown requests be part of the default: case in the switch, the various switch cases can now just break out to return which removes a _lot_ of duplicated PRELE and proc unlocks, etc. Also, it fixes at least one bug where a LWP ptrace command could return EINVAL with the proc lock still held. - Changed the locking for ptrace_single_step(), ptrace_set_pc(), and ptrace_clear_single_step() to always be called with the proc lock held (it was a mixed bag previously). Alpha and arm have to drop the lock while the mess around with breakpoints, but other archs avoid extra lock release/acquires in ptrace(). I did have to fix a couple of other consumers in kern_kse and a few other places to hold the proc lock and PHOLD. Tested by: ps (1 mostly, but some bits of 2-4 as well) MFC after: 1 week
2006-02-22 18:57:50 +00:00
error = EINVAL;
break;
}
num = imin(p->p_numthreads, data);
PROC_UNLOCK(p);
buf = malloc(num * sizeof(lwpid_t), M_TEMP, M_WAITOK);
tmp = 0;
PROC_LOCK(p);
FOREACH_THREAD_IN_PROC(p, td2) {
if (tmp >= num)
break;
buf[tmp++] = td2->td_tid;
}
PROC_UNLOCK(p);
error = copyout(buf, addr, tmp * sizeof(lwpid_t));
free(buf, M_TEMP);
if (!error)
td->td_retval[0] = tmp;
Close some races between procfs/ptrace and exit(2): - Reorder the events in exit(2) slightly so that we trigger the S_EXIT stop event earlier. After we have signalled that, we set P_WEXIT and then wait for any processes with a hold on the vmspace via PHOLD to release it. PHOLD now KASSERT()'s that P_WEXIT is clear when it is invoked, and PRELE now does a wakeup if P_WEXIT is set and p_lock drops to zero. - Change proc_rwmem() to require that the processing read from has its vmspace held via PHOLD by the caller and get rid of all the junk to screw around with the vmspace reference count as we no longer need it. - In ptrace() and pseudofs(), treat a process with P_WEXIT set as if it doesn't exist. - Only do one PHOLD in kern_ptrace() now, and do it earlier so it covers FIX_SSTEP() (since on alpha at least this can end up calling proc_rwmem() to clear an earlier single-step simualted via a breakpoint). We only do one to avoid races. Also, by making the EINVAL error for unknown requests be part of the default: case in the switch, the various switch cases can now just break out to return which removes a _lot_ of duplicated PRELE and proc unlocks, etc. Also, it fixes at least one bug where a LWP ptrace command could return EINVAL with the proc lock still held. - Changed the locking for ptrace_single_step(), ptrace_set_pc(), and ptrace_clear_single_step() to always be called with the proc lock held (it was a mixed bag previously). Alpha and arm have to drop the lock while the mess around with breakpoints, but other archs avoid extra lock release/acquires in ptrace(). I did have to fix a couple of other consumers in kern_kse and a few other places to hold the proc lock and PHOLD. Tested by: ps (1 mostly, but some bits of 2-4 as well) MFC after: 1 week
2006-02-22 18:57:50 +00:00
PROC_LOCK(p);
break;
case PT_VM_TIMESTAMP:
CTR2(KTR_PTRACE, "PT_VM_TIMESTAMP: pid %d: timestamp %d",
p->p_pid, p->p_vmspace->vm_map.timestamp);
td->td_retval[0] = p->p_vmspace->vm_map.timestamp;
break;
case PT_VM_ENTRY:
PROC_UNLOCK(p);
error = ptrace_vm_entry(td, p, addr);
PROC_LOCK(p);
break;
case PT_COREDUMP:
pc = addr;
CTR2(KTR_PTRACE, "PT_COREDUMP: pid %d, fd %d",
p->p_pid, pc->pc_fd);
if ((pc->pc_flags & ~(PC_COMPRESS | PC_ALL)) != 0) {
error = EINVAL;
break;
}
PROC_UNLOCK(p);
tcq = malloc(sizeof(*tcq), M_TEMP, M_WAITOK | M_ZERO);
fp = NULL;
error = fget_write(td, pc->pc_fd, &cap_write_rights, &fp);
if (error != 0)
goto coredump_cleanup_nofp;
if (fp->f_type != DTYPE_VNODE || fp->f_vnode->v_type != VREG) {
error = EPIPE;
goto coredump_cleanup;
}
PROC_LOCK(p);
error = proc_can_ptrace(td, p);
if (error != 0)
goto coredump_cleanup_locked;
td2 = ptrace_sel_coredump_thread(p);
if (td2 == NULL) {
error = EBUSY;
goto coredump_cleanup_locked;
}
KASSERT((td2->td_dbgflags & (TDB_COREDUMPREQ |
TDB_SCREMOTEREQ)) == 0,
("proc %d tid %d req coredump", p->p_pid, td2->td_tid));
tcq->tc_vp = fp->f_vnode;
tcq->tc_limit = pc->pc_limit == 0 ? OFF_MAX : pc->pc_limit;
tcq->tc_flags = SVC_PT_COREDUMP;
if ((pc->pc_flags & PC_COMPRESS) == 0)
tcq->tc_flags |= SVC_NOCOMPRESS;
if ((pc->pc_flags & PC_ALL) != 0)
tcq->tc_flags |= SVC_ALL;
td2->td_remotereq = tcq;
td2->td_dbgflags |= TDB_COREDUMPREQ;
thread_run_flash(td2);
while ((td2->td_dbgflags & TDB_COREDUMPREQ) != 0)
msleep(p, &p->p_mtx, PPAUSE, "crdmp", 0);
error = tcq->tc_error;
coredump_cleanup_locked:
PROC_UNLOCK(p);
coredump_cleanup:
fdrop(fp, td);
coredump_cleanup_nofp:
free(tcq, M_TEMP);
PROC_LOCK(p);
break;
case PT_SC_REMOTE:
pscr = addr;
CTR2(KTR_PTRACE, "PT_SC_REMOTE: pid %d, syscall %d",
p->p_pid, pscr->pscr_syscall);
if ((td2->td_dbgflags & TDB_BOUNDARY) == 0) {
error = EBUSY;
break;
}
PROC_UNLOCK(p);
MPASS(pscr->pscr_nargs <= nitems(td->td_sa.args));
tsr = malloc(sizeof(struct thr_syscall_req), M_TEMP,
M_WAITOK | M_ZERO);
tsr->ts_sa.code = pscr->pscr_syscall;
tsr->ts_nargs = pscr->pscr_nargs;
memcpy(&tsr->ts_sa.args, pscr->pscr_args,
sizeof(syscallarg_t) * tsr->ts_nargs);
PROC_LOCK(p);
error = proc_can_ptrace(td, p);
if (error != 0) {
free(tsr, M_TEMP);
break;
}
if (td2->td_proc != p) {
free(tsr, M_TEMP);
error = ESRCH;
break;
}
KASSERT((td2->td_dbgflags & (TDB_COREDUMPREQ |
TDB_SCREMOTEREQ)) == 0,
("proc %d tid %d req coredump", p->p_pid, td2->td_tid));
td2->td_remotereq = tsr;
td2->td_dbgflags |= TDB_SCREMOTEREQ;
thread_run_flash(td2);
while ((td2->td_dbgflags & TDB_SCREMOTEREQ) != 0)
msleep(p, &p->p_mtx, PPAUSE, "pscrx", 0);
error = 0;
memcpy(&pscr->pscr_ret, &tsr->ts_ret, sizeof(tsr->ts_ret));
free(tsr, M_TEMP);
break;
default:
#ifdef __HAVE_PTRACE_MACHDEP
if (req >= PT_FIRSTMACH) {
PROC_UNLOCK(p);
error = cpu_ptrace(td2, req, addr, data);
Close some races between procfs/ptrace and exit(2): - Reorder the events in exit(2) slightly so that we trigger the S_EXIT stop event earlier. After we have signalled that, we set P_WEXIT and then wait for any processes with a hold on the vmspace via PHOLD to release it. PHOLD now KASSERT()'s that P_WEXIT is clear when it is invoked, and PRELE now does a wakeup if P_WEXIT is set and p_lock drops to zero. - Change proc_rwmem() to require that the processing read from has its vmspace held via PHOLD by the caller and get rid of all the junk to screw around with the vmspace reference count as we no longer need it. - In ptrace() and pseudofs(), treat a process with P_WEXIT set as if it doesn't exist. - Only do one PHOLD in kern_ptrace() now, and do it earlier so it covers FIX_SSTEP() (since on alpha at least this can end up calling proc_rwmem() to clear an earlier single-step simualted via a breakpoint). We only do one to avoid races. Also, by making the EINVAL error for unknown requests be part of the default: case in the switch, the various switch cases can now just break out to return which removes a _lot_ of duplicated PRELE and proc unlocks, etc. Also, it fixes at least one bug where a LWP ptrace command could return EINVAL with the proc lock still held. - Changed the locking for ptrace_single_step(), ptrace_set_pc(), and ptrace_clear_single_step() to always be called with the proc lock held (it was a mixed bag previously). Alpha and arm have to drop the lock while the mess around with breakpoints, but other archs avoid extra lock release/acquires in ptrace(). I did have to fix a couple of other consumers in kern_kse and a few other places to hold the proc lock and PHOLD. Tested by: ps (1 mostly, but some bits of 2-4 as well) MFC after: 1 week
2006-02-22 18:57:50 +00:00
PROC_LOCK(p);
} else
#endif
Close some races between procfs/ptrace and exit(2): - Reorder the events in exit(2) slightly so that we trigger the S_EXIT stop event earlier. After we have signalled that, we set P_WEXIT and then wait for any processes with a hold on the vmspace via PHOLD to release it. PHOLD now KASSERT()'s that P_WEXIT is clear when it is invoked, and PRELE now does a wakeup if P_WEXIT is set and p_lock drops to zero. - Change proc_rwmem() to require that the processing read from has its vmspace held via PHOLD by the caller and get rid of all the junk to screw around with the vmspace reference count as we no longer need it. - In ptrace() and pseudofs(), treat a process with P_WEXIT set as if it doesn't exist. - Only do one PHOLD in kern_ptrace() now, and do it earlier so it covers FIX_SSTEP() (since on alpha at least this can end up calling proc_rwmem() to clear an earlier single-step simualted via a breakpoint). We only do one to avoid races. Also, by making the EINVAL error for unknown requests be part of the default: case in the switch, the various switch cases can now just break out to return which removes a _lot_ of duplicated PRELE and proc unlocks, etc. Also, it fixes at least one bug where a LWP ptrace command could return EINVAL with the proc lock still held. - Changed the locking for ptrace_single_step(), ptrace_set_pc(), and ptrace_clear_single_step() to always be called with the proc lock held (it was a mixed bag previously). Alpha and arm have to drop the lock while the mess around with breakpoints, but other archs avoid extra lock release/acquires in ptrace(). I did have to fix a couple of other consumers in kern_kse and a few other places to hold the proc lock and PHOLD. Tested by: ps (1 mostly, but some bits of 2-4 as well) MFC after: 1 week
2006-02-22 18:57:50 +00:00
/* Unknown request. */
error = EINVAL;
break;
}
Close some races between procfs/ptrace and exit(2): - Reorder the events in exit(2) slightly so that we trigger the S_EXIT stop event earlier. After we have signalled that, we set P_WEXIT and then wait for any processes with a hold on the vmspace via PHOLD to release it. PHOLD now KASSERT()'s that P_WEXIT is clear when it is invoked, and PRELE now does a wakeup if P_WEXIT is set and p_lock drops to zero. - Change proc_rwmem() to require that the processing read from has its vmspace held via PHOLD by the caller and get rid of all the junk to screw around with the vmspace reference count as we no longer need it. - In ptrace() and pseudofs(), treat a process with P_WEXIT set as if it doesn't exist. - Only do one PHOLD in kern_ptrace() now, and do it earlier so it covers FIX_SSTEP() (since on alpha at least this can end up calling proc_rwmem() to clear an earlier single-step simualted via a breakpoint). We only do one to avoid races. Also, by making the EINVAL error for unknown requests be part of the default: case in the switch, the various switch cases can now just break out to return which removes a _lot_ of duplicated PRELE and proc unlocks, etc. Also, it fixes at least one bug where a LWP ptrace command could return EINVAL with the proc lock still held. - Changed the locking for ptrace_single_step(), ptrace_set_pc(), and ptrace_clear_single_step() to always be called with the proc lock held (it was a mixed bag previously). Alpha and arm have to drop the lock while the mess around with breakpoints, but other archs avoid extra lock release/acquires in ptrace(). I did have to fix a couple of other consumers in kern_kse and a few other places to hold the proc lock and PHOLD. Tested by: ps (1 mostly, but some bits of 2-4 as well) MFC after: 1 week
2006-02-22 18:57:50 +00:00
out:
/* Drop our hold on this process now that the request has completed. */
_PRELE(p);
fail:
if (p2_req_set) {
if ((p->p_flag2 & P2_PTRACEREQ) != 0)
wakeup(&p->p_flag2);
p->p_flag2 &= ~P2_PTRACEREQ;
}
PROC_UNLOCK(p);
if (proctree_locked)
sx_xunlock(&proctree_lock);
return (error);
1994-05-24 10:09:53 +00:00
}
#undef PROC_READ
#undef PROC_WRITE