bpfilter_kern.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. // SPDX-License-Identifier: GPL-2.0
  2. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  3. #include <linux/init.h>
  4. #include <linux/module.h>
  5. #include <linux/umh.h>
  6. #include <linux/bpfilter.h>
  7. #include <linux/sched.h>
  8. #include <linux/sched/signal.h>
  9. #include <linux/fs.h>
  10. #include <linux/file.h>
  11. #include "msgfmt.h"
  12. extern char bpfilter_umh_start;
  13. extern char bpfilter_umh_end;
  14. static void shutdown_umh(void)
  15. {
  16. struct umd_info *info = &bpfilter_ops.info;
  17. struct pid *tgid = info->tgid;
  18. if (tgid) {
  19. kill_pid(tgid, SIGKILL, 1);
  20. wait_event(tgid->wait_pidfd, thread_group_exited(tgid));
  21. bpfilter_umh_cleanup(info);
  22. }
  23. }
  24. static void __stop_umh(void)
  25. {
  26. if (IS_ENABLED(CONFIG_INET))
  27. shutdown_umh();
  28. }
  29. static int bpfilter_send_req(struct mbox_request *req)
  30. {
  31. struct mbox_reply reply;
  32. loff_t pos = 0;
  33. ssize_t n;
  34. if (!bpfilter_ops.info.tgid)
  35. return -EFAULT;
  36. pos = 0;
  37. n = kernel_write(bpfilter_ops.info.pipe_to_umh, req, sizeof(*req),
  38. &pos);
  39. if (n != sizeof(*req)) {
  40. pr_err("write fail %zd\n", n);
  41. goto stop;
  42. }
  43. pos = 0;
  44. n = kernel_read(bpfilter_ops.info.pipe_from_umh, &reply, sizeof(reply),
  45. &pos);
  46. if (n != sizeof(reply)) {
  47. pr_err("read fail %zd\n", n);
  48. goto stop;
  49. }
  50. return reply.status;
  51. stop:
  52. __stop_umh();
  53. return -EFAULT;
  54. }
  55. static int bpfilter_process_sockopt(struct sock *sk, int optname,
  56. sockptr_t optval, unsigned int optlen,
  57. bool is_set)
  58. {
  59. struct mbox_request req = {
  60. .is_set = is_set,
  61. .pid = current->pid,
  62. .cmd = optname,
  63. .addr = (uintptr_t)optval.user,
  64. .len = optlen,
  65. };
  66. if (uaccess_kernel() || sockptr_is_kernel(optval)) {
  67. pr_err("kernel access not supported\n");
  68. return -EFAULT;
  69. }
  70. return bpfilter_send_req(&req);
  71. }
  72. static int start_umh(void)
  73. {
  74. struct mbox_request req = { .pid = current->pid };
  75. int err;
  76. /* fork usermode process */
  77. err = fork_usermode_driver(&bpfilter_ops.info);
  78. if (err)
  79. return err;
  80. pr_info("Loaded bpfilter_umh pid %d\n", pid_nr(bpfilter_ops.info.tgid));
  81. /* health check that usermode process started correctly */
  82. if (bpfilter_send_req(&req) != 0) {
  83. shutdown_umh();
  84. return -EFAULT;
  85. }
  86. return 0;
  87. }
  88. static int __init load_umh(void)
  89. {
  90. int err;
  91. err = umd_load_blob(&bpfilter_ops.info,
  92. &bpfilter_umh_start,
  93. &bpfilter_umh_end - &bpfilter_umh_start);
  94. if (err)
  95. return err;
  96. mutex_lock(&bpfilter_ops.lock);
  97. err = start_umh();
  98. if (!err && IS_ENABLED(CONFIG_INET)) {
  99. bpfilter_ops.sockopt = &bpfilter_process_sockopt;
  100. bpfilter_ops.start = &start_umh;
  101. }
  102. mutex_unlock(&bpfilter_ops.lock);
  103. if (err)
  104. umd_unload_blob(&bpfilter_ops.info);
  105. return err;
  106. }
  107. static void __exit fini_umh(void)
  108. {
  109. mutex_lock(&bpfilter_ops.lock);
  110. if (IS_ENABLED(CONFIG_INET)) {
  111. shutdown_umh();
  112. bpfilter_ops.start = NULL;
  113. bpfilter_ops.sockopt = NULL;
  114. }
  115. mutex_unlock(&bpfilter_ops.lock);
  116. umd_unload_blob(&bpfilter_ops.info);
  117. }
  118. module_init(load_umh);
  119. module_exit(fini_umh);
  120. MODULE_LICENSE("GPL");
  121. MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver);