* [PATCH AUTOSEL 6.18-5.15] fs/ntfs3: reserve NUL byte when converting UTF-16 names
[not found] <20261019135441.1420968-1-sashal@kernel.org>
@ 2026-10-19 13:48 ` Sasha Levin
2026-10-19 13:48 ` [PATCH AUTOSEL 6.18-5.15] fs/ntfs3: Fix memory leak in indx_find_sort() Sasha Levin
` (4 subsequent siblings)
5 siblings, 0 replies; 6+ messages in thread
From: Sasha Levin @ 2026-10-19 13:48 UTC (permalink / raw)
To: patches, stable
Cc: Kyle Zeng, Konstantin Komarov, Sasha Levin, ntfs3, linux-kernel
From: Kyle Zeng <kylebot@openai.com>
[ Upstream commit 4871fedaabbfd574ac0a075b80e75afdd532e11e ]
ntfs_utf16_to_nls() appends a trailing NUL to the converted output,
but it passes the caller-supplied size directly to the conversion loop.
For the UTF-8 path, utf16s_to_utf8s() can legitimately fill all
buf_len bytes and return buf_len, after which ntfs_utf16_to_nls()
writes the terminator one byte past the end of the destination buffer.
The same contract problem exists for the NLS path when a converted
character consumes the last available byte.
Reserve one byte for the terminator before doing either conversion.
The function continues to return the number of converted bytes,
excluding the NUL terminator.
Assisted-by: Codex:gpt-5.5
Signed-off-by: Kyle Zeng <kylebot@openai.com>
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
The local tree is **v7.3-rc4** (`7.3.0-rc4`). `ntfs_utf16_to_nls()` is
present here, and the bug is a real one-byte heap overflow on long
reparse/symlink conversion. Below is the full checklist.
===============================================================
PHASE 1: COMMIT MESSAGE FORENSICS
===============================================================
**Step 1.1: PARSE THE SUBJECT LINE**
Record: **[fs/ntfs3] [reserve] reserve one NUL byte when converting
UTF-16 names**
- Subsystem: `fs/ntfs3`
- Verb: “reserve” — a missing-safety-check fix (keep a terminator byte)
- Intent: stop `ntfs_utf16_to_nls()` from writing `'\0'` one byte past
the caller buffer
**Step 1.2: PARSE ALL COMMIT MESSAGE TAGS**
Record:
- `Assisted-by: Codex:gpt-5.5` — LLM-assisted; still needs code review
(done below)
- `Signed-off-by: Kyle Zeng <kylebot@openai.com>` — author
- `Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-
software.com>` — ntfs3 maintainer
- No `Fixes:`, `Reported-by:`, `Tested-by:`, `Reviewed-by:`, `Acked-
by:`, `Link:`, or `Cc: stable` (absence is expected for this review)
- Ignore any pipeline `Signed-off-by: Sasha Levin` / `[Upstream commit
...]` — none on this commit
**Step 1.3: ANALYZE THE COMMIT BODY TEXT**
Record:
- **Bug:** `ntfs_utf16_to_nls()` always stores a trailing NUL, but
passes the full caller `buf_len` into conversion.
- **UTF-8 path:** `utf16s_to_utf8s()` may write `buf_len` bytes and
return `buf_len`; then `buf[ret] = '\0'` is one past the end.
- **NLS path:** a converted character can consume the last byte; `*op =
'\0'` is then one past the end.
- **Fix:** reject `buf_len <= 0`; do `buf_len -= 1` before conversion;
still return converted length **excluding** NUL.
- **Symptom:** 1-byte heap buffer overflow (memory corruption / KASAN
slab-out-of-bounds write).
- **Versions in the message:** none.
**Step 1.4: DETECT HIDDEN BUG FIXES**
Record: Not hidden. It is an explicit off-by-one / OOB write fix, not
cleanup or a new feature.
===============================================================
PHASE 2: DIFF ANALYSIS - LINE BY LINE
===============================================================
**Step 2.1: INVENTORY THE CHANGES**
Record:
- File: `fs/ntfs3/dir.c` — **+5 / −0**
- Function: `ntfs_utf16_to_nls()`
- Scope: single-function, surgical
**Step 2.2: UNDERSTAND THE CODE FLOW CHANGE**
Record (pre-fix from `4871fedaabbfd^`):
```
ret = utf16s_to_utf8s(..., buf, buf_len);
buf[ret] = '\0';
return ret;
```
and NLS loop using full `buf_len`, then `*op = '\0'`.
After: if `buf_len <= 0` → `-EINVAL`; else `buf_len -= 1`; conversion
and NUL write use the reduced size. Return value is still converted
bytes without the terminator.
**Step 2.3: IDENTIFY THE BUG MECHANISM**
Record: **Memory safety — 1-byte out-of-bounds write.**
Verified `utf16s_to_utf8s()` in `fs/nls/nls_base.c`: it loops `while
(inlen > 0 && maxout > 0)` and for ASCII does `*op++ = ...; maxout--;`.
It can write exactly `maxout` bytes and return that count. `buf[ret] =
'\0'` is then OOB.
NLS: `uni2char()` is called only when `buf_len >= NLS_MAX_CHARSET_SIZE`
(6). If `charlen == buf_len`, remaining space becomes 0 and `*op = '\0'`
is OOB. Same class of contract bug.
**Step 2.4: ASSESS THE FIX QUALITY**
Record:
- Correct and minimal: reserve the byte the function already uses for
NUL.
- Return contract unchanged (length without NUL) — matches
`ntfs_dir_emit()`, `ntfs_readlink_hlp()`, ADS listing.
- Regression risk: **low**. Worst case is truncating one extra byte on a
max-length conversion instead of overflowing.
- `buf_len <= 0` → `-EINVAL` is defensive; current callers pass
`PATH_MAX` or `PAGE_SIZE`.
- No API/ABI/feature change.
===============================================================
PHASE 3: GIT HISTORY INVESTIGATION
===============================================================
**Step 3.1: BLAME THE CHANGED LINES**
Record:
- Unconditional `buf[ret] = '\0'` / `*op = '\0'` from
**`4342306f0f0d5`** (“fs/ntfs3: Add file operations and
implementation”, 2021-08-13).
- Contained in **v5.15-rc1**.
- UTF-8 call adjusted in `2c69078851b3d` (“Rework ntfs_utf16_to_nls”,
2021-10) but still passed full `buf_len`.
- Bug is old (since ntfs3 landed), not last-month code.
**Step 3.2: FOLLOW THE FIXES: TAG**
Record: No `Fixes:` tag. Buggy code is the original function body from
5.15, present in this tree’s ntfs3.
**Step 3.3: CHECK FILE HISTORY FOR RELATED CHANGES**
Record:
- Same-class NUL bug: `a6cd43fe9b083` (“terminate the cached volume
label after UTF-8 conversion”) — `utf16s_to_utf8s()` does not NUL-
terminate; filling the buffer overruns `%s`.
- Related bounds: `aa1bdbb39f49c` (OOB **read** of names in
`ntfs_dir_emit`) — different bug.
- Later `be310476e8868` (ADS) adds a third caller; not a prerequisite.
- Standalone 5-line fix, not patch X/Y.
**Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS**
Record: Only this ntfs3 commit from Kyle Zeng. Applied by **Konstantin
Komarov** (ntfs3 maintainer) in the `ntfs3_for_7.3` pull
(`dc83d18cdd904`).
**Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS**
Record: None. Uses existing `utf16s_to_utf8s()` / NLS loop. Applies on
top of the long-standing function.
===============================================================
PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
===============================================================
**Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION**
Record:
- `b4 dig -c 4871fedaabbfd` →
https://patch.msgid.link/20260611213331.16763-1-kylebot@openai.com
- Only **v1** (`b4 dig -a`); that version was applied.
- Lore HTTP fetch returned 403; full thread saved via `b4 dig -m
/tmp/ntfs3-nul.mbox`.
- Maintainer (23 Jul 2026): “Your patch was applied, thank you.” **No
NAK.**
- XIAO WU replied about a **different** remount/`sbi->options` UAF
(getdents vs remount). That is not this overflow and is not caused by
this patch. The nls load is unchanged.
**Step 4.2: CHECK WHO REVIEWED THE PATCH**
Record (`b4 dig -w`): To `ntfs3@lists.linux.dev`; Cc maintainer
Konstantin Komarov, LKML, `outbounddisclosures@openai.com`. Maintainer
applied it. No extra `Reviewed-by`.
**Step 4.3: SEARCH FOR THE BUG REPORT**
Record: No syzbot/bugzilla/`Reported-by`. Bug is from code inspection.
Reachability is from callers (Phase 5), not a public crash report.
**Step 4.4: CHECK FOR RELATED PATCHES AND SERIES**
Record: Standalone v1. Not part of a multi-patch series.
**Step 4.5: CHECK STABLE MAILING LIST HISTORY**
Record: lore.kernel.org/stable search via WebFetch → 403. No stable-list
discussion in the saved mbox. **UNVERIFIED:** whether AUTOSEL already
queued it for some -stable series (irrelevant to this tree’s technical
decision).
===============================================================
PHASE 5: CODE SEMANTIC ANALYSIS
===============================================================
**Step 5.1: IDENTIFY KEY FUNCTIONS IN THE DIFF**
Record: `ntfs_utf16_to_nls()` only.
**Step 5.2: TRACE CALLERS**
Record (this tree):
1. **`ntfs_dir_emit()`** (`fs/ntfs3/dir.c`) — readdir/`getdents`. Buffer
`kmalloc(PATH_MAX)` (`PATH_MAX=4096`). `static_assert(NTFS_NAME_LEN *
4 < PATH_MAX)` (`NTFS_NAME_LEN=255` → max 1020 UTF-8 bytes). **This
caller cannot fill PATH_MAX**, so the NUL OOB does not fire on normal
filenames.
2. **`ntfs_readlink_hlp()` / `ntfs_get_link()`** (`fs/ntfs3/inode.c`) —
`readlink`/`get_link`. Buffer `kmalloc(PAGE_SIZE)` passed as
`buflen`. Reparse payload allowed up to `sbi->reparse.max_size`
(comment **16K**, from `$AttrDef`). A UTF-16 path of ~4096 ASCII
units fills the page; then `buf[ret]='\0'` and the extra
`buffer[err]=0` in `ntfs_readlink_hlp()` are **one past the heap
object**.
3. **ADS listing in `frecord.c`** — `PAGE_SIZE` and `name_len` is `u8`
(max 255). Same as filenames; **does not fill PAGE_SIZE**. Added
after this fix; not required for the bug.
**Step 5.3: TRACE CALLEES**
Record: `utf16s_to_utf8s()` / `utf32_to_utf8()`; NLS `uni2char()`.
Conversion, then a terminator store. No new locks/allocs.
**Step 5.4: FOLLOW THE CALL CHAIN**
Record: Userspace **`readlink(2)`** on an NTFS symlink/junction/reparse
target. Unprivileged if the volume is mounted. Also reachable from a
**crafted NTFS image** (USB, etc.). Readdir is a common path but, given
PATH_MAX vs 255-char names, not the overflow trigger.
**Step 5.5: SEARCH FOR SIMILAR PATTERNS**
Record: Volume label (`a6cd43fe9b083`) is the same `utf16s_to_utf8s()` +
missing terminator class. Confirms the contract bug is real in ntfs3.
===============================================================
PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE
===============================================================
**Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?**
Record:
- `git describe HEAD` → **`v7.3-rc4-27-gf0100363d8c37`**
- `make kernelversion` / Makefile → **7.3.0-rc4**
- `ntfs_utf16_to_nls()` exists in `fs/ntfs3/dir.c`; callers exist.
- Bug introduced **v5.15**, well before this branch.
- `git merge-base --is-ancestor 4871fedaabbfd HEAD` → commit is already
an ancestor (current file already has `buf_len -= 1`). That is **not**
used as “already selected for stable.”
- Verdict is: this tree’s ntfs3 **has** the function and needed the fix.
**Step 6.2: CHECK FOR BACKPORT COMPLICATIONS**
Record: Clean 5-line insert after `static_assert`. Surrounding function
matches the pre-fix form from 5.15-era ntfs3. **Expected apply: clean**
on a tree that still has the unfixed function.
**Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE**
Record: No other commit fixes this terminator OOB in
`ntfs_utf16_to_nls()`. Label NUL fix is a sibling pattern, not a
substitute.
===============================================================
PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
===============================================================
**Step 7.1: IDENTIFY THE SUBSYSTEM AND ITS CRITICALITY**
Record: **fs/ntfs3** — **IMPORTANT** (in-tree filesystem, not staging;
`CONFIG_NTFS3_FS`). Not core VFS/mm, but used on removable NTFS volumes.
**Step 7.2: ASSESS SUBSYSTEM ACTIVITY**
Record: Active (7.3 pull has many bounds/UAF/leak fixes). This
particular helper has been stable since 5.15.
===============================================================
PHASE 8: IMPACT AND RISK ASSESSMENT
===============================================================
**Step 8.1: DETERMINE WHO IS AFFECTED**
Record: **Filesystem-specific / config-specific** — `CONFIG_NTFS3_FS`
users, especially `readlink` on reparse/symlink. Default charset is
UTF-8 (`nls` NULL), which is the clearer overflow path.
**Step 8.2: DETERMINE THE TRIGGER CONDITIONS**
Record:
- Trigger: convert a UTF-16 string whose UTF-8 (or NLS) form uses the
**entire** destination, then write NUL.
- **Common readdir:** unlikely (255-char names vs PATH_MAX).
- **readlink of a long reparse target:** realistic on crafted or unusual
NTFS images; unprivileged if the fs is mounted.
- Not a race.
**Step 8.3: DETERMINE THE FAILURE MODE SEVERITY**
Record: **1-byte heap overflow** past `kmalloc(PAGE_SIZE)` in
`ntfs_get_link()`. **Severity: HIGH** (memory corruption; crash and
possible security impact). Not a panic on every boot, but it is a real
memory-safety bug.
**Step 8.4: CALCULATE RISK-BENEFIT RATIO**
Record:
- **Benefit: HIGH** — closes a heap OOB on ntfs3 `readlink`, cheap and
correct.
- **Risk: VERY LOW** — 5 lines, local, return contract unchanged, slight
extra truncation vs overflow.
- **Ratio: strongly favors applying.**
===============================================================
PHASE 9: FINAL SYNTHESIS
===============================================================
**Step 9.1: COMPILE THE EVIDENCE**
FOR:
- Real off-by-one write: conversion may fill `buf_len`, then a NUL is
stored at `buf[buf_len]`.
- Confirmed in `utf16s_to_utf8s()`; NLS path has the same contract hole.
- Reachable from `ntfs_get_link()` (`readlink`, `PAGE_SIZE`, reparse up
to ~16K).
- Small, obviously correct; return value still excludes NUL.
- Maintainer applied v1; no NAK of the overflow fix.
- Same `utf16s_to_utf8s()` terminator class already fixed for volume
labels.
- Present in this tree’s ntfs3 since 5.15; no missing helpers.
AGAINST:
- No syzbot/`Reported-by`/reproducer in the message.
- Readdir/`PATH_MAX` cannot hit it for legal 255-char names.
- LLM-assisted; one list reply was about an unrelated remount UAF.
- No `Fixes:`/`Cc: stable` (not a negative for this review).
UNRESOLVED:
- Stable-list AUTOSEL status (lore/stable HTTP 403).
- Exact on-disk `$AttrDef` `$REPARSE_POINT` max on every volume (code
comments 16K; crafted images can still supply a long path).
**Step 9.2: APPLY THE STABLE RULES CHECKLIST**
1. Obviously correct and tested? **PASS** — contract is clear;
maintainer merged it. No extra Tested-by, but the code change is
verifiable.
2. Fixes a real bug that affects users? **PASS** — heap OOB on
`readlink` of a long NTFS reparse target.
3. Important (crash/security/corruption/deadlock)? **PASS** — HIGH:
1-byte heap overflow / memory corruption.
4. Small and contained? **PASS** — +5 lines, one function.
5. No new features or APIs? **PASS**
6. Can apply to the local tree? **PASS** — function and callers exist;
patch is a trivial insert.
**Step 9.3: CHECK FOR EXCEPTION CATEGORIES**
Record: None (not an ID/quirk/DT/build/docs exception). It is a normal
memory-safety fix.
**Step 9.4: MAKE YOUR DECISION**
This tree is **7.3.0-rc4** with in-tree ntfs3. The helper has written a
NUL past a full conversion buffer since v5.15. On this tree that is hit
by `ntfs_get_link()` with a `PAGE_SIZE` buffer, not by readdir’s
oversized `PATH_MAX` name buffer. The fix is five lines, preserves the
return contract, and is the right way to implement “convert then
terminate.” Benefit vs risk favors applying it here.
### What it solves for this tree
`ntfs_utf16_to_nls()` treated `buf_len` as conversion space **and**
still stored a terminator. `utf16s_to_utf8s()` is allowed to use every
byte. `ntfs_get_link()` then NUL-terminates again at `buffer[err]`. A
long symlink/junction on a mounted NTFS image can corrupt one heap byte.
That is a real, important bug, not a style change.
### Stable rules
Obviously correct, small, no new API, no extra dependencies. Meets the
documented stable criteria for this checkout.
### Risk vs benefit
Very low regression risk; high benefit on a memory-safety path used by
`readlink`.
### Concerns
- Filename readdir is not the realistic trigger (`NTFS_NAME_LEN * 4 <
PATH_MAX`).
- List discussion mixed in an unrelated remount UAF; this patch does not
fix or worsen that.
- No fuzzer report; still verified from the conversion contract and
callers in this tree.
Verification:
- [Phase 1] Subject/tags: overflow + reserve NUL; SOB Kyle Zeng +
Konstantin Komarov; Assisted-by Codex; no Fixes/Reported-by/Cc stable
- [Phase 2] Diff: +5 in `ntfs_utf16_to_nls()`: `buf_len <= 0` →
`-EINVAL`, then `buf_len -= 1`
- [Phase 2] `utf16s_to_utf8s()` (`fs/nls/nls_base.c:189-242`) can return
`maxout`; pre-fix `buf[ret] = '\0'` is OOB
- [Phase 3] Blame: `4342306f0f0d5` (v5.15-rc1); rework `2c69078851b3d`
did not reserve NUL
- [Phase 3] `git merge-base --is-ancestor 4871fedaabbfd HEAD` — commit
is in this history; not used as circular “already selected”
- [Phase 3] No prerequisites; later ADS caller is independent
- [Phase 4] `b4 dig -c 4871fedaabbfd` →
patch.msgid.link/20260611213331.16763-1-kylebot@openai.com; v1 only;
maintainer applied; XIAO WU UAF is a different bug
- [Phase 4] WebFetch lore/stable: 403; thread recovered via `b4 dig -m`
- [Phase 5] Callers: `ntfs_dir_emit` (PATH_MAX, cannot fill),
`ntfs_readlink_hlp`/`ntfs_get_link` (PAGE_SIZE, can fill), ADS
`PAGE_SIZE` (255-char names)
- [Phase 6] `git describe HEAD` = v7.3-rc4-27-gf0100363d8c37;
`kernelversion` 7.3.0-rc4; ntfs3 and callers present
- [Phase 7] fs/ntfs3, in-tree, not staging
- [Phase 8] Failure: 1-byte heap write past `kmalloc(PAGE_SIZE)` on
`readlink`; HIGH
- UNVERIFIED: AUTOSEL/stable-list queue status (HTTP 403)
**YES**
fs/ntfs3/dir.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/fs/ntfs3/dir.c b/fs/ntfs3/dir.c
index 6e1d2ad8c12ea..6d588efaf9fdf 100644
--- a/fs/ntfs3/dir.c
+++ b/fs/ntfs3/dir.c
@@ -24,6 +24,11 @@ int ntfs_utf16_to_nls(struct ntfs_sb_info *sbi, const __le16 *name, u32 len,
static_assert(sizeof(wchar_t) == sizeof(__le16));
+ if (buf_len <= 0)
+ return -EINVAL;
+
+ buf_len -= 1;
+
if (!nls) {
/* UTF-16 -> UTF-8 */
ret = utf16s_to_utf8s((wchar_t *)name, len, UTF16_LITTLE_ENDIAN,
--
2.53.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH AUTOSEL 6.18-5.15] fs/ntfs3: Fix memory leak in indx_find_sort()
[not found] <20261019135441.1420968-1-sashal@kernel.org>
2026-10-19 13:48 ` [PATCH AUTOSEL 6.18-5.15] fs/ntfs3: reserve NUL byte when converting UTF-16 names Sasha Levin
@ 2026-10-19 13:48 ` Sasha Levin
2026-10-19 13:48 ` [PATCH AUTOSEL 6.18-5.15] fs/ntfs3: load ATTR_BITMAP run extents from $MFT extension records Sasha Levin
` (3 subsequent siblings)
5 siblings, 0 replies; 6+ messages in thread
From: Sasha Levin @ 2026-10-19 13:48 UTC (permalink / raw)
To: patches, stable; +Cc: Konstantin Komarov, Sasha Levin, ntfs3, linux-kernel
From: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
[ Upstream commit 194491be54e1c9e4d29d3ee777b05ff031c4b670 ]
When popping a level from the index lookup stack, indx_find_sort() frees
the struct indx_node but not the index buffer it owns. Every call that
descends and then pops a level leaks that allocation.
Free n->index before freeing the node itself.
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
I have enough to decide: this is a one-line leak fix in
`indx_find_sort()`, the buggy code is in this 7.3-rc4 tree, and it meets
the stable rules.
===============================================================
PHASE 1: COMMIT MESSAGE FORENSICS
===============================================================
**Step 1.1: PARSE THE SUBJECT LINE**
Record: **[fs/ntfs3] [fix] memory leak in `indx_find_sort()`** —
subsystem `fs/ntfs3`, action verb **fix**, claimed intent is to stop
leaking the index buffer when a lookup level is popped.
**Step 1.2: PARSE ALL COMMIT MESSAGE TAGS**
Commit `194491be54e1c9e4d29d3ee777b05ff031c4b670` (Author: Konstantin
Komarov, 2026-07-30):
- **Fixes:** none (expected for this review)
- **Reported-by:** none
- **Tested-by:** none
- **Reviewed-by:** none
- **Acked-by:** none
- **Link:** none in the commit message
- **Cc: stable:** none (expected)
- **Signed-off-by:** Konstantin Komarov \<almaz.alexandrovich@paragon-
software.com\> (author/maintainer)
No syzbot, no multi-user reports, no explicit stable nomination. Author
is the NTFS3 maintainer.
**Step 1.3: ANALYZE THE COMMIT BODY TEXT**
Record:
- **Bug:** When popping a level from the index lookup stack,
`indx_find_sort()` frees `struct indx_node` but not the index buffer
it owns (`n->index`).
- **Symptom:** Every call that descends into a child index block and
later pops that level leaks that allocation (typically a 4 KiB
`kmalloc` of `INDEX_BUFFER`).
- **Failure mode:** kernel memory leak on NTFS3 `$SDH` index walks.
- **Version info:** none in the message.
- **Root cause (author):** `kfree(n)` without `kfree(n->index)`.
- **Fix:** free `n->index` before freeing the node.
**Step 1.4: DETECT HIDDEN BUG FIXES**
Record: Not disguised. Subject and body state a leak fix. It is a
classic missing-`kfree` resource-leak fix, not cleanup-only.
===============================================================
PHASE 2: DIFF ANALYSIS - LINE BY LINE
===============================================================
**Step 2.1: INVENTORY THE CHANGES**
Record:
- File: `fs/ntfs3/index.c` — **+1 / −0**
- Function: `indx_find_sort()`
- Scope: **single-file surgical fix** (one line in the `pop_level` path)
**Step 2.2: UNDERSTAND THE CODE FLOW CHANGE**
Record (before → after):
- Before: `fnd_pop(fnd); kfree(n);` — node struct freed; `n->index` (and
buffer heads in `n->nb`) left allocated.
- After: `fnd_pop(fnd); kfree(n->index); kfree(n);` — index buffer and
node struct freed.
- Path: **normal** pop-level path when the current directory entry is
the last in that index block and the walk moves to the parent. Not
init-only.
**Step 2.3: IDENTIFY THE BUG MECHANISM**
Record: **[Memory leak / resource leak]**
- `indx_read()` / `indx_read_ra()` allocates `struct indx_node` and
`in->index` (`kmalloc(bytes, GFP_NOFS)` where `bytes = 1u <<
indx->index_bits`, typically 4096).
- Correct teardown is `put_indx_node()`: `kfree(in->index);
nb_put(&in->nb); kfree(in);`.
- Sibling `indx_find_raw()` already does `fnd_pop()` +
`put_indx_node(n)`.
- `indx_find_sort()` used `kfree(n)` only. This patch adds
`kfree(n->index)` on the pop path.
- Mechanism: missing free of owned `kmalloc` buffer.
Note (verified, not a reason to reject): the patch does **not** call
`nb_put(&n->nb)`, so buffer_head refs can still leak on this path. Two
other `kfree(n)` sites in the same function (invalid-entry error paths
at the `de_has_vcn_ex` loop) are also unchanged.
**Step 2.4: ASSESS THE FIX QUALITY**
Record:
- Obviously correct for the stated leak: `kfree(n->index)` matches the
first action of `put_indx_node()`; `kfree(NULL)` is safe; `fnd_pop()`
NULLs the stack slot so later `fnd_clear()`/`put_indx_node()` will not
double-free.
- Minimal: one line, no unrelated edits, no API change.
- Regression risk: **very low**. Does not change lookup results,
locking, or on-disk layout.
- Residual risk: incomplete vs `put_indx_node()` (BH leak remains). That
is an unfixed sibling leak, not a regression introduced by this line.
===============================================================
PHASE 3: GIT HISTORY INVESTIGATION
===============================================================
**Step 3.1: BLAME THE CHANGED LINES**
Record:
- Pop-level `kfree(n)` / `ntfs_free(n)` present since
**`82cae269cfa95`** (“fs/ntfs3: Add initialization of super block”,
2021-08-13) — NTFS3 introduction.
- `ntfs_free(n)` → `kfree(n)` in **`195c52bdd5d5e`** (“Do not use driver
own alloc wrappers”, 2021-08-24); `ntfs_free` was just `kfree`, so the
leak is original, not introduced by that conversion.
- This leak has existed for the entire life of NTFS3 in mainline (~5.15
onward).
**Step 3.2: FOLLOW THE FIXES: TAG**
Record: No `Fixes:` tag. Buggy code is the original `indx_find_sort()`
implementation in `82cae269cfa95`, which **is an ancestor of HEAD**.
**Step 3.3: CHECK FILE HISTORY FOR RELATED CHANGES**
Record:
- Recent `fs/ntfs3/index.c` work is mostly bounds checks and cosmetics.
- Related leak: `87ac077d6ea86` “ntfs3: fix memory leak in
indx_create_allocate()” — different function.
- No later commit after `194491be54e1c` changes this site (`git log
194491be54e1c..HEAD -- fs/ntfs3/index.c` is empty).
- Standalone 1-line patch, not “X/Y” of a series.
**Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS**
Record: Konstantin Komarov is the NTFS3 maintainer (Paragon). Many
recent NTFS3 commits are his. Weight: high.
**Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS**
Record: None. The patch only uses existing `kfree`, `fnd_pop`, and
`n->index`. Those exist in this tree. **Can apply standalone.**
===============================================================
PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
===============================================================
**Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION**
Record:
- `b4 dig -c 194491be54e1c` → https://patch.msgid.link/20260724111443.14
728-1-almaz.alexandrovich@paragon-software.com
- `b4 dig -a`: single revision **v1** only (2026-07-24). Committed
version matches v1.
- lore.kernel.org fetch returned 403; patch text confirmed via
Openwall/IU mirrors. No replies found on those archives (no NAK, no
Cc: stable in-thread).
- Earlier independent patch (Jan 2026) from Jiasheng Jiang: “[PATCH v2]
fs/ntfs3: Fix memory and resource leak in indx_find_sort” replacing
**all three** `kfree(n)` with `put_indx_node(n)` and adding `Fixes:
82cae269cfa9`. That fuller patch was **not** merged; the maintainer
later landed this narrower 1-line version.
**Step 4.2: CHECK WHO REVIEWED THE PATCH**
Record (`b4 dig -w`): To/Cc: Konstantin Komarov,
`ntfs3@lists.linux.dev`, `linux-kernel@vger.kernel.org`, `linux-
fsdevel@vger.kernel.org`. No extra reviewer SOB on the commit.
Maintainer self-applied.
**Step 4.3: SEARCH FOR THE BUG REPORT**
Record: No `Reported-by` / bugzilla / syzbot. Bug established from code
(missing free vs `put_indx_node` / `indx_find_raw`). User-report count:
**unverified / none found**.
**Step 4.4: CHECK FOR RELATED PATCHES AND SERIES**
Record: Jiang’s Jan 2026 patch is the more complete form of the same
fix. This commit is a subset (pop path `n->index` only). No series
dependency for applying this one line.
**Step 4.5: CHECK STABLE MAILING LIST HISTORY**
Record: lore.kernel.org/stable search was 403; web search did not turn
up a stable-list thread for this subject. **No verified stable-list NAK
or prior selection discussion.**
===============================================================
PHASE 5: CODE SEMANTIC ANALYSIS
===============================================================
**Step 5.1: IDENTIFY KEY FUNCTIONS IN THE DIFF**
Record: `indx_find_sort()` only.
**Step 5.2: TRACE CALLERS**
Record: Only caller in this tree is `ntfs_insert_security()` in
`fs/ntfs3/fsntfs.c` (SDH index walk when inserting a security
descriptor). That is called from:
- `inode.c` file/inode create when a new default/dir security id must be
stored
- `xattr.c` when setting a security descriptor xattr
Not interrupt context. Process context, under `ni->ni_lock`. Finder is
released with `fnd_put()` → `fnd_clear()` → `put_indx_node()` for
**remaining** stack nodes; popped nodes are supposed to be freed in
`indx_find_sort` itself.
**Step 5.3: TRACE CALLEES**
Record: `fnd_pop`, `kfree`, `indx_read`/`hdr_first_de`/`de_is_last` on
the surrounding path. `indx_read_ra` allocates node + index buffer +
buffer_heads.
**Step 5.4: FOLLOW THE CALL CHAIN**
Record: Userspace NTFS3 create/`setxattr` → `ntfs_insert_security` →
`indx_find` then loop `indx_find_sort`. **Reachable from userspace** on
a mounted ntfs3 volume. Not every I/O; triggered when inserting (or
searching duplicate) security descriptors in `$Secure::$SDH`. If the SDH
B-tree is deeper than root, pop_level runs and leaked before this fix.
**Step 5.5: SEARCH FOR SIMILAR PATTERNS**
Record: Same function still has `kfree(n)` without `kfree(n->index)` on
two **error** paths. `indx_find_raw` already uses `put_indx_node`.
Pattern is systematic in `indx_find_sort`, only partly fixed here.
===============================================================
PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE
===============================================================
**Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?**
Record:
- Local tree: **`v7.3-rc4-27-gf0100363d8c37`**, `make kernelversion` =
**7.3.0-rc4**.
- `fs/ntfs3/index.c` `indx_find_sort()` exists. Pre-image is `fnd_pop` +
`kfree(n)` without freeing `n->index`.
- Bug introduced with NTFS3 in **`82cae269cfa95` (2021)**, present in
this tree (`git merge-base --is-ancestor 82cae269cfa95 HEAD`
succeeded).
- This is not “new code after this branch point.”
**Step 6.2: CHECK FOR BACKPORT COMPLICATIONS**
Record: **Clean apply.** Surrounding function text is the original
structure; the hunk is one added line. No conflicting refactor of
`indx_find_sort` in this tree. `put_indx_node()` already exists if a
slightly richer backport were used, but this exact diff applies as-is.
**Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE**
Record: No earlier alternative (Jiang `put_indx_node`) in this history.
This commit **is** the fix that landed (`ntfs3_for_7.3` merge
`dc83d18cdd904`). No competing fix for the same `kfree(n)` pop site.
===============================================================
PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
===============================================================
**Step 7.1: IDENTIFY THE SUBSYSTEM AND ITS CRITICALITY**
Record: **[fs/ntfs3] [IMPORTANT]** — real RW filesystem
(CONFIG_NTFS3_FS), not staging. Not core VFS/mm, but used on Windows
volumes, dual-boot, and some appliances. Leak is in metadata index walk
for `$Secure`.
**Step 7.2: ASSESS SUBSYSTEM ACTIVITY**
Record: Active (many 7.3 NTFS3 fixes). The leak itself is old (2021),
not a bug in brand-new code.
===============================================================
PHASE 8: IMPACT AND RISK ASSESSMENT
===============================================================
**Step 8.1: DETERMINE WHO IS AFFECTED**
Record: **filesystem-specific / config-specific** — `CONFIG_NTFS3_FS`
users who insert security descriptors (file create with new/default SD,
security xattr). Not universal.
**Step 8.2: DETERMINE THE TRIGGER CONDITIONS**
Record:
- Trigger: `indx_find_sort()` after a descent into an index allocation
block, then last-entry pop.
- How common: not every syscall; **per unique-SD insert / SDH hash-chain
walk**, not a once-per-boot init-only leak. Repeated unique ACLs leak
repeatedly.
- Unprivileged users: if they can create files or set security xattrs on
ntfs3, yes. Typical create after `def_security_id` is cached may not
re-enter insert; still reachable.
**Step 8.3: DETERMINE THE FAILURE MODE SEVERITY**
Record: **[kernel memory leak of index buffers (and remaining BH refs)]
[HIGH for the kmalloc leak on a live FS path; not panic/corruption].**
Unbounded across many unique SD inserts; can contribute to memory
pressure. Not a crash or data-corruption bug.
**Step 8.4: CALCULATE RISK-BENEFIT RATIO**
Record:
- **Benefit:** medium-high for ntfs3 users — stops a real leak on a used
lookup path; 4 KiB+ per popped level.
- **Risk:** very low — 1 line, same pattern as `put_indx_node`’s first
free, no lock/API change.
- **Ratio:** strongly in favor of taking the fix.
===============================================================
PHASE 9: FINAL SYNTHESIS
===============================================================
**Step 9.1: COMPILE THE EVIDENCE**
FOR:
- Real leak: `kfree(n)` drops the node without freeing `n->index`
allocated in `indx_read_ra()`.
- Normal pop path, not style-only.
- 1 line, obviously correct, maintainer-authored.
- Code and bug exist in this 7.3-rc4 tree since NTFS3 was added.
- Applies cleanly; no prerequisites.
- Same class as many stable leak fixes; sibling `indx_find_raw` already
frees via `put_indx_node()`.
- Reachable from userspace ntfs3 create/xattr.
AGAINST:
- Not a crash, deadlock, or corruption issue.
- Incomplete: no `nb_put()`, two error-path `kfree(n)` sites remain.
- Single caller (`ntfs_insert_security`), not a hot readdir path.
- No syzbot/user `Reported-by`, no in-commit tests.
UNRESOLVED:
- Could not fetch lore.kernel.org (403) or confirm stable-list
discussion.
- No public reply thread found on mirrors for the July v1 mail.
**Step 9.2: APPLY THE STABLE RULES CHECKLIST**
1. Obviously correct and tested? **PASS** — correctness is visible from
`put_indx_node()` / `indx_find_raw()`. Testing is only implied by
maintainer merge, not a Tested-by tag.
2. Fixes a real bug that affects users? **PASS** — leaked kernel
allocations on ntfs3 SD insert/lookup.
3. Important issue (crash, security, corruption, deadlock)? **PASS** —
memory leak on a live FS path (stable routinely takes these). Not
CRITICAL severity, but it is a real resource leak, not cosmetic.
4. Small and contained? **PASS** — +1 line, one function.
5. No new features or APIs? **PASS**.
6. Can apply to the local tree? **PASS** — context matches; ntfs3 and
`indx_find_sort()` are present.
**Step 9.3: CHECK FOR EXCEPTION CATEGORIES**
Record: Not a device-ID/quirk/DT/build/docs exception. It is a normal
leak fix.
**Step 9.4: MAKE YOUR DECISION**
This tree is **7.3.0-rc4**. The leak exists in `indx_find_sort()` here
and has since NTFS3 landed. The patch is a one-line `kfree(n->index)` on
pop, matching the node’s ownership. Residual BH/error-path leaks do not
make this line wrong or risky. Benefit outweighs risk.
===============================================================
What problem this solves for this tree
===============================================================
`indx_find_sort()` walks the NTFS `$SDH` B-tree. After `indx_read()`
fills a child `indx_node`, popping that level used to `kfree` only the
node object. The owned index buffer stayed allocated for every descent-
then-pop. NTFS3 users inserting security descriptors (file create /
security xattr) leak that memory. This commit frees `n->index` first,
which is the correct teardown for that allocation.
It meets stable rules: obviously correct, real leak, small, no new API,
applies here. Risk is a single `kfree` on a pointer the node exclusively
owns after `fnd_pop()`.
Concerns: the fuller `put_indx_node()` replacement was proposed earlier
and would also drop buffer heads and fix two error paths; this commit is
a partial fix. That is acceptable for stable — it still plugs the main
pop-path kmalloc leak without depending on other commits.
===============================================================
Verification
===============================================================
- [Phase 1] Parsed commit `194491be54e1c`: subject/body leak fix; tags =
author SOB only; no Fixes/Reported-by/Cc: stable.
- [Phase 2] Diff: +1 line `kfree(n->index)` before `kfree(n)` in
`indx_find_sort()` pop_level; confirmed `put_indx_node()` does
`kfree(in->index); nb_put(); kfree(in)`.
- [Phase 2] Confirmed `indx_read_ra()` `kmalloc`s `ib` and assigns
`in->index = ib`.
- [Phase 2] Confirmed `indx_find_raw()` uses `put_indx_node(n)` after
`fnd_pop`.
- [Phase 3] `git blame`: pop path from `82cae269cfa95` (2021);
`kfree(n)` from `195c52bdd5d5e`; this line from `194491be54e1c`.
- [Phase 3] `git merge-base --is-ancestor 82cae269cfa95 HEAD` and
`194491be54e1c HEAD`: both true.
- [Phase 3] `git log 194491be54e1c..HEAD -- fs/ntfs3/index.c`: no later
change to this file.
- [Phase 3] No `Fixes:` tag to follow.
- [Phase 4] `b4 dig -c 194491be54e1c`: lore msgid
`20260724111443.14728-1-almaz.alexandrovich@paragon-software.com`;
`-a` v1 only; `-w` ntfs3/fsdevel/lkml.
- [Phase 4] Openwall/IU mirrors: patch text matches commit; no replies
found.
- [Phase 4] Found unmerged Jan 2026 Jiasheng Jiang `put_indx_node` patch
(lkml.iu.edu / gnuweeb).
- [Phase 4] lore.kernel.org WebFetch: 403. Stable-list hit:
**UNVERIFIED**.
- [Phase 5] `git grep indx_find_sort`: only `ntfs_insert_security` +
declaration.
- [Phase 5] `ntfs_insert_security` `out:` calls `fnd_put(fnd_sdh)`.
- [Phase 6] `git describe HEAD` = `v7.3-rc4-27-gf0100363d8c37`; `make
kernelversion` = 7.3.0-rc4.
- [Phase 6] Pre-fix source at `194491be54e1c^` still has `kfree(n)`
without `kfree(n->index)`.
- [Phase 8] Failure mode: kmalloc leak of index buffers on SDH pop;
severity HIGH for leak class, not oops/corruption.
- UNVERIFIED: whether any user actually hit OOM from this; mailing-list
review comments beyond the isolated patch mail.
The fix is small, surgical, and meets the stable criteria for this tree.
**YES**
fs/ntfs3/index.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/fs/ntfs3/index.c b/fs/ntfs3/index.c
index edfcd28573ef9..03ae5a817c1b4 100644
--- a/fs/ntfs3/index.c
+++ b/fs/ntfs3/index.c
@@ -1325,6 +1325,7 @@ int indx_find_sort(struct ntfs_index *indx, struct ntfs_inode *ni,
/* Pop one level. */
if (n) {
fnd_pop(fnd);
+ kfree(n->index);
kfree(n);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH AUTOSEL 6.18-5.15] fs/ntfs3: load ATTR_BITMAP run extents from $MFT extension records
[not found] <20261019135441.1420968-1-sashal@kernel.org>
2026-10-19 13:48 ` [PATCH AUTOSEL 6.18-5.15] fs/ntfs3: reserve NUL byte when converting UTF-16 names Sasha Levin
2026-10-19 13:48 ` [PATCH AUTOSEL 6.18-5.15] fs/ntfs3: Fix memory leak in indx_find_sort() Sasha Levin
@ 2026-10-19 13:48 ` Sasha Levin
2026-10-19 13:49 ` [PATCH AUTOSEL 6.18-5.15] fs/ntfs3: fix lseek EINVAL on sparse/compressed files with 64-bit clusters Sasha Levin
` (2 subsequent siblings)
5 siblings, 0 replies; 6+ messages in thread
From: Sasha Levin @ 2026-10-19 13:48 UTC (permalink / raw)
To: patches, stable
Cc: Konstantin Komarov, Senjin, Sasha Levin, ntfs3, linux-kernel
From: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
[ Upstream commit e31886cb6e0e14cf65e27da0bf1a422ff419d893 ]
When $MFT's ATTR_BITMAP attribute is heavily fragmented, its run list
can span multiple MFT extension records (attribute list entries with
vcn > 0). The non-primary segment handler in ntfs_read_mft() only
processed ATTR_DATA extension segments for MFT_REC_MFT, silently
skipping any ATTR_BITMAP segments. This left sbi->mft.bitmap.run
incomplete, causing wnd_init() to fail with -ENOENT when wnd_rescan()
tried to look up a VCN not covered by the truncated run list.
Observed on a 16 TB NTFS volume (0xFFFFFEFF total clusters) whose MFT
bitmap run list was split across 97 extents in extension records.
wnd_rescan() successfully looked up VCNs 0-122 from the runs loaded
from the base record, then failed at VCN 123 (the last cluster of the
bitmap) whose run was only present in an extension record.
Fix by extending the MFT_REC_MFT special case to also handle
ATTR_BITMAP extension segments, storing their runs into
sbi->mft.bitmap.run the same way the primary segment does.
Signed-off-by: Senjin <senjin@hatchling.org>
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
I have enough to judge this: a real NTFS3 mount failure, a small first-
pass run-list fix, and a related later `super.c` workaround already in
this 7.3 tree. Writing the full 9-phase analysis next.
---
## PHASE 1: COMMIT MESSAGE FORENSICS
**Step 1.1: PARSE THE SUBJECT LINE**
Record: **[fs/ntfs3] [load] load ATTR_BITMAP run extents from $MFT
extension records**
The verb is “load”, not “fix”, but the body describes a mount failure
and a missing code path. Intent is a bug fix.
**Step 1.2: PARSE ALL COMMIT MESSAGE TAGS**
Commit: `e31886cb6e0e14cf65e27da0bf1a422ff419d893`
Tags present:
- `Signed-off-by: Senjin <senjin@hatchling.org>` (author of the fix)
- `Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-
software.com>` (ntfs3 maintainer)
Tags absent (expected for this pipeline): `Fixes:`, `Cc: stable`,
`Reported-by`, `Tested-by`, `Reviewed-by`, `Acked-by`, `Link:`.
AuthorDate: 2026-07-02; CommitDate: 2026-07-24 (maintainer applied it).
**Step 1.3: ANALYZE THE COMMIT BODY TEXT**
Record:
- **Bug:** When `$MFT`’s `ATTR_BITMAP` is heavily fragmented, its run
list spans MFT extension records (`le->vcn > 0`). `ntfs_read_mft()`
only unpacked `ATTR_DATA` extension segments for `MFT_REC_MFT` and
skipped `ATTR_BITMAP` segments.
- **Symptom:** `sbi->mft.bitmap.run` is truncated. `wnd_init()` →
`wnd_rescan()` → `run_lookup_entry()` returns `-ENOENT`. Mount fails.
- **Evidence:** 16 TB volume (`0xFFFFFEFF` clusters). Bitmap run list
split across 97 extents. VCNs 0–122 found from the base record; VCN
123 (last bitmap cluster) only in an extension record.
- **Root cause:** Non-primary segment handler too narrow (`ino !=
MFT_REC_MFT || attr->type != ATTR_DATA`).
- **Fix:** Same special case also unpacks `ATTR_BITMAP` into
`sbi->mft.bitmap.run`.
- **Versions:** None named in the message. Observation used
`CONFIG_NTFS3_64BIT_CLUSTER=y` (from the v2 cover letter).
**Step 1.4: DETECT HIDDEN BUG FIXES**
Record: Not a disguised cleanup. Explicit mount-failure fix; “load” is
the mechanism.
---
## PHASE 2: DIFF ANALYSIS
**Step 2.1: INVENTORY THE CHANGES**
Record:
- File: `fs/ntfs3/inode.c` — **+8 / −2** (net +6)
- Function: `ntfs_read_mft()`
- Scope: **single-file surgical fix**
**Step 2.2: UNDERSTAND THE CODE FLOW CHANGE**
Before (parent `e31886cb6e0e1^`):
```c
if (le && le->vcn) {
/* non-primary segment */
if (ino != MFT_REC_MFT || attr->type != ATTR_DATA)
goto next_attr;
run = &ni->file.run;
...
goto attr_unpack_run;
}
```
After:
```c
if (le && le->vcn) {
if (ino != MFT_REC_MFT)
goto next_attr;
if (attr->type == ATTR_DATA)
run = &ni->file.run;
else if (attr->type == ATTR_BITMAP)
run = &sbi->mft.bitmap.run;
else
goto next_attr;
...
goto attr_unpack_run;
}
```
Record: Non-primary `$MFT` `ATTR_BITMAP` segments now take the same
`attr_unpack_run` path the primary `ATTR_BITMAP` case already uses (`run
= &sbi->mft.bitmap.run` around inode.c:323–333). Other inodes and other
attribute types still skip non-primary segments.
**Step 2.3: IDENTIFY THE BUG MECHANISM**
Record: **[Logic / correctness]** Incomplete run-list construction.
Missing handling of `$MFT` `ATTR_BITMAP` extension segments left
`sbi->mft.bitmap.run` short, so `wnd_rescan()` failed with `-ENOENT` at
an uncovered VCN.
**Step 2.4: ASSESS THE FIX QUALITY**
Record:
- Obviously correct: it mirrors the existing `ATTR_DATA` special case
and the primary `ATTR_BITMAP` assignment.
- Minimal: one condition split, one extra branch.
- Regression risk: low. `run_add_entry()` allows overlapping runs, so a
later second unpack is safe.
- No API / locking / data-structure change.
---
## PHASE 3: GIT HISTORY INVESTIGATION
**Step 3.1: BLAME THE CHANGED LINES**
Record: Buggy test `if (ino != MFT_REC_MFT || attr->type != ATTR_DATA)`
comes from **`82cae269cfa953`** (“fs/ntfs3: Add initialization of super
block”, 2021-08-13) — original ntfs3 merge. Present since **v5.15**.
**Step 3.2: FOLLOW THE FIXES: TAG**
Record: No `Fixes:` tag. Introducer is `82cae269cfa953`, ancestor of
HEAD (`git merge-base --is-ancestor` exit 0).
**Step 3.3: CHECK FILE HISTORY FOR RELATED CHANGES**
Record: Related commit already in this tree:
**`6d979b64287fb`** — `ntfs3: fix mount failure on volumes with
fragmented MFT bitmap` (2026-04-07, contained in **v7.1-rc1**).
That patch:
1. Moves `ni_load_all_mi()` before `wnd_init()`.
2. Walks attributes and `run_unpack_ex()`s `$BITMAP` extents with `svcn
!= 0`.
Same symptom (`wnd_init` / `-ENOENT`), different site (`super.c` second
pass vs `inode.c` first pass). `6d979b64287fb` is an ancestor of
`e31886cb6e0e1`.
Series context: mailing-list **v2 1/2**. Patch 2/2 is `789af83e41aef`
(`lseek EINVAL` on 64-bit clusters) — independent, not a prerequisite.
**Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS**
Record: Applied by **Konstantin Komarov**, listed `M:` for NTFS3
(`MAINTAINERS`: Supported). Senjin also authored the sibling lseek fix.
Maintainer SOB is a strong quality signal.
**Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS**
Record: Standalone. Uses existing `attr_unpack_run`,
`sbi->mft.bitmap.run`, and the `MFT_REC_MFT` special case from 2021. No
new helpers. Patch 2/2 is unrelated.
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
**Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION**
Record:
- `b4 dig -c e31886cb6e0e1` **failed**: lore.kernel.org returned errors.
- Found via web search:
- v1: 2026-06-10, `[PATCH] fs/ntfs3: load ATTR_BITMAP run extents...`
- v2: 2026-06-13, `[PATCH v2 1/2]` — **hunk-header fix only, no code
change**
- Cover: `[PATCH v2 0/2] fs/ntfs3: two fixes for large NTFS volumes`
- Openwall: https://lists.openwall.net/linux-kernel/2026/06/13/668 and
`/669`
- No NAKs found. Maintainer merged it into `ntfs3_for_7.3`.
- Cover letter: both bugs seen on a 16 TB volume with
`CONFIG_NTFS3_64BIT_CLUSTER=y`.
**Step 4.2: CHECK WHO REVIEWED THE PATCH**
Record: `b4 dig -w` failed. Recipients from the archived mail:
`ntfs3@lists.linux.dev`, `almaz.alexandrovich@paragon-software.com`,
`linux-kernel@vger.kernel.org`. Maintainer was CC’d and later signed
off. No other `Reviewed-by` on the commit.
**Step 4.3: SEARCH FOR THE BUG REPORT**
Record: Reporter is Senjin (author), with a concrete 16 TB / 97-extent
case. No syzbot/bugzilla. Cover does not mention `6d979b64287fb`, so
Senjin likely reproduced on a kernel without that later-pass workaround
(UNVERIFIED which exact release they ran).
**Step 4.4: CHECK FOR RELATED PATCHES AND SERIES**
Record: v2 0/2 is two independent large-volume fixes. 2/2 is not
required for 1/2.
**Step 4.5: CHECK STABLE MAILING LIST HISTORY**
Record: lore.kernel.org/stable search did not return discussion of this
commit (403/irrelevant hits). No documented reason to keep it out of
stable.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
**Step 5.1: IDENTIFY KEY FUNCTIONS**
Record: `ntfs_read_mft()`; uses `ni_enum_attr_ex()`, `attr_unpack_run` →
`run_unpack_ex()`. Failure path: `wnd_init()` → `wnd_rescan()` →
`run_lookup_entry()`.
**Step 5.2: TRACE CALLERS**
Record:
- `ntfs_read_mft()` is static; only caller is `ntfs_iget5()` when
`I_NEW`.
- Mount: `ntfs_fill_super()` → `ntfs_iget5($MFT)` → `ntfs_read_mft()`.
- Not IRQ; mount/iget path.
**Step 5.3: TRACE CALLEES**
Record: `ni_enum_attr_ex()` loads ATTR_LIST records via `ni_load_mi()`.
Matching segments go to `run_unpack_ex()` into `sbi->mft.bitmap.run`.
Later `wnd_init(&sbi->mft.bitmap)` scans that run list.
**Step 5.4: FOLLOW THE CALL CHAIN**
Record: `mount -t ntfs3` → `ntfs_fill_super` → load `$MFT` → incomplete
bitmap runs → `wnd_init` fails → mount fails. **Userspace-reachable.**
Unprivileged users cannot trigger it without mount rights; operators
with NTFS volumes can. Volume is unusable until remounted with another
driver.
**Step 5.5: SEARCH FOR SIMILAR PATTERNS**
Record: Primary `ATTR_BITMAP` already sets `run = &sbi->mft.bitmap.run`.
`6d979b64287fb` unpacks the same extents later in `ntfs_fill_super()`.
`run_add_entry()` documents that new runs may overlap existing ones, so
both paths together are safe.
---
## PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE
**Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?**
Record:
- Local tree: **`v7.3-rc4-27-gf0100363d8c37`**, `make kernelversion` =
**7.3.0-rc4** (mainline-style checkout, detached HEAD).
- Candidate **is already an ancestor of HEAD**.
- Buggy skip has existed since `82cae269cfa953` (v5.15). Parent of this
commit still has it.
- `6d979b64287fb` (v7.1-rc1) is also in this tree and tries to paper
over the same gap in `super.c`.
**Step 6.2: CHECK FOR BACKPORT COMPLICATIONS**
Record: Expected apply: **clean** on any tree with the original
`MFT_REC_MFT`/`ATTR_DATA` special case (all ntfs3 trees since 5.15).
Hunk is isolated.
**Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE**
Record: `6d979b64287fb` is here. It is a second-pass unpack after
`ni_load_all_mi()`, not a replacement for loading during
`ntfs_read_mft()`. No later commit reverts or replaces `e31886cb6e0e1`.
ADS/iomap commits after it do not touch this branch.
---
## PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
**Step 7.1: IDENTIFY THE SUBSYSTEM AND ITS CRITICALITY**
Record: **fs/ntfs3** — **IMPORTANT** (supported RW Windows filesystem,
not staging). Not core VFS/mm, but mount failure is serious for dual-
boot, NAS, and large Windows volumes.
**Step 7.2: ASSESS SUBSYSTEM ACTIVITY**
Record: Actively maintained (Paragon tree, multiple 7.x ntfs3 pulls).
This is a targeted correctness fix, not drive-by churn.
---
## PHASE 8: IMPACT AND RISK ASSESSMENT
**Step 8.1: DETERMINE WHO IS AFFECTED**
Record: **Filesystem-specific / config-specific.** Users of
`CONFIG_NTFS3_FS` with a fragmented `$MFT` `$BITMAP` (large or long-
lived NTFS). The 16 TB report also used `CONFIG_NTFS3_64BIT_CLUSTER`.
Fragmentation itself is not limited to 64-bit clusters; `6d979b64287fb`
reproduced on a 664 GB volume.
**Step 8.2: DETERMINE THE TRIGGER CONDITIONS**
Record: Every mount of an affected volume. Not a race. Needs mount
capability, not an unprivileged syscall gadget. Common on large/aged
NTFS.
**Step 8.3: DETERMINE THE FAILURE MODE SEVERITY**
Record: **Mount failure (`-ENOENT`)** — volume cannot be mounted with
ntfs3. **HIGH** (not a panic, but the filesystem is unusable).
**Step 8.4: CALCULATE RISK-BENEFIT RATIO**
Record:
- **Benefit:** High for affected volumes (mount works). Completes the
`$MFT` parse the same way `ATTR_DATA` was always handled. Helps trees
that lack `6d979b64287fb`; on trees that have it, it is still the
right first-pass fix and is overlap-safe.
- **Risk:** Very low (6 lines in one function, existing unpack helper).
- **Ratio:** Strongly favors backport.
---
## PHASE 9: FINAL SYNTHESIS
**Step 9.1: COMPILE THE EVIDENCE**
**FOR:**
- Real mount failure, observed on a 16 TB volume (97 extents; fail at
last VCN).
- Independent 664 GB report of the same class (`6d979b64287fb`).
- Bug in ntfs3 since v5.15.
- 8-line, obviously correct extension of an existing special case.
- Maintainer SOB; merged to `ntfs3_for_7.3`.
- Standalone (series 2/2 is unrelated).
- `run_add_entry()` allows overlap with the v7.1 second-pass unpack.
**AGAINST:**
- `6d979b64287fb` already in **this** 7.3 tree may already make mount
succeed via a later unpack.
- No `Fixes:`/`Cc: stable` (not a negative in this pipeline).
- Affects ntfs3 only, not all kernel users.
**UNRESOLVED:**
- Whether Senjin’s 16 TB kernel included `6d979b64287fb` (cover letter
never mentions it).
- lore.kernel.org was unreachable for `b4 dig` / WebFetch; discussion
recovered from Openwall/LKML mirrors.
**Step 9.2: APPLY THE STABLE RULES CHECKLIST**
1. Obviously correct and tested? **PASS** — mirrors `ATTR_DATA`; tested
on a real 16 TB volume; maintainer applied it.
2. Fixes a real bug that affects users? **PASS** — mount `-ENOENT` on
fragmented `$MFT` bitmap.
3. Important issue? **PASS** — filesystem unmountable (HIGH).
4. Small and contained? **PASS** — +8/−2, one function.
5. No new features or APIs? **PASS**.
6. Can apply to the local tree? **PASS** — code and helpers are present;
hunk matches `ntfs_read_mft()`.
**Step 9.3: CHECK FOR EXCEPTION CATEGORIES**
Record: None of the ID/quirk/DT/build/doc exceptions. It qualifies as a
normal important bug fix.
**Step 9.4: DECISION**
This checkout is 7.3-rc4 and already contains the commit; the question
is still whether that fix is stable material for this lineage. It is.
`6d979b64287fb` is a later-pass workaround, not a reason to drop the
first-pass unpack. Silently skipping `$MFT` `ATTR_BITMAP` extents in
`ntfs_read_mft()` is a real bug. The patch is small, correct,
maintainer-acked, and prevents a user-visible mount failure on
large/fragmented NTFS volumes.
---
### What the commit solves
`$MFT`’s bitmap run list can spill into extension records.
`ntfs_read_mft()` unpacked only `ATTR_DATA` there, so
`sbi->mft.bitmap.run` was truncated and `wnd_init()` failed with
`-ENOENT`. Mount failed. The patch stores those bitmap extents the same
way the primary segment already does.
### Stable rules
Meets all six criteria: small, obviously correct, real important bug, no
new API, applies here.
### Risk vs benefit
Benefit: restores mount on affected NTFS volumes. Risk: very low;
overlap with `6d979b64287fb` is handled by `run_add_entry()`.
### Concerns
- Series 1/2: 2/2 is an unrelated lseek fix; not required.
- `6d979b64287fb` already in this 7.3 tree: complementary, not a
blocker.
- No extra prerequisites beyond original ntfs3 `MFT_REC_MFT` handling
(v5.15).
---
## Verification
- **[Phase 1]** Parsed `e31886cb6e0e1`: Senjin + Konstantin SOBs only;
no Fixes/stable/Reported-by.
- **[Phase 2]** `git show e31886cb6e0e1`: +8/−2 in `ntfs_read_mft()`;
`ATTR_BITMAP` → `sbi->mft.bitmap.run`.
- **[Phase 2]** Read `inode.c` ATTR_BITMAP primary case (lines 323–333)
and `attr_unpack_run` (399–414).
- **[Phase 2]** Read `wnd_rescan()`: missing run → `err = -ENOENT`.
- **[Phase 3]** `git blame` on parent: buggy line from `82cae269cfa953`
(2021-08-13).
- **[Phase 3]** `git merge-base --is-ancestor 82cae269cfa953 HEAD` →
yes.
- **[Phase 3]** Related fix `6d979b64287fb` in tree (`v7.1-rc1~76^2~6`);
ancestor of this commit.
- **[Phase 3]** `git log --author=Konstantin Komarov -- fs/ntfs3/`:
maintainer.
- **[Phase 4]** `b4 dig -c e31886cb6e0e1`: lore error; UNVERIFIED via
b4.
- **[Phase 4]** Openwall v2 0/2 and 1/2: 16 TB repro; v2 is hunk-header
only; 2/2 independent.
- **[Phase 4]** WebFetch spinics/lore: 500/403; used Openwall/LKML
mirrors.
- **[Phase 4]** No stable@ discussion found.
- **[Phase 5]** Only caller of `ntfs_read_mft`: `ntfs_iget5`
(mount/`I_NEW`).
- **[Phase 5]** `run_add_entry()` documents overlap is allowed.
- **[Phase 6]** `git describe HEAD` = `v7.3-rc4-27-gf0100363d8c37`;
`make kernelversion` = 7.3.0-rc4.
- **[Phase 6]** Candidate is ancestor of HEAD; parent still has the
skip.
- **[Phase 7]** `MAINTAINERS`: NTFS3 Supported, M: Konstantin Komarov.
- **[Phase 8]** Failure mode: mount `-ENOENT`, severity HIGH.
- **UNVERIFIED:** Exact kernel Senjin reproduced on; whether
`6d979b64287fb` alone would have mounted that 16 TB volume.
The local tree has the ntfs3 code path, the bug dates to the original
driver, the patch is a small contained mount fix, and it should be
backported.
**YES**
fs/ntfs3/inode.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c
index 120691bc71ee9..99fdba7b403cb 100644
--- a/fs/ntfs3/inode.c
+++ b/fs/ntfs3/inode.c
@@ -126,10 +126,16 @@ static struct inode *ntfs_read_mft(struct inode *inode,
if (le && le->vcn) {
/* This is non primary attribute segment. Ignore if not MFT. */
- if (ino != MFT_REC_MFT || attr->type != ATTR_DATA)
+ if (ino != MFT_REC_MFT)
+ goto next_attr;
+
+ if (attr->type == ATTR_DATA)
+ run = &ni->file.run;
+ else if (attr->type == ATTR_BITMAP)
+ run = &sbi->mft.bitmap.run;
+ else
goto next_attr;
- run = &ni->file.run;
asize = le32_to_cpu(attr->size);
goto attr_unpack_run;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH AUTOSEL 6.18-5.15] fs/ntfs3: fix lseek EINVAL on sparse/compressed files with 64-bit clusters
[not found] <20261019135441.1420968-1-sashal@kernel.org>
` (2 preceding siblings ...)
2026-10-19 13:48 ` [PATCH AUTOSEL 6.18-5.15] fs/ntfs3: load ATTR_BITMAP run extents from $MFT extension records Sasha Levin
@ 2026-10-19 13:49 ` Sasha Levin
2026-10-19 13:51 ` [PATCH AUTOSEL 6.18-6.12] ntfs3: initialize err in attr_wof_frame_info Sasha Levin
2026-10-19 13:51 ` [PATCH AUTOSEL 6.18-5.15] ntfs3: fix info-leak in ntfs_rename() Sasha Levin
5 siblings, 0 replies; 6+ messages in thread
From: Sasha Levin @ 2026-10-19 13:49 UTC (permalink / raw)
To: patches, stable
Cc: Senjin, Konstantin Komarov, Sasha Levin, ntfs3, linux-kernel
From: Senjin <senjin@hatchling.org>
[ Upstream commit 789af83e41aef54c1ff1cee16adc27822e0a0d71 ]
When CONFIG_NTFS3_64BIT_CLUSTER is enabled, sbi->maxbytes_sparse is set
to -1. As a signed loff_t this is -1LL, the most negative value. Any
lseek on a sparse or compressed file passes this as maxsize to
vfs_setpos(), which returns -EINVAL whenever offset > maxsize, and
since -1LL is less than any non-negative offset, every seek fails,
including lseek(fd, 0, SEEK_SET).
The intent of -1 here appears to be "no limit" (matching the spirit of
MAX_LFS_FILESIZE assigned to sbi->maxbytes and sb->s_maxbytes in the
same block), but the signed type makes it the minimum instead of the
maximum.
Fix by assigning MAX_LFS_FILESIZE to sbi->maxbytes_sparse in the
64-bit cluster path, consistent with the other two limits set there.
Observed on a 16 TB NTFS volume with 0xFFFFFEFF total clusters compiled
with CONFIG_NTFS3_64BIT_CLUSTER=y. Sequential reads via dd/cp worked
correctly; any lseek call on sparse files returned EINVAL, preventing
archive managers and other tools from random-accessing files on the
volume. The non-64-bit-cluster path correctly sets maxbytes_sparse to
(1ull << (cluster_bits + 32)) - 1, a large positive value.
Signed-off-by: Senjin <senjin@hatchling.org>
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
This is a one-line NTFS3 correctness fix: with 64-bit clusters,
sparse/compressed `lseek` was passing a signed `-1` limit into
`vfs_setpos()`, so every nonnegative seek returned `-EINVAL`. The local
tree is **7.3.0-rc4** (`v7.3-rc4-27-gf0100363d8c37`); the path and the
bug both exist here.
---
## PHASE 1: COMMIT MESSAGE FORENSICS
**Step 1.1: PARSE THE SUBJECT LINE**
Record: `[fs/ntfs3] [fix] [lseek returns EINVAL on sparse/compressed
files when CONFIG_NTFS3_64BIT_CLUSTER is set]`
**Step 1.2: PARSE ALL COMMIT MESSAGE TAGS**
Record:
- `Signed-off-by: Senjin <senjin@hatchling.org>` (author)
- `Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-
software.com>` (NTFS3 maintainer; listed in MAINTAINERS)
- No `Fixes:`, `Reported-by:`, `Tested-by:`, `Reviewed-by:`, `Acked-
by:`, `Link:`, or `Cc: stable@` (absence is expected for this review)
**Step 1.3: ANALYZE THE COMMIT BODY TEXT**
Record:
- **Bug:** With `CONFIG_NTFS3_64BIT_CLUSTER`, `sbi->maxbytes_sparse` is
set to `-1`. Used as signed `loff_t`, that is `-1LL`. `ntfs_llseek()`
passes it to `vfs_setpos()` / `generic_file_llseek_size()`, which
rejects any `offset > maxsize`.
- **Symptom:** Every `lseek` on sparse/compressed files fails with
`EINVAL`, including `lseek(fd, 0, SEEK_SET)`. Sequential `dd`/`cp`
still work. Archive managers cannot random-access those files.
- **Trigger:** Observed on a 16 TB NTFS volume (`0xFFFFFEFF` clusters)
with `CONFIG_NTFS3_64BIT_CLUSTER=y`.
- **Root cause:** `-1` was meant as “no limit” (same idea as
`MAX_LFS_FILESIZE` for `sb->s_maxbytes`), but as a signed max it is
the minimum, not the maximum.
- **Fix:** Assign `MAX_LFS_FILESIZE` instead, matching `sb->s_maxbytes`
in the same `#ifdef`.
**Step 1.4: DETECT HIDDEN BUG FIXES**
Record: `[Not hidden]` — subject and body describe a real, reproduced
functional bug.
---
## PHASE 2: DIFF ANALYSIS - LINE BY LINE
**Step 2.1: INVENTORY THE CHANGES**
Record:
- File: `fs/ntfs3/super.c` — 1 insertion, 1 deletion
- Function: `ntfs_init_from_boot()`
- Scope: single-file surgical one-liner
**Step 2.2: UNDERSTAND THE CODE FLOW CHANGE**
Record:
- **Before:** `#ifdef CONFIG_NTFS3_64BIT_CLUSTER` always does
`sbi->maxbytes_sparse = -1`.
- **After:** `sbi->maxbytes_sparse = MAX_LFS_FILESIZE`.
- Path: superblock init at mount. Affects every later
`ntfs_get_maxbytes()` use for sparse/compressed inodes.
**Step 2.3: IDENTIFY THE BUG MECHANISM**
Record: `[Logic / type-signedness]`
Verified types and call path:
- `maxbytes_sparse` is `u64` (`fs/ntfs3/ntfs_fs.h`). Assigning `-1`
stores `U64_MAX`.
- `ntfs_get_maxbytes()` returns that as `loff_t`. `U64_MAX` → `-1LL`.
- `ntfs_llseek()` (`fs/ntfs3/file.c`) passes that to
`generic_file_llseek_size()` / `vfs_setpos()`.
- `vfs_setpos_cookie()` (`fs/read_write.c`) does `if (offset > maxsize)
return -EINVAL`. For `offset == 0` and `maxsize == -1`, `0 > -1` is
true.
Same conversion also breaks `ntfs_iomap_begin()`’s `IOMAP_REPORT` check
(`offset > ntfs_get_maxbytes(ni)`), so fiemap/bmap on those files can
fail the same way.
The `#else` path already uses a large positive `(1ull << (cluster_bits +
32)) - 1`.
**Step 2.4: ASSESS THE FIX QUALITY**
Record:
- Obviously correct: `MAX_LFS_FILESIZE` is `LLONG_MAX` on 64-bit
(`include/linux/fs.h`); this config is 64-bit-only (`#error` on
32-bit). Same constant is already assigned to `sb->s_maxbytes` in this
block.
- Minimal: one assignment change, no API/struct change.
- Regression risk: very low. Limit goes from “every seek fails” to the
VFS max file size. `ntfs_set_size()` / attrib insert compare against
`u64`; `LLONG_MAX` is still a huge positive cap and matches VFS, vs
the old `U64_MAX` which was accidentally unlimited on those u64
checks.
---
## PHASE 3: GIT HISTORY INVESTIGATION
**Step 3.1: BLAME THE CHANGED LINES**
Record:
- Buggy assignment introduced in `82cae269cfa95` (“fs/ntfs3: Add
initialization of super block”, 2021-08-13), first in **v5.15-rc1**.
- Field has been `u64 maxbytes_sparse` since the original headers
(`4534a70b7056f`).
- User-visible `lseek` breakage requires `ntfs_llseek()` using
`ntfs_get_maxbytes()`, added in `c613269677283` (“implement llseek
SEEK_DATA/SEEK_HOLE…”), contained in **v7.0-rc1**. Before that,
`.llseek = generic_file_llseek` used `sb->s_maxbytes`
(`MAX_LFS_FILESIZE` in this config), so SEEK_SET worked.
**Step 3.2: FOLLOW THE FIXES: TAG**
Record: `[N/A — no Fixes: tag]`. Effective buggy commit for the reported
symptom is `c613269677283` (in this tree). The `-1` store itself is from
`82cae269cfa95` (also in this tree).
**Step 3.3: CHECK FILE HISTORY FOR RELATED CHANGES**
Record:
- Candidate: `789af83e41aef` (2026-06-13 / committed 2026-07-24).
- Merged to Linus in `dc83d18cdd904` (`ntfs3_for_7.3`, 2026-08-20);
present in **v7.3-rc1**. **Not** in v7.2 / v7.1 / v7.0.
- Series sibling (v2 1/2): `e31886cb6e0e1` (ATTR_BITMAP extents) is the
git parent but touches `fs/ntfs3/inode.c` only. Independent of this
hunk.
- No other `maxbytes_sparse` fix in this tree.
**Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS**
Record: Senjin has this plus the ATTR_BITMAP mount fix on the same 16 TB
volume. Konstantin Komarov is the NTFS3 maintainer (`MAINTAINERS`:
Supported) and committed both.
**Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS**
Record: Standalone. Needs only `CONFIG_NTFS3_64BIT_CLUSTER` and
`MAX_LFS_FILESIZE`, both present since ntfs3 was added. Does not need
patch 1/2.
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
**Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION**
Record:
- `b4 dig -c 789af83e41aef`: `[PATCH v2 2/2]`,
https://patch.msgid.link/6a2dba8e030b48618aa54661@mailersend.net
- `b4 dig -a`: v1 was only the ATTR_BITMAP patch (2026-06-10); v2 added
this as 2/2 (2026-06-13). Applied version is v2.
- lore.kernel.org / patch.msgid.link returned **403**; spinics ntfs3
thread returned **500**. Patch text confirmed via LKML IU and Openwall
mirrors. Full reply thread: **UNVERIFIED**.
**Step 4.2: CHECK WHO REVIEWED THE PATCH**
Record (`b4 dig -w`): `senjin@hatchling.org`, `ntfs3@lists.linux.dev`,
`almaz.alexandrovich@paragon-software.com`, `linux-
kernel@vger.kernel.org`. Maintainer list was CCed; maintainer signed off
and merged. No NAK found in reachable archives.
**Step 4.3: SEARCH FOR THE BUG REPORT**
Record: No syzbot/bugzilla link. Author reports a real 16 TB volume;
sequential I/O worked, `lseek` did not. Same volume as the ATTR_BITMAP
mount failure.
**Step 4.4: CHECK FOR RELATED PATCHES AND SERIES**
Record: v2 1/2 is a different mount bug (`inode.c`). This 2/2 is self-
contained. Linus’s `ntfs3_for_7.3` pull lists “lseek EINVAL on
sparse/compressed files with 64-bit clusters” under Fixed.
**Step 4.5: CHECK STABLE MAILING LIST HISTORY**
Record: lore.kernel.org/stable search did not turn up this subject
(403/unrelated hits). **UNVERIFIED** whether anyone already
requested/rejected it for stable.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
**Step 5.1: IDENTIFY KEY FUNCTIONS IN THE DIFF**
Record: `ntfs_init_from_boot()` (assignment). Consumers:
`ntfs_get_maxbytes()` → `ntfs_llseek()`, `ntfs_iomap_begin()`; also raw
`sbi->maxbytes_sparse` in `ntfs_set_size()` and attrib insert.
**Step 5.2: TRACE CALLERS**
Record:
- `ntfs_init_from_boot()` — mount/fill_super.
- `ntfs_llseek` — `file_operations.llseek` for regular ntfs3 files
(syscall `lseek`/`llseek`).
- `ntfs_iomap_begin` — fiemap/bmap `IOMAP_REPORT`.
- Directory `llseek` still uses `generic_file_llseek` (`dir.c`); not
this bug.
**Step 5.3: TRACE CALLEES**
Record: The changed line is an assignment. Downstream: `vfs_setpos()` /
`generic_file_llseek_size()`.
**Step 5.4: FOLLOW THE CALL CHAIN**
Record: Userspace `lseek` → `ntfs_llseek` → `ntfs_get_maxbytes` →
`vfs_setpos`. Reachable from unprivileged processes with a file open.
Confirmed in-tree.
**Step 5.5: SEARCH FOR SIMILAR PATTERNS**
Record: `sbi->maxbytes = -1` remains in the overflow branch (`clusters
>= 1ull << (64 - cluster_bits)`). Same signedness issue for *non-sparse*
files, but that volume size is far beyond the reported 16 TB /
`0xFFFFFEFF` clusters. Out of this patch’s scope.
---
## PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE
**Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?**
Record: Yes. `fs/ntfs3/super.c`, `ntfs_llseek`,
`CONFIG_NTFS3_64BIT_CLUSTER`, and `ntfs_get_maxbytes()` are all present.
Current line is already the fixed assignment (`sbi->maxbytes_sparse =
MAX_LFS_FILESIZE` at line 1214). Pre-fix `-1` is in `789af83e41aef^`.
Bug introduction for lseek: v7.0; this checkout is 7.3-rc4.
**Step 6.2: CHECK FOR BACKPORT COMPLICATIONS**
Record: Clean apply. Surrounding `#ifdef CONFIG_NTFS3_64BIT_CLUSTER` /
`sb->s_maxbytes = MAX_LFS_FILESIZE` matches the hunk. No conflicting
refactor in this function.
**Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE**
Record: This commit *is* the fix (`789af83e41aef` is an ancestor of
HEAD). No earlier substitute fix. That is origin-tree presence, not a
reason to reject on merit.
---
## PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
**Step 7.1: IDENTIFY THE SUBSYSTEM AND ITS CRITICALITY**
Record: `[fs/ntfs3] [IMPORTANT]` — not core VFS, but a supported RW
filesystem used for Windows/large volumes. Maintainer-supported.
**Step 7.2: ASSESS SUBSYSTEM ACTIVITY**
Record: Actively maintained (regular `ntfs3_for_*` pulls, many 7.3
fixes). This is not staging.
---
## PHASE 8: IMPACT AND RISK ASSESSMENT
**Step 8.1: DETERMINE WHO IS AFFECTED**
Record: Config-specific (`CONFIG_NTFS3_64BIT_CLUSTER=y`, 64-bit,
recommended N in Kconfig) **and** sparse or compressed files. That
option exists specifically for 16T+ volumes with 4K clusters (Windows
ntfs.sys is 32-bit cluster). Real users of large NTFS volumes.
**Step 8.2: DETERMINE THE TRIGGER CONDITIONS**
Record: Any `lseek` (SEEK_SET/SEEK_END/nonzero SEEK_CUR) on a
sparse/compressed file after mount. Common for archive tools, not rare
error-path. Unprivileged if the user can open the file. Not a race.
**Step 8.3: DETERMINE THE FAILURE MODE SEVERITY**
Record: `[Failure: all random access via lseek fails with EINVAL;
sequential read still works] [Severity: HIGH]`. Not a panic/UAF, but the
filesystem is unusable for a normal class of tools. Also breaks
fiemap/bmap `IOMAP_REPORT` on those inodes.
**Step 8.4: CALCULATE RISK-BENEFIT RATIO**
Record: Benefit high for affected mounts (restores `lseek`). Risk very
low (1 line, same constant already used for `s_maxbytes`). Ratio
strongly favors backport.
---
## PHASE 9: FINAL SYNTHESIS
**Step 9.1: COMPILE THE EVIDENCE**
**FOR:**
- Real user-visible bug on a 16 TB volume; `lseek` always `EINVAL` on
sparse/compressed files.
- Mechanism verified in this tree (`vfs_setpos` `offset > maxsize`,
signed `-1`).
- One-line, obviously correct, matches existing `MAX_LFS_FILESIZE`
usage.
- Maintainer signed off and merged.
- Standalone; no new API/feature.
- Call path is a normal syscall.
**AGAINST:**
- Option defaults to N; smaller population.
- Not a crash/UAF/corruption.
- Series labeled 2/2 (sibling is unrelated and not required).
- Full lore review thread not readable (403/500).
**UNRESOLVED:** Full reviewer comments; any stable@ discussion.
**Step 9.2: APPLY THE STABLE RULES CHECKLIST**
1. Obviously correct and tested? **PASS** — type/`vfs_setpos` logic is
clear; author observed it on real hardware; maintainer merged.
2. Fixes a real bug that affects users? **PASS** — reproduced; tools
cannot seek.
3. Important issue? **PASS** — HIGH: filesystem random-access completely
broken for sparse/compressed files on this config (not a panic, but a
serious functional failure).
4. Small and contained? **PASS** — 1 line, one file, one assignment.
5. No new features or APIs? **PASS**.
6. Can apply to the local tree? **PASS** — hunk matches
`ntfs_init_from_boot()` here.
**Step 9.3: CHECK FOR EXCEPTION CATEGORIES**
Record: `[None]` — ordinary bugfix, not a device-ID/quirk/DT/build/doc
exception.
**Step 9.4: MAKE YOUR DECISION**
This tree has the ntfs3 64-bit-cluster init path and
`ntfs_llseek()`/`ntfs_get_maxbytes()`. The signed `-1` max makes every
sparse/compressed seek fail. Replacing it with `MAX_LFS_FILESIZE` is the
right, minimal fix and meets stable rules.
---
### What the commit solves and why it matters here
On `CONFIG_NTFS3_64BIT_CLUSTER=y`, sparse/compressed files cannot be
seeked at all. That breaks archive managers and any random-access reader
while sequential copy still works. This checkout is 7.3, which already
has the 7.0 `ntfs_llseek` path, so the bug is in this codebase.
### Stable rules
Small, correct, user-reported functional failure, no new API, applies
cleanly.
### Risk vs benefit
Very low risk, high benefit for large NTFS volumes built with 64-bit
clusters.
### Concerns
Kconfig recommends N, so not every ntfs3 user. Patch 1/2 is not a
dependency. Residual `sbi->maxbytes = -1` overflow branch is a separate
edge case.
---
Verification:
- [Phase 1] Parsed commit `789af83e41aef`: SOB Senjin + maintainer
Komarov; no Fixes/Cc stable/Reported-by
- [Phase 2] Diff: `sbi->maxbytes_sparse = -1` → `MAX_LFS_FILESIZE` in
`ntfs_init_from_boot()`; 1 line
- [Phase 2] Confirmed `maxbytes_sparse` is `u64`; `ntfs_get_maxbytes()`
returns `loff_t`; `vfs_setpos_cookie()` rejects `offset > maxsize`
- [Phase 2] Confirmed `ntfs_llseek()` and `ntfs_iomap_begin()` consume
that value
- [Phase 3] `git blame`: `-1` from `82cae269cfa95` (v5.15-rc1);
`ntfs_llseek` from `c613269677283` (v7.0-rc1)
- [Phase 3] `git merge-base --is-ancestor 789af83e41aef HEAD`: yes; in
v7.3-rc1; not in v7.2/v7.1/v7.0
- [Phase 3] Series 1/2 `e31886cb6e0e1` touches `inode.c` only; not
required
- [Phase 4] `b4 dig -c/-a/-w`: v2 2/2, maintainer+ntfs3 list CCed; lore
fetch 403
- [Phase 4] LKML IU / Openwall: patch text matches; no NAK in those
copies
- [Phase 4] UNVERIFIED: full lore thread, stable@ discussion
- [Phase 5] Callers: `ntfs_llseek` (syscall), `ntfs_iomap_begin`
(fiemap)
- [Phase 6] `git describe HEAD`: `v7.3-rc4-27-gf0100363d8c37`; `make
kernelversion`: 7.3.0-rc4; current `super.c:1214` already has the fix
- [Phase 6] `CONFIG_NTFS3_64BIT_CLUSTER` in `fs/ntfs3/Kconfig`, 64-bit
only
- [Phase 7] MAINTAINERS: Konstantin Komarov, Supported
- [Phase 8] Failure: every sparse/compressed `lseek` → `-EINVAL`;
severity HIGH; trigger is normal userspace seek
**YES**
fs/ntfs3/super.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c
index 346c52f952076..dcf14410c6621 100644
--- a/fs/ntfs3/super.c
+++ b/fs/ntfs3/super.c
@@ -1163,7 +1163,7 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size,
#ifdef CONFIG_NTFS3_64BIT_CLUSTER
if (clusters >= (1ull << (64 - cluster_bits)))
sbi->maxbytes = -1;
- sbi->maxbytes_sparse = -1;
+ sbi->maxbytes_sparse = MAX_LFS_FILESIZE;
sb->s_maxbytes = MAX_LFS_FILESIZE;
#else
/* Maximum size for sparse file. */
--
2.53.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH AUTOSEL 6.18-6.12] ntfs3: initialize err in attr_wof_frame_info
[not found] <20261019135441.1420968-1-sashal@kernel.org>
` (3 preceding siblings ...)
2026-10-19 13:49 ` [PATCH AUTOSEL 6.18-5.15] fs/ntfs3: fix lseek EINVAL on sparse/compressed files with 64-bit clusters Sasha Levin
@ 2026-10-19 13:51 ` Sasha Levin
2026-10-19 13:51 ` [PATCH AUTOSEL 6.18-5.15] ntfs3: fix info-leak in ntfs_rename() Sasha Levin
5 siblings, 0 replies; 6+ messages in thread
From: Sasha Levin @ 2026-10-19 13:51 UTC (permalink / raw)
To: patches, stable
Cc: Ruoyu Wang, Konstantin Komarov, Sasha Levin, ntfs3, linux-kernel
From: Ruoyu Wang <ruoyuw560@gmail.com>
[ Upstream commit dd64afb32c4d8d3c934ae84df59a2e463d6fa43c ]
attr_wof_frame_info() may reuse a cached offsets folio. In that case the
loop can fill the output offsets without calling attr_load_runs_range()
or ntfs_read_run(), leaving err uninitialized before the common return
path. Initialize err to 0 for the successful cached path.
Signed-off-by: Ruoyu Wang <ruoyuw560@gmail.com>
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
The local checkout is **7.3.0-rc4** (`v7.3-rc4-27-gf0100363d8c37`). The
change is a one-line init of `err` in `attr_wof_frame_info()` so a
cached WOF offsets folio does not return stack garbage; that path is in
this tree and is a real user-visible bug.
===============================================================
PHASE 1: COMMIT MESSAGE FORENSICS
===============================================================
Step 1.1: PARSE THE SUBJECT LINE
Record: **[ntfs3] [initialize] initialize `err` in
`attr_wof_frame_info`**
- Subsystem: `ntfs3` (NTFS3 filesystem)
- Action verb: **initialize** (classic uninitialized-variable fix
language)
- Claimed intent: set `err` so the cached-folio success path does not
return an uninitialized value
Step 1.2: PARSE ALL COMMIT MESSAGE TAGS
Record:
- **Signed-off-by: Ruoyu Wang** (author)
- **Signed-off-by: Konstantin Komarov** (ntfs3 maintainer; applied the
patch)
- **No Fixes:** tag (expected for this review pipeline)
- **No Reported-by / Tested-by / Reviewed-by / Acked-by**
- **No Link:** / **no syzbot**
- **No Cc: stable** (expected; not a negative)
- Ignore pipeline-added Sasha Levin SOB / Upstream markers (none present
on the real commit)
Step 1.3: ANALYZE THE COMMIT BODY TEXT
Record:
- **Bug:** `attr_wof_frame_info()` can reuse a cached offsets folio
(`ni->file.offs_folio`). On that path the loop fills `off[]` from the
cached page and never calls `attr_load_runs_range()` /
`ntfs_read_run()`, so `err` is never written.
- **Symptom:** common `return err` then returns uninitialized stack
memory. Callers treat any non-zero as failure → spurious I/O errors on
WOF LZX/Xpress compressed files after the first cache hit.
- **Version info:** none in the message. Code is present since ntfs3
introduction.
- **Root cause:** `int i, err;` with `err` only assigned on I/O / alloc
/ corruption paths, not on cache-hit success.
Step 1.4: DETECT HIDDEN BUG FIXES
Record: **Not disguised.** This is an explicit uninitialized-variable
fix (`Initialize X`). Matches the KMSAN / uninit-use class even without
a sanitizer tag.
===============================================================
PHASE 2: DIFF ANALYSIS - LINE BY LINE
===============================================================
Step 2.1: INVENTORY THE CHANGES
Record:
- File: `fs/ntfs3/attrib.c` — **1 insertion, 1 deletion**
- Function: `attr_wof_frame_info()`
- Change: `int i, err;` → `int i, err = 0;`
- Scope: **single-file surgical fix** (one local initializer)
Step 2.2: UNDERSTAND THE CODE FLOW CHANGE
Record (verified in current `fs/ntfs3/attrib.c`):
- Resident attribute path returns `0` directly; unaffected.
- Non-resident path:
- Alloc fail: `err = -ENOMEM; goto out;`
- I/O / metadata fail: `err = ...; goto out1;`
- **Cache hit** (`index == folio->index`): loop reads offsets from the
cached folio, never assigns `err`, then falls through to `*vbo_data
+= off[0]; *ondisk_size = off[1] - off[0];` and `return err;`
- **Before:** cache-hit success returned uninitialized `err`
- **After:** that path returns `0`
Step 2.3: IDENTIFY THE BUG MECHANISM
Record:
- **Category:** (e) Initialization / uninitialized data use
- **Mechanism:** stack `err` used as the function return value without
assignment on the cached-folio success path
- **Not** a leak, race, refcount, or API change
Step 2.4: ASSESS THE FIX QUALITY
Record:
- **Obviously correct:** initializing `err = 0` is the right default;
every error path still overwrites `err` before return
- **Minimal:** one token
- **Regression risk: very low** — does not change locking, structures,
or successful I/O that already assigned `err`
- **Red flags:** none
===============================================================
PHASE 3: GIT HISTORY INVESTIGATION
===============================================================
Step 3.1: BLAME THE CHANGED LINES
Record:
- Current line is the fix: `dd64afb32c4d8` (Ruoyu Wang, 2026-06-18)
- Uninitialized `int i, err;` dates to **`be71b5cba2e648`** (“fs/ntfs3:
Add attrib operations”, 2021-08-13)
- Contained in **`v5.15-rc1`** (`git describe --contains be71b5cba2e648`
→ `v5.15-rc1~...`)
- Folio conversion `c091354d6bf60e` (2024) kept the same uninit `err`;
it did not introduce the bug
- The cached offsets page/`offs_folio` reuse path existed from day one
Step 3.2: FOLLOW THE FIXES: TAG
Record: **No Fixes: tag.** Bug was in the original function, not a later
regression commit.
Step 3.3: CHECK FILE HISTORY FOR RELATED CHANGES
Record:
- Nearby: `859d777646b56` (OOB write in same function), other ntfs3
bounds/init fixes
- This commit is **standalone**, not “patch X/Y”
- No prerequisite refactor required for the one-line init
Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS
Record:
- Ruoyu Wang: this is their only commit under `fs/ntfs3/` in this tree
- Applied by **Konstantin Komarov** (ntfs3 maintainer) — maintainer-
accepted
Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS
Record:
- Diff assumes only `int err` in `attr_wof_frame_info()` — present since
v5.15
- **Applies standalone.** No new helpers or struct changes.
===============================================================
PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
===============================================================
Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION
Record:
- `b4 dig -c dd64afb32c4d8` →
https://patch.msgid.link/20260617182227.965603-1-ruoyuw560@gmail.com
- `b4 dig -a`: **v1 only** (no later revisions)
- Thread (mbox via `b4 dig -m`):
- Patch submitted 2026-06-17 by Ruoyu Wang
- Maintainer reply 2026-07-23: “The patch was applied, thank you.”
- **No NAK, no stable nomination, no reviewer risk flags**
- lore.kernel.org HTTP fetch returned **403**; thread recovered via b4
mbox (verified)
Step 4.2: CHECK WHO REVIEWED THE PATCH
Record (`b4 dig -w`):
- To/Cc: Konstantin Komarov, ntfs3@lists.linux.dev, linux-
kernel@vger.kernel.org
- Subsystem maintainer was the recipient and applied it
- No extra Reviewed-by tags
Step 4.3: SEARCH FOR THE BUG REPORT
Record: **No Reported-by, no syzbot, no bugzilla.** Bug is from code
inspection / static reasoning, confirmed by reading the cache-hit path.
No user crash report found.
Step 4.4: CHECK FOR RELATED PATCHES AND SERIES
Record: **Standalone v1 patch**, not part of a series.
Step 4.5: CHECK STABLE MAILING LIST HISTORY
Record: lore.kernel.org/stable HTTP search returned **403**.
**UNVERIFIED** whether stable@ discussed this. b4 thread has no Cc:
stable. Absence of stable discussion is not a negative here.
===============================================================
PHASE 5: CODE SEMANTIC ANALYSIS
===============================================================
Step 5.1: IDENTIFY KEY FUNCTIONS IN THE DIFF
Record: **`attr_wof_frame_info()`** only. Guarded by
`CONFIG_NTFS3_LZX_XPRESS`.
Step 5.2: TRACE CALLERS
Record:
- Sole caller: `ni_read_frame()` in `fs/ntfs3/frecord.c` (~2379), WOF
(Xpress/LZX) branch
- `ni_read_frame()` callers:
- `ni_read_folio_cmpr()` (`frecord.c` ~1987) — compressed `read_folio`
- `ni_decompress_file()` (`frecord.c` ~2087) — decompress on
write/size change
- `ntfs_file_write_iter` path in `file.c` (~1056, ~1121) — extending
valid size / writing compressed files
- `ntfs_read_folio()` (`inode.c` ~850) calls `ni_read_folio_cmpr()` when
`is_compressed(ni)`
Step 5.3: TRACE CALLEES
Record (success cache path does not call these):
`attr_load_runs_range()`, `ntfs_read_run()`, `folio_alloc()`, folio
lock/unlock, `down_write`/`up_write` on `ni->file.run_lock`. Bug is
return-value init, not those callees.
Step 5.4: FOLLOW THE CALL CHAIN
Record:
- Userspace `read()` → VFS `read_folio` → `ntfs_read_folio()` →
`ni_read_folio_cmpr()` → `ni_read_frame()` → `attr_wof_frame_info()`
- **Reachable from userspace** on NTFS volumes with Windows 10+
`compact.exe` WOF files (`CONFIG_NTFS3_LZX_XPRESS`, Kconfig
“recommended Y”)
- Cache is per-inode (`ni->file.offs_folio`); sequential reads of a
compressed file hit the uninit path **after the first frame on that
offsets page** (typical, not rare)
Step 5.5: SEARCH FOR SIMILAR PATTERNS
Record: ntfs3 has many prior uninit fixes (`5f33da04e6cee` KMSAN,
`a8a3ca23bbd9d`, `57ac2831c8e0f`, etc.). Same class of bug; this
instance was missed until 2026.
===============================================================
PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE
===============================================================
Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?
Record:
- `git describe HEAD` = **v7.3-rc4-27-gf0100363d8c37**
- `make kernelversion` = **7.3.0-rc4**
- `attr_wof_frame_info()` is present; current code already has `int i,
err = 0;` (this commit is an ancestor of HEAD)
- **Buggy pattern existed here** from v5.15 through parent of
`dd64afb32c4d8`
- Bug was **not** introduced after this tree; it is native to this
lineage
Step 6.2: CHECK FOR BACKPORT COMPLICATIONS
Record: **Clean apply.** One-line change to a declaration that has been
`int i, err;` since 2021. Folio vs page rename does not affect this
line.
Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE
Record: This exact fix **is** commit `dd64afb32c4d8` in this checkout.
No different competing fix for the same uninit `err`. Per instructions,
that is not used as “already selected → skip”; it confirms the
maintainer accepted the same one-line change.
===============================================================
PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
===============================================================
Step 7.1: IDENTIFY THE SUBSYSTEM AND ITS CRITICALITY
Record:
- **Subsystem:** `fs/ntfs3` (NTFS3 filesystem)
- **Criticality:** **IMPORTANT** — not core VFS/mm, but a production
filesystem used for Windows volumes, dual-boot, and some distros.
Failure is I/O error / failed reads, not a global panic.
Step 7.2: ASSESS SUBSYSTEM ACTIVITY
Record: Active (regular `ntfs3_for_7.x` pulls, many 2026 fixes). This
particular bug is **old** (2021), not a new-subsystem-only issue.
===============================================================
PHASE 8: IMPACT AND RISK ASSESSMENT
===============================================================
Step 8.1: DETERMINE WHO IS AFFECTED
Record: **Filesystem-specific + config-specific:** `CONFIG_NTFS3_FS` +
`CONFIG_NTFS3_LZX_XPRESS`, users reading WOF-compressed files (Windows
10 `compact` xpress4k/8k/16k/lzx).
Step 8.2: DETERMINE THE TRIGGER CONDITIONS
Record:
- Trigger: read (or decompress-on-write) of a **non-resident** WOF
compressed stream after `offs_folio` already holds the needed offsets
page
- **Common** for sequential reads of a compressed file (page holds many
32/64-bit offsets)
- **Unprivileged users** can trigger it if they can read such files
- Not a race; deterministic once the folio is cached
Step 8.3: DETERMINE THE FAILURE MODE SEVERITY
Record:
- Failure: return of uninitialized `err` to `ni_read_frame()` → `if
(err) goto out1;`
- If stack garbage is non-zero: **read/decompress fails** (EIO-class
userspace error) despite successful offset decode
- If garbage is zero: silent luck
- C2 unsafety / KMSAN-class uninit use
- **Severity: HIGH** (broken reads of compressed files; undefined
behavior). Not a guaranteed oops, not data corruption of written data.
Step 8.4: CALCULATE RISK-BENEFIT RATIO
Record:
- **Benefit:** high for ntfs3+WOF users — fixes real false I/O failures
on a hot cached path
- **Risk:** very low (one initializer)
- **Ratio:** strongly favorable
===============================================================
PHASE 9: FINAL SYNTHESIS
===============================================================
Step 9.1: COMPILE THE EVIDENCE
**FOR backporting:**
- Real uninitialized return on a realistic, common cache-hit path
(verified in source)
- Userspace-reachable via normal reads of WOF-compressed NTFS files
- One-line, obviously correct, maintainer-applied
- Code present in this tree since v5.15; no missing prerequisites
- Matches stable’s uninitialized-data / KMSAN class (even without a
sanitizer report)
**AGAINST:**
- No crash/syzbot/CVE report; failure is typically spurious I/O error,
not panic
- Limited to ntfs3 WOF (`CONFIG_NTFS3_LZX_XPRESS`), not all kernel users
- No explicit Cc: stable (not a valid NO reason in this pipeline)
**UNRESOLVED:**
- Could not HTTP-fetch lore.kernel.org (403); used b4 mbox instead
- No stable@ thread verified
- No KMSAN/syzbot report located for this exact function
Step 9.2: APPLY THE STABLE RULES CHECKLIST
1. Obviously correct and tested? **PASS** — one initializer; maintainer
applied it
2. Fixes a real bug that affects users? **PASS** — uninit `err` on
cached WOF reads
3. Important issue? **PASS** — HIGH: failed reads / UB on compressed
files (not a panic, but user-visible breakage)
4. Small and contained? **PASS** — 1 line, 1 function
5. No new features or APIs? **PASS**
6. Can apply to the local tree? **PASS** — declaration exists; applies
cleanly
Step 9.3: CHECK FOR EXCEPTION CATEGORIES
Record: Not a device-ID/quirk/DT/docs exception. It is a normal uninit
bugfix.
Step 9.4: MAKE YOUR DECISION
This tree contains `attr_wof_frame_info()` and the cached-folio path.
The one-line init is a real, contained fix for returning uninitialized
error codes on WOF compressed reads. It meets stable-kernel rules for
this checkout.
**What the commit solves:** On cache reuse, `err` was never set, so the
function returned stack garbage. Callers abort the read. Initializing
`err = 0` makes the successful cached path return success.
**Risk vs benefit:** Benefit is fixing broken/undefined reads of WOF
files; risk is a single local initializer.
**Concerns:** None on dependencies or apply difficulty. Impact is
ntfs3+WOF only, which is acceptable for a filesystem correctness fix.
Verification:
- [Phase 1] Parsed tags: author + maintainer SOB only; no
Fixes/syzbot/Cc stable
- [Phase 1] Subject/body: initialize `err` for cached offsets folio path
- [Phase 2] Diff: 1 line in `attr_wof_frame_info()`, `int i, err` → `int
i, err = 0`
- [Phase 2] Confirmed cache-hit loop skips
`attr_load_runs_range`/`ntfs_read_run` then `return err`
- [Phase 3] `git blame`: uninit `err` from `be71b5cba2e648` (v5.15-rc1)
- [Phase 3] Folio conversion `c091354d6bf60e` kept uninitialized `err`
- [Phase 3] Author: one ntfs3 commit; applied by Konstantin Komarov
- [Phase 3] Standalone; `git merge-base --is-ancestor dd64afb32c4d8
HEAD` is true
- [Phase 4] `b4 dig -c`: lore msgid
20260617182227.965603-1-ruoyuw560@gmail.com
- [Phase 4] `b4 dig -a`: v1 only
- [Phase 4] `b4 dig -w`: maintainer + ntfs3 list + lkml
- [Phase 4] mbox: maintainer “patch was applied”; no NAK
- [Phase 4] lore HTTP 403 — discussion via b4 only
- [Phase 5] Only caller `ni_read_frame()`; chain from `ntfs_read_folio`
/ `ni_read_folio_cmpr`
- [Phase 5] semcode MCP not available; used grep/read
- [Phase 6] Local tree v7.3-rc4; function present; parent still had `int
i, err;`
- [Phase 7] fs/ntfs3, IMPORTANT, actively maintained
- [Phase 8] Trigger: cached WOF offset folio on compressed file read;
severity HIGH
- UNVERIFIED: stable@ mailing list discussion (HTTP 403)
- UNVERIFIED: no KMSAN/syzbot report found for this exact bug
**YES**
fs/ntfs3/attrib.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/ntfs3/attrib.c b/fs/ntfs3/attrib.c
index 501f2ec153ab8..e500f7be8cc38 100644
--- a/fs/ntfs3/attrib.c
+++ b/fs/ntfs3/attrib.c
@@ -1410,7 +1410,7 @@ int attr_wof_frame_info(struct ntfs_inode *ni, struct ATTRIB *attr,
u8 bytes_per_off;
char *addr;
struct folio *folio;
- int i, err;
+ int i, err = 0;
__le32 *off32;
__le64 *off64;
--
2.53.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH AUTOSEL 6.18-5.15] ntfs3: fix info-leak in ntfs_rename()
[not found] <20261019135441.1420968-1-sashal@kernel.org>
` (4 preceding siblings ...)
2026-10-19 13:51 ` [PATCH AUTOSEL 6.18-6.12] ntfs3: initialize err in attr_wof_frame_info Sasha Levin
@ 2026-10-19 13:51 ` Sasha Levin
5 siblings, 0 replies; 6+ messages in thread
From: Sasha Levin @ 2026-10-19 13:51 UTC (permalink / raw)
To: patches, stable
Cc: Konstantin Komarov, syzbot+905d785c4923bea2c1db, Dmitry Antipov,
Sasha Levin, ntfs3, linux-kernel
From: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
[ Upstream commit 2fa56613b25d0c983ef3ff6d3e865d4254280abe ]
Hard to say about copy_to_user_iter(), but at least the first splat
looks correct. At the end of fill_name_de(), data layout is:
struct NTFS_DE *e = buf;
...
|<- data_size + sizeof(struct NTFS_DE) ->|<- XXX ->|
buf |-----------------------------------------------------------
|<- ALIGN(data_size, 8) + sizeof(struct NTFS_DE) ->| ;; e->size
If 'buf' was allocated with kmalloc(), XXX remains uninitialized and
passed as such to memcpy() called from hdr_insert_de().
So using kzalloc() for all buffers passed to fill_name_de() looks
the simplest and most safe solution. OTOH if someone would have
said that an overhead of PAGE_SIZE'd memset() is too large, more
fine-granted solution is to memset() XXX only.
Reported-by: syzbot+905d785c4923bea2c1db@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=905d785c4923bea2c1db
Signed-off-by: Dmitry Antipov <dmantipov@yandex.ru>
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
This is a real KMSAN kernel infoleak in ntfs3 rename: 8-byte alignment
padding in directory entries is copied from uninitialized `kmalloc()`
memory onto the volume. The local tree is **7.3.0-rc4**
(`v7.3-rc4-27-gf0100363d8c37`); ntfs3 and `fill_name_de()` exist here,
and the fix is small, correct, and reachable from `rename(2)`.
===============================================================
PHASE 1: COMMIT MESSAGE FORENSICS
===============================================================
**Step 1.1: PARSE THE SUBJECT LINE**
Record: **[ntfs3] [fix] info-leak in `ntfs_rename()`**
**Step 1.2: PARSE ALL COMMIT MESSAGE TAGS**
Record:
- **Reported-by:**
`syzbot+905d785c4923bea2c1db@syzkaller.appspotmail.com` (syzbot /
KMSAN)
- **Closes:**
`https://syzkaller.appspot.com/bug?extid=905d785c4923bea2c1db`
- **Signed-off-by:** Dmitry Antipov (author of the analysis/patch);
Konstantin Komarov (ntfs3 maintainer, applied it)
- **No Fixes:** tag on the committed version (v1 on-list had `Fixes:
ca2a04e84af7`, dropped later)
- **No Cc: stable** (expected for this review)
- **No Tested-by / Reviewed-by / Acked-by / Link:** (Closes URL is the
bug tracker)
Notable: syzbot + maintainer SOB.
**Step 1.3: ANALYZE THE COMMIT BODY TEXT**
Record:
- **Bug:** After `fill_name_de()`, `e->size` is 8-byte-aligned
(`ALIGN(data_size, 8) + sizeof(NTFS_DE)`). The pad between `data_size
+ sizeof(NTFS_DE)` and that aligned size (`XXX`) is never written if
`buf` came from `kmalloc()`.
- **Failure mode:** That pad is `memcpy()`’d in `hdr_insert_de()`,
written out with the index/MFT record, then observed as a **KMSAN
kernel-infoleak** when the block is later read into userspace
(`copy_to_user_iter` / `filemap_read`).
- **Root cause (author):** uninitialized alignment padding, not a
`rename()` copy_to_user of the name buffer itself.
- **Fix chosen:** memset only `XXX` (0–7 bytes), instead of
`kzalloc(PATH_MAX)` for every caller.
- **Version info in message:** none.
**Step 1.4: DETECT HIDDEN BUG FIXES**
Record: Not hidden. Subject and body describe a KMSAN infoleak. The
“fine-grained memset” wording is the fix, not cleanup.
===============================================================
PHASE 2: DIFF ANALYSIS
===============================================================
**Step 2.1: INVENTORY THE CHANGES**
Record:
- **File:** `fs/ntfs3/namei.c` only (`+7 / -2`)
- **Function:** `fill_name_de()`
- **Scope:** single-file surgical fix
**Step 2.2: UNDERSTAND THE CODE FLOW CHANGE**
Record:
- **Before:** `e->size = cpu_to_le16(ALIGN(data_size, 8) + sizeof(struct
NTFS_DE));` with no write of the pad.
- **After:** compute `real_size` and `aligned_size`; if they differ,
`memset` the pad; then set `e->size` to `aligned_size`.
- **Path:** every `fill_name_de()` caller (rename still uses
`kmalloc(PATH_MAX)`; create/link/unlink already `kzalloc`).
**Step 2.3: IDENTIFY THE BUG MECHANISM**
Record:
- **Category:** uninitialized data / kernel infoleak (KMSAN)
- **Mechanism:** `hdr_insert_de()` does `memcpy(before, de, de_size)`
with `de_size = le16_to_cpu(de->size)` including alignment pad. Pad
bytes are slab leftovers. They land in the directory index, get
written via `ni_write_inode` → `ntfs_write_bh`, then leak through
`blkdev_read_iter` / `filemap_read`.
**Step 2.4: ASSESS THE FIX QUALITY**
Record:
- Obviously correct: pad length is `ALIGN(x,8)-x` ∈ [0,7]; memset only
when needed.
- Minimal; no API/locking/refcount changes.
- Regression risk very low: those bytes were garbage; NTFS index entries
are 8-byte aligned and pad should be zero.
- Completeness: this matches the KMSAN “Bytes 404-407 of 1536” (4-byte
pad). `ni_add_name()` still fills `ref`/`home`/`dup` after
`fill_name_de()`, so this is not trying to zero the whole
`ATTR_FILE_NAME`.
===============================================================
PHASE 3: GIT HISTORY INVESTIGATION
===============================================================
**Step 3.1: BLAME THE CHANGED LINES**
Record:
- Alignment-in-`e->size` comes from **4342306f0f0d5** (`fs/ntfs3: Add
file operations and implementation`, 2021-08-13; originally
`QuadAlign(data_size)`).
- **fa3cacf544636** only switched `QuadAlign` to `ALIGN`.
- Bug present since ntfs3 was added (**v5.15-era**).
**Step 3.2: FOLLOW THE FIXES: TAG**
Record: Committed version has **no Fixes:** tag. On-list v1 used `Fixes:
ca2a04e84af7` (`ntfs: ->d_compare() must not block`), which swapped
`__getname()` for `kmalloc()` — both uninitialized. That tag is
**wrong**; the leak is as old as `fill_name_de()`. `ca2a04e84af79`
**is** an ancestor of this HEAD, but is **not** a prerequisite for the
memset.
**Step 3.3: CHECK FILE HISTORY**
Record: Recent `namei.c` work is ADS, mkdir, vfs `->create`. **No
follow-up** to this infoleak. Not patch X/Y. Standalone.
**Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS**
Record: Dmitry Antipov has no other recent ntfs3 commits in this
history. Konstantin Komarov is the ntfs3 maintainer and applied the
memset form.
**Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS**
Record: Uses existing `fill_name_de`, `ALIGN`, `fname_full_size`,
`NTFS_DE`. **Applies standalone.** `ntfs_rename` can keep `kmalloc`.
===============================================================
PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
===============================================================
**Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION**
Record:
- **b4 dig:**
https://patch.msgid.link/20260609123618.712961-1-dmantipov@yandex.ru
- **Series:** v1 only (`[PATCH] ntfs3: fix info-leak in ntfs_rename()`),
2026-06-09
- **v1 diff:** `kmalloc` → `kzalloc` in `ntfs_rename` only
- **Al Viro** asked how that buffer reaches `copy_to_user_iter()`, then
guessed a deeper metadata/bh reuse bug
- **Dmitry** explained the pad/`hdr_insert_de` path and posted the
memset version (what landed)
- **Konstantin (2026-07-15):** “The patch is applied, thank you.” No
NAK. No Cc: stable in-thread.
**Step 4.2: CHECK WHO REVIEWED THE PATCH**
Record (**b4 dig -w**): Dmitry Antipov, Konstantin Komarov, Al Viro,
`ntfs3@lists.linux.dev`, `lvc-project@linuxtesting.org`, syzbot.
Maintainer applied it after VFS questions.
**Step 4.3: SEARCH FOR THE BUG REPORT**
Record (syzkaller):
- Title: **KMSAN: kernel-infoleak in filemap_read**
- First crash 2023-12-20; C repro; **9090** crashes; prio:high
- Uninit created at `kmalloc` in `ntfs_rename`; stored in
`hdr_insert_de` → `indx_insert_into_root` → `ni_rename`; written via
`ntfs_write_bh`; copied out via `blkdev_read_iter` (sample: **udevd**)
- Syzbot lists **2fa56613b25d** as the fix commit
**Step 4.4: CHECK FOR RELATED PATCHES AND SERIES**
Record: Standalone. Related local infoleak: `35d1ea92c7d94` (LZNT
decompress) — different path.
**Step 4.5: CHECK STABLE MAILING LIST HISTORY**
Record: **UNVERIFIED** — lore.kernel.org/stable returned 403. No local
evidence this was rejected for stable.
===============================================================
PHASE 5: CODE SEMANTIC ANALYSIS
===============================================================
**Step 5.1: KEY FUNCTIONS**
Record: `fill_name_de()`; leak sink `hdr_insert_de()`; user entry
`ntfs_rename()` → `ni_rename()` → `ni_add_name()` →
`indx_insert_entry()`.
**Step 5.2: TRACE CALLERS**
Record (`git grep`):
- `ntfs_rename()` — `rename(2)`; `kmalloc(PATH_MAX)` (**the syzbot
path**)
- `ntfs_create_inode()` — create/mkdir/symlink; already `kzalloc`
- `ntfs_link_inode()` — `link(2)`; already `kzalloc`
- `ntfs_unlink_inode()` — unlink/rmdir; already `kzalloc`
**Step 5.3: TRACE CALLEES**
Record: `ntfs_nls_to_utf16` / `memcpy` for the name; `fname_full_size`;
then `memset` of pad.
**Step 5.4: FOLLOW THE CALL CHAIN**
Record: Userspace `rename()` on ntfs3 → directory index insert →
MFT/index write → later `read()` of the block device (udev) copies pad
to userspace. **Reachable from a normal syscall** on a mounted ntfs3
volume.
**Step 5.5: SEARCH FOR SIMILAR PATTERNS**
Record: Other `fill_name_de` callers already `kzalloc`. Rename is the
remaining `kmalloc` caller; fixing `fill_name_de` covers all of them.
===============================================================
PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE
===============================================================
**Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?**
Record:
- Tree: **7.3.0-rc4** (`git describe`: `v7.3-rc4-27-gf0100363d8c37`)
- `fs/ntfs3/namei.c` and `fill_name_de()` exist
- Bug introduced **4342306f0f0d5** (ntfs3 add, ~5.15); **is ancestor of
HEAD**
- Current `fill_name_de()` **already contains** this memset (`git merge-
base --is-ancestor 2fa56613b25d0 HEAD` → yes)
- `ntfs_rename` still does `de = kmalloc(PATH_MAX, GFP_KERNEL)` — the
memset is what stops the leak
**Step 6.2: CHECK FOR BACKPORT COMPLICATIONS**
Record: Hunk is local to `fill_name_de` and matches the long-standing
function shape (`QuadAlign`/`ALIGN` + `e->size`). **Clean apply** on any
tree with original `fill_name_de`. No structural prereq.
**Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE**
Record: This **is** the fix (`2fa56613b25d0`). No later replacement.
LZNT infoleak is separate.
===============================================================
PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
===============================================================
**Step 7.1: SUBSYSTEM AND CRITICALITY**
Record: **fs/ntfs3** — **IMPORTANT** (in-tree RW NTFS since 5.15; not
core VFS, but a real production FS). Not staging.
**Step 7.2: SUBSYSTEM ACTIVITY**
Record: Actively maintained (Paragon / Komarov); mix of features and
sanitizer/bounds fixes.
===============================================================
PHASE 8: IMPACT AND RISK ASSESSMENT
===============================================================
**Step 8.1: WHO IS AFFECTED**
Record: **Filesystem-specific** — `CONFIG_NTFS3_FS` users who rename on
ntfs3. Trigger is rename, not an obscure ioctl.
**Step 8.2: TRIGGER CONDITIONS**
Record: `rename(2)` when the new name is inserted into a directory
index. Common. Unprivileged users with write access to an ntfs3 mount
can write slab leftovers into on-disk index entries. The syzbot read
path is `blkdev_read_iter` (typically privileged udev), but the
**confidentiality failure is writing kernel heap into the volume**.
**Step 8.3: FAILURE MODE SEVERITY**
Record: **KMSAN kernel-infoleak** of uninitialized kmalloc memory onto
disk / into a later userspace read. **Severity: HIGH** (security
infoleak; not a panic). Syzbot prio:high; C repro; thousands of crashes.
**Step 8.4: RISK-BENEFIT RATIO**
Record:
- **Benefit:** high — stops a real, fuzzer-reproduced kernel infoleak on
a syscall path
- **Risk:** very low — 5-line memset of 0–7 pad bytes
- **Ratio:** strongly favors taking the fix
===============================================================
PHASE 9: FINAL SYNTHESIS
===============================================================
**Step 9.1: COMPILE THE EVIDENCE**
FOR:
- Syzbot KMSAN kernel-infoleak with C repro and a clear `kmalloc` →
`hdr_insert_de` → disk → `copy_to_user` chain
- Small, obviously correct memset of alignment padding
- ntfs3 maintainer applied it after discussion with Al Viro
- Bug present since ntfs3 introduction; code exists in this tree
- No new API, no locking, no series dependencies
- Rename still uses `kmalloc`; without this, the leak remains
AGAINST:
- Al Viro first wondered if `copy_to_user` meant a deeper metadata-reuse
bug; Dmitry’s pad explanation is what was applied, and it matches the
first splat
- Infoleak, not a crash (still stable-worthy)
- lore.kernel.org HTTP 403; stable-list history not independently
fetched
UNRESOLVED:
- Whether older stable series already carried a different zeroing
approach (not this 7.3 tree)
- Whether KMSAN instances still listed as “missing” are stale vs. a
second leak
**Step 9.2: STABLE RULES CHECKLIST**
1. Obviously correct and tested? **PASS** — pad math is local; syzbot +
maintainer apply
2. Fixes a real bug that affects users? **PASS** — KMSAN infoleak, C
repro, udev read of written metadata
3. Important (crash/security/corruption/deadlock)? **PASS** — kernel
infoleak / security, HIGH
4. Small and contained? **PASS** — `fill_name_de` only, ~5 lines
5. No new features or APIs? **PASS**
6. Can apply to the local tree? **PASS** — same function exists; no
missing helpers
**Step 9.3: EXCEPTION CATEGORIES**
Record: None (not an ID/quirk/DT/build/doc exception). It is a normal
memory-safety fix.
**Step 9.4: DECISION**
This tree has ntfs3 and the buggy `fill_name_de`/`ntfs_rename` design.
The change is a contained KMSAN infoleak fix with a documented syscall
trigger. It meets stable criteria on technical merit.
Verification:
- [Phase 1] Tags: syzbot Reported-by + Closes URL; maintainer SOB; no
Fixes on committed form
- [Phase 2] Diff: +7/-2 in `fill_name_de`; memset of `aligned_size -
real_size`
- [Phase 2] `hdr_insert_de` (index.c:873): `memcpy(before, de, de_size)`
with `de_size` from `de->size`
- [Phase 3] Blame: 4342306f0f0d5 introduced QuadAlign size;
fa3cacf544636 switched to ALIGN
- [Phase 3] `git merge-base --is-ancestor 4342306f0f0d5 HEAD` → 0 (bug
origin in this tree)
- [Phase 3] `git merge-base --is-ancestor 2fa56613b25d0 HEAD` → 0 (this
SHA is in HEAD)
- [Phase 3] Original v1 Fixes: ca2a04e84af79 is in HEAD but is not
required for the memset
- [Phase 4] `b4 dig -c 2fa56613b25d0`: lore msgid
`20260609123618.712961-1-dmantipov@yandex.ru`
- [Phase 4] `b4 dig -a`: v1 only; committed code is Dmitry’s follow-up
memset, not v1 kzalloc
- [Phase 4] `b4 dig -w`: ntfs3 list, Komarov, Al Viro, syzbot, lvc-
project
- [Phase 4] mbox: Viro questions; Dmitry pad diagram; Komarov “patch is
applied”
- [Phase 4] WebFetch lore.kernel.org → 403; used b4 mbox instead
- [Phase 4] syzbot: KMSAN infoleak, C repro, uninit at ntfs_rename
kmalloc, store at hdr_insert_de
- [Phase 5] Callers: rename (kmalloc), create/link/unlink (kzalloc)
- [Phase 5] `ni_add_name` fills ref/home/dup after fill_name_de; then
`indx_insert_entry`
- [Phase 6] `git describe HEAD` = v7.3-rc4-27-gf0100363d8c37; `make
kernelversion` = 7.3.0-rc4
- [Phase 6] Current namei.c lines 56–61 already have the memset
- [Phase 8] Failure mode: kernel heap bytes written into NTFS index and
readable via blkdev read
- UNVERIFIED: stable@ mailing-list discussion (lore 403)
**YES**
fs/ntfs3/namei.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/fs/ntfs3/namei.c b/fs/ntfs3/namei.c
index 64cde1a856f44..f547ce82520f8 100644
--- a/fs/ntfs3/namei.c
+++ b/fs/ntfs3/namei.c
@@ -22,7 +22,7 @@ int fill_name_de(struct ntfs_sb_info *sbi, void *buf, const struct qstr *name,
{
int err;
struct NTFS_DE *e = buf;
- u16 data_size;
+ u16 data_size, real_size, aligned_size;
struct ATTR_FILE_NAME *fname = (struct ATTR_FILE_NAME *)(e + 1);
#ifndef CONFIG_NTFS3_64BIT_CLUSTER
@@ -53,7 +53,12 @@ int fill_name_de(struct ntfs_sb_info *sbi, void *buf, const struct qstr *name,
fname->type = FILE_NAME_POSIX;
data_size = fname_full_size(fname);
- e->size = cpu_to_le16(ALIGN(data_size, 8) + sizeof(struct NTFS_DE));
+ real_size = data_size + sizeof(struct NTFS_DE);
+ aligned_size = ALIGN(data_size, 8) + sizeof(struct NTFS_DE);
+ if (aligned_size > real_size)
+ memset((char *)buf + real_size, 0, aligned_size - real_size);
+
+ e->size = cpu_to_le16(aligned_size);
e->key_size = cpu_to_le16(data_size);
e->flags = 0;
e->res = 0;
--
2.53.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-10-19 14:04 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20261019135441.1420968-1-sashal@kernel.org>
2026-10-19 13:48 ` [PATCH AUTOSEL 6.18-5.15] fs/ntfs3: reserve NUL byte when converting UTF-16 names Sasha Levin
2026-10-19 13:48 ` [PATCH AUTOSEL 6.18-5.15] fs/ntfs3: Fix memory leak in indx_find_sort() Sasha Levin
2026-10-19 13:48 ` [PATCH AUTOSEL 6.18-5.15] fs/ntfs3: load ATTR_BITMAP run extents from $MFT extension records Sasha Levin
2026-10-19 13:49 ` [PATCH AUTOSEL 6.18-5.15] fs/ntfs3: fix lseek EINVAL on sparse/compressed files with 64-bit clusters Sasha Levin
2026-10-19 13:51 ` [PATCH AUTOSEL 6.18-6.12] ntfs3: initialize err in attr_wof_frame_info Sasha Levin
2026-10-19 13:51 ` [PATCH AUTOSEL 6.18-5.15] ntfs3: fix info-leak in ntfs_rename() Sasha Levin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox