6 - Improvements: KASAN#

We have room to improve our current fuzzing setup.

In fact, the Linux kernel can be compiled with KASAN (Kernel Address Sanitizer), which is a dynamic memory safety error detector.

It provides a fast and comprehensive solution for finding use-after-free and out-of-bounds bugs, with a compile-time instrumentation for checking every memory access.

Compiling with KASAN#

Let’s have a quick look at our Makefile again:

Makefile rule to build the kernel bzImage#
1$(LINUX_AGENT_BZIMAGE):
2	$(MAKE) -C $(LINUX_AGENT_DIR) x86_64_defconfig
3	cd $(LINUX_AGENT_DIR) && ./scripts/config --disable MODULE_SIG
4	cd $(LINUX_AGENT_DIR) && ./scripts/config --enable DEBUG_INFO_DWARF5
5	cd $(LINUX_AGENT_DIR) && ./scripts/config --enable GDB_SCRIPTS
6ifdef DVKM_KASAN
7	cd $(LINUX_AGENT_DIR) && ./scripts/config --enable KASAN
8	cd $(LINUX_AGENT_DIR) && ./scripts/config --enable KASAN_INLINE
9endif

And recompile our target with KASAN checks enabled:

(.venv) cd $EXAMPLES_ROOT/linux-user/dvkm
(.venv) make clean && make DVKM_KASAN=y

Thanks to the KASAN kAFL event inserted into kasan_report, we should detect new memory corruption crashes in kAFL:

Modified mm/kasan/report.c#
 #include <asm/sections.h>

+#include <asm/nyx_api.h>
+
 #include "kasan.h"
 #include "../slab.h"

@@ -588,6 +590,7 @@ bool kasan_report(const void *addr, size_t size, bool is_write,
        print_report(&info);

        end_report(&irq_flags, (void *)addr, is_write);
+       kAFL_hypercall(HYPERCALL_KAFL_KASAN, 0);

 out:
        user_access_restore(ua_flags);

Running an enhanced campaign#

We can now run our fuzzing campaign again, and watch for the results.

In just 30 seconds, kAFL was able to find 8 KASAN related crashes:

  ┏━┫▌kAFL Grand UI▐┣━┓
┏━┻━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Runtime:    0m33s  #Execs:    249.7K │ Stability:     6% │ Workers:   20/64 ┃                    CurExec/s:   9824  Funkiness:   0.0%  CPU Use:      0% ┃
┃ Est. Done:    40%  AvgExec/s:   7529  Timeouts:    0.1%  RAM Use:      1% ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
┏━━❮❰ Progress ❱❯━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃                                                                              ┃
┃ Paths:             Bitmap:            Findings:                            ┃
┃  Total:        38                      Crash:           5 (N/A)      0m27s ┃
┃  Seeds:        23   Edges:       100   AddSan:          8 (N/A)      0m23s ┃
┃  Favs:         38   Blocks:      150   Timeout:        12 (N/A)      0m08s ┃
┃  Norm:          0   p(col):     0.2%   Regular:        38 (N/A)      0m15s ┃
┠──────────────────────────────────────────────────────────────────────────────┨

Viewing a KASAN report#

We can already stop our fuzzing campaign by now, and check into 📂 $KAFL_WORKDIR/corpus/kasan:

(.venv) ls -l $KAFL_WORKDIR/corpus/kasan
total 32
-rw-r--r-- 1 mtarral mtarral 12 Oct 26 06:40 payload_00026
-rw-r--r-- 1 mtarral mtarral 12 Oct 26 06:40 payload_00036
-rw-r--r-- 1 mtarral mtarral 12 Oct 26 06:40 payload_00038
-rw-r--r-- 1 mtarral mtarral 12 Oct 26 06:40 payload_00039
-rw-r--r-- 1 mtarral mtarral 12 Oct 26 06:40 payload_00040
-rw-r--r-- 1 mtarral mtarral 12 Oct 26 06:40 payload_00044
-rw-r--r-- 1 mtarral mtarral 12 Oct 26 06:40 payload_00048
-rw-r--r-- 1 mtarral mtarral  1 Oct 26 06:40 payload_00059

Our 8 crashing KASAN payloads are regrouped here.

Let’s now have a look at the hprintf logs associated with a KASAN crash:

(.venv) ls -l $KAFL_WORKDIR/logs/kasan_*.log
-rw-rw-r-- 1 mtarral mtarral 3376 Oct 26 06:40 /dev/shm/kafl_mtarral/logs/kasan_020e1d.log
-rw-rw-r-- 1 mtarral mtarral 3565 Oct 26 06:40 /dev/shm/kafl_mtarral/logs/kasan_1bfee1.log
-rw-rw-r-- 1 mtarral mtarral 2773 Oct 26 06:40 /dev/shm/kafl_mtarral/logs/kasan_2253d6.log
-rw-rw-r-- 1 mtarral mtarral 3101 Oct 26 06:40 /dev/shm/kafl_mtarral/logs/kasan_79191f.log
-rw-rw-r-- 1 mtarral mtarral 3517 Oct 26 06:40 /dev/shm/kafl_mtarral/logs/kasan_9251db.log
-rw-rw-r-- 1 mtarral mtarral 3365 Oct 26 06:40 /dev/shm/kafl_mtarral/logs/kasan_a034fe.log
-rw-rw-r-- 1 mtarral mtarral 3514 Oct 26 06:40 /dev/shm/kafl_mtarral/logs/kasan_b91a90.log
-rw-rw-r-- 1 mtarral mtarral 3388 Oct 26 06:40 /dev/shm/kafl_mtarral/logs/kasan_f0e92d.log

Let’s now open the first one: kasan_020e1d.log:

6****Triggering use after free****
6dvkm: [+] datasize: 16
3==================================================================
3BUG: KASAN: slab-out-of-bounds in string+0x2a0/0x320
3Read of size 1 at addr ffff888008511390 by task fuzz_dvkm/75
3
3CPU: 0 PID: 75 Comm: fuzz_dvkm Tainted: G           O       6.5.0-00004-g6521682f674d #11
3Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.12.0-59-gc9ba5276e321-prebuilt.qemu.org 04/01/2014
3Call Trace:
3 <TASK>
3 dump_stack_lvl+0x37/0x50
3 print_report+0xcc/0x620
3 ? string+0x2a0/0x320
3 kasan_report+0xb0/0xf0
3 ? string+0x2a0/0x320
3 string+0x2a0/0x320
3 ? __x64_sys_ioctl+0x12d/0x1a0
3 ? __pfx_string+0x10/0x10
3 ? __pte_offset_map_lock+0xdf/0x1e0
3 vsnprintf+0x809/0x1600
3 ? __pfx_vsnprintf+0x10/0x10
3 ? ioctl_has_perm.constprop.0.isra.0+0x274/0x440
3 _printk+0xce/0x120
3 ? __pfx__printk+0x10/0x10
3 ? kasan_set_track+0x25/0x30
3 ? __kasan_kmalloc+0x7f/0x90
3 Use_after_free_IOCTL_Handler.part.0+0x71/0xb0 [dvkm]
3 dvkm_ioctl+0x1b2/0x230 [dvkm]
3 proc_reg_unlocked_ioctl+0x1a1/0x270
3 __x64_sys_ioctl+0x12d/0x1a0
3 do_syscall_64+0x3c/0x90
3 entry_SYSCALL_64_after_hwframe+0x6e/0xd8
3RIP: 0033:0x7fec88b37b3f
3Code: 00 48 89 44 24 18 31 c0 48 8d 44 24 60 c7 04 24 10 00 00 00 48 89 44 24 08 48 8d 44 24 20 48 89 44 24 10 b8 10 00 00 00 0f 05 <41> 89 c0 3d 00 f0 ff ff 77 1f 48 8b 44 24 18 64 48 2b 04 25 28 00
3RSP: 002b:00007ffe5d840a80 EFLAGS: 00000246c ORIG_RAX: 0000000000000010
3RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fec88b37b3f
3RDX: 000056144fe16000 RSI: 00000000c018440a RDI: 0000000000000003
3RBP: 00007ffe5d840b10 R08: 0000000000000010 R09: 00007ffe5d83f7f0
3R10: 0000000000000000 R11: 0000000000000246 R12: 00007ffe5d840c28
3R13: 000056144fe119e0 R14: 000056144fe13d48 R15: 00007fec88c81040
3 </TASK>
3
3Allocated by task 75:
 kasan_save_stack+0x22/0x50
 kasan_set_track+0x25/0x30
 __kasan_kmalloc+0x7f/0x90
 __kmalloc+0x5a/0x140
 Use_after_free_IOCTL_Handler.part.0+0x2f/0xb0 [dvkm]
 dvkm_ioctl+0x1b2/0x230 [dvkm]
 proc_reg_unlocked_ioctl+0x1a1/0x270
 __x64_sys_ioctl+0x12d/0x1a0
 do_syscall_64+0x3c/0x90
 entry_SYSCALL_64_after_hwframe+0x6e/0xd8
3
3The buggy address belongs to the object at ffff888008511380
 which belongs to the cache kmalloc-16 of size 16
3The buggy address is located 0 bytes to the right of
 allocated 16-byte region [ffff888008511380, ffff888008511390)
3
3The buggy address belongs to the physical page:
4page:(____ptrval____) refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x8511
4flags: 0x100000000000200(slab|node=0|zone=1)
4page_type: 0xffffffff()
4raw: 0100000000000200 ffff8880064413c0 dead000000000122 0000000000000000
4raw: 0000000000000000 0000000080800080 00000001ffffffff 0000000000000000
4page dumped because: kasan: bad access detected
3
3Memory state around the buggy address:
3 ffff888008511280: 00 00 fc fc 00 00 fc fc 00 00 fc fc 00 00 fc fc
3 ffff888008511300: 00 04 fc fc 00 00 fc fc 00 03 fc fc 00 00 fc fc
3>ffff888008511380: 00 00 fc fc fb fb fc fc fb fb fc fc fb fb fc fc
3                         ^
3 ffff888008511400: 00 06 fc fc 00 04 fc fc 00 00 fc fc 00 04 fc fc
3 ffff888008511480: 00 07 fc fc 00 04 fc fc 00 04 fc fc 00 04 fc fc
3==================================================================
4Disabling lock debugging due to kernel taint

This is a use-after-free crash !

Feel free to investigate the detailed KASAN report, or consult the official documentation

This marks the end of the DVKM tutorial ! 🎉

You should have a better understanding of kAFL, a solid workflow to fuzz your Linux kernel modules and insights how to debug them !