[PATCH] timekeeping: Use READ_ONCE/WRITE_ONCE() for ktime_sec to prevent tearing

Thomas Weißschuh posted 1 patch 3 weeks, 2 days ago
kernel/time/timekeeping.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
[PATCH] timekeeping: Use READ_ONCE/WRITE_ONCE() for ktime_sec to prevent tearing
Posted by Thomas Weißschuh 3 weeks, 2 days ago
The timekeeper update path uses a bulk memcpy() to synchronize the
timekeeper structure, which is not guaranteed to be atomic. This allows for
torn reads in ktime_get_seconds() which bypasses the sequence counter
protection for performance.

To prevent reading a torn ktime_sec value, enforce atomic-like
access by using WRITE_ONCE() for the critical field before the bulk
memcpy() in timekeeping_update_from_shadow(). Correspondingly, use
READ_ONCE() in ktime_get_seconds() to ensure a fresh, consistent load
from memory.

The same was done for xtime_sec and ktime_get_real_seconds() in commit
d7fc133bf91f ("timekeeping: Use READ_ONCE/WRITE_ONCE() for xtime_sec to
prevent tearing").

Signed-off-by: Thomas Weißschuh (Schneider Electric) <thomas.weissschuh@linutronix.de>
---
Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
---
 kernel/time/timekeeping.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index ea2e6e55f37b..d54c4d303db6 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -861,8 +861,10 @@ static void timekeeping_update_from_shadow(struct tk_data *tkd, unsigned int act
 	 *
 	 * Write xtime_sec first so that even if the memcpy() tears the store
 	 * data integrity is provided for ktime_get_real_seconds().
+	 * The same goes for ktime_sec and ktime_get_seconds().
 	 */
 	WRITE_ONCE(tkd->timekeeper.xtime_sec, tk->xtime_sec);
+	WRITE_ONCE(tkd->timekeeper.ktime_sec, tk->ktime_sec);
 	memcpy(&tkd->timekeeper, tk, sizeof(*tk));
 	write_seqcount_end(&tkd->seq);
 }
@@ -1169,7 +1171,7 @@ time64_t ktime_get_seconds(void)
 	struct timekeeper *tk = &tk_core.timekeeper;
 
 	WARN_ON(timekeeping_suspended);
-	return tk->ktime_sec;
+	return READ_ONCE(tk->ktime_sec);
 }
 EXPORT_SYMBOL_GPL(ktime_get_seconds);
 

---
base-commit: cee9395acd8043be0644b25c34bfa86623f2b935
change-id: 20260831-timekeeping-ktime_sec-075e744411bd

Best regards,
--  
Thomas Weißschuh <thomas.weissschuh@linutronix.de>

Re: [PATCH] timekeeping: Use READ_ONCE/WRITE_ONCE() for ktime_sec to prevent tearing
Posted by John Stultz 3 weeks, 1 day ago
On Thu, Sep 3, 2026 at 12:11 AM Thomas Weißschuh
<thomas.weissschuh@linutronix.de> wrote:
>
> The timekeeper update path uses a bulk memcpy() to synchronize the
> timekeeper structure, which is not guaranteed to be atomic. This allows for
> torn reads in ktime_get_seconds() which bypasses the sequence counter
> protection for performance.
>
> To prevent reading a torn ktime_sec value, enforce atomic-like
> access by using WRITE_ONCE() for the critical field before the bulk
> memcpy() in timekeeping_update_from_shadow(). Correspondingly, use
> READ_ONCE() in ktime_get_seconds() to ensure a fresh, consistent load
> from memory.
>
> The same was done for xtime_sec and ktime_get_real_seconds() in commit
> d7fc133bf91f ("timekeeping: Use READ_ONCE/WRITE_ONCE() for xtime_sec to
> prevent tearing").
>
> Signed-off-by: Thomas Weißschuh (Schneider Electric) <thomas.weissschuh@linutronix.de>
> ---
> Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>

Acked-by: John Stultz <jstultz@google.com>