summaryrefslogtreecommitdiffstats
path: root/sys/kern/sys_process.c
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2016-08-15 21:10:41 +0000
committerjhb <jhb@FreeBSD.org>2016-08-15 21:10:41 +0000
commite4842c451d2fcb20d4e7734a423b4dda17c5e79b (patch)
tree5e1aaaba2757e8de80c939a791a338c87196b1dd /sys/kern/sys_process.c
parentbdf6ecc5e6663cf315031bec7696e4418f02bd24 (diff)
downloadFreeBSD-src-e4842c451d2fcb20d4e7734a423b4dda17c5e79b.zip
FreeBSD-src-e4842c451d2fcb20d4e7734a423b4dda17c5e79b.tar.gz
MFC 302900,302902,302921,303461,304009:
Add a mask of optional ptrace() events. 302900: Add a test for user signal delivery. This test verifies we get the correct ptrace event details when a signal is posted to a traced process from userland. 302902: Add a mask of optional ptrace() events. ptrace() now stores a mask of optional events in p_ptevents. Currently this mask is a single integer, but it can be expanded into an array of integers in the future. Two new ptrace requests can be used to manipulate the event mask: PT_GET_EVENT_MASK fetches the current event mask and PT_SET_EVENT_MASK sets the current event mask. The current set of events include: - PTRACE_EXEC: trace calls to execve(). - PTRACE_SCE: trace system call entries. - PTRACE_SCX: trace syscam call exits. - PTRACE_FORK: trace forks and auto-attach to new child processes. - PTRACE_LWP: trace LWP events. The S_PT_SCX and S_PT_SCE events in the procfs p_stops flags have been replaced by PTRACE_SCE and PTRACE_SCX. PTRACE_FORK replaces P_FOLLOW_FORK and PTRACE_LWP replaces P2_LWP_EVENTS. The PT_FOLLOW_FORK and PT_LWP_EVENTS ptrace requests remain for compatibility but now simply toggle corresponding flags in the event mask. While here, document that PT_SYSCALL, PT_TO_SCE, and PT_TO_SCX both modify the event mask and continue the traced process. 302921: Rename PTRACE_SYSCALL to LINUX_PTRACE_SYSCALL. 303461: Note that not all optional ptrace events use SIGTRAP. New child processes attached due to PTRACE_FORK use SIGSTOP instead of SIGTRAP. All other ptrace events use SIGTRAP. 304009: Remove description of P_FOLLOWFORK as this flag was removed.
Diffstat (limited to 'sys/kern/sys_process.c')
-rw-r--r--sys/kern/sys_process.c77
1 files changed, 60 insertions, 17 deletions
diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c
index af71ea8..f1477ce 100644
--- a/sys/kern/sys_process.c
+++ b/sys/kern/sys_process.c
@@ -586,6 +586,7 @@ sys_ptrace(struct thread *td, struct ptrace_args *uap)
struct ptrace_lwpinfo32 pl32;
struct ptrace_vm_entry32 pve32;
#endif
+ int ptevents;
} r;
void *addr;
int error = 0;
@@ -600,6 +601,7 @@ sys_ptrace(struct thread *td, struct ptrace_args *uap)
AUDIT_ARG_VALUE(uap->data);
addr = &r;
switch (uap->req) {
+ case PT_GET_EVENT_MASK:
case PT_GETREGS:
case PT_GETFPREGS:
case PT_GETDBREGS:
@@ -614,6 +616,12 @@ sys_ptrace(struct thread *td, struct ptrace_args *uap)
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;
@@ -647,7 +655,12 @@ sys_ptrace(struct thread *td, struct ptrace_args *uap)
case PT_GETDBREGS:
error = COPYOUT(&r.dbreg, uap->addr, sizeof r.dbreg);
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;
}
@@ -711,6 +724,8 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
case PT_SYSCALL:
case PT_FOLLOW_FORK:
case PT_LWP_EVENTS:
+ case PT_GET_EVENT_MASK:
+ case PT_SET_EVENT_MASK:
case PT_DETACH:
sx_xlock(&proctree_lock);
proctree_locked = 1;
@@ -885,6 +900,7 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
case PT_TRACE_ME:
/* set my trace flag and "owner" so it can read/write me */
p->p_flag |= P_TRACED;
+ p->p_ptevents = PTRACE_DEFAULT;
if (p->p_flag & P_PPWAIT)
p->p_flag |= P_PPTRACE;
p->p_oppid = p->p_pptr->p_pid;
@@ -903,6 +919,7 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
* on a "detach".
*/
p->p_flag |= P_TRACED;
+ p->p_ptevents = PTRACE_DEFAULT;
p->p_oppid = p->p_pptr->p_pid;
if (p->p_pptr != td->td_proc) {
proc_reparent(p, td->td_proc);
@@ -941,24 +958,50 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
case PT_FOLLOW_FORK:
CTR3(KTR_PTRACE, "PT_FOLLOW_FORK: pid %d %s -> %s", p->p_pid,
- p->p_flag & P_FOLLOWFORK ? "enabled" : "disabled",
+ p->p_ptevents & PTRACE_FORK ? "enabled" : "disabled",
data ? "enabled" : "disabled");
if (data)
- p->p_flag |= P_FOLLOWFORK;
+ p->p_ptevents |= PTRACE_FORK;
else
- p->p_flag &= ~P_FOLLOWFORK;
+ 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_flag2 & P2_LWP_EVENTS ? "enabled" : "disabled",
+ p->p_ptevents & PTRACE_LWP ? "enabled" : "disabled",
data ? "enabled" : "disabled");
if (data)
- p->p_flag2 |= P2_LWP_EVENTS;
+ p->p_ptevents |= PTRACE_LWP;
else
- p->p_flag2 &= ~P2_LWP_EVENTS;
+ 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)) != 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_STEP:
case PT_CONTINUE:
case PT_TO_SCE:
@@ -991,24 +1034,24 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
}
switch (req) {
case PT_TO_SCE:
- p->p_stops |= S_PT_SCE;
+ p->p_ptevents |= PTRACE_SCE;
CTR4(KTR_PTRACE,
- "PT_TO_SCE: pid %d, stops = %#x, PC = %#lx, sig = %d",
- p->p_pid, p->p_stops,
+ "PT_TO_SCE: pid %d, events = %#x, PC = %#lx, sig = %d",
+ p->p_pid, p->p_ptevents,
(u_long)(uintfptr_t)addr, data);
break;
case PT_TO_SCX:
- p->p_stops |= S_PT_SCX;
+ p->p_ptevents |= PTRACE_SCX;
CTR4(KTR_PTRACE,
- "PT_TO_SCX: pid %d, stops = %#x, PC = %#lx, sig = %d",
- p->p_pid, p->p_stops,
+ "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_stops |= S_PT_SCE | S_PT_SCX;
+ p->p_ptevents |= PTRACE_SYSCALL;
CTR4(KTR_PTRACE,
- "PT_SYSCALL: pid %d, stops = %#x, PC = %#lx, sig = %d",
- p->p_pid, p->p_stops,
+ "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:
@@ -1027,7 +1070,7 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
* parent. Otherwise the debugee will be set
* as an orphan of the debugger.
*/
- p->p_flag &= ~(P_TRACED | P_WAITED | P_FOLLOWFORK);
+ p->p_flag &= ~(P_TRACED | P_WAITED);
if (p->p_oppid != p->p_pptr->p_pid) {
PROC_LOCK(p->p_pptr);
sigqueue_take(p->p_ksi);
@@ -1044,7 +1087,7 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
CTR2(KTR_PTRACE, "PT_DETACH: pid %d, sig %d",
p->p_pid, data);
p->p_oppid = 0;
- p->p_stops = 0;
+ p->p_ptevents = 0;
/* should we send SIGCHLD? */
/* childproc_continued(p); */
OpenPOWER on IntegriCloud