|
|
827db5 |
From 99788909d9ec36e3210cf85976fe5b18da690ddd Mon Sep 17 00:00:00 2001
|
|
|
827db5 |
From: "Richard W.M. Jones" <rjones@redhat.com>
|
|
|
827db5 |
Date: Wed, 4 Aug 2021 20:24:59 +0100
|
|
|
827db5 |
Subject: [PATCH] cache, cow: Fix data corruption in zero and trim on unaligned
|
|
|
827db5 |
tail
|
|
|
827db5 |
|
|
|
827db5 |
Commit eb6009b092 ("cache, cow: Reduce use of bounce-buffer") first
|
|
|
827db5 |
introduced in nbdkit 1.14 added an optimization of the
|
|
|
827db5 |
read-modify-write mechanism used for unaligned heads and tails when
|
|
|
827db5 |
zeroing in the cache layer.
|
|
|
827db5 |
|
|
|
827db5 |
Unfortunately the part applied to the tail contained a mistake: It
|
|
|
827db5 |
zeroes the end of the buffer rather than the beginning. This causes
|
|
|
827db5 |
data corruption when you use the zero or trim function with an offset
|
|
|
827db5 |
and count which is not aligned to the block size.
|
|
|
827db5 |
|
|
|
827db5 |
Although the bug has been around for years, a recent change made it
|
|
|
827db5 |
more likely to happen. Commit c1905b0a28 ("cache, cow: Use a 64K
|
|
|
827db5 |
block size by default") increased the default block size from 4K to
|
|
|
827db5 |
64K. Most filesystems use a 4K block size so operations like fstrim
|
|
|
827db5 |
will make 4K-aligned requests, and with a 4K block size also in the
|
|
|
827db5 |
cache or cow filter the unaligned case would never have been hit
|
|
|
827db5 |
before.
|
|
|
827db5 |
|
|
|
827db5 |
We can demonstrate the bug simply by filling a buffer with data
|
|
|
827db5 |
(100000 bytes in the example), and then trimming that data, which
|
|
|
827db5 |
ought to zero it out.
|
|
|
827db5 |
|
|
|
827db5 |
Before this commit there is data visible after the trim:
|
|
|
827db5 |
|
|
|
827db5 |
$ nbdkit --filter=cow data "0x21 * 100000" --run 'nbdsh -u $uri -c "h.trim(100000, 0)" ; nbdcopy $uri - | hexdump -C'
|
|
|
827db5 |
00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
|
|
|
827db5 |
*
|
|
|
827db5 |
00018000 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 |!!!!!!!!!!!!!!!!|
|
|
|
827db5 |
*
|
|
|
827db5 |
000186a0
|
|
|
827db5 |
|
|
|
827db5 |
After this commit the trim completely clears the data:
|
|
|
827db5 |
|
|
|
827db5 |
$ nbdkit --filter=cow data "0x21 * 100000" --run 'nbdsh -u $uri -c "h.trim(100000, 0)" ; nbdcopy $uri - | hexdump -C'
|
|
|
827db5 |
00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
|
|
|
827db5 |
*
|
|
|
827db5 |
000186a0
|
|
|
827db5 |
|
|
|
827db5 |
Thanks: Ming Xie for finding the bug
|
|
|
827db5 |
Fixes: commit eb6009b092ae642ed25f133d487dd40ef7bf70f8
|
|
|
827db5 |
(cherry picked from commit a0ae7b2158598ce48ac31706319007f716d01c87)
|
|
|
827db5 |
(cherry picked from commit c0b15574647672cb5c48178333acdd07424692ef)
|
|
|
827db5 |
---
|
|
|
827db5 |
filters/cache/cache.c | 2 +-
|
|
|
827db5 |
filters/cow/cow.c | 2 +-
|
|
|
827db5 |
2 files changed, 2 insertions(+), 2 deletions(-)
|
|
|
827db5 |
|
|
|
827db5 |
diff --git a/filters/cache/cache.c b/filters/cache/cache.c
|
|
|
827db5 |
index 91dcc43d..0616cc7b 100644
|
|
|
827db5 |
--- a/filters/cache/cache.c
|
|
|
827db5 |
+++ b/filters/cache/cache.c
|
|
|
827db5 |
@@ -493,7 +493,7 @@ cache_zero (struct nbdkit_next_ops *next_ops, void *nxdata,
|
|
|
827db5 |
ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock);
|
|
|
827db5 |
r = blk_read (next_ops, nxdata, blknum, block, err);
|
|
|
827db5 |
if (r != -1) {
|
|
|
827db5 |
- memset (&block[count], 0, blksize - count);
|
|
|
827db5 |
+ memset (block, 0, count);
|
|
|
827db5 |
r = blk_write (next_ops, nxdata, blknum, block, flags, err);
|
|
|
827db5 |
}
|
|
|
827db5 |
if (r == -1)
|
|
|
827db5 |
diff --git a/filters/cow/cow.c b/filters/cow/cow.c
|
|
|
827db5 |
index 51ca64a4..1cfcc4e7 100644
|
|
|
827db5 |
--- a/filters/cow/cow.c
|
|
|
827db5 |
+++ b/filters/cow/cow.c
|
|
|
827db5 |
@@ -419,7 +419,7 @@ cow_zero (struct nbdkit_next_ops *next_ops, void *nxdata,
|
|
|
827db5 |
ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock);
|
|
|
827db5 |
r = blk_read (next_ops, nxdata, blknum, block, err);
|
|
|
827db5 |
if (r != -1) {
|
|
|
827db5 |
- memset (&block[count], 0, BLKSIZE - count);
|
|
|
827db5 |
+ memset (block, 0, count);
|
|
|
827db5 |
r = blk_write (blknum, block, err);
|
|
|
827db5 |
}
|
|
|
827db5 |
if (r == -1)
|
|
|
827db5 |
--
|
|
|
fcc3c9 |
2.31.1
|
|
|
827db5 |
|