Please check this doc first before you proceed.
Similar to CVE-2017-7533, we do not have PoC in Syzkaller's format. Instead, we need to annotate the C code directly. See poc.c
for the final output.
sh make.sh
s2e new_project -n udp -i debian-9.2.1-x86_64 -f poc
cd aeg-analysis
python main.py pahole -i ../s2e/image/.tmp-output/linux-4.9.3-x86_64/linux-4.9.3/vmlinux --known
python main.py genconf -p udp -i ../s2e/image/.tmp-output/linux-4.9.3-x86_64/linux-4.9.3/vmlinux -e -m 1
cd ${S2EDIR}/projects/inotify && timeout 60s ./launch-s2e.sh
Note that this bug causes the kernel to hang, therefore we set a timeout for it.
Different from other PoC, in this case some OOB access is not detected by default KASAN, which we rely on as the first step to locate the vulnerable object. The reason is that some memory operation performed by assembly code is not checked by sanitizer, and thus we have to further analyze it to assist the tool.
python main.py genconf -p udp -i ../s2e/image/.tmp-output/linux-4.9.3-x86_64/linux-4.9.3/vmlinux -e -m 2
Due to the aforementioned reason, this step fails to locate the vulnerable object, but it shows some messages like:
DEBUG | 2020-08-06 14:32:00,415 | aeg.util | {'Addr': 0, 'ip': 18446744071592931174}
DEBUG | 2020-08-06 14:32:00,415 | aeg.util | {'Addr': 18446612133246106608, 'ip': 18446744071580286340}
... ...
where ip
is the PC address where KASAN detect something went wrong. If we take a look at the first log, it shows a null pointer deference. By using addr2line
we could know it happens at net/core/skbuff.c:604
(SOURCE). From the source code, we can confirm the statement uarg->callback
is the trouble maker if uarg
is a null pointer. We also learn that uarg
come from shinfo
, which is the vulnerable object.
600 if (shinfo->tx_flags & SKBTX_DEV_ZEROCOPY) {
601 struct ubuf_info *uarg;
602
603 uarg = shinfo->destructor_arg;
604 if (uarg->callback)
605 uarg->callback(uarg, true);
606 }
By inspecting the assembly code, we find the register %r12
corresponding to the variable shinfo
.
0xffffffff81d6ef59 <+329>: mov 0x28(%r12),%rbx
0xffffffff81d6ef5e <+334>: mov %rbx,%rdi
0xffffffff81d6ef61 <+337>: callq 0xffffffff812b8650 <__asan_load8>
0xffffffff81d6ef66 <+342>: mov (%rbx),%r13
Now we could adjust s2e-config.lua
to implement a simple script to tell S2E how to deal with it as follows.
pluginsConfig.KernelInstructionTracer = {
... ...
annotations = {
fun_0 = {
pc = 0xffffffff81d6ef4f,
onExecute = "track"
}
},
... ...
}
function track(state, pc)
plg = g_s2e:getPlugin("KernelInstructionTracer")
local addr = plg:readRegister(state, "r12")
plg:findObject(state, addr)
end
Now let's re-run it.
cd ${S2EDIR}/projects/udp && timeout 60s ./launch-s2e.sh # locate the vulnerable object
# Now the next step can succeed
python main.py genconf -p udp -i ../s2e/image/.tmp-output/linux-4.9.3-x86_64/linux-4.9.3/vmlinux -e -m 2
cd ${S2EDIR}/projects/udp && timeout 60s ./launch-s2e.sh
python main.py genconf -p udp -i ../s2e/image/.tmp-output/linux-4.9.3-x86_64/linux-4.9.3/vmlinux -e -m 3
cd ${S2EDIR}/projects/udp && ./launch-s2e.sh
python main.py parselog -p udp --solution
Now we should have ans_kmalloc_2048.json
in ${S2EDIR}/projects/udp
.