1 // SPDX-License-Identifier: GPL-2.0 2 /* Converted from tools/testing/selftests/bpf/verifier/runtime_jit.c */ 3 4 #include <linux/bpf.h> 5 #include <bpf/bpf_helpers.h> 6 #include "bpf_misc.h" 7 8 void dummy_prog_42_socket(void); 9 void dummy_prog_24_socket(void); 10 void dummy_prog_loop1_socket(void); 11 void dummy_prog_loop2_socket(void); 12 13 struct { 14 __uint(type, BPF_MAP_TYPE_PROG_ARRAY); 15 __uint(max_entries, 4); 16 __uint(key_size, sizeof(int)); 17 __array(values, void (void)); 18 } map_prog1_socket SEC(".maps") = { 19 .values = { 20 [0] = (void *)&dummy_prog_42_socket, 21 [1] = (void *)&dummy_prog_loop1_socket, 22 [2] = (void *)&dummy_prog_24_socket, 23 }, 24 }; 25 26 struct { 27 __uint(type, BPF_MAP_TYPE_PROG_ARRAY); 28 __uint(max_entries, 8); 29 __uint(key_size, sizeof(int)); 30 __array(values, void (void)); 31 } map_prog2_socket SEC(".maps") = { 32 .values = { 33 [1] = (void *)&dummy_prog_loop2_socket, 34 [2] = (void *)&dummy_prog_24_socket, 35 [7] = (void *)&dummy_prog_42_socket, 36 }, 37 }; 38 39 SEC("socket") 40 __auxiliary __auxiliary_unpriv 41 __naked void dummy_prog_42_socket(void) 42 { 43 asm volatile ("r0 = 42; exit;"); 44 } 45 46 SEC("socket") 47 __auxiliary __auxiliary_unpriv 48 __naked void dummy_prog_24_socket(void) 49 { 50 asm volatile ("r0 = 24; exit;"); 51 } 52 53 SEC("socket") 54 __auxiliary __auxiliary_unpriv 55 __naked void dummy_prog_loop1_socket(void) 56 { 57 asm volatile (" \ 58 r3 = 1; \ 59 r2 = %[map_prog1_socket] ll; \ 60 call %[bpf_tail_call]; \ 61 r0 = 41; \ 62 exit; \ 63 " : 64 : __imm(bpf_tail_call), 65 __imm_addr(map_prog1_socket) 66 : __clobber_all); 67 } 68 69 SEC("socket") 70 __auxiliary __auxiliary_unpriv 71 __naked void dummy_prog_loop2_socket(void) 72 { 73 asm volatile (" \ 74 r3 = 1; \ 75 r2 = %[map_prog2_socket] ll; \ 76 call %[bpf_tail_call]; \ 77 r0 = 41; \ 78 exit; \ 79 " : 80 : __imm(bpf_tail_call), 81 __imm_addr(map_prog2_socket) 82 : __clobber_all); 83 } 84 85 SEC("socket") 86 __description("runtime/jit: tail_call within bounds, prog once") 87 __success __success_unpriv __retval(42) 88 __naked void call_within_bounds_prog_once(void) 89 { 90 asm volatile (" \ 91 r3 = 0; \ 92 r2 = %[map_prog1_socket] ll; \ 93 call %[bpf_tail_call]; \ 94 r0 = 1; \ 95 exit; \ 96 " : 97 : __imm(bpf_tail_call), 98 __imm_addr(map_prog1_socket) 99 : __clobber_all); 100 } 101 102 SEC("socket") 103 __description("runtime/jit: tail_call within bounds, prog loop") 104 __success __success_unpriv __retval(41) 105 __naked void call_within_bounds_prog_loop(void) 106 { 107 asm volatile (" \ 108 r3 = 1; \ 109 r2 = %[map_prog1_socket] ll; \ 110 call %[bpf_tail_call]; \ 111 r0 = 1; \ 112 exit; \ 113 " : 114 : __imm(bpf_tail_call), 115 __imm_addr(map_prog1_socket) 116 : __clobber_all); 117 } 118 119 SEC("socket") 120 __description("runtime/jit: tail_call within bounds, no prog") 121 __success __success_unpriv __retval(1) 122 __naked void call_within_bounds_no_prog(void) 123 { 124 asm volatile (" \ 125 r3 = 3; \ 126 r2 = %[map_prog1_socket] ll; \ 127 call %[bpf_tail_call]; \ 128 r0 = 1; \ 129 exit; \ 130 " : 131 : __imm(bpf_tail_call), 132 __imm_addr(map_prog1_socket) 133 : __clobber_all); 134 } 135 136 SEC("socket") 137 __description("runtime/jit: tail_call within bounds, key 2") 138 __success __success_unpriv __retval(24) 139 __naked void call_within_bounds_key_2(void) 140 { 141 asm volatile (" \ 142 r3 = 2; \ 143 r2 = %[map_prog1_socket] ll; \ 144 call %[bpf_tail_call]; \ 145 r0 = 1; \ 146 exit; \ 147 " : 148 : __imm(bpf_tail_call), 149 __imm_addr(map_prog1_socket) 150 : __clobber_all); 151 } 152 153 SEC("socket") 154 __description("runtime/jit: tail_call within bounds, key 2 / key 2, first branch") 155 __success __success_unpriv __retval(24) 156 __naked void _2_key_2_first_branch(void) 157 { 158 asm volatile (" \ 159 r0 = 13; \ 160 *(u8*)(r1 + %[__sk_buff_cb_0]) = r0; \ 161 r0 = *(u8*)(r1 + %[__sk_buff_cb_0]); \ 162 if r0 == 13 goto l0_%=; \ 163 r3 = 2; \ 164 r2 = %[map_prog1_socket] ll; \ 165 goto l1_%=; \ 166 l0_%=: r3 = 2; \ 167 r2 = %[map_prog1_socket] ll; \ 168 l1_%=: call %[bpf_tail_call]; \ 169 r0 = 1; \ 170 exit; \ 171 " : 172 : __imm(bpf_tail_call), 173 __imm_addr(map_prog1_socket), 174 __imm_const(__sk_buff_cb_0, offsetof(struct __sk_buff, cb[0])) 175 : __clobber_all); 176 } 177 178 SEC("socket") 179 __description("runtime/jit: tail_call within bounds, key 2 / key 2, second branch") 180 __success __success_unpriv __retval(24) 181 __naked void _2_key_2_second_branch(void) 182 { 183 asm volatile (" \ 184 r0 = 14; \ 185 *(u8*)(r1 + %[__sk_buff_cb_0]) = r0; \ 186 r0 = *(u8*)(r1 + %[__sk_buff_cb_0]); \ 187 if r0 == 13 goto l0_%=; \ 188 r3 = 2; \ 189 r2 = %[map_prog1_socket] ll; \ 190 goto l1_%=; \ 191 l0_%=: r3 = 2; \ 192 r2 = %[map_prog1_socket] ll; \ 193 l1_%=: call %[bpf_tail_call]; \ 194 r0 = 1; \ 195 exit; \ 196 " : 197 : __imm(bpf_tail_call), 198 __imm_addr(map_prog1_socket), 199 __imm_const(__sk_buff_cb_0, offsetof(struct __sk_buff, cb[0])) 200 : __clobber_all); 201 } 202 203 SEC("socket") 204 __description("runtime/jit: tail_call within bounds, key 0 / key 2, first branch") 205 __success __success_unpriv __retval(24) 206 __naked void _0_key_2_first_branch(void) 207 { 208 asm volatile (" \ 209 r0 = 13; \ 210 *(u8*)(r1 + %[__sk_buff_cb_0]) = r0; \ 211 r0 = *(u8*)(r1 + %[__sk_buff_cb_0]); \ 212 if r0 == 13 goto l0_%=; \ 213 r3 = 0; \ 214 r2 = %[map_prog1_socket] ll; \ 215 goto l1_%=; \ 216 l0_%=: r3 = 2; \ 217 r2 = %[map_prog1_socket] ll; \ 218 l1_%=: call %[bpf_tail_call]; \ 219 r0 = 1; \ 220 exit; \ 221 " : 222 : __imm(bpf_tail_call), 223 __imm_addr(map_prog1_socket), 224 __imm_const(__sk_buff_cb_0, offsetof(struct __sk_buff, cb[0])) 225 : __clobber_all); 226 } 227 228 SEC("socket") 229 __description("runtime/jit: tail_call within bounds, key 0 / key 2, second branch") 230 __success __success_unpriv __retval(42) 231 __naked void _0_key_2_second_branch(void) 232 { 233 asm volatile (" \ 234 r0 = 14; \ 235 *(u8*)(r1 + %[__sk_buff_cb_0]) = r0; \ 236 r0 = *(u8*)(r1 + %[__sk_buff_cb_0]); \ 237 if r0 == 13 goto l0_%=; \ 238 r3 = 0; \ 239 r2 = %[map_prog1_socket] ll; \ 240 goto l1_%=; \ 241 l0_%=: r3 = 2; \ 242 r2 = %[map_prog1_socket] ll; \ 243 l1_%=: call %[bpf_tail_call]; \ 244 r0 = 1; \ 245 exit; \ 246 " : 247 : __imm(bpf_tail_call), 248 __imm_addr(map_prog1_socket), 249 __imm_const(__sk_buff_cb_0, offsetof(struct __sk_buff, cb[0])) 250 : __clobber_all); 251 } 252 253 SEC("socket") 254 __description("runtime/jit: tail_call within bounds, different maps, first branch") 255 __success __failure_unpriv __msg_unpriv("tail_call abusing map_ptr") 256 __retval(1) 257 __naked void bounds_different_maps_first_branch(void) 258 { 259 asm volatile (" \ 260 r0 = 13; \ 261 *(u8*)(r1 + %[__sk_buff_cb_0]) = r0; \ 262 r0 = *(u8*)(r1 + %[__sk_buff_cb_0]); \ 263 if r0 == 13 goto l0_%=; \ 264 r3 = 0; \ 265 r2 = %[map_prog1_socket] ll; \ 266 goto l1_%=; \ 267 l0_%=: r3 = 0; \ 268 r2 = %[map_prog2_socket] ll; \ 269 l1_%=: call %[bpf_tail_call]; \ 270 r0 = 1; \ 271 exit; \ 272 " : 273 : __imm(bpf_tail_call), 274 __imm_addr(map_prog1_socket), 275 __imm_addr(map_prog2_socket), 276 __imm_const(__sk_buff_cb_0, offsetof(struct __sk_buff, cb[0])) 277 : __clobber_all); 278 } 279 280 SEC("socket") 281 __description("runtime/jit: tail_call within bounds, different maps, second branch") 282 __success __failure_unpriv __msg_unpriv("tail_call abusing map_ptr") 283 __retval(42) 284 __naked void bounds_different_maps_second_branch(void) 285 { 286 asm volatile (" \ 287 r0 = 14; \ 288 *(u8*)(r1 + %[__sk_buff_cb_0]) = r0; \ 289 r0 = *(u8*)(r1 + %[__sk_buff_cb_0]); \ 290 if r0 == 13 goto l0_%=; \ 291 r3 = 0; \ 292 r2 = %[map_prog1_socket] ll; \ 293 goto l1_%=; \ 294 l0_%=: r3 = 0; \ 295 r2 = %[map_prog2_socket] ll; \ 296 l1_%=: call %[bpf_tail_call]; \ 297 r0 = 1; \ 298 exit; \ 299 " : 300 : __imm(bpf_tail_call), 301 __imm_addr(map_prog1_socket), 302 __imm_addr(map_prog2_socket), 303 __imm_const(__sk_buff_cb_0, offsetof(struct __sk_buff, cb[0])) 304 : __clobber_all); 305 } 306 307 SEC("socket") 308 __description("runtime/jit: tail_call out of bounds") 309 __success __success_unpriv __retval(2) 310 __naked void tail_call_out_of_bounds(void) 311 { 312 asm volatile (" \ 313 r3 = 256; \ 314 r2 = %[map_prog1_socket] ll; \ 315 call %[bpf_tail_call]; \ 316 r0 = 2; \ 317 exit; \ 318 " : 319 : __imm(bpf_tail_call), 320 __imm_addr(map_prog1_socket) 321 : __clobber_all); 322 } 323 324 SEC("socket") 325 __description("runtime/jit: pass negative index to tail_call") 326 __success __success_unpriv __retval(2) 327 __naked void negative_index_to_tail_call(void) 328 { 329 asm volatile (" \ 330 r3 = -1; \ 331 r2 = %[map_prog1_socket] ll; \ 332 call %[bpf_tail_call]; \ 333 r0 = 2; \ 334 exit; \ 335 " : 336 : __imm(bpf_tail_call), 337 __imm_addr(map_prog1_socket) 338 : __clobber_all); 339 } 340 341 SEC("socket") 342 __description("runtime/jit: pass > 32bit index to tail_call") 343 __success __success_unpriv __retval(42) 344 /* Verifier rewrite for unpriv skips tail call here. */ 345 __retval_unpriv(2) 346 __naked void _32bit_index_to_tail_call(void) 347 { 348 asm volatile (" \ 349 r3 = 0x100000000 ll; \ 350 r2 = %[map_prog1_socket] ll; \ 351 call %[bpf_tail_call]; \ 352 r0 = 2; \ 353 exit; \ 354 " : 355 : __imm(bpf_tail_call), 356 __imm_addr(map_prog1_socket) 357 : __clobber_all); 358 } 359 360 char _license[] SEC("license") = "GPL"; 361