summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Hanselmann <public@hansmi.ch>2021-08-26 22:32:55 +0200
committerMichael Hanselmann <public@hansmi.ch>2021-08-28 17:48:17 +0200
commit186c4c7951319031771d69b580420c7a0065a107 (patch)
tree06f0ffeb9143208fdd1a85ce2c2b719a70bfd519
parentc3c67aba715e892fcb2ce02158e8bd47b05929a5 (diff)
Avoid memory leak from ill-formatted serialization data
At commit 060d7914ea the following `fuzzing/usbredirparserfuzz` input triggers a memory leak: ``` $ base64 -d <<'EOF' | gunzip -c > testcase H4sIAFDwJ2ECA2NgZIADBQWF/zD2HQgfAv4DgcJ/BTzgP0iRAlwRivL/ePX9 R1VAyBaSjcShB8nPTBA9/xn+g5UAANvH+dkSAQAA ``` The data type header segment is empty while there's (supposed) payload data in there. The internal buffers must be filled in the order of header, type header and then data, an invariant important for `usbredirparser_do_read` and violated by this input. With this change the input data is read the same way, but if the invariant would be violated the data read is just ignored. The parser check at the beginning of `usbredirparser_unserialize` is also improved and `write_buf_count` is no longer set explicitly. Signed-off-by: Michael Hanselmann <public@hansmi.ch>
-rw-r--r--usbredirparser/usbredirparser.c18
1 files changed, 13 insertions, 5 deletions
diff --git a/usbredirparser/usbredirparser.c b/usbredirparser/usbredirparser.c
index e980f5a..d54c2fd 100644
--- a/usbredirparser/usbredirparser.c
+++ b/usbredirparser/usbredirparser.c
@@ -1751,8 +1751,9 @@ int usbredirparser_unserialize(struct usbredirparser *parser_pub,
return -1;
}
- if (parser->write_buf_count != 0 || parser->write_buf != NULL ||
- parser->data != NULL) {
+ if (!(parser->write_buf_count == 0 && parser->write_buf == NULL &&
+ parser->data == NULL && parser->header_read == 0 &&
+ parser->type_header_read == 0 && parser->data_read == 0)) {
ERROR("unserialization must use a pristine parser");
return -1;
}
@@ -1828,7 +1829,9 @@ int usbredirparser_unserialize(struct usbredirparser *parser_pub,
i = parser->type_header_len;
if (unserialize_data(parser, &state, &remain, &data, &i, "type_header"))
return -1;
- parser->type_header_read = i;
+ if (parser->header_read == header_len) {
+ parser->type_header_read = i;
+ }
if (parser->data_len) {
parser->data = malloc(parser->data_len);
@@ -1840,8 +1843,13 @@ int usbredirparser_unserialize(struct usbredirparser *parser_pub,
i = parser->data_len;
if (unserialize_data(parser, &state, &remain, &parser->data, &i, "data"))
return -1;
- parser->data_read = i;
- parser->write_buf_count = 0;
+ if (parser->header_read == header_len &&
+ parser->type_header_read == parser->type_header_len) {
+ parser->data_read = i;
+ } else if (parser->data != NULL) {
+ free(parser->data);
+ parser->data = NULL;
+ }
/* Get the write buffer count and the write buffers */
if (unserialize_int(parser, &state, &remain, &i, "write_buf_count"))