From def2e761e389195f126e0139e49c7e9b88de8acf Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Mon, 23 Apr 2018 10:54:51 -0600 Subject: [PATCH] We can only use fexecve() on a script if /dev/fd/N exists. Some systems, such as FreeBSD, don't have /dev/fd mounted by default. Bug #831 --- plugins/sudoers/match.c | 52 +++++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 18 deletions(-) diff --git a/plugins/sudoers/match.c b/plugins/sudoers/match.c index bf3eaa1cc..a1202ea0e 100644 --- a/plugins/sudoers/match.c +++ b/plugins/sudoers/match.c @@ -487,32 +487,22 @@ do_stat(int fd, const char *path, struct stat *sb) debug_return_bool(stat(path, sb) == 0); } +#ifdef HAVE_FEXECVE /* - * On systems with fexecve(2), set the close-on-exec flag on the file - * descriptor only if the file is not a script. Because scripts need - * to be executed by an interpreter the fd must remain open for the - * interpreter to use. + * Check whether the fd refers to a shell script with a "#!" shebang. */ -static void -set_cloexec(int fd) +static bool +is_script(int fd) { - bool is_script = false; -#ifdef HAVE_FEXECVE + bool ret = false; char magic[2]; - /* Check for #! cookie and set is_script. */ if (read(fd, magic, 2) == 2) { if (magic[0] == '#' && magic[1] == '!') - is_script = true; + ret = true; } (void) lseek(fd, (off_t)0, SEEK_SET); -#endif /* HAVE_FEXECVE */ - /* - * Shell scripts go through namei twice and so we can't set the close - * on exec flag on the fd for fexecve(2). - */ - if (!is_script) - (void)fcntl(fd, F_SETFD, FD_CLOEXEC); + return ret; } /* @@ -541,10 +531,36 @@ open_cmnd(const char *path, const struct sudo_digest *digest, int *fdp) if (fd == -1) debug_return_bool(false); - set_cloexec(fd); + 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(false); + } + + /* + * 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; +} +#endif /* HAVE_FEXECVE */ static bool command_matches_fnmatch(const char *sudoers_cmnd, const char *sudoers_args, -- 2.40.0