]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ntfs: bound the look-ahead attribute-list entry in ntfs_external_attr_find()
authorBryam Vargas <hexlabsecurity@proton.me>
Sun, 7 Jun 2026 20:30:00 +0000 (20:30 +0000)
committerNamjae Jeon <linkinjeon@kernel.org>
Mon, 8 Jun 2026 13:58:00 +0000 (22:58 +0900)
When resolving an attribute lookup with a non-zero @lowest_vcn,
ntfs_external_attr_find() peeks at the next $ATTRIBUTE_LIST entry to
decide whether to keep searching, but bounds that not-yet-validated
entry only with "(u8 *)next_al_entry + 6 < al_end" (which proves just
bytes 0..6 are in range) and "(u8 *)next_al_entry + length <= al_end"
with an attacker-controlled, non-8-aligned length. It then reads
next_al_entry->lowest_vcn (an __le64 at offset 8) and the name at
next_al_entry->name_offset, both of which can lie past al_end -- the
exact end of the kvmalloc'd attribute-list buffer (allocated at the
on-disk attr_list_size, no rounding). A crafted on-disk $ATTRIBUTE_LIST
whose last entry sits a few bytes before al_end therefore yields a slab
out-of-bounds read when the inode is read.

Validate the look-ahead entry with ntfs_attr_list_entry_is_valid() (added
in patch 1/3) before dereferencing lowest_vcn and the name, so the same
fixed-header, length and name bounds the main attribute-list walk uses now
guard this read too.

Fixes: 1e9ea7e04472 ("Revert "fs: Remove NTFS classic"")
Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me>
Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
fs/ntfs/attrib.c

index 2d675bf99ca762deaf5671bfd056a08e924827fc..1e0076ef81efcc220efa88f400f106cbbaf04277 100644 (file)
@@ -1263,9 +1263,8 @@ find_attr_list_attr:
                 * we have reached the right one or the search has failed.
                 */
                if (lowest_vcn && (u8 *)next_al_entry >= al_start &&
-                               (u8 *)next_al_entry + 6 < al_end &&
-                               (u8 *)next_al_entry + le16_to_cpu(
-                                       next_al_entry->length) <= al_end &&
+                               ntfs_attr_list_entry_is_valid(next_al_entry,
+                                                             al_end) &&
                                le64_to_cpu(next_al_entry->lowest_vcn) <=
                                        lowest_vcn &&
                                next_al_entry->type == al_entry->type &&