Richard W.M. Jones
2021-Aug-04 19:48 UTC
[Libguestfs] [PATCH nbdkit] cache, cow: Fix data corruption in zero and trim on unaligned tail
Finally I tracked down the data corrupter that I've been searching for for most of this week. I think we will need to backport this patch to quite a few branches upstream and downstream. Rich.
Richard W.M. Jones
2021-Aug-04 19:48 UTC
[Libguestfs] [PATCH nbdkit] cache, cow: Fix data corruption in zero and trim on unaligned tail
Commit eb6009b092 ("cache, cow: Reduce use of bounce-buffer") first introduced in nbdkit 1.14 added an optimization of the read-modify-write mechanism used for unaligned heads and tails when zeroing in the cache layer. Unfortunately the part applied to the tail contained a mistake: It zeroes the end of the buffer rather than the beginning. This causes data corruption when you use the zero or trim function with an offset and count which is not aligned to the block size. We can demonstrate this by filling a buffer with data (100000 bytes in the example), and then trimming that data which ought to zero it all out but does not. Before this commit: $ nbdkit --filter=cow data "33 * 100000" --run 'nbdsh -u $uri -c "h.trim(100000, 0)" ; nbdcopy $uri - | hexdump -C' 00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00018000 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 |!!!!!!!!!!!!!!!!| * 000186a0 After this commit: $ ./nbdkit --filter=cow data "33 * 100000" --run 'nbdsh -u $uri -c "h.trim(100000, 0)" ; nbdcopy $uri - | hexdump -C' 00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 000186a0 Fixes: commit eb6009b092ae642ed25f133d487dd40ef7bf70f8 Thanks: Ming Xie for originally finding the bug --- filters/cache/cache.c | 2 +- filters/cow/cow.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/filters/cache/cache.c b/filters/cache/cache.c index f7b01039..c912c5fb 100644 --- a/filters/cache/cache.c +++ b/filters/cache/cache.c @@ -572,7 +572,7 @@ cache_zero (nbdkit_next *next, ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock); r = blk_read (next, blknum, block, err); if (r != -1) { - memset (&block[count], 0, blksize - count); + memset (block, 0, count); r = blk_write (next, blknum, block, flags, err); } if (r == -1) diff --git a/filters/cow/cow.c b/filters/cow/cow.c index 74fcd61c..6ad42eec 100644 --- a/filters/cow/cow.c +++ b/filters/cow/cow.c @@ -449,7 +449,7 @@ cow_zero (nbdkit_next *next, ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&rmw_lock); r = blk_read (next, blknum, block, cow_on_read (), err); if (r != -1) { - memset (&block[count], 0, BLKSIZE - count); + memset (block, 0, count); r = blk_write (blknum, block, err); } if (r == -1) @@ -520,7 +520,7 @@ cow_trim (nbdkit_next *next, ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&rmw_lock); r = blk_read (next, blknum, block, cow_on_read (), err); if (r != -1) { - memset (&block[count], 0, BLKSIZE - count); + memset (block, 0, count); r = blk_write (blknum, block, err); } if (r == -1) -- 2.32.0