|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
| 2 | +/* Copyright (c) 2024 Google LLC. */ |
| 3 | + |
| 4 | +#include <linux/bpf.h> |
| 5 | +#include <linux/btf.h> |
| 6 | +#include <linux/btf_ids.h> |
| 7 | +#include <linux/dcache.h> |
| 8 | +#include <linux/fs.h> |
| 9 | +#include <linux/file.h> |
| 10 | +#include <linux/mm.h> |
| 11 | + |
| 12 | +__bpf_kfunc_start_defs(); |
| 13 | + |
| 14 | +/** |
| 15 | + * bpf_get_task_exe_file - get a reference on the exe_file struct file member of |
| 16 | + * the mm_struct that is nested within the supplied |
| 17 | + * task_struct |
| 18 | + * @task: task_struct of which the nested mm_struct exe_file member to get a |
| 19 | + * reference on |
| 20 | + * |
| 21 | + * Get a reference on the exe_file struct file member field of the mm_struct |
| 22 | + * nested within the supplied *task*. The referenced file pointer acquired by |
| 23 | + * this BPF kfunc must be released using bpf_put_file(). Failing to call |
| 24 | + * bpf_put_file() on the returned referenced struct file pointer that has been |
| 25 | + * acquired by this BPF kfunc will result in the BPF program being rejected by |
| 26 | + * the BPF verifier. |
| 27 | + * |
| 28 | + * This BPF kfunc may only be called from BPF LSM programs. |
| 29 | + * |
| 30 | + * Internally, this BPF kfunc leans on get_task_exe_file(), such that calling |
| 31 | + * bpf_get_task_exe_file() would be analogous to calling get_task_exe_file() |
| 32 | + * directly in kernel context. |
| 33 | + * |
| 34 | + * Return: A referenced struct file pointer to the exe_file member of the |
| 35 | + * mm_struct that is nested within the supplied *task*. On error, NULL is |
| 36 | + * returned. |
| 37 | + */ |
| 38 | +__bpf_kfunc struct file *bpf_get_task_exe_file(struct task_struct *task) |
| 39 | +{ |
| 40 | + return get_task_exe_file(task); |
| 41 | +} |
| 42 | + |
| 43 | +/** |
| 44 | + * bpf_put_file - put a reference on the supplied file |
| 45 | + * @file: file to put a reference on |
| 46 | + * |
| 47 | + * Put a reference on the supplied *file*. Only referenced file pointers may be |
| 48 | + * passed to this BPF kfunc. Attempting to pass an unreferenced file pointer, or |
| 49 | + * any other arbitrary pointer for that matter, will result in the BPF program |
| 50 | + * being rejected by the BPF verifier. |
| 51 | + * |
| 52 | + * This BPF kfunc may only be called from BPF LSM programs. |
| 53 | + */ |
| 54 | +__bpf_kfunc void bpf_put_file(struct file *file) |
| 55 | +{ |
| 56 | + fput(file); |
| 57 | +} |
| 58 | + |
| 59 | +/** |
| 60 | + * bpf_path_d_path - resolve the pathname for the supplied path |
| 61 | + * @path: path to resolve the pathname for |
| 62 | + * @buf: buffer to return the resolved pathname in |
| 63 | + * @buf__sz: length of the supplied buffer |
| 64 | + * |
| 65 | + * Resolve the pathname for the supplied *path* and store it in *buf*. This BPF |
| 66 | + * kfunc is the safer variant of the legacy bpf_d_path() helper and should be |
| 67 | + * used in place of bpf_d_path() whenever possible. It enforces KF_TRUSTED_ARGS |
| 68 | + * semantics, meaning that the supplied *path* must itself hold a valid |
| 69 | + * reference, or else the BPF program will be outright rejected by the BPF |
| 70 | + * verifier. |
| 71 | + * |
| 72 | + * This BPF kfunc may only be called from BPF LSM programs. |
| 73 | + * |
| 74 | + * Return: A positive integer corresponding to the length of the resolved |
| 75 | + * pathname in *buf*, including the NUL termination character. On error, a |
| 76 | + * negative integer is returned. |
| 77 | + */ |
| 78 | +__bpf_kfunc int bpf_path_d_path(struct path *path, char *buf, size_t buf__sz) |
| 79 | +{ |
| 80 | + int len; |
| 81 | + char *ret; |
| 82 | + |
| 83 | + if (!buf__sz) |
| 84 | + return -EINVAL; |
| 85 | + |
| 86 | + ret = d_path(path, buf, buf__sz); |
| 87 | + if (IS_ERR(ret)) |
| 88 | + return PTR_ERR(ret); |
| 89 | + |
| 90 | + len = buf + buf__sz - ret; |
| 91 | + memmove(buf, ret, len); |
| 92 | + return len; |
| 93 | +} |
| 94 | + |
| 95 | +__bpf_kfunc_end_defs(); |
| 96 | + |
| 97 | +BTF_KFUNCS_START(bpf_fs_kfunc_set_ids) |
| 98 | +BTF_ID_FLAGS(func, bpf_get_task_exe_file, |
| 99 | + KF_ACQUIRE | KF_TRUSTED_ARGS | KF_RET_NULL) |
| 100 | +BTF_ID_FLAGS(func, bpf_put_file, KF_RELEASE) |
| 101 | +BTF_ID_FLAGS(func, bpf_path_d_path, KF_TRUSTED_ARGS) |
| 102 | +BTF_KFUNCS_END(bpf_fs_kfunc_set_ids) |
| 103 | + |
| 104 | +static int bpf_fs_kfuncs_filter(const struct bpf_prog *prog, u32 kfunc_id) |
| 105 | +{ |
| 106 | + if (!btf_id_set8_contains(&bpf_fs_kfunc_set_ids, kfunc_id) || |
| 107 | + prog->type == BPF_PROG_TYPE_LSM) |
| 108 | + return 0; |
| 109 | + return -EACCES; |
| 110 | +} |
| 111 | + |
| 112 | +static const struct btf_kfunc_id_set bpf_fs_kfunc_set = { |
| 113 | + .owner = THIS_MODULE, |
| 114 | + .set = &bpf_fs_kfunc_set_ids, |
| 115 | + .filter = bpf_fs_kfuncs_filter, |
| 116 | +}; |
| 117 | + |
| 118 | +static int __init bpf_fs_kfuncs_init(void) |
| 119 | +{ |
| 120 | + return register_btf_kfunc_id_set(BPF_PROG_TYPE_LSM, &bpf_fs_kfunc_set); |
| 121 | +} |
| 122 | + |
| 123 | +late_initcall(bpf_fs_kfuncs_init); |
0 commit comments