bpf_fuse.c 3.0 KB

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