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 struct bpf_cpumask *cpumask; 65 66 /* Can't set the CPU of a non-struct bpf_cpumask. */ 67 bpf_cpumask_set_cpu(0, (struct bpf_cpumask *)task->cpus_ptr); 68 __sink(cpumask); 69 70 return 0; 71 } 72 73 SEC("tp_btf/task_newtask") 74 __failure __msg("Unreleased reference") 75 int BPF_PROG(test_insert_remove_no_release, struct task_struct *task, u64 clone_flags) 76 { 77 struct bpf_cpumask *cpumask; 78 struct __cpumask_map_value *v; 79 80 cpumask = create_cpumask(); 81 if (!cpumask) 82 return 0; 83 84 if (cpumask_map_insert(cpumask)) 85 return 0; 86 87 v = cpumask_map_value_lookup(); 88 if (!v) 89 return 0; 90 91 cpumask = bpf_kptr_xchg(&v->cpumask, NULL); 92 93 /* cpumask is never released. */ 94 return 0; 95 } 96 97 SEC("tp_btf/task_newtask") 98 __failure __msg("NULL pointer passed to trusted arg0") 99 int BPF_PROG(test_cpumask_null, struct task_struct *task, u64 clone_flags) 100 { 101 /* NULL passed to KF_TRUSTED_ARGS kfunc. */ 102 bpf_cpumask_empty(NULL); 103 104 return 0; 105 } 106 107 SEC("tp_btf/task_newtask") 108 __failure __msg("R2 must be a rcu pointer") 109 int BPF_PROG(test_global_mask_out_of_rcu, struct task_struct *task, u64 clone_flags) 110 { 111 struct bpf_cpumask *local, *prev; 112 113 local = create_cpumask(); 114 if (!local) 115 return 0; 116 117 prev = bpf_kptr_xchg(&global_mask, local); 118 if (prev) { 119 bpf_cpumask_release(prev); 120 err = 3; 121 return 0; 122 } 123 124 bpf_rcu_read_lock(); 125 local = global_mask; 126 if (!local) { 127 err = 4; 128 bpf_rcu_read_unlock(); 129 return 0; 130 } 131 132 bpf_rcu_read_unlock(); 133 134 /* RCU region is exited before calling KF_RCU kfunc. */ 135 136 bpf_cpumask_test_cpu(0, (const struct cpumask *)local); 137 138 return 0; 139 } 140 141 SEC("tp_btf/task_newtask") 142 __failure __msg("NULL pointer passed to trusted arg1") 143 int BPF_PROG(test_global_mask_no_null_check, struct task_struct *task, u64 clone_flags) 144 { 145 struct bpf_cpumask *local, *prev; 146 147 local = create_cpumask(); 148 if (!local) 149 return 0; 150 151 prev = bpf_kptr_xchg(&global_mask, local); 152 if (prev) { 153 bpf_cpumask_release(prev); 154 err = 3; 155 return 0; 156 } 157 158 bpf_rcu_read_lock(); 159 local = global_mask; 160 161 /* No NULL check is performed on global cpumask kptr. */ 162 bpf_cpumask_test_cpu(0, (const struct cpumask *)local); 163 164 bpf_rcu_read_unlock(); 165 166 return 0; 167 } 168 169 SEC("tp_btf/task_newtask") 170 __failure __msg("Possibly NULL pointer passed to helper arg2") 171 int BPF_PROG(test_global_mask_rcu_no_null_check, struct task_struct *task, u64 clone_flags) 172 { 173 struct bpf_cpumask *prev, *curr; 174 175 curr = bpf_cpumask_create(); 176 if (!curr) 177 return 0; 178 179 prev = bpf_kptr_xchg(&global_mask, curr); 180 if (prev) 181 bpf_cpumask_release(prev); 182 183 bpf_rcu_read_lock(); 184 curr = global_mask; 185 /* PTR_TO_BTF_ID | PTR_MAYBE_NULL | MEM_RCU passed to bpf_kptr_xchg() */ 186 prev = bpf_kptr_xchg(&global_mask, curr); 187 bpf_rcu_read_unlock(); 188 if (prev) 189 bpf_cpumask_release(prev); 190 191 return 0; 192 } 193