# 版本變動
# initialize
before init_timer(struct timer_list *)
after timer_setup(struct timer_list *, void (*callback)(struct timer_list *), unsigned int)
# callback
before callback(unsigned long)
after callback(struct timer_list *)
# timer_list
before
struct timer_list { | |
... | |
void (*function)(unsigned long); | |
unsigned long data; | |
... | |
} |
after
struct timer_list { | |
... | |
void (*function)(struct timer_list *); | |
... | |
} |
# 原因
- timer_list 結構膨脹,通常是冗餘的 .data 欄位。
- 沒有執行類型檢查,迫使 callback 將 unsigned long 轉換為傳遞的對象,而不像大多數其他 callback 中使用 container_of () 。
- 相鄰的緩衝區溢位可能會覆蓋 .function 和 .data 字段,為攻擊者提供一種從緩衝區溢位升級到簡單的 ROP(Return-Oriented Programming)類似機制的方式,允許呼叫帶有受控第一 個參數的任意函數。
# Example
# Makefile
mname := brook_timer | |
$(mname)-objs := main.o | |
obj-m := $(mname).o | |
KERNELDIR := /lib/modules/`uname -r`/build | |
all: | |
$(MAKE) -C $(KERNELDIR) M=`pwd` modules | |
clean: | |
$(MAKE) -C $(KERNELDIR) M=`pwd` clean |
# main.c
#include <linux/init.h> | |
#include <linux/module.h> | |
#include <linux/timer.h> | |
MODULE_LICENSE("GPL"); | |
struct data { | |
struct timer_list timer; | |
int count; | |
}; | |
static struct data data; | |
static void timer_callback(struct timer_list *t) | |
{ | |
struct data *dp = from_timer(dp, t, timer); | |
printk("%s(): %d\n", __FUNCTION__, dp->count); | |
if (dp->count--) { | |
mod_timer(&dp->timer, data.timer.expires + 5 * HZ); | |
} else { | |
del_timer(&dp->timer); | |
} | |
} | |
static int __init init_modules(void) | |
{ | |
data.count = 7; | |
timer_setup(&data.timer, timer_callback, 0); | |
data.timer.expires = jiffies + 5 * HZ; | |
add_timer(&data.timer); | |
return 0; | |
} | |
static void __exit exit_modules(void) | |
{ | |
del_timer(&data.timer); | |
} | |
module_init(init_modules); | |
module_exit(exit_modules); |
# 參考來源
- http://nano-chicken.blogspot.com/2009/12/linux-modules71-timer.html
- https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=686fef928bba6be13cabe639f154af7d72b63120