Skip to content

timer_list / hrtimer function-pointer hijack

Heap'te bulunan bir struct timer_list (veya struct hrtimer) object'inin function pointer'ını corrupt et; böylece timer ateşlendiğinde kernel, argüman olarak timer object'inin kendisiyle attacker'ın seçtiği bir adresi çağırır.

Mechanism

Note

struct timer_list klasik low-resolution timer'dır. Süresi dolduğunda kernel, function pointer'ını tek argüman olarak timer pointer'ının kendisini geçirerek çağırır (modern signature void (*function)(struct timer_list *)). Dolayısıyla function'ı corrupt etmek, kernel'in arg0 olarak (attacker'ın etkileyebileceği) timer object'i ile attacker'ın seçtiği bir adresi çağırmasını sağlar — bir mov rsp, [rdi+x] stack pivot veya tek seferlik bir call gadget için ideal. High-resolution muadili struct hrtimer'dır; callback'i enum hrtimer_restart (*function)(struct hrtimer *)'dir ve HRTIMER_NORESTART ya da HRTIMER_RESTART döndürmelidir. Her iki callback de softirq/interrupt context'inden çalışır (timer_list için __run_timers / run_timer_softirq; hrtimer için hrtimer softirq'i), dolayısıyla hijack edilen control flow herhangi bir task context'i dışında yürütülür.

Walkthrough

Struct (include/linux/timer_types.h'tan birebir):

struct timer_list {
    struct hlist_node   entry;       /* +0x00, 16 bytes */
    unsigned long       expires;     /* +0x10 */
    void                (*function)(struct timer_list *);  /* +0x18 */
    u32                 flags;       /* +0x20 */
#ifdef CONFIG_LOCKDEP
    struct lockdep_map  lockdep_map;
#endif
};
  1. Bir write primitive (UAF, overflow veya arbitrary write) kullanarak +0x18 offset'indeki function'ı hedef adresle overwrite et. +0x10'daki expires, ne zaman ateşleneceğini kontrol eder — callback'i talep üzerine tetikleyecek şekilde arm et.
  2. Timer ateşlendiğinde kernel, rdi timer object'ine işaret eder halde kontrolü aktararak timer->function(timer)'a eşdeğer işlemi gerçekleştirir.
  3. hrtimer için, embedded function field'ını (normal işleyişte timerfd_tmrproc gibi bir .text pointer'ı) overwrite et ve aynı etki için süresinin dolmasını bekle; callback, enum hrtimer_restart dönüş konvansiyonuna uymalıdır.

Warning

Callback softirq/IRQ context'inde çalışır — "herhangi bir task ile ilişkili değildir" — bu nedenle bir ROP chain tipik olarak doğrudan return etmek yerine msleep() ve bir fork()/"telefork" hilesiyle biter; böylece privileged bir userspace task geri kazanılır.

Mitigation

  • CFI (CONFIG_CFI_CLANG / kCFI), indirect-call hedefinin type signature'ını doğrular ve arbitrary bir adrese yapılan call-through'u bloklar.
  • timer_list/hrtimer birçok heap object'inin içine embed edildiği için, CFI'nin özellikle hedeflediği generic bir write-what-where → control-flow primitive'idir.

References