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
|
|||
|
|
|