1*48671232SYonghong Song // SPDX-License-Identifier: GPL-2.0 2*48671232SYonghong Song /* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */ 3*48671232SYonghong Song 4*48671232SYonghong Song #include "vmlinux.h" 5*48671232SYonghong Song #include <bpf/bpf_helpers.h> 6*48671232SYonghong Song #include <bpf/bpf_tracing.h> 7*48671232SYonghong Song #include "bpf_tracing_net.h" 8*48671232SYonghong Song #include "bpf_misc.h" 9*48671232SYonghong Song 10*48671232SYonghong Song char _license[] SEC("license") = "GPL"; 11*48671232SYonghong Song 12*48671232SYonghong Song struct { 13*48671232SYonghong Song __uint(type, BPF_MAP_TYPE_TASK_STORAGE); 14*48671232SYonghong Song __uint(map_flags, BPF_F_NO_PREALLOC); 15*48671232SYonghong Song __type(key, int); 16*48671232SYonghong Song __type(value, long); 17*48671232SYonghong Song } map_a SEC(".maps"); 18*48671232SYonghong Song 19*48671232SYonghong Song __u32 user_data, key_serial, target_pid; 20*48671232SYonghong Song __u64 flags, task_storage_val, cgroup_id; 21*48671232SYonghong Song 22*48671232SYonghong Song struct bpf_key *bpf_lookup_user_key(__u32 serial, __u64 flags) __ksym; 23*48671232SYonghong Song void bpf_key_put(struct bpf_key *key) __ksym; 24*48671232SYonghong Song void bpf_rcu_read_lock(void) __ksym; 25*48671232SYonghong Song void bpf_rcu_read_unlock(void) __ksym; 26*48671232SYonghong Song struct task_struct *bpf_task_acquire(struct task_struct *p) __ksym; 27*48671232SYonghong Song void bpf_task_release(struct task_struct *p) __ksym; 28*48671232SYonghong Song 29*48671232SYonghong Song SEC("?fentry.s/" SYS_PREFIX "sys_getpgid") 30*48671232SYonghong Song int get_cgroup_id(void *ctx) 31*48671232SYonghong Song { 32*48671232SYonghong Song struct task_struct *task; 33*48671232SYonghong Song 34*48671232SYonghong Song task = bpf_get_current_task_btf(); 35*48671232SYonghong Song if (task->pid != target_pid) 36*48671232SYonghong Song return 0; 37*48671232SYonghong Song 38*48671232SYonghong Song /* simulate bpf_get_current_cgroup_id() helper */ 39*48671232SYonghong Song bpf_rcu_read_lock(); 40*48671232SYonghong Song cgroup_id = task->cgroups->dfl_cgrp->kn->id; 41*48671232SYonghong Song bpf_rcu_read_unlock(); 42*48671232SYonghong Song return 0; 43*48671232SYonghong Song } 44*48671232SYonghong Song 45*48671232SYonghong Song SEC("?fentry.s/" SYS_PREFIX "sys_getpgid") 46*48671232SYonghong Song int task_succ(void *ctx) 47*48671232SYonghong Song { 48*48671232SYonghong Song struct task_struct *task, *real_parent; 49*48671232SYonghong Song long init_val = 2; 50*48671232SYonghong Song long *ptr; 51*48671232SYonghong Song 52*48671232SYonghong Song task = bpf_get_current_task_btf(); 53*48671232SYonghong Song if (task->pid != target_pid) 54*48671232SYonghong Song return 0; 55*48671232SYonghong Song 56*48671232SYonghong Song bpf_rcu_read_lock(); 57*48671232SYonghong Song /* region including helper using rcu ptr real_parent */ 58*48671232SYonghong Song real_parent = task->real_parent; 59*48671232SYonghong Song ptr = bpf_task_storage_get(&map_a, real_parent, &init_val, 60*48671232SYonghong Song BPF_LOCAL_STORAGE_GET_F_CREATE); 61*48671232SYonghong Song if (!ptr) 62*48671232SYonghong Song goto out; 63*48671232SYonghong Song ptr = bpf_task_storage_get(&map_a, real_parent, 0, 0); 64*48671232SYonghong Song if (!ptr) 65*48671232SYonghong Song goto out; 66*48671232SYonghong Song task_storage_val = *ptr; 67*48671232SYonghong Song out: 68*48671232SYonghong Song bpf_rcu_read_unlock(); 69*48671232SYonghong Song return 0; 70*48671232SYonghong Song } 71*48671232SYonghong Song 72*48671232SYonghong Song SEC("?fentry.s/" SYS_PREFIX "sys_nanosleep") 73*48671232SYonghong Song int no_lock(void *ctx) 74*48671232SYonghong Song { 75*48671232SYonghong Song struct task_struct *task, *real_parent; 76*48671232SYonghong Song 77*48671232SYonghong Song /* no bpf_rcu_read_lock(), old code still works */ 78*48671232SYonghong Song task = bpf_get_current_task_btf(); 79*48671232SYonghong Song real_parent = task->real_parent; 80*48671232SYonghong Song (void)bpf_task_storage_get(&map_a, real_parent, 0, 0); 81*48671232SYonghong Song return 0; 82*48671232SYonghong Song } 83*48671232SYonghong Song 84*48671232SYonghong Song SEC("?fentry.s/" SYS_PREFIX "sys_nanosleep") 85*48671232SYonghong Song int two_regions(void *ctx) 86*48671232SYonghong Song { 87*48671232SYonghong Song struct task_struct *task, *real_parent; 88*48671232SYonghong Song 89*48671232SYonghong Song /* two regions */ 90*48671232SYonghong Song task = bpf_get_current_task_btf(); 91*48671232SYonghong Song bpf_rcu_read_lock(); 92*48671232SYonghong Song bpf_rcu_read_unlock(); 93*48671232SYonghong Song bpf_rcu_read_lock(); 94*48671232SYonghong Song real_parent = task->real_parent; 95*48671232SYonghong Song (void)bpf_task_storage_get(&map_a, real_parent, 0, 0); 96*48671232SYonghong Song bpf_rcu_read_unlock(); 97*48671232SYonghong Song return 0; 98*48671232SYonghong Song } 99*48671232SYonghong Song 100*48671232SYonghong Song SEC("?fentry/" SYS_PREFIX "sys_getpgid") 101*48671232SYonghong Song int non_sleepable_1(void *ctx) 102*48671232SYonghong Song { 103*48671232SYonghong Song struct task_struct *task, *real_parent; 104*48671232SYonghong Song 105*48671232SYonghong Song task = bpf_get_current_task_btf(); 106*48671232SYonghong Song bpf_rcu_read_lock(); 107*48671232SYonghong Song real_parent = task->real_parent; 108*48671232SYonghong Song (void)bpf_task_storage_get(&map_a, real_parent, 0, 0); 109*48671232SYonghong Song bpf_rcu_read_unlock(); 110*48671232SYonghong Song return 0; 111*48671232SYonghong Song } 112*48671232SYonghong Song 113*48671232SYonghong Song SEC("?fentry/" SYS_PREFIX "sys_getpgid") 114*48671232SYonghong Song int non_sleepable_2(void *ctx) 115*48671232SYonghong Song { 116*48671232SYonghong Song struct task_struct *task, *real_parent; 117*48671232SYonghong Song 118*48671232SYonghong Song bpf_rcu_read_lock(); 119*48671232SYonghong Song task = bpf_get_current_task_btf(); 120*48671232SYonghong Song bpf_rcu_read_unlock(); 121*48671232SYonghong Song 122*48671232SYonghong Song bpf_rcu_read_lock(); 123*48671232SYonghong Song real_parent = task->real_parent; 124*48671232SYonghong Song (void)bpf_task_storage_get(&map_a, real_parent, 0, 0); 125*48671232SYonghong Song bpf_rcu_read_unlock(); 126*48671232SYonghong Song return 0; 127*48671232SYonghong Song } 128*48671232SYonghong Song 129*48671232SYonghong Song SEC("?fentry.s/" SYS_PREFIX "sys_nanosleep") 130*48671232SYonghong Song int task_acquire(void *ctx) 131*48671232SYonghong Song { 132*48671232SYonghong Song struct task_struct *task, *real_parent; 133*48671232SYonghong Song 134*48671232SYonghong Song task = bpf_get_current_task_btf(); 135*48671232SYonghong Song bpf_rcu_read_lock(); 136*48671232SYonghong Song real_parent = task->real_parent; 137*48671232SYonghong Song /* acquire a reference which can be used outside rcu read lock region */ 138*48671232SYonghong Song real_parent = bpf_task_acquire(real_parent); 139*48671232SYonghong Song bpf_rcu_read_unlock(); 140*48671232SYonghong Song (void)bpf_task_storage_get(&map_a, real_parent, 0, 0); 141*48671232SYonghong Song bpf_task_release(real_parent); 142*48671232SYonghong Song return 0; 143*48671232SYonghong Song } 144*48671232SYonghong Song 145*48671232SYonghong Song SEC("?fentry.s/" SYS_PREFIX "sys_getpgid") 146*48671232SYonghong Song int miss_lock(void *ctx) 147*48671232SYonghong Song { 148*48671232SYonghong Song struct task_struct *task; 149*48671232SYonghong Song struct css_set *cgroups; 150*48671232SYonghong Song struct cgroup *dfl_cgrp; 151*48671232SYonghong Song 152*48671232SYonghong Song /* missing bpf_rcu_read_lock() */ 153*48671232SYonghong Song task = bpf_get_current_task_btf(); 154*48671232SYonghong Song bpf_rcu_read_lock(); 155*48671232SYonghong Song (void)bpf_task_storage_get(&map_a, task, 0, 0); 156*48671232SYonghong Song bpf_rcu_read_unlock(); 157*48671232SYonghong Song bpf_rcu_read_unlock(); 158*48671232SYonghong Song return 0; 159*48671232SYonghong Song } 160*48671232SYonghong Song 161*48671232SYonghong Song SEC("?fentry.s/" SYS_PREFIX "sys_getpgid") 162*48671232SYonghong Song int miss_unlock(void *ctx) 163*48671232SYonghong Song { 164*48671232SYonghong Song struct task_struct *task; 165*48671232SYonghong Song struct css_set *cgroups; 166*48671232SYonghong Song struct cgroup *dfl_cgrp; 167*48671232SYonghong Song 168*48671232SYonghong Song /* missing bpf_rcu_read_unlock() */ 169*48671232SYonghong Song task = bpf_get_current_task_btf(); 170*48671232SYonghong Song bpf_rcu_read_lock(); 171*48671232SYonghong Song (void)bpf_task_storage_get(&map_a, task, 0, 0); 172*48671232SYonghong Song return 0; 173*48671232SYonghong Song } 174*48671232SYonghong Song 175*48671232SYonghong Song SEC("?fentry/" SYS_PREFIX "sys_getpgid") 176*48671232SYonghong Song int non_sleepable_rcu_mismatch(void *ctx) 177*48671232SYonghong Song { 178*48671232SYonghong Song struct task_struct *task, *real_parent; 179*48671232SYonghong Song 180*48671232SYonghong Song task = bpf_get_current_task_btf(); 181*48671232SYonghong Song /* non-sleepable: missing bpf_rcu_read_unlock() in one path */ 182*48671232SYonghong Song bpf_rcu_read_lock(); 183*48671232SYonghong Song real_parent = task->real_parent; 184*48671232SYonghong Song (void)bpf_task_storage_get(&map_a, real_parent, 0, 0); 185*48671232SYonghong Song if (real_parent) 186*48671232SYonghong Song bpf_rcu_read_unlock(); 187*48671232SYonghong Song return 0; 188*48671232SYonghong Song } 189*48671232SYonghong Song 190*48671232SYonghong Song SEC("?fentry.s/" SYS_PREFIX "sys_getpgid") 191*48671232SYonghong Song int inproper_sleepable_helper(void *ctx) 192*48671232SYonghong Song { 193*48671232SYonghong Song struct task_struct *task, *real_parent; 194*48671232SYonghong Song struct pt_regs *regs; 195*48671232SYonghong Song __u32 value = 0; 196*48671232SYonghong Song void *ptr; 197*48671232SYonghong Song 198*48671232SYonghong Song task = bpf_get_current_task_btf(); 199*48671232SYonghong Song /* sleepable helper in rcu read lock region */ 200*48671232SYonghong Song bpf_rcu_read_lock(); 201*48671232SYonghong Song real_parent = task->real_parent; 202*48671232SYonghong Song regs = (struct pt_regs *)bpf_task_pt_regs(real_parent); 203*48671232SYonghong Song if (!regs) { 204*48671232SYonghong Song bpf_rcu_read_unlock(); 205*48671232SYonghong Song return 0; 206*48671232SYonghong Song } 207*48671232SYonghong Song 208*48671232SYonghong Song ptr = (void *)PT_REGS_IP(regs); 209*48671232SYonghong Song (void)bpf_copy_from_user_task(&value, sizeof(uint32_t), ptr, task, 0); 210*48671232SYonghong Song user_data = value; 211*48671232SYonghong Song (void)bpf_task_storage_get(&map_a, real_parent, 0, 0); 212*48671232SYonghong Song bpf_rcu_read_unlock(); 213*48671232SYonghong Song return 0; 214*48671232SYonghong Song } 215*48671232SYonghong Song 216*48671232SYonghong Song SEC("?lsm.s/bpf") 217*48671232SYonghong Song int BPF_PROG(inproper_sleepable_kfunc, int cmd, union bpf_attr *attr, unsigned int size) 218*48671232SYonghong Song { 219*48671232SYonghong Song struct bpf_key *bkey; 220*48671232SYonghong Song 221*48671232SYonghong Song /* sleepable kfunc in rcu read lock region */ 222*48671232SYonghong Song bpf_rcu_read_lock(); 223*48671232SYonghong Song bkey = bpf_lookup_user_key(key_serial, flags); 224*48671232SYonghong Song bpf_rcu_read_unlock(); 225*48671232SYonghong Song if (!bkey) 226*48671232SYonghong Song return -1; 227*48671232SYonghong Song bpf_key_put(bkey); 228*48671232SYonghong Song 229*48671232SYonghong Song return 0; 230*48671232SYonghong Song } 231*48671232SYonghong Song 232*48671232SYonghong Song SEC("?fentry.s/" SYS_PREFIX "sys_nanosleep") 233*48671232SYonghong Song int nested_rcu_region(void *ctx) 234*48671232SYonghong Song { 235*48671232SYonghong Song struct task_struct *task, *real_parent; 236*48671232SYonghong Song 237*48671232SYonghong Song /* nested rcu read lock regions */ 238*48671232SYonghong Song task = bpf_get_current_task_btf(); 239*48671232SYonghong Song bpf_rcu_read_lock(); 240*48671232SYonghong Song bpf_rcu_read_lock(); 241*48671232SYonghong Song real_parent = task->real_parent; 242*48671232SYonghong Song (void)bpf_task_storage_get(&map_a, real_parent, 0, 0); 243*48671232SYonghong Song bpf_rcu_read_unlock(); 244*48671232SYonghong Song bpf_rcu_read_unlock(); 245*48671232SYonghong Song return 0; 246*48671232SYonghong Song } 247*48671232SYonghong Song 248*48671232SYonghong Song SEC("?fentry.s/" SYS_PREFIX "sys_getpgid") 249*48671232SYonghong Song int task_untrusted_non_rcuptr(void *ctx) 250*48671232SYonghong Song { 251*48671232SYonghong Song struct task_struct *task, *last_wakee; 252*48671232SYonghong Song 253*48671232SYonghong Song task = bpf_get_current_task_btf(); 254*48671232SYonghong Song bpf_rcu_read_lock(); 255*48671232SYonghong Song /* the pointer last_wakee marked as untrusted */ 256*48671232SYonghong Song last_wakee = task->real_parent->last_wakee; 257*48671232SYonghong Song (void)bpf_task_storage_get(&map_a, last_wakee, 0, 0); 258*48671232SYonghong Song bpf_rcu_read_unlock(); 259*48671232SYonghong Song return 0; 260*48671232SYonghong Song } 261*48671232SYonghong Song 262*48671232SYonghong Song SEC("?fentry.s/" SYS_PREFIX "sys_getpgid") 263*48671232SYonghong Song int task_untrusted_rcuptr(void *ctx) 264*48671232SYonghong Song { 265*48671232SYonghong Song struct task_struct *task, *real_parent; 266*48671232SYonghong Song 267*48671232SYonghong Song task = bpf_get_current_task_btf(); 268*48671232SYonghong Song bpf_rcu_read_lock(); 269*48671232SYonghong Song real_parent = task->real_parent; 270*48671232SYonghong Song bpf_rcu_read_unlock(); 271*48671232SYonghong Song /* helper use of rcu ptr outside the rcu read lock region */ 272*48671232SYonghong Song (void)bpf_task_storage_get(&map_a, real_parent, 0, 0); 273*48671232SYonghong Song return 0; 274*48671232SYonghong Song } 275*48671232SYonghong Song 276*48671232SYonghong Song SEC("?fentry.s/" SYS_PREFIX "sys_nanosleep") 277*48671232SYonghong Song int cross_rcu_region(void *ctx) 278*48671232SYonghong Song { 279*48671232SYonghong Song struct task_struct *task, *real_parent; 280*48671232SYonghong Song 281*48671232SYonghong Song /* rcu ptr define/use in different regions */ 282*48671232SYonghong Song task = bpf_get_current_task_btf(); 283*48671232SYonghong Song bpf_rcu_read_lock(); 284*48671232SYonghong Song real_parent = task->real_parent; 285*48671232SYonghong Song bpf_rcu_read_unlock(); 286*48671232SYonghong Song bpf_rcu_read_lock(); 287*48671232SYonghong Song (void)bpf_task_storage_get(&map_a, real_parent, 0, 0); 288*48671232SYonghong Song bpf_rcu_read_unlock(); 289*48671232SYonghong Song return 0; 290*48671232SYonghong Song } 291