callout_thread uses freed stack memory
Closed this issue · 3 comments
The following scenario, which is present in the kernel (e.g. in sleepq_wait_timed
's implementation), causes race conditionish use-after-scope/use-after-return:
{
callout_t co;
bzero(&co, sizeof(callout_t));
callout_setup_relative(&co, timeout, callback, arg);
/* ... */
callout_stop(&co);
/* co deallocated */
}
There is a probability that callout_stop
will be unsuccessful (because callout_thread
is already processing co
), but in the meantime we'll get to the end of co
's scope and deallocate it. And then callout_thread
will access freed memory (by trying to run / modify co
).
Note: callout_thread
is only using a pointer to the callout, it's not creating any copy.
I went over several files in NetBSD code and it seems they always allocate callout_t
either statically or as a part of some structure, but never alone on a stack.
Their implementation of sleepq_wait_timed
, namely sleepq_block in NetBSD or sleepq_set_timeout_sbt in FreeBSD, uses a field of thread structure (correspondingly lwp::l_timeout_ch
or thread::td_slpcallout
).
This bug is also reported by KASAN:
==========KernelAddressSanitizer==========
ERROR:
* invalid access to address 0xc0025d60
* read of size 4
* redzone code 0xF3 (stack buffer-overflow)
==========================================
(gdb) backtrace full
#0 panic_fail () at /root/mimiker/sys/kern/assert.c:13
#1 0xc010df5c in kasan_shadow_check (read=true, size=4, addr=addr@entry=3221380448) at /root/mimiker/sys/kern/kasan.c:172
#2 __asan_load4_noabort (addr=addr@entry=3221380448) at /root/mimiker/sys/kern/kasan.c:245
#3 0xc013fb10 in callout_thread (arg=<optimized out>) at /root/mimiker/sys/kern/callout.c:58
__scoped52 = 0x0
__loop52 = 0x1
elem = 0xc0025d60
#4 0xc0120444 in thread_self () at /root/mimiker/sys/kern/thread.c:119
While accessing elem
inside callout_thread
.
Error type is stack buffer-overflow as the freed memory contains some stack redzone.
Solved by #683