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