root/net/bpfilter/bpfilter_kern.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. shutdown_umh
  2. __stop_umh
  3. __bpfilter_process_sockopt
  4. start_umh
  5. load_umh
  6. fini_umh

   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 
  13 extern char bpfilter_umh_start;
  14 extern char bpfilter_umh_end;
  15 
  16 static void shutdown_umh(void)
  17 {
  18         struct task_struct *tsk;
  19 
  20         if (bpfilter_ops.stop)
  21                 return;
  22 
  23         tsk = get_pid_task(find_vpid(bpfilter_ops.info.pid), PIDTYPE_PID);
  24         if (tsk) {
  25                 send_sig(SIGKILL, tsk, 1);
  26                 put_task_struct(tsk);
  27         }
  28 }
  29 
  30 static void __stop_umh(void)
  31 {
  32         if (IS_ENABLED(CONFIG_INET))
  33                 shutdown_umh();
  34 }
  35 
  36 static int __bpfilter_process_sockopt(struct sock *sk, int optname,
  37                                       char __user *optval,
  38                                       unsigned int optlen, bool is_set)
  39 {
  40         struct mbox_request req;
  41         struct mbox_reply reply;
  42         loff_t pos;
  43         ssize_t n;
  44         int ret = -EFAULT;
  45 
  46         req.is_set = is_set;
  47         req.pid = current->pid;
  48         req.cmd = optname;
  49         req.addr = (long __force __user)optval;
  50         req.len = optlen;
  51         if (!bpfilter_ops.info.pid)
  52                 goto out;
  53         n = __kernel_write(bpfilter_ops.info.pipe_to_umh, &req, sizeof(req),
  54                            &pos);
  55         if (n != sizeof(req)) {
  56                 pr_err("write fail %zd\n", n);
  57                 __stop_umh();
  58                 ret = -EFAULT;
  59                 goto out;
  60         }
  61         pos = 0;
  62         n = kernel_read(bpfilter_ops.info.pipe_from_umh, &reply, sizeof(reply),
  63                         &pos);
  64         if (n != sizeof(reply)) {
  65                 pr_err("read fail %zd\n", n);
  66                 __stop_umh();
  67                 ret = -EFAULT;
  68                 goto out;
  69         }
  70         ret = reply.status;
  71 out:
  72         return ret;
  73 }
  74 
  75 static int start_umh(void)
  76 {
  77         int err;
  78 
  79         /* fork usermode process */
  80         err = fork_usermode_blob(&bpfilter_umh_start,
  81                                  &bpfilter_umh_end - &bpfilter_umh_start,
  82                                  &bpfilter_ops.info);
  83         if (err)
  84                 return err;
  85         bpfilter_ops.stop = false;
  86         pr_info("Loaded bpfilter_umh pid %d\n", bpfilter_ops.info.pid);
  87 
  88         /* health check that usermode process started correctly */
  89         if (__bpfilter_process_sockopt(NULL, 0, NULL, 0, 0) != 0) {
  90                 shutdown_umh();
  91                 return -EFAULT;
  92         }
  93 
  94         return 0;
  95 }
  96 
  97 static int __init load_umh(void)
  98 {
  99         int err;
 100 
 101         mutex_lock(&bpfilter_ops.lock);
 102         if (!bpfilter_ops.stop) {
 103                 err = -EFAULT;
 104                 goto out;
 105         }
 106         err = start_umh();
 107         if (!err && IS_ENABLED(CONFIG_INET)) {
 108                 bpfilter_ops.sockopt = &__bpfilter_process_sockopt;
 109                 bpfilter_ops.start = &start_umh;
 110         }
 111 out:
 112         mutex_unlock(&bpfilter_ops.lock);
 113         return err;
 114 }
 115 
 116 static void __exit fini_umh(void)
 117 {
 118         mutex_lock(&bpfilter_ops.lock);
 119         if (IS_ENABLED(CONFIG_INET)) {
 120                 shutdown_umh();
 121                 bpfilter_ops.start = NULL;
 122                 bpfilter_ops.sockopt = NULL;
 123         }
 124         mutex_unlock(&bpfilter_ops.lock);
 125 }
 126 module_init(load_umh);
 127 module_exit(fini_umh);
 128 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */