{"id":"CVE-2026-97437","state":"PUBLISHED","title":"ntfs3: fix out-of-bounds read in ntfs_dir_emit() and hdr_find_e()","description":"In the Linux kernel, the following vulnerability has been resolved:\n\nntfs3: fix out-of-bounds read in ntfs_dir_emit() and hdr_find_e()\n\nThe bounds check in ntfs_dir_emit() compares fname->name_len (a\ncharacter count) against e->size (a byte count) without accounting\nfor the 2-byte-per-character UTF-16LE encoding or the ATTR_FILE_NAME\nheader size:\n\n  if (fname->name_len + sizeof(struct NTFS_DE) > le16_to_cpu(e->size))\n\nThis computes: name_len + 16 > e_size\n\nThe correct check must account for the ATTR_FILE_NAME header (66 bytes\nbefore the name) and the UTF-16LE character size (2 bytes each):\n\n  sizeof(NTFS_DE) + offsetof(ATTR_FILE_NAME, name) +\n  name_len * sizeof(short) > e_size\n\nWhich computes: 16 + 66 + name_len * 2 > e_size\n\nThe correct calculation already exists as fname_full_size() in ntfs.h\nand is used in cmp_fnames(), namei.c, and fslog.c, but was not used\nin the readdir path.\n\nA crafted NTFS image with an index entry containing a small e->size\nbut large fname->name_len bypasses the current check, causing\nntfs_utf16_to_nls() to read past the entry boundary.\n\nAdditionally, add a key_size validation in hdr_find_e() to ensure the\ndeclared key_size does not exceed the available entry data, preventing\ncomparison functions from reading past entry boundaries on the lookup\npath.","publishedAt":"2026-09-24T16:03:50.105Z","updatedAt":"2026-10-03T10:58:22.091Z","severity":{"score":7.1,"label":"High","version":"3.1","vector":"CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:H","source":"Linux"},"assigner":"Linux","products":["Linux Linux"],"affected":[{"vendor":"Linux","product":"Linux","defaultStatus":"unaffected","versions":[{"version":"4342306f0f0d5ff4315a204d315c1b51b914fca5","status":"affected","lessThan":"d1f98938e437732c0ecdfc8ee451e12a072f6d07","versionType":"git"},{"version":"4342306f0f0d5ff4315a204d315c1b51b914fca5","status":"affected","lessThan":"0505f1e7bb5b981b6ed62d98b26ddce76142865d","versionType":"git"},{"version":"4342306f0f0d5ff4315a204d315c1b51b914fca5","status":"affected","lessThan":"2f7d0ec8c10dc7bf7a8c9a9cb169f9a4d1fac2ba","versionType":"git"},{"version":"4342306f0f0d5ff4315a204d315c1b51b914fca5","status":"affected","lessThan":"ed6da1abeec50db9060d714f03743fe0b63e4fe4","versionType":"git"},{"version":"4342306f0f0d5ff4315a204d315c1b51b914fca5","status":"affected","lessThan":"6a8149a20e46086c756c2a9202e377c0b649a0c3","versionType":"git"},{"version":"4342306f0f0d5ff4315a204d315c1b51b914fca5","status":"affected","lessThan":"aa1bdbb39f49c5bc9779316891c40005517842a5","versionType":"git"}],"repo":"https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git","programFiles":["fs/ntfs3/dir.c","fs/ntfs3/index.c"]},{"vendor":"Linux","product":"Linux","defaultStatus":"affected","versions":[{"version":"5.15","status":"affected"},{"version":"0","status":"unaffected","lessThan":"5.15","versionType":"semver"},{"version":"5.15.222","status":"unaffected","lessThanOrEqual":"5.15.*","versionType":"semver"},{"version":"6.1.189","status":"unaffected","lessThanOrEqual":"6.1.*","versionType":"semver"},{"version":"6.6.158","status":"unaffected","lessThanOrEqual":"6.6.*","versionType":"semver"},{"version":"6.12.111","status":"unaffected","lessThanOrEqual":"6.12.*","versionType":"semver"},{"version":"6.18.53","status":"unaffected","lessThanOrEqual":"6.18.*","versionType":"semver"},{"version":"7.2","status":"unaffected","lessThanOrEqual":"*","versionType":"original_commit_for_fix"}],"repo":"https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git","programFiles":["fs/ntfs3/dir.c","fs/ntfs3/index.c"]}],"references":["https://git.kernel.org/stable/c/d1f98938e437732c0ecdfc8ee451e12a072f6d07","https://git.kernel.org/stable/c/0505f1e7bb5b981b6ed62d98b26ddce76142865d","https://git.kernel.org/stable/c/2f7d0ec8c10dc7bf7a8c9a9cb169f9a4d1fac2ba","https://git.kernel.org/stable/c/ed6da1abeec50db9060d714f03743fe0b63e4fe4","https://git.kernel.org/stable/c/6a8149a20e46086c756c2a9202e377c0b649a0c3","https://git.kernel.org/stable/c/aa1bdbb39f49c5bc9779316891c40005517842a5"],"weaknesses":[],"ingestedAt":"2026-10-29T20:13:43.249Z","source":{"repository":"CVEProject/cvelistV5","path":"cves/2026/97xxx/CVE-2026-97437.json","commit":"556c9d3a8cd17e218bb8e452ba7cd619a384ff47"},"raw":{"dataType":"CVE_RECORD","dataVersion":"5.2","cveMetadata":{"cveId":"CVE-2026-97437","state":"PUBLISHED","datePublished":"2026-09-24T16:03:50.105Z","dateUpdated":"2026-10-03T10:58:22.091Z","assignerShortName":"Linux","assignerOrgId":"416baaa9-dc9f-4396-8d5f-8c081fb06d67","dateReserved":"2026-09-24T14:53:16.869Z"},"containers":{"cna":{"title":"ntfs3: fix out-of-bounds read in ntfs_dir_emit() and hdr_find_e()","descriptions":[{"lang":"en","value":"In the Linux kernel, the following vulnerability has been resolved:\n\nntfs3: fix out-of-bounds read in ntfs_dir_emit() and hdr_find_e()\n\nThe bounds check in ntfs_dir_emit() compares fname->name_len (a\ncharacter count) against e->size (a byte count) without accounting\nfor the 2-byte-per-character UTF-16LE encoding or the ATTR_FILE_NAME\nheader size:\n\n  if (fname->name_len + sizeof(struct NTFS_DE) > le16_to_cpu(e->size))\n\nThis computes: name_len + 16 > e_size\n\nThe correct check must account for the ATTR_FILE_NAME header (66 bytes\nbefore the name) and the UTF-16LE character size (2 bytes each):\n\n  sizeof(NTFS_DE) + offsetof(ATTR_FILE_NAME, name) +\n  name_len * sizeof(short) > e_size\n\nWhich computes: 16 + 66 + name_len * 2 > e_size\n\nThe correct calculation already exists as fname_full_size() in ntfs.h\nand is used in cmp_fnames(), namei.c, and fslog.c, but was not used\nin the readdir path.\n\nA crafted NTFS image with an index entry containing a small e->size\nbut large fname->name_len bypasses the current check, causing\nntfs_utf16_to_nls() to read past the entry boundary.\n\nAdditionally, add a key_size validation in hdr_find_e() to ensure the\ndeclared key_size does not exceed the available entry data, preventing\ncomparison functions from reading past entry boundaries on the lookup\npath."}],"affected":[{"vendor":"Linux","product":"Linux","defaultStatus":"unaffected","versions":[{"version":"4342306f0f0d5ff4315a204d315c1b51b914fca5","status":"affected","lessThan":"d1f98938e437732c0ecdfc8ee451e12a072f6d07","versionType":"git"},{"version":"4342306f0f0d5ff4315a204d315c1b51b914fca5","status":"affected","lessThan":"0505f1e7bb5b981b6ed62d98b26ddce76142865d","versionType":"git"},{"version":"4342306f0f0d5ff4315a204d315c1b51b914fca5","status":"affected","lessThan":"2f7d0ec8c10dc7bf7a8c9a9cb169f9a4d1fac2ba","versionType":"git"},{"version":"4342306f0f0d5ff4315a204d315c1b51b914fca5","status":"affected","lessThan":"ed6da1abeec50db9060d714f03743fe0b63e4fe4","versionType":"git"},{"version":"4342306f0f0d5ff4315a204d315c1b51b914fca5","status":"affected","lessThan":"6a8149a20e46086c756c2a9202e377c0b649a0c3","versionType":"git"},{"version":"4342306f0f0d5ff4315a204d315c1b51b914fca5","status":"affected","lessThan":"aa1bdbb39f49c5bc9779316891c40005517842a5","versionType":"git"}],"repo":"https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git","programFiles":["fs/ntfs3/dir.c","fs/ntfs3/index.c"]},{"vendor":"Linux","product":"Linux","defaultStatus":"affected","versions":[{"version":"5.15","status":"affected"},{"version":"0","status":"unaffected","lessThan":"5.15","versionType":"semver"},{"version":"5.15.222","status":"unaffected","lessThanOrEqual":"5.15.*","versionType":"semver"},{"version":"6.1.189","status":"unaffected","lessThanOrEqual":"6.1.*","versionType":"semver"},{"version":"6.6.158","status":"unaffected","lessThanOrEqual":"6.6.*","versionType":"semver"},{"version":"6.12.111","status":"unaffected","lessThanOrEqual":"6.12.*","versionType":"semver"},{"version":"6.18.53","status":"unaffected","lessThanOrEqual":"6.18.*","versionType":"semver"},{"version":"7.2","status":"unaffected","lessThanOrEqual":"*","versionType":"original_commit_for_fix"}],"repo":"https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git","programFiles":["fs/ntfs3/dir.c","fs/ntfs3/index.c"]}],"references":[{"url":"https://git.kernel.org/stable/c/d1f98938e437732c0ecdfc8ee451e12a072f6d07"},{"url":"https://git.kernel.org/stable/c/0505f1e7bb5b981b6ed62d98b26ddce76142865d"},{"url":"https://git.kernel.org/stable/c/2f7d0ec8c10dc7bf7a8c9a9cb169f9a4d1fac2ba"},{"url":"https://git.kernel.org/stable/c/ed6da1abeec50db9060d714f03743fe0b63e4fe4"},{"url":"https://git.kernel.org/stable/c/6a8149a20e46086c756c2a9202e377c0b649a0c3"},{"url":"https://git.kernel.org/stable/c/aa1bdbb39f49c5bc9779316891c40005517842a5"}],"metrics":[{"cvssV3_1":{"version":"3.1","vectorString":"CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:H","baseScore":7.1,"baseSeverity":"HIGH"},"scenarios":[{"lang":"en","value":"AV:L - The attacker-controlled bytes are on-disk NTFS_DE.size, ATTR_FILE_NAME.name_len and NTFS_DE.key_size. getdents64→iterate_dir→ntfs_readdir→ntfs_read_hdr→ntfs_dir_emit() and ntfs_lookup/ntfs_fill_super→ntfs_extend_init→dir_search_u→indx_find→hdr_find_e() consume those fields; no SMB, NFS, or TCP message carries them.\nAC:L - A crafted index entry with e->size >= name_len+sizeof(NTFS_DE) but smaller than sizeof(NTFS_DE)+offsetof(ATTR_FILE_NAME,name)+name_len*2 bypasses the old ntfs_dir_emit() check so ntfs_utf16_to_nls() over-reads on every readdir of that directory; the same image can set key_size > e->size-sizeof(NTFS_DE) so hdr_find_e() passes an oversized key to cmp_fnames(). No race.\nPR:N - Crafting the NTFS image needs no host account. ntfs_fs_type.fs_flags is only FS_REQUIRES_DEV|FS_ALLOW_IDMAP (no FS_USERNS_MOUNT), so mount_capable() requires init-namespace CAP_SYS_ADMIN; that mount is scored as UI:R, not attacker privilege. ntfs_dir_emit() and hdr_find_e() have no capable() gate after the volume is mounted.\nUI:R - The bad name_len and key_size are inert on-disk until a victim or automount helper mounts the image via path_mount→get_tree_bdev→ntfs_fill_super. That mount is the required user action; ntfs_extend_init() even calls dir_search_u()→hdr_find_e() during fill_super, and a subsequent getdents reaches ntfs_dir_emit().\nS:U - The over-read in ntfs_utf16_to_nls()/cmp_fnames() and any oops stay in the host kernel that mounted the volume. This is not a KVM/Xen guest-to-host escape or an IOMMU/DMA boundary bypass.\nC:H - ntfs_dir_emit() hands attacker-chosen fname->name_len (u8, up to 255 UTF-16 units) to ntfs_utf16_to_nls() after a check that ignores the 66-byte ATTR_FILE_NAME header and 2-byte encoding, so up to ~321 bytes past the NTFS_DE—and past indx_read()'s kmalloc(1<<index_bits) if the entry is at the buffer tail—are converted and dir_emit()'d into getdents. hdr_find_e() likewise lets cmp_fnames() read past that slab.\nI:N - ntfs_utf16_to_nls() writes only into the PATH_MAX buffer kmalloc'd by ntfs_readdir(); dir_emit()/filldir() then copy that name to the user dirent. hdr_find_e's cmp_fnames() returns only a comparison integer. Neither path is an out-of-bounds write, UAF, or control-flow hijack.\nA:H - indx_read() kmallocs 1<<index_bits (typically 4K) for the INDEX_BUFFER. An entry near the end with name_len=255, or key_size larger than the remaining payload, makes ntfs_utf16_to_nls() or fname_full_size() in cmp_fnames() read off that object, which can fault unmapped adjacent pages and oops the kernel."}]}],"providerMetadata":{"shortName":"Linux","orgId":"416baaa9-dc9f-4396-8d5f-8c081fb06d67","dateUpdated":"2026-10-03T10:58:22.091Z"},"cpeApplicability":[{"nodes":[{"operator":"OR","negate":false,"cpeMatch":[{"vulnerable":true,"criteria":"cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*","versionStartIncluding":"5.15","versionEndExcluding":"5.15.222"},{"vulnerable":true,"criteria":"cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*","versionStartIncluding":"5.15","versionEndExcluding":"6.1.189"},{"vulnerable":true,"criteria":"cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*","versionStartIncluding":"5.15","versionEndExcluding":"6.6.158"},{"vulnerable":true,"criteria":"cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*","versionStartIncluding":"5.15","versionEndExcluding":"6.12.111"},{"vulnerable":true,"criteria":"cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*","versionStartIncluding":"5.15","versionEndExcluding":"6.18.53"},{"vulnerable":true,"criteria":"cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*","versionStartIncluding":"5.15","versionEndExcluding":"7.2"}]}]}],"x_generator":{"engine":"bippy-1.2.0"}}}}}