DF-0805 / fix.diff
diff --git a/sys/vfs/hammer2/hammer2_strategy.c b/sys/vfs/hammer2/hammer2_strategy.c index 1d477f1d76dba9e617634a2f9150cb89b22f76a3..725dd733de25a9f62a22fd9aa61cec3b3eb4058a 100644 --- a/sys/vfs/hammer2/hammer2_strategy.c +++ b/sys/vfs/hammer2/hammer2_strategy.c @@ -196,7 +196,27 @@ KKASSERT(bp->b_bufsize <= HAMMER2_PBUFSIZE); compressed_size = *(const int *)data; - KKASSERT((uint32_t)compressed_size <= bytes - sizeof(int)); + + /* + * Validate the on-media compressed_size BEFORE handing it to + * LZ4_decompress_safe() as inputSize. LZ4 trusts inputSize and + * uses it as the source bound (iend = ip + inputSize at + * hammer2_lz4.c:391); an attacker-controlled value read directly + * from disk in a corrupted/malicious image would cause the decoder + * to read past the chain dio buffer into adjacent kernel memory. + * The previous KKASSERT-only guard was compiled out on non- + * INVARIANTS kernels (sys/sys/systm.h:118). + */ + if (compressed_size < 0 || + (u_int)compressed_size > bytes - sizeof(int)) { + kprintf("HAMMER2 LZ4: bad compressed_size %d (bytes=%u)\n", + compressed_size, bytes); + bp->b_error = EIO; + bp->b_flags |= B_ERROR; + bp->b_resid = bp->b_bufsize; + bzero(bp->b_data, bp->b_bufsize); + return; + } compressed_buffer = objcache_get(cache_buffer_read, M_INTWAIT); result = LZ4_decompress_safe(__DECONST(char *, &data[sizeof(int)]), |