diff options
author | Todd Carson <toc@daybefore.net> | 2023-03-19 17:32:29 -1000 |
---|---|---|
committer | Philip Withnall <pwithnall@endlessos.org> | 2023-04-14 16:52:10 +0100 |
commit | 7f4726d151a616720bfd4e4f6a2c3a2d471f8b33 (patch) | |
tree | b023ddf14f0ee670447d3ba9799fef8b50290c8e | |
parent | e979fd9a157688a1a65fb58250b2a9fe94d14d50 (diff) | |
download | glib-7f4726d151a616720bfd4e4f6a2c3a2d471f8b33.tar.gz |
g_utf8_normalize: don't read past the end of the buffer
_g_utf8_normalize_wc() could read past the end of the provided buffer if
it ends with a truncated multibyte character. If max_len is -1, it can
continue reading until it encounters either a NUL or unreadable
memory. Avoid this with extra bounds checks prior to g_utf8_get_char()
to ensure that it does not read past either max_len or a NUL
terminator.
-rw-r--r-- | glib/gunidecomp.c | 39 |
1 files changed, 33 insertions, 6 deletions
diff --git a/glib/gunidecomp.c b/glib/gunidecomp.c index 07bc3cb22..f14944397 100644 --- a/glib/gunidecomp.c +++ b/glib/gunidecomp.c @@ -388,9 +388,33 @@ _g_utf8_normalize_wc (const gchar *str, while ((max_len < 0 || p < str + max_len) && *p) { const gchar *decomp; - gunichar wc = g_utf8_get_char (p); + const char *next, *between; + gunichar wc; - if (wc >= SBase && wc < SBase + SCount) + next = g_utf8_next_char (p); + /* Avoid reading truncated multibyte characters + which run past the end of the buffer */ + if (max_len < 0) + { + /* Does the character contain a NUL terminator? */ + for (between = &p[1]; between < next; between++) + { + if (G_UNLIKELY (!*between)) + return NULL; + } + } + else + { + if (G_UNLIKELY (next > str + max_len)) + return NULL; + } + wc = g_utf8_get_char (p); + + if (G_UNLIKELY (wc == (gunichar) -1)) + { + return NULL; + } + else if (wc >= SBase && wc < SBase + SCount) { gsize result_len; decompose_hangul (wc, NULL, &result_len); @@ -406,7 +430,7 @@ _g_utf8_normalize_wc (const gchar *str, n_wc++; } - p = g_utf8_next_char (p); + p = next; } wc_buffer = g_new (gunichar, n_wc + 1); @@ -548,10 +572,13 @@ g_utf8_normalize (const gchar *str, GNormalizeMode mode) { gunichar *result_wc = _g_utf8_normalize_wc (str, len, mode); - gchar *result; + gchar *result = NULL; - result = g_ucs4_to_utf8 (result_wc, -1, NULL, NULL, NULL); - g_free (result_wc); + if (G_LIKELY (result_wc != NULL)) + { + result = g_ucs4_to_utf8 (result_wc, -1, NULL, NULL, NULL); + g_free (result_wc); + } return result; } |