mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2026-09-22 09:34:56 +02:00
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. [ tglx: Format changelog and add comment ] Reported-by: syzbot+72789cd1697965e714ca@syzkaller.appspotmail.com Signed-off-by: Dennis Moshegov <dennis@xzync.uk> Signed-off-by: Thomas Gleixner <tglx@kernel.org> Link: https://patch.msgid.link/20260724154405.70-1-dennis@xzync.uk Closes: https://syzkaller.appspot.com/bug?extid=72789cd1697965e714ca
This commit is contained in:
committed by
Thomas Gleixner
parent
ecc330e309
commit
d7fc133bf9
@@ -858,7 +858,11 @@ static void timekeeping_update_from_shadow(struct tk_data *tkd, unsigned int act
|
||||
* the downside that the reader side does not longer benefit from
|
||||
* the cacheline optimized data layout of the timekeeper and requires
|
||||
* another indirection.
|
||||
*
|
||||
* Write xtime_sec first so that even if the memcpy() tears the store
|
||||
* data integrity is provided for ktime_get_real_seconds().
|
||||
*/
|
||||
WRITE_ONCE(tkd->timekeeper.xtime_sec, tk->xtime_sec);
|
||||
memcpy(&tkd->timekeeper, tk, sizeof(*tk));
|
||||
write_seqcount_end(&tkd->seq);
|
||||
}
|
||||
@@ -1186,11 +1190,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));
|
||||
|
||||
@@ -1212,7 +1216,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);
|
||||
}
|
||||
|
||||
static inline u64 tk_clock_read_snapshot(const struct tk_read_base *tkr,
|
||||
|
||||
Reference in New Issue
Block a user