Message ID | 1489182344-29818-1-git-send-email-ce3g8jdj@umail.furryterror.org (mailing list archive) |
---|---|
State | Accepted |
Headers | show |
On 10/Mar/2017 16:45, Zygo Blaxell wrote: > This is a story about 4 distinct (and very old) btrfs bugs. > <...> Tested-by: Ismael Luceno <ismael@iodev.co.uk> I encountered the issue in the wild; it caused frequent segfaults at ld.so after some hours of operation, as well as integrity check failures. A quick inspection revealed corruption in the ELF headers, with garbage where there should be zeros. I managed to reproduce the issue right away by enabling page poisoning, and the problem effectively goes away when applying the patch. -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 25ac2cf..f41ef5d 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -6805,6 +6805,20 @@ static noinline int uncompress_inline(struct btrfs_path *path, max_size = min_t(unsigned long, PAGE_SIZE, max_size); ret = btrfs_decompress(compress_type, tmp, page, extent_offset, inline_size, max_size); + + /* + * decompression code contains a memset to fill in any space between the end + * of the uncompressed data and the end of max_size in case the decompressed + * data ends up shorter than ram_bytes. That doesn't cover the hole between + * the end of an inline extent and the beginning of the next block, so we + * cover that region here. + */ + + if (max_size + pg_offset < PAGE_SIZE) { + char *map = kmap(page); + memset(map + pg_offset + max_size, 0, PAGE_SIZE - max_size - pg_offset); + kunmap(page); + } kfree(tmp); return ret; }