1*fdcecdffSEduard Zingerman // SPDX-License-Identifier: GPL-2.0 2*fdcecdffSEduard Zingerman /* Copyright (c) 2025 Meta Platforms, Inc. and affiliates. */ 3*fdcecdffSEduard Zingerman 4*fdcecdffSEduard Zingerman #include <linux/bpf.h> 5*fdcecdffSEduard Zingerman #include <bpf/bpf_helpers.h> 6*fdcecdffSEduard Zingerman #include "bpf_misc.h" 7*fdcecdffSEduard Zingerman 8*fdcecdffSEduard Zingerman struct { 9*fdcecdffSEduard Zingerman __uint(type, BPF_MAP_TYPE_HASH); 10*fdcecdffSEduard Zingerman __uint(max_entries, 1); 11*fdcecdffSEduard Zingerman __type(key, int); 12*fdcecdffSEduard Zingerman __type(value, long long); 13*fdcecdffSEduard Zingerman } map SEC(".maps"); 14*fdcecdffSEduard Zingerman 15*fdcecdffSEduard Zingerman SEC("socket") 16*fdcecdffSEduard Zingerman __log_level(2) 17*fdcecdffSEduard Zingerman __msg("(0) frame 0 insn 2 +written -8") 18*fdcecdffSEduard Zingerman __msg("(0) frame 0 insn 1 +live -24") 19*fdcecdffSEduard Zingerman __msg("(0) frame 0 insn 1 +written -8") 20*fdcecdffSEduard Zingerman __msg("(0) frame 0 insn 0 +live -8,-24") 21*fdcecdffSEduard Zingerman __msg("(0) frame 0 insn 0 +written -8") 22*fdcecdffSEduard Zingerman __msg("(0) live stack update done in 2 iterations") 23*fdcecdffSEduard Zingerman __naked void simple_read_simple_write(void) 24*fdcecdffSEduard Zingerman { 25*fdcecdffSEduard Zingerman asm volatile ( 26*fdcecdffSEduard Zingerman "r1 = *(u64 *)(r10 - 8);" 27*fdcecdffSEduard Zingerman "r2 = *(u64 *)(r10 - 24);" 28*fdcecdffSEduard Zingerman "*(u64 *)(r10 - 8) = r1;" 29*fdcecdffSEduard Zingerman "r0 = 0;" 30*fdcecdffSEduard Zingerman "exit;" 31*fdcecdffSEduard Zingerman ::: __clobber_all); 32*fdcecdffSEduard Zingerman } 33*fdcecdffSEduard Zingerman 34*fdcecdffSEduard Zingerman SEC("socket") 35*fdcecdffSEduard Zingerman __log_level(2) 36*fdcecdffSEduard Zingerman __msg("(0) frame 0 insn 1 +live -8") 37*fdcecdffSEduard Zingerman __not_msg("(0) frame 0 insn 1 +written") 38*fdcecdffSEduard Zingerman __msg("(0) live stack update done in 2 iterations") 39*fdcecdffSEduard Zingerman __msg("(0) frame 0 insn 1 +live -16") 40*fdcecdffSEduard Zingerman __msg("(0) frame 0 insn 1 +written -32") 41*fdcecdffSEduard Zingerman __msg("(0) live stack update done in 2 iterations") 42*fdcecdffSEduard Zingerman __naked void read_write_join(void) 43*fdcecdffSEduard Zingerman { 44*fdcecdffSEduard Zingerman asm volatile ( 45*fdcecdffSEduard Zingerman "call %[bpf_get_prandom_u32];" 46*fdcecdffSEduard Zingerman "if r0 > 42 goto 1f;" 47*fdcecdffSEduard Zingerman "r0 = *(u64 *)(r10 - 8);" 48*fdcecdffSEduard Zingerman "*(u64 *)(r10 - 32) = r0;" 49*fdcecdffSEduard Zingerman "*(u64 *)(r10 - 40) = r0;" 50*fdcecdffSEduard Zingerman "exit;" 51*fdcecdffSEduard Zingerman "1:" 52*fdcecdffSEduard Zingerman "r0 = *(u64 *)(r10 - 16);" 53*fdcecdffSEduard Zingerman "*(u64 *)(r10 - 32) = r0;" 54*fdcecdffSEduard Zingerman "exit;" 55*fdcecdffSEduard Zingerman :: __imm(bpf_get_prandom_u32) 56*fdcecdffSEduard Zingerman : __clobber_all); 57*fdcecdffSEduard Zingerman } 58*fdcecdffSEduard Zingerman 59*fdcecdffSEduard Zingerman SEC("socket") 60*fdcecdffSEduard Zingerman __log_level(2) 61*fdcecdffSEduard Zingerman __msg("2: (25) if r0 > 0x2a goto pc+1") 62*fdcecdffSEduard Zingerman __msg("7: (95) exit") 63*fdcecdffSEduard Zingerman __msg("(0) frame 0 insn 2 +written -16") 64*fdcecdffSEduard Zingerman __msg("(0) live stack update done in 2 iterations") 65*fdcecdffSEduard Zingerman __msg("7: (95) exit") 66*fdcecdffSEduard Zingerman __not_msg("(0) frame 0 insn 2") 67*fdcecdffSEduard Zingerman __msg("(0) live stack update done in 1 iterations") 68*fdcecdffSEduard Zingerman __naked void must_write_not_same_slot(void) 69*fdcecdffSEduard Zingerman { 70*fdcecdffSEduard Zingerman asm volatile ( 71*fdcecdffSEduard Zingerman "call %[bpf_get_prandom_u32];" 72*fdcecdffSEduard Zingerman "r1 = -8;" 73*fdcecdffSEduard Zingerman "if r0 > 42 goto 1f;" 74*fdcecdffSEduard Zingerman "r1 = -16;" 75*fdcecdffSEduard Zingerman "1:" 76*fdcecdffSEduard Zingerman "r2 = r10;" 77*fdcecdffSEduard Zingerman "r2 += r1;" 78*fdcecdffSEduard Zingerman "*(u64 *)(r2 + 0) = r0;" 79*fdcecdffSEduard Zingerman "exit;" 80*fdcecdffSEduard Zingerman :: __imm(bpf_get_prandom_u32) 81*fdcecdffSEduard Zingerman : __clobber_all); 82*fdcecdffSEduard Zingerman } 83*fdcecdffSEduard Zingerman 84*fdcecdffSEduard Zingerman SEC("socket") 85*fdcecdffSEduard Zingerman __log_level(2) 86*fdcecdffSEduard Zingerman __msg("(0) frame 0 insn 0 +written -8,-16") 87*fdcecdffSEduard Zingerman __msg("(0) live stack update done in 2 iterations") 88*fdcecdffSEduard Zingerman __msg("(0) frame 0 insn 0 +written -8") 89*fdcecdffSEduard Zingerman __msg("(0) live stack update done in 2 iterations") 90*fdcecdffSEduard Zingerman __naked void must_write_not_same_type(void) 91*fdcecdffSEduard Zingerman { 92*fdcecdffSEduard Zingerman asm volatile ( 93*fdcecdffSEduard Zingerman "*(u64*)(r10 - 8) = 0;" 94*fdcecdffSEduard Zingerman "r2 = r10;" 95*fdcecdffSEduard Zingerman "r2 += -8;" 96*fdcecdffSEduard Zingerman "r1 = %[map] ll;" 97*fdcecdffSEduard Zingerman "call %[bpf_map_lookup_elem];" 98*fdcecdffSEduard Zingerman "if r0 != 0 goto 1f;" 99*fdcecdffSEduard Zingerman "r0 = r10;" 100*fdcecdffSEduard Zingerman "r0 += -16;" 101*fdcecdffSEduard Zingerman "1:" 102*fdcecdffSEduard Zingerman "*(u64 *)(r0 + 0) = 42;" 103*fdcecdffSEduard Zingerman "exit;" 104*fdcecdffSEduard Zingerman : 105*fdcecdffSEduard Zingerman : __imm(bpf_get_prandom_u32), 106*fdcecdffSEduard Zingerman __imm(bpf_map_lookup_elem), 107*fdcecdffSEduard Zingerman __imm_addr(map) 108*fdcecdffSEduard Zingerman : __clobber_all); 109*fdcecdffSEduard Zingerman } 110*fdcecdffSEduard Zingerman 111*fdcecdffSEduard Zingerman SEC("socket") 112*fdcecdffSEduard Zingerman __log_level(2) 113*fdcecdffSEduard Zingerman __msg("(2,4) frame 0 insn 4 +written -8") 114*fdcecdffSEduard Zingerman __msg("(2,4) live stack update done in 2 iterations") 115*fdcecdffSEduard Zingerman __msg("(0) frame 0 insn 2 +written -8") 116*fdcecdffSEduard Zingerman __msg("(0) live stack update done in 2 iterations") 117*fdcecdffSEduard Zingerman __naked void caller_stack_write(void) 118*fdcecdffSEduard Zingerman { 119*fdcecdffSEduard Zingerman asm volatile ( 120*fdcecdffSEduard Zingerman "r1 = r10;" 121*fdcecdffSEduard Zingerman "r1 += -8;" 122*fdcecdffSEduard Zingerman "call write_first_param;" 123*fdcecdffSEduard Zingerman "exit;" 124*fdcecdffSEduard Zingerman ::: __clobber_all); 125*fdcecdffSEduard Zingerman } 126*fdcecdffSEduard Zingerman 127*fdcecdffSEduard Zingerman static __used __naked void write_first_param(void) 128*fdcecdffSEduard Zingerman { 129*fdcecdffSEduard Zingerman asm volatile ( 130*fdcecdffSEduard Zingerman "*(u64 *)(r1 + 0) = 7;" 131*fdcecdffSEduard Zingerman "r0 = 0;" 132*fdcecdffSEduard Zingerman "exit;" 133*fdcecdffSEduard Zingerman ::: __clobber_all); 134*fdcecdffSEduard Zingerman } 135*fdcecdffSEduard Zingerman 136*fdcecdffSEduard Zingerman SEC("socket") 137*fdcecdffSEduard Zingerman __log_level(2) 138*fdcecdffSEduard Zingerman /* caller_stack_read() function */ 139*fdcecdffSEduard Zingerman __msg("2: .12345.... (85) call pc+4") 140*fdcecdffSEduard Zingerman __msg("5: .12345.... (85) call pc+1") 141*fdcecdffSEduard Zingerman __msg("6: 0......... (95) exit") 142*fdcecdffSEduard Zingerman /* read_first_param() function */ 143*fdcecdffSEduard Zingerman __msg("7: .1........ (79) r0 = *(u64 *)(r1 +0)") 144*fdcecdffSEduard Zingerman __msg("8: 0......... (95) exit") 145*fdcecdffSEduard Zingerman /* update for callsite at (2) */ 146*fdcecdffSEduard Zingerman __msg("(2,7) frame 0 insn 7 +live -8") 147*fdcecdffSEduard Zingerman __msg("(2,7) live stack update done in 2 iterations") 148*fdcecdffSEduard Zingerman __msg("(0) frame 0 insn 2 +live -8") 149*fdcecdffSEduard Zingerman __msg("(0) live stack update done in 2 iterations") 150*fdcecdffSEduard Zingerman /* update for callsite at (5) */ 151*fdcecdffSEduard Zingerman __msg("(5,7) frame 0 insn 7 +live -16") 152*fdcecdffSEduard Zingerman __msg("(5,7) live stack update done in 2 iterations") 153*fdcecdffSEduard Zingerman __msg("(0) frame 0 insn 5 +live -16") 154*fdcecdffSEduard Zingerman __msg("(0) live stack update done in 2 iterations") 155*fdcecdffSEduard Zingerman __naked void caller_stack_read(void) 156*fdcecdffSEduard Zingerman { 157*fdcecdffSEduard Zingerman asm volatile ( 158*fdcecdffSEduard Zingerman "r1 = r10;" 159*fdcecdffSEduard Zingerman "r1 += -8;" 160*fdcecdffSEduard Zingerman "call read_first_param;" 161*fdcecdffSEduard Zingerman "r1 = r10;" 162*fdcecdffSEduard Zingerman "r1 += -16;" 163*fdcecdffSEduard Zingerman "call read_first_param;" 164*fdcecdffSEduard Zingerman "exit;" 165*fdcecdffSEduard Zingerman ::: __clobber_all); 166*fdcecdffSEduard Zingerman } 167*fdcecdffSEduard Zingerman 168*fdcecdffSEduard Zingerman static __used __naked void read_first_param(void) 169*fdcecdffSEduard Zingerman { 170*fdcecdffSEduard Zingerman asm volatile ( 171*fdcecdffSEduard Zingerman "r0 = *(u64 *)(r1 + 0);" 172*fdcecdffSEduard Zingerman "exit;" 173*fdcecdffSEduard Zingerman ::: __clobber_all); 174*fdcecdffSEduard Zingerman } 175*fdcecdffSEduard Zingerman 176*fdcecdffSEduard Zingerman SEC("socket") 177*fdcecdffSEduard Zingerman __flag(BPF_F_TEST_STATE_FREQ) 178*fdcecdffSEduard Zingerman __log_level(2) 179*fdcecdffSEduard Zingerman /* read_first_param2() function */ 180*fdcecdffSEduard Zingerman __msg(" 9: .1........ (79) r0 = *(u64 *)(r1 +0)") 181*fdcecdffSEduard Zingerman __msg("10: .......... (b7) r0 = 0") 182*fdcecdffSEduard Zingerman __msg("11: 0......... (05) goto pc+0") 183*fdcecdffSEduard Zingerman __msg("12: 0......... (95) exit") 184*fdcecdffSEduard Zingerman /* 185*fdcecdffSEduard Zingerman * The purpose of the test is to check that checkpoint in 186*fdcecdffSEduard Zingerman * read_first_param2() stops path traversal. This will only happen if 187*fdcecdffSEduard Zingerman * verifier understands that fp[0]-8 at insn (12) is not alive. 188*fdcecdffSEduard Zingerman */ 189*fdcecdffSEduard Zingerman __msg("12: safe") 190*fdcecdffSEduard Zingerman __msg("processed 20 insns") 191*fdcecdffSEduard Zingerman __naked void caller_stack_pruning(void) 192*fdcecdffSEduard Zingerman { 193*fdcecdffSEduard Zingerman asm volatile ( 194*fdcecdffSEduard Zingerman "call %[bpf_get_prandom_u32];" 195*fdcecdffSEduard Zingerman "if r0 == 42 goto 1f;" 196*fdcecdffSEduard Zingerman "r0 = %[map] ll;" 197*fdcecdffSEduard Zingerman "1:" 198*fdcecdffSEduard Zingerman "*(u64 *)(r10 - 8) = r0;" 199*fdcecdffSEduard Zingerman "r1 = r10;" 200*fdcecdffSEduard Zingerman "r1 += -8;" 201*fdcecdffSEduard Zingerman /* 202*fdcecdffSEduard Zingerman * fp[0]-8 is either pointer to map or a scalar, 203*fdcecdffSEduard Zingerman * preventing state pruning at checkpoint created for call. 204*fdcecdffSEduard Zingerman */ 205*fdcecdffSEduard Zingerman "call read_first_param2;" 206*fdcecdffSEduard Zingerman "exit;" 207*fdcecdffSEduard Zingerman : 208*fdcecdffSEduard Zingerman : __imm(bpf_get_prandom_u32), 209*fdcecdffSEduard Zingerman __imm_addr(map) 210*fdcecdffSEduard Zingerman : __clobber_all); 211*fdcecdffSEduard Zingerman } 212*fdcecdffSEduard Zingerman 213*fdcecdffSEduard Zingerman static __used __naked void read_first_param2(void) 214*fdcecdffSEduard Zingerman { 215*fdcecdffSEduard Zingerman asm volatile ( 216*fdcecdffSEduard Zingerman "r0 = *(u64 *)(r1 + 0);" 217*fdcecdffSEduard Zingerman "r0 = 0;" 218*fdcecdffSEduard Zingerman /* 219*fdcecdffSEduard Zingerman * Checkpoint at goto +0 should fire, 220*fdcecdffSEduard Zingerman * as caller stack fp[0]-8 is not alive at this point. 221*fdcecdffSEduard Zingerman */ 222*fdcecdffSEduard Zingerman "goto +0;" 223*fdcecdffSEduard Zingerman "exit;" 224*fdcecdffSEduard Zingerman ::: __clobber_all); 225*fdcecdffSEduard Zingerman } 226*fdcecdffSEduard Zingerman 227*fdcecdffSEduard Zingerman SEC("socket") 228*fdcecdffSEduard Zingerman __flag(BPF_F_TEST_STATE_FREQ) 229*fdcecdffSEduard Zingerman __failure 230*fdcecdffSEduard Zingerman __msg("R1 type=scalar expected=map_ptr") 231*fdcecdffSEduard Zingerman __naked void caller_stack_pruning_callback(void) 232*fdcecdffSEduard Zingerman { 233*fdcecdffSEduard Zingerman asm volatile ( 234*fdcecdffSEduard Zingerman "r0 = %[map] ll;" 235*fdcecdffSEduard Zingerman "*(u64 *)(r10 - 8) = r0;" 236*fdcecdffSEduard Zingerman "r1 = 2;" 237*fdcecdffSEduard Zingerman "r2 = loop_cb ll;" 238*fdcecdffSEduard Zingerman "r3 = r10;" 239*fdcecdffSEduard Zingerman "r3 += -8;" 240*fdcecdffSEduard Zingerman "r4 = 0;" 241*fdcecdffSEduard Zingerman /* 242*fdcecdffSEduard Zingerman * fp[0]-8 is either pointer to map or a scalar, 243*fdcecdffSEduard Zingerman * preventing state pruning at checkpoint created for call. 244*fdcecdffSEduard Zingerman */ 245*fdcecdffSEduard Zingerman "call %[bpf_loop];" 246*fdcecdffSEduard Zingerman "r0 = 42;" 247*fdcecdffSEduard Zingerman "exit;" 248*fdcecdffSEduard Zingerman : 249*fdcecdffSEduard Zingerman : __imm(bpf_get_prandom_u32), 250*fdcecdffSEduard Zingerman __imm(bpf_loop), 251*fdcecdffSEduard Zingerman __imm_addr(map) 252*fdcecdffSEduard Zingerman : __clobber_all); 253*fdcecdffSEduard Zingerman } 254*fdcecdffSEduard Zingerman 255*fdcecdffSEduard Zingerman static __used __naked void loop_cb(void) 256*fdcecdffSEduard Zingerman { 257*fdcecdffSEduard Zingerman asm volatile ( 258*fdcecdffSEduard Zingerman /* 259*fdcecdffSEduard Zingerman * Checkpoint at function entry should not fire, as caller 260*fdcecdffSEduard Zingerman * stack fp[0]-8 is alive at this point. 261*fdcecdffSEduard Zingerman */ 262*fdcecdffSEduard Zingerman "r6 = r2;" 263*fdcecdffSEduard Zingerman "r1 = *(u64 *)(r6 + 0);" 264*fdcecdffSEduard Zingerman "*(u64*)(r10 - 8) = 7;" 265*fdcecdffSEduard Zingerman "r2 = r10;" 266*fdcecdffSEduard Zingerman "r2 += -8;" 267*fdcecdffSEduard Zingerman "call %[bpf_map_lookup_elem];" 268*fdcecdffSEduard Zingerman /* 269*fdcecdffSEduard Zingerman * This should stop verifier on a second loop iteration, 270*fdcecdffSEduard Zingerman * but only if verifier correctly maintains that fp[0]-8 271*fdcecdffSEduard Zingerman * is still alive. 272*fdcecdffSEduard Zingerman */ 273*fdcecdffSEduard Zingerman "*(u64 *)(r6 + 0) = 0;" 274*fdcecdffSEduard Zingerman "r0 = 0;" 275*fdcecdffSEduard Zingerman "exit;" 276*fdcecdffSEduard Zingerman : 277*fdcecdffSEduard Zingerman : __imm(bpf_map_lookup_elem), 278*fdcecdffSEduard Zingerman __imm(bpf_get_prandom_u32) 279*fdcecdffSEduard Zingerman : __clobber_all); 280*fdcecdffSEduard Zingerman } 281*fdcecdffSEduard Zingerman 282*fdcecdffSEduard Zingerman /* 283*fdcecdffSEduard Zingerman * Because of a bug in verifier.c:compute_postorder() 284*fdcecdffSEduard Zingerman * the program below overflowed traversal queue in that function. 285*fdcecdffSEduard Zingerman */ 286*fdcecdffSEduard Zingerman SEC("socket") 287*fdcecdffSEduard Zingerman __naked void syzbot_postorder_bug1(void) 288*fdcecdffSEduard Zingerman { 289*fdcecdffSEduard Zingerman asm volatile ( 290*fdcecdffSEduard Zingerman "r0 = 0;" 291*fdcecdffSEduard Zingerman "if r0 != 0 goto -1;" 292*fdcecdffSEduard Zingerman "exit;" 293*fdcecdffSEduard Zingerman ::: __clobber_all); 294*fdcecdffSEduard Zingerman } 295