History

btrfs: declare btrfs_ioctl_search_args_v2::buf as __u8

The variable-sized buffer buf in struct btrfs_ioctl_search_args_v2 is declared as __u64[], but it holds a packed byte stream of search results, where all offsets into the buffer are in bytes. Declaring buf as __u64[] makes it easy for user space to write incorrect pointer arithmetic: adding a byte offset directly to a __u64 pointer scales the offset by 8, landing at byte position offset*8 instead of offset. This recently caused an infinite loop in btrfs-progs: the accessor read all-zero data from misaddressed items, which fed zeroed search keys back into the ioctl loop and spun forever. The issue was worked around at the time by disabling TREE_SEARCH_V2 entirely in btrfs-progs (d73e69824854: "btrfs-progs: temporarily disable usage of v2 of search tree ioctl"). The kernel side already treats buf as a byte buffer, so change the declaration to __u8[] to match the actual semantics and prevent similar misuse in user space. The change is ABI compatible: both the structure size and alignment are unchanged.

You-Kai Zheng committed 4 months ago

Commit b95181f1 parent b78fe951 file · +1 −1Browse files

Unified · Split

include/uapi/linux/btrfs.h+1−1
@@ -598,7 +598,7 @@ struct btrfs_ioctl_search_args_v2 { · 597 unmodified lines
598 __u64 buf_size; /* in - size of buffer598 __u64 buf_size; /* in - size of buffer
599 * out - on EOVERFLOW: needed size599 * out - on EOVERFLOW: needed size
600 * to store item */600 * to store item */
601 __u64 buf[]; /* out - found items */601 __u8 buf[]; /* out - found items */
602};602};
603 603
604/* With a @src_length of zero, the range from @src_offset->EOF is cloned! */604/* With a @src_length of zero, the range from @src_offset->EOF is cloned! */