sigaction.sa_restorer problem / new signal handling / WINE

Marcus Meissner (msmeissn@cip.informatik.uni-erlangen.de)
Wed, 4 Feb 1998 11:20:01 +0100 (MET)


Hi Linus,

(cc:ed to linux-kernel and Peter Waltenberg, who pointed this bug out to me)

While debugging a strange memorycorruption under WINE I noticed that the new
signal handling code seems to have changed the semantics of the (well,
obsolete, but neithertheless used by WINE) sigaction.sa_restorer field.

The offending piece of code looks like this in the 2.0 kernel:
(arch/i386/kernel/signal.c, line 163ff)
|static void setup_frame(struct sigaction * sa,
| struct pt_regs * regs, int signr,
| unsigned long oldmask)
|{
| unsigned long * frame;
|
| frame = (unsigned long *) regs->esp;
| if (regs->ss != USER_DS && sa->sa_restorer)
| frame = (unsigned long *) sa->sa_restorer;
| frame -= 64;
| if (verify_area(VERIFY_WRITE,frame,64*4))
| do_exit(SIGSEGV);

Here the signal frame is stored for the WINE 16bit case in
sa->sa_restorer-64*4 up to sa->sa_restorer.

In 2.1.84 the same piece of code looks like this (line 370ff):
|static void setup_frame(int sig, struct k_sigaction *ka,
| sigset_t *set, struct pt_regs * regs)
|{
| struct sigframe *frame;
|
| frame = (struct sigframe *)((regs->esp - sizeof(*frame)) & -8);
|
| /* XXX: Check here if we need to switch stacks.. */
|
| /* This is legacy signal stack switching. */
| if ((regs->xss & 0xffff) != __USER_DS
| && !(ka->sa.sa_flags & SA_RESTORER) && ka->sa.sa_restorer)
| frame = (struct sigframe *) ka->sa.sa_restorer;
|
| if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
| goto segv_and_exit;

Here the signal frame is stored for the WINE 16bit case in
sa->sa_restorer up to sa->sa_restorer+sizeof(*frame), which is rather
different from the behaviour in 2.0.

Was/Is this change of behaviour intended?

Ciao, Marcus