From bfb1cead60c8992e8196b3f5e896531be8a175e3 Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Tue, 1 Sep 2015 10:24:59 -0600 Subject: [PATCH] When decoding base64, avoid using '=' in the decoded temporary array as a sentinel as it can legitimately be present. Instead, just use the count of bytes stored in the temp array to determine which bytes to fold into the destination. --- plugins/sudoers/base64.c | 22 ++++++------------- plugins/sudoers/match.c | 6 ++++- plugins/sudoers/regress/parser/check_base64.c | 6 +++++ 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/plugins/sudoers/base64.c b/plugins/sudoers/base64.c index 23b402007..d85bfbf59 100644 --- a/plugins/sudoers/base64.c +++ b/plugins/sudoers/base64.c @@ -53,27 +53,19 @@ base64_decode(const char *str, unsigned char *dst, size_t dsize) */ while (*str != '\0') { for (i = 0; i < 4; i++) { - switch (*str) { - case '=': - str++; - /* FALLTHROUGH */ - case '\0': - ch[i] = '='; + if (*str == '=' || *str == '\0') break; - default: - if ((pos = strchr(b64, *str++)) == NULL) - debug_return_size_t((size_t)-1); - ch[i] = (unsigned char)(pos - b64); - break; - } + if ((pos = strchr(b64, *str++)) == NULL) + debug_return_size_t((size_t)-1); + ch[i] = (unsigned char)(pos - b64); } - if (ch[0] == '=' || ch[1] == '=' || dst == dend) + if (i == 0 || i == 1 || dst == dend) break; *dst++ = (ch[0] << 2) | ((ch[1] & 0x30) >> 4); - if (ch[2] == '=' || dst == dend) + if (i == 2 || dst == dend) break; *dst++ = ((ch[1] & 0x0f) << 4) | ((ch[2] & 0x3c) >> 2); - if (ch[3] == '=' || dst == dend) + if (i == 3 || dst == dend) break; *dst++ = ((ch[2] & 0x03) << 6) | ch[3]; } diff --git a/plugins/sudoers/match.c b/plugins/sudoers/match.c index 524ab5bd1..e41e72192 100644 --- a/plugins/sudoers/match.c +++ b/plugins/sudoers/match.c @@ -617,8 +617,12 @@ digest_matches(const char *file, const struct sudo_digest *sd) } else { size_t len = base64_decode(sd->digest_str, sudoers_digest, sizeof(sudoers_digest)); - if (len != func->digest_len) + if (len != func->digest_len) { + sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, + "incorrect length for digest, expected %u, got %zu", + func->digest_len, len); goto bad_format; + } } if ((fp = fopen(file, "r")) == NULL) { diff --git a/plugins/sudoers/regress/parser/check_base64.c b/plugins/sudoers/regress/parser/check_base64.c index 53753020a..7c9afa6fe 100644 --- a/plugins/sudoers/regress/parser/check_base64.c +++ b/plugins/sudoers/regress/parser/check_base64.c @@ -39,10 +39,16 @@ extern size_t base64_decode(const char *str, unsigned char *dst, size_t dsize); __dso_public int main(int argc, char *argv[]); +static char bstring1[] = { 0xea, 0xb8, 0xa2, 0x71, 0xef, 0x67, 0xc1, 0xcd, 0x0d, 0xd9, 0xa6, 0xaa, 0xa8, 0x24, 0x77, 0x2a, 0xfc, 0x6f, 0x76, 0x37, 0x1b, 0xed, 0x9e, 0x1a, 0x90, 0x5f, 0xcf, 0xbc, 0x00 }; + struct base64_test { const char *ascii; const char *encoded; } test_strings[] = { + { + bstring1, + "6riice9nwc0N2aaqqCR3Kvxvdjcb7Z4akF/PvA==" + }, { "any carnal pleasure.", "YW55IGNhcm5hbCBwbGVhc3VyZS4=" -- 2.40.0