From ba8f756695eea98b3d34186351700e253833b280 Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Fri, 27 Jan 2017 09:26:51 -0700 Subject: [PATCH] Always set the close-on-exec bit on the fd used to generate the digest (i.e. the command to run) on systems that lack fexecve(2). That way we don't need to explicitly close it using #ifdefs. --- plugins/sudoers/match.c | 47 +++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/plugins/sudoers/match.c b/plugins/sudoers/match.c index 7a4bdef3d..b51eff4bb 100644 --- a/plugins/sudoers/match.c +++ b/plugins/sudoers/match.c @@ -451,6 +451,34 @@ do_stat(int fd, const char *path, struct stat *sb) debug_return_bool(stat(path, sb) == 0); } +/* + * 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. + */ +static void +set_cloexec(int fd) +{ + bool is_script = false; +#ifdef HAVE_FEXECVE + char magic[2]; + + /* Check for #! cookie and set is_script. */ + if (read(fd, magic, 2) == 2) { + if (magic[0] == '#' && magic[1] == '!') + is_script = 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); +} + /* * Open path if fdexec is enabled or if a digest is present. * Returns false on error, else true. @@ -459,7 +487,6 @@ static bool open_cmnd(const char *path, const struct sudo_digest *digest, int *fdp) { int fd = -1; - bool is_script = false; debug_decl(open_cmnd, SUDOERS_DEBUG_MATCH) /* Only open the file for fdexec or for digest matching. */ @@ -478,23 +505,7 @@ open_cmnd(const char *path, const struct sudo_digest *digest, int *fdp) if (fd == -1) debug_return_bool(false); -#ifdef HAVE_FEXECVE - do { - /* Check for #! cookie and set is_script. */ - char magic[2]; - if (read(fd, magic, 2) == 2) { - if (magic[0] == '#' && magic[1] == '!') - is_script = true; - } - (void) lseek(fd, (off_t)0, SEEK_SET); - } while (0); - /* - * 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); -#endif /* HAVE_FEXECVE */ + set_cloexec(fd); *fdp = fd; debug_return_bool(true); } -- 2.40.0