1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ 3 4 #include <vmlinux.h> 5 #include <bpf/bpf_tracing.h> 6 #include <bpf/bpf_helpers.h> 7 #include "bpf_misc.h" 8 9 #include "cpumask_common.h" 10 11 char _license[] SEC("license") = "GPL"; 12 13 /* Prototype for all of the program trace events below: 14 * 15 * TRACE_EVENT(task_newtask, 16 * TP_PROTO(struct task_struct *p, u64 clone_flags) 17 */ 18 19 SEC("tp_btf/task_newtask") 20 __failure __msg("Unreleased reference") 21 int BPF_PROG(test_alloc_no_release, struct task_struct *task, u64 clone_flags) 22 { 23 struct bpf_cpumask *cpumask; 24 25 cpumask = create_cpumask(); 26 __sink(cpumask); 27 28 /* cpumask is never released. */ 29 return 0; 30 } 31 32 SEC("tp_btf/task_newtask") 33 __failure __msg("NULL pointer passed to trusted arg0") 34 int BPF_PROG(test_alloc_double_release, struct task_struct *task, u64 clone_flags) 35 { 36 struct bpf_cpumask *cpumask; 37 38 cpumask = create_cpumask(); 39 40 /* cpumask is released twice. */ 41 bpf_cpumask_release(cpumask); 42 bpf_cpumask_release(cpumask); 43 44 return 0; 45 } 46 47 SEC("tp_btf/task_newtask") 48 __failure __msg("must be referenced") 49 int BPF_PROG(test_acquire_wrong_cpumask, struct task_struct *task, u64 clone_flags) 50 { 51 struct bpf_cpumask *cpumask; 52 53 /* Can't acquire a non-struct bpf_cpumask. */ 54 cpumask = bpf_cpumask_acquire((struct bpf_cpumask *)task->cpus_ptr); 55 __sink(cpumask); 56 57 return 0; 58 } 59 60 SEC("tp_btf/task_newtask") 61 __failure __msg("bpf_cpumask_set_cpu args#1 expected pointer to STRUCT bpf_cpumask") 62 int BPF_PROG(test_mutate_cpumask, struct task_struct *task, u64 clone_flags) 63 { 64 /* Can't set the CPU of a non-struct bpf_cpumask. */ 65 bpf_cpumask_set_cpu(0, (struct bpf_cpumask *)task->cpus_ptr); 66 67 return 0; 68 } 69 70 SEC("tp_btf/task_newtask") 71 __failure __msg("Unreleased reference") 72 int BPF_PROG(test_insert_remove_no_release, struct task_struct *task, u64 clone_flags) 73 { 74 struct bpf_cpumask *cpumask; 75 struct __cpumask_map_value *v; 76 77 cpumask = create_cpumask(); 78 if (!cpumask) 79 return 0; 80 81 if (cpumask_map_insert(cpumask)) 82 return 0; 83 84 v = cpumask_map_value_lookup(); 85 if (!v) 86 return 0; 87 88 cpumask = bpf_kptr_xchg(&v->cpumask, NULL); 89 90 /* cpumask is never released. */ 91 return 0; 92 } 93 94 SEC("tp_btf/task_newtask") 95 __failure __msg("NULL pointer passed to trusted arg0") 96 int BPF_PROG(test_cpumask_null, struct task_struct *task, u64 clone_flags) 97 { 98 /* NULL passed to KF_TRUSTED_ARGS kfunc. */ 99 bpf_cpumask_empty(NULL); 100 101 return 0; 102 } 103 104 SEC("tp_btf/task_newtask") 105 __failure __msg("R2 must be a rcu pointer") 106 int BPF_PROG(test_global_mask_out_of_rcu, struct task_struct *task, u64 clone_flags) 107 { 108 struct bpf_cpumask *local, *prev; 109 110 local = create_cpumask(); 111 if (!local) 112 return 0; 113 114 prev = bpf_kptr_xchg(&global_mask, local); 115 if (prev) { 116 bpf_cpumask_release(prev); 117 err = 3; 118 return 0; 119 } 120 121 bpf_rcu_read_lock(); 122 local = global_mask; 123 if (!local) { 124 err = 4; 125 bpf_rcu_read_unlock(); 126 return 0; 127 } 128 129 bpf_rcu_read_unlock(); 130 131 /* RCU region is exited before calling KF_RCU kfunc. */ 132 133 bpf_cpumask_test_cpu(0, (const struct cpumask *)local); 134 135 return 0; 136 } 137 138 SEC("tp_btf/task_newtask") 139 __failure __msg("NULL pointer passed to trusted arg1") 140 int BPF_PROG(test_global_mask_no_null_check, struct task_struct *task, u64 clone_flags) 141 { 142 struct bpf_cpumask *local, *prev; 143 144 local = create_cpumask(); 145 if (!local) 146 return 0; 147 148 prev = bpf_kptr_xchg(&global_mask, local); 149 if (prev) { 150 bpf_cpumask_release(prev); 151 err = 3; 152 return 0; 153 } 154 155 bpf_rcu_read_lock(); 156 local = global_mask; 157 158 /* No NULL check is performed on global cpumask kptr. */ 159 bpf_cpumask_test_cpu(0, (const struct cpumask *)local); 160 161 bpf_rcu_read_unlock(); 162 163 return 0; 164 } 165 166 SEC("tp_btf/task_newtask") 167 __failure __msg("Possibly NULL pointer passed to helper arg2") 168 int BPF_PROG(test_global_mask_rcu_no_null_check, struct task_struct *task, u64 clone_flags) 169 { 170 struct bpf_cpumask *prev, *curr; 171 172 curr = bpf_cpumask_create(); 173 if (!curr) 174 return 0; 175 176 prev = bpf_kptr_xchg(&global_mask, curr); 177 if (prev) 178 bpf_cpumask_release(prev); 179 180 bpf_rcu_read_lock(); 181 curr = global_mask; 182 /* PTR_TO_BTF_ID | PTR_MAYBE_NULL | MEM_RCU passed to bpf_kptr_xchg() */ 183 prev = bpf_kptr_xchg(&global_mask, curr); 184 bpf_rcu_read_unlock(); 185 if (prev) 186 bpf_cpumask_release(prev); 187 188 return 0; 189 } 190