File revert-suse-disable-dir-canonicalization.patch of Package sudo.34945
commit ff64b1940a82a5e2a5d176b191105716d792cba6
Author: Simon Lees <sflees@suse.de>
Date: Wed Jun 5 12:37:05 2024 +0930
Revert "Match using canonicalized directories where possible."
This reverts commit b52631e8777ae9334e403259d211fb980aebc848.
Index: sudo-1.9.15p5/plugins/sudoers/match_command.c
===================================================================
--- sudo-1.9.15p5.orig/plugins/sudoers/match_command.c
+++ sudo-1.9.15p5/plugins/sudoers/match_command.c
@@ -240,51 +240,66 @@ static int
command_matches_dir(struct sudoers_context *ctx, const char *sudoers_dir,
size_t dlen, int real_root, const struct command_digest_list *digests)
{
+ char buf[PATH_MAX];
struct stat sudoers_stat;
- char path[PATH_MAX];
- int len, fd = -1;
+ struct dirent *dent;
+ int fd = -1;
+ DIR *dirp;
int ret = DENY;
debug_decl(command_matches_dir, SUDOERS_DEBUG_MATCH);
- /* Compare the canonicalized directories, if possible. */
- if (ctx->user.cmnd_dir != NULL) {
- char *resolved = canon_path(sudoers_dir);
- if (resolved != NULL) {
- if (strcmp(resolved, ctx->user.cmnd_dir) != 0) {
- canon_path_free(resolved);
- goto done;
+ /*
+ * Grot through directory entries, looking for user_base.
+ */
+ dirp = opendir(sudoers_dir);
+ if (dirp == NULL)
+ debug_return_int(DENY);
+
+ if (strlcpy(buf, sudoers_dir, sizeof(buf)) >= sizeof(buf)) {
+ closedir(dirp);
+ debug_return_int(DENY);
}
- canon_path_free(resolved);
- }
+ while ((dent = readdir(dirp)) != NULL) {
+ if (fd != -1) {
+ close(fd);
+ fd = -1;
}
- /* Check for command in sudoers_dir. */
- len = snprintf(path, sizeof(path), "%s/%s", sudoers_dir, ctx->user.cmnd_base);
- if (len < 0 || len >= ssizeof(path))
- goto done;
+ /* ignore paths > PATH_MAX (XXX - log) */
+ buf[dlen] = '\0';
+ if (strlcat(buf, dent->d_name, sizeof(buf)) >= sizeof(buf))
+ continue;
+
+ /* only stat if basenames are the same */
+ if (strcmp(ctx->user.cmnd_base, dent->d_name) != 0)
+ continue;
/* Open the file for fdexec or for digest matching. */
- if (!open_cmnd(path, digests, &fd))
- goto done;
- if (!do_stat(fd, path, &sudoers_stat))
- goto done;
-
- if (ctx->user.cmnd_stat == NULL ||
- (ctx->user.cmnd_stat->st_dev == sudoers_stat.st_dev &&
- ctx->user.cmnd_stat->st_ino == sudoers_stat.st_ino)) {
- if (digest_matches(fd, path, digests) != ALLOW)
- goto done;
- free(ctx->runas.cmnd);
- if ((ctx->runas.cmnd = strdup(path)) == NULL) {
- sudo_warnx(U_("%s: %s"), __func__,
- U_("unable to allocate memory"));
- }
- ret = ALLOW;
- goto done;
+ if (!open_cmnd(buf, digests, &fd))
+ continue;
+ if (!do_stat(fd, buf, &sudoers_stat))
+ continue;
+
+ if (ctx->user.cmnd_stat == NULL ||
+ (ctx->user.cmnd_stat->st_dev == sudoers_stat.st_dev &&
+ ctx->user.cmnd_stat->st_ino == sudoers_stat.st_ino)) {
+ if (digest_matches(fd, buf, digests) != ALLOW)
+ continue;
+ free(ctx->runas.cmnd);
+ if ((ctx->runas.cmnd = strdup(buf)) == NULL) {
+ sudo_warnx(U_("%s: %s"), __func__,
+ U_("unable to allocate memory"));
+ dent = NULL;
+ }
+ break;
+ }
}
- ret = DENY;
+ closedir(dirp);
-done:
+ if (dent != NULL) {
+ set_cmnd_fd(ctx, fd, real_root);
+ debug_return_int(ALLOW);
+ }
if (fd != -1)
close(fd);
debug_return_int(ret);
@@ -333,7 +348,7 @@ command_matches_all(struct sudoers_conte
int fd = -1;
debug_decl(command_matches_all, SUDOERS_DEBUG_MATCH);
- if (strchr(ctx->user.cmnd, '/') != NULL) {
+ if (ctx->user.cmnd[0] == '/') {
#ifndef SUDOERS_NAME_MATCH
/* Open the file for fdexec or for digest matching. */
bool open_error = !open_cmnd(ctx->user.cmnd, digests, &fd);
@@ -369,25 +384,12 @@ command_matches_fnmatch(struct sudoers_c
const char *sudoers_args, int real_root,
const struct command_digest_list *digests)
{
- const char *cmnd = ctx->user.cmnd;
- char buf[PATH_MAX];
- int len, fd = -1;
#ifndef SUDOERS_NAME_MATCH
struct stat sb;
#endif
+ int fd = -1;
debug_decl(command_matches_fnmatch, SUDOERS_DEBUG_MATCH);
- /* A relative ctx->user.cmnd will not match, try canonicalized version. */
- if (ctx->user.cmnd[0] != '/') {
- if (ctx->user.cmnd_dir == NULL)
- debug_return_int(DENY);
- len = snprintf(buf, sizeof(buf), "%s/%s", ctx->user.cmnd_dir,
- ctx->user.cmnd_base);
- if (len < 0 || len >= ssizeof(buf))
- debug_return_int(DENY);
- cmnd = buf;
- }
-
/*
* Return ALLOW if fnmatch(3) succeeds AND
* a) there are no args in sudoers OR
@@ -395,19 +397,19 @@ command_matches_fnmatch(struct sudoers_c
* c) there are args in sudoers and on command line and they match
* else return DENY.
*/
- if (fnmatch(sudoers_cmnd, cmnd, FNM_PATHNAME) != 0)
+ if (fnmatch(sudoers_cmnd, ctx->user.cmnd, FNM_PATHNAME) != 0)
debug_return_int(DENY);
if (command_args_match(ctx, sudoers_cmnd, sudoers_args) == ALLOW) {
/* Open the file for fdexec or for digest matching. */
- if (!open_cmnd(cmnd, digests, &fd))
+ if (!open_cmnd(ctx->user.cmnd, digests, &fd))
goto bad;
#ifndef SUDOERS_NAME_MATCH
- if (!do_stat(fd, cmnd, &sb))
+ if (!do_stat(fd, ctx->user.cmnd, &sb))
goto bad;
#endif
- /* Check digest of cmnd since sudoers_cmnd is a pattern. */
- if (digest_matches(fd, cmnd, digests) != ALLOW)
+ /* Check digest of user_ctx.cmnd since sudoers_cmnd is a pattern. */
+ if (!digest_matches(fd, ctx->user.cmnd, digests))
goto bad;
set_cmnd_fd(ctx, fd, real_root);
@@ -425,45 +427,32 @@ command_matches_regex(struct sudoers_con
const char *sudoers_args, int real_root,
const struct command_digest_list *digests)
{
- const char *cmnd = ctx->user.cmnd;
- char buf[PATH_MAX];
- int len, fd = -1;
#ifndef SUDOERS_NAME_MATCH
struct stat sb;
#endif
+ int fd = -1;
debug_decl(command_matches_regex, SUDOERS_DEBUG_MATCH);
- /* A relative ctx->user.cmnd will not match, try canonicalized version. */
- if (ctx->user.cmnd[0] != '/') {
- if (ctx->user.cmnd_dir == NULL)
- debug_return_int(DENY);
- len = snprintf(buf, sizeof(buf), "%s/%s", ctx->user.cmnd_dir,
- ctx->user.cmnd_base);
- if (len < 0 || len >= ssizeof(buf))
- debug_return_int(DENY);
- cmnd = buf;
- }
-
/*
- * Return ALLOW if sudoers_cmnd regex matches cmnd AND
+ * Return true if sudoers_cmnd regex matches user_cmnd AND
* a) there are no args in sudoers OR
* b) there are no args on command line and none required by sudoers OR
* c) there are args in sudoers and on command line and they match
* else return DENY.
*/
- if (regex_matches(sudoers_cmnd, cmnd) != ALLOW)
+ if (regex_matches(sudoers_cmnd, ctx->user.cmnd) != ALLOW)
debug_return_int(DENY);
if (command_args_match(ctx, sudoers_cmnd, sudoers_args) == ALLOW) {
/* Open the file for fdexec or for digest matching. */
- if (!open_cmnd(cmnd, digests, &fd))
+ if (!open_cmnd(ctx->user.cmnd, digests, &fd))
goto bad;
#ifndef SUDOERS_NAME_MATCH
- if (!do_stat(fd, cmnd, &sb))
+ if (!do_stat(fd, ctx->user.cmnd, &sb))
goto bad;
#endif
- /* Check digest of cmnd since sudoers_cmnd is a pattern. */
- if (digest_matches(fd, cmnd, digests) != ALLOW)
+ /* Check digest of user_cmnd since sudoers_cmnd is a pattern. */
+ if (!digest_matches(fd, ctx->user.cmnd, digests))
goto bad;
set_cmnd_fd(ctx, fd, real_root);
@@ -550,7 +539,7 @@ command_matches_glob(struct sudoers_cont
goto done;
}
}
- /* No exact match, compare basename, cmnd_dir, st_dev and st_ino. */
+ /* No exact match, compare basename, st_dev and st_ino. */
if (!bad_digest) {
for (ap = gl.gl_pathv; (cp = *ap) != NULL; ap++) {
if (fd != -1) {
@@ -573,24 +562,6 @@ command_matches_glob(struct sudoers_cont
if (strcmp(ctx->user.cmnd_base, base) != 0)
continue;
- /* Compare the canonicalized parent directories, if possible. */
- if (ctx->user.cmnd_dir != NULL) {
- char *slash = strrchr(cp, '/');
- if (slash != NULL) {
- char *resolved;
- *slash = '\0';
- resolved = canon_path(cp);
- *slash = '/';
- if (resolved != NULL) {
- /* Canonicalized directories must match. */
- int result = strcmp(resolved, ctx->user.cmnd_dir);
- canon_path_free(resolved);
- if (result != 0)
- continue;
- }
- }
- }
-
/* Open the file for fdexec or for digest matching. */
if (!open_cmnd(cp, digests, &fd))
continue;
@@ -600,7 +571,7 @@ command_matches_glob(struct sudoers_cont
(ctx->user.cmnd_stat->st_dev == sudoers_stat.st_dev &&
ctx->user.cmnd_stat->st_ino == sudoers_stat.st_ino)) {
if (digest_matches(fd, cp, digests) != ALLOW)
- continue;
+ continue;
free(ctx->runas.cmnd);
if ((ctx->runas.cmnd = strdup(cp)) == NULL) {
sudo_warnx(U_("%s: %s"), __func__,
@@ -648,28 +619,6 @@ command_matches_normal(struct sudoers_co
if (strcmp(ctx->user.cmnd_base, base) != 0)
debug_return_int(DENY);
- /* Compare the canonicalized parent directories, if possible. */
- if (ctx->user.cmnd_dir != NULL) {
- const char *slash = strrchr(sudoers_cmnd, '/');
- if (slash != NULL) {
- char sudoers_cmnd_dir[PATH_MAX], *resolved;
- const size_t len = (size_t)(slash - sudoers_cmnd);
- if (len >= sizeof(sudoers_cmnd_dir))
- goto bad;
- if (len != 0)
- memcpy(sudoers_cmnd_dir, sudoers_cmnd, len);
- sudoers_cmnd_dir[len] = '\0';
- resolved = canon_path(sudoers_cmnd_dir);
- if (resolved != NULL) {
- if (strcmp(resolved, ctx->user.cmnd_dir) != 0) {
- canon_path_free(resolved);
- goto bad;
- }
- canon_path_free(resolved);
- }
- }
- }
-
/* Open the file for fdexec or for digest matching. */
if (!open_cmnd(sudoers_cmnd, digests, &fd))
goto bad;