diff --git a/src/basic/compress.c b/src/basic/compress.c index f3e57dd284..8a3cf92a41 100644 --- a/src/basic/compress.c +++ b/src/basic/compress.c @@ -1440,6 +1440,9 @@ static int decompress_startswith_gzip( if (r == Z_STREAM_END) return 0; + if (s.avail_out > 0) + return -EBADMSG; /* truncated */ + size_t used = allocated - s.avail_out; if (!(greedy_realloc(buffer, allocated * 2, 1))) @@ -1506,6 +1509,9 @@ static int decompress_startswith_bzip2( if (r == BZ_STREAM_END) return 0; + if (s.avail_out > 0) + return -EBADMSG; /* truncated */ + size_t used = allocated - s.avail_out; if (!(greedy_realloc(buffer, allocated * 2, 1))) diff --git a/src/test/test-compress.c b/src/test/test-compress.c index 5c419310b8..e66fb5ce30 100644 --- a/src/test/test-compress.c +++ b/src/test/test-compress.c @@ -341,6 +341,19 @@ TEST(decompress_startswith_short) { ASSERT_OK_POSITIVE(decompress_startswith(c, buf, csize, &buf2, TEXT, i, TEXT[i])); ASSERT_OK_ZERO(decompress_startswith(c, buf, csize, &buf2, TEXT, i, 'y')); } + + /* A truncated stream leaves the decoder unable to make progress: it has consumed all the + * input there is, and the prefix we are after never materialises. Since + * decompress_startswith() grows its output buffer whenever it comes back with less than + * the prefix decoded, that has to be recognised, as more output room cannot substitute + * for missing input. Hence the result may be a match, a non-match, or -EBADMSG, but never + * -ENOMEM. */ + for (size_t i = 1; i < csize; i++) { + _cleanup_free_ void *buf2 = NULL; + + ASSERT_OK_OR(decompress_startswith(c, buf, i, &buf2, TEXT, strlen(TEXT), TEXT[strlen(TEXT)]), + -EBADMSG); + } } #undef TEXT }