net: add skeleton of bpfilter kernel module
bpfilter.ko consists of bpfilter_kern.c (normal kernel module code) and user mode helper code that is embedded into bpfilter.ko The steps to build bpfilter.ko are the following: - main.c is compiled by HOSTCC into the bpfilter_umh elf executable file - with quite a bit of objcopy and Makefile magic the bpfilter_umh elf file is converted into bpfilter_umh.o object file with _binary_net_bpfilter_bpfilter_umh_start and _end symbols Example: $ nm ./bld_x64/net/bpfilter/bpfilter_umh.o 0000000000004cf8 T _binary_net_bpfilter_bpfilter_umh_end 0000000000004cf8 A _binary_net_bpfilter_bpfilter_umh_size 0000000000000000 T _binary_net_bpfilter_bpfilter_umh_start - bpfilter_umh.o and bpfilter_kern.o are linked together into bpfilter.ko bpfilter_kern.c is a normal kernel module code that calls the fork_usermode_blob() helper to execute part of its own data as a user mode process. Notice that _binary_net_bpfilter_bpfilter_umh_start - end is placed into .init.rodata section, so it's freed as soon as __init function of bpfilter.ko is finished. As part of __init the bpfilter.ko does first request/reply action via two unix pipe provided by fork_usermode_blob() helper to make sure that umh is healthy. If not it will kill it via pid. Later bpfilter_process_sockopt() will be called from bpfilter hooks in get/setsockopt() to pass iptable commands into umh via bpfilter.ko If admin does 'rmmod bpfilter' the __exit code bpfilter.ko will kill umh as well. Signed-off-by: Alexei Starovoitov <ast@kernel.org> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:

committed by
David S. Miller

parent
449325b52b
commit
d2ba09c17a
@@ -16,6 +16,8 @@ obj-y := route.o inetpeer.o protocol.o \
|
||||
inet_fragment.o ping.o ip_tunnel_core.o gre_offload.o \
|
||||
metrics.o
|
||||
|
||||
obj-$(CONFIG_BPFILTER) += bpfilter/
|
||||
|
||||
obj-$(CONFIG_NET_IP_TUNNEL) += ip_tunnel.o
|
||||
obj-$(CONFIG_SYSCTL) += sysctl_net_ipv4.o
|
||||
obj-$(CONFIG_PROC_FS) += proc.o
|
||||
|
2
net/ipv4/bpfilter/Makefile
Normal file
2
net/ipv4/bpfilter/Makefile
Normal file
@@ -0,0 +1,2 @@
|
||||
obj-$(CONFIG_BPFILTER) += sockopt.o
|
||||
|
42
net/ipv4/bpfilter/sockopt.c
Normal file
42
net/ipv4/bpfilter/sockopt.c
Normal file
@@ -0,0 +1,42 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/bpfilter.h>
|
||||
#include <uapi/linux/bpf.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/kmod.h>
|
||||
|
||||
int (*bpfilter_process_sockopt)(struct sock *sk, int optname,
|
||||
char __user *optval,
|
||||
unsigned int optlen, bool is_set);
|
||||
EXPORT_SYMBOL_GPL(bpfilter_process_sockopt);
|
||||
|
||||
int bpfilter_mbox_request(struct sock *sk, int optname, char __user *optval,
|
||||
unsigned int optlen, bool is_set)
|
||||
{
|
||||
if (!bpfilter_process_sockopt) {
|
||||
int err = request_module("bpfilter");
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
if (!bpfilter_process_sockopt)
|
||||
return -ECHILD;
|
||||
}
|
||||
return bpfilter_process_sockopt(sk, optname, optval, optlen, is_set);
|
||||
}
|
||||
|
||||
int bpfilter_ip_set_sockopt(struct sock *sk, int optname, char __user *optval,
|
||||
unsigned int optlen)
|
||||
{
|
||||
return bpfilter_mbox_request(sk, optname, optval, optlen, true);
|
||||
}
|
||||
|
||||
int bpfilter_ip_get_sockopt(struct sock *sk, int optname, char __user *optval,
|
||||
int __user *optlen)
|
||||
{
|
||||
int len;
|
||||
|
||||
if (get_user(len, optlen))
|
||||
return -EFAULT;
|
||||
|
||||
return bpfilter_mbox_request(sk, optname, optval, len, false);
|
||||
}
|
@@ -47,6 +47,8 @@
|
||||
#include <linux/errqueue.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <linux/bpfilter.h>
|
||||
|
||||
/*
|
||||
* SOL_IP control messages.
|
||||
*/
|
||||
@@ -1244,6 +1246,11 @@ int ip_setsockopt(struct sock *sk, int level,
|
||||
return -ENOPROTOOPT;
|
||||
|
||||
err = do_ip_setsockopt(sk, level, optname, optval, optlen);
|
||||
#ifdef CONFIG_BPFILTER
|
||||
if (optname >= BPFILTER_IPT_SO_SET_REPLACE &&
|
||||
optname < BPFILTER_IPT_SET_MAX)
|
||||
err = bpfilter_ip_set_sockopt(sk, optname, optval, optlen);
|
||||
#endif
|
||||
#ifdef CONFIG_NETFILTER
|
||||
/* we need to exclude all possible ENOPROTOOPTs except default case */
|
||||
if (err == -ENOPROTOOPT && optname != IP_HDRINCL &&
|
||||
@@ -1552,6 +1559,11 @@ int ip_getsockopt(struct sock *sk, int level,
|
||||
int err;
|
||||
|
||||
err = do_ip_getsockopt(sk, level, optname, optval, optlen, 0);
|
||||
#ifdef CONFIG_BPFILTER
|
||||
if (optname >= BPFILTER_IPT_SO_GET_INFO &&
|
||||
optname < BPFILTER_IPT_GET_MAX)
|
||||
err = bpfilter_ip_get_sockopt(sk, optname, optval, optlen);
|
||||
#endif
|
||||
#ifdef CONFIG_NETFILTER
|
||||
/* we need to exclude all possible ENOPROTOOPTs except default case */
|
||||
if (err == -ENOPROTOOPT && optname != IP_PKTOPTIONS &&
|
||||
@@ -1584,6 +1596,11 @@ int compat_ip_getsockopt(struct sock *sk, int level, int optname,
|
||||
err = do_ip_getsockopt(sk, level, optname, optval, optlen,
|
||||
MSG_CMSG_COMPAT);
|
||||
|
||||
#ifdef CONFIG_BPFILTER
|
||||
if (optname >= BPFILTER_IPT_SO_GET_INFO &&
|
||||
optname < BPFILTER_IPT_GET_MAX)
|
||||
err = bpfilter_ip_get_sockopt(sk, optname, optval, optlen);
|
||||
#endif
|
||||
#ifdef CONFIG_NETFILTER
|
||||
/* we need to exclude all possible ENOPROTOOPTs except default case */
|
||||
if (err == -ENOPROTOOPT && optname != IP_PKTOPTIONS &&
|
||||
|
Reference in New Issue
Block a user