The sigaction(2) manpage states that the signal stack is inherited by
the child after fork(2), but the signal stack is not inherited in fact.

The attached test program checks if the sigaltstack(2) setting is
inherited by the child or not.
The result of the program is:
  original: sp=0x0 size=0 flags=4
   changed: sp=0x8049a20 size=1048576 flags=0
     child: sp=0x8049a20 size=1048576 flags=4    <- flags: 4
    parent: sp=0x8049a20 size=1048576 flags=0

but it should be:
  original: sp=0x0 size=0 flags=4
   changed: sp=0x8049a20 size=1048576 flags=0
     child: sp=0x8049a20 size=1048576 flags=0    <- flags: 0
    parent: sp=0x8049a20 size=1048576 flags=0

The parent had cleared the SS_DISABLE flag of ss_flags (in struct
sigaltstack) and forked the child, but SS_DISABLE is set on the child.

The following patch against sys/kern/kern_fork.c fixes this problem:

Index: sys/kern/kern_fork.c
===================================================================
RCS file: /usr/local/share/cvsup/cvsroot/src/sys/kern/kern_fork.c,v
retrieving revision 1.103
diff -u -r1.103 kern_fork.c
--- sys/kern/kern_fork.c        2001/02/28 02:53:43     1.103
+++ sys/kern/kern_fork.c        2001/03/02 12:45:40
@@ -461,7 +461,7 @@
         * Preserve some more flags in subprocess.  P_PROFIL has already
         * been preserved.
         */
-       p2->p_flag |= p1->p_flag & P_SUGID;
+       p2->p_flag |= p1->p_flag & (P_SUGID | P_ALTSTACK);
        if (p1->p_session->s_ttyvp != NULL && p1->p_flag & P_CONTROLT)
                p2->p_flag |= P_CONTROLT;
        if (flags & RFPPWAIT)

#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <assert.h>

#define ALTSTACKSIZE    (1024 * 1024)
static u_int64_t        altstack[ALTSTACKSIZE / sizeof(u_int64_t)];

static void
print_sigstack(char *info)
{
        struct sigaltstack              ss;
        int                             ret;

        ret = sigaltstack(NULL, &ss);
        if (ret < 0) {
                perror("sigaltstack");
                exit(1);
        }
        printf("%10s: sp=%p size=%d flags=%x\n",
               info, ss.ss_sp, ss.ss_size, ss.ss_flags);
        fflush(stdout);
}

int
main(int argc, char *argv[])
{
        struct sigaltstack              ss;
        pid_t                           pid;
        int                             ret;

        print_sigstack("original");

        ss.ss_sp = (char *)altstack;
        ss.ss_size = sizeof(altstack);
        ss.ss_flags = 0;
        ret = sigaltstack(&ss, NULL);
        if (ret < 0) {
                perror("sigaltstack");
                exit(1);
        }
        print_sigstack("changed");

        pid = fork();
        if (pid < 0) {
                perror("fork");
                exit(1);
        }
        if (pid == 0) {
                print_sigstack("child");
                exit(0);
        }
        wait(NULL);
        print_sigstack("parent");

        return 0;
}

Reply via email to