• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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