[PATCH] set saner MAX_ARGS

Denys Vlasenko dvlasenk at redhat.com
Fri Aug 19 15:38:19 UTC 2011


On Fri, 2011-08-19 at 00:02 +0400, Dmitry V. Levin wrote:
> On Thu, Aug 18, 2011 at 12:47:38PM +0200, Denys Vlasenko wrote:
> > On Thu, 2011-08-18 at 12:23 +0200, Denys Vlasenko wrote:
> > > 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!
> > > 
> > > I propose to change 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 MAX_ARGS == 5 should be enough for saving signal masks.
> 
> I agree.
> 
> > > The proposed patch is below.
> > > 
> > > Alternative solution is to make sys_sigreturn print mask
> > > on entry, not on exit. What is the reson it doesn't do that now?
> 
> Can sys_sigreturn be interrupted somehow?

Does it matter?


Currently, sigreturn in strace looks like this:

wait4(-1, 0xbfa81764, WSTOPPED, NULL)   = ? ERESTARTSYS (To be restarted)
--- {si_signo=SIGINT, si_code=SI_USER, si_pid=13194, si_uid=0} (Interrupt) ---
sigreturn()                             = ? (mask now [])
--- {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=13194, si_status=0, si_utime=0, si_stime=0} (Child exited) ---
sigreturn()                             = ? (mask now [])
wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], WSTOPPED, NULL) = 13194


I propose to change it into something like this:

wait4(-1, 0xbfa81764, WSTOPPED, NULL)   = ? ERESTARTSYS (To be restarted)
--- {si_signo=SIGINT, si_code=SI_USER, si_pid=13194, si_uid=0} (Interrupt) ---
sigreturn([])                           = 0
--- {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=13194, si_status=0, si_utime=0, si_stime=0} (Child exited) ---
sigreturn([])                           = 0
wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], WSTOPPED, NULL) = 13194

because that's how it _really_ happens: the signal mask is actually known
BEFORE sigreturn is executed, so why are we printing it AFTER it returns?
(And in the process, torture ourselves with stupid saving/restoring of
sigmask for that). Look at sys_sigreturn() in strace source to see it.

(The only wart here is that sigmask is not a sigreturn's parameter, so
printing it as "sigreturn([])" is slightly wrong/misleading. Any ideas
how to show it better? With curly braces maybe - {[mask]}?)

Do you like this idea?


> > --- strace.5/defs.h	2011-08-18 11:57:30.512416447 +0200
> > +++ strace.6/defs.h	2011-08-18 11:46:56.349540479 +0200
> > @@ -64,7 +64,7 @@
> >  #define DEFAULT_ACOLUMN	40	/* default alignment column for results */
> >  #endif
> >  #ifndef MAX_ARGS
> > -# ifdef HPPA
> > +# if defined HPPA || defined X86_64 || defined I386
> >  #  define MAX_ARGS	6	/* maximum number of args to a syscall */
> >  # else
> >  /* Way too big. Switch your arch to saner size after you tested that it works */
> 
> What about other architectures?  Is there any with MAX_ARGS > 6?
> Can we assume MAX_ARGS == 6 on linux?

I looked deeper. Apparently FREEBSD needs MAX_ARGS = 8. Also there's
a bug in sys_mmap64 where it will try to access (but not write to)
u_args[6,7] wrongly - see other mail.

My current knowledge is summed up by this comment:

/* 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.
 */

Basically, all linux arches sans ia64 should be ok with MAX_ARGS = 6.

Looks like mips needs fixing - only lone two printargs with nargs = 7??
FREEBSD sys_mmap's nargs look wrong too.

For now, I plan to commit the updated patch which sets MAX_ARGS
to 6 (or 8 for FREEBSD) on X86_64 & I386 only.

-- 
vda






More information about the Strace-devel mailing list