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 struct kptr_nested_array_2 { 14 struct bpf_cpumask __kptr * mask; 15 }; 16 17 struct kptr_nested_array_1 { 18 /* Make btf_parse_fields() in map_create() return -E2BIG */ 19 struct kptr_nested_array_2 d_2[CPUMASK_KPTR_FIELDS_MAX + 1]; 20 }; 21 22 struct kptr_nested_array { 23 struct kptr_nested_array_1 d_1; 24 }; 25 26 private(MASK_NESTED) static struct kptr_nested_array global_mask_nested_arr; 27 28 /* Prototype for all of the program trace events below: 29 * 30 * TRACE_EVENT(task_newtask, 31 * TP_PROTO(struct task_struct *p, u64 clone_flags) 32 */ 33 34 SEC("tp_btf/task_newtask") 35 __failure __msg("Unreleased reference") 36 int BPF_PROG(test_alloc_no_release, struct task_struct *task, u64 clone_flags) 37 { 38 struct bpf_cpumask *cpumask; 39 40 cpumask = create_cpumask(); 41 __sink(cpumask); 42 43 /* cpumask is never released. */ 44 return 0; 45 } 46 47 SEC("tp_btf/task_newtask") 48 __failure __msg("NULL pointer passed to trusted arg0") 49 int BPF_PROG(test_alloc_double_release, struct task_struct *task, u64 clone_flags) 50 { 51 struct bpf_cpumask *cpumask; 52 53 cpumask = create_cpumask(); 54 55 /* cpumask is released twice. */ 56 bpf_cpumask_release(cpumask); 57 bpf_cpumask_release(cpumask); 58 59 return 0; 60 } 61 62 SEC("tp_btf/task_newtask") 63 __failure __msg("must be referenced") 64 int BPF_PROG(test_acquire_wrong_cpumask, struct task_struct *task, u64 clone_flags) 65 { 66 struct bpf_cpumask *cpumask; 67 68 /* Can't acquire a non-struct bpf_cpumask. */ 69 cpumask = bpf_cpumask_acquire((struct bpf_cpumask *)task->cpus_ptr); 70 __sink(cpumask); 71 72 return 0; 73 } 74 75 SEC("tp_btf/task_newtask") 76 __failure __msg("bpf_cpumask_set_cpu args#1 expected pointer to STRUCT bpf_cpumask") 77 int BPF_PROG(test_mutate_cpumask, struct task_struct *task, u64 clone_flags) 78 { 79 /* Can't set the CPU of a non-struct bpf_cpumask. */ 80 bpf_cpumask_set_cpu(0, (struct bpf_cpumask *)task->cpus_ptr); 81 82 return 0; 83 } 84 85 SEC("tp_btf/task_newtask") 86 __failure __msg("Unreleased reference") 87 int BPF_PROG(test_insert_remove_no_release, struct task_struct *task, u64 clone_flags) 88 { 89 struct bpf_cpumask *cpumask; 90 struct __cpumask_map_value *v; 91 92 cpumask = create_cpumask(); 93 if (!cpumask) 94 return 0; 95 96 if (cpumask_map_insert(cpumask)) 97 return 0; 98 99 v = cpumask_map_value_lookup(); 100 if (!v) 101 return 0; 102 103 cpumask = bpf_kptr_xchg(&v->cpumask, NULL); 104 105 /* cpumask is never released. */ 106 return 0; 107 } 108 109 SEC("tp_btf/task_newtask") 110 __failure __msg("NULL pointer passed to trusted arg0") 111 int BPF_PROG(test_cpumask_null, struct task_struct *task, u64 clone_flags) 112 { 113 /* NULL passed to KF_TRUSTED_ARGS kfunc. */ 114 bpf_cpumask_empty(NULL); 115 116 return 0; 117 } 118 119 SEC("tp_btf/task_newtask") 120 __failure __msg("R2 must be a rcu pointer") 121 int BPF_PROG(test_global_mask_out_of_rcu, struct task_struct *task, u64 clone_flags) 122 { 123 struct bpf_cpumask *local, *prev; 124 125 local = create_cpumask(); 126 if (!local) 127 return 0; 128 129 prev = bpf_kptr_xchg(&global_mask, local); 130 if (prev) { 131 bpf_cpumask_release(prev); 132 err = 3; 133 return 0; 134 } 135 136 bpf_rcu_read_lock(); 137 local = global_mask; 138 if (!local) { 139 err = 4; 140 bpf_rcu_read_unlock(); 141 return 0; 142 } 143 144 bpf_rcu_read_unlock(); 145 146 /* RCU region is exited before calling KF_RCU kfunc. */ 147 148 bpf_cpumask_test_cpu(0, (const struct cpumask *)local); 149 150 return 0; 151 } 152 153 SEC("tp_btf/task_newtask") 154 __failure __msg("NULL pointer passed to trusted arg1") 155 int BPF_PROG(test_global_mask_no_null_check, struct task_struct *task, u64 clone_flags) 156 { 157 struct bpf_cpumask *local, *prev; 158 159 local = create_cpumask(); 160 if (!local) 161 return 0; 162 163 prev = bpf_kptr_xchg(&global_mask, local); 164 if (prev) { 165 bpf_cpumask_release(prev); 166 err = 3; 167 return 0; 168 } 169 170 bpf_rcu_read_lock(); 171 local = global_mask; 172 173 /* No NULL check is performed on global cpumask kptr. */ 174 bpf_cpumask_test_cpu(0, (const struct cpumask *)local); 175 176 bpf_rcu_read_unlock(); 177 178 return 0; 179 } 180 181 SEC("tp_btf/task_newtask") 182 __failure __msg("Possibly NULL pointer passed to helper arg2") 183 int BPF_PROG(test_global_mask_rcu_no_null_check, struct task_struct *task, u64 clone_flags) 184 { 185 struct bpf_cpumask *prev, *curr; 186 187 curr = bpf_cpumask_create(); 188 if (!curr) 189 return 0; 190 191 prev = bpf_kptr_xchg(&global_mask, curr); 192 if (prev) 193 bpf_cpumask_release(prev); 194 195 bpf_rcu_read_lock(); 196 curr = global_mask; 197 /* PTR_TO_BTF_ID | PTR_MAYBE_NULL | MEM_RCU passed to bpf_kptr_xchg() */ 198 prev = bpf_kptr_xchg(&global_mask, curr); 199 bpf_rcu_read_unlock(); 200 if (prev) 201 bpf_cpumask_release(prev); 202 203 return 0; 204 } 205 206 SEC("tp_btf/task_newtask") 207 __failure __msg("has no valid kptr") 208 int BPF_PROG(test_invalid_nested_array, struct task_struct *task, u64 clone_flags) 209 { 210 struct bpf_cpumask *local, *prev; 211 212 local = create_cpumask(); 213 if (!local) 214 return 0; 215 216 prev = bpf_kptr_xchg(&global_mask_nested_arr.d_1.d_2[CPUMASK_KPTR_FIELDS_MAX].mask, local); 217 if (prev) { 218 bpf_cpumask_release(prev); 219 err = 3; 220 return 0; 221 } 222 223 return 0; 224 } 225