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 10struct test_val { 11 unsigned int index; 12 int foo[MAX_ENTRIES]; 13}; 14 15struct { 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 22struct { 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 29struct { 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 42void dummy_prog_42_socket(void); 43void dummy_prog_24_socket(void); 44void dummy_prog_loop1_socket(void); 45void dummy_prog_loop2_socket(void); 46 47struct { 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 60struct { 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 73SEC("socket") 74__auxiliary __auxiliary_unpriv 75__naked void dummy_prog_42_socket(void) 76{ 77 asm volatile ("r0 = 42; exit;"); 78} 79 80SEC("socket") 81__auxiliary __auxiliary_unpriv 82__naked void dummy_prog_24_socket(void) 83{ 84 asm volatile ("r0 = 24; exit;"); 85} 86 87SEC("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 103SEC("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 119SEC("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_%=; \ 129l0_%=: call pointers_for_lookup_hash_array__2; \ 130l1_%=: 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; \ 140l2_%=: exit; \ 141" : 142 : __imm(bpf_map_lookup_elem), 143 __imm_const(test_val_foo, offsetof(struct test_val, foo)) 144 : __clobber_all); 145} 146 147static __naked __noinline __attribute__((used)) 148void 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 158static __naked __noinline __attribute__((used)) 159void 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 169SEC("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_%=; \ 179l0_%=: call lookup_hash_map_in_map__2; \ 180l1_%=: 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; \ 190l2_%=: exit; \ 191" : 192 : __imm(bpf_map_lookup_elem), 193 __imm_const(test_val_foo, offsetof(struct test_val, foo)) 194 : __clobber_all); 195} 196 197static __naked __noinline __attribute__((used)) 198void 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 208static __naked __noinline __attribute__((used)) 209void 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 219SEC("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_%=; \ 230l0_%=: r2 = %[map_prog1_socket] ll; \ 231l1_%=: 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 243SEC("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_%=; \ 253l0_%=: r2 = %[map_prog2_socket] ll; \ 254l1_%=: 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 265char _license[] SEC("license") = "GPL"; 266