dovecot-2.2: lib: Fixed NUL-handling in uni_utf8_*strlen*()
dovecot at dovecot.org
dovecot at dovecot.org
Wed Jan 14 23:23:20 UTC 2015
details: http://hg.dovecot.org/dovecot-2.2/rev/e645ee117fa9
changeset: 18148:e645ee117fa9
user: Timo Sirainen <tss at iki.fi>
date: Thu Jan 15 01:03:58 2015 +0200
description:
lib: Fixed NUL-handling in uni_utf8_*strlen*()
uni_utf8_strlen() could have skipped over the ending NUL byte and caused
read buffer overflows with invalid input.
uni_utf8_strlen_n() and uni_utf8_partial_strlen_n() now allow NUL bytes in
the input and they're treated as regular control characters. Previously the
size was actually treated as max_size with early NUL byte termination.
Technically this is an API change, but I'm not aware of anything using these
functions in an incompatible way.
diffstat:
src/lib/test-unichar.c | 22 ++++++++++++++++++++--
src/lib/unichar.c | 4 ++--
src/lib/unichar.h | 4 ++--
3 files changed, 24 insertions(+), 6 deletions(-)
diffs (83 lines):
diff -r 14bf136959bc -r e645ee117fa9 src/lib/test-unichar.c
--- a/src/lib/test-unichar.c Thu Jan 15 00:10:56 2015 +0200
+++ b/src/lib/test-unichar.c Thu Jan 15 01:03:58 2015 +0200
@@ -5,9 +5,25 @@
#include "buffer.h"
#include "unichar.h"
+static void test_unichar_uni_utf8_strlen(void)
+{
+ static const char input[] = "\xC3\xA4\xC3\xA4\0a";
+
+ test_begin("uni_utf8_strlen()");
+ test_assert(uni_utf8_strlen(input) == 2);
+ test_end();
+
+ test_begin("uni_utf8_strlen_n()");
+ test_assert(uni_utf8_strlen_n(input, 1) == 0);
+ test_assert(uni_utf8_strlen_n(input, 2) == 1);
+ test_assert(uni_utf8_strlen_n(input, 3) == 1);
+ test_assert(uni_utf8_strlen_n(input, 4) == 2);
+ test_end();
+}
+
static void test_unichar_uni_utf8_partial_strlen_n(void)
{
- static const char input[] = "\xC3\xA4\xC3\xA4";
+ static const char input[] = "\xC3\xA4\xC3\xA4\0a";
size_t pos;
test_begin("uni_utf8_partial_strlen_n()");
@@ -15,7 +31,8 @@
test_assert(uni_utf8_partial_strlen_n(input, 2, &pos) == 1 && pos == 2);
test_assert(uni_utf8_partial_strlen_n(input, 3, &pos) == 1 && pos == 2);
test_assert(uni_utf8_partial_strlen_n(input, 4, &pos) == 2 && pos == 4);
- test_assert(uni_utf8_partial_strlen_n(input, (size_t)-1, &pos) == 2 && pos == 4);
+ test_assert(uni_utf8_partial_strlen_n(input, 5, &pos) == 3 && pos == 5);
+ test_assert(uni_utf8_partial_strlen_n(input, 6, &pos) == 4 && pos == 6);
test_end();
}
@@ -47,5 +64,6 @@
test_assert(uni_utf8_get_char(overlong_utf8, &chr2) < 0);
test_end();
+ test_unichar_uni_utf8_strlen();
test_unichar_uni_utf8_partial_strlen_n();
}
diff -r 14bf136959bc -r e645ee117fa9 src/lib/unichar.c
--- a/src/lib/unichar.c Thu Jan 15 00:10:56 2015 +0200
+++ b/src/lib/unichar.c Thu Jan 15 01:03:58 2015 +0200
@@ -189,7 +189,7 @@
unsigned int uni_utf8_strlen(const char *input)
{
- return uni_utf8_strlen_n(input, (size_t)-1);
+ return uni_utf8_strlen_n(input, strlen(input));
}
unsigned int uni_utf8_strlen_n(const void *input, size_t size)
@@ -206,7 +206,7 @@
unsigned int count, len = 0;
size_t i;
- for (i = 0; i < size && input[i] != '\0'; ) {
+ for (i = 0; i < size; ) {
count = uni_utf8_char_bytes(input[i]);
if (i + count > size)
break;
diff -r 14bf136959bc -r e645ee117fa9 src/lib/unichar.h
--- a/src/lib/unichar.h Thu Jan 15 00:10:56 2015 +0200
+++ b/src/lib/unichar.h Thu Jan 15 01:03:58 2015 +0200
@@ -51,9 +51,9 @@
-1 for invalid input. */
int uni_utf8_get_char(const char *input, unichar_t *chr_r);
int uni_utf8_get_char_n(const void *input, size_t max_len, unichar_t *chr_r);
-/* Returns UTF-8 string length. */
+/* Returns number of characters in UTF-8 string. */
unsigned int uni_utf8_strlen(const char *input) ATTR_PURE;
-/* Returns UTF-8 string length with maximum input size. */
+/* Returns number of characters in UTF-8 input of specified size. */
unsigned int uni_utf8_strlen_n(const void *input, size_t size) ATTR_PURE;
/* Same as uni_utf8_strlen_n(), but if input ends with a partial UTF-8
character, don't include it in the return value and set partial_pos_r to
More information about the dovecot-cvs
mailing list