225 lines · c
1// SPDX-License-Identifier: GPL-2.02/* 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 13struct kptr_nested_array_2 {14 struct bpf_cpumask __kptr * mask;15};16 17struct 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 22struct kptr_nested_array {23 struct kptr_nested_array_1 d_1;24};25 26private(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 34SEC("tp_btf/task_newtask")35__failure __msg("Unreleased reference")36int 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 47SEC("tp_btf/task_newtask")48__failure __msg("NULL pointer passed to trusted arg0")49int 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 62SEC("tp_btf/task_newtask")63__failure __msg("must be referenced")64int 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 75SEC("tp_btf/task_newtask")76__failure __msg("bpf_cpumask_set_cpu args#1 expected pointer to STRUCT bpf_cpumask")77int 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 85SEC("tp_btf/task_newtask")86__failure __msg("Unreleased reference")87int 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 109SEC("tp_btf/task_newtask")110__failure __msg("NULL pointer passed to trusted arg0")111int 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 119SEC("tp_btf/task_newtask")120__failure __msg("R2 must be a rcu pointer")121int 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 153SEC("tp_btf/task_newtask")154__failure __msg("NULL pointer passed to trusted arg1")155int 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 181SEC("tp_btf/task_newtask")182__failure __msg("Possibly NULL pointer passed to helper arg2")183int 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 206SEC("tp_btf/task_newtask")207__failure __msg("has no valid kptr")208int 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