From fca2c0eec377e2ebbf8ff1ca1055230e50c6e404 Mon Sep 17 00:00:00 2001 From: qsw333 Date: Wed, 10 Jan 2024 09:25:22 +0800 Subject: [PATCH] fix CVE-2023-42465 (cherry picked from commit 8652c512ab188b5e5f2aa7bd185a86a04fd84c90) --- backport-CVE-2023-42465.patch | 442 +++++++ ...he-definition-of-ALLOW-DENY-being-tr.patch | 249 ++++ ...l-match-functions-return-ALLOW-DENY-.patch | 1117 +++++++++++++++++ sudo.spec | 8 +- 4 files changed, 1815 insertions(+), 1 deletion(-) create mode 100644 backport-CVE-2023-42465.patch create mode 100644 backport-Do-not-rely-on-the-definition-of-ALLOW-DENY-being-tr.patch create mode 100644 backport-Make-all-match-functions-return-ALLOW-DENY-.patch diff --git a/backport-CVE-2023-42465.patch b/backport-CVE-2023-42465.patch new file mode 100644 index 0000000..00b3fb5 --- /dev/null +++ b/backport-CVE-2023-42465.patch @@ -0,0 +1,442 @@ +From 7873f8334c8d31031f8cfa83bd97ac6029309e4f Mon Sep 17 00:00:00 2001 +From: "Todd C. Miller" +Date: Sat, 9 Sep 2023 14:07:04 -0600 +Subject: [PATCH] Try to make sudo less vulnerable to ROWHAMMER attacks. + +We now use ROWHAMMER-resistent values for ALLOW, DENY, AUTH_SUCCESS, +AUTH_FAILURE, AUTH_ERROR and AUTH_NONINTERACTIVE. In addition, we +explicitly test for expected values instead of using a negated test +against an error value. In the parser match functions this means +explicitly checking for ALLOW or DENY instead of accepting anything +that is not set to UNSPEC. + +Thanks to Andrew J. Adiletta, M. Caner Tol, Yarkin Doroz, and Berk +Sunar, all affiliated with the Vernam Applied Cryptography and +Cybersecurity Lab at Worcester Polytechnic Institute, for the report. +Paper preprint: https://arxiv.org/abs/2309.02545 + +Reference: https://github.com/sudo-project/sudo/commit/7873f8334c8d31031f8cfa83bd97ac6029309e4f +Conflict: passwd.c sudo_auth.h match.c parse.c +--- + plugins/sudoers/auth/passwd.c | 27 ++++++++++------- + plugins/sudoers/auth/sudo_auth.c | 51 ++++++++++++++++++++++---------- + plugins/sudoers/auth/sudo_auth.h | 10 +++---- + plugins/sudoers/match.c | 25 ++++++++-------- + plugins/sudoers/parse.c | 6 ++-- + plugins/sudoers/parse.h | 23 ++++++++++---- + 6 files changed, 92 insertions(+), 50 deletions(-) + +diff --git a/plugins/sudoers/auth/passwd.c b/plugins/sudoers/auth/passwd.c +index bb9f2d6..8f163cb 100644 +--- a/plugins/sudoers/auth/passwd.c ++++ b/plugins/sudoers/auth/passwd.c +@@ -62,7 +62,7 @@ sudo_passwd_verify(struct passwd *pw, char *pass, sudo_auth *auth, struct sudo_c + char des_pass[9], *epass; + char *pw_epasswd = auth->data; + size_t pw_len; +- int matched = 0; ++ int ret; + debug_decl(sudo_passwd_verify, SUDOERS_DEBUG_AUTH); + + /* An empty plain-text password must match an empty encrypted password. */ +@@ -74,7 +74,7 @@ sudo_passwd_verify(struct passwd *pw, char *pass, sudo_auth *auth, struct sudo_c + */ + pw_len = strlen(pw_epasswd); + if (pw_len == DESLEN || HAS_AGEINFO(pw_epasswd, pw_len)) { +- strlcpy(des_pass, pass, sizeof(des_pass)); ++ (void)strlcpy(des_pass, pass, sizeof(des_pass)); + pass = des_pass; + } + +@@ -84,29 +84,36 @@ sudo_passwd_verify(struct passwd *pw, char *pass, sudo_auth *auth, struct sudo_c + * only compare the first DESLEN characters in that case. + */ + epass = (char *) crypt(pass, pw_epasswd); ++ ret = AUTH_FAILURE; + if (epass != NULL) { +- if (HAS_AGEINFO(pw_epasswd, pw_len) && strlen(epass) == DESLEN) +- matched = !strncmp(pw_epasswd, epass, DESLEN); +- else +- matched = !strcmp(pw_epasswd, epass); ++ if (HAS_AGEINFO(pw_epasswd, pw_len) && strlen(epass) == DESLEN) { ++ if (strncmp(pw_epasswd, epass, DESLEN) == 0) ++ ret = AUTH_SUCCESS; ++ } else { ++ if (strcmp(pw_epasswd, epass) == 0) ++ ret = AUTH_SUCCESS; ++ } + } + + explicit_bzero(des_pass, sizeof(des_pass)); + +- debug_return_int(matched ? AUTH_SUCCESS : AUTH_FAILURE); ++ debug_return_int(ret); + } + #else + int + sudo_passwd_verify(struct passwd *pw, char *pass, sudo_auth *auth, struct sudo_conv_callback *callback) + { + char *pw_passwd = auth->data; +- int matched; ++ int ret; + debug_decl(sudo_passwd_verify, SUDOERS_DEBUG_AUTH); + + /* Simple string compare for systems without crypt(). */ +- matched = !strcmp(pass, pw_passwd); ++ if (strcmp(pass, pw_passwd) == 0) ++ ret = AUTH_SUCCESS; ++ else ++ ret = AUTH_FAILURE; + +- debug_return_int(matched ? AUTH_SUCCESS : AUTH_FAILURE); ++ debug_return_int(ret); + } + #endif + +diff --git a/plugins/sudoers/auth/sudo_auth.c b/plugins/sudoers/auth/sudo_auth.c +index 188b65f..467233a 100644 +--- a/plugins/sudoers/auth/sudo_auth.c ++++ b/plugins/sudoers/auth/sudo_auth.c +@@ -112,10 +112,16 @@ sudo_auth_init(struct passwd *pw) + if (auth->init && !IS_DISABLED(auth)) { + /* Disable if it failed to init unless there was a fatal error. */ + status = (auth->init)(pw, auth); +- if (status == AUTH_FAILURE) ++ switch (status) { ++ case AUTH_SUCCESS: ++ break; ++ case AUTH_FAILURE: + SET(auth->flags, FLAG_DISABLED); +- else if (status == AUTH_FATAL) +- break; /* assume error msg already printed */ ++ break; ++ default: ++ /* Assume error msg already printed. */ ++ debug_return_int(-1); ++ } + } + } + +@@ -161,7 +167,7 @@ sudo_auth_init(struct passwd *pw) + } + } + +- debug_return_int(status == AUTH_FATAL ? -1 : 0); ++ debug_return_int(0); + } + + /* +@@ -202,7 +208,7 @@ sudo_auth_cleanup(struct passwd *pw, bool force) + for (auth = auth_switch; auth->name; auth++) { + if (auth->cleanup && !IS_DISABLED(auth)) { + int status = (auth->cleanup)(pw, auth, force); +- if (status == AUTH_FATAL) { ++ if (status != AUTH_SUCCESS) { + /* Assume error msg already printed. */ + debug_return_int(-1); + } +@@ -297,7 +303,7 @@ verify_user(struct passwd *pw, char *prompt, int validated, + status = (auth->setup)(pw, &prompt, auth); + if (status == AUTH_FAILURE) + SET(auth->flags, FLAG_DISABLED); +- else if (status == AUTH_FATAL || user_interrupted()) ++ else if (status != AUTH_SUCCESS || user_interrupted()) + goto done; /* assume error msg already printed */ + } + } +@@ -348,7 +354,6 @@ done: + log_auth_failure(validated, ntries); + ret = false; + break; +- case AUTH_FATAL: + default: + log_auth_failure(validated, 0); + ret = -1; +@@ -360,24 +365,32 @@ done: + + /* + * Call authentication method begin session hooks. +- * Returns 1 on success and -1 on error. ++ * Returns true on success, false on failure and -1 on error. + */ + int + sudo_auth_begin_session(struct passwd *pw, char **user_env[]) + { + sudo_auth *auth; ++ int ret = true; + debug_decl(sudo_auth_begin_session, SUDOERS_DEBUG_AUTH); + + for (auth = auth_switch; auth->name; auth++) { + if (auth->begin_session && !IS_DISABLED(auth)) { + int status = (auth->begin_session)(pw, user_env, auth); +- if (status != AUTH_SUCCESS) { ++ switch (status) { ++ case AUTH_SUCCESS: ++ break; ++ case AUTH_FAILURE: ++ ret = false; ++ break; ++ default: + /* Assume error msg already printed. */ +- debug_return_int(-1); ++ ret = -1; ++ break; + } + } + } +- debug_return_int(1); ++ debug_return_int(ret); + } + + bool +@@ -398,25 +411,33 @@ sudo_auth_needs_end_session(void) + + /* + * Call authentication method end session hooks. +- * Returns 1 on success and -1 on error. ++ * Returns true on success, false on failure and -1 on error. + */ + int + sudo_auth_end_session(struct passwd *pw) + { + sudo_auth *auth; ++ int ret = true; + int status; + debug_decl(sudo_auth_end_session, SUDOERS_DEBUG_AUTH); + + for (auth = auth_switch; auth->name; auth++) { + if (auth->end_session && !IS_DISABLED(auth)) { + status = (auth->end_session)(pw, auth); +- if (status == AUTH_FATAL) { ++ switch (status) { ++ case AUTH_SUCCESS: ++ break; ++ case AUTH_FAILURE: ++ ret = false; ++ break; ++ default: + /* Assume error msg already printed. */ +- debug_return_int(-1); ++ ret = -1; ++ break; + } + } + } +- debug_return_int(1); ++ debug_return_int(ret); + } + + /* +diff --git a/plugins/sudoers/auth/sudo_auth.h b/plugins/sudoers/auth/sudo_auth.h +index 9ee408d..0b30d0c 100644 +--- a/plugins/sudoers/auth/sudo_auth.h ++++ b/plugins/sudoers/auth/sudo_auth.h +@@ -19,11 +19,11 @@ + #ifndef SUDO_AUTH_H + #define SUDO_AUTH_H + +-/* Auth function return values. */ +-#define AUTH_SUCCESS 0 +-#define AUTH_FAILURE 1 +-#define AUTH_INTR 2 +-#define AUTH_FATAL 3 ++/* Auth function return values (rowhammer resistent). */ ++#define AUTH_SUCCESS 0x52a2925 /* 0101001010100010100100100101 */ ++#define AUTH_FAILURE 0xad5d6da /* 1010110101011101011011011010 */ ++#define AUTH_INTR 0x69d61fc8 /* 1101001110101100001111111001000 */ ++#define AUTH_FATAL 0x1629e037 /* 0010110001010011110000000110111 */ + + typedef struct sudo_auth { + int flags; /* various flags, see below */ +diff --git a/plugins/sudoers/match.c b/plugins/sudoers/match.c +index 9324159..0891d63 100644 +--- a/plugins/sudoers/match.c ++++ b/plugins/sudoers/match.c +@@ -92,7 +92,7 @@ user_matches(struct sudoers_parse_tree *parse_tree, const struct passwd *pw, + if ((a = alias_get(parse_tree, m->name, USERALIAS)) != NULL) { + /* XXX */ + const int rc = userlist_matches(parse_tree, pw, &a->members); +- if (rc != UNSPEC) { ++ if (SPECIFIED(rc)) { + if (m->negated) { + matched = rc == ALLOW ? DENY : ALLOW; + } else { +@@ -124,7 +124,8 @@ userlist_matches(struct sudoers_parse_tree *parse_tree, const struct passwd *pw, + debug_decl(userlist_matches, SUDOERS_DEBUG_MATCH); + + TAILQ_FOREACH_REVERSE(m, list, member_list, entries) { +- if ((matched = user_matches(parse_tree, pw, m)) != UNSPEC) ++ matched = user_matches(parse_tree, pw, m); ++ if (SPECIFIED(matched)) + break; + } + debug_return_int(matched); +@@ -194,7 +195,7 @@ runaslist_matches(struct sudoers_parse_tree *parse_tree, + if (a != NULL) { + rc = runaslist_matches(parse_tree, &a->members, + &empty, matching_user, NULL); +- if (rc != UNSPEC) { ++ if (SPECIFIED(rc)) { + if (m->negated) { + user_matched = rc == ALLOW ? DENY : ALLOW; + } else { +@@ -215,7 +216,7 @@ runaslist_matches(struct sudoers_parse_tree *parse_tree, + user_matched = m->negated ? DENY : ALLOW; + break; + } +- if (user_matched != UNSPEC) { ++ if (SPECIFIED(user_matched)) { + if (matching_user != NULL && m->type != ALIAS) + *matching_user = m; + break; +@@ -228,7 +229,7 @@ runaslist_matches(struct sudoers_parse_tree *parse_tree, + * Skip checking runas group if none was specified. + */ + if (ISSET(sudo_user.flags, RUNAS_GROUP_SPECIFIED)) { +- if (user_matched == UNSPEC) { ++ if (!SPECIFIED(user_matched)) { + if (strcmp(user_name, runas_pw->pw_name) == 0) + user_matched = ALLOW; /* only changing group */ + } +@@ -243,7 +244,7 @@ runaslist_matches(struct sudoers_parse_tree *parse_tree, + if (a != NULL) { + rc = runaslist_matches(parse_tree, &empty, + &a->members, NULL, matching_group); +- if (rc != UNSPEC) { ++ if (SPECIFIED(rc)) { + if (m->negated) { + group_matched = rc == ALLOW ? DENY : ALLOW; + } else { +@@ -259,14 +260,14 @@ runaslist_matches(struct sudoers_parse_tree *parse_tree, + group_matched = m->negated ? DENY : ALLOW; + break; + } +- if (group_matched != UNSPEC) { ++ if (SPECIFIED(group_matched)) { + if (matching_group != NULL && m->type != ALIAS) + *matching_group = m; + break; + } + } + } +- if (group_matched == UNSPEC) { ++ if (!SPECIFIED(group_matched)) { + struct gid_list *runas_groups; + /* + * The runas group was not explicitly allowed by sudoers. +@@ -310,7 +311,7 @@ hostlist_matches_int(struct sudoers_parse_tree *parse_tree, + + TAILQ_FOREACH_REVERSE(m, list, member_list, entries) { + matched = host_matches(parse_tree, pw, lhost, shost, m); +- if (matched != UNSPEC) ++ if (SPECIFIED(matched)) + break; + } + debug_return_int(matched); +@@ -361,7 +362,7 @@ host_matches(struct sudoers_parse_tree *parse_tree, const struct passwd *pw, + /* XXX */ + const int rc = hostlist_matches_int(parse_tree, pw, lhost, + shost, &a->members); +- if (rc != UNSPEC) { ++ if (SPECIFIED(rc)) { + if (m->negated) { + matched = rc == ALLOW ? DENY : ALLOW; + } else { +@@ -395,7 +396,7 @@ cmndlist_matches(struct sudoers_parse_tree *parse_tree, + + TAILQ_FOREACH_REVERSE(m, list, member_list, entries) { + matched = cmnd_matches(parse_tree, m, runchroot, info); +- if (matched != UNSPEC) ++ if (SPECIFIED(matched)) + break; + } + debug_return_int(matched); +@@ -425,7 +426,7 @@ cmnd_matches(struct sudoers_parse_tree *parse_tree, const struct member *m, + a = alias_get(parse_tree, m->name, CMNDALIAS); + if (a != NULL) { + rc = cmndlist_matches(parse_tree, &a->members, runchroot, info); +- if (rc != UNSPEC) { ++ if (SPECIFIED(rc)) { + if (m->negated) { + matched = rc == ALLOW ? DENY : ALLOW; + } else { +diff --git a/plugins/sudoers/parse.c b/plugins/sudoers/parse.c +index d3bf8a5..e38e7e9 100644 +--- a/plugins/sudoers/parse.c ++++ b/plugins/sudoers/parse.c +@@ -153,7 +153,7 @@ sudoers_lookup_check(struct sudo_nss *nss, struct passwd *pw, + if (runas_match == ALLOW) { + cmnd_match = cmnd_matches(nss->parse_tree, cs->cmnd, + cs->runchroot, info); +- if (cmnd_match != UNSPEC) { ++ if (SPECIFIED(cmnd_match)) { + /* + * If user is running command as himself, + * set runas_pw = sudo_user.pw. +@@ -396,7 +396,7 @@ sudoers_lookup(struct sudo_nss_list *snl, struct passwd *pw, int *cmnd_status, + } + + m = sudoers_lookup_check(nss, pw, &validated, &info, &cs, &defs, now); +- if (m != UNSPEC) { ++ if (SPECIFIED(m)) { + match = m; + parse_tree = nss->parse_tree; + } +@@ -404,7 +404,7 @@ sudoers_lookup(struct sudo_nss_list *snl, struct passwd *pw, int *cmnd_status, + if (!sudo_nss_can_continue(nss, m)) + break; + } +- if (match != UNSPEC) { ++ if (SPECIFIED(match)) { + if (info.cmnd_path != NULL) { + /* Update user_cmnd, user_stat, cmnd_status from matching entry. */ + free(user_cmnd); +diff --git a/plugins/sudoers/parse.h b/plugins/sudoers/parse.h +index ea2a179..8559849 100644 +--- a/plugins/sudoers/parse.h ++++ b/plugins/sudoers/parse.h +@@ -34,15 +34,28 @@ + # define SUDOERS_NAME_MATCH + #endif + ++/* Allowed by policy (rowhammer resistent). */ ++#undef ALLOW ++#define ALLOW 0x52a2925 /* 0101001010100010100100100101 */ ++ ++/* Denied by policy (rowhammer resistent). */ ++#undef DENY ++#define DENY 0xad5d6da /* 1010110101011101011011011010 */ ++ ++/* Neither allowed, nor denied. */ + #undef UNSPEC + #define UNSPEC -1 +-#undef DENY +-#define DENY 0 +-#undef ALLOW +-#define ALLOW 1 ++ ++/* Tag implied by root access (SETENV only). */ + #undef IMPLIED + #define IMPLIED 2 + ++/* ++ * We must explicitly check against ALLOW and DENY instead testing ++ * that the value is not UNSPEC to avoid potential ROWHAMMER issues. ++ */ ++#define SPECIFIED(_v) ((_v) == ALLOW || (_v) == DENY) ++ + /* + * Initialize all tags to UNSPEC. + */ +@@ -92,7 +105,7 @@ + * Returns true if the specified tag is not UNSPEC or IMPLIED, else false. + */ + #define TAG_SET(tt) \ +- ((tt) != UNSPEC && (tt) != IMPLIED) ++ ((tt) == true || (tt) == false) + + /* + * Returns true if any tags set in nt differ between ot and nt, else false. +-- +2.42.0.windows.2 + diff --git a/backport-Do-not-rely-on-the-definition-of-ALLOW-DENY-being-tr.patch b/backport-Do-not-rely-on-the-definition-of-ALLOW-DENY-being-tr.patch new file mode 100644 index 0000000..85607dc --- /dev/null +++ b/backport-Do-not-rely-on-the-definition-of-ALLOW-DENY-being-tr.patch @@ -0,0 +1,249 @@ +From cf00568d888c90a8c5d06a06283bc87a45992933 Mon Sep 17 00:00:00 2001 +From: "Todd C. Miller" +Date: Sat, 26 Aug 2023 10:32:37 -0600 +Subject: [PATCH] Do not rely on the definition of ALLOW/DENY being true/false. + +We now explicitly check for ALLOW and DENY when checking return +values and negating values. + +Reference: https://github.com/sudo-project/sudo/commit/cf00568d888c90a8c5d06a06283bc87a45992933 +Conflict: cvtsudoers.c match.c +--- + plugins/sudoers/cvtsudoers.c | 6 +-- + plugins/sudoers/match.c | 83 +++++++++++++++++++++++------------- + 2 files changed, 57 insertions(+), 32 deletions(-) + +diff --git a/plugins/sudoers/cvtsudoers.c b/plugins/sudoers/cvtsudoers.c +index 79558c3..8cedcc6 100644 +--- a/plugins/sudoers/cvtsudoers.c ++++ b/plugins/sudoers/cvtsudoers.c +@@ -690,7 +690,7 @@ userlist_matches_filter(struct sudoers_parse_tree *parse_tree, + pw.pw_uid = (uid_t)-1; + pw.pw_gid = (gid_t)-1; + +- if (user_matches(parse_tree, &pw, m) == true) ++ if (user_matches(parse_tree, &pw, m) == ALLOW) + matched = true; + } else { + STAILQ_FOREACH(s, &filters->users, entries) { +@@ -716,7 +716,7 @@ userlist_matches_filter(struct sudoers_parse_tree *parse_tree, + if (pw == NULL) + continue; + +- if (user_matches(parse_tree, pw, m) == true) ++ if (user_matches(parse_tree, pw, m) == ALLOW) + matched = true; + sudo_pw_delref(pw); + +@@ -792,7 +792,7 @@ hostlist_matches_filter(struct sudoers_parse_tree *parse_tree, + + /* Only need one host in the filter to match. */ + /* XXX - can't use netgroup_tuple with NULL pw */ +- if (host_matches(parse_tree, NULL, lhost, shost, m) == true) { ++ if (host_matches(parse_tree, NULL, lhost, shost, m) == ALLOW) { + matched = true; + break; + } +diff --git a/plugins/sudoers/match.c b/plugins/sudoers/match.c +index 9801f38..9324159 100644 +--- a/plugins/sudoers/match.c ++++ b/plugins/sudoers/match.c +@@ -76,31 +76,36 @@ user_matches(struct sudoers_parse_tree *parse_tree, const struct passwd *pw, + + switch (m->type) { + case ALL: +- matched = !m->negated; ++ matched = m->negated ? DENY : ALLOW; + break; + case NETGROUP: + if (netgr_matches(m->name, + def_netgroup_tuple ? lhost : NULL, + def_netgroup_tuple ? shost : NULL, pw->pw_name)) +- matched = !m->negated; ++ matched = m->negated ? DENY : ALLOW; + break; + case USERGROUP: + if (usergr_matches(m->name, pw->pw_name, pw)) +- matched = !m->negated; ++ matched = m->negated ? DENY : ALLOW; + break; + case ALIAS: + if ((a = alias_get(parse_tree, m->name, USERALIAS)) != NULL) { + /* XXX */ +- int rc = userlist_matches(parse_tree, pw, &a->members); +- if (rc != UNSPEC) +- matched = m->negated ? !rc : rc; ++ const int rc = userlist_matches(parse_tree, pw, &a->members); ++ if (rc != UNSPEC) { ++ if (m->negated) { ++ matched = rc == ALLOW ? DENY : ALLOW; ++ } else { ++ matched = rc; ++ } ++ } + alias_put(a); + break; + } + FALLTHROUGH; + case WORD: + if (userpw_matches(m->name, pw->pw_name, pw)) +- matched = !m->negated; ++ matched = m->negated ? DENY : ALLOW; + break; + } + debug_return_int(matched); +@@ -171,38 +176,43 @@ runaslist_matches(struct sudoers_parse_tree *parse_tree, + TAILQ_FOREACH_REVERSE(m, user_list, member_list, entries) { + switch (m->type) { + case ALL: +- user_matched = !m->negated; ++ user_matched = m->negated ? DENY : ALLOW; + break; + case NETGROUP: + if (netgr_matches(m->name, + def_netgroup_tuple ? lhost : NULL, + def_netgroup_tuple ? shost : NULL, + runas_pw->pw_name)) +- user_matched = !m->negated; ++ user_matched = m->negated ? DENY : ALLOW; + break; + case USERGROUP: + if (usergr_matches(m->name, runas_pw->pw_name, runas_pw)) +- user_matched = !m->negated; ++ user_matched = m->negated ? DENY : ALLOW; + break; + case ALIAS: + a = alias_get(parse_tree, m->name, RUNASALIAS); + if (a != NULL) { + rc = runaslist_matches(parse_tree, &a->members, + &empty, matching_user, NULL); +- if (rc != UNSPEC) +- user_matched = m->negated ? !rc : rc; ++ if (rc != UNSPEC) { ++ if (m->negated) { ++ user_matched = rc == ALLOW ? DENY : ALLOW; ++ } else { ++ user_matched = rc; ++ } ++ } + alias_put(a); + break; + } + FALLTHROUGH; + case WORD: + if (userpw_matches(m->name, runas_pw->pw_name, runas_pw)) +- user_matched = !m->negated; ++ user_matched = m->negated ? DENY : ALLOW; + break; + case MYSELF: + if (!ISSET(sudo_user.flags, RUNAS_USER_SPECIFIED) || + strcmp(user_name, runas_pw->pw_name) == 0) +- user_matched = !m->negated; ++ user_matched = m->negated ? DENY : ALLOW; + break; + } + if (user_matched != UNSPEC) { +@@ -226,22 +236,27 @@ runaslist_matches(struct sudoers_parse_tree *parse_tree, + TAILQ_FOREACH_REVERSE(m, group_list, member_list, entries) { + switch (m->type) { + case ALL: +- group_matched = !m->negated; ++ group_matched = m->negated ? DENY : ALLOW; + break; + case ALIAS: + a = alias_get(parse_tree, m->name, RUNASALIAS); + if (a != NULL) { + rc = runaslist_matches(parse_tree, &empty, + &a->members, NULL, matching_group); +- if (rc != UNSPEC) +- group_matched = m->negated ? !rc : rc; ++ if (rc != UNSPEC) { ++ if (m->negated) { ++ group_matched = rc == ALLOW ? DENY : ALLOW; ++ } else { ++ group_matched = rc; ++ } ++ } + alias_put(a); + break; + } + FALLTHROUGH; + case WORD: + if (group_matches(m->name, runas_gr)) +- group_matched = !m->negated; ++ group_matched = m->negated ? DENY : ALLOW; + break; + } + if (group_matched != UNSPEC) { +@@ -329,32 +344,37 @@ host_matches(struct sudoers_parse_tree *parse_tree, const struct passwd *pw, + + switch (m->type) { + case ALL: +- matched = !m->negated; ++ matched = m->negated ? DENY : ALLOW; + break; + case NETGROUP: + if (netgr_matches(m->name, lhost, shost, + def_netgroup_tuple ? pw->pw_name : NULL)) +- matched = !m->negated; ++ matched = m->negated ? DENY : ALLOW; + break; + case NTWKADDR: + if (addr_matches(m->name)) +- matched = !m->negated; ++ matched = m->negated ? DENY : ALLOW; + break; + case ALIAS: + a = alias_get(parse_tree, m->name, HOSTALIAS); + if (a != NULL) { + /* XXX */ +- int rc = hostlist_matches_int(parse_tree, pw, lhost, shost, +- &a->members); +- if (rc != UNSPEC) +- matched = m->negated ? !rc : rc; ++ const int rc = hostlist_matches_int(parse_tree, pw, lhost, ++ shost, &a->members); ++ if (rc != UNSPEC) { ++ if (m->negated) { ++ matched = rc == ALLOW ? DENY : ALLOW; ++ } else { ++ matched = rc; ++ } ++ } + alias_put(a); + break; + } + FALLTHROUGH; + case WORD: + if (hostname_matches(shost, lhost, m->name)) +- matched = !m->negated; ++ matched = m->negated ? DENY : ALLOW; + break; + } + debug_return_int(matched); +@@ -399,14 +419,19 @@ cmnd_matches(struct sudoers_parse_tree *parse_tree, const struct member *m, + case COMMAND: + c = (struct sudo_command *)m->name; + if (command_matches(c->cmnd, c->args, runchroot, info, &c->digests)) +- matched = !m->negated; ++ matched = m->negated ? DENY : ALLOW; + break; + case ALIAS: + a = alias_get(parse_tree, m->name, CMNDALIAS); + if (a != NULL) { + rc = cmndlist_matches(parse_tree, &a->members, runchroot, info); +- if (rc != UNSPEC) +- matched = m->negated ? !rc : rc; ++ if (rc != UNSPEC) { ++ if (m->negated) { ++ matched = rc == ALLOW ? DENY : ALLOW; ++ } else { ++ matched = rc; ++ } ++ } + alias_put(a); + } + break; +-- +2.42.0.windows.2 + diff --git a/backport-Make-all-match-functions-return-ALLOW-DENY-.patch b/backport-Make-all-match-functions-return-ALLOW-DENY-.patch new file mode 100644 index 0000000..b03a2a2 --- /dev/null +++ b/backport-Make-all-match-functions-return-ALLOW-DENY-.patch @@ -0,0 +1,1117 @@ +From 2ef90231a132547fa4236ff05fc0fafcd3f3d7a4 Mon Sep 17 00:00:00 2001 +From: "Todd C. Miller" +Date: Sat, 9 Sep 2023 14:07:06 -0600 +Subject: [PATCH] Make all match functions return ALLOW/DENY not true/false. + +Reference: https://github.com/sudo-project/sudo/commit/2ef90231a132547fa4236ff05fc0fafcd3f3d7a4 +Conflict: match.c match_command.c lookup.c +--- + plugins/sudoers/ldap.c | 2 +- + plugins/sudoers/match.c | 147 +++++++++++--------- + plugins/sudoers/match_addr.c | 45 +++--- + plugins/sudoers/match_command.c | 131 ++++++++--------- + plugins/sudoers/match_digest.c | 12 +- + plugins/sudoers/parse.h | 16 +-- + plugins/sudoers/regress/parser/check_addr.c | 2 +- + plugins/sudoers/sssd.c | 6 +- + 8 files changed, 187 insertions(+), 174 deletions(-) + +diff --git a/plugins/sudoers/ldap.c b/plugins/sudoers/ldap.c +index 60ffeb9..44e4693 100644 +--- a/plugins/sudoers/ldap.c ++++ b/plugins/sudoers/ldap.c +@@ -341,7 +341,7 @@ sudo_ldap_check_non_unix_group(LDAP *ld, LDAPMessage *entry, struct passwd *pw) + val = (*p)->bv_val; + if (*val == '+') { + if (netgr_matches(val, def_netgroup_tuple ? user_runhost : NULL, +- def_netgroup_tuple ? user_srunhost : NULL, pw->pw_name)) ++ def_netgroup_tuple ? user_srunhost : NULL, pw->pw_name) == ALLOW) + ret = true; + DPRINTF2("ldap sudoUser netgroup '%s' ... %s", val, + ret ? "MATCH!" : "not"); +diff --git a/plugins/sudoers/match.c b/plugins/sudoers/match.c +index 0891d63..efb596e 100644 +--- a/plugins/sudoers/match.c ++++ b/plugins/sudoers/match.c +@@ -81,11 +81,11 @@ user_matches(struct sudoers_parse_tree *parse_tree, const struct passwd *pw, + case NETGROUP: + if (netgr_matches(m->name, + def_netgroup_tuple ? lhost : NULL, +- def_netgroup_tuple ? shost : NULL, pw->pw_name)) ++ def_netgroup_tuple ? shost : NULL, pw->pw_name) == ALLOW) + matched = m->negated ? DENY : ALLOW; + break; + case USERGROUP: +- if (usergr_matches(m->name, pw->pw_name, pw)) ++ if (usergr_matches(m->name, pw->pw_name, pw) == ALLOW) + matched = m->negated ? DENY : ALLOW; + break; + case ALIAS: +@@ -104,7 +104,7 @@ user_matches(struct sudoers_parse_tree *parse_tree, const struct passwd *pw, + } + FALLTHROUGH; + case WORD: +- if (userpw_matches(m->name, pw->pw_name, pw)) ++ if (userpw_matches(m->name, pw->pw_name, pw) == ALLOW) + matched = m->negated ? DENY : ALLOW; + break; + } +@@ -183,11 +183,11 @@ runaslist_matches(struct sudoers_parse_tree *parse_tree, + if (netgr_matches(m->name, + def_netgroup_tuple ? lhost : NULL, + def_netgroup_tuple ? shost : NULL, +- runas_pw->pw_name)) ++ runas_pw->pw_name) == ALLOW) + user_matched = m->negated ? DENY : ALLOW; + break; + case USERGROUP: +- if (usergr_matches(m->name, runas_pw->pw_name, runas_pw)) ++ if (usergr_matches(m->name, runas_pw->pw_name, runas_pw) == ALLOW) + user_matched = m->negated ? DENY : ALLOW; + break; + case ALIAS: +@@ -207,7 +207,7 @@ runaslist_matches(struct sudoers_parse_tree *parse_tree, + } + FALLTHROUGH; + case WORD: +- if (userpw_matches(m->name, runas_pw->pw_name, runas_pw)) ++ if (userpw_matches(m->name, runas_pw->pw_name, runas_pw) == ALLOW) + user_matched = m->negated ? DENY : ALLOW; + break; + case MYSELF: +@@ -256,7 +256,7 @@ runaslist_matches(struct sudoers_parse_tree *parse_tree, + } + FALLTHROUGH; + case WORD: +- if (group_matches(m->name, runas_gr)) ++ if (group_matches(m->name, runas_gr) == ALLOW) + group_matched = m->negated ? DENY : ALLOW; + break; + } +@@ -340,21 +340,21 @@ host_matches(struct sudoers_parse_tree *parse_tree, const struct passwd *pw, + const char *lhost, const char *shost, const struct member *m) + { + struct alias *a; +- int matched = UNSPEC; ++ int ret = UNSPEC; + debug_decl(host_matches, SUDOERS_DEBUG_MATCH); + + switch (m->type) { + case ALL: +- matched = m->negated ? DENY : ALLOW; ++ ret = m->negated ? DENY : ALLOW; + break; + case NETGROUP: + if (netgr_matches(m->name, lhost, shost, +- def_netgroup_tuple ? pw->pw_name : NULL)) +- matched = m->negated ? DENY : ALLOW; ++ def_netgroup_tuple ? pw->pw_name : NULL) == ALLOW) ++ ret = m->negated ? DENY : ALLOW; + break; + case NTWKADDR: +- if (addr_matches(m->name)) +- matched = m->negated ? DENY : ALLOW; ++ if (addr_matches(m->name) == ALLOW) ++ ret = m->negated ? DENY : ALLOW; + break; + case ALIAS: + a = alias_get(parse_tree, m->name, HOSTALIAS); +@@ -364,9 +364,9 @@ host_matches(struct sudoers_parse_tree *parse_tree, const struct passwd *pw, + shost, &a->members); + if (SPECIFIED(rc)) { + if (m->negated) { +- matched = rc == ALLOW ? DENY : ALLOW; ++ ret = rc == ALLOW ? DENY : ALLOW; + } else { +- matched = rc; ++ ret = rc; + } + } + alias_put(a); +@@ -374,11 +374,11 @@ host_matches(struct sudoers_parse_tree *parse_tree, const struct passwd *pw, + } + FALLTHROUGH; + case WORD: +- if (hostname_matches(shost, lhost, m->name)) +- matched = m->negated ? DENY : ALLOW; ++ if (hostname_matches(shost, lhost, m->name) == ALLOW) ++ ret = m->negated ? DENY : ALLOW; + break; + } +- debug_return_int(matched); ++ debug_return_int(ret); + } + + /* +@@ -391,15 +391,15 @@ cmndlist_matches(struct sudoers_parse_tree *parse_tree, + struct cmnd_info *info) + { + struct member *m; +- int matched = UNSPEC; ++ int matched; + debug_decl(cmndlist_matches, SUDOERS_DEBUG_MATCH); + + TAILQ_FOREACH_REVERSE(m, list, member_list, entries) { + matched = cmnd_matches(parse_tree, m, runchroot, info); + if (SPECIFIED(matched)) +- break; ++ debug_return_int(matched); + } +- debug_return_int(matched); ++ debug_return_int(UNSPEC); + } + + /* +@@ -419,7 +419,8 @@ cmnd_matches(struct sudoers_parse_tree *parse_tree, const struct member *m, + case ALL: + case COMMAND: + c = (struct sudo_command *)m->name; +- if (command_matches(c->cmnd, c->args, runchroot, info, &c->digests)) ++ if (command_matches(c->cmnd, c->args, runchroot, ++ info, &c->digests) == ALLOW) + matched = m->negated ? DENY : ALLOW; + break; + case ALIAS: +@@ -441,96 +442,105 @@ cmnd_matches(struct sudoers_parse_tree *parse_tree, const struct member *m, + } + + /* +- * Returns true if the hostname matches the pattern, else false ++ * Returns ALLOW if the hostname matches the pattern, else DENY + */ +-bool ++int + hostname_matches(const char *shost, const char *lhost, const char *pattern) + { + const char *host; +- bool rc; ++ int ret; + debug_decl(hostname_matches, SUDOERS_DEBUG_MATCH); + + host = strchr(pattern, '.') != NULL ? lhost : shost; ++ ret = DENY; + if (has_meta(pattern)) { +- rc = !fnmatch(pattern, host, FNM_CASEFOLD); ++ if (fnmatch(pattern, host, FNM_CASEFOLD) == 0) ++ ret = ALLOW; + } else { +- rc = !strcasecmp(host, pattern); ++ if (strcasecmp(host, pattern) == 0) ++ ret = ALLOW; + } + sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO, + "host %s matches sudoers pattern %s: %s", +- host, pattern, rc ? "true" : "false"); +- debug_return_bool(rc); ++ host, pattern, ret == ALLOW ? "ALLOW" : "DENY"); ++ debug_return_int(ret); + } + + /* +- * Returns true if the user/uid from sudoers matches the specified user/uid, +- * else returns false. ++ * Returns ALLOW if the user/uid from sudoers matches the specified user/uid, ++ * else returns DENY. + */ +-bool ++int + userpw_matches(const char *sudoers_user, const char *user, const struct passwd *pw) + { + const char *errstr; ++ int ret = DENY; + uid_t uid; +- bool rc; + debug_decl(userpw_matches, SUDOERS_DEBUG_MATCH); + + if (pw != NULL && *sudoers_user == '#') { + uid = (uid_t) sudo_strtoid(sudoers_user + 1, &errstr); + if (errstr == NULL && uid == pw->pw_uid) { +- rc = true; ++ ret = ALLOW; + goto done; + } + } +- if (def_case_insensitive_user) +- rc = strcasecmp(sudoers_user, user) == 0; +- else +- rc = strcmp(sudoers_user, user) == 0; ++ if (def_case_insensitive_user) { ++ if (strcasecmp(sudoers_user, user) == 0) ++ ret = ALLOW; ++ } else { ++ if (strcmp(sudoers_user, user) == 0) ++ ret = ALLOW; ++ } + done: + sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO, + "user %s matches sudoers user %s: %s", +- user, sudoers_user, rc ? "true" : "false"); +- debug_return_bool(rc); ++ user, sudoers_user, ret == ALLOW ? "ALLOW" : "DENY"); ++ debug_return_int(ret); + } + + /* +- * Returns true if the group/gid from sudoers matches the specified group/gid, +- * else returns false. ++ * Returns ALLOW if the group/gid from sudoers matches the specified group/gid, ++ * else returns DENY. + */ +-bool ++int + group_matches(const char *sudoers_group, const struct group *gr) + { + const char *errstr; ++ int ret = DENY; + gid_t gid; +- bool rc; + debug_decl(group_matches, SUDOERS_DEBUG_MATCH); + + if (*sudoers_group == '#') { + gid = (gid_t) sudo_strtoid(sudoers_group + 1, &errstr); + if (errstr == NULL && gid == gr->gr_gid) { +- rc = true; ++ ret = ALLOW; + goto done; + } + } +- if (def_case_insensitive_group) +- rc = strcasecmp(sudoers_group, gr->gr_name) == 0; +- else +- rc = strcmp(sudoers_group, gr->gr_name) == 0; ++ if (def_case_insensitive_group) { ++ if (strcasecmp(sudoers_group, gr->gr_name) == 0) ++ ret = ALLOW; ++ } else { ++ if (strcmp(sudoers_group, gr->gr_name) == 0) ++ ret = ALLOW; ++ } + done: + sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO, + "group %s matches sudoers group %s: %s", +- gr->gr_name, sudoers_group, rc ? "true" : "false"); +- debug_return_bool(rc); ++ gr->gr_name, sudoers_group, ret == ALLOW ? "ALLOW" : "DENY"); ++ debug_return_int(ret); + } + + /* + * Returns true if the given user belongs to the named group, + * else returns false. + */ +-bool ++int + usergr_matches(const char *group, const char *user, const struct passwd *pw) + { +- bool matched = false; + struct passwd *pw0 = NULL; ++ int ret = DENY; + debug_decl(usergr_matches, SUDOERS_DEBUG_MATCH); + + /* Make sure we have a valid usergroup, sudo style */ +@@ -543,7 +553,7 @@ usergr_matches(const char *group, const char *user, const struct passwd *pw) + /* Query group plugin for %:name groups. */ + if (*group == ':' && def_group_plugin) { + if (group_plugin_query(user, group + 1, pw) == true) +- matched = true; ++ ret = ALLOW; + goto done; + } + +@@ -558,14 +568,14 @@ usergr_matches(const char *group, const char *user, const struct passwd *pw) + } + + if (user_in_group(pw, group)) { +- matched = true; ++ ret = ALLOW; + goto done; + } + + /* Query the group plugin for Unix groups too? */ + if (def_group_plugin && def_always_query_group_plugin) { + if (group_plugin_query(user, group, pw) == true) { +- matched = true; ++ ret = ALLOW; + goto done; + } + } +@@ -575,8 +585,9 @@ done: + sudo_pw_delref(pw0); + + sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO, +- "user %s matches group %s: %s", user, group, matched ? "true" : "false"); +- debug_return_bool(matched); ++ "user %s matches group %s: %s", user, group, ++ ret == ALLOW ? "ALLOW" : "DENY"); ++ debug_return_int(ret); + } + + #if defined(HAVE_GETDOMAINNAME) || defined(SI_SRPC_DOMAIN) +@@ -652,22 +663,22 @@ sudo_getdomainname(void) + #endif /* HAVE_GETDOMAINNAME || SI_SRPC_DOMAIN */ + + /* +- * Returns true if "host" and "user" belong to the netgroup "netgr", +- * else return false. Either of "lhost", "shost" or "user" may be NULL ++ * Returns ALLOW if "host" and "user" belong to the netgroup "netgr", ++ * else return DENY. Either of "lhost", "shost" or "user" may be NULL + * in which case that argument is not checked... + */ +-bool ++int + netgr_matches(const char *netgr, const char *lhost, const char *shost, const char *user) + { + #ifdef HAVE_INNETGR + const char *domain; + #endif +- bool rc = false; ++ int ret = DENY; + debug_decl(netgr_matches, SUDOERS_DEBUG_MATCH); + + if (!def_use_netgroups) { + sudo_debug_printf(SUDO_DEBUG_INFO, "netgroups are disabled"); +- debug_return_bool(false); ++ debug_return_int(DENY); + } + + #ifdef HAVE_INNETGR +@@ -675,22 +686,22 @@ netgr_matches(const char *netgr, const char *lhost, const char *shost, const cha + if (*netgr++ != '+') { + sudo_debug_printf(SUDO_DEBUG_DIAG, "netgroup %s has no leading '+'", + netgr); +- debug_return_bool(false); ++ debug_return_int(DENY); + } + + /* get the domain name (if any) */ + domain = sudo_getdomainname(); + + if (innetgr(netgr, lhost, user, domain)) +- rc = true; ++ ret = ALLOW; + else if (lhost != shost && innetgr(netgr, shost, user, domain)) +- rc = true; ++ ret = ALLOW; + + sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO, + "netgroup %s matches (%s|%s, %s, %s): %s", netgr, lhost ? lhost : "", + shost ? shost : "", user ? user : "", domain ? domain : "", +- rc ? "true" : "false"); ++ ret == ALLOW ? "ALLOW" : "DENY"); + #endif /* HAVE_INNETGR */ + +- debug_return_bool(rc); ++ debug_return_int(ret); + } +diff --git a/plugins/sudoers/match_addr.c b/plugins/sudoers/match_addr.c +index 714c41c..3b701c9 100644 +--- a/plugins/sudoers/match_addr.c ++++ b/plugins/sudoers/match_addr.c +@@ -44,7 +44,7 @@ + #include "sudoers.h" + #include "interfaces.h" + +-static bool ++static int + addr_matches_if(const char *n) + { + union sudo_in_addr_un addr; +@@ -63,7 +63,7 @@ addr_matches_if(const char *n) + if (inet_pton(AF_INET, n, &addr.ip4) == 1) { + family = AF_INET; + } else { +- debug_return_bool(false); ++ debug_return_int(DENY); + } + + SLIST_FOREACH(ifp, get_interfaces(), entries) { +@@ -74,28 +74,28 @@ addr_matches_if(const char *n) + if (ifp->addr.ip4.s_addr == addr.ip4.s_addr || + (ifp->addr.ip4.s_addr & ifp->netmask.ip4.s_addr) + == addr.ip4.s_addr) +- debug_return_bool(true); ++ debug_return_int(ALLOW); + break; + #ifdef HAVE_STRUCT_IN6_ADDR + case AF_INET6: + if (memcmp(ifp->addr.ip6.s6_addr, addr.ip6.s6_addr, + sizeof(addr.ip6.s6_addr)) == 0) +- debug_return_bool(true); ++ debug_return_int(ALLOW); + for (j = 0; j < sizeof(addr.ip6.s6_addr); j++) { + if ((ifp->addr.ip6.s6_addr[j] & ifp->netmask.ip6.s6_addr[j]) != addr.ip6.s6_addr[j]) + break; + } + if (j == sizeof(addr.ip6.s6_addr)) +- debug_return_bool(true); ++ debug_return_int(ALLOW); + break; + #endif /* HAVE_STRUCT_IN6_ADDR */ + } + } + +- debug_return_bool(false); ++ debug_return_int(DENY); + } + +-static bool ++static int + addr_matches_if_netmask(const char *n, const char *m) + { + unsigned int i; +@@ -116,7 +116,7 @@ addr_matches_if_netmask(const char *n, const char *m) + if (inet_pton(AF_INET, n, &addr.ip4) == 1) { + family = AF_INET; + } else { +- debug_return_bool(false); ++ debug_return_int(DENY); + } + + if (family == AF_INET) { +@@ -124,14 +124,14 @@ addr_matches_if_netmask(const char *n, const char *m) + if (inet_pton(AF_INET, m, &mask.ip4) != 1) { + sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, + "IPv4 netmask %s: %s", m, "invalid value"); +- debug_return_bool(false); ++ debug_return_int(DENY); + } + } else { + i = sudo_strtonum(m, 1, 32, &errstr); + if (errstr != NULL) { + sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, + "IPv4 netmask %s: %s", m, errstr); +- debug_return_bool(false); ++ debug_return_int(DENY); + } + mask.ip4.s_addr = htonl(0xffffffffU << (32 - i)); + } +@@ -144,7 +144,7 @@ addr_matches_if_netmask(const char *n, const char *m) + if (errstr != NULL) { + sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, + "IPv6 netmask %s: %s", m, errstr); +- debug_return_bool(false); ++ debug_return_int(DENY); + } + for (i = 0; i < sizeof(addr.ip6.s6_addr); i++) { + if (j < i * 8) +@@ -165,7 +165,7 @@ addr_matches_if_netmask(const char *n, const char *m) + switch (family) { + case AF_INET: + if ((ifp->addr.ip4.s_addr & mask.ip4.s_addr) == addr.ip4.s_addr) +- debug_return_bool(true); ++ debug_return_int(ALLOW); + break; + #ifdef HAVE_STRUCT_IN6_ADDR + case AF_INET6: +@@ -174,35 +174,36 @@ addr_matches_if_netmask(const char *n, const char *m) + break; + } + if (j == sizeof(addr.ip6.s6_addr)) +- debug_return_bool(true); ++ debug_return_int(ALLOW); + break; + #endif /* HAVE_STRUCT_IN6_ADDR */ + } + } + +- debug_return_bool(false); ++ debug_return_int(DENY); + } + + /* +- * Returns true if "n" is one of our ip addresses or if +- * "n" is a network that we are on, else returns false. ++ * Returns ALLOW if "n" is one of our ip addresses or if ++ * "n" is a network that we are on, else returns DENY. + */ +-bool ++int + addr_matches(char *n) + { + char *m; +- bool rc; ++ int ret; + debug_decl(addr_matches, SUDOERS_DEBUG_MATCH); + + /* If there's an explicit netmask, use it. */ + if ((m = strchr(n, '/'))) { + *m++ = '\0'; +- rc = addr_matches_if_netmask(n, m); ++ ret = addr_matches_if_netmask(n, m); + *(m - 1) = '/'; + } else +- rc = addr_matches_if(n); ++ ret = addr_matches_if(n); + + sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_LINENO, +- "IP address %s matches local host: %s", n, rc ? "true" : "false"); +- debug_return_bool(rc); ++ "IP address %s matches local host: %s", n, ++ ret == ALLOW ? "ALLOW" : "DENY"); ++ debug_return_int(ret); + } +diff --git a/plugins/sudoers/match_command.c b/plugins/sudoers/match_command.c +index f1c09bd..ee89741 100644 +--- a/plugins/sudoers/match_command.c ++++ b/plugins/sudoers/match_command.c +@@ -56,7 +56,7 @@ + # define O_EXEC O_PATH + #endif + +-static bool ++static int + command_args_match(const char *sudoers_cmnd, const char *sudoers_args) + { + int flags = 0; +@@ -67,7 +67,7 @@ command_args_match(const char *sudoers_cmnd, const char *sudoers_args) + * If the empty string is specified in sudoers, no user args are allowed. + */ + if (!sudoers_args || (!user_args && !strcmp("\"\"", sudoers_args))) +- debug_return_bool(true); ++ debug_return_int(ALLOW); + + /* + * If args are specified in sudoers, they must match the user args. +@@ -76,9 +76,9 @@ command_args_match(const char *sudoers_cmnd, const char *sudoers_args) + if (strcmp(sudoers_cmnd, "sudoedit") == 0) + flags = FNM_PATHNAME; + if (fnmatch(sudoers_args, user_args ? user_args : "", flags) == 0) +- debug_return_bool(true); ++ debug_return_int(ALLOW); + +- debug_return_bool(false); ++ debug_return_int(DENY); + } + + #ifndef SUDOERS_NAME_MATCH +@@ -229,7 +229,7 @@ set_cmnd_fd(int fd) + /* + * Return true if user_cmnd names one of the inodes in dir, else false. + */ +-static bool ++static int + command_matches_dir(const char *sudoers_dir, size_t dlen, const char *runchroot, + bool intercepted, const struct command_digest_list *digests) + { +@@ -247,7 +247,7 @@ command_matches_dir(const char *sudoers_dir, size_t dlen, const char *runchroot, + snprintf(sdbuf, sizeof(sdbuf), "%s%s", runchroot, sudoers_dir); + if (len >= ssizeof(sdbuf)) { + errno = ENAMETOOLONG; +- debug_return_bool(false); ++ debug_return_int(DENY); + } + sudoers_dir = sdbuf; + chrootlen = strlen(runchroot); +@@ -258,11 +258,11 @@ command_matches_dir(const char *sudoers_dir, size_t dlen, const char *runchroot, + */ + dirp = opendir(sudoers_dir); + if (dirp == NULL) +- debug_return_bool(false); ++ debug_return_int(DENY); + + if (strlcpy(buf, sudoers_dir, sizeof(buf)) >= sizeof(buf)) { + closedir(dirp); +- debug_return_bool(false); ++ debug_return_int(DENY); + } + while ((dent = readdir(dirp)) != NULL) { + if (fd != -1) { +@@ -289,7 +289,7 @@ command_matches_dir(const char *sudoers_dir, size_t dlen, const char *runchroot, + (user_stat->st_dev == sudoers_stat.st_dev && + user_stat->st_ino == sudoers_stat.st_ino)) { + /* buf is already relative to runchroot */ +- if (!digest_matches(fd, buf, NULL, digests)) ++ if (digest_matches(fd, buf, NULL, digests) != ALLOW) + continue; + free(safe_cmnd); + if ((safe_cmnd = strdup(buf + chrootlen)) == NULL) { +@@ -304,17 +304,17 @@ command_matches_dir(const char *sudoers_dir, size_t dlen, const char *runchroot, + + if (dent != NULL) { + set_cmnd_fd(fd); +- debug_return_bool(true); ++ debug_return_int(ALLOW); + } + if (fd != -1) + close(fd); +- debug_return_bool(false); ++ debug_return_int(DENY); + } + #else /* SUDOERS_NAME_MATCH */ + /* + * Return true if user_cmnd names one of the inodes in dir, else false. + */ +-static bool ++static int + command_matches_dir(const char *sudoers_dir, size_t dlen, const char *runchroot, + bool intercepted, const struct command_digest_list *digests) + { +@@ -332,19 +332,19 @@ command_matches_dir(const char *sudoers_dir, size_t dlen, const char *runchroot, + /* Open the file for fdexec or for digest matching. */ + if (!open_cmnd(user_cmnd, runchroot, digests, &fd)) + goto bad; +- if (!digest_matches(fd, user_cmnd, runchroot, digests)) ++ if (digest_matches(fd, user_cmnd, runchroot, digests) != ALLOW) + goto bad; + set_cmnd_fd(fd); + +- debug_return_bool(true); ++ debug_return_int(ALLOW); + bad: + if (fd != -1) + close(fd); +- debug_return_bool(false); ++ debug_return_int(DENY); + } + #endif /* SUDOERS_NAME_MATCH */ + +-static bool ++static int + command_matches_all(const char *runchroot, + bool intercepted, const struct command_digest_list *digests) + { +@@ -366,19 +366,19 @@ command_matches_all(const char *runchroot, + } + + /* Check digest of user_cmnd since we have no sudoers_cmnd for ALL. */ +- if (!digest_matches(fd, user_cmnd, runchroot, digests)) ++ if (digest_matches(fd, user_cmnd, runchroot, digests) != ALLOW) + goto bad; + set_cmnd_fd(fd); + + /* No need to set safe_cmnd for ALL. */ +- debug_return_bool(true); ++ debug_return_int(ALLOW); + bad: + if (fd != -1) + close(fd); +- debug_return_bool(false); ++ debug_return_int(DENY); + } + +-static bool ++static int + command_matches_fnmatch(const char *sudoers_cmnd, const char *sudoers_args, + const char *runchroot, bool intercepted, + const struct command_digest_list *digests) +@@ -396,8 +396,8 @@ command_matches_fnmatch(const char *sudoers_cmnd, const char *sudoers_args, + * Neither sudoers_cmnd nor user_cmnd are relative to runchroot. + */ + if (fnmatch(sudoers_cmnd, user_cmnd, FNM_PATHNAME) != 0) +- debug_return_bool(false); +- if (command_args_match(sudoers_cmnd, sudoers_args)) { ++ debug_return_int(DENY); ++ if (command_args_match(sudoers_cmnd, sudoers_args) == ALLOW) { + /* Open the file for fdexec or for digest matching. */ + if (!open_cmnd(user_cmnd, runchroot, digests, &fd)) + goto bad; +@@ -406,22 +406,22 @@ command_matches_fnmatch(const char *sudoers_cmnd, const char *sudoers_args, + goto bad; + #endif + /* Check digest of user_cmnd since sudoers_cmnd is a pattern. */ +- if (!digest_matches(fd, user_cmnd, runchroot, digests)) ++ if (digest_matches(fd, user_cmnd, runchroot, digests) != ALLOW) + goto bad; + set_cmnd_fd(fd); + + /* No need to set safe_cmnd since user_cmnd matches sudoers_cmnd */ +- debug_return_bool(true); ++ debug_return_int(ALLOW); + bad: + if (fd != -1) + close(fd); +- debug_return_bool(false); ++ debug_return_int(DENY); + } +- debug_return_bool(false); ++ debug_return_int(DENY); + } + + #ifndef SUDOERS_NAME_MATCH +-static bool ++static int + command_matches_glob(const char *sudoers_cmnd, const char *sudoers_args, + const char *runchroot, bool intercepted, + const struct command_digest_list *digests) +@@ -444,7 +444,7 @@ command_matches_glob(const char *sudoers_cmnd, const char *sudoers_args, + if (sudoers_cmnd[dlen - 1] != '/') { + base = sudo_basename(sudoers_cmnd); + if (!has_meta(base) && strcmp(user_base, base) != 0) +- debug_return_bool(false); ++ debug_return_int(DENY); + } + + /* Make sudoers_cmnd relative to the new root, if any. */ +@@ -453,22 +453,22 @@ command_matches_glob(const char *sudoers_cmnd, const char *sudoers_args, + snprintf(pathbuf, sizeof(pathbuf), "%s%s", runchroot, sudoers_cmnd); + if (len >= ssizeof(pathbuf)) { + errno = ENAMETOOLONG; +- debug_return_bool(false); ++ debug_return_int(DENY); + } + sudoers_cmnd = pathbuf; + chrootlen = strlen(runchroot); + } + + /* +- * Return true if we find a match in the glob(3) results AND ++ * Return ALLOW if we find a match in the glob(3) results 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 false. ++ * else return DENY. + */ + if (glob(sudoers_cmnd, GLOB_NOSORT, NULL, &gl) != 0 || gl.gl_pathc == 0) { + globfree(&gl); +- debug_return_bool(false); ++ debug_return_int(DENY); + } + /* If user_cmnd is fully-qualified, check for an exact match. */ + if (user_cmnd[0] == '/') { +@@ -491,7 +491,7 @@ command_matches_glob(const char *sudoers_cmnd, const char *sudoers_args, + (user_stat->st_dev == sudoers_stat.st_dev && + user_stat->st_ino == sudoers_stat.st_ino)) { + /* There could be multiple matches, check digest early. */ +- if (!digest_matches(fd, cp, runchroot, digests)) { ++ if (digest_matches(fd, cp, runchroot, digests) != ALLOW) { + bad_digest = true; + continue; + } +@@ -522,9 +522,9 @@ command_matches_glob(const char *sudoers_cmnd, const char *sudoers_args, + /* If it ends in '/' it is a directory spec. */ + dlen = strlen(cp); + if (cp[dlen - 1] == '/') { +- if (command_matches_dir(cp, dlen, runchroot, intercepted, digests)) { ++ if (command_matches_dir(cp, dlen, runchroot, intercepted, digests) == ALLOW) { + globfree(&gl); +- debug_return_bool(true); ++ debug_return_int(ALLOW); + } + continue; + } +@@ -542,7 +542,7 @@ command_matches_glob(const char *sudoers_cmnd, const char *sudoers_args, + if (user_stat == NULL || + (user_stat->st_dev == sudoers_stat.st_dev && + user_stat->st_ino == sudoers_stat.st_ino)) { +- if (!digest_matches(fd, cp, runchroot, digests)) ++ if (digest_matches(fd, cp, runchroot, digests) != ALLOW) + continue; + free(safe_cmnd); + if ((safe_cmnd = strdup(cp)) == NULL) { +@@ -557,18 +557,18 @@ command_matches_glob(const char *sudoers_cmnd, const char *sudoers_args, + done: + globfree(&gl); + if (cp != NULL) { +- if (command_args_match(sudoers_cmnd, sudoers_args)) { ++ if (command_args_match(sudoers_cmnd, sudoers_args) == ALLOW) { + /* safe_cmnd was set above. */ + set_cmnd_fd(fd); +- debug_return_bool(true); ++ debug_return_int(ALLOW); + } + } + if (fd != -1) + close(fd); +- debug_return_bool(false); ++ debug_return_int(DENY); + } + +-static bool ++static int + command_matches_normal(const char *sudoers_cmnd, const char *sudoers_args, + const char *runchroot, bool intercepted, + const struct command_digest_list *digests) +@@ -582,14 +582,14 @@ command_matches_normal(const char *sudoers_cmnd, const char *sudoers_args, + /* If it ends in '/' it is a directory spec. */ + dlen = strlen(sudoers_cmnd); + if (sudoers_cmnd[dlen - 1] == '/') { +- debug_return_bool(command_matches_dir(sudoers_cmnd, dlen, runchroot, ++ debug_return_int(command_matches_dir(sudoers_cmnd, dlen, runchroot, + intercepted, digests)); + } + + /* Only proceed if user_base and basename(sudoers_cmnd) match */ + base = sudo_basename(sudoers_cmnd); + if (strcmp(user_base, base) != 0) +- debug_return_bool(false); ++ debug_return_int(DENY); + + /* Open the file for fdexec or for digest matching. */ + if (!open_cmnd(sudoers_cmnd, runchroot, digests, &fd)) +@@ -611,9 +611,9 @@ command_matches_normal(const char *sudoers_cmnd, const char *sudoers_args, + if (strcmp(user_cmnd, sudoers_cmnd) != 0) + goto bad; + } +- if (!command_args_match(sudoers_cmnd, sudoers_args)) ++ if (command_args_match(sudoers_cmnd, sudoers_args) != ALLOW) + goto bad; +- if (!digest_matches(fd, sudoers_cmnd, runchroot, digests)) { ++ if (digest_matches(fd, sudoers_cmnd, runchroot, digests) != ALLOW) { + /* XXX - log functions not available but we should log very loudly */ + goto bad; + } +@@ -623,14 +623,14 @@ command_matches_normal(const char *sudoers_cmnd, const char *sudoers_args, + goto bad; + } + set_cmnd_fd(fd); +- debug_return_bool(true); ++ debug_return_int(ALLOW); + bad: + if (fd != -1) + close(fd); +- debug_return_bool(false); ++ debug_return_int(DENY); + } + #else /* SUDOERS_NAME_MATCH */ +-static bool ++static int + command_matches_glob(const char *sudoers_cmnd, const char *sudoers_args, + const char *runchroot, bool intercepted, + const struct command_digest_list *digests) +@@ -639,7 +639,7 @@ command_matches_glob(const char *sudoers_cmnd, const char *sudoers_args, + intercepted, digests); + } + +-static bool ++static int + command_matches_normal(const char *sudoers_cmnd, const char *sudoers_args, + const char *runchroot, bool intercepted, + const struct command_digest_list *digests) +@@ -651,16 +651,16 @@ command_matches_normal(const char *sudoers_cmnd, const char *sudoers_args, + /* If it ends in '/' it is a directory spec. */ + dlen = strlen(sudoers_cmnd); + if (sudoers_cmnd[dlen - 1] == '/') { +- debug_return_bool(command_matches_dir(sudoers_cmnd, dlen, runchroot, ++ debug_return_int(command_matches_dir(sudoers_cmnd, dlen, runchroot, + intercepted, digests)); + } + + if (strcmp(user_cmnd, sudoers_cmnd) == 0) { +- if (command_args_match(sudoers_cmnd, sudoers_args)) { ++ if (command_args_match(sudoers_cmnd, sudoers_args) == ALLOW) { + /* Open the file for fdexec or for digest matching. */ + if (!open_cmnd(user_cmnd, runchroot, digests, &fd)) + goto bad; +- if (!digest_matches(fd, user_cmnd, runchroot, digests)) ++ if (digest_matches(fd, user_cmnd, runchroot, digests) != ALLOW) + goto bad; + + /* Successful match. */ +@@ -671,21 +671,22 @@ command_matches_normal(const char *sudoers_cmnd, const char *sudoers_args, + goto bad; + } + set_cmnd_fd(fd); +- debug_return_bool(true); ++ debug_return_int(ALLOW); + } + } + bad: + if (fd != -1) + close(fd); +- debug_return_bool(false); ++ debug_return_int(DENY); + } + #endif /* SUDOERS_NAME_MATCH */ + + /* +- * If path doesn't end in /, return true iff cmnd & path name the same inode; +- * otherwise, return true if user_cmnd names one of the inodes in path. ++ * If path doesn't end in /, return ALLOW iff cmnd & path name the same inode; ++ * otherwise, return ALLOW if ctx->user.cmnd names one of the inodes in path. ++ * Returns DENY on failure. + */ +-bool ++int + command_matches(const char *sudoers_cmnd, const char *sudoers_args, + const char *runchroot, struct cmnd_info *info, + const struct command_digest_list *digests) +@@ -693,7 +694,7 @@ command_matches(const char *sudoers_cmnd, const char *sudoers_args, + const bool intercepted = info ? info->intercepted : false; + char *saved_user_cmnd = NULL; + struct stat saved_user_stat; +- bool rc = false; ++ int ret = DENY; + debug_decl(command_matches, SUDOERS_DEBUG_MATCH); + + if (user_runchroot != NULL) { +@@ -728,7 +729,7 @@ command_matches(const char *sudoers_cmnd, const char *sudoers_args, + + if (sudoers_cmnd == NULL) { + sudoers_cmnd = "ALL"; +- rc = command_matches_all(runchroot, intercepted, digests); ++ ret = command_matches_all(runchroot, intercepted, digests); + goto done; + } + +@@ -742,9 +743,9 @@ command_matches(const char *sudoers_cmnd, const char *sudoers_args, + */ + if (strcmp(sudoers_cmnd, "sudoedit") == 0 && + strcmp(user_cmnd, "sudoedit") == 0 && +- command_args_match(sudoers_cmnd, sudoers_args)) { ++ command_args_match(sudoers_cmnd, sudoers_args) == ALLOW) { + /* No need to set safe_cmnd since user_cmnd matches sudoers_cmnd */ +- rc = true; ++ ret = ALLOW; + } + goto done; + } +@@ -755,14 +756,14 @@ command_matches(const char *sudoers_cmnd, const char *sudoers_args, + * use glob(3) and/or fnmatch(3) to do the matching. + */ + if (def_fast_glob) { +- rc = command_matches_fnmatch(sudoers_cmnd, sudoers_args, runchroot, ++ ret = command_matches_fnmatch(sudoers_cmnd, sudoers_args, runchroot, + intercepted, digests); + } else { +- rc = command_matches_glob(sudoers_cmnd, sudoers_args, runchroot, ++ ret = command_matches_glob(sudoers_cmnd, sudoers_args, runchroot, + intercepted, digests); + } + } else { +- rc = command_matches_normal(sudoers_cmnd, sudoers_args, runchroot, ++ ret = command_matches_normal(sudoers_cmnd, sudoers_args, runchroot, + intercepted, digests); + } + done: +@@ -783,6 +784,6 @@ done: + user_cmnd, user_args ? " " : "", user_args ? user_args : "", + sudoers_cmnd, sudoers_args ? " " : "", sudoers_args ? sudoers_args : "", + runchroot ? ", chroot " : "", runchroot ? runchroot : "", +- rc ? "true" : "false"); +- debug_return_bool(rc); ++ ret == ALLOW ? "ALLOW" : "DENY"); ++ debug_return_int(ret); + } +diff --git a/plugins/sudoers/match_digest.c b/plugins/sudoers/match_digest.c +index 5c39f52..78cfe0d 100644 +--- a/plugins/sudoers/match_digest.c ++++ b/plugins/sudoers/match_digest.c +@@ -38,7 +38,7 @@ + #include "sudo_digest.h" + #include + +-bool ++int + digest_matches(int fd, const char *path, const char *runchroot, + const struct command_digest_list *digests) + { +@@ -48,12 +48,12 @@ digest_matches(int fd, const char *path, const char *runchroot, + struct command_digest *digest; + size_t digest_len = (size_t)-1; + char pathbuf[PATH_MAX]; +- bool matched = false; ++ int matched = DENY; + debug_decl(digest_matches, SUDOERS_DEBUG_MATCH); + + if (TAILQ_EMPTY(digests)) { + /* No digest, no problem. */ +- debug_return_bool(true); ++ debug_return_int(ALLOW); + } + + if (fd == -1) { +@@ -66,7 +66,7 @@ digest_matches(int fd, const char *path, const char *runchroot, + snprintf(pathbuf, sizeof(pathbuf), "%s%s", runchroot, path); + if (len >= ssizeof(pathbuf)) { + errno = ENAMETOOLONG; +- debug_return_bool(false); ++ debug_return_int(DENY); + } + path = pathbuf; + } +@@ -113,7 +113,7 @@ digest_matches(int fd, const char *path, const char *runchroot, + } + } + if (memcmp(file_digest, sudoers_digest, digest_len) == 0) { +- matched = true; ++ matched = ALLOW; + break; + } + +@@ -131,5 +131,5 @@ bad_format: + done: + free(sudoers_digest); + free(file_digest); +- debug_return_bool(matched); ++ debug_return_int(matched); + } +diff --git a/plugins/sudoers/parse.h b/plugins/sudoers/parse.h +index 8559849..bfc5bc8 100644 +--- a/plugins/sudoers/parse.h ++++ b/plugins/sudoers/parse.h +@@ -384,22 +384,22 @@ bool parser_leak_remove(enum parser_leak_types type, void *v); + void parser_leak_init(void); + + /* match_addr.c */ +-bool addr_matches(char *n); ++int addr_matches(char *n); + + /* match_command.c */ +-bool command_matches(const char *sudoers_cmnd, const char *sudoers_args, const char *runchroot, struct cmnd_info *info, const struct command_digest_list *digests); ++int command_matches(const char *sudoers_cmnd, const char *sudoers_args, const char *runchroot, struct cmnd_info *info, const struct command_digest_list *digests); + + /* match_digest.c */ +-bool digest_matches(int fd, const char *path, const char *runchroot, const struct command_digest_list *digests); ++int digest_matches(int fd, const char *path, const char *runchroot, const struct command_digest_list *digests); + + /* match.c */ + struct group; + struct passwd; +-bool group_matches(const char *sudoers_group, const struct group *gr); +-bool hostname_matches(const char *shost, const char *lhost, const char *pattern); +-bool netgr_matches(const char *netgr, const char *lhost, const char *shost, const char *user); +-bool usergr_matches(const char *group, const char *user, const struct passwd *pw); +-bool userpw_matches(const char *sudoers_user, const char *user, const struct passwd *pw); ++int group_matches(const char *sudoers_group, const struct group *gr); ++int hostname_matches(const char *shost, const char *lhost, const char *pattern); ++int netgr_matches(const char *netgr, const char *lhost, const char *shost, const char *user); ++int usergr_matches(const char *group, const char *user, const struct passwd *pw); ++int userpw_matches(const char *sudoers_user, const char *user, const struct passwd *pw); + int cmnd_matches(struct sudoers_parse_tree *parse_tree, const struct member *m, const char *runchroot, struct cmnd_info *info); + int cmndlist_matches(struct sudoers_parse_tree *parse_tree, const struct member_list *list, const char *runchroot, struct cmnd_info *info); + int host_matches(struct sudoers_parse_tree *parse_tree, const struct passwd *pw, const char *host, const char *shost, const struct member *m); +diff --git a/plugins/sudoers/regress/parser/check_addr.c b/plugins/sudoers/regress/parser/check_addr.c +index cf50226..a465d14 100644 +--- a/plugins/sudoers/regress/parser/check_addr.c ++++ b/plugins/sudoers/regress/parser/check_addr.c +@@ -57,7 +57,7 @@ check_addr(char *input) + sudo_fatalx("expecting 0 or 1, got %s", cp); + input[len] = '\0'; + +- matched = addr_matches(input); ++ matched = addr_matches(input) == ALLOW; + if (matched != expected) { + sudo_warnx("%s %smatched: FAIL", input, matched ? "" : "not "); + return 1; +diff --git a/plugins/sudoers/sssd.c b/plugins/sudoers/sssd.c +index e396d84..8760e4c 100644 +--- a/plugins/sudoers/sssd.c ++++ b/plugins/sudoers/sssd.c +@@ -195,20 +195,20 @@ sudo_sss_check_user(struct sudo_sss_handle *handle, struct sss_sudo_rule *rule) + case '+': + /* Netgroup spec found, check membership. */ + if (netgr_matches(val, def_netgroup_tuple ? host : NULL, +- def_netgroup_tuple ? shost : NULL, handle->pw->pw_name)) { ++ def_netgroup_tuple ? shost : NULL, handle->pw->pw_name) == ALLOW) { + ret = true; + } + break; + case '%': + /* User group found, check membership. */ +- if (usergr_matches(val, handle->pw->pw_name, handle->pw)) { ++ if (usergr_matches(val, handle->pw->pw_name, handle->pw) == ALLOW) { + ret = true; + } + break; + default: + /* Not a netgroup or user group. */ + if (strcmp(val, "ALL") == 0 || +- userpw_matches(val, handle->pw->pw_name, handle->pw)) { ++ userpw_matches(val, handle->pw->pw_name, handle->pw) == ALLOW) { + ret = true; + } + break; +-- +2.42.0.windows.2 + diff --git a/sudo.spec b/sudo.spec index 2699177..bf04b79 100644 --- a/sudo.spec +++ b/sudo.spec @@ -1,6 +1,6 @@ Name: sudo Version: 1.9.8p2 -Release: 15 +Release: 16 Summary: Allows restricted root access for specified users License: ISC URL: http://www.courtesan.com/sudo/ @@ -39,6 +39,9 @@ Patch25: backport-Linux-execve-2-allows-argv-or-envp-to-be-NULL.patch Patch26: backport-Fix-potential-NULL-pointer-deference-found-by-clang-.patch Patch27: backport-Set-command_info-to-NULL-once-it-is-freed.patch Patch28: backport-sudoers_parse_ldif-do-not-free-parse_tree-before-usi.patch +Patch29: backport-Do-not-rely-on-the-definition-of-ALLOW-DENY-being-tr.patch +Patch30: backport-CVE-2023-42465.patch +Patch31: backport-Make-all-match-functions-return-ALLOW-DENY-.patch Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) Requires: pam @@ -189,6 +192,9 @@ install -p -c -m 0644 %{SOURCE3} $RPM_BUILD_ROOT/etc/pam.d/sudo-i %exclude %{_pkgdocdir}/ChangeLog %changelog +* Wed Jan 10 2024 wangqingsan - 1.9.8p2-16 +- fix CVE-2023-42465 + * Tue Nov 28 2023 zhangruifang - 1.9.8p2-15 - Backport patches from upstream community -- Gitee