altstack: Restore alternate signal stack state
authorDavid Gibson <david@gibson.dropbear.id.au>
Fri, 3 Jun 2016 08:42:00 +0000 (18:42 +1000)
committerDan Good <dan@dancancode.com>
Thu, 16 Jun 2016 20:18:52 +0000 (20:18 +0000)
altstack relies on catching a SIGSEGV caused when overrunning the stack.
This means that the SEGV handler itself can't use the already overflowed
stack, and so we use sigaltstack() to assign the signal handler a different
stack.  On completion, altstack() clears the alternate signal stack.

However, it's possible that the calling program could be using
sigaltstack() for its own reasons, so it's more correct to restore the
sigaltstack() state to that from the beginning of the altstack() call.
This patch implements this behaviour.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
ccan/altstack/altstack.c

index edd79f6813d0b2e09e4e7391a1f25f39153b6d1c..62db343cb2c9523a2d4ba11002c27d83c87ac43e 100644 (file)
@@ -71,6 +71,7 @@ int altstack(rlim_t max, void *(*fn)(void *), void *arg, void **out)
        struct rlimit rl_save;
        struct sigaction sa_save;
        int errno_save;
+       stack_t ss_save;
 
        assert(max > 0 && fn);
        #define ok(x, y) ({ long __r = (long) (x); if (__r == -1) { bang(#x); if (y) goto out; } __r; })
@@ -98,7 +99,7 @@ int altstack(rlim_t max, void *(*fn)(void *), void *arg, void **out)
                stack_t ss = { .ss_sp = sigstk, .ss_size = sizeof(sigstk) };
                struct sigaction sa = { .sa_handler = segvjmp, .sa_flags = SA_NODEFER|SA_RESETHAND|SA_ONSTACK };
 
-               ok(sigaltstack(&ss, 0), 1);
+               ok(sigaltstack(&ss, &ss_save), 1);
                undo++;
 
                sigemptyset(&sa.sa_mask);
@@ -131,7 +132,7 @@ out:
        case 4:
                ok(sigaction(SIGSEGV, &sa_save, 0), 0);
        case 3:
-               ok(sigaltstack(&(stack_t) { .ss_flags = SS_DISABLE }, 0), 0);
+               ok(sigaltstack(&ss_save, 0), 0);
        case 2:
                ok(munmap(m, max), 0);
        case 1: