]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
kernel-netlink: Handle Netlink sequence number counter overflows gracefully
authorMartin Willi <martin@strongswan.org>
Wed, 10 Jan 2024 15:54:17 +0000 (16:54 +0100)
committerMartin Willi <martin@strongswan.org>
Fri, 16 Feb 2024 09:11:11 +0000 (10:11 +0100)
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

index 72c13a69787da8aeeac2fb23b29a08d995c9c01b..339d0b9e6ca6b7436f8bfc4d93693efb20012ad8 100644 (file)
@@ -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),