# 版本變動

# 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