Set saner MAX_ARGS (6 or 8) for X86_64 and I386
I noticed that tcp->u_args[MAX_ARGS] array is way larger than I'd expect: for all arches except HPPA it has 32 (!) elements. I looked at the code and so far I spotted only one abuser of this fact: sys_sigreturn. On several arches, it saves sigset_t into tcp->u_args[1...N] on entry and prints it on exit, a-la memcpy(&tcp->u_arg[1], &sc.oldmask[0], sizeof(sigset_t)) The problem here is that in glibc sigset_t is insanely large: 128 bytes, and using sizeof(sigset_t) in memcpy will overrun &tcp->u_args[1] even with MAX_ARGS == 32: On 32 bits, sizeof(tcp->u_args) == 32*4 == 128 bytes! We may already have a bug there! This commit changes the code to save NSIG / 8 bytes only. NSIG can't ever be > 256, and in practice is <= 129, thus NSIG / 8 is <= 16 bytes == 4 32-bit words, and even MAX_ARGS == 5 should be enough for saving signal masks. * defs.h: Reduce MAX_ARGS for X86_64 and I386 from 32 to 8 for FreeBSD and to 6 for everyone else. Add comment about current state of needed MAX_ARGS. * signal.c: Add comment about size of sigset_t. (sprintsigmask): Reduce static string buffer from 8k to 2k. (sys_sigreturn): Fix sigset saving to save only NSIG / 8 bytes, not sizeof(sigset_t) bytes. * linux/mips/syscallent.h: Reduce nargs of printargs-type syscall to 7. * linux/arm/syscallent.h: Reduce nargs of printargs-type syscall to 6. * linux/i386/syscallent.h: Likewise. * linux/m68k/syscallent.h: Likewise. * linux/powerpc/syscallent.h: Likewise. * linux/s390/syscallent.h: Likewise. * linux/s390x/syscallent.h: Likewise. * linux/sh/syscallent.h: Likewise. * linux/sh64/syscallent.h: Likewise. * linux/sparc/syscallent.h: Likewise. Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
This commit is contained in:
parent
9aa97968ed
commit
d9560c1080
27
defs.h
27
defs.h
@ -48,7 +48,7 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* configuration section */
|
||||
/* Configuration section */
|
||||
#ifndef MAX_QUALS
|
||||
#if defined(LINUX) && defined(MIPS)
|
||||
#define MAX_QUALS 7000 /* maximum number of syscalls, signals, etc. */
|
||||
@ -63,14 +63,35 @@
|
||||
#ifndef DEFAULT_ACOLUMN
|
||||
#define DEFAULT_ACOLUMN 40 /* default alignment column for results */
|
||||
#endif
|
||||
|
||||
/* Maximum number of args to a syscall.
|
||||
*
|
||||
* Make sure that all entries in all syscallent.h files
|
||||
* have nargs <= MAX_ARGS!
|
||||
* linux/<ARCH>/syscallent.h: ia64 has many syscalls with
|
||||
* nargs = 8, mips has two with nargs = 7 (both are printargs),
|
||||
* all others are <= 6.
|
||||
* freebsd/i386/syscallent.h: one syscall with nargs = 8
|
||||
* (sys_sendfile, looks legitimate)
|
||||
* and one with nargs = 7 (sys_mmap, maybe it should have 6?).
|
||||
* sunos4/syscallent.h: all are <= 6.
|
||||
* svr4/syscallent.h: all are -1.
|
||||
*/
|
||||
#ifndef MAX_ARGS
|
||||
# ifdef HPPA
|
||||
# define MAX_ARGS 6 /* maximum number of args to a syscall */
|
||||
# define MAX_ARGS 6
|
||||
# elif defined X86_64 || defined I386
|
||||
# ifdef FREEBSD
|
||||
# define MAX_ARGS 8
|
||||
# else
|
||||
# define MAX_ARGS 6
|
||||
# endif
|
||||
# else
|
||||
/* Way too big. Switch your arch to saner size after you tested that it works */
|
||||
# define MAX_ARGS 32 /* maximum number of args to a syscall */
|
||||
# define MAX_ARGS 32
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_SORTBY
|
||||
#define DEFAULT_SORTBY "time" /* default sorting method for call profiling */
|
||||
#endif
|
||||
|
@ -435,7 +435,7 @@
|
||||
#if SYS_socket_subcall != 400
|
||||
#error fix me
|
||||
#endif
|
||||
{ 8, 0, printargs, "socket_subcall"}, /* 400 */
|
||||
{ 6, 0, printargs, "socket_subcall"}, /* 400 */
|
||||
{ 3, TN, sys_socket, "socket" }, /* 401 */
|
||||
{ 3, TN, sys_bind, "bind" }, /* 402 */
|
||||
{ 3, TN, sys_connect, "connect" }, /* 403 */
|
||||
|
@ -434,7 +434,7 @@
|
||||
#if SYS_socket_subcall != 400
|
||||
#error fix me
|
||||
#endif
|
||||
{ 8, 0, printargs, "socket_subcall"}, /* 400 */
|
||||
{ 6, 0, printargs, "socket_subcall"}, /* 400 */
|
||||
{ 3, TN, sys_socket, "socket" }, /* 401 */
|
||||
{ 3, TN, sys_bind, "bind" }, /* 402 */
|
||||
{ 3, TN, sys_connect, "connect" }, /* 403 */
|
||||
|
@ -432,7 +432,7 @@
|
||||
#if SYS_socket_subcall != 400
|
||||
#error fix me
|
||||
#endif
|
||||
{ 8, 0, printargs, "socket_subcall"}, /* 400 */
|
||||
{ 6, 0, printargs, "socket_subcall"}, /* 400 */
|
||||
{ 3, TN, sys_socket, "socket" }, /* 401 */
|
||||
{ 3, TN, sys_bind, "bind" }, /* 402 */
|
||||
{ 3, TN, sys_connect, "connect" }, /* 403 */
|
||||
|
@ -4002,7 +4002,7 @@
|
||||
{ 0, 0, printargs, "SYS_3999" }, /* 3999 */ /* end of POSIX */
|
||||
#if !defined (LINUX_MIPSN32) && !defined (LINUX_MIPSN64)
|
||||
/* For an O32 strace, decode the o32 syscalls. */
|
||||
{ 8, 0, printargs, "syscall" }, /* 4000 */ /* start of Linux o32 */
|
||||
{ 7, 0, printargs, "syscall" }, /* 4000 */ /* start of Linux o32 */
|
||||
{ 1, TP, sys_exit, "exit" }, /* 4001 */
|
||||
{ 0, TP, sys_fork, "fork" }, /* 4002 */
|
||||
{ 3, TD, sys_read, "read" }, /* 4003 */
|
||||
|
@ -229,7 +229,7 @@
|
||||
{ 5, 0, printargs, "pciconfig_read" }, /* 198 */
|
||||
{ 5, 0, printargs, "pciconfig_write" }, /* 199 */
|
||||
{ 3, 0, printargs, "pciconfig_iobase" }, /* 200 */
|
||||
{ 8, 0, printargs, "MOL" }, /* 201 */
|
||||
{ 6, 0, printargs, "MOL" }, /* 201 */
|
||||
{ 3, TD, sys_getdents64, "getdents64" }, /* 202 */
|
||||
{ 2, TF, sys_pivotroot, "pivot_root" }, /* 203 */
|
||||
{ 3, TD, sys_fcntl, "fcntl64" }, /* 204 */
|
||||
@ -432,7 +432,7 @@
|
||||
#if SYS_socket_subcall != 400
|
||||
#error fix me
|
||||
#endif
|
||||
{ 8, 0, printargs, "socket_subcall"}, /* 400 */
|
||||
{ 6, 0, printargs, "socket_subcall"}, /* 400 */
|
||||
{ 3, TN, sys_socket, "socket" }, /* 401 */
|
||||
{ 3, TN, sys_bind, "bind" }, /* 402 */
|
||||
{ 3, TN, sys_connect, "connect" }, /* 403 */
|
||||
|
@ -432,7 +432,7 @@
|
||||
#if SYS_socket_subcall != 400
|
||||
#error fix me
|
||||
#endif
|
||||
{ 8, 0, printargs, "socket_subcall"}, /* 400 */
|
||||
{ 6, 0, printargs, "socket_subcall"}, /* 400 */
|
||||
{ 3, TN, sys_socket, "socket" }, /* 401 */
|
||||
{ 3, TN, sys_bind, "bind" }, /* 402 */
|
||||
{ 3, TN, sys_connect, "connect" }, /* 403 */
|
||||
|
@ -431,7 +431,7 @@
|
||||
#if SYS_socket_subcall != 400
|
||||
#error fix me
|
||||
#endif
|
||||
{ 8, 0, printargs, "socket_subcall"}, /* 400 */
|
||||
{ 6, 0, printargs, "socket_subcall"}, /* 400 */
|
||||
{ 3, TN, sys_socket, "socket" }, /* 401 */
|
||||
{ 3, TN, sys_bind, "bind" }, /* 402 */
|
||||
{ 3, TN, sys_connect, "connect" }, /* 403 */
|
||||
|
@ -436,7 +436,7 @@
|
||||
#if SYS_socket_subcall != 400
|
||||
#error fix me
|
||||
#endif
|
||||
{ 8, 0, printargs, "socket_subcall"}, /* 400 */
|
||||
{ 6, 0, printargs, "socket_subcall"}, /* 400 */
|
||||
{ 3, TN, sys_socket, "socket" }, /* 401 */
|
||||
{ 3, TN, sys_bind, "bind" }, /* 402 */
|
||||
{ 3, TN, sys_connect, "connect" }, /* 403 */
|
||||
|
@ -432,7 +432,7 @@
|
||||
#if SYS_socket_subcall != 400
|
||||
#error fix me
|
||||
#endif
|
||||
{ 8, 0, printargs, "socket_subcall"}, /* 400 */
|
||||
{ 6, 0, printargs, "socket_subcall"}, /* 400 */
|
||||
{ 3, TN, sys_socket, "socket" }, /* 401 */
|
||||
{ 3, TN, sys_bind, "bind" }, /* 402 */
|
||||
{ 3, TN, sys_connect, "connect" }, /* 403 */
|
||||
|
@ -354,7 +354,7 @@
|
||||
#if SYS_socket_subcall != 353
|
||||
#error fix me
|
||||
#endif
|
||||
{ 8, 0, printargs, "socket_subcall"}, /* 353 */
|
||||
{ 6, 0, printargs, "socket_subcall"}, /* 353 */
|
||||
{ 3, TN, sys_socket, "socket" }, /* 354 */
|
||||
{ 3, TN, sys_bind, "bind" }, /* 355 */
|
||||
{ 3, TN, sys_connect, "connect" }, /* 356 */
|
||||
|
46
signal.c
46
signal.c
@ -262,6 +262,28 @@ static const struct xlat sigprocmaskcmds[] = {
|
||||
#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 / 8) as a size instead.
|
||||
*/
|
||||
|
||||
const char *
|
||||
signame(int sig)
|
||||
{
|
||||
@ -310,11 +332,21 @@ static const char *
|
||||
sprintsigmask(const char *str, sigset_t *mask, int rt)
|
||||
/* set might include realtime sigs */
|
||||
{
|
||||
/* Was [8 * sizeof(sigset_t) * 8], but
|
||||
* glibc sigset_t is huge (1024 bits = 128 *bytes*),
|
||||
* and we were ending up with 8k (!) buffer here.
|
||||
*
|
||||
* No Unix system can have sig > 255
|
||||
* (waitpid API won't be able to indicate death from one)
|
||||
* and sig 0 doesn't exist either.
|
||||
* Therefore max possible no of sigs is 255: 1..255
|
||||
*/
|
||||
static char outstr[8 * 255];
|
||||
|
||||
int i, nsigs;
|
||||
int maxsigs;
|
||||
const char *format;
|
||||
char *s;
|
||||
static char outstr[8 * sizeof(sigset_t) * 8];
|
||||
|
||||
strcpy(outstr, str);
|
||||
s = outstr + strlen(outstr);
|
||||
@ -1134,7 +1166,7 @@ sys_sigreturn(struct tcb *tcp)
|
||||
if (umove(tcp, usp+__SIGNAL_FRAMESIZE, &sc) < 0)
|
||||
return 0;
|
||||
tcp->u_arg[0] = 1;
|
||||
memcpy(&tcp->u_arg[1], &sc.oldmask[0], sizeof(sigset_t));
|
||||
memcpy(&tcp->u_arg[1], &sc.oldmask[0], NSIG / 8);
|
||||
} else {
|
||||
tcp->u_rval = tcp->u_error = 0;
|
||||
if (tcp->u_arg[0] == 0)
|
||||
@ -1177,14 +1209,15 @@ sys_sigreturn(struct tcb *tcp)
|
||||
if (umove(tcp, sp + 16 + SIGFRAME_SC_OFFSET, &sc) < 0)
|
||||
return 0;
|
||||
tcp->u_arg[0] = 1;
|
||||
memcpy(tcp->u_arg + 1, &sc.sc_mask, sizeof(sc.sc_mask));
|
||||
memcpy(tcp->u_arg + 1, &sc.sc_mask, NSIG / 8);
|
||||
}
|
||||
else {
|
||||
sigset_t sigm;
|
||||
tcp->u_rval = tcp->u_error = 0;
|
||||
if (tcp->u_arg[0] == 0)
|
||||
return 0;
|
||||
memcpy(&sigm, tcp->u_arg + 1, sizeof(sigm));
|
||||
sigemptyset(&sigm);
|
||||
memcpy(&sigm, tcp->u_arg + 1, NSIG / 8);
|
||||
tcp->auxstr = sprintsigmask("mask now ", &sigm, 0);
|
||||
return RVAL_NONE | RVAL_STR;
|
||||
}
|
||||
@ -1377,14 +1410,15 @@ sys_sigreturn(struct tcb *tcp)
|
||||
if (umove(tcp, sp + SIGFRAME_UC_OFFSET, &uc) < 0)
|
||||
return 0;
|
||||
tcp->u_arg[0] = 1;
|
||||
memcpy(tcp->u_arg + 1, &uc.uc_sigmask, sizeof(uc.uc_sigmask));
|
||||
memcpy(tcp->u_arg + 1, &uc.uc_sigmask, NSIG / 8);
|
||||
}
|
||||
else {
|
||||
sigset_t sigm;
|
||||
tcp->u_rval = tcp->u_error = 0;
|
||||
if (tcp->u_arg[0] == 0)
|
||||
return 0;
|
||||
memcpy(&sigm, tcp->u_arg + 1, sizeof(sigm));
|
||||
sigemptyset(&sigm);
|
||||
memcpy(&sigm, tcp->u_arg + 1, NSIG / 8);
|
||||
tcp->auxstr = sprintsigmask("mask now ", &sigm, 0);
|
||||
return RVAL_NONE | RVAL_STR;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user