1 // SPDX-License-Identifier: GPL-2.0 2 3 #include <linux/bpf.h> 4 #include <bpf/bpf_helpers.h> 5 #include "../../../include/linux/filter.h" 6 #include "bpf_arena_common.h" 7 #include "bpf_misc.h" 8 9 struct { 10 __uint(type, BPF_MAP_TYPE_ARRAY); 11 __uint(max_entries, 1); 12 __type(key, __u32); 13 __type(value, __u64); 14 } test_map SEC(".maps"); 15 16 struct { 17 __uint(type, BPF_MAP_TYPE_ARENA); 18 __uint(map_flags, BPF_F_MMAPABLE); 19 __uint(max_entries, 1); 20 } arena SEC(".maps"); 21 22 SEC("socket") 23 __log_level(2) 24 __msg(" 0: .......... (b7) r0 = 42") 25 __msg(" 1: 0......... (bf) r1 = r0") 26 __msg(" 2: .1........ (bf) r2 = r1") 27 __msg(" 3: ..2....... (bf) r3 = r2") 28 __msg(" 4: ...3...... (bf) r4 = r3") 29 __msg(" 5: ....4..... (bf) r5 = r4") 30 __msg(" 6: .....5.... (bf) r6 = r5") 31 __msg(" 7: ......6... (bf) r7 = r6") 32 __msg(" 8: .......7.. (bf) r8 = r7") 33 __msg(" 9: ........8. (bf) r9 = r8") 34 __msg("10: .........9 (bf) r0 = r9") 35 __msg("11: 0......... (95) exit") 36 __naked void assign_chain(void) 37 { 38 asm volatile ( 39 "r0 = 42;" 40 "r1 = r0;" 41 "r2 = r1;" 42 "r3 = r2;" 43 "r4 = r3;" 44 "r5 = r4;" 45 "r6 = r5;" 46 "r7 = r6;" 47 "r8 = r7;" 48 "r9 = r8;" 49 "r0 = r9;" 50 "exit;" 51 ::: __clobber_all); 52 } 53 54 SEC("socket") 55 __log_level(2) 56 __msg("0: .......... (b7) r1 = 7") 57 __msg("1: .1........ (07) r1 += 7") 58 __msg("2: .......... (b7) r2 = 7") 59 __msg("3: ..2....... (b7) r3 = 42") 60 __msg("4: ..23...... (0f) r2 += r3") 61 __msg("5: .......... (b7) r0 = 0") 62 __msg("6: 0......... (95) exit") 63 __naked void arithmetics(void) 64 { 65 asm volatile ( 66 "r1 = 7;" 67 "r1 += 7;" 68 "r2 = 7;" 69 "r3 = 42;" 70 "r2 += r3;" 71 "r0 = 0;" 72 "exit;" 73 ::: __clobber_all); 74 } 75 76 #ifdef CAN_USE_BPF_ST 77 SEC("socket") 78 __log_level(2) 79 __msg(" 1: .1........ (07) r1 += -8") 80 __msg(" 2: .1........ (7a) *(u64 *)(r1 +0) = 7") 81 __msg(" 3: .1........ (b7) r2 = 42") 82 __msg(" 4: .12....... (7b) *(u64 *)(r1 +0) = r2") 83 __msg(" 5: .12....... (7b) *(u64 *)(r1 +0) = r2") 84 __msg(" 6: .......... (b7) r0 = 0") 85 __naked void store(void) 86 { 87 asm volatile ( 88 "r1 = r10;" 89 "r1 += -8;" 90 "*(u64 *)(r1 +0) = 7;" 91 "r2 = 42;" 92 "*(u64 *)(r1 +0) = r2;" 93 "*(u64 *)(r1 +0) = r2;" 94 "r0 = 0;" 95 "exit;" 96 ::: __clobber_all); 97 } 98 #endif 99 100 SEC("socket") 101 __log_level(2) 102 __msg("1: ....4..... (07) r4 += -8") 103 __msg("2: ....4..... (79) r5 = *(u64 *)(r4 +0)") 104 __msg("3: ....45.... (07) r4 += -8") 105 __naked void load(void) 106 { 107 asm volatile ( 108 "r4 = r10;" 109 "r4 += -8;" 110 "r5 = *(u64 *)(r4 +0);" 111 "r4 += -8;" 112 "r0 = r5;" 113 "exit;" 114 ::: __clobber_all); 115 } 116 117 SEC("socket") 118 __log_level(2) 119 __msg("0: .1........ (61) r2 = *(u32 *)(r1 +0)") 120 __msg("1: ..2....... (d4) r2 = le64 r2") 121 __msg("2: ..2....... (bf) r0 = r2") 122 __naked void endian(void) 123 { 124 asm volatile ( 125 "r2 = *(u32 *)(r1 +0);" 126 "r2 = le64 r2;" 127 "r0 = r2;" 128 "exit;" 129 ::: __clobber_all); 130 } 131 132 SEC("socket") 133 __log_level(2) 134 __msg(" 8: 0......... (b7) r1 = 1") 135 __msg(" 9: 01........ (db) r1 = atomic64_fetch_add((u64 *)(r0 +0), r1)") 136 __msg("10: 01........ (c3) lock *(u32 *)(r0 +0) += r1") 137 __msg("11: 01........ (db) r1 = atomic64_xchg((u64 *)(r0 +0), r1)") 138 __msg("12: 01........ (bf) r2 = r0") 139 __msg("13: .12....... (bf) r0 = r1") 140 __msg("14: 012....... (db) r0 = atomic64_cmpxchg((u64 *)(r2 +0), r0, r1)") 141 __naked void atomic(void) 142 { 143 asm volatile ( 144 "r2 = r10;" 145 "r2 += -8;" 146 "r1 = 0;" 147 "*(u64 *)(r2 +0) = r1;" 148 "r1 = %[test_map] ll;" 149 "call %[bpf_map_lookup_elem];" 150 "if r0 == 0 goto 1f;" 151 "r1 = 1;" 152 "r1 = atomic_fetch_add((u64 *)(r0 +0), r1);" 153 ".8byte %[add_nofetch];" /* same as "lock *(u32 *)(r0 +0) += r1;" */ 154 "r1 = xchg_64(r0 + 0, r1);" 155 "r2 = r0;" 156 "r0 = r1;" 157 "r0 = cmpxchg_64(r2 + 0, r0, r1);" 158 "1: exit;" 159 : 160 : __imm(bpf_map_lookup_elem), 161 __imm_addr(test_map), 162 __imm_insn(add_nofetch, BPF_ATOMIC_OP(BPF_W, BPF_ADD, BPF_REG_0, BPF_REG_1, 0)) 163 : __clobber_all); 164 } 165 166 #ifdef CAN_USE_LOAD_ACQ_STORE_REL 167 168 SEC("socket") 169 __log_level(2) 170 __msg("2: .12....... (db) store_release((u64 *)(r2 -8), r1)") 171 __msg("3: .......... (bf) r3 = r10") 172 __msg("4: ...3...... (db) r4 = load_acquire((u64 *)(r3 -8))") 173 __naked void atomic_load_acq_store_rel(void) 174 { 175 asm volatile ( 176 "r1 = 42;" 177 "r2 = r10;" 178 ".8byte %[store_release_insn];" /* store_release((u64 *)(r2 - 8), r1); */ 179 "r3 = r10;" 180 ".8byte %[load_acquire_insn];" /* r4 = load_acquire((u64 *)(r3 + 0)); */ 181 "r0 = r4;" 182 "exit;" 183 : 184 : __imm_insn(store_release_insn, 185 BPF_ATOMIC_OP(BPF_DW, BPF_STORE_REL, BPF_REG_2, BPF_REG_1, -8)), 186 __imm_insn(load_acquire_insn, 187 BPF_ATOMIC_OP(BPF_DW, BPF_LOAD_ACQ, BPF_REG_4, BPF_REG_3, -8)) 188 : __clobber_all); 189 } 190 191 #endif /* CAN_USE_LOAD_ACQ_STORE_REL */ 192 193 SEC("socket") 194 __log_level(2) 195 __msg("4: .12....7.. (85) call bpf_trace_printk#6") 196 __msg("5: 0......7.. (0f) r0 += r7") 197 __naked void regular_call(void) 198 { 199 asm volatile ( 200 "r7 = 1;" 201 "r1 = r10;" 202 "r1 += -8;" 203 "r2 = 1;" 204 "call %[bpf_trace_printk];" 205 "r0 += r7;" 206 "exit;" 207 : 208 : __imm(bpf_trace_printk) 209 : __clobber_all); 210 } 211 212 SEC("socket") 213 __log_level(2) 214 __msg("2: 012....... (25) if r1 > 0x7 goto pc+1") 215 __msg("3: ..2....... (bf) r0 = r2") 216 __naked void if1(void) 217 { 218 asm volatile ( 219 "r0 = 1;" 220 "r2 = 2;" 221 "if r1 > 0x7 goto +1;" 222 "r0 = r2;" 223 "exit;" 224 ::: __clobber_all); 225 } 226 227 SEC("socket") 228 __log_level(2) 229 __msg("3: 0123...... (2d) if r1 > r3 goto pc+1") 230 __msg("4: ..2....... (bf) r0 = r2") 231 __naked void if2(void) 232 { 233 asm volatile ( 234 "r0 = 1;" 235 "r2 = 2;" 236 "r3 = 7;" 237 "if r1 > r3 goto +1;" 238 "r0 = r2;" 239 "exit;" 240 ::: __clobber_all); 241 } 242 243 /* Verifier misses that r2 is alive if jset is not handled properly */ 244 SEC("socket") 245 __log_level(2) 246 __msg("2: 012....... (45) if r1 & 0x7 goto pc+1") 247 __naked void if3_jset_bug(void) 248 { 249 asm volatile ( 250 "r0 = 1;" 251 "r2 = 2;" 252 "if r1 & 0x7 goto +1;" 253 "exit;" 254 "r0 = r2;" 255 "exit;" 256 ::: __clobber_all); 257 } 258 259 SEC("socket") 260 __log_level(2) 261 __msg("0: .......... (b7) r1 = 0") 262 __msg("1: .1........ (b7) r2 = 7") 263 __msg("2: .12....... (25) if r1 > 0x7 goto pc+4") 264 __msg("3: .12....... (07) r1 += 1") 265 __msg("4: .12....... (27) r2 *= 2") 266 __msg("5: .12....... (05) goto pc+0") 267 __msg("6: .12....... (05) goto pc-5") 268 __msg("7: .......... (b7) r0 = 0") 269 __msg("8: 0......... (95) exit") 270 __naked void loop(void) 271 { 272 asm volatile ( 273 "r1 = 0;" 274 "r2 = 7;" 275 "if r1 > 0x7 goto +4;" 276 "r1 += 1;" 277 "r2 *= 2;" 278 "goto +0;" 279 "goto -5;" 280 "r0 = 0;" 281 "exit;" 282 : 283 : __imm(bpf_trace_printk) 284 : __clobber_all); 285 } 286 287 #ifdef CAN_USE_GOTOL 288 SEC("socket") 289 __log_level(2) 290 __msg("2: .123...... (25) if r1 > 0x7 goto pc+2") 291 __msg("3: ..2....... (bf) r0 = r2") 292 __msg("4: 0......... (06) gotol pc+1") 293 __msg("5: ...3...... (bf) r0 = r3") 294 __msg("6: 0......... (95) exit") 295 __naked void gotol(void) 296 { 297 asm volatile ( 298 "r2 = 42;" 299 "r3 = 24;" 300 "if r1 > 0x7 goto +2;" 301 "r0 = r2;" 302 "gotol +1;" 303 "r0 = r3;" 304 "exit;" 305 : 306 : __imm(bpf_trace_printk) 307 : __clobber_all); 308 } 309 #endif 310 311 SEC("socket") 312 __log_level(2) 313 __msg("0: .......... (b7) r1 = 1") 314 __msg("1: .1........ (e5) may_goto pc+1") 315 __msg("2: .......... (05) goto pc-3") 316 __msg("3: .1........ (bf) r0 = r1") 317 __msg("4: 0......... (95) exit") 318 __naked void may_goto(void) 319 { 320 asm volatile ( 321 "1: r1 = 1;" 322 ".8byte %[may_goto];" 323 "goto 1b;" 324 "r0 = r1;" 325 "exit;" 326 : 327 : __imm(bpf_get_smp_processor_id), 328 __imm_insn(may_goto, BPF_RAW_INSN(BPF_JMP | BPF_JCOND, 0, 0, +1 /* offset */, 0)) 329 : __clobber_all); 330 } 331 332 SEC("socket") 333 __log_level(2) 334 __msg("1: 0......... (18) r2 = 0x7") 335 __msg("3: 0.2....... (0f) r0 += r2") 336 __naked void ldimm64(void) 337 { 338 asm volatile ( 339 "r0 = 0;" 340 "r2 = 0x7 ll;" 341 "r0 += r2;" 342 "exit;" 343 : 344 :: __clobber_all); 345 } 346 347 /* No rules specific for LD_ABS/LD_IND, default behaviour kicks in */ 348 SEC("socket") 349 __log_level(2) 350 __msg("2: 0123456789 (30) r0 = *(u8 *)skb[42]") 351 __msg("3: 012.456789 (0f) r7 += r0") 352 __msg("4: 012.456789 (b7) r3 = 42") 353 __msg("5: 0123456789 (50) r0 = *(u8 *)skb[r3 + 0]") 354 __msg("6: 0......7.. (0f) r7 += r0") 355 __naked void ldabs(void) 356 { 357 asm volatile ( 358 "r6 = r1;" 359 "r7 = 0;" 360 "r0 = *(u8 *)skb[42];" 361 "r7 += r0;" 362 "r3 = 42;" 363 ".8byte %[ld_ind];" /* same as "r0 = *(u8 *)skb[r3];" */ 364 "r7 += r0;" 365 "r0 = r7;" 366 "exit;" 367 : 368 : __imm_insn(ld_ind, BPF_LD_IND(BPF_B, BPF_REG_3, 0)) 369 : __clobber_all); 370 } 371 372 373 #ifdef __BPF_FEATURE_ADDR_SPACE_CAST 374 SEC("?fentry.s/" SYS_PREFIX "sys_getpgid") 375 __log_level(2) 376 __msg(" 6: .12345.... (85) call bpf_arena_alloc_pages") 377 __msg(" 7: 0......... (bf) r1 = addr_space_cast(r0, 0, 1)") 378 __msg(" 8: .1........ (b7) r2 = 42") 379 __naked void addr_space_cast(void) 380 { 381 asm volatile ( 382 "r1 = %[arena] ll;" 383 "r2 = 0;" 384 "r3 = 1;" 385 "r4 = 0;" 386 "r5 = 0;" 387 "call %[bpf_arena_alloc_pages];" 388 "r1 = addr_space_cast(r0, 0, 1);" 389 "r2 = 42;" 390 "*(u64 *)(r1 +0) = r2;" 391 "r0 = 0;" 392 "exit;" 393 : 394 : __imm(bpf_arena_alloc_pages), 395 __imm_addr(arena) 396 : __clobber_all); 397 } 398 #endif 399 400 static __used __naked int aux1(void) 401 { 402 asm volatile ( 403 "r0 = r1;" 404 "r0 += r2;" 405 "exit;" 406 ::: __clobber_all); 407 } 408 409 SEC("socket") 410 __log_level(2) 411 __msg("0: ....45.... (b7) r1 = 1") 412 __msg("1: .1..45.... (b7) r2 = 2") 413 __msg("2: .12.45.... (b7) r3 = 3") 414 /* Conservative liveness for subprog parameters. */ 415 __msg("3: .12345.... (85) call pc+2") 416 __msg("4: .......... (b7) r0 = 0") 417 __msg("5: 0......... (95) exit") 418 __msg("6: .12....... (bf) r0 = r1") 419 __msg("7: 0.2....... (0f) r0 += r2") 420 /* Conservative liveness for subprog return value. */ 421 __msg("8: 0......... (95) exit") 422 __naked void subprog1(void) 423 { 424 asm volatile ( 425 "r1 = 1;" 426 "r2 = 2;" 427 "r3 = 3;" 428 "call aux1;" 429 "r0 = 0;" 430 "exit;" 431 ::: __clobber_all); 432 } 433 434 /* to retain debug info for BTF generation */ 435 void kfunc_root(void) 436 { 437 bpf_arena_alloc_pages(0, 0, 0, 0, 0); 438 } 439 440 char _license[] SEC("license") = "GPL"; 441