diff --git a/module/zfs/gzip.c b/module/zfs/gzip.c index d183e998456..2dee3e1da78 100644 --- a/module/zfs/gzip.c +++ b/module/zfs/gzip.c @@ -96,13 +96,17 @@ zfs_gzip_decompress_buf(void *s_start, void *d_start, size_t s_len, /* check if hardware accelerator can be used */ if (qat_dc_use_accel(d_len)) { if (qat_compress(QAT_DECOMPRESS, s_start, s_len, - d_start, d_len, &dstlen) == CPA_STATUS_SUCCESS) - return (0); + d_start, d_len, &dstlen) == CPA_STATUS_SUCCESS) { + if ((size_t)dstlen == d_len) + return (0); + } /* if hardware de-compress fail, do it again with software */ } if (uncompress_func(d_start, &dstlen, s_start, s_len) != Z_OK) return (-1); + if ((size_t)dstlen != d_len) + return (-1); return (0); } diff --git a/module/zfs/lz4_zfs.c b/module/zfs/lz4_zfs.c index 0c03a6855c7..672b1bd27e6 100644 --- a/module/zfs/lz4_zfs.c +++ b/module/zfs/lz4_zfs.c @@ -88,17 +88,24 @@ zfs_lz4_decompress_buf(void *s_start, void *d_start, size_t s_len, (void) n; const char *src = s_start; uint32_t bufsiz = BE_IN32(src); + int decoded; /* invalid compressed buffer size encoded at start */ if (bufsiz + sizeof (bufsiz) > s_len) return (1); /* - * Returns 0 on success (decompression function returned non-negative) - * and non-zero on failure (decompression function returned negative). + * LZ4_uncompress_unknownOutputSize returns the number of bytes decoded + * on success, or a negative value on failure. An OpenZFS block must + * expand to exactly d_len bytes */ - return (LZ4_uncompress_unknownOutputSize(&src[sizeof (bufsiz)], - d_start, bufsiz, d_len) < 0); + decoded = LZ4_uncompress_unknownOutputSize(&src[sizeof (bufsiz)], + d_start, bufsiz, d_len); + if (decoded < 0) + return (1); + if (d_len != (size_t)decoded) + return (1); + return (0); } ZFS_COMPRESS_WRAP_DECL(zfs_lz4_compress) diff --git a/module/zstd/zfs_zstd.c b/module/zstd/zfs_zstd.c index 82212055f0e..f38800f7f34 100644 --- a/module/zstd/zfs_zstd.c +++ b/module/zstd/zfs_zstd.c @@ -682,6 +682,15 @@ zfs_zstd_decompress_level_buf(void *s_start, void *d_start, size_t s_len, return (1); } + /* + * An OpenZFS compressed block must expand to exactly d_len bytes. + * ZSTD_decompressDCtx returns the decompressed size on success. + */ + if (result != d_len) { + ZSTDSTAT_BUMP(zstd_stat_dec_fail); + return (1); + } + if (level) { *level = curlevel; }