]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ntfs: fix WARN_ON for resident attribute in ntfs_map_runlist_nolock()
authorNamjae Jeon <linkinjeon@kernel.org>
Thu, 2 Jul 2026 01:31:44 +0000 (10:31 +0900)
committerNamjae Jeon <linkinjeon@kernel.org>
Mon, 6 Jul 2026 11:26:08 +0000 (20:26 +0900)
When ntfs_map_runlist_nolock() needs to look up the attribute extent
containing a target VCN (ctx_needs_reset == true), it calls
ntfs_attr_lookup() and then expects the result to be a non-resident
attribute, since only non-resident attributes have a mapping pairs
array to decompress.

A crafted NTFS image can place a resident attribute where a non-resident
one is expected, causing ntfs_attr_lookup() to succeed but return a
resident attribute record.  Previously this was caught only by a
WARN_ON(), which does not stop execution.  The code then falls through to
read a->data.non_resident.highest_vcn from what is actually a resident
attribute, accessing the wrong union member and corrupting the VCN range
check.

The caller path triggering this warning during mount is:

  ntfs_map_runlist_nolock
  ntfs_empty_logfile
  load_system_files
  ntfs_fill_super

In this path ctx is NULL, so ntfs_map_runlist_nolock() allocates a
temporary search context internally and sets ctx_needs_reset = true.
The existing resident-attribute guard in the ctx != NULL branch already
returns -EIO silently for the same condition; make the ctx_needs_reset
path consistent by replacing the WARN_ON() with the same -EIO error
return.

This causes the crafted image to be rejected with a mount error instead
of triggering a kernel warning.

Fixes: 495e90fa3348 ("ntfs: update attrib operations")
Cc: stable@vger.kernel.org
Reported-by: Sangho Lee <kudo3228@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
fs/ntfs/attrib.c

index a99b84751eb1227d4a4300d22b07e26cdc797871..e5e3bc03ad493756120c9ba5dda9d6f909d8eb6f 100644 (file)
@@ -175,7 +175,10 @@ int ntfs_map_runlist_nolock(struct ntfs_inode *ni, s64 vcn, struct ntfs_attr_sea
                                err = -EIO;
                        goto err_out;
                }
-               WARN_ON(!ctx->attr->non_resident);
+               if (unlikely(!ctx->attr->non_resident)) {
+                       err = -EIO;
+                       goto err_out;
+               }
        }
        a = ctx->attr;
        /*