libproc: Add support for some proc_attach() flags.

This change adds some handling for the equivalent of Solaris' PGRAB_*
flags. In particular, support for PGRAB_RDONLY is needed to avoid a
nasty deadlock: dtrace(1) may otherwise stop the master process for its
pseudo-terminal and end up blocking while writing to standard output.
This commit is contained in:
Mark Johnston 2016-12-06 04:22:38 +00:00
parent c156354ff8
commit b043b5dc6b
5 changed files with 39 additions and 25 deletions
cddl
compat/opensolaris/include
lib/libdtrace
lib/libproc

@ -38,9 +38,6 @@
#define PR_RLC 0x0001 #define PR_RLC 0x0001
#define PR_KLC 0x0002 #define PR_KLC 0x0002
#define PGRAB_RDONLY O_RDONLY
#define PGRAB_FORCE 0
#include_next <libproc.h> #include_next <libproc.h>
#endif #endif

@ -34,6 +34,9 @@
* Functions sorted alphabetically. * Functions sorted alphabetically.
*/ */
#define PR_LMID_EVERY 0 #define PR_LMID_EVERY 0
#define PGRAB_RDONLY PATTACH_RDONLY
#define PGRAB_FORCE PATTACH_FORCE
#define Psetrun(p, a1, a2) proc_continue((p)) #define Psetrun(p, a1, a2) proc_continue((p))
#define Pxlookup_by_addr(p, a, n, s, sym, i) \ #define Pxlookup_by_addr(p, a, n, s, sym, i) \
proc_addr2sym(p, a, n, s, sym) proc_addr2sym(p, a, n, s, sym)

@ -50,6 +50,11 @@ typedef void (*proc_child_func)(void *);
#define PS_DEAD 5 #define PS_DEAD 5
#define PS_LOST 6 #define PS_LOST 6
/* Flags for proc_attach(). */
#define PATTACH_FORCE 0x01
#define PATTACH_RDONLY 0x02
#define PATTACH_NOSTOP 0x04
/* Reason values for proc_detach(). */ /* Reason values for proc_detach(). */
#define PRELEASE_HANG 1 #define PRELEASE_HANG 1
#define PRELEASE_KILL 2 #define PRELEASE_KILL 2

@ -127,7 +127,7 @@ proc_attach(pid_t pid, int flags, struct proc_handle **pphdl)
struct proc_handle *phdl; struct proc_handle *phdl;
int error, status; int error, status;
if (pid == 0 || pid == getpid()) if (pid == 0 || (pid == getpid() && (flags & PATTACH_RDONLY) == 0))
return (EINVAL); return (EINVAL);
if (elf_version(EV_CURRENT) == EV_NONE) if (elf_version(EV_CURRENT) == EV_NONE)
return (ENOENT); return (ENOENT);
@ -140,27 +140,32 @@ proc_attach(pid_t pid, int flags, struct proc_handle **pphdl)
if (error != 0) if (error != 0)
goto out; goto out;
if (ptrace(PT_ATTACH, proc_getpid(phdl), 0, 0) != 0) { if ((flags & PATTACH_RDONLY) == 0) {
error = errno; if (ptrace(PT_ATTACH, proc_getpid(phdl), 0, 0) != 0) {
DPRINTF("ERROR: cannot ptrace child process %d", pid); error = errno;
goto out; DPRINTF("ERROR: cannot ptrace child process %d", pid);
} goto out;
}
/* Wait for the child process to stop. */ /* Wait for the child process to stop. */
if (waitpid(pid, &status, WUNTRACED) == -1) { if (waitpid(pid, &status, WUNTRACED) == -1) {
error = errno; error = errno;
DPRINTF("ERROR: child process %d didn't stop as expected", pid); DPRINTF("ERROR: child process %d didn't stop as expected", pid);
goto out; goto out;
} }
/* Check for an unexpected status. */ /* Check for an unexpected status. */
if (!WIFSTOPPED(status)) if (!WIFSTOPPED(status))
DPRINTFX("ERROR: child process %d status 0x%x", pid, status); DPRINTFX("ERROR: child process %d status 0x%x", pid, status);
else else
phdl->status = PS_STOP; phdl->status = PS_STOP;
if ((flags & PATTACH_NOSTOP) != 0)
proc_continue(phdl);
}
out: out:
if (error && phdl != NULL) { if (error != 0 && phdl != NULL) {
proc_free(phdl); proc_free(phdl);
phdl = NULL; phdl = NULL;
} }

@ -87,21 +87,25 @@ proc_detach(struct proc_handle *phdl, int reason)
if (phdl == NULL) if (phdl == NULL)
return (EINVAL); return (EINVAL);
if (reason == PRELEASE_HANG)
return (EINVAL);
if (reason == PRELEASE_KILL) { if (reason == PRELEASE_KILL) {
kill(proc_getpid(phdl), SIGKILL); kill(proc_getpid(phdl), SIGKILL);
return (0); goto free;
} }
if ((phdl->flags & PATTACH_RDONLY) != 0)
goto free;
pid = proc_getpid(phdl); pid = proc_getpid(phdl);
if (ptrace(PT_DETACH, pid, 0, 0) != 0 && errno == ESRCH) if (ptrace(PT_DETACH, pid, 0, 0) != 0 && errno == ESRCH)
return (0); goto free;
if (errno == EBUSY) { if (errno == EBUSY) {
kill(pid, SIGSTOP); kill(pid, SIGSTOP);
waitpid(pid, &status, WUNTRACED); waitpid(pid, &status, WUNTRACED);
ptrace(PT_DETACH, pid, 0, 0); ptrace(PT_DETACH, pid, 0, 0);
kill(pid, SIGCONT); kill(pid, SIGCONT);
return (0);
} }
free:
proc_free(phdl);
return (0); return (0);
} }