CVE-2023-42465: Insufficient Information (NVD-CWE-noinfo)
value: Sudo before 1.9.15 might allow row hammer attacks (for authentication bypass or privilege escalation) because application logic sometimes is based on not equaling an error value (instead of equaling a success value), and because the values do not resist flips of a single bit.
CWE description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
CVSS v3 base score: 7
Published: 2023-12-22T16:15Z
Repository: https://github.com/sudo-project/sudo
Language: C
Files changed: plugins/sudoers/auth/passwd.c, plugins/sudoers/auth/sudo_auth.c, plugins/sudoers/auth/sudo_auth.h, plugins/sudoers/lookup.c, plugins/sudoers/match.c, plugins/sudoers/parse.h
Commit date: 2023-09-09 14:07:04 -0600
Commit message: 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

Diff: diff --git a/plugins/sudoers/auth/passwd.c b/plugins/sudoers/auth/passwd.c
index 17c96d4a0..df12805f8 100644
--- a/plugins/sudoers/auth/passwd.c
+++ b/plugins/sudoers/auth/passwd.c
@@ -66,11 +66,11 @@ sudo_passwd_verify(const struct sudoers_context *ctx, struct passwd *pw,
     const char *pass, sudo_auth *auth, struct sudo_conv_callback *callback)
 {
     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. */
     if (pass[0] == '\0')
 	debug_return_int(pw_epasswd[0] ? AUTH_FAILURE : AUTH_SUCCESS);
@@ -78,44 +78,51 @@ sudo_passwd_verify(const struct sudoers_context *ctx, struct passwd *pw,
     /*
      * Truncate to 8 chars if standard DES since not all crypt()'s do this.
      */
     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;
     }
 
     /*
      * Normal UN*X password check.
      * HP-UX may add aging info (separated by a ',') at the end so
      * 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(const struct sudoers_context *ctx, struct passwd *pw,
     const 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
 
 int
 sudo_passwd_cleanup(const struct sudoers_context *ctx, struct passwd *pw,
diff --git a/plugins/sudoers/auth/sudo_auth.c b/plugins/sudoers/auth/sudo_auth.c
index 262a57b11..d1b168a8f 100644
--- a/plugins/sudoers/auth/sudo_auth.c
+++ b/plugins/sudoers/auth/sudo_auth.c
@@ -114,14 +114,20 @@ sudo_auth_init(const struct sudoers_context *ctx, struct passwd *pw,
 	if (ISSET(mode, MODE_NONINTERACTIVE))
 	    SET(auth->flags, FLAG_NONINTERACTIVE);
 	if (auth->init && !IS_DISABLED(auth)) {
 	    /* Disable if it failed to init unless there was a fatal error. */
 	    status = (auth->init)(ctx, pw, auth);
-	    if (status == AUTH_FAILURE)
+	    switch (status) {
+	    case AUTH_SUCCESS:
+		break;
+	    case AUTH_FAILURE:
 		SET(auth->flags, FLAG_DISABLED);
-	    else if (status == AUTH_ERROR)
-		break;		/* assume error msg already printed */
+		break;
+	    default:
+		/* Assume error msg already printed. */
+		debug_return_int(-1);
+	    }
 	}
     }
 
     /*
      * Make sure we haven't mixed standalone and shared auth methods.
@@ -164,11 +170,11 @@ sudo_auth_init(const struct sudoers_context *ctx, struct passwd *pw,
 		SET(first->flags, FLAG_ONEANDONLY);
 	    break;
 	}
     }
 
-    debug_return_int(status == AUTH_ERROR ? -1 : 0);
+    debug_return_int(0);
 }
 
 /*
  * Cleanup all authentication approval methods.
  * Returns true on success, false on failure and -1 on error.
@@ -207,11 +213,11 @@ sudo_auth_cleanup(const struct sudoers_context *ctx, struct passwd *pw,
 
     /* Call cleanup routines. */
     for (auth = auth_switch; auth->name; auth++) {
 	if (auth->cleanup && !IS_DISABLED(auth)) {
 	    int status = (auth->cleanup)(ctx, pw, auth, force);
-	    if (status == AUTH_ERROR) {
+	    if (status != AUTH_SUCCESS) {
 		/* Assume error msg already printed. */
 		debug_return_int(-1);
 	    }
 	}
     }
@@ -304,11 +310,11 @@ verify_user(const struct sudoers_context *ctx, struct passwd *pw, char *prompt,
 		status = (auth->setup)(ctx, pw, &prompt, auth);
 		if (status == AUTH_FAILURE)
 		    SET(auth->flags, FLAG_DISABLED);
 		else if (status == AUTH_NONINTERACTIVE)
 		    goto done;
-		else if (status == AUTH_ERROR || user_interrupted())
+		else if (status != AUTH_SUCCESS || user_interrupted())
 		    goto done;		/* assume error msg already printed */
 	    }
 	}
 	if (num_methods == 0) {
 	    audit_failure(ctx, ctx->runas.argv,
@@ -363,11 +369,10 @@ done:
 	    ret = false;
 	    break;
 	case AUTH_NONINTERACTIVE:
 	    SET(validated, FLAG_NO_USER_INPUT);
 	    FALLTHROUGH;
-	case AUTH_ERROR:
 	default:
 	    log_auth_failure(ctx, validated, 0);
 	    ret = -1;
 	    break;
     }
@@ -375,29 +380,37 @@ done:
     debug_return_int(ret);
 }
 
 /*
  * 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(const struct sudoers_context *ctx, 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)(ctx, 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
 sudo_auth_needs_end_session(void)
 {
@@ -414,29 +427,37 @@ sudo_auth_needs_end_session(void)
     debug_return_bool(needed);
 }
 
 /*
  * 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(void)
 {
     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)(auth);
-	    if (status == AUTH_ERROR) {
+	    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);
 }
 
 /*
  * Prompts the user for a password using the conversation function.
  * Returns the plaintext password or NULL.
diff --git a/plugins/sudoers/auth/sudo_auth.h b/plugins/sudoers/auth/sudo_auth.h
index 89e6b8422..1db4f58cd 100644
--- a/plugins/sudoers/auth/sudo_auth.h
+++ b/plugins/sudoers/auth/sudo_auth.h
@@ -17,16 +17,16 @@
  */
 
 #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_ERROR		3
-#define AUTH_NONINTERACTIVE	4
+/* Auth function return values (rowhammer resistent).  */
+#define AUTH_SUCCESS		0x52a2925	/* 0101001010100010100100100101 */
+#define AUTH_FAILURE		0xad5d6da	/* 1010110101011101011011011010 */
+#define AUTH_INTR		0x69d61fc8	/* 1101001110101100001111111001000 */
+#define AUTH_ERROR		0x1629e037	/* 0010110001010011110000000110111 */
+#define AUTH_NONINTERACTIVE	0x1fc8d3ac	/* 11111110010001101001110101100 */
 
 typedef struct sudo_auth {
     unsigned int flags;		/* various flags, see below */
     int status;			/* status from verify routine */
     const char *name;		/* name of the method as a string */
diff --git a/plugins/sudoers/lookup.c b/plugins/sudoers/lookup.c
index f23edcce9..fe3da98cd 100644
--- a/plugins/sudoers/lookup.c
+++ b/plugins/sudoers/lookup.c
@@ -98,11 +98,11 @@ sudoers_lookup_pseudo(struct sudo_nss_list *snl, struct sudoers_context *ctx,
 	 */
 	TAILQ_FOREACH(us, &nss->parse_tree->userspecs, entries) {
 	    int user_match = userlist_matches(nss->parse_tree, ctx->user.pw,
 		&us->users);
 	    if (user_match != ALLOW) {
-		if (callback != NULL && user_match != UNSPEC) {
+		if (callback != NULL && user_match == DENY) {
 		    callback(nss->parse_tree, us, user_match, NULL, UNSPEC,
 			NULL, UNSPEC, UNSPEC, UNSPEC, cb_data);
 		}
 		continue;
 	    }
@@ -187,11 +187,11 @@ sudoers_lookup_pseudo(struct sudo_nss_list *snl, struct sudoers_context *ctx,
 		    if (callback != NULL) {
 			callback(nss->parse_tree, us, user_match, priv,
 			    host_match, cs, date_match, runas_match,
 			    cmnd_match, cb_data);
 		    }
-		    if (cmnd_match != UNSPEC) {
+		    if (SPECIFIED(cmnd_match)) {
 			/*
 			 * We take the last match but must process
 			 * the entire policy for pwcheck == all.
 			 */
 			match = cmnd_match;
@@ -243,11 +243,11 @@ sudoers_lookup_check(struct sudo_nss *nss, struct sudoers_context *ctx,
     init_cmnd_info(ctx, info);
 
     TAILQ_FOREACH_REVERSE(us, &nss->parse_tree->userspecs, userspec_list, entries) {
 	int user_match = userlist_matches(nss->parse_tree, ctx->user.pw, &us->users);
 	if (user_match != ALLOW) {
-	    if (callback != NULL && user_match != UNSPEC) {
+	    if (callback != NULL && user_match == DENY) {
 		callback(nss->parse_tree, us, user_match, NULL, UNSPEC, NULL,
 		    UNSPEC, UNSPEC, UNSPEC, cb_data);
 	    }
 	    continue;
 	}
@@ -288,11 +288,11 @@ sudoers_lookup_check(struct sudo_nss *nss, struct sudoers_context *ctx,
 		if (callback != NULL) {
 		    callback(nss->parse_tree, us, user_match, priv, host_match,
 			cs, date_match, runas_match, cmnd_match, cb_data);
 		}
 
-		if (cmnd_match != UNSPEC) {
+		if (SPECIFIED(cmnd_match)) {
 		    /*
 		     * If user is running command as themselves,
 		     * set ctx->runas.pw = ctx->user.pw.
 		     * XXX - hack, want more general solution
 		     */
@@ -540,19 +540,19 @@ sudoers_lookup(struct sudo_nss_list *snl, struct sudoers_context *ctx,
 	    break;
 	}
 
 	m = sudoers_lookup_check(nss, ctx, &validated, &info, now, callback,
 	    cb_data, &cs, &defs);
-	if (m != UNSPEC) {
+	if (SPECIFIED(m)) {
 	    match = m;
 	    parse_tree = nss->parse_tree;
 	}
 
 	if (!sudo_nss_can_continue(nss, m))
 	    break;
     }
-    if (match != UNSPEC) {
+    if (SPECIFIED(match)) {
 	if (info.cmnd_path != NULL) {
 	    /* Update cmnd, cmnd_stat, cmnd_status from matching entry. */
 	    free(ctx->user.cmnd);
 	    ctx->user.cmnd = info.cmnd_path;
 	    if (ctx->user.cmnd_stat != NULL)
diff --git a/plugins/sudoers/match.c b/plugins/sudoers/match.c
index 41c48350a..fd05cb3fa 100644
--- a/plugins/sudoers/match.c
+++ b/plugins/sudoers/match.c
@@ -89,11 +89,11 @@ user_matches(const struct sudoers_parse_tree *parse_tree,
 	    break;
 	case ALIAS:
 	    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 {
 			matched = rc;
 		    }
@@ -121,11 +121,12 @@ userlist_matches(const struct sudoers_parse_tree *parse_tree,
     struct member *m;
     int matched = UNSPEC;
     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);
 }
 
@@ -182,11 +183,11 @@ runas_userlist_matches(const struct sudoers_parse_tree *parse_tree,
 	    case ALIAS:
 		a = alias_get(parse_tree, m->name, RUNASALIAS);
 		if (a != NULL) {
 		    const int rc = runas_userlist_matches(parse_tree,
 			&a->members, matching_user);
-		    if (rc != UNSPEC) {
+		    if (SPECIFIED(rc)) {
 			if (m->negated) {
 			    user_matched = rc == ALLOW ? DENY : ALLOW;
 			} else {
 			    user_matched = rc;
 			}
@@ -209,11 +210,11 @@ runas_userlist_matches(const struct sudoers_parse_tree *parse_tree,
 			ISSET(ctx->settings.flags, RUNAS_GROUP_SPECIFIED)) ||
 			strcmp(ctx->user.name, ctx->runas.pw->pw_name) == 0)
 		    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;
 	}
     }
@@ -244,11 +245,11 @@ runas_grouplist_matches(const struct sudoers_parse_tree *parse_tree,
 		case ALIAS:
 		    a = alias_get(parse_tree, m->name, RUNASALIAS);
 		    if (a != NULL) {
 			const int rc = runas_grouplist_matches(parse_tree,
 			    &a->members, matching_group);
-			if (rc != UNSPEC) {
+			if (SPECIFIED(rc)) {
 			    if (m->negated) {
 				group_matched = rc == ALLOW ? DENY : ALLOW;
 			    } else {
 				group_matched = rc;
 			    }
@@ -260,18 +261,18 @@ runas_grouplist_matches(const struct sudoers_parse_tree *parse_tree,
 		case WORD:
 		    if (group_matches(m->name, ctx->runas.gr))
 			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.
 	 */
@@ -347,11 +348,11 @@ hostlist_matches_int(const struct sudoers_parse_tree *parse_tree,
     int matched = UNSPEC;
     debug_decl(hostlist_matches, SUDOERS_DEBUG_MATCH);
 
     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);
 }
 
@@ -400,11 +401,11 @@ host_matches(const struct sudoers_parse_tree *parse_tree,
 	    a = alias_get(parse_tree, m->name, HOSTALIAS);
 	    if (a != NULL) {
 		/* 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 {
 			matched = rc;
 		    }
@@ -438,11 +439,11 @@ cmndlist_matches(const struct sudoers_parse_tree *parse_tree,
     int matched = UNSPEC;
     debug_decl(cmndlist_matches, SUDOERS_DEBUG_MATCH);
 
     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);
 }
 
@@ -469,11 +470,11 @@ cmnd_matches(const struct sudoers_parse_tree *parse_tree,
 	    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) {
+		if (SPECIFIED(rc)) {
 		    if (m->negated) {
 			matched = rc == ALLOW ? DENY : ALLOW;
 		    } else {
 			matched = rc;
 		    }
@@ -509,11 +510,11 @@ cmnd_matches_all(const struct sudoers_parse_tree *parse_tree,
 	case ALIAS:
 	    a = alias_get(parse_tree, m->name, CMNDALIAS);
 	    if (a != NULL) {
 		TAILQ_FOREACH_REVERSE(m, &a->members, member_list, entries) {
 		    matched = cmnd_matches_all(parse_tree, m, runchroot, info);
-		    if (matched != UNSPEC) {
+		    if (SPECIFIED(matched)) {
 			if (negated)
 			    matched = matched == ALLOW ? DENY : ALLOW;
 			break;
 		    }
 		}
diff --git a/plugins/sudoers/parse.h b/plugins/sudoers/parse.h
index 01e6b25d9..2ca9c5965 100644
--- a/plugins/sudoers/parse.h
+++ b/plugins/sudoers/parse.h
@@ -34,19 +34,32 @@
 /* Match by name, not inode, when fuzzing. */
 #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
 # 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.
  */
 #define TAGS_INIT(t)	do {						       \
     (t)->follow = UNSPEC;						       \
@@ -92,11 +105,11 @@
 
 /*
  * 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.
  */
 #define TAGS_CHANGED(ot, nt) \

Vulnerable code:     int matched = 0;
	strlcpy(des_pass, pass, sizeof(des_pass));
	if (HAS_AGEINFO(pw_epasswd, pw_len) && strlen(epass) == DESLEN)
	    matched = !strncmp(pw_epasswd, epass, DESLEN);
	else
	    matched = !strcmp(pw_epasswd, epass);
    debug_return_int(matched ? AUTH_SUCCESS : AUTH_FAILURE);
    int matched;
    matched = !strcmp(pass, pw_passwd);
    debug_return_int(matched ? AUTH_SUCCESS : AUTH_FAILURE);
	    if (status == AUTH_FAILURE)
	    else if (status == AUTH_ERROR)
		break;		/* assume error msg already printed */
    debug_return_int(status == AUTH_ERROR ? -1 : 0);
	    if (status == AUTH_ERROR) {
		else if (status == AUTH_ERROR || user_interrupted())
	case AUTH_ERROR:
 * Returns 1 on success and -1 on error.
	    if (status != AUTH_SUCCESS) {
		debug_return_int(-1);
    debug_return_int(1);
 * Returns 1 on success and -1 on error.
	    if (status == AUTH_ERROR) {
		debug_return_int(-1);
    debug_return_int(1);
/* Auth function return values.  */
#define AUTH_SUCCESS		0
#define AUTH_FAILURE		1
#define AUTH_INTR		2
#define AUTH_ERROR		3
#define AUTH_NONINTERACTIVE	4
		if (callback != NULL && user_match != UNSPEC) {
		    if (cmnd_match != UNSPEC) {
	    if (callback != NULL && user_match != UNSPEC) {
		if (cmnd_match != UNSPEC) {
	if (m != UNSPEC) {
    if (match != UNSPEC) {
		if (rc != UNSPEC) {
	if ((matched = user_matches(parse_tree, pw, m)) != UNSPEC)
		    if (rc != UNSPEC) {
	if (user_matched != UNSPEC) {
			if (rc != UNSPEC) {
	    if (group_matched != UNSPEC) {
    if (group_matched == UNSPEC) {
	if (matched != UNSPEC)
		if (rc != UNSPEC) {
	if (matched != UNSPEC)
		if (rc != UNSPEC) {
		    if (matched != UNSPEC) {
#undef DENY
#define DENY	 0
#undef ALLOW
#define ALLOW	 1
    ((tt) != UNSPEC && (tt) != IMPLIED)
Fixed code:     int ret;
	(void)strlcpy(des_pass, pass, sizeof(des_pass));
    ret = AUTH_FAILURE;
	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(ret);
    int ret;
    if (strcmp(pass, pw_passwd) == 0)
	ret = AUTH_SUCCESS;
    else
	ret = AUTH_FAILURE;
    debug_return_int(ret);
	    switch (status) {
	    case AUTH_SUCCESS:
		break;
	    case AUTH_FAILURE:
		break;
	    default:
		/* Assume error msg already printed. */
		debug_return_int(-1);
	    }
    debug_return_int(0);
	    if (status != AUTH_SUCCESS) {
		else if (status != AUTH_SUCCESS || user_interrupted())
 * Returns true on success, false on failure and -1 on error.
    int ret = true;
	    switch (status) {
	    case AUTH_SUCCESS:
		break;
	    case AUTH_FAILURE:
		ret = false;
		break;
	    default:
		ret = -1;
		break;
    debug_return_int(ret);
 * Returns true on success, false on failure and -1 on error.
    int ret = true;
	    switch (status) {
	    case AUTH_SUCCESS:
		break;
	    case AUTH_FAILURE:
		ret = false;
		break;
	    default:
		ret = -1;
		break;
    debug_return_int(ret);
/* Auth function return values (rowhammer resistent).  */
#define AUTH_SUCCESS		0x52a2925	/* 0101001010100010100100100101 */
#define AUTH_FAILURE		0xad5d6da	/* 1010110101011101011011011010 */
#define AUTH_INTR		0x69d61fc8	/* 1101001110101100001111111001000 */
#define AUTH_ERROR		0x1629e037	/* 0010110001010011110000000110111 */
#define AUTH_NONINTERACTIVE	0x1fc8d3ac	/* 11111110010001101001110101100 */
		if (callback != NULL && user_match == DENY) {
		    if (SPECIFIED(cmnd_match)) {
	    if (callback != NULL && user_match == DENY) {
		if (SPECIFIED(cmnd_match)) {
	if (SPECIFIED(m)) {
    if (SPECIFIED(match)) {
		if (SPECIFIED(rc)) {
	matched = user_matches(parse_tree, pw, m);
	if (SPECIFIED(matched))
		    if (SPECIFIED(rc)) {
	if (SPECIFIED(user_matched)) {
			if (SPECIFIED(rc)) {
	    if (SPECIFIED(group_matched)) {
    if (!SPECIFIED(group_matched)) {
	if (SPECIFIED(matched))
		if (SPECIFIED(rc)) {
	if (SPECIFIED(matched))
		if (SPECIFIED(rc)) {
		    if (SPECIFIED(matched)) {
/* 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. */

/* Tag implied by root access (SETENV only). */
/*
 * 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)

    ((tt) == true || (tt) == false)