1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 12:28:12 +00:00

Kernel: Convert TCP pseudo-headers through a union

This keeps us from tripping strict aliasing, which previously made TCP
connections inoperable when building without `-fsanitize=undefined` or
`-fno-strict-aliasing`.
This commit is contained in:
Tim Schumacher 2022-12-12 17:52:00 +01:00 committed by Linus Groh
parent 7cd99572be
commit 24f956c739

View file

@ -360,31 +360,35 @@ bool TCPSocket::should_delay_next_ack() const
NetworkOrdered<u16> TCPSocket::compute_tcp_checksum(IPv4Address const& source, IPv4Address const& destination, TCPPacket const& packet, u16 payload_size) NetworkOrdered<u16> TCPSocket::compute_tcp_checksum(IPv4Address const& source, IPv4Address const& destination, TCPPacket const& packet, u16 payload_size)
{ {
struct [[gnu::packed]] PseudoHeader { union PseudoHeader {
IPv4Address source; struct [[gnu::packed]] {
IPv4Address destination; IPv4Address source;
u8 zero; IPv4Address destination;
u8 protocol; u8 zero;
NetworkOrdered<u16> payload_size; u8 protocol;
NetworkOrdered<u16> payload_size;
} header;
u16 raw[6];
}; };
static_assert(sizeof(PseudoHeader) == 12);
PseudoHeader pseudo_header { source, destination, 0, (u8)IPv4Protocol::TCP, packet.header_size() + payload_size }; PseudoHeader pseudo_header { .header = { source, destination, 0, (u8)IPv4Protocol::TCP, packet.header_size() + payload_size } };
u32 checksum = 0; u32 checksum = 0;
auto raw_pseudo_header = bit_cast<u16*>(&pseudo_header); auto* raw_pseudo_header = pseudo_header.raw;
for (size_t i = 0; i < sizeof(pseudo_header) / sizeof(u16); ++i) { for (size_t i = 0; i < sizeof(pseudo_header) / sizeof(u16); ++i) {
checksum += AK::convert_between_host_and_network_endian(raw_pseudo_header[i]); checksum += AK::convert_between_host_and_network_endian(raw_pseudo_header[i]);
if (checksum > 0xffff) if (checksum > 0xffff)
checksum = (checksum >> 16) + (checksum & 0xffff); checksum = (checksum >> 16) + (checksum & 0xffff);
} }
auto raw_packet = bit_cast<u16*>(&packet); auto* raw_packet = bit_cast<u16*>(&packet);
for (size_t i = 0; i < packet.header_size() / sizeof(u16); ++i) { for (size_t i = 0; i < packet.header_size() / sizeof(u16); ++i) {
checksum += AK::convert_between_host_and_network_endian(raw_packet[i]); checksum += AK::convert_between_host_and_network_endian(raw_packet[i]);
if (checksum > 0xffff) if (checksum > 0xffff)
checksum = (checksum >> 16) + (checksum & 0xffff); checksum = (checksum >> 16) + (checksum & 0xffff);
} }
VERIFY(packet.data_offset() * 4 == packet.header_size()); VERIFY(packet.data_offset() * 4 == packet.header_size());
auto raw_payload = bit_cast<u16*>(packet.payload()); auto* raw_payload = bit_cast<u16*>(packet.payload());
for (size_t i = 0; i < payload_size / sizeof(u16); ++i) { for (size_t i = 0; i < payload_size / sizeof(u16); ++i) {
checksum += AK::convert_between_host_and_network_endian(raw_payload[i]); checksum += AK::convert_between_host_and_network_endian(raw_payload[i]);
if (checksum > 0xffff) if (checksum > 0xffff)