From 7272127927119fc4eb4a79704d5520f7cb5a0c3b Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Tue, 11 May 2021 22:18:19 +0200 Subject: [PATCH] Kernel: Don't process TCP packets out of order Previously we'd process TCP packets in whatever order we received them in. In the case where packets arrived out of order we'd end up passing garbage to the userspace process. This was most evident for TLS connections: courage:~ $ git clone https://github.com/SerenityOS/serenity Cloning into 'serenity'... remote: Enumerating objects: 178826, done. remote: Counting objects: 100% (1880/1880), done. remote: Compressing objects: 100% (907/907), done. error: RPC failed; curl 56 OpenSSL SSL_read: error:1408F119:SSL routines:SSL3_GET_RECORD:decryption failed or bad record mac, errno 0 error: 1918 bytes of body are still expected fetch-pack: unexpected disconnect while reading sideband packet fatal: early EOF fatal: fetch-pack: invalid index-pack output --- Kernel/Net/NetworkTask.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/Kernel/Net/NetworkTask.cpp b/Kernel/Net/NetworkTask.cpp index 92954ff456..7484f297e3 100644 --- a/Kernel/Net/NetworkTask.cpp +++ b/Kernel/Net/NetworkTask.cpp @@ -531,6 +531,11 @@ void handle_tcp(const IPv4Packet& ipv4_packet, const Time& packet_timestamp) return; } + if (tcp_packet.sequence_number() != socket->ack_number()) { + dbgln_if(TCP_DEBUG, "Discarding out of order packet: seq {} vs. ack {}", tcp_packet.sequence_number(), socket->ack_number()); + return; + } + if (tcp_packet.has_fin()) { if (payload_size != 0) socket->did_receive(ipv4_packet.source(), tcp_packet.source_port(), { &ipv4_packet, sizeof(IPv4Packet) + ipv4_packet.payload_size() }, packet_timestamp); @@ -542,14 +547,13 @@ void handle_tcp(const IPv4Packet& ipv4_packet, const Time& packet_timestamp) return; } - socket->set_ack_number(tcp_packet.sequence_number() + payload_size); - - dbgln_if(TCP_DEBUG, "Got packet with ack_no={}, seq_no={}, payload_size={}, acking it with new ack_no={}, seq_no={}", - tcp_packet.ack_number(), tcp_packet.sequence_number(), payload_size, socket->ack_number(), socket->sequence_number()); - if (payload_size) { - if (socket->did_receive(ipv4_packet.source(), tcp_packet.source_port(), { &ipv4_packet, sizeof(IPv4Packet) + ipv4_packet.payload_size() }, packet_timestamp)) + if (socket->did_receive(ipv4_packet.source(), tcp_packet.source_port(), { &ipv4_packet, sizeof(IPv4Packet) + ipv4_packet.payload_size() }, packet_timestamp)) { + socket->set_ack_number(tcp_packet.sequence_number() + payload_size); + dbgln_if(TCP_DEBUG, "Got packet with ack_no={}, seq_no={}, payload_size={}, acking it with new ack_no={}, seq_no={}", + tcp_packet.ack_number(), tcp_packet.sequence_number(), payload_size, socket->ack_number(), socket->sequence_number()); unused_rc = socket->send_tcp_packet(TCPFlags::ACK); + } } } }