From e7cad586d73276cbd4466de81b2092287d7475c0 Mon Sep 17 00:00:00 2001 From: Liang Hao Date: Wed, 30 Sep 2026 14:36:21 +0800 Subject: [PATCH 1/4] timers: Clear pending_map on CPU hotplug CPU hotplug migration leaves pending_map bits set on the outgoing CPU while its wheel vectors are empty. After re-online, a later next_expiry recalc can treat those empty buckets as pending and temporarily pull next_expiry forward until collect drains the bits. Clear pending_map under the base lock after migration in timers_dead_cpu(). Fixes: 500462a9de65 ("timers: Switch to a non-cascading wheel") Signed-off-by: Liang Hao Signed-off-by: Thomas Gleixner Link: https://patch.msgid.link/20260930063621.37740-1-haohlliang@gmail.com --- kernel/time/timer.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/time/timer.c b/kernel/time/timer.c index ae9abf14688e..fc374444acb6 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -2541,6 +2542,7 @@ int timers_dead_cpu(unsigned int cpu) for (i = 0; i < WHEEL_SIZE; i++) migrate_timer_list(new_base, old_base->vectors + i); + bitmap_zero(old_base->pending_map, WHEEL_SIZE); raw_spin_unlock(&old_base->lock); raw_spin_unlock_irq(&new_base->lock); put_cpu_ptr(&timer_bases); From 8ccd731b63a0183ca2b0e18f3ca15864b3f37eda Mon Sep 17 00:00:00 2001 From: "Cen Zhang (Microsoft)" Date: Mon, 12 Oct 2026 19:51:49 -0400 Subject: [PATCH 2/4] posix-cpu-timers: Fix pid refcount leak in do_cpu_nanosleep() signal path do_cpu_nanosleep() sleeps on a temporary k_itimer whose reference on the target's struct pid is taken by posix_cpu_timer_create() and dropped by posix_cpu_timer_del(). When a signal ends the sleep, the timer is disarmed with posix_cpu_timer_set(), but posix_cpu_timer_del() is only called for a result of 0 or TIMER_RETRY. If the target thread or process has exited in the meantime, timer_lock_sighand() finds no task, posix_cpu_timer_set() returns -ESRCH and the pid reference is leaked. An unprivileged user can trigger this: sleep on the CPU clock of a thread, let that thread exit, then signal the sleeper. Each round leaks one struct pid. Repeating it exhausts unreclaimable slab memory within minutes: Out of memory: Killed process 150 (poc) total-vm:789292kB, anon-rss:484kB Kernel panic - not syncing: System is deadlocked on memory Fix this by also calling posix_cpu_timer_del() on -ESRCH. With the target gone, the deletion is safe. It finds no task either and only drops the pid reference. Fixes: e26d70d271ee ("posix-timers: Cleanup reaped target handling") Reported-by: AutonomousCodeSecurity@microsoft.com Signed-off-by: Cen Zhang (Microsoft) Signed-off-by: Thomas Gleixner Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20261012235149.66531-1-cenzhang@linux.microsoft.com --- kernel/time/posix-cpu-timers.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/time/posix-cpu-timers.c b/kernel/time/posix-cpu-timers.c index 0bf4fcd969c8..65cc612046d1 100644 --- a/kernel/time/posix-cpu-timers.c +++ b/kernel/time/posix-cpu-timers.c @@ -1600,8 +1600,8 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags, */ expires = cpu_timer_getexpires(&timer.it.cpu); error = posix_cpu_timer_set(&timer, 0, &zero_it, &it); - if (!error) { - /* Timer is now unarmed, deletion can not fail. */ + if (error != TIMER_RETRY) { + /* Unarmed or target gone (-ESRCH), deletion can not fail. */ posix_cpu_timer_del(&timer); } else { while (error == TIMER_RETRY) { From 524d95c8a2000cba6cb80a173d76cb746c561244 Mon Sep 17 00:00:00 2001 From: Daehyeon Ko <4ncienth@gmail.com> Date: Mon, 19 Oct 2026 17:03:24 +0900 Subject: [PATCH 3/4] timekeeping: Require permission to set auxiliary clocks The generic clock_settime() entry point delegates permission checks to each clock-specific callback. aux_clock_set() does not perform one. Once an administrator enables an auxiliary clock, any local process can therefore change the global clock offset. A test process running as UID and GID 65534 with no effective, permitted, inheritable, or ambient capabilities set CLOCK_AUX0 successfully, and a separate process observed the new value. The same process was denied by clock_adjtime(). An AppArmor profile denying sys_time also blocked CLOCK_REALTIME changes but did not see the auxiliary clock operation. Call security_settime64() before mutating the auxiliary timekeeper. This matches CLOCK_REALTIME's permission model, enforces initial-user-namespace CAP_SYS_TIME, and gives LSMs the settime hook while preserving authorized clock changes. Fixes: 60ecc26ec5af ("timekeeping: Provide time setter for auxiliary clocks") Signed-off-by: Daehyeon Ko <4ncienth@gmail.com> Signed-off-by: Thomas Gleixner Tested-by: shaos Acked-by: John Stultz Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20261019080324.4147815-1-4ncienth@gmail.com --- kernel/time/timekeeping.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index ea2e6e55f37b..1b342825bd8f 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -3215,11 +3216,15 @@ static int aux_clock_set(const clockid_t id, const struct timespec64 *tnew) struct tk_data *aux_tkd = aux_get_tk_data(id); struct timekeeper *aux_tks; ktime_t tnow, nsecs; + int ret; if (!timespec64_valid_settod(tnew)) return -EINVAL; if (!aux_tkd) return -ENODEV; + ret = security_settime64(tnew, NULL); + if (ret) + return ret; aux_tks = &aux_tkd->shadow_timekeeper; From 6541fbc942f3b63bb8bd44e34eee6223e0abe719 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh=20=28Schneider=20Electric=29?= Date: Fri, 23 Oct 2026 13:49:17 +0200 Subject: [PATCH 4/4] timekeeping: Update offsets on sequence counter retry in ktime_get_update_offsets_now() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The sequence counter of the cwsseq target is modified during the sequence counter loop. If the loop retries, cwsseq will now match but the offsets contain the values from the previous loop iteration. These are not guaranteed to be consistent in themselves or with the current loops "now. Save the target's original sequence counter value so that the update also happens on loop retries. Fixes: 868a3e915f7f ("hrtimer: Make offset update smarter") Signed-off-by: Thomas Weißschuh (Schneider Electric) Signed-off-by: Thomas Gleixner Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20261023-timekeeping-clock_was_set_seq-v1-1-61c4c53d031c@linutronix.de --- kernel/time/timekeeping.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 1b342825bd8f..cae3e51eaf55 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -2849,6 +2849,7 @@ ktime_t ktime_get_update_offsets_now(u32 *cwsseq, ktime_t *offs_real, ktime_t *offs_boot, ktime_t *offs_tai) { struct timekeeper *tk = &tk_core.timekeeper; + u32 cwsseq_orig = *cwsseq; unsigned int seq; ktime_t base; u64 nsecs; @@ -2860,7 +2861,7 @@ ktime_t ktime_get_update_offsets_now(u32 *cwsseq, ktime_t *offs_real, nsecs = timekeeping_get_ns(&tk->tkr_mono); base = ktime_add_ns(base, nsecs); - if (*cwsseq != tk->clock_was_set_seq) { + if (cwsseq_orig != tk->clock_was_set_seq) { *cwsseq = tk->clock_was_set_seq; *offs_real = tk->offs_real; *offs_boot = tk->offs_boot;