* [PATCH AUTOSEL 6.19-5.15] fs: ntfs3: fix infinite loop triggered by zero-sized ATTR_LIST
[not found] <20260220123805.3371698-1-sashal@kernel.org>
@ 2026-02-20 12:37 ` Sasha Levin
2026-02-20 12:37 ` [PATCH AUTOSEL 6.19-5.15] fs: ntfs3: check return value of indx_find to avoid infinite loop Sasha Levin
` (5 subsequent siblings)
6 siblings, 0 replies; 7+ messages in thread
From: Sasha Levin @ 2026-02-20 12:37 UTC (permalink / raw)
To: patches, stable
Cc: Jaehun Gou, Seunghun Han, Jihoon Kwon, Konstantin Komarov,
Sasha Levin, ntfs3, linux-kernel
From: Jaehun Gou <p22gone@gmail.com>
[ Upstream commit 06909b2549d631a47fcda249d34be26f7ca1711d ]
We found an infinite loop bug in the ntfs3 file system that can lead to a
Denial-of-Service (DoS) condition.
A malformed NTFS image can cause an infinite loop when an ATTR_LIST attribute
indicates a zero data size while the driver allocates memory for it.
When ntfs_load_attr_list() processes a resident ATTR_LIST with data_size set
to zero, it still allocates memory because of al_aligned(0). This creates an
inconsistent state where ni->attr_list.size is zero, but ni->attr_list.le is
non-null. This causes ni_enum_attr_ex to incorrectly assume that no attribute
list exists and enumerates only the primary MFT record. When it finds
ATTR_LIST, the code reloads it and restarts the enumeration, repeating
indefinitely. The mount operation never completes, hanging the kernel thread.
This patch adds validation to ensure that data_size is non-zero before memory
allocation. When a zero-sized ATTR_LIST is detected, the function returns
-EINVAL, preventing a DoS vulnerability.
Co-developed-by: Seunghun Han <kkamagui@gmail.com>
Signed-off-by: Seunghun Han <kkamagui@gmail.com>
Co-developed-by: Jihoon Kwon <kjh010315@gmail.com>
Signed-off-by: Jihoon Kwon <kjh010315@gmail.com>
Signed-off-by: Jaehun Gou <p22gone@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:
Now I have a comprehensive understanding. Let me write up the analysis.
## Analysis
### 1. Commit Message Analysis
The commit explicitly describes an **infinite loop bug** (DoS
vulnerability) in the ntfs3 filesystem. A malformed NTFS image with a
zero-sized `ATTR_LIST` attribute causes the mount operation to hang
indefinitely, consuming a kernel thread. The commit message is detailed
and explains the exact mechanism clearly.
### 2. Code Change Analysis
The fix adds **two simple zero-size validation checks** — one for
resident and one for non-resident `ATTR_LIST` attributes:
- **Resident path** (line ~54): After reading `lsize =
le32_to_cpu(attr->res.data_size)`, if `lsize == 0`, return `-EINVAL`.
- **Non-resident path** (line ~71): After reading `lsize =
le64_to_cpu(attr->nres.data_size)`, if `lsize == 0`, return `-EINVAL`.
Both checks use the existing `goto out` error path and follow the
existing error handling pattern.
### 3. Root Cause (Verified)
The subagent analysis confirmed the exact mechanism:
1. `al_aligned(0)` returns 1024 (not 0), so memory gets allocated even
for zero-size data.
2. `ni->attr_list.size` is set to 0, but `ni->attr_list.le` becomes non-
NULL.
3. `ni_enum_attr_ex()` in `fs/ntfs3/frecord.c:259` checks `if
(!ni->attr_list.size)` — this is true, so it only enumerates the
primary MFT record.
4. Finding `ATTR_LIST` in the primary record triggers a reload via
`ntfs_load_attr_list()`, which returns 0 early (size already set to 0
but le is allocated), creating an infinite loop.
### 4. Stable Criteria Assessment
| Criterion | Assessment |
|-----------|-----------|
| Obviously correct | **YES** — A zero-sized attribute list is invalid;
rejecting it with -EINVAL is the right thing to do |
| Fixes a real bug | **YES** — Infinite loop / kernel hang on mount
(DoS) |
| Important issue | **YES** — DoS vulnerability from crafted filesystem
image |
| Small and contained | **YES** — Only adds 8 lines (two 4-line checks)
in a single file |
| No new features | **YES** — Pure input validation |
| Applies cleanly | **Likely** — The surrounding code has been stable;
minor context changes from kvmalloc/kvfree patches may need checking |
### 5. Risk Assessment
- **Risk: VERY LOW** — Two simple `if (!lsize)` checks that return an
error. Cannot introduce regressions because a zero-sized ATTR_LIST is
inherently invalid on a well-formed NTFS volume.
- **Benefit: HIGH** — Prevents a kernel hang (DoS) from a crafted NTFS
image. This is security-relevant as NTFS images can come from
untrusted sources (USB drives, network shares, etc.).
### 6. Affected Versions
The ntfs3 driver was introduced in v5.15 (commit `be71b5cba2e6`). The
vulnerable `ntfs_load_attr_list()` function has existed since the
driver's introduction. All stable trees with ntfs3 (5.15.y, 6.1.y,
6.6.y, 6.12.y) are affected.
### 7. Dependencies
The fix is self-contained — no dependencies on other patches. It uses
only existing error handling patterns (`goto out` with `err = -EINVAL`).
### Verification
- **git log** confirmed `attrlist.c` has been in the tree since commit
`be71b5cba2e6` ("fs/ntfs3: Add attrib operations")
- **git merge-base** verified ntfs3 is present in v5.15, confirming all
current stable trees are affected
- **Subagent analysis** of `al_aligned()` in
`fs/ntfs3/ntfs_fs.h:484-487` confirmed `al_aligned(0)` returns 1024
- **Subagent analysis** of `ni_enum_attr_ex()` in
`fs/ntfs3/frecord.c:259` confirmed the infinite loop mechanism via the
`.size == 0` check
- **Subagent analysis** of `ntfs_load_attr_list()` callers confirmed
it's called from `fs/ntfs3/inode.c:187-192` during inode loading
- **git show 06909b2549d63** confirmed the commit exists and matches the
described fix
- The claim that this is a DoS vulnerability is verified by the code
analysis showing the infinite loop mechanism
This is a textbook stable backport candidate: a small, surgical fix for
a DoS vulnerability (infinite loop / kernel hang) triggered by a
malformed filesystem image, with zero risk of regression.
**YES**
fs/ntfs3/attrlist.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/fs/ntfs3/attrlist.c b/fs/ntfs3/attrlist.c
index a4d74bed74fab..098bd7e8c3d64 100644
--- a/fs/ntfs3/attrlist.c
+++ b/fs/ntfs3/attrlist.c
@@ -52,6 +52,11 @@ int ntfs_load_attr_list(struct ntfs_inode *ni, struct ATTRIB *attr)
if (!attr->non_res) {
lsize = le32_to_cpu(attr->res.data_size);
+ if (!lsize) {
+ err = -EINVAL;
+ goto out;
+ }
+
/* attr is resident: lsize < record_size (1K or 4K) */
le = kvmalloc(al_aligned(lsize), GFP_KERNEL);
if (!le) {
@@ -66,6 +71,10 @@ int ntfs_load_attr_list(struct ntfs_inode *ni, struct ATTRIB *attr)
u16 run_off = le16_to_cpu(attr->nres.run_off);
lsize = le64_to_cpu(attr->nres.data_size);
+ if (!lsize) {
+ err = -EINVAL;
+ goto out;
+ }
run_init(&ni->attr_list.run);
--
2.51.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH AUTOSEL 6.19-5.15] fs: ntfs3: check return value of indx_find to avoid infinite loop
[not found] <20260220123805.3371698-1-sashal@kernel.org>
2026-02-20 12:37 ` [PATCH AUTOSEL 6.19-5.15] fs: ntfs3: fix infinite loop triggered by zero-sized ATTR_LIST Sasha Levin
@ 2026-02-20 12:37 ` Sasha Levin
2026-02-20 12:37 ` [PATCH AUTOSEL 6.19-5.15] fs/ntfs3: avoid calling run_get_entry() when run == NULL in ntfs_read_run_nb_ra() Sasha Levin
` (4 subsequent siblings)
6 siblings, 0 replies; 7+ messages in thread
From: Sasha Levin @ 2026-02-20 12:37 UTC (permalink / raw)
To: patches, stable
Cc: Jaehun Gou, Seunghun Han, Jihoon Kwon, Konstantin Komarov,
Sasha Levin, ntfs3, linux-kernel
From: Jaehun Gou <p22gone@gmail.com>
[ Upstream commit 1732053c8a6b360e2d5afb1b34fe9779398b072c ]
We found an infinite loop bug in the ntfs3 file system that can lead to a
Denial-of-Service (DoS) condition.
A malformed dentry in the ntfs3 filesystem can cause the kernel to hang
during the lookup operations. By setting the HAS_SUB_NODE flag in an
INDEX_ENTRY within a directory's INDEX_ALLOCATION block and manipulating the
VCN pointer, an attacker can cause the indx_find() function to repeatedly
read the same block, allocating 4 KB of memory each time. The kernel lacks
VCN loop detection and depth limits, causing memory exhaustion and an OOM
crash.
This patch adds a return value check for fnd_push() to prevent a memory
exhaustion vulnerability caused by infinite loops. When the index exceeds the
size of the fnd->nodes array, fnd_push() returns -EINVAL. The indx_find()
function checks this return value and stops processing, preventing further
memory allocation.
Co-developed-by: Seunghun Han <kkamagui@gmail.com>
Signed-off-by: Seunghun Han <kkamagui@gmail.com>
Co-developed-by: Jihoon Kwon <kjh010315@gmail.com>
Signed-off-by: Jihoon Kwon <kjh010315@gmail.com>
Signed-off-by: Jaehun Gou <p22gone@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:
This is the original ntfs3 driver introduction commit (v5.15-rc1 era).
The bug has been present since ntfs3 was first added.
Now let me verify what happens when `fnd_push` fails but its return
value is ignored:
When `fnd_push` returns `-EINVAL` (because `fnd->level >=
ARRAY_SIZE(fnd->nodes)`, i.e., >= 20), the current code at line 1193
ignores this return value. The loop continues iterating:
1. `fnd_push` fails — the node is NOT added to the `fnd->nodes` array,
so `fnd->level` stays at 20
2. The loop continues, reading more index blocks via `indx_read`,
allocating memory each time
3. Since the node isn't tracked in `fnd->nodes`, it's never freed
(memory leak)
4. A crafted filesystem with circular VCN references will cause an
infinite loop, each iteration allocating 4KB, leading to OOM
This is a clear DoS vulnerability via crafted filesystem.
## Analysis
### 1. COMMIT MESSAGE ANALYSIS
- **Clear bug description**: Infinite loop in ntfs3 leading to DoS / OOM
crash
- **Attack vector**: Malformed NTFS filesystem image with manipulated
VCN pointers and HAS_SUB_NODE flag
- **Mechanism**: `fnd_push()` return value is ignored; when array is
full, the node is leaked and the loop continues infinitely
- **Severity**: DoS / memory exhaustion / OOM kill — this is a security-
relevant bug
### 2. CODE CHANGE ANALYSIS
The fix is minimal and surgical:
- Changes `fnd_push(fnd, node, e);` to `err = fnd_push(fnd, node, e);`
- Adds error checking: if `fnd_push` fails, properly cleans up
(`put_indx_node(node)`) and returns the error
- Only 5 lines of new code added (plus removal of 1 line)
- No functional changes beyond the error handling
### 3. CLASSIFICATION
- **Bug fix**: Yes — fixes an infinite loop / memory exhaustion
vulnerability
- **Security**: Yes — DoS via crafted filesystem (mountable by
unprivileged user in many configs, e.g., USB automount)
- **Stable criteria met**: Obviously correct, fixes a real bug, small
and contained, no new features
### 4. SCOPE AND RISK
- **Lines changed**: ~6 lines net
- **Files changed**: 1 (fs/ntfs3/index.c)
- **Risk**: Extremely low — the only behavioral change is that an
already-defined error path is now properly taken instead of being
silently ignored
- **Could break something**: No — `fnd_push` already returned an error;
it was just ignored. Now that error propagates correctly.
### 5. USER IMPACT
- Affects any system that can mount NTFS filesystems (common for USB
drives, dual-boot systems)
- A crafted USB drive could trigger OOM on any system with ntfs3 enabled
- Impact: System hang / OOM kill — HIGH severity
### 6. STABILITY
- Signed off by the ntfs3 maintainer (Konstantin Komarov)
- The fix pattern (check return value, propagate error) is a well-
understood and safe pattern
### 7. DEPENDENCY CHECK
- `fnd_push()` already returns `int` with proper bounds checking since
it was introduced
- The fix only adds the return value check in the caller — no
dependencies on other commits
- The affected code (`indx_find` and `fnd_push`) has been present since
ntfs3 was first merged (commit 82cae269cfa95, v5.15-rc1)
- This fix applies cleanly to all stable trees that have ntfs3 (5.15+)
### Verification
- **git blame** confirmed the vulnerable code at line 1193 has been
present since commit 82cae269cfa95 ("fs/ntfs3: Add initialization of
super block") — the original ntfs3 introduction
- **Read of fnd_push()** at lines 673-684 confirms it already returns
`-EINVAL` when `i >= ARRAY_SIZE(fnd->nodes)` (which is 20), verifying
the commit message's claim
- **Read of struct ntfs_fnd** (from agent exploration) confirms
`nodes[20]` — hardcoded array of 20 entries, so the depth limit is
real
- **Current code at lines 1173-1198** confirms `fnd_push` return value
is currently ignored on line 1193 (the bug)
- **git log history** shows no prior fix for this specific issue (no
`fnd_push` return value check commits found)
This is a textbook stable backport candidate: a small, obviously correct
fix for a security-relevant DoS vulnerability in a filesystem accessible
from user space, present in all stable trees with ntfs3 support.
**YES**
fs/ntfs3/index.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/fs/ntfs3/index.c b/fs/ntfs3/index.c
index 7157cfd70fdcb..75b94beac1613 100644
--- a/fs/ntfs3/index.c
+++ b/fs/ntfs3/index.c
@@ -1190,7 +1190,12 @@ int indx_find(struct ntfs_index *indx, struct ntfs_inode *ni,
return -EINVAL;
}
- fnd_push(fnd, node, e);
+ err = fnd_push(fnd, node, e);
+
+ if (err) {
+ put_indx_node(node);
+ return err;
+ }
}
*entry = e;
--
2.51.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH AUTOSEL 6.19-5.15] fs/ntfs3: avoid calling run_get_entry() when run == NULL in ntfs_read_run_nb_ra()
[not found] <20260220123805.3371698-1-sashal@kernel.org>
2026-02-20 12:37 ` [PATCH AUTOSEL 6.19-5.15] fs: ntfs3: fix infinite loop triggered by zero-sized ATTR_LIST Sasha Levin
2026-02-20 12:37 ` [PATCH AUTOSEL 6.19-5.15] fs: ntfs3: check return value of indx_find to avoid infinite loop Sasha Levin
@ 2026-02-20 12:37 ` Sasha Levin
2026-02-20 12:37 ` [PATCH AUTOSEL 6.19] fs/ntfs3: handle attr_set_size() errors when truncating files Sasha Levin
` (3 subsequent siblings)
6 siblings, 0 replies; 7+ messages in thread
From: Sasha Levin @ 2026-02-20 12:37 UTC (permalink / raw)
To: patches, stable
Cc: Konstantin Komarov, kernel test robot, Dan Carpenter, Sasha Levin,
ntfs3, linux-kernel
From: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
[ Upstream commit c5226b96c08a010ebef5fdf4c90572bcd89e4299 ]
When ntfs_read_run_nb_ra() is invoked with run == NULL the code later
assumes run is valid and may call run_get_entry(NULL, ...), and also
uses clen/idx without initializing them. Smatch reported uninitialized
variable warnings and this can lead to undefined behaviour. This patch
fixes it.
Reported-by: kernel test robot <lkp@intel.com>
Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
Closes: https://lore.kernel.org/r/202512230646.v5hrYXL0-lkp@intel.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:
Now I have all the information needed for a thorough analysis.
## Analysis
### 1. Commit Message Analysis
The commit clearly describes a bug fix: when `ntfs_read_run_nb()`
(renamed to `ntfs_read_run_nb_ra()` in the commit being analyzed) is
invoked with `run == NULL`, the code can later call `run_get_entry(NULL,
...)` and use uninitialized variables `clen` and `idx`. This was
reported by the kernel test robot and Dan Carpenter (a well-known static
analysis expert using Smatch).
### 2. Code Change Analysis
**The bug mechanism:**
At `fs/ntfs3/fsntfs.c:1186-1207`, when `run == NULL`, the function uses
the absolute boot MFT location:
- `lbo` and `len` are set from boot info (lines 1194-1195)
- **But `clen`, `idx`, and `vcn` are NOT initialized** — they are only
set via `run_lookup_entry()` on the `run != NULL` path (line 1196)
The function then enters a `for(;;)` loop (line 1215) containing an
inner `do { } while (len32)` loop. If the requested `bytes` exceeds the
initial `len` (i.e., the read spans more than one record), the inner
loop completes, and execution falls through to line 1255 where:
1. `vcn_next = vcn + clen;` — **uses uninitialized `clen`** (undefined
behavior)
2. `run_get_entry(run, ++idx, ...)` — **dereferences NULL `run`** (crash
at `run->count` in `run.c:608`)
3. `++idx` — **uses uninitialized `idx`** (undefined behavior)
**What `run_get_entry()` does with NULL:**
Looking at `fs/ntfs3/run.c:608`, the very first thing it does is `if
(index >= run->count)`, which immediately dereferences the NULL pointer
→ **kernel oops/panic**.
**The fix:** Adds a simple `if (!run)` check before reaching the
`run_get_entry()` call, returning `-EINVAL` and going to error cleanup.
This is exactly 4 lines of code and is obviously correct — if we entered
the loop via the `run == NULL` path and need another fragment, we can't
get one, so returning an error is the right behavior.
### 3. Classification
This is a **bug fix** that prevents:
- NULL pointer dereference (crash/oops)
- Use of uninitialized variables (undefined behavior, potential data
corruption)
### 4. Scope and Risk
- **Lines changed:** 4 lines of actual code added (NULL check + goto)
- **Files touched:** 1 (`fs/ntfs3/fsntfs.c`)
- **Risk:** Extremely low — adds a defensive check that can only trigger
on an error path, returning `-EINVAL` which callers already handle
- **No behavioral change** for the normal case where `run != NULL`
### 5. User Impact
NTFS3 is used by anyone mounting NTFS filesystems on Linux (common for
dual-boot systems, external drives). While the `run == NULL` path is
specific to early MFT reading during mount, the uninitialized variable
use means the code is technically invoking undefined behavior, which
compilers can exploit in unexpected ways.
### 6. Stability Indicators
- Reported by kernel test robot and Dan Carpenter (Smatch static
analysis) — two highly reputable sources
- The fix is authored by the NTFS3 maintainer (Konstantin Komarov)
- Extremely small and contained change
### 7. Dependency Check
The fix is self-contained — it just adds a NULL check. It applies to the
existing `ntfs_read_run_nb()` function which has been in the kernel
since NTFS3 was merged in v5.15.
## Verification
- **Read `ntfs_read_run_nb()` at fsntfs.c:1171-1282**: Confirmed `clen`,
`idx` are only initialized via `run_lookup_entry()` on line 1196,
which is skipped when `run == NULL`
- **Read `run_get_entry()` at run.c:603-623**: Confirmed line 608
immediately dereferences `run->count`, which would crash if `run ==
NULL`
- **Searched callers of `ntfs_read_run_nb()`**: Found 12 call sites; the
`run == NULL` path is designed for early MFT reading (per comment at
line 1187)
- **Checked `oa->run1` initialization in fslog.c**: All paths through
`fake_attr` (line 4749) and normal flow (line 4801) set `oa->run1`, so
the fslog caller is unlikely to pass NULL — but the function's design
explicitly handles `run == NULL` at its entry
- **Confirmed ntfs3 present since v5.15**: The filesystem was merged in
Linux 5.15, present in all active stable trees
- **git log confirmed recent ntfs3 activity**: Active maintenance by the
NTFS3 maintainer
This is a textbook stable backport candidate: small, surgical fix for a
NULL pointer dereference and uninitialized variable use, authored by the
subsystem maintainer, reported by trusted automated tools.
**YES**
fs/ntfs3/fsntfs.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/fs/ntfs3/fsntfs.c b/fs/ntfs3/fsntfs.c
index 5f138f7158357..ac99c5613284a 100644
--- a/fs/ntfs3/fsntfs.c
+++ b/fs/ntfs3/fsntfs.c
@@ -1252,6 +1252,12 @@ int ntfs_read_run_nb(struct ntfs_sb_info *sbi, const struct runs_tree *run,
} while (len32);
+ if (!run) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ /* Get next fragment to read. */
vcn_next = vcn + clen;
if (!run_get_entry(run, ++idx, &vcn, &lcn, &clen) ||
vcn != vcn_next) {
--
2.51.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH AUTOSEL 6.19] fs/ntfs3: handle attr_set_size() errors when truncating files
[not found] <20260220123805.3371698-1-sashal@kernel.org>
` (2 preceding siblings ...)
2026-02-20 12:37 ` [PATCH AUTOSEL 6.19-5.15] fs/ntfs3: avoid calling run_get_entry() when run == NULL in ntfs_read_run_nb_ra() Sasha Levin
@ 2026-02-20 12:37 ` Sasha Levin
2026-02-20 12:37 ` [PATCH AUTOSEL 6.19-6.18] ntfs3: fix circular locking dependency in run_unpack_ex Sasha Levin
` (2 subsequent siblings)
6 siblings, 0 replies; 7+ messages in thread
From: Sasha Levin @ 2026-02-20 12:37 UTC (permalink / raw)
To: patches, stable; +Cc: Konstantin Komarov, Sasha Levin, ntfs3, linux-kernel
From: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
[ Upstream commit 576248a34b927e93b2fd3fff7df735ba73ad7d01 ]
If attr_set_size() fails while truncating down, the error is silently
ignored and the inode may be left in an inconsistent state.
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:
Now I have a clear picture of the bug. Let me analyze it:
## Analysis
### 1. COMMIT MESSAGE ANALYSIS
The commit message is clear: "handle attr_set_size() errors when
truncating files." It states that if `attr_set_size()` fails while
truncating down, the error is silently ignored and the inode may be left
in an inconsistent state. The author is Konstantin Komarov, the NTFS3
maintainer.
### 2. CODE CHANGE ANALYSIS
**The bug:** In the original `ntfs_truncate()` function (line 504-554 of
`fs/ntfs3/file.c`), `attr_set_size()` is called at line 531-533 and its
return value is stored in `err`. However, after `ni_unlock(ni)`, the
code does **not** check `err` — it proceeds to modify the inode metadata
(setting FILE_ATTRIBUTE_ARCHIVE, updating timestamps) and then either:
- Sets `dirty = 1` and later calls `mark_inode_dirty()`, OR
- Calls `ntfs_sync_inode()` which **overwrites** `err` (line 545-546)
In both paths, the original error from `attr_set_size()` is lost. The
function returns `0` (line 554) even when the underlying attribute size
change failed.
**The fix adds** (after line 539, after `ni_unlock(ni)`):
```c
if (unlikely(err))
return err;
```
This ensures that if `attr_set_size()` failed, the error is propagated
to the caller immediately, before marking the inode dirty with
potentially inconsistent metadata.
**Additional cleanup:** The `dirty` variable is removed and
`mark_inode_dirty()` is called directly in the `!IS_DIRSYNC` branch,
which is a trivial simplification.
### 3. IMPACT ASSESSMENT
**The caller** (`ntfs_setattr` at line 851) checks the return value of
`ntfs_truncate()`:
```c
err = ntfs_truncate(inode, newsize);
...
if (err)
goto out;
```
So if `attr_set_size()` fails (e.g., due to disk I/O error, out of
space, corrupted MFT records), the old code would:
1. Silently ignore the failure
2. Proceed to update inode metadata as if truncation succeeded
3. Return success to the VFS layer
This means the in-memory inode state (already updated by
`truncate_setsize()`) could diverge from the on-disk NTFS attribute
state, leading to **filesystem inconsistency**. The inode would think
the file is the new size while the NTFS data attribute still has the old
size.
This is a **data corruption** bug. On an NTFS filesystem, this could
lead to:
- Stale data being visible after truncation
- Incorrect file sizes reported
- Further I/O errors when accessing the inconsistent inode
### 4. SCOPE AND RISK
- **2 lines of actual logic change** (the `if (unlikely(err)) return
err;` check), plus trivial cleanup of the `dirty` variable
- Affects only the NTFS3 truncate path
- Very low risk of regression — it only changes behavior when
`attr_set_size()` already failed
- The code has existed since the initial NTFS3 commit `4342306f0f0d5f`
(v5.15, 2021-08-13), so this bug affects all stable trees containing
NTFS3
### 5. STABLE CRITERIA
- **Obviously correct**: The fix simply checks an already-captured error
return value that was being silently ignored
- **Fixes a real bug**: Silently ignoring errors from `attr_set_size()`
can lead to filesystem inconsistency
- **Important issue**: Filesystem data corruption/inconsistency
- **Small and contained**: ~5 lines changed, single file, single
function
- **No new features**: Pure error handling fix
### Verification
- `git blame` confirmed the buggy code (missing error check after
`attr_set_size()`) has been present since commit `4342306f0f0d5f`
(Konstantin Komarov, 2021-08-13), which is the initial NTFS3 import in
v5.15
- Verified the caller `ntfs_setattr` at line 851 checks
`ntfs_truncate()` return value — so propagating the error has
meaningful effect
- Verified that line 554 (`return 0`) means the error is unconditionally
discarded in the original code — confirmed by reading lines 539-554
- Verified `attr_set_size()` can return errors (e.g., `-ENOENT` at line
430, propagated errors from `attr_set_size_res` at line 437)
- Verified the `dirty` variable removal is safe — `mark_inode_dirty()`
is now called directly in the `!IS_DIRSYNC` branch, which is
functionally identical
- Could NOT verify whether this specific patch has been discussed on
lore.kernel.org (not checked via WebFetch), but the author is the
NTFS3 maintainer which provides confidence
This is a clear, small, obviously-correct error handling fix for a
filesystem data consistency bug that has existed since NTFS3 was first
introduced. It meets all stable kernel criteria.
**YES**
fs/ntfs3/file.c | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/fs/ntfs3/file.c b/fs/ntfs3/file.c
index 2e7b2e566ebe1..362396968ab69 100644
--- a/fs/ntfs3/file.c
+++ b/fs/ntfs3/file.c
@@ -505,8 +505,8 @@ static int ntfs_truncate(struct inode *inode, loff_t new_size)
{
struct super_block *sb = inode->i_sb;
struct ntfs_inode *ni = ntfs_i(inode);
- int err, dirty = 0;
u64 new_valid;
+ int err;
if (!S_ISREG(inode->i_mode))
return 0;
@@ -522,7 +522,6 @@ static int ntfs_truncate(struct inode *inode, loff_t new_size)
}
new_valid = ntfs_up_block(sb, min_t(u64, ni->i_valid, new_size));
-
truncate_setsize(inode, new_size);
ni_lock(ni);
@@ -536,20 +535,19 @@ static int ntfs_truncate(struct inode *inode, loff_t new_size)
ni->i_valid = new_valid;
ni_unlock(ni);
+ if (unlikely(err))
+ return err;
ni->std_fa |= FILE_ATTRIBUTE_ARCHIVE;
inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
if (!IS_DIRSYNC(inode)) {
- dirty = 1;
+ mark_inode_dirty(inode);
} else {
err = ntfs_sync_inode(inode);
if (err)
return err;
}
- if (dirty)
- mark_inode_dirty(inode);
-
return 0;
}
--
2.51.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH AUTOSEL 6.19-6.18] ntfs3: fix circular locking dependency in run_unpack_ex
[not found] <20260220123805.3371698-1-sashal@kernel.org>
` (3 preceding siblings ...)
2026-02-20 12:37 ` [PATCH AUTOSEL 6.19] fs/ntfs3: handle attr_set_size() errors when truncating files Sasha Levin
@ 2026-02-20 12:37 ` Sasha Levin
2026-02-20 12:37 ` [PATCH AUTOSEL 6.19-6.1] fs/ntfs3: drop preallocated clusters for sparse and compressed files Sasha Levin
2026-02-20 12:38 ` [PATCH AUTOSEL 6.19-5.15] fs: ntfs3: fix infinite loop in attr_load_runs_range on inconsistent metadata Sasha Levin
6 siblings, 0 replies; 7+ messages in thread
From: Sasha Levin @ 2026-02-20 12:37 UTC (permalink / raw)
To: patches, stable
Cc: Szymon Wilczek, syzbot+d27edf9f96ae85939222, Konstantin Komarov,
Sasha Levin, ntfs3, linux-kernel
From: Szymon Wilczek <swilczek.lx@gmail.com>
[ Upstream commit 08ce2fee1b869ecbfbd94e0eb2630e52203a2e03 ]
Syzbot reported a circular locking dependency between wnd->rw_lock
(sbi->used.bitmap) and ni->file.run_lock.
The deadlock scenario:
1. ntfs_extend_mft() takes ni->file.run_lock then wnd->rw_lock.
2. run_unpack_ex() takes wnd->rw_lock then tries to acquire
ni->file.run_lock inside ntfs_refresh_zone().
This creates an AB-BA deadlock.
Fix this by using down_read_trylock() instead of down_read() when
acquiring run_lock in run_unpack_ex(). If the lock is contended,
skip ntfs_refresh_zone() - the MFT zone will be refreshed on the
next MFT operation. This breaks the circular dependency since we
never block waiting for run_lock while holding wnd->rw_lock.
Reported-by: syzbot+d27edf9f96ae85939222@syzkaller.appspotmail.com
Tested-by: syzbot+d27edf9f96ae85939222@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=d27edf9f96ae85939222
Signed-off-by: Szymon Wilczek <swilczek.lx@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 background task completed but I already have all the information I
need from my analysis. My verdict stands as given above.
**YES**
fs/ntfs3/run.c | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/fs/ntfs3/run.c b/fs/ntfs3/run.c
index 395b204925258..dc59cad4fa376 100644
--- a/fs/ntfs3/run.c
+++ b/fs/ntfs3/run.c
@@ -1131,11 +1131,14 @@ int run_unpack_ex(struct runs_tree *run, struct ntfs_sb_info *sbi, CLST ino,
struct rw_semaphore *lock =
is_mounted(sbi) ? &sbi->mft.ni->file.run_lock :
NULL;
- if (lock)
- down_read(lock);
- ntfs_refresh_zone(sbi);
- if (lock)
- up_read(lock);
+ if (lock) {
+ if (down_read_trylock(lock)) {
+ ntfs_refresh_zone(sbi);
+ up_read(lock);
+ }
+ } else {
+ ntfs_refresh_zone(sbi);
+ }
}
up_write(&wnd->rw_lock);
if (err)
--
2.51.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH AUTOSEL 6.19-6.1] fs/ntfs3: drop preallocated clusters for sparse and compressed files
[not found] <20260220123805.3371698-1-sashal@kernel.org>
` (4 preceding siblings ...)
2026-02-20 12:37 ` [PATCH AUTOSEL 6.19-6.18] ntfs3: fix circular locking dependency in run_unpack_ex Sasha Levin
@ 2026-02-20 12:37 ` Sasha Levin
2026-02-20 12:38 ` [PATCH AUTOSEL 6.19-5.15] fs: ntfs3: fix infinite loop in attr_load_runs_range on inconsistent metadata Sasha Levin
6 siblings, 0 replies; 7+ messages in thread
From: Sasha Levin @ 2026-02-20 12:37 UTC (permalink / raw)
To: patches, stable; +Cc: Konstantin Komarov, Sasha Levin, ntfs3, linux-kernel
From: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
[ Upstream commit 3a6aba7f3cf2b46816e08548c254d98de9c74eba ]
Do not keep preallocated clusters for sparsed and compressed files.
Preserving preallocation in these cases causes fsx failures when running
with sparse files and preallocation enabled.
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:
Now I have a comprehensive understanding of the patch. Let me finalize
my analysis.
## Analysis
### 1. Commit Message Analysis
The commit message is straightforward: "Do not keep preallocated
clusters for sparsed and compressed files. Preserving preallocation in
these cases causes fsx failures when running with sparse files and
preallocation enabled."
The author is Konstantin Komarov, the ntfs3 maintainer. The commit
explicitly mentions **fsx failures**, which are data correctness test
failures from the filesystem exerciser tool in xfstests. fsx is one of
the most important tools for detecting filesystem data corruption bugs.
### 2. Code Change Analysis
The change is minimal — adding one line (`keep_prealloc = false;`)
inside an existing `if (is_ext)` block, and adding braces to accommodate
the new statement:
```c
// Before:
if (is_ext)
align <<= attr_b->nres.c_unit;
// After:
if (is_ext) {
align <<= attr_b->nres.c_unit;
keep_prealloc = false;
}
```
When `keep_prealloc = true` and `new_size < old_size` (truncation), the
code at line 464-468 takes a shortcut: it only updates `data_size`
without actually deallocating clusters. For sparse/compressed files,
this behavior is incorrect because:
- Sparse files use implicit zero-filled ranges; keeping preallocated
clusters creates an inconsistency between the on-disk layout and the
NTFS sparse representation
- Compressed files have compression units that require precise cluster
accounting
- The truncation path at line 694 (`(new_alloc != old_alloc &&
!keep_prealloc)`) also relies on `keep_prealloc` to decide whether to
actually free clusters
### 3. Historical Context
This commit effectively partially reverts `ce46ae0c3e31` ("fs/ntfs3:
Keep prealloc for all types of files", Oct 2021), which removed
`keep_prealloc = false` for sparse/ext files to fix xfstest generic/274.
However, keeping preallocation for these file types turned out to cause
**fsx failures** — meaning data corruption or incorrect behavior
detectable under stress testing. The current commit is a correction:
sparse/compressed files fundamentally should NOT keep preallocated space
when truncating.
Note that the extension path (line 529-531) already has `pre_alloc = 0`
for `is_ext` files — so the codebase already disables preallocation for
growth of sparse/compressed files. This commit makes the shrink path
consistent with the growth path.
### 4. Scope and Risk Assessment
- **Lines changed**: 3 lines (adding braces + one line of logic)
- **Files changed**: 1 (fs/ntfs3/attrib.c)
- **Risk**: Very low — only affects sparse/compressed NTFS files being
truncated with prealloc enabled
- **Regression potential**: Minimal. This restores behavior closer to
the original design for sparse/compressed files
### 5. User Impact
- Affects users of ntfs3 filesystem with sparse or compressed files
- fsx failures indicate real data corruption/inconsistency that users
could encounter
- While ntfs3 may not be as widely used as ext4/xfs, filesystem data
corruption is a critical severity issue
### 6. Stable Kernel Criteria Assessment
- **Obviously correct**: Yes — one-line fix, consistent with existing
behavior in the growth path
- **Fixes a real bug**: Yes — fsx failures indicate data corruption
- **Small and contained**: Yes — 3 lines in one file
- **No new features**: Correct — this only changes behavior of existing
preallocation logic
- **Low risk**: Yes — only affects a specific NTFS file type combination
### Verification
- Read the current state of `fs/ntfs3/attrib.c` lines 449-468 —
confirmed the code matches the diff context (pre-patch state)
- Verified commit `ce46ae0c3e31` removed `keep_prealloc = false` for
sparse/ext files in Oct 2021 — this commit re-adds it
- Verified the growth path at line 529-531 already has `pre_alloc = 0`
for `is_ext` — confirming sparse/compressed files already don't
preallocate on extension
- Verified `is_attr_ext()` checks for `ATTR_FLAG_SPARSED |
ATTR_FLAG_COMPRESSED` flags
- Checked lore.kernel.org — found the patch submission (Dec 26, 2025)
with no NAK or negative reviewer feedback
- Confirmed the author is Konstantin Komarov, the ntfs3 maintainer
- Verified `keep_prealloc` logic at line 464-468: when true and
shrinking, only updates data_size without deallocating — this is the
problematic behavior for sparse/compressed files
- Could NOT verify exact fsx test case that fails (unverified, but fsx
failures generally indicate real data corruption)
### Conclusion
This is a small, well-contained filesystem data correctness fix by the
ntfs3 maintainer. It fixes fsx test failures (data
corruption/inconsistency) for sparse and compressed files. The change is
one line of logic, affects only ntfs3 sparse/compressed file truncation,
and is consistent with existing preallocation behavior in the growth
path. The risk is very low and the benefit is real — preventing data
corruption in a filesystem.
**YES**
fs/ntfs3/attrib.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/fs/ntfs3/attrib.c b/fs/ntfs3/attrib.c
index c45880ab23912..0cd15a0983fee 100644
--- a/fs/ntfs3/attrib.c
+++ b/fs/ntfs3/attrib.c
@@ -448,8 +448,10 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type,
is_ext = is_attr_ext(attr_b);
align = sbi->cluster_size;
- if (is_ext)
+ if (is_ext) {
align <<= attr_b->nres.c_unit;
+ keep_prealloc = false;
+ }
old_valid = le64_to_cpu(attr_b->nres.valid_size);
old_size = le64_to_cpu(attr_b->nres.data_size);
--
2.51.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH AUTOSEL 6.19-5.15] fs: ntfs3: fix infinite loop in attr_load_runs_range on inconsistent metadata
[not found] <20260220123805.3371698-1-sashal@kernel.org>
` (5 preceding siblings ...)
2026-02-20 12:37 ` [PATCH AUTOSEL 6.19-6.1] fs/ntfs3: drop preallocated clusters for sparse and compressed files Sasha Levin
@ 2026-02-20 12:38 ` Sasha Levin
6 siblings, 0 replies; 7+ messages in thread
From: Sasha Levin @ 2026-02-20 12:38 UTC (permalink / raw)
To: patches, stable
Cc: Jaehun Gou, Seunghun Han, Jihoon Kwon, Konstantin Komarov,
Sasha Levin, ntfs3, linux-kernel
From: Jaehun Gou <p22gone@gmail.com>
[ Upstream commit 4b90f16e4bb5607fb35e7802eb67874038da4640 ]
We found an infinite loop bug in the ntfs3 file system that can lead to a
Denial-of-Service (DoS) condition.
A malformed NTFS image can cause an infinite loop when an attribute header
indicates an empty run list, while directory entries reference it as
containing actual data. In NTFS, setting evcn=-1 with svcn=0 is a valid way
to represent an empty run list, and run_unpack() correctly handles this by
checking if evcn + 1 equals svcn and returning early without parsing any run
data. However, this creates a problem when there is metadata inconsistency,
where the attribute header claims to be empty (evcn=-1) but the caller
expects to read actual data. When run_unpack() immediately returns success
upon seeing this condition, it leaves the runs_tree uninitialized with
run->runs as a NULL. The calling function attr_load_runs_range() assumes
that a successful return means that the runs were loaded and sets clen to 0,
expecting the next run_lookup_entry() call to succeed. Because runs_tree
remains uninitialized, run_lookup_entry() continues to fail, and the loop
increments vcn by zero (vcn += 0), leading to an infinite loop.
This patch adds a retry counter to detect when run_lookup_entry() fails
consecutively after attr_load_runs_vcn(). If the run is still not found on
the second attempt, it indicates corrupted metadata and returns -EINVAL,
preventing the Denial-of-Service (DoS) vulnerability.
Co-developed-by: Seunghun Han <kkamagui@gmail.com>
Signed-off-by: Seunghun Han <kkamagui@gmail.com>
Co-developed-by: Jihoon Kwon <kjh010315@gmail.com>
Signed-off-by: Jihoon Kwon <kjh010315@gmail.com>
Signed-off-by: Jaehun Gou <p22gone@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:
This confirms the key detail: `run_unpack()` (called via
`run_unpack_ex()`) at line 940-941 returns 0 (success) when `evcn + 1 ==
svcn` — the "empty run" condition. This means `attr_load_runs_vcn()`
returns success even when no runs are actually loaded into the
`runs_tree`.
Let me now verify the infinite loop mechanism more carefully:
1. `attr_load_runs_range()` enters the loop, `run_lookup_entry()` fails
(returns false) because `run->runs` is NULL
2. `attr_load_runs_vcn()` is called, which calls `run_unpack_ex()` →
`run_unpack()`, which returns 0 (success) for the empty run case
without adding any entries
3. `clen` is set to 0
4. Loop iterates: `vcn += clen` → `vcn += 0` — no progress
5. `run_lookup_entry()` fails again → infinite loop
The fix adds a `retry` counter. If `run_lookup_entry()` fails after
`attr_load_runs_vcn()` has already been called once for the same VCN, it
returns `-EINVAL` instead of looping forever.
## Analysis
### 1. COMMIT MESSAGE ANALYSIS
- **Subject**: Clearly states "fix infinite loop" — this is a bug fix
- **Body**: Excellent description of the root cause, trigger mechanism,
and DoS impact
- **Impact**: Denial-of-Service via crafted NTFS image — security
relevant
- **Tags**: Multiple Co-developed-by/Signed-off-by, signed by ntfs3
maintainer (Konstantin Komarov)
### 2. CODE CHANGE ANALYSIS
The patch is small and surgical (~20 lines changed in a single
function):
- Adds a `retry` counter initialized to 0
- After `attr_load_runs_vcn()` succeeds but `run_lookup_entry()` still
fails on the next iteration, returns `-EINVAL`
- Resets `retry` to 0 on successful lookup
- Changes `return err` to `break` for consistency with the new error
path
- All changes are self-contained within `attr_load_runs_range()`
### 3. BUG CLASSIFICATION
- **Type**: Infinite loop / DoS from inconsistent metadata on malformed
NTFS image
- **Trigger**: Mounting/reading a crafted NTFS image where attribute
header claims empty run list (evcn=-1, svcn=0) but directory entries
reference it as containing data
- **Severity**: HIGH — causes complete system hang (infinite loop in
kernel)
- **Security**: This is a DoS vulnerability triggerable by mounting a
malicious filesystem image (e.g., USB stick)
### 4. SCOPE AND RISK
- **Lines changed**: ~20, single function, single file
- **Risk**: Very low — only adds early termination for a detected
inconsistency condition
- **Side effects**: None — the retry counter only triggers when metadata
is already corrupt
- **Regression risk**: Minimal — legitimate NTFS images won't trigger
the retry mechanism because `run_lookup_entry()` will succeed after
loading runs
### 5. USER IMPACT
- Affects anyone who mounts NTFS volumes (very common: USB drives, dual-
boot, data exchange)
- A malicious NTFS image on a USB drive could hang the kernel
- Multiple callers of `attr_load_runs_range()` are affected: xattr,
index, frecord, WOF operations
### 6. STABLE CRITERIA
- **Obviously correct**: Yes — if loading runs succeeded but lookup
still fails, metadata is corrupt
- **Fixes a real bug**: Yes — infinite loop / DoS
- **Small and contained**: Yes — ~20 lines in one function
- **No new features**: Correct — only adds error detection
- **Tested**: Signed by ntfs3 maintainer, merged to mainline
### Verification
- **Verified** the `run_unpack()` early return at line 940-941: `if
(evcn + 1 == svcn) return 0;` — this is the empty run case that
returns success without populating runs_tree
- **Verified** `run_lookup_entry()` at line 201: `if (!run->runs) return
false;` — confirms it returns false when runs_tree is uninitialized
- **Verified** the infinite loop mechanism: `vcn += clen` with `clen =
0` causes no progress, leading to infinite re-entry into the same
lookup failure path
- **Verified** callers via grep: `attr_load_runs_range` is called from
xattr.c:127, xattr.c:498, index.c:1080, frecord.c:2529, and
attrib.c:1463 — multiple code paths are affected
- **Verified** the fix is self-contained: only changes
`attr_load_runs_range()` in attrib.c, no dependencies on other commits
- **Verified** via git log that this code has been present in ntfs3
since its inclusion (the function structure is unchanged), meaning all
stable trees with ntfs3 are affected
- **Could not verify** specific CVE assignment (none mentioned in
commit), but the DoS nature makes it security-relevant regardless
This is a textbook stable backport candidate: a small, surgical fix for
a DoS-triggering infinite loop in a filesystem driver, caused by
inconsistent metadata on crafted images. The fix is obviously correct,
contained, low-risk, and signed off by the subsystem maintainer.
**YES**
fs/ntfs3/attrib.c | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/fs/ntfs3/attrib.c b/fs/ntfs3/attrib.c
index 980ae9157248d..c45880ab23912 100644
--- a/fs/ntfs3/attrib.c
+++ b/fs/ntfs3/attrib.c
@@ -1354,19 +1354,28 @@ int attr_load_runs_range(struct ntfs_inode *ni, enum ATTR_TYPE type,
CLST vcn;
CLST vcn_last = (to - 1) >> cluster_bits;
CLST lcn, clen;
- int err;
+ int err = 0;
+ int retry = 0;
for (vcn = from >> cluster_bits; vcn <= vcn_last; vcn += clen) {
if (!run_lookup_entry(run, vcn, &lcn, &clen, NULL)) {
+ if (retry != 0) { /* Next run_lookup_entry(vcn) also failed. */
+ err = -EINVAL;
+ break;
+ }
err = attr_load_runs_vcn(ni, type, name, name_len, run,
vcn);
if (err)
- return err;
+ break;
+
clen = 0; /* Next run_lookup_entry(vcn) must be success. */
+ retry++;
}
+ else
+ retry = 0;
}
- return 0;
+ return err;
}
#ifdef CONFIG_NTFS3_LZX_XPRESS
--
2.51.0
^ permalink raw reply related [flat|nested] 7+ messages in thread