From cfdae3a4fd8bdaac4e1cb9ea5b9f83acf192e20a Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Tue, 24 Apr 2018 07:21:08 -0600 Subject: [PATCH] Move the check for /dev/fd/N until *after* the digest has been 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 | 125 +++++++++++++++++----------------------- 1 file changed, 52 insertions(+), 73 deletions(-) diff --git a/plugins/sudoers/match.c b/plugins/sudoers/match.c index f9ee3d963..c40c6f411 100644 --- a/plugins/sudoers/match.c +++ b/plugins/sudoers/match.c @@ -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; - - /* 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) { - close(fd); - debug_return_bool(true); - } - - /* - * 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); - } - + (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) + +static void +set_cmnd_fd(int fd) { - return true; + debug_decl(set_cmnd_fd, SUDOERS_DEBUG_MATCH) + + if (cmnd_fd != -1) + close(cmnd_fd); + + if (fd != -1) { + if (def_fdexec == never) { + /* Never use fexedcve() */ + close(fd); + 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); + } + } + } + + 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)