Skip to content

Commit 111fd83

Browse files
committed
Use constant-time string compare for plain text password check.
Avoid potential password guessing based on timing attacks on the strcmp() function. Reported by Quarkslab.
1 parent a294a8b commit 111fd83

File tree

1 file changed

+24
-2
lines changed

1 file changed

+24
-2
lines changed

plugins/sudoers/auth/passwd.c

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,16 +106,38 @@ sudo_passwd_verify(const struct sudoers_context *ctx, struct passwd *pw,
106106
debug_return_int(ret);
107107
}
108108
#else
109+
/*
110+
* Constant-time string match, compares "candidate" against "target".
111+
* Will always traverse the entirety of "candidate".
112+
* Returns 0 for match, -1 for mismatch.
113+
*/
114+
static int
115+
timingsafe_strmatch(const char *candidate, const char *target)
116+
{
117+
int ret = 0;
118+
debug_decl(timingsafe_strmatch, SUDOERS_DEBUG_AUTH);
119+
120+
for (;;) {
121+
ret |= *candidate ^ *target;
122+
if (*candidate == '\0')
123+
break;
124+
candidate++;
125+
target += *target != '\0';
126+
}
127+
debug_return_int(ret ? -1 : 0);
128+
}
129+
109130
int
110131
sudo_passwd_verify(const struct sudoers_context *ctx, struct passwd *pw,
111132
const char *pass, sudo_auth *auth, struct sudo_conv_callback *callback)
112133
{
113-
char *pw_passwd = auth->data;
134+
int (* volatile cmp)(const char *, const char *) = timingsafe_strmatch;
135+
const char *pw_passwd = auth->data;
114136
int ret;
115137
debug_decl(sudo_passwd_verify, SUDOERS_DEBUG_AUTH);
116138

117139
/* Simple string compare for systems without crypt(). */
118-
if (strcmp(pass, pw_passwd) == 0)
140+
if (cmp(pass, pw_passwd) == 0)
119141
ret = AUTH_SUCCESS;
120142
else
121143
ret = AUTH_FAILURE;

0 commit comments

Comments
 (0)