| // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause |
| // Copyright (c) 2021 Google LLC |
| |
| #define __EXPORTED_HEADERS__ |
| #define __KERNEL__ |
| |
| #ifdef __ANDROID__ |
| #include <stdint.h> |
| #endif |
| |
| #include <uapi/linux/types.h> |
| #include <uapi/linux/bpf.h> |
| #include <uapi/linux/fuse.h> |
| #include <uapi/linux/errno.h> |
| |
| struct fuse_bpf_map { |
| int map_type; |
| size_t key_size; |
| size_t value_size; |
| int max_entries; |
| }; |
| |
| static void *(*bpf_map_lookup_elem)(struct fuse_bpf_map *map, void *key) |
| = (void *) 1; |
| |
| static void *(*bpf_map_update_elem)(struct fuse_bpf_map *map, void *key, |
| void *value, int flags) |
| = (void *) 2; |
| |
| static long (*bpf_trace_printk)(const char *fmt, __u32 fmt_size, ...) |
| = (void *) 6; |
| |
| static long (*bpf_get_current_pid_tgid)() |
| = (void *) 14; |
| |
| static long (*bpf_get_current_uid_gid)() |
| = (void *) 15; |
| |
| #define bpf_printk(fmt, ...) \ |
| ({ \ |
| char ____fmt[] = fmt; \ |
| bpf_trace_printk(____fmt, sizeof(____fmt), \ |
| ##__VA_ARGS__); \ |
| }) |
| |
| #define SEC(NAME) __attribute__((section(NAME), used)) |
| |
| SEC("dummy") |
| |
| inline int strcmp(const char *a, const char *b) |
| { |
| int i; |
| |
| for (i = 0; i < __builtin_strlen(b) + 1; ++i) |
| if (a[i] != b[i]) |
| return -1; |
| |
| return 0; |
| } |
| |
| SEC("maps") struct fuse_bpf_map test_map = { |
| BPF_MAP_TYPE_ARRAY, |
| sizeof(uint32_t), |
| sizeof(uint32_t), |
| 1000, |
| }; |
| |
| SEC("maps") struct fuse_bpf_map test_map2 = { |
| BPF_MAP_TYPE_HASH, |
| sizeof(uint32_t), |
| sizeof(uint64_t), |
| 76, |
| }; |
| |
| SEC("test_daemon") |
| |
| int trace_daemon(struct fuse_args *fa) |
| { |
| uint64_t uid_gid = bpf_get_current_uid_gid(); |
| uint32_t uid = uid_gid & 0xffffffff; |
| uint64_t pid_tgid = bpf_get_current_pid_tgid(); |
| uint32_t pid = pid_tgid & 0xffffffff; |
| uint32_t key = 23; |
| uint32_t *pvalue; |
| |
| |
| pvalue = bpf_map_lookup_elem(&test_map, &key); |
| if (pvalue) { |
| uint32_t value = *pvalue; |
| |
| bpf_printk("pid %u uid %u value %u", pid, uid, value); |
| value++; |
| bpf_map_update_elem(&test_map, &key, &value, BPF_ANY); |
| } |
| |
| switch (fa->opcode) { |
| case FUSE_ACCESS | FUSE_PREFILTER: { |
| bpf_printk("Access: %d", fa->nodeid); |
| return FUSE_BPF_BACKING; |
| } |
| |
| case FUSE_GETATTR | FUSE_PREFILTER: { |
| const struct fuse_getattr_in *fgi = fa->in_args[0].value; |
| |
| bpf_printk("Get Attr %d", fgi->fh); |
| return FUSE_BPF_BACKING; |
| } |
| |
| case FUSE_SETATTR | FUSE_PREFILTER: { |
| const struct fuse_setattr_in *fsi = fa->in_args[0].value; |
| |
| bpf_printk("Set Attr %d", fsi->fh); |
| return FUSE_BPF_BACKING; |
| } |
| |
| case FUSE_OPENDIR | FUSE_PREFILTER: { |
| bpf_printk("Open Dir: %d", fa->nodeid); |
| return FUSE_BPF_BACKING; |
| } |
| |
| case FUSE_READDIR | FUSE_PREFILTER: { |
| const struct fuse_read_in *fri = fa->in_args[0].value; |
| |
| bpf_printk("Read Dir: fh: %lu", fri->fh, fri->offset); |
| return FUSE_BPF_BACKING; |
| } |
| |
| case FUSE_LOOKUP | FUSE_PREFILTER: { |
| const char *name = fa->in_args[0].value; |
| |
| bpf_printk("Lookup: %lx %s", fa->nodeid, name); |
| if (fa->nodeid == 1) |
| return FUSE_BPF_USER_FILTER | FUSE_BPF_BACKING; |
| else |
| return FUSE_BPF_BACKING; |
| } |
| |
| case FUSE_MKNOD | FUSE_PREFILTER: { |
| const struct fuse_mknod_in *fmi = fa->in_args[0].value; |
| const char *name = fa->in_args[1].value; |
| |
| bpf_printk("mknod %s %x %x", name, fmi->rdev | fmi->mode, fmi->umask); |
| return FUSE_BPF_BACKING; |
| } |
| |
| case FUSE_MKDIR | FUSE_PREFILTER: { |
| const struct fuse_mkdir_in *fmi = fa->in_args[0].value; |
| const char *name = fa->in_args[1].value; |
| |
| bpf_printk("mkdir: %s %x %x", name, fmi->mode, fmi->umask); |
| return FUSE_BPF_BACKING; |
| } |
| |
| case FUSE_RMDIR | FUSE_PREFILTER: { |
| const char *name = fa->in_args[0].value; |
| |
| bpf_printk("rmdir: %s", name); |
| return FUSE_BPF_BACKING; |
| } |
| |
| case FUSE_RENAME | FUSE_PREFILTER: { |
| const char *oldname = fa->in_args[1].value; |
| const char *newname = fa->in_args[2].value; |
| |
| bpf_printk("rename from %s", oldname); |
| bpf_printk("rename to %s", newname); |
| return FUSE_BPF_BACKING; |
| } |
| |
| case FUSE_RENAME2 | FUSE_PREFILTER: { |
| const struct fuse_rename2_in *fri = fa->in_args[0].value; |
| uint32_t flags = fri->flags; |
| const char *oldname = fa->in_args[1].value; |
| const char *newname = fa->in_args[2].value; |
| |
| bpf_printk("rename(%x) from %s", flags, oldname); |
| bpf_printk("rename to %s", newname); |
| return FUSE_BPF_BACKING; |
| } |
| |
| case FUSE_UNLINK | FUSE_PREFILTER: { |
| const char *name = fa->in_args[0].value; |
| |
| bpf_printk("unlink: %s", name); |
| return FUSE_BPF_BACKING; |
| } |
| |
| case FUSE_LINK | FUSE_PREFILTER: { |
| const struct fuse_link_in *fli = fa->in_args[0].value; |
| const char *dst_name = fa->in_args[1].value; |
| |
| bpf_printk("Link: %d %s", fli->oldnodeid, dst_name); |
| return FUSE_BPF_BACKING; |
| } |
| |
| case FUSE_SYMLINK | FUSE_PREFILTER: { |
| const char *link_name = fa->in_args[0].value; |
| const char *link_dest = fa->in_args[1].value; |
| |
| bpf_printk("symlink from %s", link_name); |
| bpf_printk("symlink to %s", link_dest); |
| return FUSE_BPF_BACKING; |
| } |
| |
| case FUSE_READLINK | FUSE_PREFILTER: { |
| const char *link_name = fa->in_args[0].value; |
| |
| bpf_printk("readlink from %s", link_name); |
| return FUSE_BPF_BACKING; |
| } |
| |
| case FUSE_RELEASE | FUSE_PREFILTER: { |
| const struct fuse_release_in *fri = fa->in_args[0].value; |
| |
| bpf_printk("Release: %d", fri->fh); |
| return FUSE_BPF_BACKING; |
| } |
| |
| case FUSE_RELEASEDIR | FUSE_PREFILTER: { |
| const struct fuse_release_in *fri = fa->in_args[0].value; |
| |
| bpf_printk("Release Dir: %d", fri->fh); |
| return FUSE_BPF_BACKING; |
| } |
| |
| case FUSE_CREATE | FUSE_PREFILTER: { |
| bpf_printk("Create %s", fa->in_args[1].value); |
| return FUSE_BPF_BACKING; |
| } |
| |
| case FUSE_OPEN | FUSE_PREFILTER: { |
| bpf_printk("Open: %d", fa->nodeid); |
| return FUSE_BPF_BACKING; |
| } |
| |
| case FUSE_READ | FUSE_PREFILTER: { |
| const struct fuse_read_in *fri = fa->in_args[0].value; |
| |
| bpf_printk("Read: fh: %lu, offset %lu, size %lu", |
| fri->fh, fri->offset, fri->size); |
| return FUSE_BPF_BACKING; |
| } |
| |
| case FUSE_WRITE | FUSE_PREFILTER: { |
| const struct fuse_write_in *fwi = fa->in_args[0].value; |
| |
| bpf_printk("Write: fh: %lu, offset %lu, size %lu", |
| fwi->fh, fwi->offset, fwi->size); |
| return FUSE_BPF_BACKING; |
| } |
| |
| case FUSE_FLUSH | FUSE_PREFILTER: { |
| const struct fuse_flush_in *ffi = fa->in_args[0].value; |
| |
| bpf_printk("Flush %d", ffi->fh); |
| return FUSE_BPF_BACKING; |
| } |
| |
| case FUSE_FALLOCATE | FUSE_PREFILTER: { |
| const struct fuse_fallocate_in *ffa = fa->in_args[0].value; |
| |
| bpf_printk("Fallocate %d %lu", ffa->fh, ffa->length); |
| return FUSE_BPF_BACKING; |
| } |
| |
| case FUSE_GETXATTR | FUSE_PREFILTER: { |
| const char *name = fa->in_args[1].value; |
| |
| bpf_printk("Getxattr %d %s", fa->nodeid, name); |
| return FUSE_BPF_BACKING; |
| } |
| |
| case FUSE_LISTXATTR | FUSE_PREFILTER: { |
| const char *name = fa->in_args[1].value; |
| |
| bpf_printk("Listxattr %d %s", fa->nodeid, name); |
| return FUSE_BPF_BACKING; |
| } |
| |
| case FUSE_SETXATTR | FUSE_PREFILTER: { |
| const char *name = fa->in_args[1].value; |
| |
| bpf_printk("Setxattr %d %s", fa->nodeid, name); |
| return FUSE_BPF_BACKING; |
| } |
| |
| case FUSE_STATFS | FUSE_PREFILTER: { |
| bpf_printk("statfs %d", fa->nodeid); |
| return FUSE_BPF_BACKING; |
| } |
| |
| case FUSE_LSEEK | FUSE_PREFILTER: { |
| const struct fuse_lseek_in *fli = fa->in_args[0].value; |
| |
| bpf_printk("lseek type:%d, offset:%lld", fli->whence, fli->offset); |
| return FUSE_BPF_BACKING; |
| } |
| |
| default: |
| if (fa->opcode & FUSE_PREFILTER) |
| bpf_printk("prefilter *** UNKNOWN *** opcode: %d", |
| fa->opcode & FUSE_OPCODE_FILTER); |
| else if (fa->opcode & FUSE_POSTFILTER) |
| bpf_printk("postfilter *** UNKNOWN *** opcode: %d", |
| fa->opcode & FUSE_OPCODE_FILTER); |
| else |
| bpf_printk("*** UNKNOWN *** opcode: %d", fa->opcode); |
| return FUSE_BPF_BACKING; |
| } |
| } |