1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (C) 2023 Chuyi Zhou <zhouchuyi@bytedance.com> */ 3 4 #include "vmlinux.h" 5 #include <bpf/bpf_helpers.h> 6 #include <bpf/bpf_tracing.h> 7 #include "bpf_misc.h" 8 #include "bpf_experimental.h" 9 10 char _license[] SEC("license") = "GPL"; 11 12 struct cgroup *bpf_cgroup_from_id(u64 cgid) __ksym; 13 void bpf_cgroup_release(struct cgroup *p) __ksym; 14 void bpf_rcu_read_lock(void) __ksym; 15 void bpf_rcu_read_unlock(void) __ksym; 16 17 SEC("?fentry.s/" SYS_PREFIX "sys_getpgid") 18 __failure __msg("kernel func bpf_iter_task_new requires RCU critical section protection") 19 int BPF_PROG(iter_tasks_without_lock) 20 { 21 struct task_struct *pos; 22 23 bpf_for_each(task, pos, NULL, BPF_TASK_ITER_ALL_PROCS) { 24 25 } 26 return 0; 27 } 28 29 SEC("?fentry.s/" SYS_PREFIX "sys_getpgid") 30 __failure __msg("kernel func bpf_iter_css_new requires RCU critical section protection") 31 int BPF_PROG(iter_css_without_lock) 32 { 33 u64 cg_id = bpf_get_current_cgroup_id(); 34 struct cgroup *cgrp = bpf_cgroup_from_id(cg_id); 35 struct cgroup_subsys_state *root_css, *pos; 36 37 if (!cgrp) 38 return 0; 39 root_css = &cgrp->self; 40 41 bpf_for_each(css, pos, root_css, BPF_CGROUP_ITER_DESCENDANTS_POST) { 42 43 } 44 bpf_cgroup_release(cgrp); 45 return 0; 46 } 47 48 SEC("?fentry.s/" SYS_PREFIX "sys_getpgid") 49 __failure __msg("expected an RCU CS when using bpf_iter_task_next") 50 int BPF_PROG(iter_tasks_lock_and_unlock) 51 { 52 struct task_struct *pos; 53 54 bpf_rcu_read_lock(); 55 bpf_for_each(task, pos, NULL, BPF_TASK_ITER_ALL_PROCS) { 56 bpf_rcu_read_unlock(); 57 58 bpf_rcu_read_lock(); 59 } 60 bpf_rcu_read_unlock(); 61 return 0; 62 } 63 64 SEC("?fentry.s/" SYS_PREFIX "sys_getpgid") 65 __failure __msg("expected an RCU CS when using bpf_iter_task_next") 66 __flag(BPF_F_TEST_STATE_FREQ) 67 int BPF_PROG(iter_tasks_rcu_state_pruning) 68 { 69 struct bpf_iter_task it; 70 71 asm volatile ( 72 "call %[bpf_rcu_read_lock];" 73 "r1 = %[it];" 74 "r2 = 0;" 75 "r3 = 0;" /* BPF_TASK_ITER_ALL_PROCS */ 76 "call %[bpf_iter_task_new];" 77 78 "call %[bpf_get_prandom_u32];" 79 "if w0 == 0 goto unprotected_%=;" 80 81 /* Keep the outer RCU lock active on the straight-line path. */ 82 "call %[bpf_rcu_read_lock];" 83 "call %[bpf_rcu_read_unlock];" 84 "goto merge_%=;" 85 86 "unprotected_%=:" 87 /* Create an unprotected gap on the taken path. */ 88 "call %[bpf_rcu_read_unlock];" 89 "call %[bpf_rcu_read_lock];" 90 91 "merge_%=: r1 = %[it];" 92 "call %[bpf_iter_task_next];" 93 "r1 = %[it];" 94 "call %[bpf_iter_task_destroy];" 95 "call %[bpf_rcu_read_unlock];" 96 : 97 : __imm_ptr(it), 98 __imm(bpf_get_prandom_u32), 99 __imm(bpf_iter_task_new), 100 __imm(bpf_iter_task_next), 101 __imm(bpf_iter_task_destroy), 102 __imm(bpf_rcu_read_lock), 103 __imm(bpf_rcu_read_unlock) 104 : __clobber_common 105 ); 106 107 return 0; 108 } 109 110 SEC("?fentry.s/" SYS_PREFIX "sys_getpgid") 111 __failure __msg("expected an RCU CS when using bpf_iter_css_next") 112 int BPF_PROG(iter_css_lock_and_unlock) 113 { 114 u64 cg_id = bpf_get_current_cgroup_id(); 115 struct cgroup *cgrp = bpf_cgroup_from_id(cg_id); 116 struct cgroup_subsys_state *root_css, *pos; 117 118 if (!cgrp) 119 return 0; 120 root_css = &cgrp->self; 121 122 bpf_rcu_read_lock(); 123 bpf_for_each(css, pos, root_css, BPF_CGROUP_ITER_DESCENDANTS_POST) { 124 bpf_rcu_read_unlock(); 125 126 bpf_rcu_read_lock(); 127 } 128 bpf_rcu_read_unlock(); 129 bpf_cgroup_release(cgrp); 130 return 0; 131 } 132 133 SEC("?fentry/" SYS_PREFIX "sys_getpgid") 134 __failure __msg("css_task_iter is only allowed in bpf_lsm, bpf_iter and sleepable progs") 135 int BPF_PROG(iter_css_task_for_each) 136 { 137 u64 cg_id = bpf_get_current_cgroup_id(); 138 struct cgroup *cgrp = bpf_cgroup_from_id(cg_id); 139 struct cgroup_subsys_state *css; 140 struct task_struct *task; 141 142 if (cgrp == NULL) 143 return 0; 144 css = &cgrp->self; 145 146 bpf_for_each(css_task, task, css, CSS_TASK_ITER_PROCS) { 147 148 } 149 bpf_cgroup_release(cgrp); 150 return 0; 151 } 152