599 lines
18 KiB
Diff
599 lines
18 KiB
Diff
|
diff -up ./plugins/sudoers/auth/passwd.c.rowhammer ./plugins/sudoers/auth/passwd.c
|
||
|
--- ./plugins/sudoers/auth/passwd.c.rowhammer 2020-12-17 02:33:44.000000000 +0100
|
||
|
+++ ./plugins/sudoers/auth/passwd.c 2024-01-22 16:01:16.331874669 +0100
|
||
|
@@ -62,7 +62,7 @@ sudo_passwd_verify(struct passwd *pw, ch
|
||
|
char sav, *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. */
|
||
|
@@ -85,27 +85,37 @@ sudo_passwd_verify(struct passwd *pw, ch
|
||
|
*/
|
||
|
epass = (char *) crypt(pass, pw_epasswd);
|
||
|
pass[8] = sav;
|
||
|
+ 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;
|
||
|
+ }
|
||
|
}
|
||
|
|
||
|
- debug_return_int(matched ? AUTH_SUCCESS : AUTH_FAILURE);
|
||
|
+ explicit_bzero(des_pass, sizeof(des_pass));
|
||
|
+
|
||
|
+ 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 -up ./plugins/sudoers/auth/sudo_auth.c.rowhammer ./plugins/sudoers/auth/sudo_auth.c
|
||
|
--- ./plugins/sudoers/auth/sudo_auth.c.rowhammer 2020-12-17 02:33:43.000000000 +0100
|
||
|
+++ ./plugins/sudoers/auth/sudo_auth.c 2024-01-22 16:01:16.331874669 +0100
|
||
|
@@ -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)
|
||
|
- SET(auth->flags, FLAG_DISABLED);
|
||
|
- else if (status == AUTH_FATAL)
|
||
|
- break; /* assume error msg already printed */
|
||
|
+ switch (status) {
|
||
|
+ case AUTH_SUCCESS:
|
||
|
+ break;
|
||
|
+ case AUTH_FAILURE:
|
||
|
+ SET(auth->flags, FLAG_DISABLED);
|
||
|
+ 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, boo
|
||
|
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 *pro
|
||
|
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) {
|
||
|
- /* Assume error msg already printed. */
|
||
|
- debug_return_int(-1);
|
||
|
+ switch (status) {
|
||
|
+ case AUTH_SUCCESS:
|
||
|
+ break;
|
||
|
+ case AUTH_FAILURE:
|
||
|
+ ret = false;
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ /* Assume error msg already printed. */
|
||
|
+ 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) {
|
||
|
- /* Assume error msg already printed. */
|
||
|
- debug_return_int(-1);
|
||
|
- }
|
||
|
+ switch (status) {
|
||
|
+ case AUTH_SUCCESS:
|
||
|
+ break;
|
||
|
+ case AUTH_FAILURE:
|
||
|
+ ret = false;
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ /* Assume error msg already printed. */
|
||
|
+ ret = -1;
|
||
|
+ break;
|
||
|
+ }
|
||
|
}
|
||
|
}
|
||
|
- debug_return_int(1);
|
||
|
+ debug_return_int(ret);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
diff -up ./plugins/sudoers/auth/sudo_auth.h.rowhammer ./plugins/sudoers/auth/sudo_auth.h
|
||
|
--- ./plugins/sudoers/auth/sudo_auth.h.rowhammer 2020-12-17 02:33:43.000000000 +0100
|
||
|
+++ ./plugins/sudoers/auth/sudo_auth.h 2024-01-22 16:01:16.332874679 +0100
|
||
|
@@ -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 -up ./plugins/sudoers/cvtsudoers.c.rowhammer ./plugins/sudoers/cvtsudoers.c
|
||
|
--- ./plugins/sudoers/cvtsudoers.c.rowhammer 2024-01-22 18:30:09.585081693 +0100
|
||
|
+++ ./plugins/sudoers/cvtsudoers.c 2024-01-22 18:32:35.238519869 +0100
|
||
|
@@ -685,7 +685,7 @@ userlist_matches_filter(struct sudoers_p
|
||
|
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) {
|
||
|
@@ -711,7 +711,7 @@ userlist_matches_filter(struct sudoers_p
|
||
|
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);
|
||
|
|
||
|
@@ -787,7 +787,7 @@ hostlist_matches_filter(struct sudoers_p
|
||
|
|
||
|
/* 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 -up ./plugins/sudoers/match.c.rowhammer ./plugins/sudoers/match.c
|
||
|
--- ./plugins/sudoers/match.c.rowhammer 2020-12-17 02:33:44.000000000 +0100
|
||
|
+++ ./plugins/sudoers/match.c 2024-01-22 16:01:16.332874679 +0100
|
||
|
@@ -26,6 +26,7 @@
|
||
|
* PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||
|
*/
|
||
|
|
||
|
+#include "parse.h"
|
||
|
#include <config.h>
|
||
|
|
||
|
#include <sys/stat.h>
|
||
|
@@ -70,37 +71,42 @@ user_matches(struct sudoers_parse_tree *
|
||
|
{
|
||
|
const char *lhost = parse_tree->lhost ? parse_tree->lhost : user_runhost;
|
||
|
const char *shost = parse_tree->shost ? parse_tree->shost : user_srunhost;
|
||
|
- int matched = UNSPEC;
|
||
|
+ int rc, matched = UNSPEC;
|
||
|
struct alias *a;
|
||
|
debug_decl(user_matches, SUDOERS_DEBUG_MATCH);
|
||
|
|
||
|
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;
|
||
|
+ rc = userlist_matches(parse_tree, pw, &a->members);
|
||
|
+ if (SPECIFIED(rc)) {
|
||
|
+ 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);
|
||
|
@@ -119,7 +125,8 @@ userlist_matches(struct sudoers_parse_tr
|
||
|
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);
|
||
|
@@ -164,48 +171,53 @@ runaslist_matches(struct sudoers_parse_t
|
||
|
/* If no runas user or runas group listed in sudoers, use default. */
|
||
|
if (user_list == NULL && group_list == NULL) {
|
||
|
debug_return_int(userpw_matches(def_runas_default,
|
||
|
- runas_pw->pw_name, runas_pw));
|
||
|
+ runas_pw->pw_name, runas_pw) ? ALLOW : DENY);
|
||
|
}
|
||
|
|
||
|
if (user_list != NULL) {
|
||
|
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 (SPECIFIED(rc)) {
|
||
|
+ 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) {
|
||
|
+ if (SPECIFIED(user_matched)) {
|
||
|
if (matching_user != NULL && m->type != ALIAS)
|
||
|
*matching_user = m;
|
||
|
break;
|
||
|
@@ -226,34 +238,40 @@ runaslist_matches(struct sudoers_parse_t
|
||
|
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 (SPECIFIED(rc)) {
|
||
|
+ 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) {
|
||
|
+ 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.
|
||
|
* Check whether it is one of the target user's groups.
|
||
|
*/
|
||
|
@@ -295,7 +313,7 @@ hostlist_matches_int(struct sudoers_pars
|
||
|
|
||
|
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);
|
||
|
@@ -324,37 +342,42 @@ host_matches(struct sudoers_parse_tree *
|
||
|
const char *lhost, const char *shost, const struct member *m)
|
||
|
{
|
||
|
struct alias *a;
|
||
|
- int matched = UNSPEC;
|
||
|
+ int rc, matched = UNSPEC;
|
||
|
debug_decl(host_matches, SUDOERS_DEBUG_MATCH);
|
||
|
|
||
|
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,
|
||
|
+ rc = hostlist_matches_int(parse_tree, pw, lhost, shost,
|
||
|
&a->members);
|
||
|
- if (rc != UNSPEC)
|
||
|
- matched = m->negated ? !rc : rc;
|
||
|
+ if (SPECIFIED(rc)) {
|
||
|
+ 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);
|
||
|
@@ -375,7 +398,7 @@ cmndlist_matches(struct sudoers_parse_tr
|
||
|
|
||
|
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);
|
||
|
@@ -397,21 +420,26 @@ cmnd_matches(struct sudoers_parse_tree *
|
||
|
switch (m->type) {
|
||
|
case ALL:
|
||
|
if (m->name == NULL) {
|
||
|
- matched = !m->negated;
|
||
|
+ matched = m->negated ? DENY : ALLOW;
|
||
|
break;
|
||
|
}
|
||
|
FALLTHROUGH;
|
||
|
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 (SPECIFIED(rc)) {
|
||
|
+ if (m->negated) {
|
||
|
+ matched = rc == ALLOW ? DENY : ALLOW;
|
||
|
+ } else {
|
||
|
+ matched = rc;
|
||
|
+ }
|
||
|
+ }
|
||
|
alias_put(a);
|
||
|
}
|
||
|
break;
|
||
|
diff -up ./plugins/sudoers/parse.c.rowhammer ./plugins/sudoers/parse.c
|
||
|
--- ./plugins/sudoers/parse.c.rowhammer 2020-12-17 02:33:43.000000000 +0100
|
||
|
+++ ./plugins/sudoers/parse.c 2024-01-22 16:01:16.333874689 +0100
|
||
|
@@ -151,7 +151,7 @@ sudoers_lookup_check(struct sudo_nss *ns
|
||
|
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.
|
||
|
@@ -365,7 +365,7 @@ sudoers_lookup(struct sudo_nss_list *snl
|
||
|
}
|
||
|
|
||
|
m = sudoers_lookup_check(nss, pw, &validated, &info, &cs, &defs, now);
|
||
|
- if (m != UNSPEC) {
|
||
|
+ if (SPECIFIED(m)) {
|
||
|
match = m;
|
||
|
parse_tree = nss->parse_tree;
|
||
|
}
|
||
|
@@ -373,7 +373,7 @@ sudoers_lookup(struct sudo_nss_list *snl
|
||
|
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 -up ./plugins/sudoers/parse.h.rowhammer ./plugins/sudoers/parse.h
|
||
|
--- ./plugins/sudoers/parse.h.rowhammer 2021-01-09 21:12:16.000000000 +0100
|
||
|
+++ ./plugins/sudoers/parse.h 2024-01-22 16:01:16.333874689 +0100
|
||
|
@@ -20,6 +20,9 @@
|
||
|
#ifndef SUDOERS_PARSE_H
|
||
|
#define SUDOERS_PARSE_H
|
||
|
|
||
|
+#include <stdbool.h>
|
||
|
+#include <stddef.h>
|
||
|
+#include <stdio.h>
|
||
|
#include <sys/stat.h>
|
||
|
#include "sudo_queue.h"
|
||
|
|
||
|
@@ -31,13 +34,26 @@
|
||
|
|
||
|
#undef UNSPEC
|
||
|
#define UNSPEC -1
|
||
|
+
|
||
|
+/* Denied by policy (rowhammer resistent). */
|
||
|
#undef DENY
|
||
|
-#define DENY 0
|
||
|
+#define DENY 0xad5d6da /* 1010110101011101011011011010 */
|
||
|
+
|
||
|
+/* Allowed by policy (rowhammer resistent). */
|
||
|
#undef ALLOW
|
||
|
-#define ALLOW 1
|
||
|
+#define ALLOW 0x52a2925 /* 0101001010100010100100100101 */
|
||
|
+
|
||
|
#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.
|
||
|
*/
|