The Linux Kernel Mailing List
 help / color / mirror / Atom feed
* [PATCH] timekeeping: Use data_race() and READ_ONCE() in ktime_get_real_seconds()
@ 2026-05-30 17:38 Dennis Moshegov
  2026-06-02  9:46 ` Thomas Gleixner
  0 siblings, 1 reply; 4+ messages in thread
From: Dennis Moshegov @ 2026-05-30 17:38 UTC (permalink / raw)
  To: john.stultz, tglx; +Cc: linux-kernel

From: Dennis Moshegov <dennis@xzync.uk>
Subject: [PATCH] timekeeping: Use data_race() and READ_ONCE() in
ktime_get_real_seconds()

On 64-bit architectures, ktime_get_real_seconds() directly returns
tk_core.timekeeper.xtime_sec without acquiring a seqlock. This lockless
read is an intentional design choice optimized for ultra-fast,
approximate timestamping paths where a minor 1-second discrepancy is
acceptable.

However, Kernel Concurrency Sanitizer (KCSAN) flags a data race here
because the timekeeper structure is updated concurrently via a bulk
structure copy inside timekeeping_update_from_shadow() during timer
interrupts.

Since the 64-bit read is naturally aligned and atomic at the hardware
level, this data race is benign and does not cause data tearing.
Annotate the read path using data_race() combined with READ_ONCE() to
prevent compiler optimization anomalies and suppress the KCSAN warning.

Reported-by: syzbot+72789cd1697965e714ca@syzkaller.appspotmail.com
Closes: https://syzkaller.appspotmail.com/bug?extid=72789cd1697965e714ca
Assisted-by: Gemini:3.5-flash
Signed-off-by: Dennis Moshegov <dennis@xzync.uk>
---
 kernel/time/timekeeping.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 4fd3c70c1..b2e5a87da 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -1153,7 +1153,7 @@ time64_t ktime_get_real_seconds(void)
 time64_t ktime_get_real_seconds(void)
 {
 #if BITS_PER_LONG == 64
- return tk_core.timekeeper.xtime_sec;
+ return data_race(READ_ONCE(tk_core.timekeeper.xtime_sec));
 #else
  unsigned int seq;
  time64_t seconds;
-- 
2.43.0

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH] timekeeping: Use data_race() and READ_ONCE() in ktime_get_real_seconds()
  2026-05-30 17:38 [PATCH] timekeeping: Use data_race() and READ_ONCE() in ktime_get_real_seconds() Dennis Moshegov
@ 2026-06-02  9:46 ` Thomas Gleixner
       [not found]   ` <CAGqVGMp6z7VHvD6YGhgAL+2mffvM7FoFY1F__Xa2-u98YZRYeQ@mail.gmail.com>
  0 siblings, 1 reply; 4+ messages in thread
From: Thomas Gleixner @ 2026-06-02  9:46 UTC (permalink / raw)
  To: Dennis Moshegov, john.stultz; +Cc: linux-kernel

On Sat, May 30 2026 at 18:38, Dennis Moshegov wrote:
> From: Dennis Moshegov <dennis@xzync.uk>
> Subject: [PATCH] timekeeping: Use data_race() and READ_ONCE() in
> ktime_get_real_seconds()
>
> On 64-bit architectures, ktime_get_real_seconds() directly returns
> tk_core.timekeeper.xtime_sec without acquiring a seqlock. This lockless
> read is an intentional design choice optimized for ultra-fast,
> approximate timestamping paths where a minor 1-second discrepancy is
> acceptable.
>
> However, Kernel Concurrency Sanitizer (KCSAN) flags a data race here
> because the timekeeper structure is updated concurrently via a bulk
> structure copy inside timekeeping_update_from_shadow() during timer
> interrupts.
>
> Since the 64-bit read is naturally aligned and atomic at the hardware
> level, this data race is benign and does not cause data tearing.
> Annotate the read path using data_race() combined with READ_ONCE() to
> prevent compiler optimization anomalies and suppress the KCSAN warning.
>
> Reported-by: syzbot+72789cd1697965e714ca@syzkaller.appspotmail.com
> Closes: https://syzkaller.appspotmail.com/bug?extid=72789cd1697965e714ca
> Assisted-by: Gemini:3.5-flash
> Signed-off-by: Dennis Moshegov <dennis@xzync.uk>
> ---
>  kernel/time/timekeeping.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
> index 4fd3c70c1..b2e5a87da 100644
> --- a/kernel/time/timekeeping.c
> +++ b/kernel/time/timekeeping.c
> @@ -1153,7 +1153,7 @@ time64_t ktime_get_real_seconds(void)
>  time64_t ktime_get_real_seconds(void)
>  {
>  #if BITS_PER_LONG == 64
> - return tk_core.timekeeper.xtime_sec;
> + return data_race(READ_ONCE(tk_core.timekeeper.xtime_sec));

Where is the corresponding WRITE_ONCE() and what guarantees that the
memcpy(), which updates the timekeeper, will not result in a copy with
a smaller granularity?

Just suppressing the warning w/o validating that there is no way for
store tearing to happen is not cutting it. Tell your AI buddy to make
his homework.

Thanks,

        tglx

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] timekeeping: Use data_race() and READ_ONCE() in ktime_get_real_seconds()
       [not found]       ` <CAGqVGMrdhhVdCOQxNLtFkrDbeeEytJiiY+=2D7VYMue0xDD8DQ@mail.gmail.com>
@ 2026-06-16  9:11         ` Dennis Moshegov
  2026-06-21 13:17           ` Thomas Gleixner
  0 siblings, 1 reply; 4+ messages in thread
From: Dennis Moshegov @ 2026-06-16  9:11 UTC (permalink / raw)
  To: Thomas Gleixner, linux-kernel

From: Dennis M <dennismoshegov@gmail.com>
Subject: [PATCH v2] timekeeping: Use READ_ONCE/WRITE_ONCE for
xtime_sec to prevent tearing

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_real_seconds() on 64-bit systems,
 where the sequence counter protection is bypassed for performance.

To prevent reading a torn 64-bit xtime_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_real_seconds() to ensure a fresh, consistent
load from memory.

Reported-by: syzbot+72789cd1697965e714ca@syzkaller.appspotmail.com
Closes: https://syzkaller.appspotmail.com/bug?extid=72789cd1697965e714ca
Signed-off-by: Dennis Moshegov <dennis@xzync.uk>
---
 timekeeping.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/timekeeping.c b/timekeeping.c
index c493a40..461a68e 100644
--- a/timekeeping.c
+++ b/timekeeping.c
@@ -826,6 +826,7 @@ static void timekeeping_update_from_shadow(struct
tk_data *tkd, unsigned int act
     * the cacheline optimized data layout of the timekeeper and requires
     * another indirection.
     */
+   WRITE_ONCE(tkd->timekeeper.xtime_secy, tk->xtime_sec);
    memcpy(&tkd->timekeeper, tk, sizeof(*tk));
    write_seqcount_end(&tkd->seq);
 }
@@ -1153,11 +1154,11 @@ time64_t ktime_get_real_seconds(void)
    unsigned int seq;

    if (IS_ENABLED(CONFIG_64BIT))
-       return tk->xtime_sec;
+       return READ_ONCE(tk->xtime_sec);

    do {
        seq = read_seqcount_begin(&tk_core.seq);
-       seconds = tk->xtime_sec;
+       seconds = READ_ONCE(tk->xtime_sec);

    } while (read_seqcount_retry(&tk_core.seq, seq));

@@ -1179,7 +1180,7 @@ noinstr time64_t __ktime_get_real_seconds(void)
 {
    struct timekeeper *tk = &tk_core.timekeeper;

-   return tk->xtime_sec;
+   return READ_ONCE(tk->xtime_sec);
 }

 /**

--
2.53.0.windows.1

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH] timekeeping: Use data_race() and READ_ONCE() in ktime_get_real_seconds()
  2026-06-16  9:11         ` Dennis Moshegov
@ 2026-06-21 13:17           ` Thomas Gleixner
  0 siblings, 0 replies; 4+ messages in thread
From: Thomas Gleixner @ 2026-06-21 13:17 UTC (permalink / raw)
  To: Dennis Moshegov, linux-kernel

On Tue, Jun 16 2026 at 10:11, Dennis Moshegov wrote:
> From: Dennis M <dennismoshegov@gmail.com>
> Subject: [PATCH v2] timekeeping: Use READ_ONCE/WRITE_ONCE for
> xtime_sec to prevent tearing
>
> 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_real_seconds() on 64-bit systems,
>  where the sequence counter protection is bypassed for performance.
>
> To prevent reading a torn 64-bit xtime_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_real_seconds() to ensure a fresh, consistent
> load from memory.
>
> Reported-by: syzbot+72789cd1697965e714ca@syzkaller.appspotmail.com
> Closes: https://syzkaller.appspotmail.com/bug?extid=72789cd1697965e714ca
> Signed-off-by: Dennis Moshegov <dennis@xzync.uk>
> ---
>  timekeeping.c | 7 ++++---
>  1 file changed, 4 insertions(+), 3 deletions(-)
>
> diff --git a/timekeeping.c b/timekeeping.c
> index c493a40..461a68e 100644
> --- a/timekeeping.c
> +++ b/timekeeping.c

You need to create the patch in the top level directory so that this
becomes a/kernel/time/timekeeping.c

> @@ -826,6 +826,7 @@ static void timekeeping_update_from_shadow(struct
> tk_data *tkd, unsigned int act

There is a line break after 'struct', which makes the patch malformed
and it can't be applied as is.

Thanks,

        tglx



^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-06-21 13:17 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-30 17:38 [PATCH] timekeeping: Use data_race() and READ_ONCE() in ktime_get_real_seconds() Dennis Moshegov
2026-06-02  9:46 ` Thomas Gleixner
     [not found]   ` <CAGqVGMp6z7VHvD6YGhgAL+2mffvM7FoFY1F__Xa2-u98YZRYeQ@mail.gmail.com>
     [not found]     ` <871peo9485.ffs@fw13>
     [not found]       ` <CAGqVGMrdhhVdCOQxNLtFkrDbeeEytJiiY+=2D7VYMue0xDD8DQ@mail.gmail.com>
2026-06-16  9:11         ` Dennis Moshegov
2026-06-21 13:17           ` Thomas Gleixner

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox