1// SPDX-License-Identifier: GPL-2.0 2/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ 3 4#include <errno.h> 5#include <string.h> 6#include <linux/bpf.h> 7#include <bpf/bpf_helpers.h> 8#include "bpf_misc.h" 9 10char _license[] SEC("license") = "GPL"; 11 12#define ITER_HELPERS \ 13 __imm(bpf_iter_num_new), \ 14 __imm(bpf_iter_num_next), \ 15 __imm(bpf_iter_num_destroy) 16 17SEC("?raw_tp") 18__success 19int force_clang_to_emit_btf_for_externs(void *ctx) 20{ 21 /* we need this as a workaround to enforce compiler emitting BTF 22 * information for bpf_iter_num_{new,next,destroy}() kfuncs, 23 * as, apparently, it doesn't emit it for symbols only referenced from 24 * assembly (or cleanup attribute, for that matter, as well) 25 */ 26 bpf_repeat(0); 27 28 return 0; 29} 30 31SEC("?raw_tp") 32__success 33int consume_first_item_only(void *ctx) 34{ 35 struct bpf_iter_num iter; 36 37 asm volatile ( 38 /* create iterator */ 39 "r1 = %[iter];" 40 "r2 = 0;" 41 "r3 = 1000;" 42 "call %[bpf_iter_num_new];" 43 44 /* consume first item */ 45 "r1 = %[iter];" 46 "call %[bpf_iter_num_next];" 47 48 "if r0 == 0 goto +1;" 49 "r0 = *(u32 *)(r0 + 0);" 50 51 /* destroy iterator */ 52 "r1 = %[iter];" 53 "call %[bpf_iter_num_destroy];" 54 : 55 : __imm_ptr(iter), ITER_HELPERS 56 : __clobber_common 57 ); 58 59 return 0; 60} 61 62SEC("?raw_tp") 63__failure __msg("R0 invalid mem access 'scalar'") 64int missing_null_check_fail(void *ctx) 65{ 66 struct bpf_iter_num iter; 67 68 asm volatile ( 69 /* create iterator */ 70 "r1 = %[iter];" 71 "r2 = 0;" 72 "r3 = 1000;" 73 "call %[bpf_iter_num_new];" 74 75 /* consume first element */ 76 "r1 = %[iter];" 77 "call %[bpf_iter_num_next];" 78 79 /* FAIL: deref with no NULL check */ 80 "r1 = *(u32 *)(r0 + 0);" 81 82 /* destroy iterator */ 83 "r1 = %[iter];" 84 "call %[bpf_iter_num_destroy];" 85 : 86 : __imm_ptr(iter), ITER_HELPERS 87 : __clobber_common 88 ); 89 90 return 0; 91} 92 93SEC("?raw_tp") 94__failure 95__msg("invalid access to memory, mem_size=4 off=0 size=8") 96__msg("R0 min value is outside of the allowed memory range") 97int wrong_sized_read_fail(void *ctx) 98{ 99 struct bpf_iter_num iter; 100 101 asm volatile ( 102 /* create iterator */ 103 "r1 = %[iter];" 104 "r2 = 0;" 105 "r3 = 1000;" 106 "call %[bpf_iter_num_new];" 107 108 /* consume first element */ 109 "r1 = %[iter];" 110 "call %[bpf_iter_num_next];" 111 112 "if r0 == 0 goto +1;" 113 /* FAIL: deref more than available 4 bytes */ 114 "r0 = *(u64 *)(r0 + 0);" 115 116 /* destroy iterator */ 117 "r1 = %[iter];" 118 "call %[bpf_iter_num_destroy];" 119 : 120 : __imm_ptr(iter), ITER_HELPERS 121 : __clobber_common 122 ); 123 124 return 0; 125} 126 127SEC("?raw_tp") 128__success __log_level(2) 129__flag(BPF_F_TEST_STATE_FREQ) 130int simplest_loop(void *ctx) 131{ 132 struct bpf_iter_num iter; 133 134 asm volatile ( 135 "r6 = 0;" /* init sum */ 136 137 /* create iterator */ 138 "r1 = %[iter];" 139 "r2 = 0;" 140 "r3 = 10;" 141 "call %[bpf_iter_num_new];" 142 143 "1:" 144 /* consume next item */ 145 "r1 = %[iter];" 146 "call %[bpf_iter_num_next];" 147 148 "if r0 == 0 goto 2f;" 149 "r0 = *(u32 *)(r0 + 0);" 150 "r6 += r0;" /* accumulate sum */ 151 "goto 1b;" 152 153 "2:" 154 /* destroy iterator */ 155 "r1 = %[iter];" 156 "call %[bpf_iter_num_destroy];" 157 : 158 : __imm_ptr(iter), ITER_HELPERS 159 : __clobber_common, "r6" 160 ); 161 162 return 0; 163} 164