Commit dd6da24822 for strongswan.org
commit dd6da24822dc5022471a334d22209060bf660d4d
Author: Tobias Brunner <tobias@strongswan.org>
Date: Mon Nov 9 14:12:48 2026 +0100
kernel-netlink: Explicitly reject non-kernel responses
A privileged process could theoretically inject responses. As only the
kernel can send messages from `nl_pid` 0, this check prevents that.
Also fixed the error handling where the comparison converted `-1` to
`size_t` and previously caused an error to trigger the "exceeds buffer
size" path (no behavior change other than the log message).
diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_shared.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_shared.c
index a38f6bd8a2..59b107fc1d 100644
--- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_shared.c
+++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_shared.c
@@ -234,6 +234,8 @@ static bool write_msg(private_netlink_socket_t *this, struct nlmsghdr *msg)
static ssize_t read_msg(private_netlink_socket_t *this,
char *buf, size_t buflen, bool block)
{
+ struct sockaddr_nl addr = {};
+ socklen_t addr_len = sizeof(addr);
ssize_t len;
if (block)
@@ -251,12 +253,9 @@ static ssize_t read_msg(private_netlink_socket_t *this,
return -1;
}
}
- len = recv(this->socket, buf, buflen, MSG_TRUNC|(block ? 0 : MSG_DONTWAIT));
- if (len > buflen)
- {
- DBG1(DBG_KNL, "netlink response exceeds buffer size");
- return 0;
- }
+ len = recvfrom(this->socket, buf, buflen,
+ MSG_TRUNC|(block ? 0 : MSG_DONTWAIT),
+ (struct sockaddr*)&addr, &addr_len);
if (len < 0)
{
if (errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR)
@@ -265,6 +264,15 @@ static ssize_t read_msg(private_netlink_socket_t *this,
}
return 0;
}
+ else if (len > buflen)
+ {
+ DBG1(DBG_KNL, "netlink response exceeds buffer size");
+ return 0;
+ }
+ else if (addr.nl_pid != 0)
+ { /* ignore non-kernel messages */
+ return 0;
+ }
return len;
}
@@ -748,7 +756,7 @@ CALLBACK(watch_event, bool,
{
char buf[this->buflen];
struct nlmsghdr *hdr = (struct nlmsghdr*)buf;
- struct sockaddr_nl addr;
+ struct sockaddr_nl addr = {};
socklen_t addr_len = sizeof(addr);
int len;