1*4fec4c22SKumar Kartikeya Dwivedi // SPDX-License-Identifier: GPL-2.0 2*4fec4c22SKumar Kartikeya Dwivedi /* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */ 3*4fec4c22SKumar Kartikeya Dwivedi #include <vmlinux.h> 4*4fec4c22SKumar Kartikeya Dwivedi #include <bpf/bpf_helpers.h> 5*4fec4c22SKumar Kartikeya Dwivedi #include "bpf_misc.h" 6*4fec4c22SKumar Kartikeya Dwivedi #include "bpf_experimental.h" 7*4fec4c22SKumar Kartikeya Dwivedi 8*4fec4c22SKumar Kartikeya Dwivedi unsigned long global_flags; 9*4fec4c22SKumar Kartikeya Dwivedi 10*4fec4c22SKumar Kartikeya Dwivedi extern void bpf_local_irq_save(unsigned long *) __weak __ksym; 11*4fec4c22SKumar Kartikeya Dwivedi extern void bpf_local_irq_restore(unsigned long *) __weak __ksym; 12*4fec4c22SKumar Kartikeya Dwivedi extern int bpf_copy_from_user_str(void *dst, u32 dst__sz, const void *unsafe_ptr__ign, u64 flags) __weak __ksym; 13*4fec4c22SKumar Kartikeya Dwivedi 14*4fec4c22SKumar Kartikeya Dwivedi SEC("?tc") 15*4fec4c22SKumar Kartikeya Dwivedi __failure __msg("arg#0 doesn't point to an irq flag on stack") 16*4fec4c22SKumar Kartikeya Dwivedi int irq_save_bad_arg(struct __sk_buff *ctx) 17*4fec4c22SKumar Kartikeya Dwivedi { 18*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_save(&global_flags); 19*4fec4c22SKumar Kartikeya Dwivedi return 0; 20*4fec4c22SKumar Kartikeya Dwivedi } 21*4fec4c22SKumar Kartikeya Dwivedi 22*4fec4c22SKumar Kartikeya Dwivedi SEC("?tc") 23*4fec4c22SKumar Kartikeya Dwivedi __failure __msg("arg#0 doesn't point to an irq flag on stack") 24*4fec4c22SKumar Kartikeya Dwivedi int irq_restore_bad_arg(struct __sk_buff *ctx) 25*4fec4c22SKumar Kartikeya Dwivedi { 26*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_restore(&global_flags); 27*4fec4c22SKumar Kartikeya Dwivedi return 0; 28*4fec4c22SKumar Kartikeya Dwivedi } 29*4fec4c22SKumar Kartikeya Dwivedi 30*4fec4c22SKumar Kartikeya Dwivedi SEC("?tc") 31*4fec4c22SKumar Kartikeya Dwivedi __failure __msg("BPF_EXIT instruction in main prog cannot be used inside bpf_local_irq_save-ed region") 32*4fec4c22SKumar Kartikeya Dwivedi int irq_restore_missing_2(struct __sk_buff *ctx) 33*4fec4c22SKumar Kartikeya Dwivedi { 34*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags1; 35*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags2; 36*4fec4c22SKumar Kartikeya Dwivedi 37*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_save(&flags1); 38*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_save(&flags2); 39*4fec4c22SKumar Kartikeya Dwivedi return 0; 40*4fec4c22SKumar Kartikeya Dwivedi } 41*4fec4c22SKumar Kartikeya Dwivedi 42*4fec4c22SKumar Kartikeya Dwivedi SEC("?tc") 43*4fec4c22SKumar Kartikeya Dwivedi __failure __msg("BPF_EXIT instruction in main prog cannot be used inside bpf_local_irq_save-ed region") 44*4fec4c22SKumar Kartikeya Dwivedi int irq_restore_missing_3(struct __sk_buff *ctx) 45*4fec4c22SKumar Kartikeya Dwivedi { 46*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags1; 47*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags2; 48*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags3; 49*4fec4c22SKumar Kartikeya Dwivedi 50*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_save(&flags1); 51*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_save(&flags2); 52*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_save(&flags3); 53*4fec4c22SKumar Kartikeya Dwivedi return 0; 54*4fec4c22SKumar Kartikeya Dwivedi } 55*4fec4c22SKumar Kartikeya Dwivedi 56*4fec4c22SKumar Kartikeya Dwivedi SEC("?tc") 57*4fec4c22SKumar Kartikeya Dwivedi __failure __msg("BPF_EXIT instruction in main prog cannot be used inside bpf_local_irq_save-ed region") 58*4fec4c22SKumar Kartikeya Dwivedi int irq_restore_missing_3_minus_2(struct __sk_buff *ctx) 59*4fec4c22SKumar Kartikeya Dwivedi { 60*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags1; 61*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags2; 62*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags3; 63*4fec4c22SKumar Kartikeya Dwivedi 64*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_save(&flags1); 65*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_save(&flags2); 66*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_save(&flags3); 67*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_restore(&flags3); 68*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_restore(&flags2); 69*4fec4c22SKumar Kartikeya Dwivedi return 0; 70*4fec4c22SKumar Kartikeya Dwivedi } 71*4fec4c22SKumar Kartikeya Dwivedi 72*4fec4c22SKumar Kartikeya Dwivedi static __noinline void local_irq_save(unsigned long *flags) 73*4fec4c22SKumar Kartikeya Dwivedi { 74*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_save(flags); 75*4fec4c22SKumar Kartikeya Dwivedi } 76*4fec4c22SKumar Kartikeya Dwivedi 77*4fec4c22SKumar Kartikeya Dwivedi static __noinline void local_irq_restore(unsigned long *flags) 78*4fec4c22SKumar Kartikeya Dwivedi { 79*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_restore(flags); 80*4fec4c22SKumar Kartikeya Dwivedi } 81*4fec4c22SKumar Kartikeya Dwivedi 82*4fec4c22SKumar Kartikeya Dwivedi SEC("?tc") 83*4fec4c22SKumar Kartikeya Dwivedi __failure __msg("BPF_EXIT instruction in main prog cannot be used inside bpf_local_irq_save-ed region") 84*4fec4c22SKumar Kartikeya Dwivedi int irq_restore_missing_1_subprog(struct __sk_buff *ctx) 85*4fec4c22SKumar Kartikeya Dwivedi { 86*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags; 87*4fec4c22SKumar Kartikeya Dwivedi 88*4fec4c22SKumar Kartikeya Dwivedi local_irq_save(&flags); 89*4fec4c22SKumar Kartikeya Dwivedi return 0; 90*4fec4c22SKumar Kartikeya Dwivedi } 91*4fec4c22SKumar Kartikeya Dwivedi 92*4fec4c22SKumar Kartikeya Dwivedi SEC("?tc") 93*4fec4c22SKumar Kartikeya Dwivedi __failure __msg("BPF_EXIT instruction in main prog cannot be used inside bpf_local_irq_save-ed region") 94*4fec4c22SKumar Kartikeya Dwivedi int irq_restore_missing_2_subprog(struct __sk_buff *ctx) 95*4fec4c22SKumar Kartikeya Dwivedi { 96*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags1; 97*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags2; 98*4fec4c22SKumar Kartikeya Dwivedi 99*4fec4c22SKumar Kartikeya Dwivedi local_irq_save(&flags1); 100*4fec4c22SKumar Kartikeya Dwivedi local_irq_save(&flags2); 101*4fec4c22SKumar Kartikeya Dwivedi return 0; 102*4fec4c22SKumar Kartikeya Dwivedi } 103*4fec4c22SKumar Kartikeya Dwivedi 104*4fec4c22SKumar Kartikeya Dwivedi SEC("?tc") 105*4fec4c22SKumar Kartikeya Dwivedi __failure __msg("BPF_EXIT instruction in main prog cannot be used inside bpf_local_irq_save-ed region") 106*4fec4c22SKumar Kartikeya Dwivedi int irq_restore_missing_3_subprog(struct __sk_buff *ctx) 107*4fec4c22SKumar Kartikeya Dwivedi { 108*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags1; 109*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags2; 110*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags3; 111*4fec4c22SKumar Kartikeya Dwivedi 112*4fec4c22SKumar Kartikeya Dwivedi local_irq_save(&flags1); 113*4fec4c22SKumar Kartikeya Dwivedi local_irq_save(&flags2); 114*4fec4c22SKumar Kartikeya Dwivedi local_irq_save(&flags3); 115*4fec4c22SKumar Kartikeya Dwivedi return 0; 116*4fec4c22SKumar Kartikeya Dwivedi } 117*4fec4c22SKumar Kartikeya Dwivedi 118*4fec4c22SKumar Kartikeya Dwivedi SEC("?tc") 119*4fec4c22SKumar Kartikeya Dwivedi __failure __msg("BPF_EXIT instruction in main prog cannot be used inside bpf_local_irq_save-ed region") 120*4fec4c22SKumar Kartikeya Dwivedi int irq_restore_missing_3_minus_2_subprog(struct __sk_buff *ctx) 121*4fec4c22SKumar Kartikeya Dwivedi { 122*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags1; 123*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags2; 124*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags3; 125*4fec4c22SKumar Kartikeya Dwivedi 126*4fec4c22SKumar Kartikeya Dwivedi local_irq_save(&flags1); 127*4fec4c22SKumar Kartikeya Dwivedi local_irq_save(&flags2); 128*4fec4c22SKumar Kartikeya Dwivedi local_irq_save(&flags3); 129*4fec4c22SKumar Kartikeya Dwivedi local_irq_restore(&flags3); 130*4fec4c22SKumar Kartikeya Dwivedi local_irq_restore(&flags2); 131*4fec4c22SKumar Kartikeya Dwivedi return 0; 132*4fec4c22SKumar Kartikeya Dwivedi } 133*4fec4c22SKumar Kartikeya Dwivedi 134*4fec4c22SKumar Kartikeya Dwivedi SEC("?tc") 135*4fec4c22SKumar Kartikeya Dwivedi __success 136*4fec4c22SKumar Kartikeya Dwivedi int irq_balance(struct __sk_buff *ctx) 137*4fec4c22SKumar Kartikeya Dwivedi { 138*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags; 139*4fec4c22SKumar Kartikeya Dwivedi 140*4fec4c22SKumar Kartikeya Dwivedi local_irq_save(&flags); 141*4fec4c22SKumar Kartikeya Dwivedi local_irq_restore(&flags); 142*4fec4c22SKumar Kartikeya Dwivedi return 0; 143*4fec4c22SKumar Kartikeya Dwivedi } 144*4fec4c22SKumar Kartikeya Dwivedi 145*4fec4c22SKumar Kartikeya Dwivedi SEC("?tc") 146*4fec4c22SKumar Kartikeya Dwivedi __success 147*4fec4c22SKumar Kartikeya Dwivedi int irq_balance_n(struct __sk_buff *ctx) 148*4fec4c22SKumar Kartikeya Dwivedi { 149*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags1; 150*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags2; 151*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags3; 152*4fec4c22SKumar Kartikeya Dwivedi 153*4fec4c22SKumar Kartikeya Dwivedi local_irq_save(&flags1); 154*4fec4c22SKumar Kartikeya Dwivedi local_irq_save(&flags2); 155*4fec4c22SKumar Kartikeya Dwivedi local_irq_save(&flags3); 156*4fec4c22SKumar Kartikeya Dwivedi local_irq_restore(&flags3); 157*4fec4c22SKumar Kartikeya Dwivedi local_irq_restore(&flags2); 158*4fec4c22SKumar Kartikeya Dwivedi local_irq_restore(&flags1); 159*4fec4c22SKumar Kartikeya Dwivedi return 0; 160*4fec4c22SKumar Kartikeya Dwivedi } 161*4fec4c22SKumar Kartikeya Dwivedi 162*4fec4c22SKumar Kartikeya Dwivedi static __noinline void local_irq_balance(void) 163*4fec4c22SKumar Kartikeya Dwivedi { 164*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags; 165*4fec4c22SKumar Kartikeya Dwivedi 166*4fec4c22SKumar Kartikeya Dwivedi local_irq_save(&flags); 167*4fec4c22SKumar Kartikeya Dwivedi local_irq_restore(&flags); 168*4fec4c22SKumar Kartikeya Dwivedi } 169*4fec4c22SKumar Kartikeya Dwivedi 170*4fec4c22SKumar Kartikeya Dwivedi static __noinline void local_irq_balance_n(void) 171*4fec4c22SKumar Kartikeya Dwivedi { 172*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags1; 173*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags2; 174*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags3; 175*4fec4c22SKumar Kartikeya Dwivedi 176*4fec4c22SKumar Kartikeya Dwivedi local_irq_save(&flags1); 177*4fec4c22SKumar Kartikeya Dwivedi local_irq_save(&flags2); 178*4fec4c22SKumar Kartikeya Dwivedi local_irq_save(&flags3); 179*4fec4c22SKumar Kartikeya Dwivedi local_irq_restore(&flags3); 180*4fec4c22SKumar Kartikeya Dwivedi local_irq_restore(&flags2); 181*4fec4c22SKumar Kartikeya Dwivedi local_irq_restore(&flags1); 182*4fec4c22SKumar Kartikeya Dwivedi } 183*4fec4c22SKumar Kartikeya Dwivedi 184*4fec4c22SKumar Kartikeya Dwivedi SEC("?tc") 185*4fec4c22SKumar Kartikeya Dwivedi __success 186*4fec4c22SKumar Kartikeya Dwivedi int irq_balance_subprog(struct __sk_buff *ctx) 187*4fec4c22SKumar Kartikeya Dwivedi { 188*4fec4c22SKumar Kartikeya Dwivedi local_irq_balance(); 189*4fec4c22SKumar Kartikeya Dwivedi return 0; 190*4fec4c22SKumar Kartikeya Dwivedi } 191*4fec4c22SKumar Kartikeya Dwivedi 192*4fec4c22SKumar Kartikeya Dwivedi SEC("?fentry.s/" SYS_PREFIX "sys_getpgid") 193*4fec4c22SKumar Kartikeya Dwivedi __failure __msg("sleepable helper bpf_copy_from_user#") 194*4fec4c22SKumar Kartikeya Dwivedi int irq_sleepable_helper(void *ctx) 195*4fec4c22SKumar Kartikeya Dwivedi { 196*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags; 197*4fec4c22SKumar Kartikeya Dwivedi u32 data; 198*4fec4c22SKumar Kartikeya Dwivedi 199*4fec4c22SKumar Kartikeya Dwivedi local_irq_save(&flags); 200*4fec4c22SKumar Kartikeya Dwivedi bpf_copy_from_user(&data, sizeof(data), NULL); 201*4fec4c22SKumar Kartikeya Dwivedi local_irq_restore(&flags); 202*4fec4c22SKumar Kartikeya Dwivedi return 0; 203*4fec4c22SKumar Kartikeya Dwivedi } 204*4fec4c22SKumar Kartikeya Dwivedi 205*4fec4c22SKumar Kartikeya Dwivedi SEC("?fentry.s/" SYS_PREFIX "sys_getpgid") 206*4fec4c22SKumar Kartikeya Dwivedi __failure __msg("kernel func bpf_copy_from_user_str is sleepable within IRQ-disabled region") 207*4fec4c22SKumar Kartikeya Dwivedi int irq_sleepable_kfunc(void *ctx) 208*4fec4c22SKumar Kartikeya Dwivedi { 209*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags; 210*4fec4c22SKumar Kartikeya Dwivedi u32 data; 211*4fec4c22SKumar Kartikeya Dwivedi 212*4fec4c22SKumar Kartikeya Dwivedi local_irq_save(&flags); 213*4fec4c22SKumar Kartikeya Dwivedi bpf_copy_from_user_str(&data, sizeof(data), NULL, 0); 214*4fec4c22SKumar Kartikeya Dwivedi local_irq_restore(&flags); 215*4fec4c22SKumar Kartikeya Dwivedi return 0; 216*4fec4c22SKumar Kartikeya Dwivedi } 217*4fec4c22SKumar Kartikeya Dwivedi 218*4fec4c22SKumar Kartikeya Dwivedi int __noinline global_local_irq_balance(void) 219*4fec4c22SKumar Kartikeya Dwivedi { 220*4fec4c22SKumar Kartikeya Dwivedi local_irq_balance_n(); 221*4fec4c22SKumar Kartikeya Dwivedi return 0; 222*4fec4c22SKumar Kartikeya Dwivedi } 223*4fec4c22SKumar Kartikeya Dwivedi 224*4fec4c22SKumar Kartikeya Dwivedi SEC("?tc") 225*4fec4c22SKumar Kartikeya Dwivedi __failure __msg("global function calls are not allowed with IRQs disabled") 226*4fec4c22SKumar Kartikeya Dwivedi int irq_global_subprog(struct __sk_buff *ctx) 227*4fec4c22SKumar Kartikeya Dwivedi { 228*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags; 229*4fec4c22SKumar Kartikeya Dwivedi 230*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_save(&flags); 231*4fec4c22SKumar Kartikeya Dwivedi global_local_irq_balance(); 232*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_restore(&flags); 233*4fec4c22SKumar Kartikeya Dwivedi return 0; 234*4fec4c22SKumar Kartikeya Dwivedi } 235*4fec4c22SKumar Kartikeya Dwivedi 236*4fec4c22SKumar Kartikeya Dwivedi SEC("?tc") 237*4fec4c22SKumar Kartikeya Dwivedi __failure __msg("cannot restore irq state out of order") 238*4fec4c22SKumar Kartikeya Dwivedi int irq_restore_ooo(struct __sk_buff *ctx) 239*4fec4c22SKumar Kartikeya Dwivedi { 240*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags1; 241*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags2; 242*4fec4c22SKumar Kartikeya Dwivedi 243*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_save(&flags1); 244*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_save(&flags2); 245*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_restore(&flags1); 246*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_restore(&flags2); 247*4fec4c22SKumar Kartikeya Dwivedi return 0; 248*4fec4c22SKumar Kartikeya Dwivedi } 249*4fec4c22SKumar Kartikeya Dwivedi 250*4fec4c22SKumar Kartikeya Dwivedi SEC("?tc") 251*4fec4c22SKumar Kartikeya Dwivedi __failure __msg("cannot restore irq state out of order") 252*4fec4c22SKumar Kartikeya Dwivedi int irq_restore_ooo_3(struct __sk_buff *ctx) 253*4fec4c22SKumar Kartikeya Dwivedi { 254*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags1; 255*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags2; 256*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags3; 257*4fec4c22SKumar Kartikeya Dwivedi 258*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_save(&flags1); 259*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_save(&flags2); 260*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_restore(&flags2); 261*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_save(&flags3); 262*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_restore(&flags1); 263*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_restore(&flags3); 264*4fec4c22SKumar Kartikeya Dwivedi return 0; 265*4fec4c22SKumar Kartikeya Dwivedi } 266*4fec4c22SKumar Kartikeya Dwivedi 267*4fec4c22SKumar Kartikeya Dwivedi static __noinline void local_irq_save_3(unsigned long *flags1, unsigned long *flags2, 268*4fec4c22SKumar Kartikeya Dwivedi unsigned long *flags3) 269*4fec4c22SKumar Kartikeya Dwivedi { 270*4fec4c22SKumar Kartikeya Dwivedi local_irq_save(flags1); 271*4fec4c22SKumar Kartikeya Dwivedi local_irq_save(flags2); 272*4fec4c22SKumar Kartikeya Dwivedi local_irq_save(flags3); 273*4fec4c22SKumar Kartikeya Dwivedi } 274*4fec4c22SKumar Kartikeya Dwivedi 275*4fec4c22SKumar Kartikeya Dwivedi SEC("?tc") 276*4fec4c22SKumar Kartikeya Dwivedi __success 277*4fec4c22SKumar Kartikeya Dwivedi int irq_restore_3_subprog(struct __sk_buff *ctx) 278*4fec4c22SKumar Kartikeya Dwivedi { 279*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags1; 280*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags2; 281*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags3; 282*4fec4c22SKumar Kartikeya Dwivedi 283*4fec4c22SKumar Kartikeya Dwivedi local_irq_save_3(&flags1, &flags2, &flags3); 284*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_restore(&flags3); 285*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_restore(&flags2); 286*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_restore(&flags1); 287*4fec4c22SKumar Kartikeya Dwivedi return 0; 288*4fec4c22SKumar Kartikeya Dwivedi } 289*4fec4c22SKumar Kartikeya Dwivedi 290*4fec4c22SKumar Kartikeya Dwivedi SEC("?tc") 291*4fec4c22SKumar Kartikeya Dwivedi __failure __msg("cannot restore irq state out of order") 292*4fec4c22SKumar Kartikeya Dwivedi int irq_restore_4_subprog(struct __sk_buff *ctx) 293*4fec4c22SKumar Kartikeya Dwivedi { 294*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags1; 295*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags2; 296*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags3; 297*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags4; 298*4fec4c22SKumar Kartikeya Dwivedi 299*4fec4c22SKumar Kartikeya Dwivedi local_irq_save_3(&flags1, &flags2, &flags3); 300*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_restore(&flags3); 301*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_save(&flags4); 302*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_restore(&flags4); 303*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_restore(&flags1); 304*4fec4c22SKumar Kartikeya Dwivedi return 0; 305*4fec4c22SKumar Kartikeya Dwivedi } 306*4fec4c22SKumar Kartikeya Dwivedi 307*4fec4c22SKumar Kartikeya Dwivedi SEC("?tc") 308*4fec4c22SKumar Kartikeya Dwivedi __failure __msg("cannot restore irq state out of order") 309*4fec4c22SKumar Kartikeya Dwivedi int irq_restore_ooo_3_subprog(struct __sk_buff *ctx) 310*4fec4c22SKumar Kartikeya Dwivedi { 311*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags1; 312*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags2; 313*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags3; 314*4fec4c22SKumar Kartikeya Dwivedi 315*4fec4c22SKumar Kartikeya Dwivedi local_irq_save_3(&flags1, &flags2, &flags3); 316*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_restore(&flags3); 317*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_restore(&flags2); 318*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_save(&flags3); 319*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_restore(&flags1); 320*4fec4c22SKumar Kartikeya Dwivedi return 0; 321*4fec4c22SKumar Kartikeya Dwivedi } 322*4fec4c22SKumar Kartikeya Dwivedi 323*4fec4c22SKumar Kartikeya Dwivedi SEC("?tc") 324*4fec4c22SKumar Kartikeya Dwivedi __failure __msg("expected an initialized") 325*4fec4c22SKumar Kartikeya Dwivedi int irq_restore_invalid(struct __sk_buff *ctx) 326*4fec4c22SKumar Kartikeya Dwivedi { 327*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags1; 328*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags = 0xfaceb00c; 329*4fec4c22SKumar Kartikeya Dwivedi 330*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_save(&flags1); 331*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_restore(&flags); 332*4fec4c22SKumar Kartikeya Dwivedi return 0; 333*4fec4c22SKumar Kartikeya Dwivedi } 334*4fec4c22SKumar Kartikeya Dwivedi 335*4fec4c22SKumar Kartikeya Dwivedi SEC("?tc") 336*4fec4c22SKumar Kartikeya Dwivedi __failure __msg("expected uninitialized") 337*4fec4c22SKumar Kartikeya Dwivedi int irq_save_invalid(struct __sk_buff *ctx) 338*4fec4c22SKumar Kartikeya Dwivedi { 339*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags1; 340*4fec4c22SKumar Kartikeya Dwivedi 341*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_save(&flags1); 342*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_save(&flags1); 343*4fec4c22SKumar Kartikeya Dwivedi return 0; 344*4fec4c22SKumar Kartikeya Dwivedi } 345*4fec4c22SKumar Kartikeya Dwivedi 346*4fec4c22SKumar Kartikeya Dwivedi SEC("?tc") 347*4fec4c22SKumar Kartikeya Dwivedi __failure __msg("expected an initialized") 348*4fec4c22SKumar Kartikeya Dwivedi int irq_restore_iter(struct __sk_buff *ctx) 349*4fec4c22SKumar Kartikeya Dwivedi { 350*4fec4c22SKumar Kartikeya Dwivedi struct bpf_iter_num it; 351*4fec4c22SKumar Kartikeya Dwivedi 352*4fec4c22SKumar Kartikeya Dwivedi bpf_iter_num_new(&it, 0, 42); 353*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_restore((unsigned long *)&it); 354*4fec4c22SKumar Kartikeya Dwivedi return 0; 355*4fec4c22SKumar Kartikeya Dwivedi } 356*4fec4c22SKumar Kartikeya Dwivedi 357*4fec4c22SKumar Kartikeya Dwivedi SEC("?tc") 358*4fec4c22SKumar Kartikeya Dwivedi __failure __msg("Unreleased reference id=1") 359*4fec4c22SKumar Kartikeya Dwivedi int irq_save_iter(struct __sk_buff *ctx) 360*4fec4c22SKumar Kartikeya Dwivedi { 361*4fec4c22SKumar Kartikeya Dwivedi struct bpf_iter_num it; 362*4fec4c22SKumar Kartikeya Dwivedi 363*4fec4c22SKumar Kartikeya Dwivedi /* Ensure same sized slot has st->ref_obj_id set, so we reject based on 364*4fec4c22SKumar Kartikeya Dwivedi * slot_type != STACK_IRQ_FLAG... 365*4fec4c22SKumar Kartikeya Dwivedi */ 366*4fec4c22SKumar Kartikeya Dwivedi _Static_assert(sizeof(it) == sizeof(unsigned long), "broken iterator size"); 367*4fec4c22SKumar Kartikeya Dwivedi 368*4fec4c22SKumar Kartikeya Dwivedi bpf_iter_num_new(&it, 0, 42); 369*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_save((unsigned long *)&it); 370*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_restore((unsigned long *)&it); 371*4fec4c22SKumar Kartikeya Dwivedi return 0; 372*4fec4c22SKumar Kartikeya Dwivedi } 373*4fec4c22SKumar Kartikeya Dwivedi 374*4fec4c22SKumar Kartikeya Dwivedi SEC("?tc") 375*4fec4c22SKumar Kartikeya Dwivedi __failure __msg("expected an initialized") 376*4fec4c22SKumar Kartikeya Dwivedi int irq_flag_overwrite(struct __sk_buff *ctx) 377*4fec4c22SKumar Kartikeya Dwivedi { 378*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags; 379*4fec4c22SKumar Kartikeya Dwivedi 380*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_save(&flags); 381*4fec4c22SKumar Kartikeya Dwivedi flags = 0xdeadbeef; 382*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_restore(&flags); 383*4fec4c22SKumar Kartikeya Dwivedi return 0; 384*4fec4c22SKumar Kartikeya Dwivedi } 385*4fec4c22SKumar Kartikeya Dwivedi 386*4fec4c22SKumar Kartikeya Dwivedi SEC("?tc") 387*4fec4c22SKumar Kartikeya Dwivedi __failure __msg("expected an initialized") 388*4fec4c22SKumar Kartikeya Dwivedi int irq_flag_overwrite_partial(struct __sk_buff *ctx) 389*4fec4c22SKumar Kartikeya Dwivedi { 390*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags; 391*4fec4c22SKumar Kartikeya Dwivedi 392*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_save(&flags); 393*4fec4c22SKumar Kartikeya Dwivedi *(((char *)&flags) + 1) = 0xff; 394*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_restore(&flags); 395*4fec4c22SKumar Kartikeya Dwivedi return 0; 396*4fec4c22SKumar Kartikeya Dwivedi } 397*4fec4c22SKumar Kartikeya Dwivedi 398*4fec4c22SKumar Kartikeya Dwivedi SEC("?tc") 399*4fec4c22SKumar Kartikeya Dwivedi __failure __msg("cannot restore irq state out of order") 400*4fec4c22SKumar Kartikeya Dwivedi int irq_ooo_refs_array(struct __sk_buff *ctx) 401*4fec4c22SKumar Kartikeya Dwivedi { 402*4fec4c22SKumar Kartikeya Dwivedi unsigned long flags[4]; 403*4fec4c22SKumar Kartikeya Dwivedi struct { int i; } *p; 404*4fec4c22SKumar Kartikeya Dwivedi 405*4fec4c22SKumar Kartikeya Dwivedi /* refs=1 */ 406*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_save(&flags[0]); 407*4fec4c22SKumar Kartikeya Dwivedi 408*4fec4c22SKumar Kartikeya Dwivedi /* refs=1,2 */ 409*4fec4c22SKumar Kartikeya Dwivedi p = bpf_obj_new(typeof(*p)); 410*4fec4c22SKumar Kartikeya Dwivedi if (!p) { 411*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_restore(&flags[0]); 412*4fec4c22SKumar Kartikeya Dwivedi return 0; 413*4fec4c22SKumar Kartikeya Dwivedi } 414*4fec4c22SKumar Kartikeya Dwivedi 415*4fec4c22SKumar Kartikeya Dwivedi /* refs=1,2,3 */ 416*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_save(&flags[1]); 417*4fec4c22SKumar Kartikeya Dwivedi 418*4fec4c22SKumar Kartikeya Dwivedi /* refs=1,2,3,4 */ 419*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_save(&flags[2]); 420*4fec4c22SKumar Kartikeya Dwivedi 421*4fec4c22SKumar Kartikeya Dwivedi /* Now when we remove ref=2, the verifier must not break the ordering in 422*4fec4c22SKumar Kartikeya Dwivedi * the refs array between 1,3,4. With an older implementation, the 423*4fec4c22SKumar Kartikeya Dwivedi * verifier would swap the last element with the removed element, but to 424*4fec4c22SKumar Kartikeya Dwivedi * maintain the stack property we need to use memmove. 425*4fec4c22SKumar Kartikeya Dwivedi */ 426*4fec4c22SKumar Kartikeya Dwivedi bpf_obj_drop(p); 427*4fec4c22SKumar Kartikeya Dwivedi 428*4fec4c22SKumar Kartikeya Dwivedi /* Save and restore to reset active_irq_id to 3, as the ordering is now 429*4fec4c22SKumar Kartikeya Dwivedi * refs=1,4,3. When restoring the linear scan will find prev_id in order 430*4fec4c22SKumar Kartikeya Dwivedi * as 3 instead of 4. 431*4fec4c22SKumar Kartikeya Dwivedi */ 432*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_save(&flags[3]); 433*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_restore(&flags[3]); 434*4fec4c22SKumar Kartikeya Dwivedi 435*4fec4c22SKumar Kartikeya Dwivedi /* With the incorrect implementation, we can release flags[1], flags[2], 436*4fec4c22SKumar Kartikeya Dwivedi * and flags[0], i.e. in the wrong order. 437*4fec4c22SKumar Kartikeya Dwivedi */ 438*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_restore(&flags[1]); 439*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_restore(&flags[2]); 440*4fec4c22SKumar Kartikeya Dwivedi bpf_local_irq_restore(&flags[0]); 441*4fec4c22SKumar Kartikeya Dwivedi return 0; 442*4fec4c22SKumar Kartikeya Dwivedi } 443*4fec4c22SKumar Kartikeya Dwivedi 444*4fec4c22SKumar Kartikeya Dwivedi char _license[] SEC("license") = "GPL"; 445