From: Denys Vlasenko Date: Thu, 18 Jul 2013 08:10:46 +0000 (+0200) Subject: sys_rt_sigaction: fix sigset copying X-Git-Tag: v4.9~191 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=80b73a24a9c94e2a76dc8e6b49160e6792cfc3d3;p=strace sys_rt_sigaction: fix sigset copying In practice, we always copy as many bytes as syscall param says (8, or 16 on mips). However, malicious program can call sigaction with wrong sigset size. Such syscall will result in EINVAL, but we (strace) end up copying 128 bytes (sizeof(sigset_t)), which copyes some garbage from stack after struct sigaction. Now we always copy NSIG / 8 bytes (which is 8 bytes, or 16 on mips). Signed-off-by: Denys Vlasenko --- diff --git a/signal.c b/signal.c index 7f8ed52d..66ce6136 100644 --- a/signal.c +++ b/signal.c @@ -1331,23 +1331,18 @@ sys_rt_sigaction(struct tcb *tcp) tprints("{SIG_IGN, "); else tprintf("{%#lx, ", (long) sa.__sa_handler); - /* Questionable code below. - * Kernel won't handle sys_rt_sigaction - * with wrong sigset size (just returns EINVAL) - * therefore tcp->u_arg[3(4)] _must_ be NSIG / 8 here, - * and we always use smaller memcpy. */ + /* + * 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 / 8. + */ sigemptyset(&sigset); -#if defined(SPARC) || defined(SPARC64) - if (tcp->u_arg[4] <= sizeof(sigset)) - memcpy(&sigset, &sa.sa_mask, tcp->u_arg[4]); -#else - if (tcp->u_arg[3] <= sizeof(sigset)) - memcpy(&sigset, &sa.sa_mask, tcp->u_arg[3]); -#endif - else - memcpy(&sigset, &sa.sa_mask, sizeof(sigset)); - printsigmask(&sigset, 1); + memcpy(&sigset, &sa.sa_mask, NSIG / 8); + printsigmask(&sigset, /*rt:*/ 1); tprints(", "); + printflags(sigact_flags, sa.sa_flags, "SA_???"); #ifdef SA_RESTORER if (sa.sa_flags & SA_RESTORER)