1 /*
2  * fuseMedia eBPF program
3  *
4  * Copyright (C) 2021 Google
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License version
8  * 2 as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  */
16 
17 #include <bpf_helpers.h>
18 
19 #include <stdint.h>
20 
21 #define __KERNEL__
22 #include <fuse_kernel.h>
23 
24 #define bpf_printk(fmt, ...)                                       \
25     ({                                                             \
26         char ____fmt[] = fmt;                                      \
27         bpf_trace_printk(____fmt, sizeof(____fmt), ##__VA_ARGS__); \
28     })
29 
30 DEFINE_BPF_PROG("fuse/media", AID_ROOT, AID_MEDIA_RW, fuse_media)
31 (struct fuse_bpf_args* fa) {
32     switch (fa->opcode) {
33         case FUSE_LOOKUP | FUSE_PREFILTER: {
34             const char* name = fa->in_args[0].value;
35 
36             bpf_printk("LOOKUP_PREFILTER: %lx %s", fa->nodeid, name);
37             return FUSE_BPF_BACKING | FUSE_BPF_POST_FILTER;
38         }
39 
40         case FUSE_LOOKUP | FUSE_POSTFILTER: {
41             struct fuse_entry_out* feo = fa->out_args[0].value;
42             struct fuse_entry_bpf_out* febo = fa->out_args[1].value;
43             uint64_t uid_gid = bpf_get_current_uid_gid();
44             uint32_t uid = uid_gid;
45             uint32_t gid = uid_gid >> 32;
46 
47             febo->bpf_action = FUSE_ACTION_REMOVE;
48 
49             /* If the decision is easy, make it here for performance */
50             if (fa->error_in || (feo->attr.mode & 0001) ||
51                 ((feo->attr.mode & 0010) && gid == feo->attr.gid) ||
52                 ((feo->attr.mode & 0100) && uid == feo->attr.uid))
53                 return 0;
54 
55             /* Delegate to the daemon */
56             return FUSE_BPF_USER_FILTER;
57         }
58 
59         case FUSE_READDIR | FUSE_PREFILTER: {
60             return FUSE_BPF_BACKING | FUSE_BPF_POST_FILTER;
61         }
62 
63         case FUSE_READDIR | FUSE_POSTFILTER: {
64             return FUSE_BPF_USER_FILTER;
65         }
66 
67         default:
68             return FUSE_BPF_BACKING;
69     }
70 }
71 
72 LICENSE("GPL");
73