Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src Introduce new ptrace(2) API to allow/prevent exection of LWP
details: https://anonhg.NetBSD.org/src/rev/96d6fc564698
branches: trunk
changeset: 351696:96d6fc564698
user: kamil <kamil%NetBSD.org@localhost>
date: Wed Feb 22 23:43:43 2017 +0000
description:
Introduce new ptrace(2) API to allow/prevent exection of LWP
Introduce new API for debuggers to allow/prevent execution of the specified
thread.
New ptrace(2) operations:
PT_RESUME Allow execution of a specified thread, change its state
from suspended to continued. The addr argument is unused.
The data argument specifies the LWP ID.
This call is equivalent to _lwp_continue(2) called by a
traced process. This call does not change the general
process state from stopped to continued.
PT_SUSPEND Prevent execution of a specified thread, change its state
from continued to suspended. The addr argument is unused.
The data argument specifies the requested LWP ID.
This call is equivalent to _lwp_suspend(2) called by a
traced process. This call does not change the general
process state from continued to stopped.
This interface is modeled after FreeBSD, however with NetBSD specific arguments
passed to ptrace(2) -- FreeBSD passes only thread id, NetBSD passes process and
thread id.
Extend PT_LWPINFO operation in ptrace(2) to report suspended threads. In the
ptrace_lwpinfo structure in pl_event next to PL_EVENT_NONE and PL_EVENT_SIGNAL
add new value PL_EVENT_SUSPENDED.
Add new errno(2) value EDEADLK that might be returned by ptrace(2). It prevents
dead-locking in a scenario of resuming a process or thread that is prevented
from execution. This fixes bug that old API was vulnerable to this scenario.
Kernel bump delayed till introduction of PT_GETDBREGS/PT_SETDBREGS soon.
Add new ATF tests:
- resume1
Verify that a thread can be suspended by a debugger and later
resumed by the debugger
- suspend1
Verify that a thread can be suspended by a debugger and later
resumed by a tracee
- suspend2
Verify that the while the only thread within a process is
suspended, the whole process cannot be unstopped
Sponsored by <The NetBSD Foundation>
diffstat:
lib/libc/sys/ptrace.2 | 40 ++++-
sys/kern/sys_ptrace_common.c | 76 ++++++++-
sys/sys/ptrace.h | 15 +-
tests/kernel/t_ptrace_wait.c | 341 ++++++++++++++++++++++++++++++++++++++++++-
4 files changed, 459 insertions(+), 13 deletions(-)
diffs (truncated from 615 to 300 lines):
diff -r 5b97a3de7903 -r 96d6fc564698 lib/libc/sys/ptrace.2
--- a/lib/libc/sys/ptrace.2 Wed Feb 22 15:08:55 2017 +0000
+++ b/lib/libc/sys/ptrace.2 Wed Feb 22 23:43:43 2017 +0000
@@ -1,4 +1,4 @@
-.\" $NetBSD: ptrace.2,v 1.59 2017/02/12 06:09:53 kamil Exp $
+.\" $NetBSD: ptrace.2,v 1.60 2017/02/22 23:43:43 kamil Exp $
.\"
.\" This file is in the public domain.
.Dd February 12, 2016
@@ -355,6 +355,7 @@
.Bl -tag -width 30n -offset indent -compact
.It Dv PL_EVENT_NONE
.It Dv PL_EVENT_SIGNAL
+.It Dv PL_EVENT_SUSPENDED
.El
.Pp
The
@@ -539,6 +540,34 @@
.Fa data
argument contains the LWP ID of the thread whose mask is to be read.
If zero is supplied, the first thread of the process is read.
+.It Dv PT_RESUME
+Allow execution of a specified thread,
+change its state from suspended to continued.
+The
+.Fa addr
+argument is unused.
+The
+.Fa data
+argument specifies the LWP ID.
+.Pp
+This call is equivalent to
+.Xr _lwp_continue 2
+called by a traced process.
+This call does not change the general process state from stopped to continued.
+.It Dv PT_SUSPEND
+Prevent execution of a specified thread,
+change its state from continued to suspended.
+The
+.Fa addr
+argument is unused.
+The
+.Fa data
+argument specifies the requested LWP ID.
+.Pp
+This call is equivalent to
+.Xr _lwp_suspend 2
+called by a traced process.
+This call does not change the general process state from continued to stopped.
.El
.Pp
Additionally, the following requests exist but are
@@ -692,6 +721,8 @@
.Dv PT_ATTACH )
specified a process that wasn't stopped.
.El
+.It Bq Er EDEADLK
+An attempt to unstop a process with locked threads.
.It Bq Er EINVAL
.Bl -bullet -compact
.It
@@ -761,3 +792,10 @@
.Dv PTRACE_VFORK
is currently unimplemented and it will return
.Er ENOTSUP .
+.Pp
+.Dv PT_SET_SIGINFO ,
+.Dv PT_RESUME
+and
+.Dv PT_SUSPEND
+can change the image of process returned by
+.Dv PT_LWPINFO .
diff -r 5b97a3de7903 -r 96d6fc564698 sys/kern/sys_ptrace_common.c
--- a/sys/kern/sys_ptrace_common.c Wed Feb 22 15:08:55 2017 +0000
+++ b/sys/kern/sys_ptrace_common.c Wed Feb 22 23:43:43 2017 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: sys_ptrace_common.c,v 1.14 2017/02/12 06:09:52 kamil Exp $ */
+/* $NetBSD: sys_ptrace_common.c,v 1.15 2017/02/22 23:43:43 kamil Exp $ */
/*-
* Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@@ -118,7 +118,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sys_ptrace_common.c,v 1.14 2017/02/12 06:09:52 kamil Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sys_ptrace_common.c,v 1.15 2017/02/22 23:43:43 kamil Exp $");
#ifdef _KERNEL_OPT
#include "opt_ptrace.h"
@@ -236,6 +236,8 @@
case PT_SYSCALL:
case PT_SYSCALLEMU:
case PT_DUMPCORE:
+ case PT_RESUME:
+ case PT_SUSPEND:
result = KAUTH_RESULT_ALLOW;
break;
@@ -457,6 +459,8 @@
case PT_SET_EVENT_MASK:
case PT_GET_EVENT_MASK:
case PT_GET_PROCESS_STATE:
+ case PT_RESUME:
+ case PT_SUSPEND:
/*
* You can't do what you want to the process if:
* (1) It's not being traced at all,
@@ -755,6 +759,34 @@
break;
}
+ /* Prevent process deadlock */
+ if (resume_all) {
+#ifdef PT_STEP
+ if (req == PT_STEP) {
+ if (lt->l_flag & LW_WSUSPEND) {
+ error = EDEADLK;
+ break;
+ }
+ } else
+#endif
+ {
+ error = EDEADLK;
+ LIST_FOREACH(lt2, &t->p_lwps, l_sibling) {
+ if ((lt2->l_flag & LW_WSUSPEND) == 0) {
+ error = 0;
+ break;
+ }
+ }
+ if (error != 0)
+ break;
+ }
+ } else {
+ if (lt->l_flag & LW_WSUSPEND) {
+ error = EDEADLK;
+ break;
+ }
+ }
+
/* If the address parameter is not (int *)1, set the pc. */
if ((int *)addr != (int *)1) {
error = process_set_pc(lt, addr);
@@ -968,15 +1000,18 @@
if (lt) {
lwp_addref(lt);
pl.pl_lwpid = lt->l_lid;
+
+ if (lt->l_flag & LW_WSUSPEND)
+ pl.pl_event = PL_EVENT_SUSPENDED;
/*
* If we match the lwp, or it was sent to every lwp,
* we set PL_EVENT_SIGNAL.
* XXX: ps_lwp == 0 means everyone and noone, so
* check ps_signo too.
*/
- if (lt->l_lid == t->p_sigctx.ps_lwp
- || (t->p_sigctx.ps_lwp == 0 &&
- t->p_sigctx.ps_info._signo))
+ else if (lt->l_lid == t->p_sigctx.ps_lwp
+ || (t->p_sigctx.ps_lwp == 0 &&
+ t->p_sigctx.ps_info._signo))
pl.pl_event = PL_EVENT_SIGNAL;
}
mutex_exit(t->p_lock);
@@ -1072,6 +1107,37 @@
break;
+ case PT_RESUME:
+ write = 1;
+
+ case PT_SUSPEND:
+ /* write = 0 done above. */
+
+ tmp = data;
+ if (tmp != 0 && t->p_nlwps > 1) {
+ lwp_delref(lt);
+ mutex_enter(t->p_lock);
+ lt = lwp_find(t, tmp);
+ if (lt == NULL) {
+ mutex_exit(t->p_lock);
+ error = ESRCH;
+ break;
+ }
+ lwp_addref(lt);
+ mutex_exit(t->p_lock);
+ }
+ if (lt->l_flag & LW_SYSTEM) {
+ error = EINVAL;
+ } else {
+ lwp_lock(lt);
+ if (write == 0)
+ lt->l_flag |= LW_WSUSPEND;
+ else
+ lt->l_flag &= ~LW_WSUSPEND;
+ lwp_unlock(lt);
+ }
+ break;
+
#ifdef PT_SETREGS
case PT_SETREGS:
write = 1;
diff -r 5b97a3de7903 -r 96d6fc564698 sys/sys/ptrace.h
--- a/sys/sys/ptrace.h Wed Feb 22 15:08:55 2017 +0000
+++ b/sys/sys/ptrace.h Wed Feb 22 23:43:43 2017 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: ptrace.h,v 1.56 2017/02/12 06:09:52 kamil Exp $ */
+/* $NetBSD: ptrace.h,v 1.57 2017/02/22 23:43:43 kamil Exp $ */
/*-
* Copyright (c) 1984, 1993
@@ -57,6 +57,8 @@
#define PT_GET_SIGINFO 20 /* get signal state, defined below */
#define PT_SET_SIGMASK 21 /* set signal mask */
#define PT_GET_SIGMASK 22 /* get signal mask */
+#define PT_RESUME 23 /* allow execution of the LWP */
+#define PT_SUSPEND 24 /* prevent execution of the LWP */
#define PT_FIRSTMACH 32 /* for machine-specific requests */
#include <machine/ptrace.h> /* machine-specific requests, if any */
@@ -83,8 +85,10 @@
/* 18 */ "PT_GET_PROCESS_STATE", \
/* 19 */ "PT_SET_SIGINFO", \
/* 20 */ "PT_GET_SIGINFO", \
-/* 20 */ "PT_GET_SIGMASK", \
-/* 20 */ "PT_GET_SIGMASK",
+/* 21 */ "PT_GET_SIGMASK", \
+/* 22 */ "PT_GET_SIGMASK", \
+/* 23 */ "PT_RESUME", \
+/* 24 */ "PT_SUSPEND",
/* PT_{G,S}EVENT_MASK */
typedef struct ptrace_event {
@@ -135,8 +139,9 @@
/* Add fields at the end */
};
-#define PL_EVENT_NONE 0
-#define PL_EVENT_SIGNAL 1
+#define PL_EVENT_NONE 0
+#define PL_EVENT_SIGNAL 1
+#define PL_EVENT_SUSPENDED 2
/*
* Hardware Watchpoints
diff -r 5b97a3de7903 -r 96d6fc564698 tests/kernel/t_ptrace_wait.c
--- a/tests/kernel/t_ptrace_wait.c Wed Feb 22 15:08:55 2017 +0000
+++ b/tests/kernel/t_ptrace_wait.c Wed Feb 22 23:43:43 2017 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: t_ptrace_wait.c,v 1.70 2017/02/12 06:09:52 kamil Exp $ */
+/* $NetBSD: t_ptrace_wait.c,v 1.71 2017/02/22 23:43:43 kamil Exp $ */
/*-
* Copyright (c) 2016 The NetBSD Foundation, Inc.
@@ -27,7 +27,7 @@
*/
#include <sys/cdefs.h>
-__RCSID("$NetBSD: t_ptrace_wait.c,v 1.70 2017/02/12 06:09:52 kamil Exp $");
+__RCSID("$NetBSD: t_ptrace_wait.c,v 1.71 2017/02/22 23:43:43 kamil Exp $");
#include <sys/param.h>
#include <sys/types.h>
@@ -6947,6 +6947,338 @@
TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
}
+static void
+lwp_main_stop(void *arg)
+{
+ the_lwp_id = _lwp_self();
+
+ raise(SIGTRAP);
+
+ _lwp_exit();
+}
+
+ATF_TC(suspend1);
+ATF_TC_HEAD(suspend1, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify that a thread can be suspended by a debugger and later "
+ "resumed by a tracee");
+}
+
+ATF_TC_BODY(suspend1, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ ucontext_t uc;
+ lwpid_t lid;
+ static const size_t ssize = 16*1024;
+ void *stack;
+ struct ptrace_lwpinfo pl;
+ struct ptrace_siginfo psi;
Home |
Main Index |
Thread Index |
Old Index