Вы узнаете о том, как при помощи syzkaller обнаружить уязвимости ядра Linux. syzkaller — инструмент для фаззинга системных вызовов Linux. Во время тестирования ядра Linux внутри компании Google фаззер нашел более 400 уязвимостей; внешними пользователями также было обнаружено множество ошибок.
1. How to find 0days
in the Linux kernel
Andrey Konovalov <andreyknvl@google.com>
PHDays 2017
May 23-24th 2017
2. Userspace tools
● AddressSanitizer, ThreadSanitizer, MemorySanitizer, ...
○ C/C++/Go bug detectors
○ Detect wide range of bug types (use-after-frees and out-of-bounds, data
races and deadlocks, uninitialized memory uses, undefined behaviors)
○ Built into Clang, GCC and Go compiler
● libFuzzer
○ In-process coverage-guided fuzzing engine for C/C++
● oss-fuzz
○ Continuous fuzzing service for open source software
3. Finding bugs in the Linux kernel
Dynamic bug finding tools:
● Bug detectors
● Fuzzers
5. Kernel Sanitizers
● KASAN (use-after-frees and out-of-bounds)
○ CONFIG_KASAN available upstream since 4.0
● KTSAN (data-races and deadlocks)
○ prototype available at https://github.com/google/ktsan
● KMSAN (uninitialized-memory-use)
○ prototype available at https://github.com/google/kmsan
6. KASAN report
BUG: KASAN: use-after-free in sctp_id2assoc+0x3a3/0x3b0
net/sctp/socket.c:224
Read of size 8 at addr ffff8800385b6838 by task syz-executor2/5889
Call Trace:
sctp_id2assoc+0x3a3/0x3b0 net/sctp/socket.c:224
sctp_setsockopt_rtoinfo net/sctp/socket.c:2931 [inline]
sctp_setsockopt+0x4b7/0x60f0 net/sctp/socket.c:4018
sock_common_setsockopt+0x95/0xd0 net/core/sock.c:2850
SYSC_setsockopt net/socket.c:1798 [inline]
SyS_setsockopt+0x270/0x3a0 net/socket.c:1777
entry_SYSCALL_64_fastpath+0x1f/0xbe
9. syzkaller
● Coverage-guided syscall fuzzer for the Linux kernel
● As of now found over 400 bugs
(https://github.com/google/syzkaller/wiki/Found-Bugs)
● Over 25 CVEs
● At least 3 public local privilege escalation bugs over the
last few months (CVE-2017-7308, CVE-2017-6074,
CVE-2017-2636)
● Can generate C reproducers for found bugs
10. Coverage-guided fuzzing
(Think AFL or libFuzzer)
void TestOneInput(const char *data, int size) {
/* do something with data */
}
Fuzzer invokes the function with different inputs
Code coverage guiding:
● Corpus of “interesting” inputs
● Mutate and execute inputs from corpus
● If inputs gives new coverage, add it to corpus
15. Syscall descriptions:
resources
resource sock[fd]
socket(domain flags[socket_domain], type flags[socket_type],
proto int8) sock
bind(fd sock, addr ptr[in, sockaddr_storage], addrlen len[addr])
resource sock_packet[sock]
socket$packet(domain const[AF_PACKET], type flags[packet_socket_type],
proto const[ETH_P_ALL_BE]) sock_packet
bind$packet(fd sock_packet, addr ptr[in, sockaddr_ll], addrlen len[addr])
16. Programs
The description allows to generate and mutate "programs" in
the following form:
mmap(&(0x7f0000000000), (0x1000), 0x3, 0x32, -1, 0)
r0 = open(&(0x7f0000000000)="./file0", 0x3, 0x9)
read(r0, &(0x7f0000000000), 42)
close(r0)
17. Algorithm
1. Start with empty corpus of programs
2. Generate a new program, or choose an existing program
from corpus and mutate it
3. Interpret the program, collect coverage
4. If a syscall covers code that wasn't covered previously,
minimize program and add to corpus
5. Goto 1
20. Finding 0days in the Linux kernel
1. Setup syzkaller
2. Write syscall descriptions for some previously untested
kernel interface
3. Specify syscalls required to interact with this interface in
the configuration file
4. Run syzkaller and discover bugs
23. Coverage for the Linux kernel
● Available upstream with CONFIG_KCOV
● GCC pass that inserts a function call into every basic block
● kernel debugfs extension that collects and exposes coverage per-thread
__fuzz_coverage();
if (...) {
__fuzz_coverage();
...
}
__fuzz_coverage();
if (...) {
...
}
26. Other Linux kernel fuzzers
● https://github.com/oracle/kernel-fuzzing
● https://github.com/nccgroup/TriforceLinuxSyscallFuzzer
● http://web.eece.maine.edu/~vweaver/projects/perf_events/f
uzzer/
● https://github.com/schumilo/vUSBf
27. External Stimulus
Systems calls and external stimulus in the same program:
listen(r0)
emit_ethernet(syn)
emit_ethernet(ack)
r1 = accept(r0)
emit_ethernet(data)
read(r1)
emit_ethernet(rst)
Work in progress; also applicable to USB, ...
28. Existing system call fuzzers
Trinity in essence:
syscall(rand(), rand(), rand());
Knows argument types, so more like:
syscall(rand(), rand_fd(), rand_addr());
● Tend to find shallow bugs
● Frequently no reproducers