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 11char _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 19SEC("tp_btf/task_newtask") 20__failure __msg("Unreleased reference") 21int 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 32SEC("tp_btf/task_newtask") 33__failure __msg("NULL pointer passed to trusted arg0") 34int 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 47SEC("tp_btf/task_newtask") 48__failure __msg("must be referenced") 49int 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 60SEC("tp_btf/task_newtask") 61__failure __msg("bpf_cpumask_set_cpu args#1 expected pointer to STRUCT bpf_cpumask") 62int 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 70SEC("tp_btf/task_newtask") 71__failure __msg("Unreleased reference") 72int 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 94SEC("tp_btf/task_newtask") 95__failure __msg("NULL pointer passed to trusted arg0") 96int 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 104SEC("tp_btf/task_newtask") 105__failure __msg("R2 must be a rcu pointer") 106int 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 138SEC("tp_btf/task_newtask") 139__failure __msg("NULL pointer passed to trusted arg1") 140int 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 166SEC("tp_btf/task_newtask") 167__failure __msg("Possibly NULL pointer passed to helper arg2") 168int 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