public inbox for ntfs3@lists.linux.dev
 help / color / mirror / Atom feed
From: Sasha Levin <sashal@kernel.org>
To: patches@lists.linux.dev, stable@vger.kernel.org
Cc: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>,
	Sasha Levin <sashal@kernel.org>,
	ntfs3@lists.linux.dev
Subject: [PATCH AUTOSEL 6.18-5.15] fs/ntfs3: Support timestamps prior to epoch
Date: Sat,  6 Dec 2025 09:02:25 -0500	[thread overview]
Message-ID: <20251206140252.645973-20-sashal@kernel.org> (raw)
In-Reply-To: <20251206140252.645973-1-sashal@kernel.org>

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


  parent reply	other threads:[~2025-12-06 14:03 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [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 [this message]
2025-12-06 14:02 ` [PATCH AUTOSEL 6.18-6.6] ntfs: set dummy blocksize to read boot_block when mounting Sasha Levin
     [not found] <20251209001610.611575-1-sashal@kernel.org>
2025-12-09  0:15 ` [PATCH AUTOSEL 6.18-5.15] fs/ntfs3: Support timestamps prior to epoch Sasha Levin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20251206140252.645973-20-sashal@kernel.org \
    --to=sashal@kernel.org \
    --cc=almaz.alexandrovich@paragon-software.com \
    --cc=ntfs3@lists.linux.dev \
    --cc=patches@lists.linux.dev \
    --cc=stable@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox