]> granicus.if.org Git - sudo/commitdiff
Move the check for /dev/fd/N until *after* the digest has been
authorTodd C. Miller <Todd.Miller@sudo.ws>
Tue, 24 Apr 2018 13:21:08 +0000 (07:21 -0600)
committerTodd C. Miller <Todd.Miller@sudo.ws>
Tue, 24 Apr 2018 13:21:08 +0000 (07:21 -0600)
checked.  We still need to be able to check the digest even if there
is no /dev/fd/N or fexecve().

plugins/sudoers/match.c

index f9ee3d963b4de28e11e4d25272cc4e7b578ecfce..c40c6f41188733c2595d3211593651a3705f0b1b 100644 (file)
@@ -487,7 +487,6 @@ do_stat(int fd, const char *path, struct stat *sb)
     debug_return_bool(stat(path, sb) == 0);
 }
 
-#ifdef HAVE_FEXECVE
 /*
  * Check whether the fd refers to a shell script with a "#!" shebang.
  */
@@ -531,42 +530,57 @@ open_cmnd(const char *path, const struct sudo_digest *digest, int *fdp)
     if (fd == -1)
        debug_return_bool(false);
 
-    if (is_script(fd)) {
-       char fdpath[PATH_MAX];
-       struct stat sb;
+    (void)fcntl(fd, F_SETFD, FD_CLOEXEC);
+    *fdp = fd;
+    debug_return_bool(true);
+}
+
+static void
+set_cmnd_fd(int fd)
+{
+    debug_decl(set_cmnd_fd, SUDOERS_DEBUG_MATCH)
+
+    if (cmnd_fd != -1)
+       close(cmnd_fd);
 
-       /* We can only use fexecve() on a script if /dev/fd/N exists. */
-       snprintf(fdpath, sizeof(fdpath), "/dev/fd/%d", fd);
-       if (stat(fdpath, &sb) != 0) {
+    if (fd != -1) {
+       if (def_fdexec == never) {
+           /* Never use fexedcve() */
            close(fd);
-           debug_return_bool(true);
+           fd = -1;
+       } else if (is_script(fd)) {
+           char fdpath[PATH_MAX];
+           struct stat sb;
+           int flags;
+
+           /* We can only use fexecve() on a script if /dev/fd/N exists. */
+           snprintf(fdpath, sizeof(fdpath), "/dev/fd/%d", fd);
+           if (stat(fdpath, &sb) != 0) {
+               /* Missing /dev/fd file, can't use fexecve(). */
+               close(fd);
+               fd = -1;
+           } else {
+               /*
+                * Shell scripts go through namei twice so we can't have the
+                * close on exec flag set on the fd for fexecve(2).
+                */
+               flags = fcntl(fd, F_GETFD) & ~FD_CLOEXEC;
+               (void)fcntl(fd, F_SETFD, flags);
+           }
        }
-
-       /*
-        * Shell scripts go through namei twice so we can't set the
-        * close on exec flag on the fd for fexecve(2).
-        */
-    } else {
-       /* Not a script, close on exec is safe. */
-       (void)fcntl(fd, F_SETFD, FD_CLOEXEC);
     }
 
-    *fdp = fd;
-    debug_return_bool(true);
-}
-#else /* HAVE_FEXECVE */
-static bool
-open_cmnd(const char *path, const struct sudo_digest *digest, int *fdp)
-{
-    return true;
+    cmnd_fd = fd;
+
+    debug_return;
 }
-#endif /* HAVE_FEXECVE */
 
 static bool
 command_matches_fnmatch(const char *sudoers_cmnd, const char *sudoers_args,
     const struct sudo_digest *digest)
 {
     struct stat sb; /* XXX - unused */
+    int fd = -1;
     debug_decl(command_matches_fnmatch, SUDOERS_DEBUG_MATCH)
 
     /*
@@ -579,30 +593,22 @@ command_matches_fnmatch(const char *sudoers_cmnd, const char *sudoers_args,
     if (fnmatch(sudoers_cmnd, user_cmnd, FNM_PATHNAME) != 0)
        debug_return_bool(false);
     if (command_args_match(sudoers_cmnd, sudoers_args)) {
-       if (cmnd_fd != -1) {
-           close(cmnd_fd);
-           cmnd_fd = -1;
-       }
        /* Open the file for fdexec or for digest matching. */
-       if (!open_cmnd(user_cmnd, digest, &cmnd_fd))
+       if (!open_cmnd(user_cmnd, digest, &fd))
            goto bad;
-       if (!do_stat(cmnd_fd, user_cmnd, &sb))
+       if (!do_stat(fd, user_cmnd, &sb))
            goto bad;
        /* Check digest of user_cmnd since sudoers_cmnd is a pattern. */
-       if (digest != NULL) {
-           if (!digest_matches(cmnd_fd, user_cmnd, digest))
-               goto bad;
-           if (def_fdexec == never) {
-               close(cmnd_fd);
-               cmnd_fd = -1;
-           }
-       }
+       if (digest != NULL && !digest_matches(fd, user_cmnd, digest))
+           goto bad;
+       set_cmnd_fd(fd);
+
        /* No need to set safe_cmnd since user_cmnd matches sudoers_cmnd */
        debug_return_bool(true);
 bad:
-       if (cmnd_fd != -1) {
-           close(cmnd_fd);
-           cmnd_fd = -1;
+       if (fd != -1) {
+           close(fd);
+           fd = -1;
        }
        debug_return_bool(false);
     }
@@ -730,16 +736,7 @@ done:
     if (cp != NULL) {
        if (command_args_match(sudoers_cmnd, sudoers_args)) {
            /* safe_cmnd was set above. */
-           if (cmnd_fd != -1) {
-               close(cmnd_fd);
-               cmnd_fd = -1;
-           }
-           if (fd != -1) {
-               if (def_fdexec == never)
-                   close(fd);
-               else
-                   cmnd_fd = fd;
-           }
+           set_cmnd_fd(fd);
            debug_return_bool(true);
        }
     }
@@ -884,16 +881,7 @@ command_matches_normal(const char *sudoers_cmnd, const char *sudoers_args, const
        sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
        goto bad;
     }
-    if (cmnd_fd != -1) {
-       close(cmnd_fd);
-       cmnd_fd = -1;
-    }
-    if (fd != -1) {
-       if (def_fdexec == never)
-           close(fd);
-       else
-           cmnd_fd = fd;
-    }
+    set_cmnd_fd(fd);
     debug_return_bool(true);
 bad:
     if (fd != -1)
@@ -979,16 +967,7 @@ command_matches_dir(const char *sudoers_dir, size_t dlen,
     closedir(dirp);
 
     if (dent != NULL) {
-       if (cmnd_fd != -1) {
-           close(cmnd_fd);
-           cmnd_fd = -1;
-       }
-       if (fd != -1) {
-           if (def_fdexec == never)
-               close(fd);
-           else
-               cmnd_fd = fd;
-       }
+       set_cmnd_fd(fd);
        debug_return_bool(true);
     }
     if (fd != -1)