mirror of
https://github.com/freebsd/freebsd-src.git
synced 2026-10-28 19:34:43 +01:00
ptrace(2): add PT_GET_CHILDREN
Reviewed by: markj Sponsored by: The FreeBSD Foundation MFC after: 1 week Differential revision: https://reviews.freebsd.org/D58315
This commit is contained in:
1 parent
aa588213d8
commit
d3b7bbee92
3 files changed
+165
-2
No files matched your search
@@ -1031,6 +1031,7 @@ freebsd32_ptrace(struct thread *td, struct freebsd32_ptrace_args *uap)
|
||||
register_t args[nitems(td->td_sa.args)];
|
||||
struct ptrace_sc_ret psr;
|
||||
int ptevents;
|
||||
struct ptrace_child *children;
|
||||
} r;
|
||||
union {
|
||||
struct ptrace_io_desc32 piod;
|
||||
@@ -1173,6 +1174,14 @@ freebsd32_ptrace(struct thread *td, struct freebsd32_ptrace_args *uap)
|
||||
pscr_args[i] = pscr_args32[i];
|
||||
r.sr.pscr_args = pscr_args;
|
||||
break;
|
||||
case PT_GET_CHILDREN:
|
||||
if (uap->addr == NULL)
|
||||
addr = NULL;
|
||||
else if (uap->data < 0)
|
||||
error = EINVAL;
|
||||
else
|
||||
addr = &r.children;
|
||||
break;
|
||||
case PTINTERNAL_FIRST ... PTINTERNAL_LAST:
|
||||
error = EINVAL;
|
||||
break;
|
||||
@@ -1242,6 +1251,13 @@ freebsd32_ptrace(struct thread *td, struct freebsd32_ptrace_args *uap)
|
||||
offsetof(struct ptrace_sc_remote32, pscr_ret),
|
||||
sizeof(r32.psr));
|
||||
break;
|
||||
case PT_GET_CHILDREN:
|
||||
if (uap->addr != 0) {
|
||||
error = copyout(r.children, uap->addr,
|
||||
td->td_retval[0] * sizeof(struct ptrace_child));
|
||||
free(r.children, M_TEMP);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return (error);
|
||||
|
||||
+137
-2
@@ -733,6 +733,7 @@ sys_ptrace(struct thread *td, struct ptrace_args *uap)
|
||||
syscallarg_t args[nitems(td->td_sa.args)];
|
||||
struct ptrace_sc_ret psr;
|
||||
int ptevents;
|
||||
struct ptrace_child *children;
|
||||
} r;
|
||||
syscallarg_t pscr_args[nitems(td->td_sa.args)];
|
||||
void *addr;
|
||||
@@ -816,6 +817,14 @@ sys_ptrace(struct thread *td, struct ptrace_args *uap)
|
||||
break;
|
||||
r.sr.pscr_args = pscr_args;
|
||||
break;
|
||||
case PT_GET_CHILDREN:
|
||||
if (uap->addr == NULL)
|
||||
addr = NULL;
|
||||
else if (uap->data < 0)
|
||||
error = EINVAL;
|
||||
else
|
||||
addr = &r.children;
|
||||
break;
|
||||
case PTINTERNAL_FIRST ... PTINTERNAL_LAST:
|
||||
error = EINVAL;
|
||||
break;
|
||||
@@ -870,6 +879,13 @@ sys_ptrace(struct thread *td, struct ptrace_args *uap)
|
||||
offsetof(struct ptrace_sc_remote, pscr_ret),
|
||||
sizeof(r.sr.pscr_ret));
|
||||
break;
|
||||
case PT_GET_CHILDREN:
|
||||
if (uap->addr != NULL) {
|
||||
error = copyout(r.children, uap->addr,
|
||||
td->td_retval[0] * sizeof(struct ptrace_child));
|
||||
free(r.children, M_TEMP);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return (error);
|
||||
@@ -965,6 +981,64 @@ proc_can_ptrace(struct thread *td, struct proc *p)
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
ptrace_count_children(struct thread *td, struct proc *p, bool count_everything)
|
||||
{
|
||||
struct proc *pp;
|
||||
int error, num;
|
||||
|
||||
sx_assert(&proctree_lock, SX_LOCKED);
|
||||
num = 0;
|
||||
LIST_FOREACH(pp, &p->p_children, p_sibling) {
|
||||
if (count_everything) {
|
||||
error = 0;
|
||||
} else {
|
||||
PROC_LOCK(pp);
|
||||
error = p_cansee(td, pp);
|
||||
PROC_UNLOCK(pp);
|
||||
}
|
||||
if (error != 0)
|
||||
continue;
|
||||
num++;
|
||||
}
|
||||
LIST_FOREACH(pp, &p->p_orphans, p_orphan) {
|
||||
if (count_everything) {
|
||||
error = 0;
|
||||
} else {
|
||||
PROC_LOCK(pp);
|
||||
error = p_cansee(td, pp);
|
||||
PROC_UNLOCK(pp);
|
||||
}
|
||||
if (error != 0)
|
||||
continue;
|
||||
num++;
|
||||
}
|
||||
return (num);
|
||||
}
|
||||
|
||||
static bool
|
||||
ptrace_report_child(struct thread *td, struct proc *p, struct proc *pp,
|
||||
struct ptrace_child *ptc)
|
||||
{
|
||||
sx_assert(&proctree_lock, SX_LOCKED);
|
||||
|
||||
PROC_LOCK(pp);
|
||||
if (p_cansee(td, pp) != 0) {
|
||||
PROC_UNLOCK(pp);
|
||||
return (false);
|
||||
}
|
||||
ptc->pid = pp->p_pid;
|
||||
if ((pp->p_flag & P_TRACED) != 0) {
|
||||
ptc->flags |= PTCHLD_TRACED;
|
||||
if (pp->p_pptr == td->td_proc)
|
||||
ptc->flags |= PTCHLD_TRACED_BY_ME;
|
||||
}
|
||||
if ((pp->p_flag & P_WEXIT) != 0)
|
||||
ptc->flags |= PTCHLD_EXITED;
|
||||
PROC_UNLOCK(pp);
|
||||
return (true);
|
||||
}
|
||||
|
||||
static struct thread *
|
||||
ptrace_sel_coredump_thread(struct proc *p)
|
||||
{
|
||||
@@ -995,7 +1069,8 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
|
||||
struct ptrace_coredump *pc;
|
||||
struct thr_coredump_req *tcq;
|
||||
struct thr_syscall_req *tsr;
|
||||
int error, num, tmp;
|
||||
struct ptrace_child *children, *ptc;
|
||||
int error, num, num1, tmp;
|
||||
lwpid_t tid = 0, *buf;
|
||||
#ifdef COMPAT_FREEBSD32
|
||||
int wrap32 = 0, safe = 0;
|
||||
@@ -1021,6 +1096,7 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
|
||||
case PT_SET_EVENT_MASK:
|
||||
case PT_DETACH:
|
||||
case PT_GET_SC_ARGS:
|
||||
case PT_GET_CHILDREN:
|
||||
sx_xlock(&proctree_lock);
|
||||
proctree_locked = true;
|
||||
break;
|
||||
@@ -1132,8 +1208,14 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
|
||||
/* Allow thread to clear single step for itself */
|
||||
if (td->td_tid == tid)
|
||||
break;
|
||||
goto default_check;
|
||||
|
||||
/* FALLTHROUGH */
|
||||
case PT_GET_CHILDREN:
|
||||
if (p == curp)
|
||||
break;
|
||||
goto default_check;
|
||||
|
||||
default_check:
|
||||
default:
|
||||
/*
|
||||
* Check for ptrace eligibility before waiting for
|
||||
@@ -1864,6 +1946,59 @@ coredump_cleanup_nofp:
|
||||
free(tsr, M_TEMP);
|
||||
break;
|
||||
|
||||
case PT_GET_CHILDREN:
|
||||
PROC_UNLOCK(p);
|
||||
get_children_repeat:
|
||||
/*
|
||||
* If addr != NULL, we should ignore p_cansee() to
|
||||
* allocate enough space for the children array,
|
||||
* because the process is allowed to change visibility
|
||||
* between loops. But do not count children which
|
||||
* we cannot see when only returning the count, to
|
||||
* avoid a leak of information.
|
||||
*/
|
||||
num = ptrace_count_children(td, p, addr != NULL);
|
||||
|
||||
if (addr == NULL) {
|
||||
td->td_retval[0] = num;
|
||||
PROC_LOCK(p);
|
||||
break;
|
||||
}
|
||||
if (data < num * sizeof(struct ptrace_child)) {
|
||||
error = ENOMEM;
|
||||
PROC_LOCK(p);
|
||||
break;
|
||||
}
|
||||
sx_xunlock(&proctree_lock);
|
||||
children = mallocarray(num, sizeof(struct ptrace_child),
|
||||
M_TEMP, M_WAITOK | M_ZERO);
|
||||
sx_xlock(&proctree_lock);
|
||||
num1 = ptrace_count_children(td, p, true);
|
||||
if (num1 > num) {
|
||||
free(children, M_TEMP);
|
||||
goto get_children_repeat;
|
||||
}
|
||||
num = num1;
|
||||
num1 = 0;
|
||||
LIST_FOREACH(pp, &p->p_children, p_sibling) {
|
||||
MPASS(num1 < num);
|
||||
ptc = &children[num1];
|
||||
if (ptrace_report_child(td, p, pp, ptc))
|
||||
num1++;
|
||||
}
|
||||
LIST_FOREACH(pp, &p->p_orphans, p_orphan) {
|
||||
MPASS(num1 < num);
|
||||
ptc = &children[num1];
|
||||
if (ptrace_report_child(td, p, pp, ptc)) {
|
||||
num1++;
|
||||
ptc->flags |= PTCHLD_ORPHAN;
|
||||
}
|
||||
}
|
||||
*(struct ptrace_child **)addr = children;
|
||||
td->td_retval[0] = num1;
|
||||
PROC_LOCK(p);
|
||||
break;
|
||||
|
||||
default:
|
||||
#ifdef __HAVE_PTRACE_MACHDEP
|
||||
if (req >= PT_FIRSTMACH) {
|
||||
|
||||
@@ -86,6 +86,7 @@
|
||||
#define PT_SETREGSET 43 /* Set a target register set */
|
||||
#define PT_SC_REMOTE 44 /* Execute a syscall */
|
||||
#define PT_SET_SC_RET 45 /* Set (fake) syscall results */
|
||||
#define PT_GET_CHILDREN 46 /* Report children */
|
||||
|
||||
#define PT_FIRSTMACH 64 /* for machine-specific requests */
|
||||
#define PT_LASTMACH 127
|
||||
@@ -206,6 +207,17 @@ struct ptrace_sc_remote {
|
||||
syscallarg_t *pscr_args;
|
||||
};
|
||||
|
||||
#define PTCHLD_TRACED 0x00000001
|
||||
#define PTCHLD_TRACED_BY_ME 0x00000002
|
||||
#define PTCHLD_EXITED 0x00000004
|
||||
#define PTCHLD_ORPHAN 0x00000008
|
||||
|
||||
struct ptrace_child {
|
||||
pid_t pid;
|
||||
int flags;
|
||||
uint64ptr_t rsrv[3];
|
||||
};
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
||||
#include <sys/proc.h>
|
||||
|
||||
Reference in new issue
Block a user