-
Notifications
You must be signed in to change notification settings - Fork 31
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement in-tree build for DCO with proto fix
The initialization hack for ovpn_tcp_prot doesn't work when the tcp_prot struct is constified (by Grsec/PaX, for instance) and is generally unsafe as it performs runtime function hooking/hijack to achieve its goal. The correct way to set up the structure requires access to symbols not exported by the kernel's headers, which makes out-of-tree compilation with the appropriate initializer impossible. In-tree builds can also benefit from LTO and other toolchain optimizations, as well as become part of monolithic kernels which do not use modules such as long-running network devices. Notes: Built and run using GCC 13 for Grsecurity/PaX (stable8) with all features except PRIVKSTACK and KERNSEAL enabled - x86_64 only. Built using LLVM17 with LTO & kCFI on GrapheneOS' linux-hardened patchset with their default features enabled - x86_64 only.
- Loading branch information
RageLtMan
committed
Sep 14, 2023
1 parent
dba96d2
commit 6f4fea9
Showing
3 changed files
with
239 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig | ||
index 9d4ab0c134ea..ca3462dd7322 100644 | ||
--- a/drivers/net/Kconfig | ||
+++ b/drivers/net/Kconfig | ||
@@ -115,6 +115,19 @@ config WIREGUARD_DEBUG | ||
|
||
Say N here unless you know what you're doing. | ||
|
||
+config OVPN_DCO_V2 | ||
+ tristate "OpenVPN data channel offload (reloaded)" | ||
+ depends on NET && INET | ||
+ select NET_UDP_TUNNEL | ||
+ select DST_CACHE | ||
+ select CRYPTO | ||
+ select CRYPTO_AES | ||
+ select CRYPTO_GCM | ||
+ select CRYPTO_CHACHA20POLY1305 | ||
+ help | ||
+ This module enhances the performance of the OpenVPN userspace software | ||
+ by offloading the data channel processing to kernelspace. | ||
+ | ||
config EQUALIZER | ||
tristate "EQL (serial line load balancing) support" | ||
help | ||
diff --git a/drivers/net/Makefile b/drivers/net/Makefile | ||
index 913fdf988281..7447bd47459b 100644 | ||
--- a/drivers/net/Makefile | ||
+++ b/drivers/net/Makefile | ||
@@ -11,6 +11,7 @@ obj-$(CONFIG_IPVLAN) += ipvlan/ | ||
obj-$(CONFIG_IPVTAP) += ipvlan/ | ||
obj-$(CONFIG_DUMMY) += dummy.o | ||
obj-$(CONFIG_WIREGUARD) += wireguard/ | ||
+obj-$(CONFIG_OVPN_DCO_V2) += ovpn-dco/ | ||
obj-$(CONFIG_EQUALIZER) += eql.o | ||
obj-$(CONFIG_IFB) += ifb.o | ||
obj-$(CONFIG_MACSEC) += macsec.o |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
#!/bin/bash | ||
|
||
# Copy ovpn_dco_v2 source and headers into kernel tree | ||
# Apply diff to relevant configuration files for in-tree builds | ||
# Set KDIR to appropriate source tree and run this script | ||
|
||
KDIR="${KDIR:="/usr/src/linux"}" | ||
COMMIT="$(git log|head -1|cut -d' ' -f2|cut -c 1-8)" | ||
DIFFDIR="$(cd $( dirname "${BASH_SOURCE[0]}") && pwd )" | ||
echo "Patching kernel in $KDIR from $DIFFDIR @ $COMMIT" | ||
|
||
if [[ ! -d "$KDIR" ]]; then | ||
echo "KDIR improperly set" | ||
exit 1 | ||
else | ||
if [[ ! -f "$KDIR/Kconfig" ]]; then | ||
echo "$KDIR does not appear to be a kernel tree" | ||
exit 1 | ||
fi | ||
|
||
cd "$DIFFDIR" | ||
cp -r ../drivers/net/ovpn-dco "$KDIR/net/" | ||
cp -r ../include/* "$KDIR/include/" | ||
|
||
cd "$KDIR" | ||
if [[ $(patch -p1 -i "$DIFFDIR/config.diff" -i "$DIFFDIR/proto.diff") ]]; then | ||
if [[ -d "$KDIR/.git" ]]; then | ||
git add "$KDIR/drivers/net" | ||
git add "$KDIR/include" | ||
git commit -am "OVPN DCO: in-tree @ $COMMIT" | ||
fi | ||
echo "Update kernel build configuration to enable OVPN_DCO module" | ||
exit 0 | ||
else | ||
echo "Failed to patch kernel tree, review output and PR a fix please" | ||
exit 1 | ||
fi | ||
fi | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
diff --git a/drivers/net/ovpn-dco/main.c b/drivers/net/ovpn-dco/main.c | ||
index 810ac8024fde..2c724e16b997 100644 | ||
--- a/drivers/net/ovpn-dco/main.c | ||
+++ b/drivers/net/ovpn-dco/main.c | ||
@@ -217,7 +217,6 @@ static int __init ovpn_init(void) | ||
|
||
pr_info("%s %s -- %s\n", DRV_DESCRIPTION, DRV_VERSION, DRV_COPYRIGHT); | ||
|
||
- err = ovpn_tcp_init(); | ||
if (err) { | ||
pr_err("ovpn: can't initialize TCP subsystem\n"); | ||
goto err; | ||
diff --git a/drivers/net/ovpn-dco/tcp.c b/drivers/net/ovpn-dco/tcp.c | ||
index 288a69101016..f8ef48c48299 100644 | ||
--- a/drivers/net/ovpn-dco/tcp.c | ||
+++ b/drivers/net/ovpn-dco/tcp.c | ||
@@ -19,8 +19,6 @@ | ||
#include <net/tcp.h> | ||
#include <net/route.h> | ||
|
||
-static struct proto ovpn_tcp_prot; | ||
- | ||
static int ovpn_tcp_read_sock(read_descriptor_t *desc, struct sk_buff *in_skb, | ||
unsigned int in_offset, size_t in_len) | ||
{ | ||
@@ -271,6 +269,59 @@ static int ovpn_tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, | ||
return ret ? : -EAGAIN; | ||
} | ||
|
||
+static struct proto ovpn_tcp_prot __ro_after_init = { | ||
+ .name = "TCP", | ||
+ .owner = THIS_MODULE, | ||
+ .close = tcp_close, | ||
+ .pre_connect = tcp_v4_pre_connect, | ||
+ .connect = tcp_v4_connect, | ||
+ .disconnect = tcp_disconnect, | ||
+ .accept = inet_csk_accept, | ||
+ .ioctl = tcp_ioctl, | ||
+ .init = tcp_v4_init_sock, | ||
+ .destroy = tcp_v4_destroy_sock, | ||
+ .shutdown = tcp_shutdown, | ||
+ .setsockopt = tcp_setsockopt, | ||
+ .getsockopt = tcp_getsockopt, | ||
+ .bpf_bypass_getsockopt = tcp_bpf_bypass_getsockopt, | ||
+ .keepalive = tcp_set_keepalive, | ||
+ .recvmsg = ovpn_tcp_recvmsg, | ||
+ .sendmsg = tcp_sendmsg, | ||
+ .sendpage = tcp_sendpage, | ||
+ .backlog_rcv = tcp_v4_do_rcv, | ||
+ .release_cb = tcp_release_cb, | ||
+ .hash = inet_hash, | ||
+ .unhash = inet_unhash, | ||
+ .get_port = inet_csk_get_port, | ||
+ .put_port = inet_put_port, | ||
+#ifdef CONFIG_BPF_SYSCALL | ||
+ .psock_update_sk_prot = tcp_bpf_update_proto, | ||
+#endif | ||
+ .enter_memory_pressure = tcp_enter_memory_pressure, | ||
+ .leave_memory_pressure = tcp_leave_memory_pressure, | ||
+ .stream_memory_free = tcp_stream_memory_free, | ||
+ .sockets_allocated = &tcp_sockets_allocated, | ||
+ .orphan_count = &tcp_orphan_count, | ||
+ | ||
+ .memory_allocated = &tcp_memory_allocated, | ||
+ .per_cpu_fw_alloc = &tcp_memory_per_cpu_fw_alloc, | ||
+ | ||
+ .memory_pressure = &tcp_memory_pressure, | ||
+ .sysctl_mem = sysctl_tcp_mem, | ||
+ .sysctl_wmem_offset = offsetof(struct net, ipv4.sysctl_tcp_wmem), | ||
+ .sysctl_rmem_offset = offsetof(struct net, ipv4.sysctl_tcp_rmem), | ||
+ .max_header = MAX_TCP_HEADER, | ||
+ .typename = "tcp_sock", | ||
+ .obj_size = sizeof(struct tcp_sock), | ||
+ .slab_flags = SLAB_TYPESAFE_BY_RCU, | ||
+ .twsk_prot = &tcp_timewait_sock_ops, | ||
+ .rsk_prot = &tcp_request_sock_ops, | ||
+ .h.hashinfo = NULL, | ||
+ .no_autobind = true, | ||
+ .diag_destroy = tcp_abort, | ||
+ .sock_is_readable = ovpn_tcp_sock_is_readable, | ||
+}; | ||
+ | ||
static void ovpn_destroy_skb(void *skb) | ||
{ | ||
consume_skb(skb); | ||
@@ -455,24 +506,3 @@ int ovpn_tcp_socket_attach(struct socket *sock, struct ovpn_peer *peer) | ||
|
||
return ret; | ||
} | ||
- | ||
-int __init ovpn_tcp_init(void) | ||
-{ | ||
- /* We need to substitute the recvmsg and the sock_is_readable | ||
- * callbacks in the sk_prot member of the sock object for TCP | ||
- * sockets. | ||
- * | ||
- * However sock->sk_prot is a pointer to a static variable and | ||
- * therefore we can't directly modify it, otherwise every socket | ||
- * pointing to it will be affected. | ||
- * | ||
- * For this reason we create our own static copy and modify what | ||
- * we need. Then we make sk_prot point to this copy | ||
- * (in ovpn_tcp_socket_attach()) | ||
- */ | ||
- ovpn_tcp_prot = tcp_prot; | ||
- ovpn_tcp_prot.recvmsg = ovpn_tcp_recvmsg; | ||
- ovpn_tcp_prot.sock_is_readable = ovpn_tcp_sock_is_readable; | ||
- | ||
- return 0; | ||
-} | ||
diff --git a/drivers/net/ovpn-dco/tcp.h b/drivers/net/ovpn-dco/tcp.h | ||
index 7f0e4ec826ad..fdb8e5e48b4b 100644 | ||
--- a/drivers/net/ovpn-dco/tcp.h | ||
+++ b/drivers/net/ovpn-dco/tcp.h | ||
@@ -16,9 +16,6 @@ | ||
#include <linux/types.h> | ||
#include <linux/workqueue.h> | ||
|
||
-/* Initialize TCP static objects */ | ||
-int __init ovpn_tcp_init(void); | ||
- | ||
void ovpn_queue_tcp_skb(struct ovpn_peer *peer, struct sk_buff *skb); | ||
|
||
int ovpn_tcp_socket_attach(struct socket *sock, struct ovpn_peer *peer); | ||
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c | ||
index 1d1163cc86c5..a0fccca41bf6 100644 | ||
--- a/net/ipv4/tcp_ipv4.c | ||
+++ b/net/ipv4/tcp_ipv4.c | ||
@@ -197,6 +197,8 @@ int tcp_v4_pre_connect(struct sock *sk, struct sockaddr *uaddr, | ||
return BPF_CGROUP_RUN_PROG_INET4_CONNECT(sk, uaddr); | ||
} | ||
|
||
+EXPORT_SYMBOL(tcp_v4_pre_connect); | ||
+ | ||
/* This will initiate an outgoing connection. */ | ||
int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) | ||
{ | ||
@@ -1464,6 +1466,8 @@ struct request_sock_ops tcp_request_sock_ops __read_mostly = { | ||
.syn_ack_timeout = tcp_syn_ack_timeout, | ||
}; | ||
|
||
+EXPORT_SYMBOL(tcp_request_sock_ops); | ||
+ | ||
/* net/mptcp/subflow.c:subflow_request_sock_ipv4_ops */ | ||
const struct tcp_request_sock_ops tcp_request_sock_ipv4_ops = { | ||
.mss_clamp = TCP_MSS_DEFAULT, | ||
@@ -2207,6 +2211,8 @@ struct timewait_sock_ops tcp_timewait_sock_ops = { | ||
.twsk_destructor= tcp_twsk_destructor, | ||
}; | ||
|
||
+EXPORT_SYMBOL(tcp_timewait_sock_ops); | ||
+ | ||
void inet_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb) | ||
{ | ||
struct dst_entry *dst = skb_dst(skb); | ||
@@ -2261,6 +2267,8 @@ int tcp_v4_init_sock(struct sock *sk) | ||
return 0; | ||
} | ||
|
||
+EXPORT_SYMBOL(tcp_v4_init_sock); | ||
+ | ||
void tcp_v4_destroy_sock(struct sock *sk) | ||
{ | ||
struct tcp_sock *tp = tcp_sk(sk); |