diff --git a/plugins/sudoers/editor.c b/plugins/sudoers/editor.c index 829be82d0..35fa28159 100644 --- a/plugins/sudoers/editor.c +++ b/plugins/sudoers/editor.c @@ -147,7 +147,7 @@ resolve_editor(const char *ed, size_t edlen, int nfiles, char * const *files, goto oom; /* If we can't find the editor in the user's PATH, give up. */ - if (find_path(editor, &editor_path, &user_editor_sb, getenv("PATH"), NULL, + if (find_path(editor, &editor_path, &user_editor_sb, getenv("PATH"), 0, allowlist) != FOUND) { errno = ENOENT; goto bad; diff --git a/plugins/sudoers/find_path.c b/plugins/sudoers/find_path.c index 3ca3d4d12..793ee6a2b 100644 --- a/plugins/sudoers/find_path.c +++ b/plugins/sudoers/find_path.c @@ -43,14 +43,14 @@ * On failure, returns false. */ static bool -cmnd_allowed(char *cmnd, size_t cmnd_size, const char *runchroot, - struct stat *cmnd_sbp, char * const *allowlist) +cmnd_allowed(char *cmnd, size_t cmnd_size, struct stat *cmnd_sbp, + char * const *allowlist) { const char *cmnd_base; char * const *al; debug_decl(cmnd_allowed, SUDOERS_DEBUG_UTIL); - if (!sudo_goodpath(cmnd, runchroot, cmnd_sbp)) + if (!sudo_goodpath(cmnd, cmnd_sbp)) debug_return_bool(false); if (allowlist == NULL) @@ -67,7 +67,7 @@ cmnd_allowed(char *cmnd, size_t cmnd_size, const char *runchroot, if (strcmp(cmnd_base, base) != 0) continue; - if (sudo_goodpath(path, runchroot, &sb) && + if (sudo_goodpath(path, &sb) && sb.st_dev == cmnd_sbp->st_dev && sb.st_ino == cmnd_sbp->st_ino) { /* Overwrite cmnd with safe version from allowlist. */ if (strlcpy(cmnd, path, cmnd_size) < cmnd_size) @@ -87,8 +87,7 @@ cmnd_allowed(char *cmnd, size_t cmnd_size, const char *runchroot, */ int find_path(const char *infile, char **outfile, struct stat *sbp, - const char *path, const char *runchroot, int ignore_dot, - char * const *allowlist) + const char *path, int ignore_dot, char * const *allowlist) { char command[PATH_MAX]; const char *cp, *ep, *pathend; @@ -109,8 +108,7 @@ find_path(const char *infile, char **outfile, struct stat *sbp, errno = ENAMETOOLONG; debug_return_int(NOT_FOUND_ERROR); } - found = cmnd_allowed(command, sizeof(command), runchroot, sbp, - allowlist); + found = cmnd_allowed(command, sizeof(command), sbp, allowlist); goto done; } @@ -139,8 +137,7 @@ find_path(const char *infile, char **outfile, struct stat *sbp, errno = ENAMETOOLONG; debug_return_int(NOT_FOUND_ERROR); } - found = cmnd_allowed(command, sizeof(command), runchroot, - sbp, allowlist); + found = cmnd_allowed(command, sizeof(command), sbp, allowlist); if (found) break; } @@ -154,8 +151,7 @@ find_path(const char *infile, char **outfile, struct stat *sbp, errno = ENAMETOOLONG; debug_return_int(NOT_FOUND_ERROR); } - found = cmnd_allowed(command, sizeof(command), runchroot, - sbp, allowlist); + found = cmnd_allowed(command, sizeof(command), sbp, allowlist); if (found && ignore_dot) debug_return_int(NOT_FOUND_DOT); } diff --git a/plugins/sudoers/goodpath.c b/plugins/sudoers/goodpath.c index c4c8bbd3c..10d83ad8b 100644 --- a/plugins/sudoers/goodpath.c +++ b/plugins/sudoers/goodpath.c @@ -39,24 +39,13 @@ * Verify that path is a normal file and executable by root. */ bool -sudo_goodpath(const char *path, const char *runchroot, struct stat *sbp) +sudo_goodpath(const char *path, struct stat *sbp) { bool ret = false; + struct stat sb; debug_decl(sudo_goodpath, SUDOERS_DEBUG_UTIL); if (path != NULL) { - char pathbuf[PATH_MAX]; - struct stat sb; - - if (runchroot != NULL) { - const int len = - snprintf(pathbuf, sizeof(pathbuf), "%s%s", runchroot, path); - if (len >= ssizeof(pathbuf)) { - errno = ENAMETOOLONG; - goto done; - } - path = pathbuf; // -V507 - } if (sbp == NULL) sbp = &sb; @@ -68,6 +57,5 @@ sudo_goodpath(const char *path, const char *runchroot, struct stat *sbp) errno = EACCES; } } -done: debug_return_bool(ret); } diff --git a/plugins/sudoers/regress/editor/check_editor.c b/plugins/sudoers/regress/editor/check_editor.c index eef9d384e..e905f1acd 100644 --- a/plugins/sudoers/regress/editor/check_editor.c +++ b/plugins/sudoers/regress/editor/check_editor.c @@ -80,8 +80,7 @@ sudo_dso_public int main(int argc, char *argv[]); /* STUB */ int find_path(const char *infile, char **outfile, struct stat *sbp, - const char *path, const char *runchroot, int ignore_dot, - char * const *allowlist) + const char *path, int ignore_dot, char * const *allowlist) { if (infile[0] == '/') { *outfile = strdup(infile); diff --git a/plugins/sudoers/regress/fuzz/fuzz_policy.c b/plugins/sudoers/regress/fuzz/fuzz_policy.c index da537509f..b36bf9b0b 100644 --- a/plugins/sudoers/regress/fuzz/fuzz_policy.c +++ b/plugins/sudoers/regress/fuzz/fuzz_policy.c @@ -799,8 +799,7 @@ display_privs(struct sudo_nss_list *snl, struct passwd *pw, bool verbose) /* STUB */ int find_path(const char *infile, char **outfile, struct stat *sbp, - const char *path, const char *runchroot, int ignore_dot, - char * const *allowlist) + const char *path, int ignore_dot, char * const *allowlist) { switch (pass) { case PASS_CHECK_NOT_FOUND: diff --git a/plugins/sudoers/sudoers.c b/plugins/sudoers/sudoers.c index 9ae5f96c6..2b8d401e3 100644 --- a/plugins/sudoers/sudoers.c +++ b/plugins/sudoers/sudoers.c @@ -998,7 +998,7 @@ set_cmnd_path(const char *runchroot) const char *cmnd_in; char *cmnd_out = NULL; char *path = user_path; - int ret; + int ret, pivot_fds[2]; debug_decl(set_cmnd_path, SUDOERS_DEBUG_PLUGIN); cmnd_in = ISSET(sudo_mode, MODE_CHECK) ? NewArgv[1] : NewArgv[0]; @@ -1009,10 +1009,16 @@ set_cmnd_path(const char *runchroot) user_cmnd = NULL; if (def_secure_path && !user_is_exempt()) path = def_secure_path; + + /* Pivot root. */ + if (runchroot != NULL) { + if (!pivot_root(runchroot, pivot_fds)) + goto error; + } + if (!set_perms(PERM_RUNAS)) goto error; - ret = find_path(cmnd_in, &cmnd_out, user_stat, path, - runchroot, def_ignore_dot, NULL); + ret = find_path(cmnd_in, &cmnd_out, user_stat, path, def_ignore_dot, NULL); if (!restore_perms()) goto error; if (ret == NOT_FOUND) { @@ -1020,7 +1026,7 @@ set_cmnd_path(const char *runchroot) if (!set_perms(PERM_USER)) goto error; ret = find_path(cmnd_in, &cmnd_out, user_stat, path, - runchroot, def_ignore_dot, NULL); + def_ignore_dot, NULL); if (!restore_perms()) goto error; } @@ -1030,8 +1036,14 @@ set_cmnd_path(const char *runchroot) else user_cmnd = cmnd_out; + /* Restore root. */ + if (runchroot != NULL) + (void)unpivot_root(pivot_fds); + debug_return_int(ret); error: + if (runchroot != NULL) + (void)unpivot_root(pivot_fds); free(cmnd_out); debug_return_int(NOT_FOUND_ERROR); } diff --git a/plugins/sudoers/sudoers.h b/plugins/sudoers/sudoers.h index 5f9e545fd..a5e6d4425 100644 --- a/plugins/sudoers/sudoers.h +++ b/plugins/sudoers/sudoers.h @@ -288,12 +288,11 @@ struct timespec; #define YY_DECL int sudoerslex(void) /* goodpath.c */ -bool sudo_goodpath(const char *path, const char *runchroot, struct stat *sbp); +bool sudo_goodpath(const char *path, struct stat *sbp); /* findpath.c */ int find_path(const char *infile, char **outfile, struct stat *sbp, - const char *path, const char *runchroot, int ignore_dot, - char * const *allowlist); + const char *path, int ignore_dot, char * const *allowlist); /* check.c */ int check_user(int validate, int mode);