[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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.