139 lines
4.4 KiB
Diff
139 lines
4.4 KiB
Diff
From a2c6c5933368b573b6509b0104b1b3da916a2ee1 Mon Sep 17 00:00:00 2001
|
||
From: Qu Wenruo <wqu@suse.com>
|
||
Date: Mon, 8 Jul 2024 13:33:54 +0930
|
||
Subject: [PATCH] btrfs-progs: image: fix the bug that filename sanitization
|
||
not working
|
||
MIME-Version: 1.0
|
||
Content-Type: text/plain; charset=UTF-8
|
||
Content-Transfer-Encoding: 8bit
|
||
|
||
[BUG]
|
||
There is a bug report that image dump taken by "btrfs-image -s" doesn't
|
||
really sanitize the filenames:
|
||
|
||
# truncates -s 1G source.raw
|
||
# mkfs.btrfs -f source.raw
|
||
# mount source.raw $mnt
|
||
# touch $mnt/top_secret_filename
|
||
# touch $mnt/secret_filename
|
||
# umount $mnt
|
||
# btrfs-image -s source.raw dump.img
|
||
# string dump.img | grep filename
|
||
top_secret_filename
|
||
secret_filename
|
||
top_secret_filename
|
||
secret_filename
|
||
top_secret_filename
|
||
|
||
[CAUSE]
|
||
Using above image to store the fs, and we got the following result in fs
|
||
tree:
|
||
|
||
item 0 key (256 INODE_ITEM 0) itemoff 16123 itemsize 160
|
||
generation 3 transid 7 size 68 nbytes 16384
|
||
block group 0 mode 40755 links 1 uid 0 gid 0 rdev 0
|
||
sequence 2 flags 0x0(none)
|
||
item 1 key (256 INODE_REF 256) itemoff 16111 itemsize 12
|
||
index 0 namelen 2 name: ..
|
||
item 2 key (256 DIR_ITEM 439756795) itemoff 16062 itemsize 49
|
||
location key (257 INODE_ITEM 0) type FILE
|
||
transid 7 data_len 0 name_len 19
|
||
name: top_secret_filename
|
||
item 3 key (256 DIR_ITEM 693462946) itemoff 16017 itemsize 45
|
||
location key (258 INODE_ITEM 0) type FILE
|
||
transid 7 data_len 0 name_len 15
|
||
name: secret_filename
|
||
item 4 key (256 DIR_INDEX 2) itemoff 15968 itemsize 49
|
||
location key (257 INODE_ITEM 0) type FILE
|
||
transid 7 data_len 0 name_len 19
|
||
name: top_secret_filename
|
||
item 5 key (256 DIR_INDEX 3) itemoff 15923 itemsize 45
|
||
location key (258 INODE_ITEM 0) type FILE
|
||
transid 7 data_len 0 name_len 15
|
||
name: secret_filename
|
||
item 6 key (257 INODE_ITEM 0) itemoff 15763 itemsize 160
|
||
generation 7 transid 7 size 0 nbytes 0
|
||
block group 0 mode 100644 links 1 uid 0 gid 0 rdev 0
|
||
sequence 1 flags 0x0(none)
|
||
item 7 key (257 INODE_REF 256) itemoff 15734 itemsize 29
|
||
index 2 namelen 19 name: top_secret_filename
|
||
item 8 key (258 INODE_ITEM 0) itemoff 15574 itemsize 160
|
||
generation 7 transid 7 size 0 nbytes 0
|
||
block group 0 mode 100644 links 1 uid 0 gid 0 rdev 0
|
||
sequence 1 flags 0x0(none)
|
||
item 9 key (258 INODE_REF 256) itemoff 15549 itemsize 25
|
||
index 3 namelen 15 name: 1<><31><EFBFBD>'<27>gc*&R
|
||
|
||
The result shows, only the last INODE_REF got sanitized, all the
|
||
remaining are not touched at all.
|
||
|
||
This is caused by how we sanitize the filenames:
|
||
|
||
copy_buffer()
|
||
|- memcpy(dst, src->data, src->len);
|
||
| This means we copy the whole eb into our buffer already.
|
||
|
|
||
|- zero_items()
|
||
|- sanitize_name()
|
||
|- eb = alloc_dummy_eb();
|
||
|- memcpy(eb->data, src->data, src->len);
|
||
| This means we generate a dummy eb with the same contents of
|
||
| the source eb.
|
||
|
|
||
|- sanitize_dir_item();
|
||
| We override the dir item of the given item (specified by the
|
||
| slot number) inside our dummy eb.
|
||
|
|
||
|- memcpy(dst, eb->data, eb->lem);
|
||
|
||
The last one copy the dummy eb into our buffer, with only the slot
|
||
corrupted.
|
||
|
||
But when the whole work flow hits the next slot, we only corrupt the
|
||
next slot, but still copy the whole dummy eb back to buffer.
|
||
|
||
This means the previous slot would be overwritten by the old unsanitized
|
||
data.
|
||
|
||
Resulting only the last slot is corrupted.
|
||
|
||
[FIX]
|
||
Fix the bug by only copying back the corrupted item to the buffer.
|
||
So that other slots won't be overwritten by unsanitized data.
|
||
|
||
Reported-by: Andrea Gelmini <andrea.gelmini@gmail.com>
|
||
Signed-off-by: Qu Wenruo <wqu@suse.com>
|
||
---
|
||
image/sanitize.c | 8 +++++++-
|
||
1 file changed, 7 insertions(+), 1 deletion(-)
|
||
|
||
diff --git a/image/sanitize.c b/image/sanitize.c
|
||
index 084da22..ef4f6e5 100644
|
||
--- a/image/sanitize.c
|
||
+++ b/image/sanitize.c
|
||
@@ -449,6 +449,8 @@ void sanitize_name(enum sanitize_mode sanitize, struct rb_root *name_tree,
|
||
int slot)
|
||
{
|
||
struct extent_buffer *eb;
|
||
+ u32 item_ptr_off = btrfs_item_ptr_offset(src, slot);
|
||
+ u32 item_ptr_size = btrfs_item_size(src, slot);
|
||
|
||
eb = alloc_dummy_eb(src->start, src->len);
|
||
if (!eb) {
|
||
@@ -476,7 +478,11 @@ void sanitize_name(enum sanitize_mode sanitize, struct rb_root *name_tree,
|
||
break;
|
||
}
|
||
|
||
- memcpy(dst, eb->data, eb->len);
|
||
+ /*
|
||
+ * Only overwrite the sanitized part, or we can overwrite previous
|
||
+ * sanitized value with the old values from @src.
|
||
+ */
|
||
+ memcpy(dst + item_ptr_off, eb->data + item_ptr_off, item_ptr_size);
|
||
free(eb);
|
||
}
|
||
|
||
--
|
||
2.43.0
|
||
|