1fe147956SDavid Vernet // SPDX-License-Identifier: GPL-2.0 2fe147956SDavid Vernet /* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */ 3fe147956SDavid Vernet 4fe147956SDavid Vernet #include <vmlinux.h> 5fe147956SDavid Vernet #include <bpf/bpf_tracing.h> 6fe147956SDavid Vernet #include <bpf/bpf_helpers.h> 7fe147956SDavid Vernet 87525daeeSDavid Vernet #include "bpf_misc.h" 9fe147956SDavid Vernet #include "task_kfunc_common.h" 10fe147956SDavid Vernet 11fe147956SDavid Vernet char _license[] SEC("license") = "GPL"; 12fe147956SDavid Vernet 13fe147956SDavid Vernet /* Prototype for all of the program trace events below: 14fe147956SDavid Vernet * 15fe147956SDavid Vernet * TRACE_EVENT(task_newtask, 16fe147956SDavid Vernet * TP_PROTO(struct task_struct *p, u64 clone_flags) 17fe147956SDavid Vernet */ 18fe147956SDavid Vernet 19fe147956SDavid Vernet static struct __tasks_kfunc_map_value *insert_lookup_task(struct task_struct *task) 20fe147956SDavid Vernet { 21fe147956SDavid Vernet int status; 22fe147956SDavid Vernet 23fe147956SDavid Vernet status = tasks_kfunc_map_insert(task); 24fe147956SDavid Vernet if (status) 25fe147956SDavid Vernet return NULL; 26fe147956SDavid Vernet 27fe147956SDavid Vernet return tasks_kfunc_map_value_lookup(task); 28fe147956SDavid Vernet } 29fe147956SDavid Vernet 30fe147956SDavid Vernet SEC("tp_btf/task_newtask") 31caf713c3SDavid Vernet __failure __msg("Possibly NULL pointer passed to trusted arg0") 32fe147956SDavid Vernet int BPF_PROG(task_kfunc_acquire_untrusted, struct task_struct *task, u64 clone_flags) 33fe147956SDavid Vernet { 34fe147956SDavid Vernet struct task_struct *acquired; 35fe147956SDavid Vernet struct __tasks_kfunc_map_value *v; 36fe147956SDavid Vernet 37fe147956SDavid Vernet v = insert_lookup_task(task); 38fe147956SDavid Vernet if (!v) 39fe147956SDavid Vernet return 0; 40fe147956SDavid Vernet 41fe147956SDavid Vernet /* Can't invoke bpf_task_acquire() on an untrusted pointer. */ 42fe147956SDavid Vernet acquired = bpf_task_acquire(v->task); 43d02c48faSDavid Vernet if (!acquired) 44d02c48faSDavid Vernet return 0; 45d02c48faSDavid Vernet 46fe147956SDavid Vernet bpf_task_release(acquired); 47fe147956SDavid Vernet 48fe147956SDavid Vernet return 0; 49fe147956SDavid Vernet } 50fe147956SDavid Vernet 51fe147956SDavid Vernet SEC("tp_btf/task_newtask") 527525daeeSDavid Vernet __failure __msg("arg#0 pointer type STRUCT task_struct must point") 53fe147956SDavid Vernet int BPF_PROG(task_kfunc_acquire_fp, struct task_struct *task, u64 clone_flags) 54fe147956SDavid Vernet { 55fe147956SDavid Vernet struct task_struct *acquired, *stack_task = (struct task_struct *)&clone_flags; 56fe147956SDavid Vernet 57fe147956SDavid Vernet /* Can't invoke bpf_task_acquire() on a random frame pointer. */ 58fe147956SDavid Vernet acquired = bpf_task_acquire((struct task_struct *)&stack_task); 59d02c48faSDavid Vernet if (!acquired) 60d02c48faSDavid Vernet return 0; 61d02c48faSDavid Vernet 62fe147956SDavid Vernet bpf_task_release(acquired); 63fe147956SDavid Vernet 64fe147956SDavid Vernet return 0; 65fe147956SDavid Vernet } 66fe147956SDavid Vernet 67fe147956SDavid Vernet SEC("kretprobe/free_task") 68d02c48faSDavid Vernet __failure __msg("calling kernel function bpf_task_acquire is not allowed") 69fe147956SDavid Vernet int BPF_PROG(task_kfunc_acquire_unsafe_kretprobe, struct task_struct *task, u64 clone_flags) 70fe147956SDavid Vernet { 71fe147956SDavid Vernet struct task_struct *acquired; 72fe147956SDavid Vernet 73d02c48faSDavid Vernet /* Can't call bpf_task_acquire() or bpf_task_release() in an untrusted prog. */ 74fe147956SDavid Vernet acquired = bpf_task_acquire(task); 75d02c48faSDavid Vernet if (!acquired) 76d02c48faSDavid Vernet return 0; 77fe147956SDavid Vernet bpf_task_release(acquired); 78fe147956SDavid Vernet 79fe147956SDavid Vernet return 0; 80fe147956SDavid Vernet } 81fe147956SDavid Vernet 82d02c48faSDavid Vernet SEC("kretprobe/free_task") 83d02c48faSDavid Vernet __failure __msg("calling kernel function bpf_task_acquire is not allowed") 84d02c48faSDavid Vernet int BPF_PROG(task_kfunc_acquire_unsafe_kretprobe_rcu, struct task_struct *task, u64 clone_flags) 85fe147956SDavid Vernet { 86fe147956SDavid Vernet struct task_struct *acquired; 87fe147956SDavid Vernet 88d02c48faSDavid Vernet bpf_rcu_read_lock(); 89d02c48faSDavid Vernet if (!task) { 90d02c48faSDavid Vernet bpf_rcu_read_unlock(); 91d02c48faSDavid Vernet return 0; 92d02c48faSDavid Vernet } 93d02c48faSDavid Vernet /* Can't call bpf_task_acquire() or bpf_task_release() in an untrusted prog. */ 94d02c48faSDavid Vernet acquired = bpf_task_acquire(task); 95d02c48faSDavid Vernet if (acquired) 96fe147956SDavid Vernet bpf_task_release(acquired); 97d02c48faSDavid Vernet bpf_rcu_read_unlock(); 98fe147956SDavid Vernet 99fe147956SDavid Vernet return 0; 100fe147956SDavid Vernet } 101fe147956SDavid Vernet 102fe147956SDavid Vernet SEC("tp_btf/task_newtask") 103caf713c3SDavid Vernet __failure __msg("Possibly NULL pointer passed to trusted arg0") 104fe147956SDavid Vernet int BPF_PROG(task_kfunc_acquire_null, struct task_struct *task, u64 clone_flags) 105fe147956SDavid Vernet { 106fe147956SDavid Vernet struct task_struct *acquired; 107fe147956SDavid Vernet 108fe147956SDavid Vernet /* Can't invoke bpf_task_acquire() on a NULL pointer. */ 109fe147956SDavid Vernet acquired = bpf_task_acquire(NULL); 110fe147956SDavid Vernet if (!acquired) 111fe147956SDavid Vernet return 0; 112fe147956SDavid Vernet bpf_task_release(acquired); 113fe147956SDavid Vernet 114fe147956SDavid Vernet return 0; 115fe147956SDavid Vernet } 116fe147956SDavid Vernet 117fe147956SDavid Vernet SEC("tp_btf/task_newtask") 1187525daeeSDavid Vernet __failure __msg("Unreleased reference") 119fe147956SDavid Vernet int BPF_PROG(task_kfunc_acquire_unreleased, struct task_struct *task, u64 clone_flags) 120fe147956SDavid Vernet { 121fe147956SDavid Vernet struct task_struct *acquired; 122fe147956SDavid Vernet 123fe147956SDavid Vernet acquired = bpf_task_acquire(task); 124fe147956SDavid Vernet 125fe147956SDavid Vernet /* Acquired task is never released. */ 126c8ed6685SAndrii Nakryiko __sink(acquired); 127fe147956SDavid Vernet 128fe147956SDavid Vernet return 0; 129fe147956SDavid Vernet } 130fe147956SDavid Vernet 131fe147956SDavid Vernet SEC("tp_btf/task_newtask") 1327525daeeSDavid Vernet __failure __msg("Unreleased reference") 133fe147956SDavid Vernet int BPF_PROG(task_kfunc_xchg_unreleased, struct task_struct *task, u64 clone_flags) 134fe147956SDavid Vernet { 135fe147956SDavid Vernet struct task_struct *kptr; 136fe147956SDavid Vernet struct __tasks_kfunc_map_value *v; 137fe147956SDavid Vernet 138fe147956SDavid Vernet v = insert_lookup_task(task); 139fe147956SDavid Vernet if (!v) 140fe147956SDavid Vernet return 0; 141fe147956SDavid Vernet 142fe147956SDavid Vernet kptr = bpf_kptr_xchg(&v->task, NULL); 143fe147956SDavid Vernet if (!kptr) 144fe147956SDavid Vernet return 0; 145fe147956SDavid Vernet 146fe147956SDavid Vernet /* Kptr retrieved from map is never released. */ 147fe147956SDavid Vernet 148fe147956SDavid Vernet return 0; 149fe147956SDavid Vernet } 150fe147956SDavid Vernet 151fe147956SDavid Vernet SEC("tp_btf/task_newtask") 152d02c48faSDavid Vernet __failure __msg("Possibly NULL pointer passed to trusted arg0") 153d02c48faSDavid Vernet int BPF_PROG(task_kfunc_acquire_release_no_null_check, struct task_struct *task, u64 clone_flags) 154d02c48faSDavid Vernet { 155d02c48faSDavid Vernet struct task_struct *acquired; 156d02c48faSDavid Vernet 157d02c48faSDavid Vernet acquired = bpf_task_acquire(task); 158d02c48faSDavid Vernet /* Can't invoke bpf_task_release() on an acquired task without a NULL check. */ 159d02c48faSDavid Vernet bpf_task_release(acquired); 160d02c48faSDavid Vernet 161d02c48faSDavid Vernet return 0; 162d02c48faSDavid Vernet } 163d02c48faSDavid Vernet 164d02c48faSDavid Vernet SEC("tp_btf/task_newtask") 1656c831c46SDavid Vernet __failure __msg("Possibly NULL pointer passed to trusted arg0") 166fe147956SDavid Vernet int BPF_PROG(task_kfunc_release_untrusted, struct task_struct *task, u64 clone_flags) 167fe147956SDavid Vernet { 168fe147956SDavid Vernet struct __tasks_kfunc_map_value *v; 169fe147956SDavid Vernet 170fe147956SDavid Vernet v = insert_lookup_task(task); 171fe147956SDavid Vernet if (!v) 172fe147956SDavid Vernet return 0; 173fe147956SDavid Vernet 174fe147956SDavid Vernet /* Can't invoke bpf_task_release() on an untrusted pointer. */ 175fe147956SDavid Vernet bpf_task_release(v->task); 176fe147956SDavid Vernet 177fe147956SDavid Vernet return 0; 178fe147956SDavid Vernet } 179fe147956SDavid Vernet 180fe147956SDavid Vernet SEC("tp_btf/task_newtask") 1817525daeeSDavid Vernet __failure __msg("arg#0 pointer type STRUCT task_struct must point") 182fe147956SDavid Vernet int BPF_PROG(task_kfunc_release_fp, struct task_struct *task, u64 clone_flags) 183fe147956SDavid Vernet { 184fe147956SDavid Vernet struct task_struct *acquired = (struct task_struct *)&clone_flags; 185fe147956SDavid Vernet 186fe147956SDavid Vernet /* Cannot release random frame pointer. */ 187fe147956SDavid Vernet bpf_task_release(acquired); 188fe147956SDavid Vernet 189fe147956SDavid Vernet return 0; 190fe147956SDavid Vernet } 191fe147956SDavid Vernet 192fe147956SDavid Vernet SEC("tp_btf/task_newtask") 1936c831c46SDavid Vernet __failure __msg("Possibly NULL pointer passed to trusted arg0") 194fe147956SDavid Vernet int BPF_PROG(task_kfunc_release_null, struct task_struct *task, u64 clone_flags) 195fe147956SDavid Vernet { 196fe147956SDavid Vernet struct __tasks_kfunc_map_value local, *v; 197fe147956SDavid Vernet long status; 198fe147956SDavid Vernet struct task_struct *acquired, *old; 199fe147956SDavid Vernet s32 pid; 200fe147956SDavid Vernet 201fe147956SDavid Vernet status = bpf_probe_read_kernel(&pid, sizeof(pid), &task->pid); 202fe147956SDavid Vernet if (status) 203fe147956SDavid Vernet return 0; 204fe147956SDavid Vernet 205fe147956SDavid Vernet local.task = NULL; 206fe147956SDavid Vernet status = bpf_map_update_elem(&__tasks_kfunc_map, &pid, &local, BPF_NOEXIST); 207fe147956SDavid Vernet if (status) 208fe147956SDavid Vernet return status; 209fe147956SDavid Vernet 210fe147956SDavid Vernet v = bpf_map_lookup_elem(&__tasks_kfunc_map, &pid); 211fe147956SDavid Vernet if (!v) 212fe147956SDavid Vernet return -ENOENT; 213fe147956SDavid Vernet 214fe147956SDavid Vernet acquired = bpf_task_acquire(task); 215d02c48faSDavid Vernet if (!acquired) 216d02c48faSDavid Vernet return -EEXIST; 217fe147956SDavid Vernet 218fe147956SDavid Vernet old = bpf_kptr_xchg(&v->task, acquired); 219fe147956SDavid Vernet 220fe147956SDavid Vernet /* old cannot be passed to bpf_task_release() without a NULL check. */ 221fe147956SDavid Vernet bpf_task_release(old); 222fe147956SDavid Vernet 223fe147956SDavid Vernet return 0; 224fe147956SDavid Vernet } 225fe147956SDavid Vernet 226fe147956SDavid Vernet SEC("tp_btf/task_newtask") 2277525daeeSDavid Vernet __failure __msg("release kernel function bpf_task_release expects") 228fe147956SDavid Vernet int BPF_PROG(task_kfunc_release_unacquired, struct task_struct *task, u64 clone_flags) 229fe147956SDavid Vernet { 230fe147956SDavid Vernet /* Cannot release trusted task pointer which was not acquired. */ 231fe147956SDavid Vernet bpf_task_release(task); 232fe147956SDavid Vernet 233fe147956SDavid Vernet return 0; 234fe147956SDavid Vernet } 235f471748bSDavid Vernet 236f471748bSDavid Vernet SEC("tp_btf/task_newtask") 2376c831c46SDavid Vernet __failure __msg("Possibly NULL pointer passed to trusted arg0") 238f471748bSDavid Vernet int BPF_PROG(task_kfunc_from_pid_no_null_check, struct task_struct *task, u64 clone_flags) 239f471748bSDavid Vernet { 240f471748bSDavid Vernet struct task_struct *acquired; 241f471748bSDavid Vernet 242f471748bSDavid Vernet acquired = bpf_task_from_pid(task->pid); 243f471748bSDavid Vernet 244f471748bSDavid Vernet /* Releasing bpf_task_from_pid() lookup without a NULL check. */ 245f471748bSDavid Vernet bpf_task_release(acquired); 246f471748bSDavid Vernet 247f471748bSDavid Vernet return 0; 248f471748bSDavid Vernet } 249c0c852ddSYonghong Song 250c0c852ddSYonghong Song SEC("lsm/task_free") 251*5eccd2dbSAndrii Nakryiko __failure __msg("R1 must be a rcu pointer") 252c0c852ddSYonghong Song int BPF_PROG(task_kfunc_from_lsm_task_free, struct task_struct *task) 253c0c852ddSYonghong Song { 254c0c852ddSYonghong Song struct task_struct *acquired; 255c0c852ddSYonghong Song 256c0c852ddSYonghong Song /* the argument of lsm task_free hook is untrusted. */ 257c0c852ddSYonghong Song acquired = bpf_task_acquire(task); 258d02c48faSDavid Vernet if (!acquired) 259d02c48faSDavid Vernet return 0; 260d02c48faSDavid Vernet 261c0c852ddSYonghong Song bpf_task_release(acquired); 262c0c852ddSYonghong Song return 0; 263c0c852ddSYonghong Song } 264f25fd608SAlexei Starovoitov 265f25fd608SAlexei Starovoitov SEC("tp_btf/task_newtask") 266f25fd608SAlexei Starovoitov __failure __msg("access beyond the end of member comm") 267f25fd608SAlexei Starovoitov int BPF_PROG(task_access_comm1, struct task_struct *task, u64 clone_flags) 268f25fd608SAlexei Starovoitov { 269f25fd608SAlexei Starovoitov bpf_strncmp(task->comm, 17, "foo"); 270f25fd608SAlexei Starovoitov return 0; 271f25fd608SAlexei Starovoitov } 272f25fd608SAlexei Starovoitov 273f25fd608SAlexei Starovoitov SEC("tp_btf/task_newtask") 274f25fd608SAlexei Starovoitov __failure __msg("access beyond the end of member comm") 275f25fd608SAlexei Starovoitov int BPF_PROG(task_access_comm2, struct task_struct *task, u64 clone_flags) 276f25fd608SAlexei Starovoitov { 277f25fd608SAlexei Starovoitov bpf_strncmp(task->comm + 1, 16, "foo"); 278f25fd608SAlexei Starovoitov return 0; 279f25fd608SAlexei Starovoitov } 280f25fd608SAlexei Starovoitov 281f25fd608SAlexei Starovoitov SEC("tp_btf/task_newtask") 282f25fd608SAlexei Starovoitov __failure __msg("write into memory") 283f25fd608SAlexei Starovoitov int BPF_PROG(task_access_comm3, struct task_struct *task, u64 clone_flags) 284f25fd608SAlexei Starovoitov { 285f25fd608SAlexei Starovoitov bpf_probe_read_kernel(task->comm, 16, task->comm); 286f25fd608SAlexei Starovoitov return 0; 287f25fd608SAlexei Starovoitov } 288f25fd608SAlexei Starovoitov 289f25fd608SAlexei Starovoitov SEC("fentry/__set_task_comm") 290f25fd608SAlexei Starovoitov __failure __msg("R1 type=ptr_ expected") 291f25fd608SAlexei Starovoitov int BPF_PROG(task_access_comm4, struct task_struct *task, const char *buf, bool exec) 292f25fd608SAlexei Starovoitov { 293f25fd608SAlexei Starovoitov /* 294f25fd608SAlexei Starovoitov * task->comm is a legacy ptr_to_btf_id. The verifier cannot guarantee 295f25fd608SAlexei Starovoitov * its safety. Hence it cannot be accessed with normal load insns. 296f25fd608SAlexei Starovoitov */ 297f25fd608SAlexei Starovoitov bpf_strncmp(task->comm, 16, "foo"); 298f25fd608SAlexei Starovoitov return 0; 299f25fd608SAlexei Starovoitov } 300d02c48faSDavid Vernet 301d02c48faSDavid Vernet SEC("tp_btf/task_newtask") 302d02c48faSDavid Vernet __failure __msg("R1 must be referenced or trusted") 303d02c48faSDavid Vernet int BPF_PROG(task_kfunc_release_in_map, struct task_struct *task, u64 clone_flags) 304d02c48faSDavid Vernet { 305d02c48faSDavid Vernet struct task_struct *local; 306d02c48faSDavid Vernet struct __tasks_kfunc_map_value *v; 307d02c48faSDavid Vernet 308d02c48faSDavid Vernet if (tasks_kfunc_map_insert(task)) 309d02c48faSDavid Vernet return 0; 310d02c48faSDavid Vernet 311d02c48faSDavid Vernet v = tasks_kfunc_map_value_lookup(task); 312d02c48faSDavid Vernet if (!v) 313d02c48faSDavid Vernet return 0; 314d02c48faSDavid Vernet 315d02c48faSDavid Vernet bpf_rcu_read_lock(); 316d02c48faSDavid Vernet local = v->task; 317d02c48faSDavid Vernet if (!local) { 318d02c48faSDavid Vernet bpf_rcu_read_unlock(); 319d02c48faSDavid Vernet return 0; 320d02c48faSDavid Vernet } 321d02c48faSDavid Vernet /* Can't release a kptr that's still stored in a map. */ 322d02c48faSDavid Vernet bpf_task_release(local); 323d02c48faSDavid Vernet bpf_rcu_read_unlock(); 324d02c48faSDavid Vernet 325d02c48faSDavid Vernet return 0; 326d02c48faSDavid Vernet } 327