diff --git a/CHANGELOG.md b/CHANGELOG.md index 5792c240..a4c22bf6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -76,6 +76,13 @@ ### Deprecated ### Removed ### Fixed + +* Out-of-bounds read when parsing URIs with malformed %-encoded + content ([#2353][2353]). + +[2353]: https://codeberg.org/dnkl/foot/issues/2353 + + ### Security ### Contributors diff --git a/uri.c b/uri.c index 3f3beb53..ddbfacdd 100644 --- a/uri.c +++ b/uri.c @@ -195,7 +195,9 @@ uri_parse(const char *uri, size_t len, encoded_len -= prefix_len; decoded_len += prefix_len; - if (hex2nibble(next[1]) <= 15 && hex2nibble(next[2]) <= 15) { + if (encoded_len >= 3 && + hex2nibble(next[1]) <= 15 && hex2nibble(next[2]) <= 15) + { *p++ = hex2nibble(next[1]) << 4 | hex2nibble(next[2]); decoded_len++; encoded_len -= 3; @@ -416,3 +418,30 @@ UNITTEST xassert(query == NULL); xassert(fragment == NULL); } + +UNITTEST +{ + /* Malformed URI, trailing '%' */ + const char uri[] = "file:///%ABNOT-PART-OF-INPUT"; + char *path; + uri_parse(uri, 9, NULL, NULL, NULL, NULL, NULL, &path, NULL, NULL); + xassert(streq(path, "/%")); free(path); +} + +UNITTEST +{ + /* Malformed URI, trailing '%2' */ + const char uri[] = "file:///%2ANOT-PART-OF-INPUT"; + char *path; + uri_parse(uri, 10, NULL, NULL, NULL, NULL, NULL, &path, NULL, NULL); + xassert(streq(path, "/%2")); free(path); +} + +UNITTEST +{ + /* Malformed URI, trailing '%ag' */ + const char uri[] = "file:///%ag"; + char *path; + uri_parse(uri, sizeof(uri) - 1, NULL, NULL, NULL, NULL, NULL, &path, NULL, NULL); + xassert(streq(path, "/%ag")); free(path); +}