[tip: timers/core] time: Prevent time64_to_tm() day truncation on 32-bit
From: tip-bot2 for Karl Mehltretter
Date: Tue Sep 29 2026 - 15:24:29 EST
The following commit has been merged into the timers/core branch of tip:
Commit-ID: 2927f7ca78448781e11a4623d347cd653c28adf6
Gitweb: https://git.kernel.org/tip/2927f7ca78448781e11a4623d347cd653c28adf6
Author: Karl Mehltretter <kmehltretter@xxxxxxxxx>
AuthorDate: Fri, 25 Sep 2026 18:57:01 +02:00
Committer: Thomas Gleixner <tglx@xxxxxxxxxx>
CommitterDate: Tue, 29 Sep 2026 21:18:42 +02:00
time: Prevent time64_to_tm() day truncation on 32-bit
time64_to_tm() accepts a 64-bit seconds value, but stores the quotient in
long. On a 32-bit kernel the day count therefore wraps when it reaches
2^31, even though the corresponding year remains representable in
struct tm.
This is reachable when formatting externally supplied timestamps. For
example, NILFS recovery copies the little-endian 64-bit ss_create field
from an on-disk segment summary into time64_t. Its sysfs attributes then
print that value with %ptTs, whose formatter calls time64_to_tm(). A
corrupted image can consequently produce an architecture-dependent printed
date.
Keep the day quotient in s64 while leaving the seconds-within-day remainder
as long. Use div_s64_rem() for the weekday calculation so 32-bit builds do
not require compiler runtime division helpers.
Fixes: e6c2682a1da3 ("time: Add time64_to_tm()")
Signed-off-by: Karl Mehltretter <kmehltretter@xxxxxxxxx>
Signed-off-by: Thomas Gleixner <tglx@xxxxxxxxxx>
Assisted-by: LLM
Reviewed-by: Thomas Weißschuh <thomas.weissschuh@xxxxxxxxxxxxx>
Link: https://patch.msgid.link/20260925165702.51677-2-kmehltretter@xxxxxxxxx
---
kernel/time/timeconv.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/kernel/time/timeconv.c b/kernel/time/timeconv.c
index 59b922c..aed3af9 100644
--- a/kernel/time/timeconv.c
+++ b/kernel/time/timeconv.c
@@ -49,8 +49,9 @@ void time64_to_tm(time64_t totalsecs, int offset, struct tm *result)
u32 u32tmp, day_of_century, year_of_century, day_of_year, month, day;
u64 u64tmp, udays, century, year;
bool is_Jan_or_Feb, is_leap_year;
- long days, rem;
int remainder;
+ long rem;
+ s64 days;
days = div_s64_rem(totalsecs, SECS_PER_DAY, &remainder);
rem = remainder;
@@ -70,7 +71,8 @@ void time64_to_tm(time64_t totalsecs, int offset, struct tm *result)
result->tm_sec = rem % 60;
/* January 1, 1970 was a Thursday. */
- result->tm_wday = (4 + days) % 7;
+ div_s64_rem(days + 4, 7, &remainder);
+ result->tm_wday = remainder;
if (result->tm_wday < 0)
result->tm_wday += 7;