POSIX CPU Timers TOCTOU race (CVE-2025-38352)
Tip
AWS Hacking’i öğrenin ve pratik yapın:
HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking’i öğrenin ve pratik yapın:HackTricks Training GCP Red Team Expert (GRTE)
Azure Hacking’i öğrenin ve pratik yapın:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks'i Destekleyin
- abonelik planlarını kontrol edin!
- 💬 Discord grubuna veya telegram grubuna katılın ya da Twitter’da bizi takip edin 🐦 @hacktricks_live.**
- Hacking ipuçlarını paylaşmak için HackTricks ve HackTricks Cloud github reposuna PR gönderin.
Bu sayfa, Linux/Android POSIX CPU timers içindeki bir TOCTOU yarış durumunu belgelemektedir; bu durum timer durumunu bozabilir ve kernel’in çökmesine yol açabilir ve bazı durumlarda yetki yükseltmeye doğru yönlendirilebilir.
- Affected component: kernel/time/posix-cpu-timers.c
- Primitif: görev çıkışı sırasında sona erme vs silme yarışı
- Konfigürasyon duyarlı: CONFIG_POSIX_CPU_TIMERS_TASK_WORK=n (IRQ-context expiry path)
Kısa iç yapı özeti (istismar için ilgili)
- Üç CPU saati, timer’ların hesaplamasını cpu_clock_sample() aracılığıyla sağlar:
- CPUCLOCK_PROF: utime + stime
- CPUCLOCK_VIRT: utime sadece
- CPUCLOCK_SCHED: task_sched_runtime()
- Timer oluşturma, bir timer’ı bir task/pid’e bağlar ve timerqueue düğümlerini başlatır:
static int posix_cpu_timer_create(struct k_itimer *new_timer) {
struct pid *pid;
rcu_read_lock();
pid = pid_for_clock(new_timer->it_clock, false);
if (!pid) { rcu_read_unlock(); return -EINVAL; }
new_timer->kclock = &clock_posix_cpu;
timerqueue_init(&new_timer->it.cpu.node);
new_timer->it.cpu.pid = get_pid(pid);
rcu_read_unlock();
return 0;
}
- Arming per-base timerqueue’ye ekleme yapar ve next-expiry cache’i güncelleyebilir:
static void arm_timer(struct k_itimer *timer, struct task_struct *p) {
struct posix_cputimer_base *base = timer_base(timer, p);
struct cpu_timer *ctmr = &timer->it.cpu;
u64 newexp = cpu_timer_getexpires(ctmr);
if (!cpu_timer_enqueue(&base->tqhead, ctmr)) return;
if (newexp < base->nextevt) base->nextevt = newexp;
}
- Hızlı yol, önbelleğe alınmış süresinin dolması olası bir tetiklemeyi gösterene kadar pahalı işlemlerden kaçınır:
static inline bool fastpath_timer_check(struct task_struct *tsk) {
struct posix_cputimers *pct = &tsk->posix_cputimers;
if (!expiry_cache_is_inactive(pct)) {
u64 samples[CPUCLOCK_MAX];
task_sample_cputime(tsk, samples);
if (task_cputimers_expired(samples, pct))
return true;
}
return false;
}
- Sona erme, süresi dolmuş timers’ları toplar, bunları firing olarak işaretler, queue’dan çıkarır; gerçek teslimat ertelenir:
#define MAX_COLLECTED 20
static u64 collect_timerqueue(struct timerqueue_head *head,
struct list_head *firing, u64 now) {
struct timerqueue_node *next; int i = 0;
while ((next = timerqueue_getnext(head))) {
struct cpu_timer *ctmr = container_of(next, struct cpu_timer, node);
u64 expires = cpu_timer_getexpires(ctmr);
if (++i == MAX_COLLECTED || now < expires) return expires;
ctmr->firing = 1; // critical state
rcu_assign_pointer(ctmr->handling, current);
cpu_timer_dequeue(ctmr);
list_add_tail(&ctmr->elist, firing);
}
return U64_MAX;
}
İki sona erme işleme modu
- CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y: sona erme hedef görev üzerinde task_work aracılığıyla ertelenir
- CONFIG_POSIX_CPU_TIMERS_TASK_WORK=n: sona erme doğrudan IRQ bağlamında ele alınır
POSIX CPU timer çalışma yolları
```c void run_posix_cpu_timers(void) { struct task_struct *tsk = current; __run_posix_cpu_timers(tsk); } #ifdef CONFIG_POSIX_CPU_TIMERS_TASK_WORK static inline void __run_posix_cpu_timers(struct task_struct *tsk) { if (WARN_ON_ONCE(tsk->posix_cputimers_work.scheduled)) return; tsk->posix_cputimers_work.scheduled = true; task_work_add(tsk, &tsk->posix_cputimers_work.work, TWA_RESUME); } #else static inline void __run_posix_cpu_timers(struct task_struct *tsk) { lockdep_posixtimer_enter(); handle_posix_cpu_timers(tsk); // IRQ-context path lockdep_posixtimer_exit(); } #endif ```IRQ-context yolunda, firing list sighand dışında işlenir
IRQ-context işleme yolu
```c static void handle_posix_cpu_timers(struct task_struct *tsk) { struct k_itimer *timer, *next; unsigned long flags, start; LIST_HEAD(firing); if (!lock_task_sighand(tsk, &flags)) return; // may fail on exit do { start = READ_ONCE(jiffies); barrier(); check_thread_timers(tsk, &firing); check_process_timers(tsk, &firing); } while (!posix_cpu_timers_enable_work(tsk, start)); unlock_task_sighand(tsk, &flags); // race window opens here list_for_each_entry_safe(timer, next, &firing, it.cpu.elist) { int cpu_firing; spin_lock(&timer->it_lock); list_del_init(&timer->it.cpu.elist); cpu_firing = timer->it.cpu.firing; // read then reset timer->it.cpu.firing = 0; if (likely(cpu_firing >= 0)) cpu_timer_fire(timer); rcu_assign_pointer(timer->it.cpu.handling, NULL); spin_unlock(&timer->it_lock); } } ```Root cause: IRQ-zamanında süresinin dolması ile task çıkışı altındaki eşzamanlı silme arasındaki TOCTOU
Preconditions
- CONFIG_POSIX_CPU_TIMERS_TASK_WORK kapalı (IRQ yolu kullanılıyor)
- Hedef task çıkış yapıyor ancak tamamen toplanmamış
- Başka bir thread aynı timer için posix_cpu_timer_del()’i eşzamanlı olarak çağırıyor
Sequence
- update_process_times() çıkışta olan task için IRQ bağlamında run_posix_cpu_timers()’ı tetikler.
- collect_timerqueue() ctmr->firing = 1 olarak ayarlar ve timer’ı geçici firing listesine taşır.
- handle_posix_cpu_timers() timer’ları kilit dışında teslim etmek için unlock_task_sighand() ile sighand’i serbest bırakır.
- Kilidin hemen ardından, çıkmakta olan task toplanabilir; bir kardeş thread posix_cpu_timer_del()’i çalıştırır.
- Bu pencere içinde, posix_cpu_timer_del() cpu_timer_task_rcu()/lock_task_sighand() aracılığıyla state’i alamayabilir ve böylece timer->it.cpu.firing’i kontrol eden normal in-flight korumasını atlayabilir. Silme, firing durumda değilmiş gibi devam eder; süresinin dolması işlenirken state bozulur ve çökme/UB ile sonuçlanır.
Why TASK_WORK mode is safe by design
- CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y ile süresinin dolması task_work’a ertelenir; exit_task_work exit_notify’dan önce çalışır, bu yüzden IRQ-zamanı ile toplanma çakışması oluşmaz.
- Buna rağmen, task zaten çıkışta ise task_work_add() başarısız olur; exit_state’e göre kontrol etmek her iki modu tutarlı kılar.
Fix (Android common kernel) and rationale
- current task çıkışta ise tüm işlemleri engelleyen erken bir dönüş ekleyin:
// kernel/time/posix-cpu-timers.c (Android common kernel commit 157f357d50b5038e5eaad0b2b438f923ac40afeb)
if (tsk->exit_state)
return;
- Bu, çıkmakta olan görevler için handle_posix_cpu_timers()’e girilmesini engeller; böylece posix_cpu_timer_del()’in it.cpu.firing’i kaçırabileceği ve expiry işlemiyle yarışabileceği pencere ortadan kalkar.
Impact
- Eşzamanlı expiry/silme sırasında zamanlayıcı yapılarına yönelik kernel bellek bozulması hemen çökmelere (DoS) yol açabilir ve keyfi kernel durumu manipülasyonu fırsatları nedeniyle ayrıcalık yükseltmeye yönelik güçlü bir primitive oluşturur.
Triggering the bug (safe, reproducible conditions) Build/config
- Ensure CONFIG_POSIX_CPU_TIMERS_TASK_WORK=n and use a kernel without the exit_state gating fix.
Runtime strategy
- Çıkmak üzere olan bir iş parçacığını hedefleyin ve ona bir CPU timer bağlayın (iş-parçacığı-başı veya süreç-geneli clock):
- For per-thread: timer_create(CLOCK_THREAD_CPUTIME_ID, …)
- For process-wide: timer_create(CLOCK_PROCESS_CPUTIME_ID, …)
- IRQ-path girişlerini maksimize etmek için çok kısa bir ilk sona erme zamanı ve küçük bir aralık ile kurun:
static timer_t t;
static void setup_cpu_timer(void) {
struct sigevent sev = {0};
sev.sigev_notify = SIGEV_SIGNAL; // delivery type not critical for the race
sev.sigev_signo = SIGUSR1;
if (timer_create(CLOCK_THREAD_CPUTIME_ID, &sev, &t)) perror("timer_create");
struct itimerspec its = {0};
its.it_value.tv_nsec = 1; // fire ASAP
its.it_interval.tv_nsec = 1; // re-fire
if (timer_settime(t, 0, &its, NULL)) perror("timer_settime");
}
- Bir sibling thread’ten, target thread sonlanırken aynı timer’ı eşzamanlı olarak silin:
void *deleter(void *arg) {
for (;;) (void)timer_delete(t); // hammer delete in a loop
}
- Yarışı hızlandıran etkenler: yüksek scheduler tick hızı, CPU yükü, tekrar eden iş parçacığı çıkış/yeni oluşturma döngüleri. Çökme genellikle posix_cpu_timer_del() unlock_task_sighand()’den hemen sonra görev araması/locking başarısız olduğu için firing’i fark etmediğinde ortaya çıkar.
Detection and hardening
- Mitigasyon: exit_state guard’ını uygulayın; mümkünse CONFIG_POSIX_CPU_TIMERS_TASK_WORK’u etkinleştirmeyi tercih edin.
- Gözlemlenebilirlik: unlock_task_sighand()/posix_cpu_timer_del() etrafına tracepoint’ler/WARN_ONCE ekleyin; it.cpu.firing==1 gözlenirken cpu_timer_task_rcu()/lock_task_sighand() başarısızlığıyla birlikte uyarı verin; task çıkışı sırasında timerqueue tutarsızlıklarını izleyin.
Audit hotspots (for reviewers)
- update_process_times() → run_posix_cpu_timers() (IRQ)
- __run_posix_cpu_timers() selection (TASK_WORK vs IRQ path)
- collect_timerqueue(): sets ctmr->firing and moves nodes
- handle_posix_cpu_timers(): drops sighand before firing loop
- posix_cpu_timer_del(): relies on it.cpu.firing to detect in-flight expiry; this check is skipped when task lookup/lock fails during exit/reap
Notes for exploitation research
- Açıklanan davranış güvenilir bir kernel crash primitive sağlar; bunu ayrıcalık yükseltmeye (priv-esc) dönüştürmek genellikle bu özetin kapsamı dışındaki ek bir kontrol edilebilir örtüşme (nesne yaşam süresi veya write-what-where etkisi) gerektirir. Herhangi bir PoC’u potansiyel olarak kararsızlaştırıcı olarak değerlendirin ve yalnızca emülatörlerde/VM’lerde çalıştırın.
Chronomaly exploit strategy (priv-esc without fixed text offsets)
- Tested target & configs: x86_64 v5.10.157 under QEMU (4 cores, 3 GB RAM). Critical options:
CONFIG_POSIX_CPU_TIMERS_TASK_WORK=n,CONFIG_PREEMPT=y,CONFIG_SLAB_MERGE_DEFAULT=n,DEBUG_LIST=n,BUG_ON_DATA_CORRUPTION=n,LIST_HARDENED=n. - Race steering with CPU timers: Bir yarışan iş parçacığı (
race_func()) CPU tüketirken CPU timer’ları tetiklenir;free_func()timer’ın tetiklenip tetiklenmediğini doğrulamak içinSIGUSR1’i yoklar.CPU_USAGE_THRESHOLD’u sinyallerin sadece bazen gelmesini sağlayacak şekilde ayarlayın (aralıklı olarak görülen “Parent raced too late/too early” mesajları). Eğer timer’lar her denemede tetikleniyorsa threshold’u düşürün; iş parçacığı çıkmadan önce hiç tetiklenmiyorsa yükseltin. - Dual-process alignment into
send_sigqueue(): Ebeveyn/çocuk süreçlerisend_sigqueue()içinde ikinci bir yarış penceresine girmeye çalışır. Ebeveyn, timer’ları kurmadan öncePARENT_SETTIME_DELAY_USmikro saniye uyur; çoğunlukla “Parent raced too late” görüyorsanız bu değeri düşürün, çoğunlukla “Parent raced too early” görüyorsanız yükseltin. Her ikisini görmeniz pencerenin ortasında olduğunuzu gösterir; bir kez ayarlandığında başarı yaklaşık ~1 dakika içinde beklenir. - Cross-cache UAF replacement: Exploit bir
struct sigqueue’yu free eder ve ardından allocator durumunu (sigqueue_crosscache_preallocs()) düzenler, böylece hem danglinguaf_sigqueuehem de yerine gelenrealloc_sigqueuebir pipe buffer data sayfasına (cross-cache reallocation) yerleşir. Güvenilirlik, daha önce az sayıdasigqueueayrımı olan sessiz bir kernel varsayar; per-CPU/per-node kısmi slab sayfaları zaten mevcutsa (meşgul sistemler), replacement kaçırır ve zincir başarısız olur. Yazar, gürültülü kernel’ler için kasıtlı olarak optimize etmemiştir.
See also
Ksmbd Streams Xattr Oob Write Cve 2025 37947
References
- Race Against Time in the Kernel’s Clockwork (StreyPaws)
- Android security bulletin – September 2025
- Android common kernel patch commit 157f357d50b5…
- Chronomaly exploit PoC (CVE-2025-38352)
- CVE-2025-38352 analysis – Part 1
- CVE-2025-38352 analysis – Part 2
- CVE-2025-38352 analysis – Part 3
Tip
AWS Hacking’i öğrenin ve pratik yapın:
HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking’i öğrenin ve pratik yapın:HackTricks Training GCP Red Team Expert (GRTE)
Azure Hacking’i öğrenin ve pratik yapın:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks'i Destekleyin
- abonelik planlarını kontrol edin!
- 💬 Discord grubuna veya telegram grubuna katılın ya da Twitter’da bizi takip edin 🐦 @hacktricks_live.**
- Hacking ipuçlarını paylaşmak için HackTricks ve HackTricks Cloud github reposuna PR gönderin.


