1 | // SPDX-License-Identifier: GPL-2.0 |
2 | #include <linux/init.h> |
3 | #include <linux/module.h> |
4 | #include <linux/uaccess.h> |
5 | #include <linux/bpfilter.h> |
6 | #include <uapi/linux/bpf.h> |
7 | #include <linux/wait.h> |
8 | #include <linux/kmod.h> |
9 | #include <linux/fs.h> |
10 | #include <linux/file.h> |
11 | |
12 | struct bpfilter_umh_ops bpfilter_ops; |
13 | EXPORT_SYMBOL_GPL(bpfilter_ops); |
14 | |
15 | static int bpfilter_mbox_request(struct sock *sk, int optname, sockptr_t optval, |
16 | unsigned int optlen, bool is_set) |
17 | { |
18 | int err; |
19 | mutex_lock(&bpfilter_ops.lock); |
20 | if (!bpfilter_ops.sockopt) { |
21 | mutex_unlock(lock: &bpfilter_ops.lock); |
22 | request_module("bpfilter" ); |
23 | mutex_lock(&bpfilter_ops.lock); |
24 | |
25 | if (!bpfilter_ops.sockopt) { |
26 | err = -ENOPROTOOPT; |
27 | goto out; |
28 | } |
29 | } |
30 | if (bpfilter_ops.info.tgid && |
31 | thread_group_exited(pid: bpfilter_ops.info.tgid)) |
32 | umd_cleanup_helper(info: &bpfilter_ops.info); |
33 | |
34 | if (!bpfilter_ops.info.tgid) { |
35 | err = bpfilter_ops.start(); |
36 | if (err) |
37 | goto out; |
38 | } |
39 | err = bpfilter_ops.sockopt(sk, optname, optval, optlen, is_set); |
40 | out: |
41 | mutex_unlock(lock: &bpfilter_ops.lock); |
42 | return err; |
43 | } |
44 | |
45 | int bpfilter_ip_set_sockopt(struct sock *sk, int optname, sockptr_t optval, |
46 | unsigned int optlen) |
47 | { |
48 | return bpfilter_mbox_request(sk, optname, optval, optlen, is_set: true); |
49 | } |
50 | |
51 | int bpfilter_ip_get_sockopt(struct sock *sk, int optname, char __user *optval, |
52 | int __user *optlen) |
53 | { |
54 | int len; |
55 | |
56 | if (get_user(len, optlen)) |
57 | return -EFAULT; |
58 | |
59 | return bpfilter_mbox_request(sk, optname, optval: USER_SOCKPTR(p: optval), optlen: len, |
60 | is_set: false); |
61 | } |
62 | |
63 | static int __init bpfilter_sockopt_init(void) |
64 | { |
65 | mutex_init(&bpfilter_ops.lock); |
66 | bpfilter_ops.info.tgid = NULL; |
67 | bpfilter_ops.info.driver_name = "bpfilter_umh" ; |
68 | |
69 | return 0; |
70 | } |
71 | device_initcall(bpfilter_sockopt_init); |
72 | |