1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2021 Google LLC
3
4 #include <linux/filter.h>
5 #include <linux/android_fuse.h>
6
7 static const struct bpf_func_proto *
fuse_prog_func_proto(enum bpf_func_id func_id,const struct bpf_prog * prog)8 fuse_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
9 {
10 switch (func_id) {
11 case BPF_FUNC_trace_printk:
12 return bpf_get_trace_printk_proto();
13
14 case BPF_FUNC_get_current_uid_gid:
15 return &bpf_get_current_uid_gid_proto;
16
17 case BPF_FUNC_get_current_pid_tgid:
18 return &bpf_get_current_pid_tgid_proto;
19
20 case BPF_FUNC_map_lookup_elem:
21 return &bpf_map_lookup_elem_proto;
22
23 case BPF_FUNC_map_update_elem:
24 return &bpf_map_update_elem_proto;
25
26 default:
27 pr_debug("Invalid fuse bpf func %d\n", func_id);
28 return NULL;
29 }
30 }
31
fuse_prog_is_valid_access(int off,int size,enum bpf_access_type type,const struct bpf_prog * prog,struct bpf_insn_access_aux * info)32 static bool fuse_prog_is_valid_access(int off, int size,
33 enum bpf_access_type type,
34 const struct bpf_prog *prog,
35 struct bpf_insn_access_aux *info)
36 {
37 int i;
38
39 if (off < 0 || off > offsetofend(struct fuse_bpf_args, out_args))
40 return false;
41
42 /* TODO This is garbage. Do it properly */
43 for (i = 0; i < 5; i++) {
44 if (off == offsetof(struct fuse_bpf_args, in_args[i].value)) {
45 info->reg_type = PTR_TO_BUF;
46 info->ctx_field_size = 256;
47 if (type != BPF_READ)
48 return false;
49 return true;
50 }
51 }
52 for (i = 0; i < 3; i++) {
53 if (off == offsetof(struct fuse_bpf_args, out_args[i].value)) {
54 info->reg_type = PTR_TO_BUF;
55 info->ctx_field_size = 256;
56 return true;
57 }
58 }
59 if (type != BPF_READ)
60 return false;
61
62 return true;
63 }
64
65 const struct bpf_verifier_ops fuse_verifier_ops = {
66 .get_func_proto = fuse_prog_func_proto,
67 .is_valid_access = fuse_prog_is_valid_access,
68 };
69
70 const struct bpf_prog_ops fuse_prog_ops = {
71 };
72
fuse_get_bpf_prog(struct file * file)73 struct bpf_prog *fuse_get_bpf_prog(struct file *file)
74 {
75 struct bpf_prog *bpf_prog = ERR_PTR(-EINVAL);
76
77 if (!file || IS_ERR(file))
78 return bpf_prog;
79 /**
80 * Two ways of getting a bpf prog from another task's fd, since
81 * bpf_prog_get_type_dev only works with an fd
82 *
83 * 1) Duplicate a little of the needed code. Requires access to
84 * bpf_prog_fops for validation, which is not exported for modules
85 * 2) Insert the bpf_file object into a fd from the current task
86 * Stupidly complex, but I think OK, as security checks are not run
87 * during the existence of the handle
88 *
89 * Best would be to upstream 1) into kernel/bpf/syscall.c and export it
90 * for use here. Failing that, we have to use 2, since fuse must be
91 * compilable as a module.
92 */
93 #if 1
94 if (file->f_op != &bpf_prog_fops)
95 goto out;
96
97 bpf_prog = file->private_data;
98 if (bpf_prog->type == BPF_PROG_TYPE_FUSE)
99 bpf_prog_inc(bpf_prog);
100 else
101 bpf_prog = ERR_PTR(-EINVAL);
102
103 #else
104 {
105 int task_fd = get_unused_fd_flags(file->f_flags);
106
107 if (task_fd < 0)
108 goto out;
109
110 fd_install(task_fd, file);
111
112 bpf_prog = bpf_prog_get_type_dev(task_fd, BPF_PROG_TYPE_FUSE,
113 false);
114
115 /* Close the fd, which also closes the file */
116 __close_fd(current->files, task_fd);
117 file = NULL;
118 }
119 #endif
120
121 out:
122 if (file)
123 fput(file);
124 return bpf_prog;
125 }
126 EXPORT_SYMBOL(fuse_get_bpf_prog);
127
128
129