]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ntfs: sanitize MFT references returned from ntfs_lookup_inode_by_name()
authorNamjae Jeon <linkinjeon@kernel.org>
Mon, 6 Jul 2026 03:00:00 +0000 (12:00 +0900)
committerNamjae Jeon <linkinjeon@kernel.org>
Mon, 6 Jul 2026 11:27:16 +0000 (20:27 +0900)
ntfs_lookup_inode_by_name() returns MFT references read from directory
index entries on disk. These values are untrusted, but the function can
currently return an error-marked MFT reference to its callers without
validating it.

Callers later decode lookup failures with MREF_ERR(). A crafted NTFS image
can set the MREF error bit while leaving the low bits as an arbitrary
value, causing callers to consume a bogus pseudo-errno instead of treating
the lookup result as corrupted on-disk metadata.

Fix this at the source by normalizing every error-marked MFT reference
returned from ntfs_lookup_inode_by_name() to ERR_MREF(-EIO). Apply this to
all four directory lookup return paths so every caller gets a validated
result without needing additional checks or an API change.

This keeps the sanitization in the common lookup helper, which is cleaner
than duplicating validation in each caller.

Fixes: 1e9ea7e04472 ("Revert "fs: Remove NTFS classic"")
Cc: stable@vger.kernel.org
Reported-by: Hongling Zeng <zenghongling@kylinos.cn>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
fs/ntfs/dir.c

index 4b6bd5f30c65ea422dc119ef4b2303b4859d3d8d..6fa9ae3377cb89d6a0cdfa9ef41badb2dabeef01 100644 (file)
 __le16 I30[5] = { cpu_to_le16('$'), cpu_to_le16('I'),
                cpu_to_le16('3'),       cpu_to_le16('0'), 0 };
 
+static inline u64 ntfs_check_mref(u64 mref)
+{
+       if (IS_ERR_MREF(mref))
+               return ERR_MREF(-EIO);
+       return mref;
+}
+
 /*
  * ntfs_lookup_inode_by_name - find an inode in a directory given its name
  * @dir_ni:    ntfs inode of the directory in which to search for the name
@@ -178,7 +185,7 @@ found_it:
                        mref = le64_to_cpu(ie->data.dir.indexed_file);
                        ntfs_attr_put_search_ctx(ctx);
                        unmap_mft_record(dir_ni);
-                       return mref;
+                       return ntfs_check_mref(mref);
                }
                /*
                 * For a case insensitive mount, we also perform a case
@@ -273,7 +280,7 @@ found_it:
                if (name) {
                        ntfs_attr_put_search_ctx(ctx);
                        unmap_mft_record(dir_ni);
-                       return name->mref;
+                       return ntfs_check_mref(name->mref);
                }
                ntfs_debug("Entry not found.");
                err = -ENOENT;
@@ -413,7 +420,7 @@ found_it2:
                        mref = le64_to_cpu(ie->data.dir.indexed_file);
                        kfree(kaddr);
                        iput(ia_vi);
-                       return mref;
+                       return ntfs_check_mref(mref);
                }
                /*
                 * For a case insensitive mount, we also perform a case
@@ -538,7 +545,7 @@ found_it2:
        if (name) {
                kfree(kaddr);
                iput(ia_vi);
-               return name->mref;
+               return ntfs_check_mref(name->mref);
        }
        ntfs_debug("Entry not found.");
        err = -ENOENT;