]> granicus.if.org Git - sudo/commitdiff
If execve fails in logging mode, pass the errno directly to the grandparent
authorTodd C. Miller <Todd.Miller@courtesan.com>
Tue, 13 Apr 2010 10:31:55 +0000 (06:31 -0400)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Tue, 13 Apr 2010 10:31:55 +0000 (06:31 -0400)
on the backchannel and exit.  The immediate parent will get SIGCHLD and
try to report that status but its parent will no longer be listening.
It would probably be cleaner to pass this over a pipe in script_child().

src/script.c

index 5cc4ddd465e5b046eac67e1637adbc879d9aba19..60a850dad24a2768525e6c1e215a4b2de519595f 100644 (file)
@@ -599,6 +599,9 @@ script_execve(struct command_details *details, char *argv[], char *envp[],
                break;
            }
        }
+       if (!log_io)
+           continue;
+
        if (FD_ISSET(sv[0], fdsw)) {
            for (n = 0; n < NSIG; n++) {
                if (!recvsig[n])
@@ -616,9 +619,6 @@ script_execve(struct command_details *details, char *argv[], char *envp[],
                }
            }
        }
-       if (!log_io)
-           continue;
-
        if (FD_ISSET(script_fds[SFD_USERTTY], fdsr)) {
            n = read(script_fds[SFD_USERTTY], input.buf + input.len,
                sizeof(input.buf) - input.len);
@@ -836,7 +836,10 @@ script_child(const char *path, char *argv[], char *envp[], int backchannel, int
        /* setup tty and exec command */
        script_run(path, argv, envp, rbac);
        warning("unable to execute %s", path); /* XXX - leave this to plugin? */
-       goto bad;
+       cstat.type = CMD_ERRNO;
+       cstat.val = errno;
+       send(backchannel, &cstat, sizeof(cstat), 0);
+       _exit(1);
     }
 
     /*
@@ -874,9 +877,17 @@ script_child(const char *path, char *argv[], char *envp[], int backchannel, int
                do {
                    n = send(backchannel, &cstat, sizeof(cstat), 0);
                } while (n == -1 && errno == EINTR);
-               if (n != sizeof(cstat))
-                   break; /* XXX - error, kill child and exit */
-               sudo_debug(8, "sent wait status to parent");
+               if (n != sizeof(cstat)) {
+                   /*
+                    * If child failed to exec it sends its own status
+                    * which will result in ECONNRERFUSED here.
+                    * XXX - treat other errno as fatal
+                    */
+                   sudo_debug(8, "unable to send wait status: %s",
+                       strerror(errno));
+               } else {
+                   sudo_debug(8, "sent wait status to parent");
+               }
                if (!WIFSTOPPED(status)) {
                    /* XXX */
                    _exit(1); /* child dead */