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>
6 #include <linux/bpfilter.h>
7 #include <linux/sched.h>
8 #include <linux/sched/signal.h>
10 #include <linux/file.h>
13 extern char bpfilter_umh_start
;
14 extern char bpfilter_umh_end
;
16 static void shutdown_umh(void)
18 struct umd_info
*info
= &bpfilter_ops
.info
;
19 struct pid
*tgid
= info
->tgid
;
22 kill_pid(tgid
, SIGKILL
, 1);
23 wait_event(tgid
->wait_pidfd
, thread_group_exited(tgid
));
24 bpfilter_umh_cleanup(info
);
28 static void __stop_umh(void)
30 if (IS_ENABLED(CONFIG_INET
))
34 static int bpfilter_send_req(struct mbox_request
*req
)
36 struct mbox_reply reply
;
40 if (!bpfilter_ops
.info
.tgid
)
43 n
= kernel_write(bpfilter_ops
.info
.pipe_to_umh
, req
, sizeof(*req
),
45 if (n
!= sizeof(*req
)) {
46 pr_err("write fail %zd\n", n
);
50 n
= kernel_read(bpfilter_ops
.info
.pipe_from_umh
, &reply
, sizeof(reply
),
52 if (n
!= sizeof(reply
)) {
53 pr_err("read fail %zd\n", n
);
62 static int bpfilter_process_sockopt(struct sock
*sk
, int optname
,
63 sockptr_t optval
, unsigned int optlen
,
66 struct mbox_request req
= {
70 .addr
= (uintptr_t)optval
.user
,
73 if (uaccess_kernel() || sockptr_is_kernel(optval
)) {
74 pr_err("kernel access not supported\n");
77 return bpfilter_send_req(&req
);
80 static int start_umh(void)
82 struct mbox_request req
= { .pid
= current
->pid
};
85 /* fork usermode process */
86 err
= fork_usermode_driver(&bpfilter_ops
.info
);
89 pr_info("Loaded bpfilter_umh pid %d\n", pid_nr(bpfilter_ops
.info
.tgid
));
91 /* health check that usermode process started correctly */
92 if (bpfilter_send_req(&req
) != 0) {
100 static int __init
load_umh(void)
104 err
= umd_load_blob(&bpfilter_ops
.info
,
106 &bpfilter_umh_end
- &bpfilter_umh_start
);
110 mutex_lock(&bpfilter_ops
.lock
);
112 if (!err
&& IS_ENABLED(CONFIG_INET
)) {
113 bpfilter_ops
.sockopt
= &bpfilter_process_sockopt
;
114 bpfilter_ops
.start
= &start_umh
;
116 mutex_unlock(&bpfilter_ops
.lock
);
118 umd_unload_blob(&bpfilter_ops
.info
);
122 static void __exit
fini_umh(void)
124 mutex_lock(&bpfilter_ops
.lock
);
125 if (IS_ENABLED(CONFIG_INET
)) {
127 bpfilter_ops
.start
= NULL
;
128 bpfilter_ops
.sockopt
= NULL
;
130 mutex_unlock(&bpfilter_ops
.lock
);
132 umd_unload_blob(&bpfilter_ops
.info
);
134 module_init(load_umh
);
135 module_exit(fini_umh
);
136 MODULE_LICENSE("GPL");