When setting a timestamp before epoch 0, ksmbd converts it from NT format to Unix format without normalizing it, leading to the nanoseconds field to be saved (on-disk too) as a negative number, which leads to a garbled stat command output and a reported +4 seconds in the timestamp. This bug also violates a struct timespec64 invariant, as documented in the set_normalized_timespec64() kernel-doc: [...] * Note: The tv_nsec part is always in the range of 0 <= tv_nsec < NSEC_PER_SEC. * For negative values only the tv_sec field is negative ! */ Reproducer, with /tmp as the local filesystem folder exported as [test] in ksmbd.conf and /mnt as the smb folder mounted with mount -t cifs: mount -t cifs //127.0.0.1/test /mnt -o username=user,password=pass touch /mnt/test.txt touch -d "1969-07-20 20:17:40.123456789" /mnt/test.txt stat -c "Server local (/tmp): %y" /tmp/test.txt stat -c "CIFS client (/mnt): %y" /mnt/test.txt --cached=never smbclient //127.0.0.1/test -U user%pass -c "allinfo test.txt" which prints (stat output is garbled because of negative value): Server local (/tmp): 1969-07-20 20:17:41.()*+,--00 +0000 CIFS client (/mnt): 1969-07-20 20:17:45.+(/+)*/00 +0000 altname: TESTT~K6.TXT [...] access_time: Sun Jul 20 20:17:44 1969 UTC write_time: Sun Jul 20 20:17:44 1969 UTC [...] Fix this by using set_normalized_timespec64() in ksmbd_NTtimeToUnix(). Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3") Cc: stable@vger.kernel.org Assisted-by: Gemini:3.8-flash-high antigravity-cli-1.5.3 Signed-off-by: koraynilay --- Yet another small fix I found while implementing ptime[1]. (Still not the last one :c) Thanks. [1]: https://lore.kernel.org/all/20261101015551.786044-1-koray.fra@gmail.com/T/#t fs/smb/server/misc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/smb/server/misc.c b/fs/smb/server/misc.c index 5037f37c9226..94781246b4d6 100644 --- a/fs/smb/server/misc.c +++ b/fs/smb/server/misc.c @@ -336,8 +336,7 @@ struct timespec64 ksmbd_NTtimeToUnix(__le64 ntutc) if (t < 0) { abs_t = -t; ts.tv_nsec = do_div(abs_t, 10000000) * 100; - ts.tv_nsec = -ts.tv_nsec; - ts.tv_sec = -abs_t; + set_normalized_timespec64(&ts, -abs_t, -ts.tv_nsec); } else { abs_t = t; ts.tv_nsec = do_div(abs_t, 10000000) * 100; base-commit: f4692d0e3b5e16d32d4ec7b1e0e58d7dbe74aaf4 -- 2.56.0