1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Copyright (c) 2022 SUSE LLC <rpalethorpe@suse.com> 4 */ 5 6/*\ 7 * [Description] 8 * 9 * ringbuf_submit takes a pointer to a ringbuf record, but not the 10 * size of this record. The verifier only validates offset ptrs[1] passed 11 * to functions if the function has a size parameter. So we can 12 * perform a wide range of ptr arithmetic on this record ptr. 13 * 14 * ringbuf_submit updates some data (i.e. the length) in the 15 * ringbuf header which is calculated from the record ptr. So this can 16 * be used to corrupt memory. 17 * 18 * This test does not try to cause a crash. Howver it does run the 19 * eBPF if it can. This will result in an instant crash or memory 20 * corruption which may later cause a crash. 21 * 22 * This test is adapted from a full reproducer which can be found here: 23 * https://github.com/tr3ee/CVE-2021-4204 24 * 25 * It's recommended to disable unprivileged eBPF by setting 26 * /proc/sys/kernel/unprivileged_bpf_disabled. Also there is a 27 * specific fix for this issue: 28 * 29 * commit 64620e0a1e712a778095bd35cbb277dc2259281f 30 * Author: Daniel Borkmann <daniel@iogearbox.net> 31 * Date: Tue Jan 11 14:43:41 2022 +0000 32 * 33 * bpf: Fix out of bounds access for ringbuf helpers 34 * 35 * [1]: Depending on the ptr/reg type 36 */ 37 38#include <stdio.h> 39#include <string.h> 40#include <inttypes.h> 41 42#include "config.h" 43#include "tst_test.h" 44#include "tst_taint.h" 45#include "tst_capability.h" 46#include "lapi/bpf.h" 47#include "bpf_common.h" 48 49static const char MSG[] = "Ahoj!"; 50static char *msg; 51 52static int map_fd; 53static uint32_t *key; 54static uint64_t *val; 55static char *log; 56static union bpf_attr *attr; 57 58static int load_prog(void) 59{ 60 int ret; 61 const struct bpf_insn prog_insn[] = { 62 // r0 = bpf_ringbuf_reserve(ctx->ringbuf_fd, 0xff0, 0) 63 BPF_LD_MAP_FD(BPF_REG_1, map_fd), 64 BPF_MOV64_IMM(BPF_REG_2, 0xff0), 65 BPF_MOV64_IMM(BPF_REG_3, 0x00), 66 BPF_EMIT_CALL(BPF_FUNC_ringbuf_reserve), 67 68 // if (r0 == NULL) exit(2) 69 BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 2), 70 BPF_MOV64_IMM(BPF_REG_0, 2), 71 BPF_EXIT_INSN(), 72 73 // r0 = BPF_FUNC_ringbuf_submit(r0-(0x3008-0x38), BPF_RB_NO_WAKEUP) 74 BPF_ALU64_IMM(BPF_SUB, BPF_REG_0, (0x3008-0x38)), 75 BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), 76 BPF_MOV64_IMM(BPF_REG_2, 1), 77 BPF_EMIT_CALL(BPF_FUNC_ringbuf_submit), 78 79 /* exit(0) */ 80 BPF_MOV64_IMM(BPF_REG_0, 0), 81 BPF_EXIT_INSN() 82 }; 83 84 bpf_init_prog_attr(attr, prog_insn, sizeof(prog_insn), log, BUFSIZE); 85 86 ret = TST_RETRY_FUNC(bpf(BPF_PROG_LOAD, attr, sizeof(*attr)), 87 TST_RETVAL_GE0); 88 89 if (ret >= 0) 90 return ret; 91 92 if (ret != -1) 93 tst_brk(TBROK, "Invalid bpf() return value: %d", ret); 94 95 if (log[0] != 0) 96 tst_printf("%s\n", log); 97 98 return ret; 99} 100 101static void setup(void) 102{ 103 rlimit_bump_memlock(); 104 memcpy(msg, MSG, sizeof(MSG)); 105} 106 107static void run(void) 108{ 109 int prog_fd; 110 111 map_fd = bpf_map_create(&(union bpf_attr){ 112 .map_type = BPF_MAP_TYPE_RINGBUF, 113 .key_size = 0, 114 .value_size = 0, 115 .max_entries = getpagesize() 116 }); 117 118 tst_res(TINFO, "Trying to load eBPF with OOB write"); 119 prog_fd = load_prog(); 120 if (prog_fd == -1) { 121 tst_res(TPASS, "Failed verification"); 122 return; 123 } 124 125 tst_res(TFAIL, "Loaded program with OOB write"); 126 tst_res(TINFO, "Running eBPF with OOB"); 127 bpf_run_prog(prog_fd, msg, sizeof(MSG)); 128 tst_res(TINFO, "Ran eBPF"); 129 130 SAFE_CLOSE(prog_fd); 131} 132 133static struct tst_test test = { 134 .setup = setup, 135 .test_all = run, 136 .min_kver = "5.8", 137 .taint_check = TST_TAINT_W | TST_TAINT_D, 138 .caps = (struct tst_cap []) { 139 TST_CAP(TST_CAP_DROP, CAP_SYS_ADMIN), 140 TST_CAP(TST_CAP_DROP, CAP_BPF), 141 {} 142 }, 143 .bufs = (struct tst_buffers []) { 144 {&key, .size = sizeof(*key)}, 145 {&val, .size = sizeof(*val)}, 146 {&log, .size = BUFSIZE}, 147 {&attr, .size = sizeof(*attr)}, 148 {&msg, .size = sizeof(MSG)}, 149 {} 150 }, 151 .tags = (const struct tst_tag[]) { 152 {"linux-git", "64620e0a1e71"}, 153 {"CVE", "CVE-2021-4204"}, 154 {} 155 } 156}; 157