* [PATCH AUTOSEL 6.18-6.12] fs/ntfs3: check for shutdown in fsync
[not found] <20251206140252.645973-1-sashal@kernel.org>
@ 2025-12-06 14:02 ` Sasha Levin
2025-12-06 14:02 ` [PATCH AUTOSEL 6.18-5.15] fs/ntfs3: Support timestamps prior to epoch Sasha Levin
2025-12-06 14:02 ` [PATCH AUTOSEL 6.18-6.6] ntfs: set dummy blocksize to read boot_block when mounting Sasha Levin
2 siblings, 0 replies; 3+ messages in thread
From: Sasha Levin @ 2025-12-06 14:02 UTC (permalink / raw)
To: patches, stable; +Cc: Konstantin Komarov, Sasha Levin, ntfs3
From: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
[ Upstream commit 1b2ae190ea43bebb8c73d21f076addc8a8c71849 ]
Ensure fsync() returns -EIO when the ntfs3 filesystem is in forced
shutdown, instead of silently succeeding via generic_file_fsync().
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:
## Analysis Summary
### What the commit does:
Adds a new wrapper function `ntfs_file_fsync()` that checks if the ntfs3
filesystem is in forced shutdown state before calling
`generic_file_fsync()`. If the filesystem is shutting down, it returns
`-EIO` instead of silently succeeding.
### Technical mechanism:
The fix is straightforward:
1. Get the inode from the file
2. Call `ntfs3_forced_shutdown(inode->i_sb)` to check if filesystem is
in error state
3. Return `-EIO` if true, otherwise delegate to `generic_file_fsync()`
### Is this a real bug fix?
**Yes** - this fixes a data integrity semantics issue. When a filesystem
is in forced shutdown (typically after critical I/O errors), fsync()
should return an error to inform applications their data was not synced.
Silently succeeding could cause data loss without applications knowing.
### Stable kernel criteria evaluation:
| Criteria | Assessment |
|----------|------------|
| Fixes real bug | Yes - data integrity semantics issue |
| Small/contained | Yes - ~10 lines, single function |
| Obviously correct | Yes - follows existing pattern in ntfs3 |
| Stable tag | **NO** - maintainer didn't request stable |
| Fixes: tag | **NO** - no indication of when bug was introduced |
### Critical dependency issue:
The `ntfs3_forced_shutdown()` function was introduced in **kernel 6.8**
(commit 6c3684e703837). My verification shows:
- **v6.6**: Does NOT have `ntfs3_forced_shutdown` (0 occurrences)
- **v6.8+**: Has the shutdown infrastructure
This means:
- Stable trees **6.6.y**, **6.1.y**, **5.15.y**, etc. cannot use this
fix without first backporting the entire shutdown feature (~75 lines
across 7 files)
- Only newer stable trees (if any exist based on 6.8+) would benefit
### Risk vs Benefit:
- **Benefit**: Correct fsync() error handling during filesystem shutdown
- **Risk**: Low for applicable kernels - simple logic, well-tested
pattern
- **Applicability**: Very limited - only affects recent kernels with
shutdown support
### Conclusion:
While this is a legitimate fix for a data integrity issue, several
factors argue against backporting:
1. **No maintainer request**: No "Cc: stable@vger.kernel.org" tag
indicates the maintainer didn't consider this critical for stable
2. **Dependency on new feature**: Requires the shutdown infrastructure
from 6.8, which is not in most active stable trees (6.6.y, 6.1.y,
5.15.y)
3. **Limited impact scope**: Only applies to the relatively recent
kernel versions that have the shutdown feature
4. **The shutdown feature itself is new**: The forced shutdown
functionality only existed for a short time before this fix, meaning
the exposure window is small
This fix would require significant infrastructure backporting to be
useful in most stable trees, making it unsuitable as-is for stable
backporting.
**NO**
fs/ntfs3/file.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/fs/ntfs3/file.c b/fs/ntfs3/file.c
index 4c90ec2fa2eae..83f0072f0896c 100644
--- a/fs/ntfs3/file.c
+++ b/fs/ntfs3/file.c
@@ -1375,6 +1375,18 @@ static ssize_t ntfs_file_splice_write(struct pipe_inode_info *pipe,
return iter_file_splice_write(pipe, file, ppos, len, flags);
}
+/*
+ * ntfs_file_fsync - file_operations::fsync
+ */
+static int ntfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)
+{
+ struct inode *inode = file_inode(file);
+ if (unlikely(ntfs3_forced_shutdown(inode->i_sb)))
+ return -EIO;
+
+ return generic_file_fsync(file, start, end, datasync);
+}
+
// clang-format off
const struct inode_operations ntfs_file_inode_operations = {
.getattr = ntfs_getattr,
@@ -1397,7 +1409,7 @@ const struct file_operations ntfs_file_operations = {
.splice_write = ntfs_file_splice_write,
.mmap_prepare = ntfs_file_mmap_prepare,
.open = ntfs_file_open,
- .fsync = generic_file_fsync,
+ .fsync = ntfs_file_fsync,
.fallocate = ntfs_fallocate,
.release = ntfs_file_release,
};
--
2.51.0
^ permalink raw reply related [flat|nested] 3+ messages in thread* [PATCH AUTOSEL 6.18-5.15] fs/ntfs3: Support timestamps prior to epoch
[not found] <20251206140252.645973-1-sashal@kernel.org>
2025-12-06 14:02 ` [PATCH AUTOSEL 6.18-6.12] fs/ntfs3: check for shutdown in fsync Sasha Levin
@ 2025-12-06 14:02 ` Sasha Levin
2025-12-06 14:02 ` [PATCH AUTOSEL 6.18-6.6] ntfs: set dummy blocksize to read boot_block when mounting Sasha Levin
2 siblings, 0 replies; 3+ messages in thread
From: Sasha Levin @ 2025-12-06 14:02 UTC (permalink / raw)
To: patches, stable; +Cc: Konstantin Komarov, Sasha Levin, ntfs3
From: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
[ Upstream commit 5180138604323895b5c291eca6aa7c20be494ade ]
Before it used an unsigned 64-bit type, which prevented proper handling
of timestamps earlier than 1970-01-01. Switch to a signed 64-bit type to
support pre-epoch timestamps. The issue was caught by xfstests.
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 complete understanding. Let me write the detailed analysis:
## Detailed Analysis
### 1. COMMIT MESSAGE ANALYSIS
**Subject:** `fs/ntfs3: Support timestamps prior to epoch`
**Commit Body:**
- The commit explains that before this fix, the code used an **unsigned
64-bit type** (`u64`), which prevented proper handling of timestamps
earlier than 1970-01-01 (the Unix epoch).
- The fix switches to a **signed 64-bit type** (`s64`) to support pre-
epoch timestamps.
- The issue was caught by **xfstests test 258**, which specifically
tests for timestamps prior to the epoch.
**Tags:**
- **No `Cc: stable@vger.kernel.org` tag** is present.
- **No `Fixes:` tag** is present.
### 2. CODE CHANGE ANALYSIS
#### The Bug:
In the current code (before the patch):
```980:987:fs/ntfs3/ntfs_fs.h
static inline void nt2kernel(const __le64 tm, struct timespec64 *ts)
{
u64 t = le64_to_cpu(tm) - _100ns2seconds * SecondsToStartOf1970;
// WARNING: do_div changes its first argument(!)
ts->tv_nsec = do_div(t, _100ns2seconds) * 100;
ts->tv_sec = t;
}
```
The variable `t` is declared as `u64` (unsigned 64-bit integer). NTFS
timestamps are stored as the number of 100-nanosecond intervals since
January 1, 1601. After subtracting `SecondsToStartOf1970`
(0x00000002B6109100), which represents the number of seconds between
1601 and 1970, `t` represents a Unix timestamp.
**Problem:** When the NTFS timestamp represents a date before January 1,
1970, the subtraction produces a **negative** result. But since `t` is
unsigned (`u64`), the negative value wraps around to a very large
positive value, resulting in a wrong (future) timestamp.
**The `do_div` macro** operates on unsigned integers and uses unsigned
division, which doesn't handle negative values correctly.
#### The Fix:
The patch changes:
1. `u64 t` → `s64 t` (signed 64-bit integer)
2. `do_div(t, _100ns2seconds)` → `div_s64_rem(t, _100ns2seconds, &t32)`
(signed division)
3. Introduces `s32 t32` to hold the remainder
The new code:
```c
static inline void nt2kernel(const __le64 tm, struct timespec64 *ts)
{
s32 t32;
/* use signed 64 bit to support timestamps prior to epoch.
xfstest 258. */
s64 t = le64_to_cpu(tm) - _100ns2seconds * SecondsToStartOf1970;
ts->tv_sec = div_s64_rem(t, _100ns2seconds, &t32);
ts->tv_nsec = t32 * 100;
}
```
`div_s64_rem()` is designed for signed 64-bit division with a 32-bit
divisor, properly handling negative values and returning the remainder
through a pointer.
**Root Cause:** Using unsigned arithmetic for a value that can be
negative (pre-epoch timestamps).
### 3. CLASSIFICATION
- **Bug fix:** YES - This is fixing incorrect behavior with timestamps
before 1970.
- **New feature:** NO - It doesn't add new functionality, only fixes
existing functionality.
- **Security fix:** NO - No security implications.
- **Exception category:** NO - Not a device ID, quirk, DT update, build
fix, or documentation fix.
### 4. SCOPE AND RISK ASSESSMENT
**Lines Changed:** Very minimal - changes ~8 lines of code within a
single inline function.
**Files Touched:** 1 file (`fs/ntfs3/ntfs_fs.h`)
**Subsystem Complexity:**
- NTFS3 is a relatively new filesystem (added in 5.15)
- The change is in a core time conversion function `nt2kernel()` that is
called whenever reading timestamps from disk
- All file timestamps (creation, modification, access times) use this
function
**Risk Assessment:**
- **LOW RISK** - The change is small, surgical, and uses a well-
established kernel API (`div_s64_rem`)
- The new code is mathematically equivalent to the old code for
timestamps after 1970
- For timestamps before 1970, the new code produces correct results
(negative `tv_sec` values)
- The `timespec64` structure's `tv_sec` field is `time64_t` which is
signed (`__s64`), so it can properly represent negative timestamps
### 5. USER IMPACT
**Who is affected?**
- Users of NTFS3 filesystem
- Users with NTFS volumes containing files with pre-1970 timestamps
**How severe?**
- The bug causes **data corruption** (incorrect timestamp
display/storage) for pre-epoch files
- Without this fix, timestamps like January 1, 1960 would appear as some
date far in the future
- This breaks file management tools and any software relying on correct
timestamps
**Test Coverage:**
- The fix was identified by **xfstests generic/258**, a standard
filesystem test that specifically validates pre-epoch timestamp
handling
- This is a well-known and commonly run test suite
### 6. STABILITY INDICATORS
- **No `Tested-by:` tag** - However, xfstests is mentioned, implying the
fix was tested against this test suite
- **No `Reviewed-by:` tag**
- The commit is from the ntfs3 maintainer (Konstantin Komarov from
Paragon Software)
### 7. DEPENDENCY CHECK
- **No dependencies** - This is a standalone fix
- Uses existing kernel APIs (`div_s64_rem`, `s64`, `s32`) that have been
available for a long time
- The affected code (`nt2kernel` function) has existed since ntfs3 was
introduced in kernel 5.15
### Summary
**YES signals:**
1. ✅ Fixes a **real bug** (incorrect timestamps for pre-epoch dates)
2. ✅ **Small and surgical** change - only 8 lines changed in one
function
3. ✅ **Obviously correct** - uses proper signed arithmetic for values
that can be negative
4. ✅ No new features, no new APIs
5. ✅ Caught by **xfstests**, a standard fs test suite (test 258)
6. ✅ Applies to all stable kernels that have ntfs3 (5.15+)
7. ✅ Zero risk of regression for post-epoch timestamps (mathematically
equivalent)
8. ✅ Fixes **data integrity issue** (timestamp corruption)
**NO signals:**
1. ⚠️ No explicit `Cc: stable@vger.kernel.org` tag
2. ⚠️ No `Fixes:` tag
3. ⚠️ No `Tested-by:` or `Reviewed-by:` tags
**Verdict:**
This is a clear bug fix that addresses a real issue (incorrect pre-epoch
timestamp handling) that affects NTFS3 users. The fix is small,
surgical, uses well-tested kernel APIs, and is mathematically correct.
While the commit lacks stable tags, the nature of the fix - correcting
data integrity issues with timestamps - makes it appropriate for
backporting. The bug has existed since ntfs3 was introduced (5.15), so
all stable trees with ntfs3 would benefit from this fix.
The lack of `Cc: stable` tag is likely an oversight since the fix
clearly meets stable kernel criteria: it's a bug fix, small in scope,
obviously correct, and fixes a real user-visible issue (incorrect file
timestamps).
**YES**
fs/ntfs3/ntfs_fs.h | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/fs/ntfs3/ntfs_fs.h b/fs/ntfs3/ntfs_fs.h
index 630128716ea73..2649fbe16669d 100644
--- a/fs/ntfs3/ntfs_fs.h
+++ b/fs/ntfs3/ntfs_fs.h
@@ -979,11 +979,12 @@ static inline __le64 kernel2nt(const struct timespec64 *ts)
*/
static inline void nt2kernel(const __le64 tm, struct timespec64 *ts)
{
- u64 t = le64_to_cpu(tm) - _100ns2seconds * SecondsToStartOf1970;
+ s32 t32;
+ /* use signed 64 bit to support timestamps prior to epoch. xfstest 258. */
+ s64 t = le64_to_cpu(tm) - _100ns2seconds * SecondsToStartOf1970;
- // WARNING: do_div changes its first argument(!)
- ts->tv_nsec = do_div(t, _100ns2seconds) * 100;
- ts->tv_sec = t;
+ ts->tv_sec = div_s64_rem(t, _100ns2seconds, &t32);
+ ts->tv_nsec = t32 * 100;
}
static inline struct ntfs_sb_info *ntfs_sb(struct super_block *sb)
--
2.51.0
^ permalink raw reply related [flat|nested] 3+ messages in thread* [PATCH AUTOSEL 6.18-6.6] ntfs: set dummy blocksize to read boot_block when mounting
[not found] <20251206140252.645973-1-sashal@kernel.org>
2025-12-06 14:02 ` [PATCH AUTOSEL 6.18-6.12] fs/ntfs3: check for shutdown in fsync Sasha Levin
2025-12-06 14:02 ` [PATCH AUTOSEL 6.18-5.15] fs/ntfs3: Support timestamps prior to epoch Sasha Levin
@ 2025-12-06 14:02 ` Sasha Levin
2 siblings, 0 replies; 3+ messages in thread
From: Sasha Levin @ 2025-12-06 14:02 UTC (permalink / raw)
To: patches, stable
Cc: Pedro Demarchi Gomes, syzbot+f4f84b57a01d6b8364ad,
Konstantin Komarov, Sasha Levin, ntfs3
From: Pedro Demarchi Gomes <pedrodemargomes@gmail.com>
[ Upstream commit d1693a7d5a38acf6424235a6070bcf5b186a360d ]
When mounting, sb->s_blocksize is used to read the boot_block without
being defined or validated. Set a dummy blocksize before attempting to
read the boot_block.
The issue can be triggered with the following syz reproducer:
mkdirat(0xffffffffffffff9c, &(0x7f0000000080)='./file1\x00', 0x0)
r4 = openat$nullb(0xffffffffffffff9c, &(0x7f0000000040), 0x121403, 0x0)
ioctl$FS_IOC_SETFLAGS(r4, 0x40081271, &(0x7f0000000980)=0x4000)
mount(&(0x7f0000000140)=@nullb, &(0x7f0000000040)='./cgroup\x00',
&(0x7f0000000000)='ntfs3\x00', 0x2208004, 0x0)
syz_clone(0x88200200, 0x0, 0x0, 0x0, 0x0, 0x0)
Here, the ioctl sets the bdev block size to 16384. During mount,
get_tree_bdev_flags() calls sb_set_blocksize(sb, block_size(bdev)),
but since block_size(bdev) > PAGE_SIZE, sb_set_blocksize() leaves
sb->s_blocksize at zero.
Later, ntfs_init_from_boot() attempts to read the boot_block while
sb->s_blocksize is still zero, which triggers the bug.
Reported-by: syzbot+f4f84b57a01d6b8364ad@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=f4f84b57a01d6b8364ad
Signed-off-by: Pedro Demarchi Gomes <pedrodemargomes@gmail.com>
[almaz.alexandrovich@paragon-software.com: changed comment style, added
return value handling]
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 complete picture of the issue. Let me summarize my
analysis:
## Summary of Analysis
### The Bug
The commit fixes a bug in ntfs3's `ntfs_init_from_boot()` function where
`ntfs_bread()` is called to read the boot block **before**
`sb->s_blocksize` is properly set.
### Root Cause Analysis
1. **Mount Flow**: When mounting an ntfs3 filesystem:
- `get_tree_bdev()` calls `setup_bdev_super()` which calls
`sb_set_blocksize(sb, block_size(bdev))`
- If `block_size(bdev) > PAGE_SIZE` (which can happen via ioctl
`FS_IOC_SETFLAGS` setting bdev block size to 16384 as shown in the
reproducer), and the filesystem doesn't have `FS_LBS` flag,
`sb_set_blocksize()` returns 0 and leaves `sb->s_blocksize = 0`
2. **The Crash Path**: In `ntfs_init_from_boot()`:
```c
sbi->volume.blocks = dev_size >> PAGE_SHIFT;
// sb->s_blocksize is 0 here!
bh = ntfs_bread(sb, boot_block); // Uses sb->s_blocksize = 0
```
3. **Cascade to Infinite Loop**:
- `ntfs_bread()` → `sb_bread_unmovable()` → `__bread_gfp()` with
size=0
- `bdev_getblk()` → `__getblk_slow()` → `grow_buffers()` →
`grow_dev_folio()` → `folio_alloc_buffers()`
- In `folio_alloc_buffers()`: `while ((offset -= size) >= 0)` with
size=0 causes infinite loop
### The Fix
The fix adds a call to `sb_min_blocksize(sb, PAGE_SIZE)` before
attempting to read the boot block:
```c
/* Set dummy blocksize to read boot_block. */
if (!sb_min_blocksize(sb, PAGE_SIZE)) {
return -EINVAL;
}
```
This ensures:
1. `sb->s_blocksize` is set to at least the device's logical block size,
capped at PAGE_SIZE
2. If this fails, mount fails gracefully with `-EINVAL` instead of
hanging
### Backport Assessment
**STRONG YES signals:**
1. ✅ **Fixes a real crash/hang** - System hangs due to infinite loop in
`folio_alloc_buffers()`
2. ✅ **Syzbot reported** - Has syzkaller reproducer
(`f4f84b57a01d6b8364ad`)
3. ✅ **Small, surgical fix** - Only 4 lines added
4. ✅ **Clear, obvious fix** - Sets blocksize before using it for reads
5. ✅ **Uses well-established API** - `sb_min_blocksize()` is a standard
helper used by many filesystems
6. ✅ **Affects production users** - ntfs3 is widely used (included since
5.15)
7. ✅ **Denial of Service potential** - A local user can trigger the hang
**Risk Assessment:**
- **Very Low Risk**: The fix adds a safety check before an I/O operation
- **No behavioral change** for normal cases - the blocksize would have
been set to PAGE_SIZE anyway after successful boot read
- **Graceful failure** if `sb_min_blocksize()` fails (which would be
very rare in practice)
**Stable Trees Affected:**
- All stable trees with ntfs3: 5.15.y, 6.1.y, 6.6.y, 6.10.y, 6.11.y,
etc.
- The bug has existed since ntfs3 was introduced in v5.15
- The recent `FS_LBS` change (March 2025) made it easier to trigger but
the underlying issue predates it
**Dependencies:**
- The fix is standalone and uses existing kernel APIs
- No other patches required for backport
- `sb_min_blocksize()` has been available since at least 2.6.x
**YES**
fs/ntfs3/super.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c
index ddff94c091b8c..e6c0908e27c29 100644
--- a/fs/ntfs3/super.c
+++ b/fs/ntfs3/super.c
@@ -933,6 +933,11 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size,
sbi->volume.blocks = dev_size >> PAGE_SHIFT;
+ /* Set dummy blocksize to read boot_block. */
+ if (!sb_min_blocksize(sb, PAGE_SIZE)) {
+ return -EINVAL;
+ }
+
read_boot:
bh = ntfs_bread(sb, boot_block);
if (!bh)
--
2.51.0
^ permalink raw reply related [flat|nested] 3+ messages in thread