Skip to content

Commit

Permalink
OS-5431 under many conditions, ptrace (strace) on Ubuntu 16 shows sys…
Browse files Browse the repository at this point in the history
…calls return ENOSYS

Reviewed by: Patrick Mooney <patrick.mooney@joyent.com>
  • Loading branch information
jjelinek committed Jun 20, 2016
1 parent 45bb95d commit 158f4db
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 11 deletions.
8 changes: 7 additions & 1 deletion usr/src/lib/brand/lx/lx_brand/common/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
*/

/*
* Copyright 2015 Joyent, Inc. All rights reserved.
* Copyright 2016 Joyent, Inc. All rights reserved.
*/

#include <sys/types.h>
Expand Down Expand Up @@ -1077,6 +1077,12 @@ lx_rt_sigreturn(void)
ucontext_t *retucp;
uintptr_t sp;

/*
* Since we don't take the normal return path from this syscall, we
* inform the kernel that we're returning, for the sake of ptrace.
*/
(void) syscall(SYS_brand, B_PTRACE_SIG_RETURN);

/* Get the registers at the emulated Linux rt_sigreturn syscall */
ucp = lx_syscall_regs();

Expand Down
16 changes: 16 additions & 0 deletions usr/src/uts/common/brand/lx/os/lx_brand.c
Original file line number Diff line number Diff line change
Expand Up @@ -1485,6 +1485,22 @@ lx_brandsys(int cmd, int64_t *rval, uintptr_t arg1, uintptr_t arg2,
return (lx_ptrace_set_clone_inherit((int)arg1, arg2 == 0 ?
B_FALSE : B_TRUE));

case B_PTRACE_SIG_RETURN: {
/*
* Our ptrace emulation must emit PR_SYSEXIT for rt_sigreturn.
* Since that syscall does not pass through the normal
* emulation, which would call lx_syscall_return, the event is
* emitted manually. A successful result of the syscall is
* assumed since there is little to be done in the face of
* failure.
*/
struct regs *rp = lwptoregs(lwp);

rp->r_r0 = 0;
lx_ptrace_stop(LX_PR_SYSEXIT);
return (0);
}

case B_UNSUPPORTED: {
char dmsg[256];

Expand Down
28 changes: 25 additions & 3 deletions usr/src/uts/common/brand/lx/os/lx_misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,11 @@ lx_forklwp(klwp_t *srclwp, klwp_t *dstlwp)
*/
dst->br_lwp_flags = src->br_lwp_flags & BR_CPU_BOUND;
dst->br_scall_args = NULL;

/*
* Flag so child doesn't ptrace-stop on syscall exit.
*/
dst->br_ptrace_flags |= LX_PTF_NOSTOP;
}

/*
Expand Down Expand Up @@ -1078,10 +1083,27 @@ lx_regs_location(lx_lwp_data_t *lwpd, void **ucp, boolean_t for_write)
/* setting registers not allowed in this state */
break;
}
if (lwpd->br_ptrace_whystop == PR_BRAND &&
lwpd->br_ptrace_whatstop == LX_PR_EVENT) {
if (lwpd->br_ptrace_whystop == PR_BRAND) {
/* Called while ptrace-event-stopped by lx_exec. */
return (LX_REG_LOC_LWP);
if (lwpd->br_ptrace_whatstop == LX_PR_EVENT) {
return (LX_REG_LOC_LWP);
}

/* Called while ptrace-event-stopped after clone. */
if (lwpd->br_ptrace_whatstop == LX_PR_SIGNALLED &&
lwpd->br_ptrace_stopsig == LX_SIGSTOP &&
(lwpd->br_ptrace_flags & LX_PTF_STOPPED)) {
return (LX_REG_LOC_LWP);
}

/*
* Called to obtain syscall exit for other cases
* (e.g. pseudo return from rt_sigreturn).
*/
if (lwpd->br_ptrace_whatstop == LX_PR_SYSEXIT &&
(lwpd->br_ptrace_flags & LX_PTF_STOPPED)) {
return (LX_REG_LOC_LWP);
}
}
break;
default:
Expand Down
60 changes: 56 additions & 4 deletions usr/src/uts/common/brand/lx/os/lx_ptrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,10 @@
*
* Various actions, either directly ptrace(2) related or commonly associated
* with tracing, cause process- or thread-directed SIGSTOP signals to be sent
* to tracees. These signals, and indeed any signal other than SIGKILL, can
* be suppressed by the tracer when using a restarting request (including
* PTRACE_DETACH) on a child. The signal may also be substituted for a
* different signal.
* to tracees (a "signal-delivery-stop"). These signals, and indeed any signal
* other than SIGKILL, can be suppressed by the tracer when using a restarting
* request (including PTRACE_DETACH) on a child. The signal may also be
* substituted for a different signal.
*
* If a SIGSTOP (or other stopping signal) is not suppressed by the tracer,
* it will induce the regular illumos native job control stop of the entire
Expand All @@ -148,6 +148,20 @@
* cleared after each stop; for ongoing system call tracing the tracee must
* be continuously restarted with PTRACE_SYSCALL.
*
* SPECIAL CASES FOR STOP EVENTS
*
* The strace command is one of the primary consumers of ptrace. In order for
* strace to properly understand what is actually happening when it receives a
* signal associated with a stop event, these signals must match Linux behavior
* exactly or the strace consumer will get out of sync and report incorrect
* state. There are a couple of special cases we have to handle to provide
* proper interaction of the syscall-entry-stop, syscall-exit-stop, and
* signal-delivery-stop events:
* 1) The child process of a clone/fork does not emit a syscall-exit-stop event.
* 2) A signal that arrives between syscall-enter-stop & syscall-exit-stop must
* not immediately emit signal-delivery-stop. This event must be emitted
* after the syscall is interrupted and syscall-exit-stop has been emitted.
*
* EVENT STOPS
*
* Various events (particularly FORK, VFORK, CLONE, EXEC and EXIT) are
Expand Down Expand Up @@ -1042,6 +1056,9 @@ lx_ptrace_attach(pid_t lx_pid)
rlwpd->br_ptrace_attach = LX_PTA_ATTACH;
rlwpd->br_ptrace_tracer = accord;

/* Don't emit ptrace syscall-stop-exit event on kernel exit. */
rlwpd->br_ptrace_flags |= LX_PTF_NOSTOP;

/*
* We had no tracer, and are thus not in the tracees list.
* It is safe to take the tracee list lock while we insert
Expand Down Expand Up @@ -1568,13 +1585,29 @@ lx_ptrace_stop(ushort_t what)
* Lock this process and re-check the condition.
*/
mutex_enter(&p->p_lock);

/*
* The child after a fork/clone doesn't emit syscall-exit-stop event.
*/
if (what == LX_PR_SYSEXIT && (lwpd->br_ptrace_flags & LX_PTF_NOSTOP)) {
lwpd->br_ptrace_flags &= ~LX_PTF_NOSTOP;
mutex_exit(&p->p_lock);
return (B_FALSE);
}

if (lwpd->br_ptrace_tracer == NULL) {
VERIFY0(lwpd->br_ptrace_flags & LX_PTF_SYSCALL);
mutex_exit(&p->p_lock);
return (B_FALSE);
}

if (what == LX_PR_SYSENTRY || what == LX_PR_SYSEXIT) {
if (what == LX_PR_SYSENTRY) {
lwpd->br_ptrace_flags |= LX_PTF_INSYSCALL;
} else {
lwpd->br_ptrace_flags &= ~LX_PTF_INSYSCALL;
}

/*
* This is a syscall-entry-stop or syscall-exit-stop point.
*/
Expand Down Expand Up @@ -1641,6 +1674,17 @@ lx_ptrace_issig_stop(proc_t *p, klwp_t *lwp)
return (0);
}

/*
* We can't deliver the signal-delivery-stop condition while we're
* between the syscall-enter-stop and syscall-exit-stop conditions.
* We must first let the signal interrupt the in-progress syscall, let
* it emit syscall-exit-stop with the interrupted result, then we'll
* come back here to emit signal-delivery-stop.
*/
if (lwpd->br_ptrace_flags & LX_PTF_INSYSCALL) {
return (0);
}

/*
* We stash the signal on the LWP where our waitid_helper will find it
* and enter the ptrace "signal-delivery-stop" condition.
Expand Down Expand Up @@ -2401,6 +2445,14 @@ lx_ptrace_kernel(int ptrace_op, pid_t lxpid, uintptr_t addr, uintptr_t data)
return (ESRCH);
}

if (ptrace_op == LX_PTRACE_DETACH) {
/*
* We're detaching, make sure in-syscall flag is off so that
* signal will stop the process directly.
*/
remote->br_ptrace_flags &= ~LX_PTF_INSYSCALL;
}

/*
* Attempt to lock the target LWP.
*/
Expand Down
8 changes: 5 additions & 3 deletions usr/src/uts/common/brand/lx/sys/lx_brand.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ extern "C" {
#define B_SET_NATIVE_STACK 147
#define B_SIGEV_THREAD_ID 148
#define B_OVERRIDE_KERN_VER 149
/* formerly B_NOTIFY_VDSO_LOC 150 */
#define B_PTRACE_SIG_RETURN 150
#define B_GET_PERSONALITY 151

#ifndef _ASM
Expand Down Expand Up @@ -379,15 +379,17 @@ typedef enum lx_accord_flags {
* Flags values for "br_ptrace_flags" in the LWP-specific data.
*/
typedef enum lx_ptrace_flags {
LX_PTF_SYSCALL = 0x01,
LX_PTF_SYSCALL = 0x01, /* handling syscall or a trap */
LX_PTF_EXITING = 0x02,
LX_PTF_STOPPING = 0x04,
LX_PTF_INHERIT = 0x08,
LX_PTF_STOPPED = 0x10,
LX_PTF_PARENT_WAIT = 0x20,
LX_PTF_CLDPEND = 0x40,
LX_PTF_CLONING = 0x80,
LX_PTF_WAITPEND = 0x100
LX_PTF_WAITPEND = 0x100,
LX_PTF_NOSTOP = 0x200, /* disable syscall stop event */
LX_PTF_INSYSCALL = 0x400 /* between syscall enter & exit */
} lx_ptrace_flags_t;

/*
Expand Down

0 comments on commit 158f4db

Please sign in to comment.