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"; 266