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); 43*d02c48faSDavid Vernet if (!acquired) 44*d02c48faSDavid Vernet return 0; 45*d02c48faSDavid 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); 59*d02c48faSDavid Vernet if (!acquired) 60*d02c48faSDavid Vernet return 0; 61*d02c48faSDavid Vernet 62fe147956SDavid Vernet bpf_task_release(acquired); 63fe147956SDavid Vernet 64fe147956SDavid Vernet return 0; 65fe147956SDavid Vernet } 66fe147956SDavid Vernet 67fe147956SDavid Vernet SEC("kretprobe/free_task") 68*d02c48faSDavid 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 73*d02c48faSDavid Vernet /* Can't call bpf_task_acquire() or bpf_task_release() in an untrusted prog. */ 74fe147956SDavid Vernet acquired = bpf_task_acquire(task); 75*d02c48faSDavid Vernet if (!acquired) 76*d02c48faSDavid Vernet return 0; 77fe147956SDavid Vernet bpf_task_release(acquired); 78fe147956SDavid Vernet 79fe147956SDavid Vernet return 0; 80fe147956SDavid Vernet } 81fe147956SDavid Vernet 82*d02c48faSDavid Vernet SEC("kretprobe/free_task") 83*d02c48faSDavid Vernet __failure __msg("calling kernel function bpf_task_acquire is not allowed") 84*d02c48faSDavid 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 88*d02c48faSDavid Vernet bpf_rcu_read_lock(); 89*d02c48faSDavid Vernet if (!task) { 90*d02c48faSDavid Vernet bpf_rcu_read_unlock(); 91*d02c48faSDavid Vernet return 0; 92*d02c48faSDavid Vernet } 93*d02c48faSDavid Vernet /* Can't call bpf_task_acquire() or bpf_task_release() in an untrusted prog. */ 94*d02c48faSDavid Vernet acquired = bpf_task_acquire(task); 95*d02c48faSDavid Vernet if (acquired) 96fe147956SDavid Vernet bpf_task_release(acquired); 97*d02c48faSDavid 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("arg#0 expected pointer to map value") 133fe147956SDavid Vernet int BPF_PROG(task_kfunc_get_non_kptr_param, struct task_struct *task, u64 clone_flags) 134fe147956SDavid Vernet { 135fe147956SDavid Vernet struct task_struct *kptr; 136fe147956SDavid Vernet 137fe147956SDavid Vernet /* Cannot use bpf_task_kptr_get() on a non-kptr, even on a valid task. */ 138fe147956SDavid Vernet kptr = bpf_task_kptr_get(&task); 139fe147956SDavid Vernet if (!kptr) 140fe147956SDavid Vernet return 0; 141fe147956SDavid Vernet 142fe147956SDavid Vernet bpf_task_release(kptr); 143fe147956SDavid Vernet 144fe147956SDavid Vernet return 0; 145fe147956SDavid Vernet } 146fe147956SDavid Vernet 147fe147956SDavid Vernet SEC("tp_btf/task_newtask") 1487525daeeSDavid Vernet __failure __msg("arg#0 expected pointer to map value") 149fe147956SDavid Vernet int BPF_PROG(task_kfunc_get_non_kptr_acquired, struct task_struct *task, u64 clone_flags) 150fe147956SDavid Vernet { 151fe147956SDavid Vernet struct task_struct *kptr, *acquired; 152fe147956SDavid Vernet 153fe147956SDavid Vernet acquired = bpf_task_acquire(task); 154*d02c48faSDavid Vernet if (!acquired) 155*d02c48faSDavid Vernet return 0; 156fe147956SDavid Vernet 157fe147956SDavid Vernet /* Cannot use bpf_task_kptr_get() on a non-kptr, even if it was acquired. */ 158fe147956SDavid Vernet kptr = bpf_task_kptr_get(&acquired); 159fe147956SDavid Vernet bpf_task_release(acquired); 160fe147956SDavid Vernet if (!kptr) 161fe147956SDavid Vernet return 0; 162fe147956SDavid Vernet 163fe147956SDavid Vernet bpf_task_release(kptr); 164fe147956SDavid Vernet 165fe147956SDavid Vernet return 0; 166fe147956SDavid Vernet } 167fe147956SDavid Vernet 168fe147956SDavid Vernet SEC("tp_btf/task_newtask") 1697525daeeSDavid Vernet __failure __msg("arg#0 expected pointer to map value") 170fe147956SDavid Vernet int BPF_PROG(task_kfunc_get_null, struct task_struct *task, u64 clone_flags) 171fe147956SDavid Vernet { 172fe147956SDavid Vernet struct task_struct *kptr; 173fe147956SDavid Vernet 174fe147956SDavid Vernet /* Cannot use bpf_task_kptr_get() on a NULL pointer. */ 175fe147956SDavid Vernet kptr = bpf_task_kptr_get(NULL); 176fe147956SDavid Vernet if (!kptr) 177fe147956SDavid Vernet return 0; 178fe147956SDavid Vernet 179fe147956SDavid Vernet bpf_task_release(kptr); 180fe147956SDavid Vernet 181fe147956SDavid Vernet return 0; 182fe147956SDavid Vernet } 183fe147956SDavid Vernet 184fe147956SDavid Vernet SEC("tp_btf/task_newtask") 1857525daeeSDavid Vernet __failure __msg("Unreleased reference") 186fe147956SDavid Vernet int BPF_PROG(task_kfunc_xchg_unreleased, struct task_struct *task, u64 clone_flags) 187fe147956SDavid Vernet { 188fe147956SDavid Vernet struct task_struct *kptr; 189fe147956SDavid Vernet struct __tasks_kfunc_map_value *v; 190fe147956SDavid Vernet 191fe147956SDavid Vernet v = insert_lookup_task(task); 192fe147956SDavid Vernet if (!v) 193fe147956SDavid Vernet return 0; 194fe147956SDavid Vernet 195fe147956SDavid Vernet kptr = bpf_kptr_xchg(&v->task, NULL); 196fe147956SDavid Vernet if (!kptr) 197fe147956SDavid Vernet return 0; 198fe147956SDavid Vernet 199fe147956SDavid Vernet /* Kptr retrieved from map is never released. */ 200fe147956SDavid Vernet 201fe147956SDavid Vernet return 0; 202fe147956SDavid Vernet } 203fe147956SDavid Vernet 204fe147956SDavid Vernet SEC("tp_btf/task_newtask") 205*d02c48faSDavid Vernet __failure __msg("Possibly NULL pointer passed to trusted arg0") 206*d02c48faSDavid Vernet int BPF_PROG(task_kfunc_acquire_release_no_null_check, struct task_struct *task, u64 clone_flags) 207*d02c48faSDavid Vernet { 208*d02c48faSDavid Vernet struct task_struct *acquired; 209*d02c48faSDavid Vernet 210*d02c48faSDavid Vernet acquired = bpf_task_acquire(task); 211*d02c48faSDavid Vernet /* Can't invoke bpf_task_release() on an acquired task without a NULL check. */ 212*d02c48faSDavid Vernet bpf_task_release(acquired); 213*d02c48faSDavid Vernet 214*d02c48faSDavid Vernet return 0; 215*d02c48faSDavid Vernet } 216*d02c48faSDavid Vernet 217*d02c48faSDavid Vernet SEC("tp_btf/task_newtask") 2187525daeeSDavid Vernet __failure __msg("Unreleased reference") 219fe147956SDavid Vernet int BPF_PROG(task_kfunc_get_unreleased, struct task_struct *task, u64 clone_flags) 220fe147956SDavid Vernet { 221fe147956SDavid Vernet struct task_struct *kptr; 222fe147956SDavid Vernet struct __tasks_kfunc_map_value *v; 223fe147956SDavid Vernet 224fe147956SDavid Vernet v = insert_lookup_task(task); 225fe147956SDavid Vernet if (!v) 226fe147956SDavid Vernet return 0; 227fe147956SDavid Vernet 228fe147956SDavid Vernet kptr = bpf_task_kptr_get(&v->task); 229fe147956SDavid Vernet if (!kptr) 230fe147956SDavid Vernet return 0; 231fe147956SDavid Vernet 232fe147956SDavid Vernet /* Kptr acquired above is never released. */ 233fe147956SDavid Vernet 234fe147956SDavid Vernet return 0; 235fe147956SDavid Vernet } 236fe147956SDavid Vernet 237fe147956SDavid Vernet SEC("tp_btf/task_newtask") 2386c831c46SDavid Vernet __failure __msg("Possibly NULL pointer passed to trusted arg0") 239fe147956SDavid Vernet int BPF_PROG(task_kfunc_release_untrusted, struct task_struct *task, u64 clone_flags) 240fe147956SDavid Vernet { 241fe147956SDavid Vernet struct __tasks_kfunc_map_value *v; 242fe147956SDavid Vernet 243fe147956SDavid Vernet v = insert_lookup_task(task); 244fe147956SDavid Vernet if (!v) 245fe147956SDavid Vernet return 0; 246fe147956SDavid Vernet 247fe147956SDavid Vernet /* Can't invoke bpf_task_release() on an untrusted pointer. */ 248fe147956SDavid Vernet bpf_task_release(v->task); 249fe147956SDavid Vernet 250fe147956SDavid Vernet return 0; 251fe147956SDavid Vernet } 252fe147956SDavid Vernet 253fe147956SDavid Vernet SEC("tp_btf/task_newtask") 2547525daeeSDavid Vernet __failure __msg("arg#0 pointer type STRUCT task_struct must point") 255fe147956SDavid Vernet int BPF_PROG(task_kfunc_release_fp, struct task_struct *task, u64 clone_flags) 256fe147956SDavid Vernet { 257fe147956SDavid Vernet struct task_struct *acquired = (struct task_struct *)&clone_flags; 258fe147956SDavid Vernet 259fe147956SDavid Vernet /* Cannot release random frame pointer. */ 260fe147956SDavid Vernet bpf_task_release(acquired); 261fe147956SDavid Vernet 262fe147956SDavid Vernet return 0; 263fe147956SDavid Vernet } 264fe147956SDavid Vernet 265fe147956SDavid Vernet SEC("tp_btf/task_newtask") 2666c831c46SDavid Vernet __failure __msg("Possibly NULL pointer passed to trusted arg0") 267fe147956SDavid Vernet int BPF_PROG(task_kfunc_release_null, struct task_struct *task, u64 clone_flags) 268fe147956SDavid Vernet { 269fe147956SDavid Vernet struct __tasks_kfunc_map_value local, *v; 270fe147956SDavid Vernet long status; 271fe147956SDavid Vernet struct task_struct *acquired, *old; 272fe147956SDavid Vernet s32 pid; 273fe147956SDavid Vernet 274fe147956SDavid Vernet status = bpf_probe_read_kernel(&pid, sizeof(pid), &task->pid); 275fe147956SDavid Vernet if (status) 276fe147956SDavid Vernet return 0; 277fe147956SDavid Vernet 278fe147956SDavid Vernet local.task = NULL; 279fe147956SDavid Vernet status = bpf_map_update_elem(&__tasks_kfunc_map, &pid, &local, BPF_NOEXIST); 280fe147956SDavid Vernet if (status) 281fe147956SDavid Vernet return status; 282fe147956SDavid Vernet 283fe147956SDavid Vernet v = bpf_map_lookup_elem(&__tasks_kfunc_map, &pid); 284fe147956SDavid Vernet if (!v) 285fe147956SDavid Vernet return -ENOENT; 286fe147956SDavid Vernet 287fe147956SDavid Vernet acquired = bpf_task_acquire(task); 288*d02c48faSDavid Vernet if (!acquired) 289*d02c48faSDavid Vernet return -EEXIST; 290fe147956SDavid Vernet 291fe147956SDavid Vernet old = bpf_kptr_xchg(&v->task, acquired); 292fe147956SDavid Vernet 293fe147956SDavid Vernet /* old cannot be passed to bpf_task_release() without a NULL check. */ 294fe147956SDavid Vernet bpf_task_release(old); 295fe147956SDavid Vernet 296fe147956SDavid Vernet return 0; 297fe147956SDavid Vernet } 298fe147956SDavid Vernet 299fe147956SDavid Vernet SEC("tp_btf/task_newtask") 3007525daeeSDavid Vernet __failure __msg("release kernel function bpf_task_release expects") 301fe147956SDavid Vernet int BPF_PROG(task_kfunc_release_unacquired, struct task_struct *task, u64 clone_flags) 302fe147956SDavid Vernet { 303fe147956SDavid Vernet /* Cannot release trusted task pointer which was not acquired. */ 304fe147956SDavid Vernet bpf_task_release(task); 305fe147956SDavid Vernet 306fe147956SDavid Vernet return 0; 307fe147956SDavid Vernet } 308f471748bSDavid Vernet 309f471748bSDavid Vernet SEC("tp_btf/task_newtask") 3106c831c46SDavid Vernet __failure __msg("Possibly NULL pointer passed to trusted arg0") 311f471748bSDavid Vernet int BPF_PROG(task_kfunc_from_pid_no_null_check, struct task_struct *task, u64 clone_flags) 312f471748bSDavid Vernet { 313f471748bSDavid Vernet struct task_struct *acquired; 314f471748bSDavid Vernet 315f471748bSDavid Vernet acquired = bpf_task_from_pid(task->pid); 316f471748bSDavid Vernet 317f471748bSDavid Vernet /* Releasing bpf_task_from_pid() lookup without a NULL check. */ 318f471748bSDavid Vernet bpf_task_release(acquired); 319f471748bSDavid Vernet 320f471748bSDavid Vernet return 0; 321f471748bSDavid Vernet } 322c0c852ddSYonghong Song 323c0c852ddSYonghong Song SEC("lsm/task_free") 3247525daeeSDavid Vernet __failure __msg("reg type unsupported for arg#0 function") 325c0c852ddSYonghong Song int BPF_PROG(task_kfunc_from_lsm_task_free, struct task_struct *task) 326c0c852ddSYonghong Song { 327c0c852ddSYonghong Song struct task_struct *acquired; 328c0c852ddSYonghong Song 329c0c852ddSYonghong Song /* the argument of lsm task_free hook is untrusted. */ 330c0c852ddSYonghong Song acquired = bpf_task_acquire(task); 331*d02c48faSDavid Vernet if (!acquired) 332*d02c48faSDavid Vernet return 0; 333*d02c48faSDavid Vernet 334c0c852ddSYonghong Song bpf_task_release(acquired); 335c0c852ddSYonghong Song return 0; 336c0c852ddSYonghong Song } 337f25fd608SAlexei Starovoitov 338f25fd608SAlexei Starovoitov SEC("tp_btf/task_newtask") 339f25fd608SAlexei Starovoitov __failure __msg("access beyond the end of member comm") 340f25fd608SAlexei Starovoitov int BPF_PROG(task_access_comm1, struct task_struct *task, u64 clone_flags) 341f25fd608SAlexei Starovoitov { 342f25fd608SAlexei Starovoitov bpf_strncmp(task->comm, 17, "foo"); 343f25fd608SAlexei Starovoitov return 0; 344f25fd608SAlexei Starovoitov } 345f25fd608SAlexei Starovoitov 346f25fd608SAlexei Starovoitov SEC("tp_btf/task_newtask") 347f25fd608SAlexei Starovoitov __failure __msg("access beyond the end of member comm") 348f25fd608SAlexei Starovoitov int BPF_PROG(task_access_comm2, struct task_struct *task, u64 clone_flags) 349f25fd608SAlexei Starovoitov { 350f25fd608SAlexei Starovoitov bpf_strncmp(task->comm + 1, 16, "foo"); 351f25fd608SAlexei Starovoitov return 0; 352f25fd608SAlexei Starovoitov } 353f25fd608SAlexei Starovoitov 354f25fd608SAlexei Starovoitov SEC("tp_btf/task_newtask") 355f25fd608SAlexei Starovoitov __failure __msg("write into memory") 356f25fd608SAlexei Starovoitov int BPF_PROG(task_access_comm3, struct task_struct *task, u64 clone_flags) 357f25fd608SAlexei Starovoitov { 358f25fd608SAlexei Starovoitov bpf_probe_read_kernel(task->comm, 16, task->comm); 359f25fd608SAlexei Starovoitov return 0; 360f25fd608SAlexei Starovoitov } 361f25fd608SAlexei Starovoitov 362f25fd608SAlexei Starovoitov SEC("fentry/__set_task_comm") 363f25fd608SAlexei Starovoitov __failure __msg("R1 type=ptr_ expected") 364f25fd608SAlexei Starovoitov int BPF_PROG(task_access_comm4, struct task_struct *task, const char *buf, bool exec) 365f25fd608SAlexei Starovoitov { 366f25fd608SAlexei Starovoitov /* 367f25fd608SAlexei Starovoitov * task->comm is a legacy ptr_to_btf_id. The verifier cannot guarantee 368f25fd608SAlexei Starovoitov * its safety. Hence it cannot be accessed with normal load insns. 369f25fd608SAlexei Starovoitov */ 370f25fd608SAlexei Starovoitov bpf_strncmp(task->comm, 16, "foo"); 371f25fd608SAlexei Starovoitov return 0; 372f25fd608SAlexei Starovoitov } 373*d02c48faSDavid Vernet 374*d02c48faSDavid Vernet SEC("tp_btf/task_newtask") 375*d02c48faSDavid Vernet __failure __msg("R1 must be referenced or trusted") 376*d02c48faSDavid Vernet int BPF_PROG(task_kfunc_release_in_map, struct task_struct *task, u64 clone_flags) 377*d02c48faSDavid Vernet { 378*d02c48faSDavid Vernet struct task_struct *local; 379*d02c48faSDavid Vernet struct __tasks_kfunc_map_value *v; 380*d02c48faSDavid Vernet 381*d02c48faSDavid Vernet if (tasks_kfunc_map_insert(task)) 382*d02c48faSDavid Vernet return 0; 383*d02c48faSDavid Vernet 384*d02c48faSDavid Vernet v = tasks_kfunc_map_value_lookup(task); 385*d02c48faSDavid Vernet if (!v) 386*d02c48faSDavid Vernet return 0; 387*d02c48faSDavid Vernet 388*d02c48faSDavid Vernet bpf_rcu_read_lock(); 389*d02c48faSDavid Vernet local = v->task; 390*d02c48faSDavid Vernet if (!local) { 391*d02c48faSDavid Vernet bpf_rcu_read_unlock(); 392*d02c48faSDavid Vernet return 0; 393*d02c48faSDavid Vernet } 394*d02c48faSDavid Vernet /* Can't release a kptr that's still stored in a map. */ 395*d02c48faSDavid Vernet bpf_task_release(local); 396*d02c48faSDavid Vernet bpf_rcu_read_unlock(); 397*d02c48faSDavid Vernet 398*d02c48faSDavid Vernet return 0; 399*d02c48faSDavid Vernet } 400