[PATCH] btrfs: props: ensure data buffer is NUL terminated
Qu Wenruo <[email protected]>
| Newsgroups | org.kernel.vger.linux-btrfs |
|---|---|
| Message-ID | <a47ac74a9d7d7e51eeb4f47eeafc09ac512815e7.1786316357.git.wqu@suse.com> |
Btrfs stores its specific XATTR strings in XATTR_ITEM without NUL
termination. e.g:
item 6 key (257 XATTR_ITEM 550297449) itemoff 15812 itemsize 51
location key (0 UNKNOWN.0 0) type XATTR
transid 10 data_len 4 name_len 17
name: btrfs.compression
data zlib
Note that both name and data have no extra NUL termination byte.
Meanwhile we have a lot of call sites that are calling
strncmp()/strcmp() which requires both strings to be NUL terminated.
For name buffer it's fine, as we allocate the name buffer by name_len +
1, and manually set the byte at @name_len to '\0' after reading the
name.
But it's not the case for data buffer, and inside prop_compression_*(),
we have all kinds of call sites calling strncmp()/strcmp(), including:
- prop_compression_validate()
- prop_compression_apply()
Those strncmp()/strcmp() can read at most 4 bytes, which can go beyond
the value_buf[] allocated, especially when the image is maliciously
crafted.
Avoid such problem by following the name_len handling, by allocating one
extra byte for value_buf[] and always set the byte at @data_len to '\0'
so the value_buf[] is always NUL terminated.
Fixes: 63541927c8d1 ("Btrfs: add support for inode properties")
Signed-off-by: Qu Wenruo <[email protected]>
---
fs/btrfs/props.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/fs/btrfs/props.c b/fs/btrfs/props.c
index bb77d46376d4..4dfe8708e5ba 100644
--- a/fs/btrfs/props.c
+++ b/fs/btrfs/props.c
@@ -234,16 +234,17 @@ static int iterate_object_props(struct btrfs_root *root,
if (!handler)
goto next_dir_item;
- if (data_len > value_buf_len) {
+ if (data_len >= value_buf_len) {
kfree(value_buf);
- value_buf_len = data_len;
- value_buf = kmalloc(data_len, GFP_NOFS);
+ value_buf_len = data_len + 1;
+ value_buf = kmalloc(value_buf_len, GFP_NOFS);
if (!value_buf) {
ret = -ENOMEM;
goto out;
}
}
read_extent_buffer(leaf, value_buf, data_ptr, data_len);
+ value_buf[data_len] = '\0';
iterator(ctx, handler, value_buf, data_len);
next_dir_item:
--
2.54.0