diff options
author | Frediano Ziglio <freddy77@gmail.com> | 2021-09-09 12:05:09 +0100 |
---|---|---|
committer | Victor Toso <me@victortoso.com> | 2021-09-28 08:43:18 +0000 |
commit | a4d9ae93abb2b22adc83c6fecc8c8e8f69366a88 (patch) | |
tree | daf601548d3bbea109d6ebf3fdaf38e868c6891d | |
parent | db13ad0206d4362af8ede6371044c32b443d64a2 (diff) |
Implement some internal checks to make sure usbredirparser_priv is correct
Make sure structure keeps its integrity.
This is useful used with the fuzzer.
Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
-rwxr-xr-x | build-aux/oss-fuzz.sh | 3 | ||||
-rw-r--r-- | meson.build | 4 | ||||
-rw-r--r-- | meson_options.txt | 5 | ||||
-rw-r--r-- | usbredirparser/usbredirparser.c | 93 |
4 files changed, 94 insertions, 11 deletions
diff --git a/build-aux/oss-fuzz.sh b/build-aux/oss-fuzz.sh index ffa4002..852080b 100755 --- a/build-aux/oss-fuzz.sh +++ b/build-aux/oss-fuzz.sh @@ -46,6 +46,9 @@ config=( # Don't use "-Wl,--no-undefined" -Db_lundef=false + + # Enable internal tests + -Dextra-checks=true ) if ! meson setup "${config[@]}" -- "$builddir"; then diff --git a/meson.build b/meson.build index e0311dd..49dbce4 100644 --- a/meson.build +++ b/meson.build @@ -34,6 +34,10 @@ add_project_arguments(supported_cc_flags, language: 'c') config = configuration_data() +if get_option('extra-checks') + config.set('ENABLE_EXTRA_CHECKS', '1') +endif + config.set('USBREDIR_VISIBLE', '') foreach visibility : [ '__attribute__((visibility ("default")))', diff --git a/meson_options.txt b/meson_options.txt index 34dd392..da9b700 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -31,3 +31,8 @@ option('tests', type : 'feature', value : 'enabled', description : 'Build usbredir\'s tests such as filter') + +option('extra-checks', + type : 'boolean', + value : false, + description : 'Enable extra checks on code. Do not use for production') diff --git a/usbredirparser/usbredirparser.c b/usbredirparser/usbredirparser.c index d54c2fd..d851fb4 100644 --- a/usbredirparser/usbredirparser.c +++ b/usbredirparser/usbredirparser.c @@ -111,6 +111,35 @@ va_log(struct usbredirparser_priv *parser, int verbose, const char *fmt, ...) #define INFO(...) va_log(parser, usbredirparser_info, __VA_ARGS__) #define DEBUG(...) va_log(parser, usbredirparser_debug, __VA_ARGS__) +static inline void +usbredirparser_assert_invariants(const struct usbredirparser_priv *parser) +{ +#ifdef ENABLE_EXTRA_CHECKS + assert(parser != NULL); + assert(parser->header_read >= 0); + assert(parser->header_read <= sizeof(parser->header)); + assert(parser->type_header_read >= 0); + assert(parser->type_header_len <= sizeof(parser->type_header)); + assert(parser->type_header_read <= parser->type_header_len); + assert(parser->data_len >= 0); + assert(parser->data_len <= MAX_PACKET_SIZE); + assert(parser->data_read >= 0); + assert(parser->data_read <= parser->data_len); + assert((parser->data_len != 0) ^ (parser->data == NULL)); + + int write_buf_count = 0; + const struct usbredirparser_buf *write_buf = parser->write_buf; + for (; write_buf != NULL ; write_buf = write_buf->next) { + assert(write_buf->pos >= 0); + assert(write_buf->len >= 0); + assert(write_buf->pos <= write_buf->len); + assert(write_buf->len == 0 || write_buf->buf != NULL); + write_buf_count++; + } + assert(parser->write_buf_count == write_buf_count); +#endif +} + #if 0 /* Can be enabled and called from random place to test serialization */ static void serialize_test(struct usbredirparser *parser_pub) { @@ -974,13 +1003,16 @@ int usbredirparser_do_read(struct usbredirparser *parser_pub) header_len = usbredirparser_get_header_len(parser_pub); + usbredirparser_assert_invariants(parser); /* Skip forward to next packet (only used in error conditions) */ while (parser->to_skip > 0) { uint8_t buf[65536]; r = (parser->to_skip > sizeof(buf)) ? sizeof(buf) : parser->to_skip; r = parser->callb.read_func(parser->callb.priv, buf, r); - if (r <= 0) + if (r <= 0) { + usbredirparser_assert_invariants(parser); return r; + } parser->to_skip -= r; } @@ -1000,6 +1032,7 @@ int usbredirparser_do_read(struct usbredirparser *parser_pub) if (r > 0) { r = parser->callb.read_func(parser->callb.priv, dest, r); if (r <= 0) { + usbredirparser_assert_invariants(parser); return r; } } @@ -1015,6 +1048,7 @@ int usbredirparser_do_read(struct usbredirparser *parser_pub) parser->header.type); parser->to_skip = parser->header.length; parser->header_read = 0; + usbredirparser_assert_invariants(parser); return usbredirparser_read_parse_error; } /* This should never happen */ @@ -1022,6 +1056,7 @@ int usbredirparser_do_read(struct usbredirparser *parser_pub) ERROR("error type specific header buffer too small, please report!!"); parser->to_skip = parser->header.length; parser->header_read = 0; + usbredirparser_assert_invariants(parser); return usbredirparser_read_parse_error; } if (parser->header.length > MAX_PACKET_SIZE) { @@ -1029,6 +1064,7 @@ int usbredirparser_do_read(struct usbredirparser *parser_pub) parser->header.length, MAX_PACKET_SIZE); parser->to_skip = parser->header.length; parser->header_read = 0; + usbredirparser_assert_invariants(parser); return usbredirparser_read_parse_error; } if ((int)parser->header.length < type_header_len || @@ -1038,6 +1074,7 @@ int usbredirparser_do_read(struct usbredirparser *parser_pub) parser->header.type, parser->header.length); parser->to_skip = parser->header.length; parser->header_read = 0; + usbredirparser_assert_invariants(parser); return usbredirparser_read_parse_error; } data_len = parser->header.length - type_header_len; @@ -1047,6 +1084,7 @@ int usbredirparser_do_read(struct usbredirparser *parser_pub) ERROR("Out of memory allocating data buffer"); parser->to_skip = parser->header.length; parser->header_read = 0; + usbredirparser_assert_invariants(parser); return usbredirparser_read_parse_error; } } @@ -1075,8 +1113,10 @@ int usbredirparser_do_read(struct usbredirparser *parser_pub) parser->data_len = 0; parser->data_read = 0; parser->data = NULL; - if (!r) + if (!r) { + usbredirparser_assert_invariants(parser); return usbredirparser_read_parse_error; + } /* header len may change if this was an hello packet */ header_len = usbredirparser_get_header_len(parser_pub); } @@ -1744,10 +1784,14 @@ int usbredirparser_unserialize(struct usbredirparser *parser_pub, uint8_t *data; uint32_t i, l, header_len, remain = len; - if (unserialize_int(parser, &state, &remain, &i, "magic")) + usbredirparser_assert_invariants(parser); + if (unserialize_int(parser, &state, &remain, &i, "magic")) { + usbredirparser_assert_invariants(parser); return -1; + } if (i != USBREDIRPARSER_SERIALIZE_MAGIC) { ERROR("error unserialize magic mismatch"); + usbredirparser_assert_invariants(parser); return -1; } @@ -1755,21 +1799,27 @@ int usbredirparser_unserialize(struct usbredirparser *parser_pub, parser->data == NULL && parser->header_read == 0 && parser->type_header_read == 0 && parser->data_read == 0)) { ERROR("unserialization must use a pristine parser"); + usbredirparser_assert_invariants(parser); return -1; } - if (unserialize_int(parser, &state, &remain, &i, "length")) + if (unserialize_int(parser, &state, &remain, &i, "length")) { + usbredirparser_assert_invariants(parser); return -1; + } if (i != len) { ERROR("error unserialize length mismatch"); + usbredirparser_assert_invariants(parser); return -1; } data = (uint8_t *)parser->our_caps; i = USB_REDIR_CAPS_SIZE * sizeof(int32_t); memcpy(orig_caps, parser->our_caps, i); - if (unserialize_data(parser, &state, &remain, &data, &i, "our_caps")) + if (unserialize_data(parser, &state, &remain, &data, &i, "our_caps")) { + usbredirparser_assert_invariants(parser); return -1; + } for (i =0; i < USB_REDIR_CAPS_SIZE; i++) { if (parser->our_caps[i] != orig_caps[i]) { /* orig_caps is our original settings @@ -1781,6 +1831,7 @@ int usbredirparser_unserialize(struct usbredirparser *parser_pub, /* Source has a cap we don't */ ERROR("error unserialize caps mismatch ours: %x recv: %x", orig_caps[i], parser->our_caps[i]); + usbredirparser_assert_invariants(parser); return -1; } else { /* We've got a cap the source doesn't - that's OK */ @@ -1792,20 +1843,26 @@ int usbredirparser_unserialize(struct usbredirparser *parser_pub, data = (uint8_t *)parser->peer_caps; i = USB_REDIR_CAPS_SIZE * sizeof(int32_t); - if (unserialize_data(parser, &state, &remain, &data, &i, "peer_caps")) + if (unserialize_data(parser, &state, &remain, &data, &i, "peer_caps")) { + usbredirparser_assert_invariants(parser); return -1; + } if (i) parser->have_peer_caps = 1; - if (unserialize_int(parser, &state, &remain, &i, "skip")) + if (unserialize_int(parser, &state, &remain, &i, "skip")) { + usbredirparser_assert_invariants(parser); return -1; + } parser->to_skip = i; header_len = usbredirparser_get_header_len(parser_pub); data = (uint8_t *)&parser->header; i = header_len; - if (unserialize_data(parser, &state, &remain, &data, &i, "header")) + if (unserialize_data(parser, &state, &remain, &data, &i, "header")) { + usbredirparser_assert_invariants(parser); return -1; + } parser->header_read = i; /* Set various length field froms the header (if we've a header) */ @@ -1819,6 +1876,7 @@ int usbredirparser_unserialize(struct usbredirparser *parser_pub, (parser->header.length > type_header_len && !usbredirparser_expect_extra_data(parser))) { ERROR("error unserialize packet header invalid"); + usbredirparser_assert_invariants(parser); return -1; } parser->type_header_len = type_header_len; @@ -1827,8 +1885,10 @@ int usbredirparser_unserialize(struct usbredirparser *parser_pub, data = parser->type_header; i = parser->type_header_len; - if (unserialize_data(parser, &state, &remain, &data, &i, "type_header")) + if (unserialize_data(parser, &state, &remain, &data, &i, "type_header")) { + usbredirparser_assert_invariants(parser); return -1; + } if (parser->header_read == header_len) { parser->type_header_read = i; } @@ -1837,12 +1897,15 @@ int usbredirparser_unserialize(struct usbredirparser *parser_pub, parser->data = malloc(parser->data_len); if (!parser->data) { ERROR("Out of memory allocating unserialize buffer"); + usbredirparser_assert_invariants(parser); return -1; } } i = parser->data_len; - if (unserialize_data(parser, &state, &remain, &parser->data, &i, "data")) + if (unserialize_data(parser, &state, &remain, &parser->data, &i, "data")) { + usbredirparser_assert_invariants(parser); return -1; + } if (parser->header_read == header_len && parser->type_header_read == parser->type_header_len) { parser->data_read = i; @@ -1852,20 +1915,25 @@ int usbredirparser_unserialize(struct usbredirparser *parser_pub, } /* Get the write buffer count and the write buffers */ - if (unserialize_int(parser, &state, &remain, &i, "write_buf_count")) + if (unserialize_int(parser, &state, &remain, &i, "write_buf_count")) { + usbredirparser_assert_invariants(parser); return -1; + } next = &parser->write_buf; + usbredirparser_assert_invariants(parser); while (i) { uint8_t *buf = NULL; l = 0; if (unserialize_data(parser, &state, &remain, &buf, &l, "wbuf")) { + usbredirparser_assert_invariants(parser); return -1; } if (l == 0) { free(buf); ERROR("write buffer %d is empty", i); + usbredirparser_assert_invariants(parser); return -1; } @@ -1873,6 +1941,7 @@ int usbredirparser_unserialize(struct usbredirparser *parser_pub, if (!wbuf) { free(buf); ERROR("Out of memory allocating unserialize buffer"); + usbredirparser_assert_invariants(parser); return -1; } wbuf->buf = buf; @@ -1885,8 +1954,10 @@ int usbredirparser_unserialize(struct usbredirparser *parser_pub, if (remain) { ERROR("error unserialize %d bytes of extraneous state data", remain); + usbredirparser_assert_invariants(parser); return -1; } + usbredirparser_assert_invariants(parser); return 0; } |