1268896Sbapt// SPDX-License-Identifier: GPL-2.0 2268896Sbapt/* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */ 3268896Sbapt 4268896Sbapt#include "vmlinux.h" 5268896Sbapt#include <bpf/bpf_helpers.h> 6268896Sbapt#include <bpf/bpf_tracing.h> 7268896Sbapt#include "bpf_tracing_net.h" 8268896Sbapt#include "bpf_misc.h" 9268896Sbapt 10268896Sbaptchar _license[] SEC("license") = "GPL"; 11268896Sbapt 12268896Sbaptstruct { 13268896Sbapt __uint(type, BPF_MAP_TYPE_TASK_STORAGE); 14268896Sbapt __uint(map_flags, BPF_F_NO_PREALLOC); 15268896Sbapt __type(key, int); 16268896Sbapt __type(value, long); 17268896Sbapt} map_a SEC(".maps"); 18268896Sbapt 19268896Sbapt__u32 user_data, key_serial, target_pid; 20268896Sbapt__u64 flags, task_storage_val, cgroup_id; 21268896Sbapt 22268896Sbaptstruct bpf_key *bpf_lookup_user_key(__u32 serial, __u64 flags) __ksym; 23268896Sbaptvoid bpf_key_put(struct bpf_key *key) __ksym; 24268896Sbaptvoid bpf_rcu_read_lock(void) __ksym; 25268896Sbaptvoid bpf_rcu_read_unlock(void) __ksym; 26268896Sbaptstruct task_struct *bpf_task_acquire(struct task_struct *p) __ksym; 27268896Sbaptvoid bpf_task_release(struct task_struct *p) __ksym; 28268896Sbapt 29268896SbaptSEC("?fentry.s/" SYS_PREFIX "sys_getpgid") 30268896Sbaptint get_cgroup_id(void *ctx) 31268896Sbapt{ 32268896Sbapt struct task_struct *task; 33268896Sbapt struct css_set *cgroups; 34268896Sbapt 35268896Sbapt task = bpf_get_current_task_btf(); 36268896Sbapt if (task->pid != target_pid) 37268896Sbapt return 0; 38268896Sbapt 39268896Sbapt /* simulate bpf_get_current_cgroup_id() helper */ 40268896Sbapt bpf_rcu_read_lock(); 41268896Sbapt cgroups = task->cgroups; 42268896Sbapt if (!cgroups) 43268896Sbapt goto unlock; 44268896Sbapt cgroup_id = cgroups->dfl_cgrp->kn->id; 45268896Sbaptunlock: 46268896Sbapt bpf_rcu_read_unlock(); 47268896Sbapt return 0; 48268896Sbapt} 49268896Sbapt 50268896SbaptSEC("?fentry.s/" SYS_PREFIX "sys_getpgid") 51268896Sbaptint task_succ(void *ctx) 52268896Sbapt{ 53268896Sbapt struct task_struct *task, *real_parent; 54268896Sbapt long init_val = 2; 55268896Sbapt long *ptr; 56268896Sbapt 57268896Sbapt task = bpf_get_current_task_btf(); 58268896Sbapt if (task->pid != target_pid) 59268896Sbapt return 0; 60268896Sbapt 61268896Sbapt bpf_rcu_read_lock(); 62268896Sbapt /* region including helper using rcu ptr real_parent */ 63268896Sbapt real_parent = task->real_parent; 64268896Sbapt if (!real_parent) 65268896Sbapt goto out; 66268896Sbapt ptr = bpf_task_storage_get(&map_a, real_parent, &init_val, 67268896Sbapt BPF_LOCAL_STORAGE_GET_F_CREATE); 68268896Sbapt if (!ptr) 69268896Sbapt goto out; 70268896Sbapt ptr = bpf_task_storage_get(&map_a, real_parent, 0, 0); 71268896Sbapt if (!ptr) 72268896Sbapt goto out; 73268896Sbapt task_storage_val = *ptr; 74268896Sbaptout: 75268896Sbapt bpf_rcu_read_unlock(); 76268896Sbapt return 0; 77268896Sbapt} 78268896Sbapt 79268896SbaptSEC("?fentry.s/" SYS_PREFIX "sys_nanosleep") 80268896Sbaptint no_lock(void *ctx) 81268896Sbapt{ 82268896Sbapt struct task_struct *task, *real_parent; 83268896Sbapt 84268896Sbapt /* old style ptr_to_btf_id is not allowed in sleepable */ 85268896Sbapt task = bpf_get_current_task_btf(); 86268896Sbapt real_parent = task->real_parent; 87268896Sbapt (void)bpf_task_storage_get(&map_a, real_parent, 0, 0); 88268896Sbapt return 0; 89268896Sbapt} 90268896Sbapt 91268896SbaptSEC("?fentry.s/" SYS_PREFIX "sys_nanosleep") 92268896Sbaptint two_regions(void *ctx) 93268896Sbapt{ 94268896Sbapt struct task_struct *task, *real_parent; 95268896Sbapt 96268896Sbapt /* two regions */ 97268896Sbapt task = bpf_get_current_task_btf(); 98268896Sbapt bpf_rcu_read_lock(); 99268896Sbapt bpf_rcu_read_unlock(); 100268896Sbapt bpf_rcu_read_lock(); 101268896Sbapt real_parent = task->real_parent; 102268896Sbapt if (!real_parent) 103268896Sbapt goto out; 104268896Sbapt (void)bpf_task_storage_get(&map_a, real_parent, 0, 0); 105268896Sbaptout: 106268896Sbapt bpf_rcu_read_unlock(); 107268896Sbapt return 0; 108268896Sbapt} 109268896Sbapt 110268896SbaptSEC("?fentry/" SYS_PREFIX "sys_getpgid") 111268896Sbaptint non_sleepable_1(void *ctx) 112268896Sbapt{ 113268896Sbapt struct task_struct *task, *real_parent; 114268896Sbapt 115268896Sbapt task = bpf_get_current_task_btf(); 116268896Sbapt bpf_rcu_read_lock(); 117268896Sbapt real_parent = task->real_parent; 118268896Sbapt if (!real_parent) 119268896Sbapt goto out; 120268896Sbapt (void)bpf_task_storage_get(&map_a, real_parent, 0, 0); 121268896Sbaptout: 122268896Sbapt bpf_rcu_read_unlock(); 123268896Sbapt return 0; 124268896Sbapt} 125268896Sbapt 126268896SbaptSEC("?fentry/" SYS_PREFIX "sys_getpgid") 127268896Sbaptint non_sleepable_2(void *ctx) 128268896Sbapt{ 129268896Sbapt struct task_struct *task, *real_parent; 130268896Sbapt 131268896Sbapt bpf_rcu_read_lock(); 132268896Sbapt task = bpf_get_current_task_btf(); 133268896Sbapt bpf_rcu_read_unlock(); 134268896Sbapt 135268896Sbapt bpf_rcu_read_lock(); 136268896Sbapt real_parent = task->real_parent; 137268896Sbapt if (!real_parent) 138268896Sbapt goto out; 139268896Sbapt (void)bpf_task_storage_get(&map_a, real_parent, 0, 0); 140268896Sbaptout: 141268896Sbapt bpf_rcu_read_unlock(); 142268896Sbapt return 0; 143268896Sbapt} 144268896Sbapt 145268896SbaptSEC("?fentry.s/" SYS_PREFIX "sys_nanosleep") 146268896Sbaptint task_acquire(void *ctx) 147268896Sbapt{ 148268896Sbapt struct task_struct *task, *real_parent, *gparent; 149268896Sbapt 150268896Sbapt task = bpf_get_current_task_btf(); 151268896Sbapt bpf_rcu_read_lock(); 152268896Sbapt real_parent = task->real_parent; 153268896Sbapt if (!real_parent) 154268896Sbapt goto out; 155268896Sbapt 156268896Sbapt /* rcu_ptr->rcu_field */ 157268896Sbapt gparent = real_parent->real_parent; 158268896Sbapt if (!gparent) 159268896Sbapt goto out; 160268896Sbapt 161268896Sbapt /* acquire a reference which can be used outside rcu read lock region */ 162268896Sbapt gparent = bpf_task_acquire(gparent); 163268896Sbapt if (!gparent) 164268896Sbapt goto out; 165268896Sbapt 166268896Sbapt (void)bpf_task_storage_get(&map_a, gparent, 0, 0); 167268896Sbapt bpf_task_release(gparent); 168268896Sbaptout: 169268896Sbapt bpf_rcu_read_unlock(); 170268896Sbapt return 0; 171268896Sbapt} 172268896Sbapt 173268896SbaptSEC("?fentry.s/" SYS_PREFIX "sys_getpgid") 174268896Sbaptint miss_lock(void *ctx) 175268896Sbapt{ 176268896Sbapt struct task_struct *task; 177268896Sbapt 178268896Sbapt /* missing bpf_rcu_read_lock() */ 179268896Sbapt task = bpf_get_current_task_btf(); 180268896Sbapt bpf_rcu_read_lock(); 181268896Sbapt (void)bpf_task_storage_get(&map_a, task, 0, 0); 182268896Sbapt bpf_rcu_read_unlock(); 183268896Sbapt bpf_rcu_read_unlock(); 184268896Sbapt return 0; 185268896Sbapt} 186268896Sbapt 187268896SbaptSEC("?fentry.s/" SYS_PREFIX "sys_getpgid") 188268896Sbaptint miss_unlock(void *ctx) 189268896Sbapt{ 190268896Sbapt struct task_struct *task; 191268896Sbapt 192268896Sbapt /* missing bpf_rcu_read_unlock() */ 193268896Sbapt task = bpf_get_current_task_btf(); 194268896Sbapt bpf_rcu_read_lock(); 195268896Sbapt (void)bpf_task_storage_get(&map_a, task, 0, 0); 196268896Sbapt return 0; 197268896Sbapt} 198268896Sbapt 199268896SbaptSEC("?fentry/" SYS_PREFIX "sys_getpgid") 200268896Sbaptint non_sleepable_rcu_mismatch(void *ctx) 201268896Sbapt{ 202268896Sbapt struct task_struct *task, *real_parent; 203268896Sbapt 204268896Sbapt task = bpf_get_current_task_btf(); 205268896Sbapt /* non-sleepable: missing bpf_rcu_read_unlock() in one path */ 206268896Sbapt bpf_rcu_read_lock(); 207268896Sbapt real_parent = task->real_parent; 208268896Sbapt if (!real_parent) 209268896Sbapt goto out; 210268896Sbapt (void)bpf_task_storage_get(&map_a, real_parent, 0, 0); 211268896Sbapt if (real_parent) 212268896Sbapt bpf_rcu_read_unlock(); 213268896Sbaptout: 214268896Sbapt return 0; 215268896Sbapt} 216268896Sbapt 217268896SbaptSEC("?fentry.s/" SYS_PREFIX "sys_getpgid") 218268896Sbaptint inproper_sleepable_helper(void *ctx) 219268896Sbapt{ 220268896Sbapt struct task_struct *task, *real_parent; 221268896Sbapt struct pt_regs *regs; 222268896Sbapt __u32 value = 0; 223268896Sbapt void *ptr; 224268896Sbapt 225268896Sbapt task = bpf_get_current_task_btf(); 226268896Sbapt /* sleepable helper in rcu read lock region */ 227268896Sbapt bpf_rcu_read_lock(); 228268896Sbapt real_parent = task->real_parent; 229268896Sbapt if (!real_parent) 230268896Sbapt goto out; 231268896Sbapt regs = (struct pt_regs *)bpf_task_pt_regs(real_parent); 232268896Sbapt if (!regs) 233268896Sbapt goto out; 234268896Sbapt 235268896Sbapt ptr = (void *)PT_REGS_IP(regs); 236268896Sbapt (void)bpf_copy_from_user_task(&value, sizeof(uint32_t), ptr, task, 0); 237268896Sbapt user_data = value; 238268896Sbapt (void)bpf_task_storage_get(&map_a, real_parent, 0, 0); 239268896Sbaptout: 240268896Sbapt bpf_rcu_read_unlock(); 241268896Sbapt return 0; 242268896Sbapt} 243268896Sbapt 244268896SbaptSEC("?lsm.s/bpf") 245268896Sbaptint BPF_PROG(inproper_sleepable_kfunc, int cmd, union bpf_attr *attr, unsigned int size) 246268896Sbapt{ 247268896Sbapt struct bpf_key *bkey; 248268896Sbapt 249268896Sbapt /* sleepable kfunc in rcu read lock region */ 250268896Sbapt bpf_rcu_read_lock(); 251268896Sbapt bkey = bpf_lookup_user_key(key_serial, flags); 252268896Sbapt bpf_rcu_read_unlock(); 253268896Sbapt if (!bkey) 254268896Sbapt return -1; 255268896Sbapt bpf_key_put(bkey); 256268896Sbapt 257268896Sbapt return 0; 258268896Sbapt} 259268896Sbapt 260268896SbaptSEC("?fentry.s/" SYS_PREFIX "sys_nanosleep") 261268896Sbaptint nested_rcu_region(void *ctx) 262268896Sbapt{ 263268896Sbapt struct task_struct *task, *real_parent; 264268896Sbapt 265268896Sbapt /* nested rcu read lock regions */ 266268896Sbapt task = bpf_get_current_task_btf(); 267268896Sbapt bpf_rcu_read_lock(); 268268896Sbapt bpf_rcu_read_lock(); 269268896Sbapt real_parent = task->real_parent; 270268896Sbapt if (!real_parent) 271268896Sbapt goto out; 272268896Sbapt (void)bpf_task_storage_get(&map_a, real_parent, 0, 0); 273268896Sbaptout: 274268896Sbapt bpf_rcu_read_unlock(); 275268896Sbapt bpf_rcu_read_unlock(); 276268896Sbapt return 0; 277268896Sbapt} 278268896Sbapt 279268896SbaptSEC("?fentry.s/" SYS_PREFIX "sys_getpgid") 280268896Sbaptint task_trusted_non_rcuptr(void *ctx) 281268896Sbapt{ 282268896Sbapt struct task_struct *task, *group_leader; 283268896Sbapt 284268896Sbapt task = bpf_get_current_task_btf(); 285268896Sbapt bpf_rcu_read_lock(); 286268896Sbapt /* the pointer group_leader is explicitly marked as trusted */ 287268896Sbapt group_leader = task->real_parent->group_leader; 288268896Sbapt (void)bpf_task_storage_get(&map_a, group_leader, 0, 0); 289268896Sbapt bpf_rcu_read_unlock(); 290268896Sbapt return 0; 291268896Sbapt} 292268896Sbapt 293268896SbaptSEC("?fentry.s/" SYS_PREFIX "sys_getpgid") 294268896Sbaptint task_untrusted_rcuptr(void *ctx) 295268896Sbapt{ 296268896Sbapt struct task_struct *task, *real_parent; 297268896Sbapt 298268896Sbapt task = bpf_get_current_task_btf(); 299268896Sbapt bpf_rcu_read_lock(); 300268896Sbapt real_parent = task->real_parent; 301268896Sbapt bpf_rcu_read_unlock(); 302268896Sbapt /* helper use of rcu ptr outside the rcu read lock region */ 303268896Sbapt (void)bpf_task_storage_get(&map_a, real_parent, 0, 0); 304268896Sbapt return 0; 305268896Sbapt} 306268896Sbapt 307268896SbaptSEC("?fentry.s/" SYS_PREFIX "sys_nanosleep") 308268896Sbaptint cross_rcu_region(void *ctx) 309268896Sbapt{ 310268896Sbapt struct task_struct *task, *real_parent; 311268896Sbapt 312268896Sbapt /* rcu ptr define/use in different regions */ 313268896Sbapt task = bpf_get_current_task_btf(); 314268896Sbapt bpf_rcu_read_lock(); 315268896Sbapt real_parent = task->real_parent; 316268896Sbapt bpf_rcu_read_unlock(); 317268896Sbapt bpf_rcu_read_lock(); 318268896Sbapt (void)bpf_task_storage_get(&map_a, real_parent, 0, 0); 319268896Sbapt bpf_rcu_read_unlock(); 320268896Sbapt return 0; 321268896Sbapt} 322268896Sbapt 323268896Sbapt__noinline 324268896Sbaptstatic int static_subprog(void *ctx) 325268896Sbapt{ 326268896Sbapt volatile int ret = 0; 327268896Sbapt 328268896Sbapt if (bpf_get_prandom_u32()) 329268896Sbapt return ret + 42; 330268896Sbapt return ret + bpf_get_prandom_u32(); 331268896Sbapt} 332268896Sbapt 333268896Sbapt__noinline 334268896Sbaptint global_subprog(u64 a) 335268896Sbapt{ 336268896Sbapt volatile int ret = a; 337268896Sbapt 338268896Sbapt return ret + static_subprog(NULL); 339268896Sbapt} 340268896Sbapt 341268896Sbapt__noinline 342268896Sbaptstatic int static_subprog_lock(void *ctx) 343268896Sbapt{ 344268896Sbapt volatile int ret = 0; 345268896Sbapt 346268896Sbapt bpf_rcu_read_lock(); 347268896Sbapt if (bpf_get_prandom_u32()) 348268896Sbapt return ret + 42; 349268896Sbapt return ret + bpf_get_prandom_u32(); 350268896Sbapt} 351268896Sbapt 352268896Sbapt__noinline 353268896Sbaptint global_subprog_lock(u64 a) 354268896Sbapt{ 355268896Sbapt volatile int ret = a; 356268896Sbapt 357268896Sbapt return ret + static_subprog_lock(NULL); 358268896Sbapt} 359268896Sbapt 360268896Sbapt__noinline 361268896Sbaptstatic int static_subprog_unlock(void *ctx) 362268896Sbapt{ 363268896Sbapt volatile int ret = 0; 364268896Sbapt 365268896Sbapt bpf_rcu_read_unlock(); 366268896Sbapt if (bpf_get_prandom_u32()) 367268896Sbapt return ret + 42; 368268896Sbapt return ret + bpf_get_prandom_u32(); 369268896Sbapt} 370268896Sbapt 371268896Sbapt__noinline 372268896Sbaptint global_subprog_unlock(u64 a) 373268896Sbapt{ 374268896Sbapt volatile int ret = a; 375268896Sbapt 376268896Sbapt return ret + static_subprog_unlock(NULL); 377268896Sbapt} 378268896Sbapt 379268896SbaptSEC("?fentry.s/" SYS_PREFIX "sys_getpgid") 380268896Sbaptint rcu_read_lock_subprog(void *ctx) 381268896Sbapt{ 382268896Sbapt volatile int ret = 0; 383268896Sbapt 384268896Sbapt bpf_rcu_read_lock(); 385268896Sbapt if (bpf_get_prandom_u32()) 386268896Sbapt ret += static_subprog(ctx); 387268896Sbapt bpf_rcu_read_unlock(); 388268896Sbapt return 0; 389268896Sbapt} 390268896Sbapt 391268896SbaptSEC("?fentry.s/" SYS_PREFIX "sys_getpgid") 392268896Sbaptint rcu_read_lock_global_subprog(void *ctx) 393268896Sbapt{ 394268896Sbapt volatile int ret = 0; 395268896Sbapt 396268896Sbapt bpf_rcu_read_lock(); 397268896Sbapt if (bpf_get_prandom_u32()) 398268896Sbapt ret += global_subprog(ret); 399268896Sbapt bpf_rcu_read_unlock(); 400268896Sbapt return 0; 401268896Sbapt} 402268896Sbapt 403268896SbaptSEC("?fentry.s/" SYS_PREFIX "sys_getpgid") 404268896Sbaptint rcu_read_lock_subprog_lock(void *ctx) 405268896Sbapt{ 406268896Sbapt volatile int ret = 0; 407268896Sbapt 408268896Sbapt ret += static_subprog_lock(ctx); 409268896Sbapt bpf_rcu_read_unlock(); 410268896Sbapt return 0; 411268896Sbapt} 412268896Sbapt 413268896SbaptSEC("?fentry.s/" SYS_PREFIX "sys_getpgid") 414268896Sbaptint rcu_read_lock_global_subprog_lock(void *ctx) 415268896Sbapt{ 416268896Sbapt volatile int ret = 0; 417268896Sbapt 418268896Sbapt ret += global_subprog_lock(ret); 419268896Sbapt bpf_rcu_read_unlock(); 420268896Sbapt return 0; 421268896Sbapt} 422268896Sbapt 423268896SbaptSEC("?fentry.s/" SYS_PREFIX "sys_getpgid") 424268896Sbaptint rcu_read_lock_subprog_unlock(void *ctx) 425268896Sbapt{ 426268896Sbapt volatile int ret = 0; 427268896Sbapt 428268896Sbapt bpf_rcu_read_lock(); 429268896Sbapt ret += static_subprog_unlock(ctx); 430268896Sbapt return 0; 431268896Sbapt} 432268896Sbapt 433268896SbaptSEC("?fentry.s/" SYS_PREFIX "sys_getpgid") 434268896Sbaptint rcu_read_lock_global_subprog_unlock(void *ctx) 435268896Sbapt{ 436268896Sbapt volatile int ret = 0; 437268896Sbapt 438268896Sbapt bpf_rcu_read_lock(); 439268896Sbapt ret += global_subprog_unlock(ret); 440268896Sbapt return 0; 441268896Sbapt} 442268896Sbapt