Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/bpf: verifier/map_ptr_mixing converted to inline assembly

Test verifier/map_ptr_mixing automatically converted to use inline assembly.

Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/r/20230421174234.2391278-13-eddyz87@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Eduard Zingerman and committed by
Alexei Starovoitov
aee1779f 4a400ef9

+267 -100
+2
tools/testing/selftests/bpf/prog_tests/verifier.c
··· 36 36 #include "verifier_lwt.skel.h" 37 37 #include "verifier_map_in_map.skel.h" 38 38 #include "verifier_map_ptr.skel.h" 39 + #include "verifier_map_ptr_mixing.skel.h" 39 40 #include "verifier_map_ret_val.skel.h" 40 41 #include "verifier_masking.skel.h" 41 42 #include "verifier_meta_access.skel.h" ··· 123 122 void test_verifier_lwt(void) { RUN(verifier_lwt); } 124 123 void test_verifier_map_in_map(void) { RUN(verifier_map_in_map); } 125 124 void test_verifier_map_ptr(void) { RUN(verifier_map_ptr); } 125 + void test_verifier_map_ptr_mixing(void) { RUN(verifier_map_ptr_mixing); } 126 126 void test_verifier_map_ret_val(void) { RUN(verifier_map_ret_val); } 127 127 void test_verifier_masking(void) { RUN(verifier_masking); } 128 128 void test_verifier_meta_access(void) { RUN(verifier_meta_access); }
+265
tools/testing/selftests/bpf/progs/verifier_map_ptr_mixing.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Converted from tools/testing/selftests/bpf/verifier/map_ptr_mixing.c */ 3 + 4 + #include <linux/bpf.h> 5 + #include <bpf/bpf_helpers.h> 6 + #include "bpf_misc.h" 7 + 8 + #define MAX_ENTRIES 11 9 + 10 + struct test_val { 11 + unsigned int index; 12 + int foo[MAX_ENTRIES]; 13 + }; 14 + 15 + struct { 16 + __uint(type, BPF_MAP_TYPE_ARRAY); 17 + __uint(max_entries, 1); 18 + __type(key, int); 19 + __type(value, struct test_val); 20 + } map_array_48b SEC(".maps"); 21 + 22 + struct { 23 + __uint(type, BPF_MAP_TYPE_HASH); 24 + __uint(max_entries, 1); 25 + __type(key, long long); 26 + __type(value, struct test_val); 27 + } map_hash_48b SEC(".maps"); 28 + 29 + struct { 30 + __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS); 31 + __uint(max_entries, 1); 32 + __type(key, int); 33 + __type(value, int); 34 + __array(values, struct { 35 + __uint(type, BPF_MAP_TYPE_ARRAY); 36 + __uint(max_entries, 1); 37 + __type(key, int); 38 + __type(value, int); 39 + }); 40 + } map_in_map SEC(".maps"); 41 + 42 + void dummy_prog_42_socket(void); 43 + void dummy_prog_24_socket(void); 44 + void dummy_prog_loop1_socket(void); 45 + void dummy_prog_loop2_socket(void); 46 + 47 + struct { 48 + __uint(type, BPF_MAP_TYPE_PROG_ARRAY); 49 + __uint(max_entries, 4); 50 + __uint(key_size, sizeof(int)); 51 + __array(values, void (void)); 52 + } map_prog1_socket SEC(".maps") = { 53 + .values = { 54 + [0] = (void *)&dummy_prog_42_socket, 55 + [1] = (void *)&dummy_prog_loop1_socket, 56 + [2] = (void *)&dummy_prog_24_socket, 57 + }, 58 + }; 59 + 60 + struct { 61 + __uint(type, BPF_MAP_TYPE_PROG_ARRAY); 62 + __uint(max_entries, 8); 63 + __uint(key_size, sizeof(int)); 64 + __array(values, void (void)); 65 + } map_prog2_socket SEC(".maps") = { 66 + .values = { 67 + [1] = (void *)&dummy_prog_loop2_socket, 68 + [2] = (void *)&dummy_prog_24_socket, 69 + [7] = (void *)&dummy_prog_42_socket, 70 + }, 71 + }; 72 + 73 + SEC("socket") 74 + __auxiliary __auxiliary_unpriv 75 + __naked void dummy_prog_42_socket(void) 76 + { 77 + asm volatile ("r0 = 42; exit;"); 78 + } 79 + 80 + SEC("socket") 81 + __auxiliary __auxiliary_unpriv 82 + __naked void dummy_prog_24_socket(void) 83 + { 84 + asm volatile ("r0 = 24; exit;"); 85 + } 86 + 87 + SEC("socket") 88 + __auxiliary __auxiliary_unpriv 89 + __naked void dummy_prog_loop1_socket(void) 90 + { 91 + asm volatile (" \ 92 + r3 = 1; \ 93 + r2 = %[map_prog1_socket] ll; \ 94 + call %[bpf_tail_call]; \ 95 + r0 = 41; \ 96 + exit; \ 97 + " : 98 + : __imm(bpf_tail_call), 99 + __imm_addr(map_prog1_socket) 100 + : __clobber_all); 101 + } 102 + 103 + SEC("socket") 104 + __auxiliary __auxiliary_unpriv 105 + __naked void dummy_prog_loop2_socket(void) 106 + { 107 + asm volatile (" \ 108 + r3 = 1; \ 109 + r2 = %[map_prog2_socket] ll; \ 110 + call %[bpf_tail_call]; \ 111 + r0 = 41; \ 112 + exit; \ 113 + " : 114 + : __imm(bpf_tail_call), 115 + __imm_addr(map_prog2_socket) 116 + : __clobber_all); 117 + } 118 + 119 + SEC("tc") 120 + __description("calls: two calls returning different map pointers for lookup (hash, array)") 121 + __success __retval(1) 122 + __naked void pointers_for_lookup_hash_array(void) 123 + { 124 + asm volatile (" \ 125 + /* main prog */ \ 126 + if r1 != 0 goto l0_%=; \ 127 + call pointers_for_lookup_hash_array__1; \ 128 + goto l1_%=; \ 129 + l0_%=: call pointers_for_lookup_hash_array__2; \ 130 + l1_%=: r1 = r0; \ 131 + r2 = 0; \ 132 + *(u64*)(r10 - 8) = r2; \ 133 + r2 = r10; \ 134 + r2 += -8; \ 135 + call %[bpf_map_lookup_elem]; \ 136 + if r0 == 0 goto l2_%=; \ 137 + r1 = %[test_val_foo]; \ 138 + *(u64*)(r0 + 0) = r1; \ 139 + r0 = 1; \ 140 + l2_%=: exit; \ 141 + " : 142 + : __imm(bpf_map_lookup_elem), 143 + __imm_const(test_val_foo, offsetof(struct test_val, foo)) 144 + : __clobber_all); 145 + } 146 + 147 + static __naked __noinline __attribute__((used)) 148 + void pointers_for_lookup_hash_array__1(void) 149 + { 150 + asm volatile (" \ 151 + r0 = %[map_hash_48b] ll; \ 152 + exit; \ 153 + " : 154 + : __imm_addr(map_hash_48b) 155 + : __clobber_all); 156 + } 157 + 158 + static __naked __noinline __attribute__((used)) 159 + void pointers_for_lookup_hash_array__2(void) 160 + { 161 + asm volatile (" \ 162 + r0 = %[map_array_48b] ll; \ 163 + exit; \ 164 + " : 165 + : __imm_addr(map_array_48b) 166 + : __clobber_all); 167 + } 168 + 169 + SEC("tc") 170 + __description("calls: two calls returning different map pointers for lookup (hash, map in map)") 171 + __failure __msg("only read from bpf_array is supported") 172 + __naked void lookup_hash_map_in_map(void) 173 + { 174 + asm volatile (" \ 175 + /* main prog */ \ 176 + if r1 != 0 goto l0_%=; \ 177 + call lookup_hash_map_in_map__1; \ 178 + goto l1_%=; \ 179 + l0_%=: call lookup_hash_map_in_map__2; \ 180 + l1_%=: r1 = r0; \ 181 + r2 = 0; \ 182 + *(u64*)(r10 - 8) = r2; \ 183 + r2 = r10; \ 184 + r2 += -8; \ 185 + call %[bpf_map_lookup_elem]; \ 186 + if r0 == 0 goto l2_%=; \ 187 + r1 = %[test_val_foo]; \ 188 + *(u64*)(r0 + 0) = r1; \ 189 + r0 = 1; \ 190 + l2_%=: exit; \ 191 + " : 192 + : __imm(bpf_map_lookup_elem), 193 + __imm_const(test_val_foo, offsetof(struct test_val, foo)) 194 + : __clobber_all); 195 + } 196 + 197 + static __naked __noinline __attribute__((used)) 198 + void lookup_hash_map_in_map__1(void) 199 + { 200 + asm volatile (" \ 201 + r0 = %[map_array_48b] ll; \ 202 + exit; \ 203 + " : 204 + : __imm_addr(map_array_48b) 205 + : __clobber_all); 206 + } 207 + 208 + static __naked __noinline __attribute__((used)) 209 + void lookup_hash_map_in_map__2(void) 210 + { 211 + asm volatile (" \ 212 + r0 = %[map_in_map] ll; \ 213 + exit; \ 214 + " : 215 + : __imm_addr(map_in_map) 216 + : __clobber_all); 217 + } 218 + 219 + SEC("socket") 220 + __description("cond: two branches returning different map pointers for lookup (tail, tail)") 221 + __success __failure_unpriv __msg_unpriv("tail_call abusing map_ptr") 222 + __retval(42) 223 + __naked void pointers_for_lookup_tail_tail_1(void) 224 + { 225 + asm volatile (" \ 226 + r6 = *(u32*)(r1 + %[__sk_buff_mark]); \ 227 + if r6 != 0 goto l0_%=; \ 228 + r2 = %[map_prog2_socket] ll; \ 229 + goto l1_%=; \ 230 + l0_%=: r2 = %[map_prog1_socket] ll; \ 231 + l1_%=: r3 = 7; \ 232 + call %[bpf_tail_call]; \ 233 + r0 = 1; \ 234 + exit; \ 235 + " : 236 + : __imm(bpf_tail_call), 237 + __imm_addr(map_prog1_socket), 238 + __imm_addr(map_prog2_socket), 239 + __imm_const(__sk_buff_mark, offsetof(struct __sk_buff, mark)) 240 + : __clobber_all); 241 + } 242 + 243 + SEC("socket") 244 + __description("cond: two branches returning same map pointers for lookup (tail, tail)") 245 + __success __success_unpriv __retval(42) 246 + __naked void pointers_for_lookup_tail_tail_2(void) 247 + { 248 + asm volatile (" \ 249 + r6 = *(u32*)(r1 + %[__sk_buff_mark]); \ 250 + if r6 == 0 goto l0_%=; \ 251 + r2 = %[map_prog2_socket] ll; \ 252 + goto l1_%=; \ 253 + l0_%=: r2 = %[map_prog2_socket] ll; \ 254 + l1_%=: r3 = 7; \ 255 + call %[bpf_tail_call]; \ 256 + r0 = 1; \ 257 + exit; \ 258 + " : 259 + : __imm(bpf_tail_call), 260 + __imm_addr(map_prog2_socket), 261 + __imm_const(__sk_buff_mark, offsetof(struct __sk_buff, mark)) 262 + : __clobber_all); 263 + } 264 + 265 + char _license[] SEC("license") = "GPL";
-100
tools/testing/selftests/bpf/verifier/map_ptr_mixing.c
··· 1 - { 2 - "calls: two calls returning different map pointers for lookup (hash, array)", 3 - .insns = { 4 - /* main prog */ 5 - BPF_JMP_IMM(BPF_JNE, BPF_REG_1, 0, 2), 6 - BPF_CALL_REL(11), 7 - BPF_JMP_IMM(BPF_JA, 0, 0, 1), 8 - BPF_CALL_REL(12), 9 - BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), 10 - BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), 11 - BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), 12 - BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), 13 - BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), 14 - BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2), 15 - BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, offsetof(struct test_val, foo)), 16 - BPF_MOV64_IMM(BPF_REG_0, 1), 17 - BPF_EXIT_INSN(), 18 - /* subprog 1 */ 19 - BPF_LD_MAP_FD(BPF_REG_0, 0), 20 - BPF_EXIT_INSN(), 21 - /* subprog 2 */ 22 - BPF_LD_MAP_FD(BPF_REG_0, 0), 23 - BPF_EXIT_INSN(), 24 - }, 25 - .prog_type = BPF_PROG_TYPE_SCHED_CLS, 26 - .fixup_map_hash_48b = { 13 }, 27 - .fixup_map_array_48b = { 16 }, 28 - .result = ACCEPT, 29 - .retval = 1, 30 - }, 31 - { 32 - "calls: two calls returning different map pointers for lookup (hash, map in map)", 33 - .insns = { 34 - /* main prog */ 35 - BPF_JMP_IMM(BPF_JNE, BPF_REG_1, 0, 2), 36 - BPF_CALL_REL(11), 37 - BPF_JMP_IMM(BPF_JA, 0, 0, 1), 38 - BPF_CALL_REL(12), 39 - BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), 40 - BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), 41 - BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), 42 - BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), 43 - BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), 44 - BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2), 45 - BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, offsetof(struct test_val, foo)), 46 - BPF_MOV64_IMM(BPF_REG_0, 1), 47 - BPF_EXIT_INSN(), 48 - /* subprog 1 */ 49 - BPF_LD_MAP_FD(BPF_REG_0, 0), 50 - BPF_EXIT_INSN(), 51 - /* subprog 2 */ 52 - BPF_LD_MAP_FD(BPF_REG_0, 0), 53 - BPF_EXIT_INSN(), 54 - }, 55 - .prog_type = BPF_PROG_TYPE_SCHED_CLS, 56 - .fixup_map_in_map = { 16 }, 57 - .fixup_map_array_48b = { 13 }, 58 - .result = REJECT, 59 - .errstr = "only read from bpf_array is supported", 60 - }, 61 - { 62 - "cond: two branches returning different map pointers for lookup (tail, tail)", 63 - .insns = { 64 - BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, 65 - offsetof(struct __sk_buff, mark)), 66 - BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 0, 3), 67 - BPF_LD_MAP_FD(BPF_REG_2, 0), 68 - BPF_JMP_IMM(BPF_JA, 0, 0, 2), 69 - BPF_LD_MAP_FD(BPF_REG_2, 0), 70 - BPF_MOV64_IMM(BPF_REG_3, 7), 71 - BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_tail_call), 72 - BPF_MOV64_IMM(BPF_REG_0, 1), 73 - BPF_EXIT_INSN(), 74 - }, 75 - .fixup_prog1 = { 5 }, 76 - .fixup_prog2 = { 2 }, 77 - .result_unpriv = REJECT, 78 - .errstr_unpriv = "tail_call abusing map_ptr", 79 - .result = ACCEPT, 80 - .retval = 42, 81 - }, 82 - { 83 - "cond: two branches returning same map pointers for lookup (tail, tail)", 84 - .insns = { 85 - BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_1, 86 - offsetof(struct __sk_buff, mark)), 87 - BPF_JMP_IMM(BPF_JEQ, BPF_REG_6, 0, 3), 88 - BPF_LD_MAP_FD(BPF_REG_2, 0), 89 - BPF_JMP_IMM(BPF_JA, 0, 0, 2), 90 - BPF_LD_MAP_FD(BPF_REG_2, 0), 91 - BPF_MOV64_IMM(BPF_REG_3, 7), 92 - BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_tail_call), 93 - BPF_MOV64_IMM(BPF_REG_0, 1), 94 - BPF_EXIT_INSN(), 95 - }, 96 - .fixup_prog2 = { 2, 5 }, 97 - .result_unpriv = ACCEPT, 98 - .result = ACCEPT, 99 - .retval = 42, 100 - },