// SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */ #include #include #include #include "../test_kmods/bpf_testmod.h" #include "../test_kmods/bpf_testmod_kfunc.h" char _license[] SEC("license") = "GPL"; /* an untrusted pointer to the argument struct, never set, for the verifier */ struct untrusted_val { struct bpf_testmod_nullable_args __kptr_untrusted *args; }; struct { __uint(type, BPF_MAP_TYPE_ARRAY); __uint(max_entries, 1); __type(key, int); __type(value, struct untrusted_val); } untrusted_map SEC(".maps"); SEC("struct_ops/test_nullable") int BPF_PROG(test_nullable_cb, struct bpf_testmod_nullable_args *args) { struct bpf_testmod_nullable_args *u; struct untrusted_val *v; struct task_struct *t; int ret = 0, *i, zero = 0; /* trusted, so good for a kfunc as is */ t = bpf_task_acquire(args->task); if (!t) return -1; bpf_task_release(t); /* trusted but __nullable, so a check has to come first */ if (args->task_or_null) { t = bpf_task_acquire(args->task_or_null); if (!t) return -1; bpf_task_release(t); ret = 1; } /* per-CPU and __nullable: a check has to come first, per_cpu_ptr() has none */ if (args->pcpu_or_null) { struct bpf_testmod_pcpu *v = bpf_this_cpu_ptr(args->pcpu_or_null); if (v->val != 0x5ca1ab1e) return -1; } /* through a plain pointer the loads are probed, __nullable still asks for a check */ t = args->self->task_or_null; if (t && t->pid != args->task->pid) return -1; /* a pointer to a scalar walks as untrusted memory, __nullable applies all the same */ i = args->int_or_null; if (i && *i != 7) return -1; /* through an untrusted pointer the member is probed too, and stays nullable */ v = bpf_map_lookup_elem(&untrusted_map, &zero); u = v ? v->args : NULL; if (u) { t = u->task_or_null; if (t && t->pid != args->task->pid) return -1; } return ret; } SEC(".struct_ops.link") struct bpf_testmod_ops3 testmod_nullable = { .test_nullable = (void *)test_nullable_cb, }; SEC("syscall") int trigger(void *ctx) { /* one call without task_or_null, one with */ return bpf_testmod_ops3_call_test_nullable() != 2; }