Browse code

Multi-socket: Fix assert triggered by stale peer-id reuse

Fixed a bug where clients using different transport
protocols (UDP, TCP) could interfere with each other
after a server restart.
The issue occurred when a client reused a previously
assigned peer-id that was now associated with a
different client using a different transport protocol.

For example, a UDP client could send packets with a
peer-id now assigned to a TCP client, which lacks
a valid context->c2.from which is filled by the
recvfrom(), causing an assert to be triggered.

A protocol check has been added to prevent packets
from different protocols from hijacking active
connections.

Github: OpenVPN/openvpn#773

Change-Id: Iecbbcf32c0059f2b16a05333b3794599060d7d6a
Signed-off-by: Gianmarco De Gregori <gianmarco@mandelbit.com>
Acked-by: Gert Doering <gert@greenie.muc.de>
Message-Id: <20250718185559.4515-1-gert@greenie.muc.de>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg32220.html
Signed-off-by: Gert Doering <gert@greenie.muc.de>

Gianmarco De Gregori authored on 2025/07/19 03:55:53
Showing 1 changed files
... ...
@@ -216,16 +216,20 @@ multi_get_create_instance_udp(struct multi_context *m, bool *floated,
216 216
 
217 217
             if (!peer_id_disabled && (peer_id < m->max_clients) && (m->instances[peer_id]))
218 218
             {
219
-                mi = m->instances[peer_id];
220
-
221
-                *floated = !link_socket_actual_match(&mi->context.c2.from, &m->top.c2.from);
222
-
223
-                if (*floated)
219
+                /* Floating on TCP will never be possible, so ensure we only process
220
+                 * UDP clients */
221
+                if (m->instances[peer_id]->context.c2.link_sockets[0]->info.proto == sock->info.proto)
224 222
                 {
225
-                    /* reset prefix, since here we are not sure peer is the one it claims to be */
226
-                    ungenerate_prefix(mi);
227
-                    msg(D_MULTI_MEDIUM, "Float requested for peer %" PRIu32 " to %s", peer_id,
228
-                        mroute_addr_print(&real, &gc));
223
+                    mi = m->instances[peer_id];
224
+                    *floated = !link_socket_actual_match(&mi->context.c2.from, &m->top.c2.from);
225
+
226
+                    if (*floated)
227
+                    {
228
+                        /* reset prefix, since here we are not sure peer is the one it claims to be */
229
+                        ungenerate_prefix(mi);
230
+                        msg(D_MULTI_MEDIUM, "Float requested for peer %" PRIu32 " to %s", peer_id,
231
+                            mroute_addr_print(&real, &gc));
232
+                    }
229 233
                 }
230 234
             }
231 235
         }