[libsoup] soup-uri: Check string lengths before reading bytes of %-encoded chars
- From: Claudio Saavedra <csaavedra src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libsoup] soup-uri: Check string lengths before reading bytes of %-encoded chars
- Date: Thu, 2 Jul 2020 18:27:43 +0000 (UTC)
commit ab859a8adaf37e2cbdb11b4e4b825b872b93ed74
Author: Philip Withnall <withnall endlessm com>
Date: Wed Jul 1 13:01:32 2020 +0100
soup-uri: Check string lengths before reading bytes of %-encoded chars
There are two instances in `SoupURI` where `g_ascii_isxdigit()` is
called two bytes ahead of the read pointer to check if a %-encoding is
valid. This is fine when the string being parsed is nul-terminated (as
the first `g_ascii_isxdigit()` call will safely return `FALSE`), but
will result in a read off the end of the buffer if it’s
length-terminated (and doesn’t happen to also be nul-terminated).
Thankfully, that’s not the case in any of the code paths in `SoupURI`
leading to these two instances, so this is not a security issue.
However, the functions should probably be fixed to do an appropriate
length check, just in case they get called from somewhere else in
future.
Spotted by oss-fuzz in oss-fuzz#23815 and oss-fuzz#23818, when it was
fuzzing the new `GUri` implementation in GLib, which is heavily based
off this code.
Includes two unit tests which don’t actually trigger the original
failure (as all strings passed into `SoupURI` are forced to be
nul-terminated), but would trigger it if the nul termination was not
present.
Signed-off-by: Philip Withnall <withnall endlessm com>
libsoup/soup-uri.c | 12 ++++++++++--
tests/uri-parsing-test.c | 12 +++++++++++-
2 files changed, 21 insertions(+), 3 deletions(-)
---
diff --git a/libsoup/soup-uri.c b/libsoup/soup-uri.c
index c01b3e3b..4bb55b81 100644
--- a/libsoup/soup-uri.c
+++ b/libsoup/soup-uri.c
@@ -754,6 +754,8 @@ soup_uri_encode (const char *part, const char *escape_extra)
#define XDIGIT(c) ((c) <= '9' ? (c) - '0' : ((c) & 0x4F) - 'A' + 10)
#define HEXCHAR(s) ((XDIGIT (s[1]) << 4) + XDIGIT (s[2]))
+/* length must be set (e.g. from strchr()) such that [part, part + length]
+ * contains no nul bytes */
char *
soup_uri_decoded_copy (const char *part, int length, int *decoded_length)
{
@@ -766,7 +768,9 @@ soup_uri_decoded_copy (const char *part, int length, int *decoded_length)
s = d = (unsigned char *)decoded;
do {
if (*s == '%') {
- if (!g_ascii_isxdigit (s[1]) ||
+ if (s[1] == '\0' ||
+ s[2] == '\0' ||
+ !g_ascii_isxdigit (s[1]) ||
!g_ascii_isxdigit (s[2])) {
*d++ = *s;
continue;
@@ -803,6 +807,8 @@ soup_uri_decode (const char *part)
return soup_uri_decoded_copy (part, strlen (part), NULL);
}
+/* length must be set (e.g. from strchr()) such that [part, part + length]
+ * contains no nul bytes */
static char *
uri_normalized_copy (const char *part, int length,
const char *unescape_extra)
@@ -817,7 +823,9 @@ uri_normalized_copy (const char *part, int length,
s = d = (unsigned char *)normalized;
while (*s) {
if (*s == '%') {
- if (!g_ascii_isxdigit (s[1]) ||
+ if (s[1] == '\0' ||
+ s[2] == '\0' ||
+ !g_ascii_isxdigit (s[1]) ||
!g_ascii_isxdigit (s[2])) {
*d++ = *s++;
continue;
diff --git a/tests/uri-parsing-test.c b/tests/uri-parsing-test.c
index 85f09b9e..d463f1f4 100644
--- a/tests/uri-parsing-test.c
+++ b/tests/uri-parsing-test.c
@@ -466,7 +466,8 @@ static struct {
{ "foo bar", NULL, "foo%20bar" },
{ "foo bar", " ", "foo bar" },
{ "fo\xc3\xb6" "bar", NULL, "fo%C3%B6bar" },
- { "fo\xc3\xb6 bar", " ", "fo%C3%B6 bar" }
+ { "fo\xc3\xb6 bar", " ", "fo%C3%B6 bar" },
+ { "%", NULL, "%" },
};
static int num_normalization_tests = G_N_ELEMENTS (normalization_tests);
@@ -563,6 +564,14 @@ do_data_tests (void)
soup_test_session_abort_unref (session);
}
+static void
+test_uri_decode (void)
+{
+ gchar *decoded = soup_uri_decode ("%");
+ g_assert_cmpstr (decoded, ==, "%");
+ g_free (decoded);
+}
+
int
main (int argc, char **argv)
{
@@ -576,6 +585,7 @@ main (int argc, char **argv)
g_test_add_func ("/uri/null", do_soup_uri_null_tests);
g_test_add_func ("/uri/normalization", do_normalization_tests);
g_test_add_func ("/uri/data", do_data_tests);
+ g_test_add_func ("/uri/decode", test_uri_decode);
ret = g_test_run ();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]