From cdf865e0b806d5311208d78c32361c912b1e0534 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 10 Jan 2024 16:54:17 +0100 Subject: [PATCH] kernel-netlink: Handle Netlink sequence number counter overflows gracefully A refcount variable is used to allocate sequential unique identifiers for Netlink sequence numbers, subject to overflows. The risk of an overflow has so far not been considered practical, as it requires 2^32 netlink requests. It seems that this issue is not only theoretical. A host with thousands of tunnels doing aggressive rekeying and/or aggressive status checking (via vici list-sas) may trigger the overflow after a few weeks uptime. The consequences are rather devastating: Once the refcount overflows, a Netlink request is sent with sequence number 0. This request is answered by the kernel, but can't be matched to the request, resulting in the error: "received unknown netlink seq 0, ignored". Without Netlink timeouts, the thread indefinitely waits for a response while holding the Netlink mutex, bringing all threads to a halt. So at all costs avoid zero sequence numbers. Also, start at sequence number 1 instead of the arbitrary 201, so the same range is used on start and after an overflow. --- src/libcharon/plugins/kernel_netlink/kernel_netlink_shared.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_shared.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_shared.c index 72c13a697..339d0b9e6 100644 --- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_shared.c +++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_shared.c @@ -514,7 +514,7 @@ METHOD(netlink_socket_t, netlink_send, status_t, uintptr_t seq; u_int try; - seq = ref_get(&this->seq); + seq = ref_get_nonzero(&this->seq); for (try = 0; try <= this->retries; ++try) { @@ -694,7 +694,6 @@ netlink_socket_t *netlink_socket_create(int protocol, enum_name_t *names, .send_ack = _netlink_send_ack, .destroy = _destroy, }, - .seq = 200, .mutex = mutex_create(MUTEX_TYPE_RECURSIVE), .socket = socket(AF_NETLINK, SOCK_RAW, protocol), .entries = hashtable_create(hashtable_hash_ptr, hashtable_equals_ptr, 4),