Commit f2a12cc3 authored by Gao Xiang's avatar Gao Xiang
Browse files

erofs: avoid infinite loop due to incomplete zstd-compressed data



Currently, the decompression logic incorrectly spins if compressed
data is truncated in crafted (deliberately corrupted) images.

Fixes: 7c35de4d ("erofs: Zstandard compression support")
Reported-by: default avatarRobert Morris <rtm@csail.mit.edu>
Closes: https://lore.kernel.org/r/50958.1761605413@localhost


Signed-off-by: default avatarGao Xiang <hsiangkao@linux.alibaba.com>
Reviewed-by: default avatarChunhai Guo <guochunhai@vivo.com>
Reviewed-by: default avatarChao Yu <chao@kernel.org>
parent 083d7af3
Loading
Loading
Loading
Loading
+7 −4
Original line number Diff line number Diff line
@@ -172,7 +172,6 @@ static int z_erofs_zstd_decompress(struct z_erofs_decompress_req *rq,
	dctx.bounce = strm->bounce;

	do {
		dctx.avail_out = out_buf.size - out_buf.pos;
		dctx.inbuf_sz = in_buf.size;
		dctx.inbuf_pos = in_buf.pos;
		err = z_erofs_stream_switch_bufs(&dctx, &out_buf.dst,
@@ -188,14 +187,18 @@ static int z_erofs_zstd_decompress(struct z_erofs_decompress_req *rq,
		in_buf.pos = dctx.inbuf_pos;

		zerr = zstd_decompress_stream(stream, &out_buf, &in_buf);
		if (zstd_is_error(zerr) || (!zerr && rq->outputsize)) {
		dctx.avail_out = out_buf.size - out_buf.pos;
		if (zstd_is_error(zerr) ||
		    ((rq->outputsize + dctx.avail_out) && (!zerr || (zerr > 0 &&
				!(rq->inputsize + in_buf.size - in_buf.pos))))) {
			erofs_err(sb, "failed to decompress in[%u] out[%u]: %s",
				  rq->inputsize, rq->outputsize,
				  zerr ? zstd_get_error_name(zerr) : "unexpected end of stream");
				  zstd_is_error(zerr) ? zstd_get_error_name(zerr) :
					"unexpected end of stream");
			err = -EFSCORRUPTED;
			break;
		}
	} while (rq->outputsize || out_buf.pos < out_buf.size);
	} while (rq->outputsize + dctx.avail_out);

	if (dctx.kout)
		kunmap_local(dctx.kout);