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().
This commit is contained in:
Todd C. Miller
2018-04-24 07:21:08 -06:00
parent 64c78a61cb
commit cfdae3a4fd

View 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;
/* 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)