| 
 | 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