strace/signal.c
Dmitry V. Levin b93d52fe3d Change the license of strace to LGPL-2.1-or-later
strace is now provided under the terms of the GNU Lesser General
Public License version 2.1 or later, see COPYING for more details.

strace test suite is now provided under the terms of the GNU General
Public License version 2 or later, see tests/COPYING for more details.
2018-12-10 00:00:00 +00:00

671 lines
16 KiB
C

/*
* Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
* Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
* Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
* Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
* Copyright (c) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Linux for s390 port by D.J. Barrow
* <barrow_dj@mail.yahoo.com,djbarrow@de.ibm.com>
* Copyright (c) 2001-2018 The strace developers.
* All rights reserved.
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#include "defs.h"
#include "nsig.h"
#include "xstring.h"
/* The libc headers do not define this constant since it should only be
used by the implementation. So we define it here. */
#ifndef SA_RESTORER
# ifdef ASM_SA_RESTORER
# define SA_RESTORER ASM_SA_RESTORER
# endif
#endif
/*
* Some architectures define SA_RESTORER in their headers,
* but do not actually have sa_restorer.
*
* Some architectures, otherwise, do not define SA_RESTORER in their headers,
* but actually have sa_restorer.
*/
#ifdef HAVE_ARCH_SA_RESTORER
# define HAVE_SA_RESTORER HAVE_ARCH_SA_RESTORER
#else /* !HAVE_ARCH_SA_RESTORER */
# ifdef SA_RESTORER
# define HAVE_SA_RESTORER 1
# else
# define HAVE_SA_RESTORER 0
# endif
#endif /* HAVE_ARCH_SA_RESTORER */
#include "xlat/sa_handler_values.h"
#include "xlat/sigact_flags.h"
#include "xlat/sigprocmaskcmds.h"
/* Anonymous realtime signals. */
#ifndef ASM_SIGRTMIN
/* Linux kernel >= 3.18 defines SIGRTMIN to 32 on all architectures. */
# define ASM_SIGRTMIN 32
#endif
#ifndef ASM_SIGRTMAX
/* Under glibc 2.1, SIGRTMAX et al are functions, but __SIGRTMAX is a
constant. This is what we want. Otherwise, just use SIGRTMAX. */
# ifdef SIGRTMAX
# ifndef __SIGRTMAX
# define __SIGRTMAX SIGRTMAX
# endif
# endif
# ifdef __SIGRTMAX
# define ASM_SIGRTMAX __SIGRTMAX
# endif
#endif
/* Note on the size of sigset_t:
*
* In glibc, sigset_t is an array with space for 1024 bits (!),
* even though all arches supported by Linux have only 64 signals
* except MIPS, which has 128. IOW, it is 128 bytes long.
*
* In-kernel sigset_t is sized correctly (it is either 64 or 128 bit long).
* However, some old syscall return only 32 lower bits (one word).
* Example: sys_sigpending vs sys_rt_sigpending.
*
* Be aware of this fact when you try to
* memcpy(&tcp->u_arg[1], &something, sizeof(sigset_t))
* - sizeof(sigset_t) is much bigger than you think,
* it may overflow tcp->u_arg[] array, and it may try to copy more data
* than is really available in <something>.
* Similarly,
* umoven(tcp, addr, sizeof(sigset_t), &sigset)
* may be a bad idea: it'll try to read much more data than needed
* to fetch a sigset_t.
* Use NSIG_BYTES as a size instead.
*/
static const char *
get_sa_handler_str(kernel_ulong_t handler)
{
return xlookup(sa_handler_values, handler);
}
static void
print_sa_handler(kernel_ulong_t handler)
{
const char *sa_handler_str = get_sa_handler_str(handler);
if (sa_handler_str)
print_xlat_ex(handler, sa_handler_str, XLAT_STYLE_DEFAULT);
else
printaddr(handler);
}
const char *
signame(const int sig)
{
static char buf[sizeof("SIGRT_%u") + sizeof(int)*3];
if (sig >= 0) {
const unsigned int s = sig;
if (s < nsignals)
return signalent[s];
#ifdef ASM_SIGRTMAX
if (s >= ASM_SIGRTMIN && s <= (unsigned int) ASM_SIGRTMAX) {
xsprintf(buf, "SIGRT_%u", s - ASM_SIGRTMIN);
return buf;
}
#endif
}
xsprintf(buf, "%d", sig);
return buf;
}
static unsigned int
popcount32(const uint32_t *a, unsigned int size)
{
unsigned int count = 0;
for (; size; ++a, --size) {
uint32_t x = *a;
#ifdef HAVE___BUILTIN_POPCOUNT
count += __builtin_popcount(x);
#else
for (; x; ++count)
x &= x - 1;
#endif
}
return count;
}
const char *
sprintsigmask_n(const char *prefix, const void *sig_mask, unsigned int bytes)
{
/*
* The maximum number of signal names to be printed
* is NSIG_BYTES * 8 * 2 / 3.
* Most of signal names have length 7,
* average length of signal names is less than 7.
* The length of prefix string does not exceed 16.
*/
static char outstr[128 + 8 * (NSIG_BYTES * 8 * 2 / 3)];
char *s;
const uint32_t *mask;
uint32_t inverted_mask[NSIG_BYTES / 4];
unsigned int size;
int i;
char sep;
s = stpcpy(outstr, prefix);
mask = sig_mask;
/* length of signal mask in 4-byte words */
size = (bytes >= NSIG_BYTES) ? NSIG_BYTES / 4 : (bytes + 3) / 4;
/* check whether 2/3 or more bits are set */
if (popcount32(mask, size) >= size * (4 * 8) * 2 / 3) {
/* show those signals that are NOT in the mask */
unsigned int j;
for (j = 0; j < size; ++j)
inverted_mask[j] = ~mask[j];
mask = inverted_mask;
*s++ = '~';
}
sep = '[';
for (i = 0; (i = next_set_bit(mask, i, size * (4 * 8))) >= 0; ) {
++i;
*s++ = sep;
if ((unsigned) i < nsignals) {
s = stpcpy(s, signalent[i] + 3);
}
#ifdef ASM_SIGRTMAX
else if (i >= ASM_SIGRTMIN && i <= ASM_SIGRTMAX) {
s = xappendstr(outstr, s, "RT_%u", i - ASM_SIGRTMIN);
}
#endif
else {
s = xappendstr(outstr, s, "%u", i);
}
sep = ' ';
}
if (sep == '[')
*s++ = sep;
*s++ = ']';
*s = '\0';
return outstr;
}
#define sprintsigmask_val(prefix, mask) \
sprintsigmask_n((prefix), &(mask), sizeof(mask))
#define tprintsigmask_val(prefix, mask) \
tprints(sprintsigmask_n((prefix), &(mask), sizeof(mask)))
static const char *
sprint_old_sigmask_val(const char *const prefix, const unsigned long mask)
{
#if defined(current_wordsize) || !defined(WORDS_BIGENDIAN)
return sprintsigmask_n(prefix, &mask, current_wordsize);
#else /* !current_wordsize && WORDS_BIGENDIAN */
if (current_wordsize == sizeof(mask)) {
return sprintsigmask_val(prefix, mask);
} else {
uint32_t mask32 = mask;
return sprintsigmask_val(prefix, mask32);
}
#endif
}
#define tprint_old_sigmask_val(prefix, mask) \
tprints(sprint_old_sigmask_val((prefix), (mask)))
void
printsignal(int nr)
{
tprints(signame(nr));
}
static void
print_sigset_addr_len_limit(struct tcb *const tcp, const kernel_ulong_t addr,
const kernel_ulong_t len, const unsigned int min_len)
{
/*
* Here len is usually equal to NSIG_BYTES or current_wordsize.
* But we code this defensively:
*/
if (len < min_len || len > NSIG_BYTES) {
printaddr(addr);
return;
}
int mask[NSIG_BYTES / sizeof(int)] = {};
if (umoven_or_printaddr(tcp, addr, len, mask))
return;
tprints(sprintsigmask_n("", mask, len));
}
void
print_sigset_addr_len(struct tcb *const tcp, const kernel_ulong_t addr,
const kernel_ulong_t len)
{
print_sigset_addr_len_limit(tcp, addr, len, current_wordsize);
}
void
print_sigset_addr(struct tcb *const tcp, const kernel_ulong_t addr)
{
print_sigset_addr_len_limit(tcp, addr, NSIG_BYTES, NSIG_BYTES);
}
SYS_FUNC(ssetmask)
{
if (entering(tcp)) {
tprint_old_sigmask_val("", (unsigned) tcp->u_arg[0]);
} else if (!syserror(tcp)) {
tcp->auxstr = sprint_old_sigmask_val("old mask ",
(unsigned) tcp->u_rval);
return RVAL_HEX | RVAL_STR;
}
return 0;
}
struct old_sigaction {
/* sa_handler may be a libc #define, need to use other name: */
#if defined MIPS
unsigned int sa_flags;
unsigned long sa_handler__;
unsigned long sa_mask;
#elif defined ALPHA
unsigned long sa_handler__;
unsigned long sa_mask;
unsigned int sa_flags;
#else
unsigned long sa_handler__;
unsigned long sa_mask;
unsigned long sa_flags;
unsigned long sa_restorer;
#endif
}
#ifdef ALPHA
ATTRIBUTE_PACKED
#endif
;
static void
decode_old_sigaction(struct tcb *const tcp, const kernel_ulong_t addr)
{
struct old_sigaction sa;
#ifndef current_wordsize
if (current_wordsize < sizeof(sa.sa_handler__)) {
struct old_sigaction32 {
uint32_t sa_handler__;
uint32_t sa_mask;
uint32_t sa_flags;
uint32_t sa_restorer;
} sa32;
if (umove_or_printaddr(tcp, addr, &sa32))
return;
memset(&sa, 0, sizeof(sa));
sa.sa_handler__ = sa32.sa_handler__;
sa.sa_flags = sa32.sa_flags;
sa.sa_restorer = sa32.sa_restorer;
sa.sa_mask = sa32.sa_mask;
} else
#endif
if (umove_or_printaddr(tcp, addr, &sa))
return;
tprints("{sa_handler=");
print_sa_handler(sa.sa_handler__);
tprints(", sa_mask=");
tprint_old_sigmask_val("", sa.sa_mask);
tprints(", sa_flags=");
printflags(sigact_flags, sa.sa_flags, "SA_???");
#if !(defined ALPHA || defined MIPS)
if (sa.sa_flags & 0x04000000U) {
tprints(", sa_restorer=");
printaddr(sa.sa_restorer);
}
#endif
tprints("}");
}
SYS_FUNC(sigaction)
{
if (entering(tcp)) {
int signo = tcp->u_arg[0];
#if defined SPARC || defined SPARC64
if (signo < 0) {
tprints("-");
signo = -signo;
}
#endif
printsignal(signo);
tprints(", ");
decode_old_sigaction(tcp, tcp->u_arg[1]);
tprints(", ");
} else
decode_old_sigaction(tcp, tcp->u_arg[2]);
return 0;
}
SYS_FUNC(signal)
{
if (entering(tcp)) {
printsignal(tcp->u_arg[0]);
tprints(", ");
print_sa_handler(tcp->u_arg[1]);
return 0;
} else if (!syserror(tcp)) {
tcp->auxstr = get_sa_handler_str(tcp->u_rval);
return RVAL_HEX | RVAL_STR;
}
return 0;
}
SYS_FUNC(sgetmask)
{
if (exiting(tcp) && !syserror(tcp)) {
tcp->auxstr = sprint_old_sigmask_val("mask ", tcp->u_rval);
return RVAL_HEX | RVAL_STR;
}
return 0;
}
SYS_FUNC(sigsuspend)
{
#ifdef MIPS
print_sigset_addr_len(tcp, tcp->u_arg[tcp->s_ent->nargs - 1],
current_wordsize);
#else
tprint_old_sigmask_val("", tcp->u_arg[tcp->s_ent->nargs - 1]);
#endif
return RVAL_DECODED;
}
#ifdef ALPHA
/*
* The OSF/1 sigprocmask is different: it doesn't pass in two pointers,
* but rather passes in the new bitmask as an argument and then returns
* the old bitmask. This "works" because we only have 64 signals to worry
* about. If you want more, use of the rt_sigprocmask syscall is required.
*
* Alpha:
* old = osf_sigprocmask(how, new);
* Everyone else:
* ret = sigprocmask(how, &new, &old, ...);
*/
SYS_FUNC(osf_sigprocmask)
{
if (entering(tcp)) {
printxval(sigprocmaskcmds, tcp->u_arg[0], "SIG_???");
tprintsigmask_val(", ", tcp->u_arg[1]);
} else if (!syserror(tcp)) {
tcp->auxstr = sprintsigmask_val("old mask ", tcp->u_rval);
return RVAL_HEX | RVAL_STR;
}
return 0;
}
#else /* !ALPHA */
/* "Old" sigprocmask, which operates with word-sized signal masks */
SYS_FUNC(sigprocmask)
{
if (entering(tcp)) {
printxval(sigprocmaskcmds, tcp->u_arg[0], "SIG_???");
tprints(", ");
print_sigset_addr_len(tcp, tcp->u_arg[1], current_wordsize);
tprints(", ");
} else {
print_sigset_addr_len(tcp, tcp->u_arg[2], current_wordsize);
}
return 0;
}
#endif /* !ALPHA */
SYS_FUNC(kill)
{
tprintf("%d, %s",
(int) tcp->u_arg[0],
signame(tcp->u_arg[1]));
return RVAL_DECODED;
}
SYS_FUNC(tgkill)
{
tprintf("%d, %d, %s",
(int) tcp->u_arg[0],
(int) tcp->u_arg[1],
signame(tcp->u_arg[2]));
return RVAL_DECODED;
}
SYS_FUNC(sigpending)
{
if (exiting(tcp))
print_sigset_addr_len(tcp, tcp->u_arg[0], current_wordsize);
return 0;
}
SYS_FUNC(rt_sigprocmask)
{
/* Note: arg[3] is the length of the sigset. Kernel requires NSIG_BYTES */
if (entering(tcp)) {
printxval(sigprocmaskcmds, tcp->u_arg[0], "SIG_???");
tprints(", ");
print_sigset_addr_len(tcp, tcp->u_arg[1], tcp->u_arg[3]);
tprints(", ");
} else {
print_sigset_addr_len(tcp, tcp->u_arg[2], tcp->u_arg[3]);
tprintf(", %" PRI_klu, tcp->u_arg[3]);
}
return 0;
}
/* Structure describing the action to be taken when a signal arrives. */
struct new_sigaction {
/* sa_handler may be a libc #define, need to use other name: */
#ifdef MIPS
unsigned int sa_flags;
unsigned long sa_handler__;
#else
unsigned long sa_handler__;
unsigned long sa_flags;
#endif /* !MIPS */
#if HAVE_SA_RESTORER
unsigned long sa_restorer;
#endif
/* Kernel treats sa_mask as an array of longs. */
unsigned long sa_mask[NSIG / sizeof(long)];
};
/* Same for i386-on-x86_64 and similar cases */
struct new_sigaction32 {
uint32_t sa_handler__;
uint32_t sa_flags;
#if HAVE_SA_RESTORER
uint32_t sa_restorer;
#endif
uint32_t sa_mask[2 * (NSIG / sizeof(long))];
};
static void
decode_new_sigaction(struct tcb *const tcp, const kernel_ulong_t addr)
{
struct new_sigaction sa;
#ifndef current_wordsize
if (current_wordsize < sizeof(sa.sa_handler__)) {
struct new_sigaction32 sa32;
if (umove_or_printaddr(tcp, addr, &sa32))
return;
memset(&sa, 0, sizeof(sa));
sa.sa_handler__ = sa32.sa_handler__;
sa.sa_flags = sa32.sa_flags;
#if HAVE_SA_RESTORER && defined SA_RESTORER
sa.sa_restorer = sa32.sa_restorer;
#endif
/* Kernel treats sa_mask as an array of longs.
* For 32-bit process, "long" is uint32_t, thus, for example,
* 32th bit in sa_mask will end up as bit 0 in sa_mask[1].
* But for (64-bit) kernel, 32th bit in sa_mask is
* 32th bit in 0th (64-bit) long!
* For little-endian, it's the same.
* For big-endian, we swap 32-bit words.
*/
sa.sa_mask[0] = ULONG_LONG(sa32.sa_mask[0], sa32.sa_mask[1]);
} else
#endif
if (umove_or_printaddr(tcp, addr, &sa))
return;
tprints("{sa_handler=");
print_sa_handler(sa.sa_handler__);
tprints(", sa_mask=");
/*
* Sigset size is in tcp->u_arg[4] (SPARC)
* or in tcp->u_arg[3] (all other),
* but kernel won't handle sys_rt_sigaction
* with wrong sigset size (just returns EINVAL instead).
* We just fetch the right size, which is NSIG_BYTES.
*/
tprintsigmask_val("", sa.sa_mask);
tprints(", sa_flags=");
printflags(sigact_flags, sa.sa_flags, "SA_???");
#if HAVE_SA_RESTORER && defined SA_RESTORER
if (sa.sa_flags & SA_RESTORER) {
tprints(", sa_restorer=");
printaddr(sa.sa_restorer);
}
#endif
tprints("}");
}
SYS_FUNC(rt_sigaction)
{
if (entering(tcp)) {
printsignal(tcp->u_arg[0]);
tprints(", ");
decode_new_sigaction(tcp, tcp->u_arg[1]);
tprints(", ");
} else {
decode_new_sigaction(tcp, tcp->u_arg[2]);
#if defined(SPARC) || defined(SPARC64)
tprintf(", %#" PRI_klx ", %" PRI_klu, tcp->u_arg[3], tcp->u_arg[4]);
#elif defined(ALPHA)
tprintf(", %" PRI_klu ", %#" PRI_klx, tcp->u_arg[3], tcp->u_arg[4]);
#else
tprintf(", %" PRI_klu, tcp->u_arg[3]);
#endif
}
return 0;
}
SYS_FUNC(rt_sigpending)
{
if (exiting(tcp)) {
/*
* One of the few syscalls where sigset size (arg[1])
* is allowed to be <= NSIG_BYTES, not strictly ==.
* This allows non-rt sigpending() syscall
* to reuse rt_sigpending() code in kernel.
*/
print_sigset_addr_len_limit(tcp, tcp->u_arg[0],
tcp->u_arg[1], 1);
tprintf(", %" PRI_klu, tcp->u_arg[1]);
}
return 0;
}
SYS_FUNC(rt_sigsuspend)
{
/* NB: kernel requires arg[1] == NSIG_BYTES */
print_sigset_addr_len(tcp, tcp->u_arg[0], tcp->u_arg[1]);
tprintf(", %" PRI_klu, tcp->u_arg[1]);
return RVAL_DECODED;
}
static void
print_sigqueueinfo(struct tcb *const tcp, const int sig,
const kernel_ulong_t addr)
{
printsignal(sig);
tprints(", ");
printsiginfo_at(tcp, addr);
}
SYS_FUNC(rt_sigqueueinfo)
{
tprintf("%d, ", (int) tcp->u_arg[0]);
print_sigqueueinfo(tcp, tcp->u_arg[1], tcp->u_arg[2]);
return RVAL_DECODED;
}
SYS_FUNC(rt_tgsigqueueinfo)
{
tprintf("%d, %d, ", (int) tcp->u_arg[0], (int) tcp->u_arg[1]);
print_sigqueueinfo(tcp, tcp->u_arg[2], tcp->u_arg[3]);
return RVAL_DECODED;
}
SYS_FUNC(rt_sigtimedwait)
{
/* NB: kernel requires arg[3] == NSIG_BYTES */
if (entering(tcp)) {
print_sigset_addr_len(tcp, tcp->u_arg[0], tcp->u_arg[3]);
tprints(", ");
if (!(tcp->u_arg[1] && verbose(tcp))) {
/*
* This is the only "return" parameter,
* if we are not going to fetch it on exit,
* decode all parameters on entry.
*/
printaddr(tcp->u_arg[1]);
tprints(", ");
print_timespec(tcp, tcp->u_arg[2]);
tprintf(", %" PRI_klu, tcp->u_arg[3]);
} else {
char *sts = xstrdup(sprint_timespec(tcp, tcp->u_arg[2]));
set_tcb_priv_data(tcp, sts, free);
}
} else {
if (tcp->u_arg[1] && verbose(tcp)) {
printsiginfo_at(tcp, tcp->u_arg[1]);
tprints(", ");
tprints(get_tcb_priv_data(tcp));
tprintf(", %" PRI_klu, tcp->u_arg[3]);
}
if (!syserror(tcp) && tcp->u_rval) {
tcp->auxstr = signame(tcp->u_rval);
return RVAL_STR;
}
}
return 0;
}
SYS_FUNC(restart_syscall)
{
tprintf("<... resuming interrupted %s ...>",
tcp->s_prev_ent ? tcp->s_prev_ent->sys_name : "system call");
return RVAL_DECODED;
}