timer: Add function-change canary
RFC PATCH 1/1 timer: Add function-change canary
This introduces canaries to struct timer_list in an effort to protect the function callback pointer from getting rewritten during stack or heap overflow attacks. The struct timer_list has become a recent target for security flaw exploitation because it includes the "data" argument in the structure, along with the function callback. This provides attackers with a ROP-like primitive for performing limited kernel function calls without needing all the prerequisites to stage a ROP attack.
Recent examples of exploits using struct timer_list attacks:
http://www.openwall.com/lists/oss-security/2016/12/06/1
(https://www.exploit-db.com/exploits/40871/)
https://googleprojectzero.blogspot.com/2017/05/exploiting-linux-kernel-via-packet.html
(https://www.exploit-db.com/exploits/41458/)
Timers normally have their callback functions initialized either via the setup_timer_*() macros or manually before calls to add_timer(). The per-timer canary gets set in either case, and then checked at timer expiration time before calling the function.
--- include/linux/timer.h | 6 ++++-- kernel/time/timer.c | 45 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 48 insertions(+), 3 deletions(-)
include/linux/timer.h +4 -2
@@ -16,6 +16,7 @@ struct timer_list {*/ struct hlist_node entry;unsigned long expires; +unsigned long canary;void (*function)(unsigned long );unsigned long data;u32 flags;
@@ -91,6 +92,7 @@ struct timer_list {void init_timer_key (struct timer_list *timer,unsigned int flags,const char *name,struct lock_class_key *key); +void init_timer_func (struct timer_list *timer,void (*func)(unsigned long ));#ifdef CONFIG_DEBUG_OBJECTS_TIMERS extern void init_timer_on_stack_key(struct timer_list *timer,
@@ -140,14 +142,14 @@ static inline void init_timer_on_stack_key(struct timer_list *timer,#define __setup_timer (_timer, _fn, _data, _flags) \ do { \ __init_timer((_timer), (_flags)); \ - (_timer)->function = (_fn); \ + init_timer_func((_timer), (_fn)); \ (_timer)->data = (_data); \ } while (0)#define __setup_timer_on_stack (_timer, _fn, _data, _flags) \ do { \ __init_timer_on_stack((_timer), (_flags)); \ - (_timer)->function = (_fn); \ + init_timer_func((_timer), (_fn)); \ (_timer)->data = (_data); \ } while (0)
kernel/time/timer.c +44 -1
87 lines not on this page · raw message
Signature · 6 lines
2.7.4 -- Kees Cook Pixel Security
Quoted 13 lines · Kees Cook
This introduces canaries to struct
timer_listin an effort to protect the function callback pointer from getting rewritten during stack or heap overflow attacks. The structtimer_listhas become a recent target for security flaw exploitation because it includes the "data" argument in the structure, along with the function callback. This provides attackers with a ROP-like primitive for performing limited kernel function calls without needing all the prerequisites to stage a ROP attack.Recent examples of exploits using struct
timer_listattacks:http://www.openwall.com/lists/oss-security/2016/12/06/1
(https://www.exploit-db.com/exploits/40871/)
Quoted 7 lines
https://googleprojectzero.blogspot.com/2017/05/exploiting-linux-kernel-via-packet.html
(https://www.exploit-db.com/exploits/41458/)Timers normally have their callback functions initialized either via the setup_timer_*() macros or manually before calls to
add_timer(). The per-timer canary gets set in either case, and then checked at timer expiration time before calling the function.
Har har, I missed DEFINE_TIMER() which is rather widely used. :P
I'll send a v2, though the canary may end up being a bit weaker to deal with static initializers.
-Kees
Signature · 2 lines
Kees Cook Pixel Security