Merge pull request #11824 from keszybz/fuzzer-fixes

Fuzzer fixes
This commit is contained in:
Lennart Poettering 2019-02-26 19:02:12 +01:00 committed by GitHub
commit f3892edd5e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 63 additions and 37 deletions

View File

@ -28,7 +28,7 @@ int encode_devnode_name(const char *str, char *str_enc, size_t len) {
for (i = 0, j = 0; str[i] != '\0'; i++) {
int seqlen;
seqlen = utf8_encoded_valid_unichar(&str[i]);
seqlen = utf8_encoded_valid_unichar(str + i, (size_t) -1);
if (seqlen > 1) {
if (len-j < (size_t)seqlen)

View File

@ -61,12 +61,7 @@ static bool unichar_is_control(char32_t ch) {
}
/* count of characters used to encode one unicode char */
static size_t utf8_encoded_expected_len(const char *str) {
uint8_t c;
assert(str);
c = (uint8_t) str[0];
static size_t utf8_encoded_expected_len(uint8_t c) {
if (c < 0x80)
return 1;
if ((c & 0xe0) == 0xc0)
@ -90,7 +85,7 @@ int utf8_encoded_to_unichar(const char *str, char32_t *ret_unichar) {
assert(str);
len = utf8_encoded_expected_len(str);
len = utf8_encoded_expected_len(str[0]);
switch (len) {
case 1:
@ -133,14 +128,14 @@ bool utf8_is_printable_newline(const char* str, size_t length, bool newline) {
assert(str);
for (p = str; length;) {
for (p = str; length > 0;) {
int encoded_len, r;
char32_t val;
encoded_len = utf8_encoded_valid_unichar(p);
if (encoded_len < 0 ||
(size_t) encoded_len > length)
encoded_len = utf8_encoded_valid_unichar(p, length);
if (encoded_len < 0)
return false;
assert(encoded_len > 0 && (size_t) encoded_len <= length);
r = utf8_encoded_to_unichar(p, &val);
if (r < 0 ||
@ -164,7 +159,7 @@ char *utf8_is_valid(const char *str) {
while (*p) {
int len;
len = utf8_encoded_valid_unichar(p);
len = utf8_encoded_valid_unichar(p, (size_t) -1);
if (len < 0)
return NULL;
@ -186,7 +181,7 @@ char *utf8_escape_invalid(const char *str) {
while (*str) {
int len;
len = utf8_encoded_valid_unichar(str);
len = utf8_encoded_valid_unichar(str, (size_t) -1);
if (len > 0) {
s = mempcpy(s, str, len);
str += len;
@ -213,7 +208,7 @@ char *utf8_escape_non_printable(const char *str) {
while (*str) {
int len;
len = utf8_encoded_valid_unichar(str);
len = utf8_encoded_valid_unichar(str, (size_t) -1);
if (len > 0) {
if (utf8_is_printable(str, len)) {
s = mempcpy(s, str, len);
@ -405,7 +400,7 @@ char16_t *utf8_to_utf16(const char *s, size_t length) {
char32_t unichar;
size_t e;
e = utf8_encoded_expected_len(s + i);
e = utf8_encoded_expected_len(s[i]);
if (e <= 1) /* Invalid and single byte characters are copied as they are */
goto copy;
@ -457,17 +452,24 @@ static int utf8_unichar_to_encoded_len(char32_t unichar) {
}
/* validate one encoded unicode char and return its length */
int utf8_encoded_valid_unichar(const char *str) {
int utf8_encoded_valid_unichar(const char *str, size_t length /* bytes */) {
char32_t unichar;
size_t len, i;
int r;
assert(str);
assert(length > 0);
len = utf8_encoded_expected_len(str);
/* We read until NUL, at most length bytes. (size_t) -1 may be used to disable the length check. */
len = utf8_encoded_expected_len(str[0]);
if (len == 0)
return -EINVAL;
/* Do we have a truncated multi-byte character? */
if (len > length)
return -EINVAL;
/* ascii is valid */
if (len == 1)
return 1;
@ -500,7 +502,7 @@ size_t utf8_n_codepoints(const char *str) {
while (*str != 0) {
int k;
k = utf8_encoded_valid_unichar(str);
k = utf8_encoded_valid_unichar(str, (size_t) -1);
if (k < 0)
return (size_t) -1;

View File

@ -32,7 +32,7 @@ char16_t *utf8_to_utf16(const char *s, size_t length);
size_t char16_strlen(const char16_t *s); /* returns the number of 16bit words in the string (not bytes!) */
int utf8_encoded_valid_unichar(const char *str);
int utf8_encoded_valid_unichar(const char *str, size_t length);
int utf8_encoded_to_unichar(const char *str, char32_t *ret_unichar);
static inline bool utf16_is_surrogate(char16_t c) {

View File

@ -15,7 +15,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
StdoutStream *stream;
int v;
if (size == 0)
if (size == 0 || size > 65536)
return 0;
if (!getenv("SYSTEMD_LOG_LEVEL"))

View File

@ -0,0 +1,2 @@
[libfuzzer]
max_len = 65536

View File

@ -23,6 +23,9 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
_cleanup_(sd_event_unrefp) sd_event *e = NULL;
_cleanup_(sd_lldp_unrefp) sd_lldp *lldp = NULL;
if (size > 2048)
return 0;
assert_se(sd_event_new(&e) == 0);
assert_se(sd_lldp_new(&lldp) >= 0);
assert_se(sd_lldp_set_ifindex(lldp, 42) >= 0);

View File

@ -0,0 +1,2 @@
[libfuzzer]
max_len = 2048

View File

@ -43,6 +43,9 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
_cleanup_(sd_event_unrefp) sd_event *e = NULL;
_cleanup_(sd_ndisc_unrefp) sd_ndisc *nd = NULL;
if (size > 2048)
return 0;
assert_se(sd_event_new(&e) >= 0);
assert_se(sd_ndisc_new(&nd) >= 0);
assert_se(sd_ndisc_attach_event(nd, e, 0) >= 0);

View File

@ -0,0 +1,2 @@
[libfuzzer]
max_len = 2048

View File

@ -175,7 +175,7 @@ size_t util_replace_chars(char *str, const char *white) {
}
/* accept valid utf8 */
len = utf8_encoded_valid_unichar(&str[i]);
len = utf8_encoded_valid_unichar(str + i, (size_t) -1);
if (len > 1) {
i += len;
continue;

View File

@ -385,13 +385,13 @@ int ask_password_tty(
if (!(flags & ASK_PASSWORD_SILENT))
backspace_chars(ttyfd, 1);
/* Remove a full UTF-8 codepoint from the end. For that, figure out where the last one
* begins */
/* Remove a full UTF-8 codepoint from the end. For that, figure out where the
* last one begins */
q = 0;
for (;;) {
size_t z;
z = utf8_encoded_valid_unichar(passphrase + q);
z = utf8_encoded_valid_unichar(passphrase + q, (size_t) -1);
if (z == 0) {
q = (size_t) -1; /* Invalid UTF8! */
break;
@ -410,8 +410,8 @@ int ask_password_tty(
flags |= ASK_PASSWORD_SILENT;
/* There are two ways to enter silent mode. Either by pressing backspace as first key
* (and only as first key), or ... */
/* There are two ways to enter silent mode. Either by pressing backspace as
* first key (and only as first key), or ... */
if (ttyfd >= 0)
(void) loop_write(ttyfd, "(no echo) ", 10, false);
@ -440,10 +440,13 @@ int ask_password_tty(
if (!(flags & ASK_PASSWORD_SILENT) && ttyfd >= 0) {
/* Check if we got a complete UTF-8 character now. If so, let's output one '*'. */
n = utf8_encoded_valid_unichar(passphrase + codepoint);
n = utf8_encoded_valid_unichar(passphrase + codepoint, (size_t) -1);
if (n >= 0) {
if (flags & ASK_PASSWORD_ECHO)
(void) loop_write(ttyfd, passphrase + codepoint, n, false);
else
(void) loop_write(ttyfd, "*", 1, false);
codepoint = p;
(void) loop_write(ttyfd, (flags & ASK_PASSWORD_ECHO) ? &c : "*", 1, false);
}
}

View File

@ -1756,7 +1756,6 @@ static void inc_lines_columns(unsigned *line, unsigned *column, const char *s, s
assert(s || n == 0);
while (n > 0) {
if (*s == '\n') {
(*line)++;
*column = 1;
@ -1765,7 +1764,7 @@ static void inc_lines_columns(unsigned *line, unsigned *column, const char *s, s
else {
int w;
w = utf8_encoded_valid_unichar(s);
w = utf8_encoded_valid_unichar(s, n);
if (w < 0) /* count invalid unichars as normal characters */
w = 1;
else if ((size_t) w > n) /* never read more than the specified number of characters */
@ -1930,7 +1929,7 @@ static int json_parse_string(const char **p, char **ret) {
continue;
}
len = utf8_encoded_valid_unichar(c);
len = utf8_encoded_valid_unichar(c, (size_t) -1);
if (len < 0)
return len;

View File

@ -36,11 +36,21 @@ static void test_ascii_is_valid_n(void) {
}
static void test_utf8_encoded_valid_unichar(void) {
assert_se(utf8_encoded_valid_unichar("\342\204\242") == 3);
assert_se(utf8_encoded_valid_unichar("\302\256") == 2);
assert_se(utf8_encoded_valid_unichar("a") == 1);
assert_se(utf8_encoded_valid_unichar("\341\204") < 0);
assert_se(utf8_encoded_valid_unichar("\341\204\341\204") < 0);
assert_se(utf8_encoded_valid_unichar("\342\204\242", 1) == -EINVAL); /* truncated */
assert_se(utf8_encoded_valid_unichar("\342\204\242", 2) == -EINVAL); /* truncated */
assert_se(utf8_encoded_valid_unichar("\342\204\242", 3) == 3);
assert_se(utf8_encoded_valid_unichar("\342\204\242", 4) == 3);
assert_se(utf8_encoded_valid_unichar("\302\256", 1) == -EINVAL); /* truncated */
assert_se(utf8_encoded_valid_unichar("\302\256", 2) == 2);
assert_se(utf8_encoded_valid_unichar("\302\256", 3) == 2);
assert_se(utf8_encoded_valid_unichar("\302\256", (size_t) -1) == 2);
assert_se(utf8_encoded_valid_unichar("a", 1) == 1);
assert_se(utf8_encoded_valid_unichar("a", 2) == 1);
assert_se(utf8_encoded_valid_unichar("\341\204", 1) == -EINVAL); /* truncated, potentially valid */
assert_se(utf8_encoded_valid_unichar("\341\204", 2) == -EINVAL); /* truncated, potentially valid */
assert_se(utf8_encoded_valid_unichar("\341\204", 3) == -EINVAL);
assert_se(utf8_encoded_valid_unichar("\341\204\341\204", 4) == -EINVAL);
assert_se(utf8_encoded_valid_unichar("\341\204\341\204", 5) == -EINVAL);
}
static void test_utf8_escaping(void) {

Binary file not shown.