diff options
Diffstat (limited to 'fs/erofs/decompress.c')
-rw-r--r-- | fs/erofs/decompress.c | 32 |
1 files changed, 26 insertions, 6 deletions
diff --git a/fs/erofs/decompress.c b/fs/erofs/decompress.c index 2be3b844cf..e04e5c34a8 100644 --- a/fs/erofs/decompress.c +++ b/fs/erofs/decompress.c @@ -15,8 +15,8 @@ static int z_erofs_decompress_lz4(struct z_erofs_decompress_req *rq) if (erofs_sb_has_lz4_0padding()) { support_0padding = true; - while (!src[inputmargin & ~PAGE_MASK]) - if (!(++inputmargin & ~PAGE_MASK)) + while (!src[inputmargin & (erofs_blksiz() - 1)]) + if (!(++inputmargin & (erofs_blksiz() - 1))) break; if (inputmargin >= rq->inputsize) @@ -40,6 +40,9 @@ static int z_erofs_decompress_lz4(struct z_erofs_decompress_req *rq) rq->decodedlength); if (ret != (int)rq->decodedlength) { + erofs_err("failed to %s decompress %d in[%u, %u] out[%u]", + rq->partial_decoding ? "partial" : "full", + ret, rq->inputsize, inputmargin, rq->decodedlength); ret = -EIO; goto out; } @@ -58,13 +61,30 @@ out: int z_erofs_decompress(struct z_erofs_decompress_req *rq) { - if (rq->alg == Z_EROFS_COMPRESSION_SHIFTED) { - if (rq->inputsize != EROFS_BLKSIZ) + if (rq->alg == Z_EROFS_COMPRESSION_INTERLACED) { + unsigned int count, rightpart, skip; + + /* XXX: should support inputsize >= erofs_blksiz() later */ + if (rq->inputsize > erofs_blksiz()) return -EFSCORRUPTED; - DBG_BUGON(rq->decodedlength > EROFS_BLKSIZ); - DBG_BUGON(rq->decodedlength < rq->decodedskip); + if (rq->decodedlength > erofs_blksiz()) + return -EFSCORRUPTED; + + if (rq->decodedlength < rq->decodedskip) + return -EFSCORRUPTED; + count = rq->decodedlength - rq->decodedskip; + skip = erofs_blkoff(rq->interlaced_offset + rq->decodedskip); + rightpart = min(erofs_blksiz() - skip, count); + memcpy(rq->out, rq->in + skip, rightpart); + memcpy(rq->out + rightpart, rq->in, count - rightpart); + return 0; + } else if (rq->alg == Z_EROFS_COMPRESSION_SHIFTED) { + if (rq->decodedlength > rq->inputsize) + return -EFSCORRUPTED; + + DBG_BUGON(rq->decodedlength < rq->decodedskip); memcpy(rq->out, rq->in + rq->decodedskip, rq->decodedlength - rq->decodedskip); return 0; |