Ticket #136: 0001-Reset-the-SIGCHLD-handler-while-running-aklog.patch

File 0001-Reset-the-SIGCHLD-handler-while-running-aklog.patch, 2.8 KB (added by broder, 14 years ago)
  • tokens.c

    From 043184ad65a59162d8c34b9ef9b7e8bc69748c83 Mon Sep 17 00:00:00 2001
    From: Evan Broder <broder@mit.edu>
    Date: Thu, 25 Mar 2010 15:09:26 -0400
    Subject: [PATCH] Reset the SIGCHLD handler while running aklog.
    
    If the SIGCHLD handler isn't set to SIG_DFL and the child returns
    before the parent gets around to calling waitpid(), waitpid will
    immediately error out with ECHILD.
    
    Some versions of GDM use a custom SIGCHLD handler, which they leave in
    place when running the PAM stack, triggering this race condition.
    
    Work around the race by setting the SIGCHLD handler to SIG_DFL before
    running aklog, then set it back to the original handler when done.
    ---
     tokens.c |   26 ++++++++++++++++++++------
     1 files changed, 20 insertions(+), 6 deletions(-)
    
    diff --git a/tokens.c b/tokens.c
    index 7a523fc..6078589 100644
    a b pamafs_should_ignore(struct pam_args *args, const struct passwd *pwd) 
    102102static int 
    103103pamafs_run_aklog(pam_handle_t *pamh, struct pam_args *args, struct passwd *pwd) 
    104104{ 
    105     int res, argc, arg, i; 
     105    int res, argc, arg, i, ret = PAM_SUCCESS; 
    106106    char **env; 
    107107    const char **argv; 
    108108    pid_t child; 
     109    struct sigaction act, oldact; 
    109110 
    110111    /* Sanity check that we have some program to run. */ 
    111112    if (args->program == NULL) { 
    pamafs_run_aklog(pam_handle_t *pamh, struct pam_args *args, struct passwd *pwd) 
    135136    argv[arg] = NULL; 
    136137 
    137138    /* 
     139     * Set the SIGCHLD handler back to SIG_DFL. If the handler is set 
     140     * to something else and the child returns before the parent calls 
     141     * waitpid, waitpid will error with ECHILD, introducing a race 
     142     * condition. GDM has been known to do this. 
     143     */ 
     144    memset(&act, 0, sizeof(act)); 
     145    act.sa_handler = SIG_DFL; 
     146    sigaction(SIGCHLD, &act, &oldact); 
     147 
     148    /* 
    138149     * Run the program.  Be sure to use _exit instead of exit in the 
    139150     * subprocess so that we won't run exit handlers or double-flush stdio 
    140151     * buffers in the child process. 
    pamafs_run_aklog(pam_handle_t *pamh, struct pam_args *args, struct passwd *pwd) 
    145156    child = fork(); 
    146157    if (child < 0) { 
    147158        pamafs_error("cannot fork: %s", strerror(errno)); 
    148         return PAM_SESSION_ERR; 
     159        ret = PAM_SESSION_ERR; 
     160        goto done; 
    149161    } else if (child == 0) { 
    150162        if (setuid(pwd->pw_uid) < 0) { 
    151163            pamafs_error("cannot setuid to UID %lu: %s", 
    pamafs_run_aklog(pam_handle_t *pamh, struct pam_args *args, struct passwd *pwd) 
    164176    } 
    165177    free(argv); 
    166178    pamafs_free_envlist(env); 
    167     if (waitpid(child, &res, 0) && WIFEXITED(res) && WEXITSTATUS(res) == 0) 
    168         return PAM_SUCCESS; 
    169     else 
    170         return PAM_SESSION_ERR; 
     179    if (!waitpid(child, &res, 0) || !WIFEXITED(res) || WEXITSTATUS(res) != 0) 
     180        ret = PAM_SESSION_ERR; 
     181 
     182done: 
     183    sigaction(SIGCHLD, &oldact, NULL); 
     184    return ret; 
    171185} 
    172186 
    173187