Skip to content

Commit

Permalink
Merge pull request #1119 from dorssel/pcapng_unchecked
Browse files Browse the repository at this point in the history
Fix PcapNg unchecked overflow
  • Loading branch information
dorssel authored Jan 27, 2025
2 parents c19b90f + 36c9f72 commit b2e1eb1
Showing 1 changed file with 23 additions and 14 deletions.
37 changes: 23 additions & 14 deletions Usbipd/PcapNg.cs
Original file line number Diff line number Diff line change
Expand Up @@ -236,11 +236,14 @@ public void DumpPacketIsoReply(UsbIpHeaderBasic basic, UsbIpHeaderCmdSubmit cmdS
static void UpdateChecksum(ref ushort checksum, byte[] data, int offset)
{
var v = BinaryPrimitives.ReadUInt16BigEndian(data.AsSpan(offset, 2));
if ((uint)checksum + v > ushort.MaxValue)
unchecked
{
++checksum;
if ((uint)checksum + v > ushort.MaxValue)
{
++checksum;
}
checksum += v;
}
checksum += v;
}

static readonly IPEndPoint hostFakeIpv4 = new(IPAddress.Parse("10.0.0.0"), USBIP_PORT);
Expand Down Expand Up @@ -269,7 +272,7 @@ public void DumpPacketUnlink(BusId busId, bool reply, UsbIpHeader header)
// IPv4 header
ipv4.Write((byte)0x45); // Version 4, header_size = 5 * sizeof(uint)
ipv4.Write((byte)0); // DSCP/ECN (unused)
ipv4.Write(IPAddress.HostToNetworkOrder((short)(20 + 20 + Unsafe.SizeOf<UsbIpHeader>()))); // IPv4 header + TCP header + UsbIpHeader
ipv4.Write(IPAddress.HostToNetworkOrder(unchecked((short)(20 + 20 + Unsafe.SizeOf<UsbIpHeader>())))); // IPv4 header + TCP header + UsbIpHeader
ipv4.Write((ushort)0); // Id (unused)
ipv4.Write((ushort)0); // Flags/Offset (unused)
ipv4.Write((byte)255); // TTL
Expand All @@ -279,8 +282,8 @@ public void DumpPacketUnlink(BusId busId, bool reply, UsbIpHeader header)
ipv4.Write(destination.Address.GetAddressBytes()); // destination IP address

// TCP header
ipv4.Write(IPAddress.HostToNetworkOrder((short)source.Port)); // source port
ipv4.Write(IPAddress.HostToNetworkOrder((short)destination.Port)); // destination port
ipv4.Write(IPAddress.HostToNetworkOrder(unchecked((short)source.Port))); // source port
ipv4.Write(IPAddress.HostToNetworkOrder(unchecked((short)destination.Port))); // destination port
ipv4.Write(0); // sequence number (unused)
ipv4.Write(0); // ACK number (unused)
ipv4.Write((byte)0x50); // data offset (in uint_32), 0 (reserved)
Expand All @@ -301,7 +304,7 @@ public void DumpPacketUnlink(BusId busId, bool reply, UsbIpHeader header)
{
UpdateChecksum(ref checksum, bytes, offset);
}
BinaryPrimitives.WriteUInt16BigEndian(bytes.AsSpan(10, 2), (ushort)~checksum);
BinaryPrimitives.WriteUInt16BigEndian(bytes.AsSpan(10, 2), unchecked((ushort)~checksum));
}

// TCP checksum
Expand All @@ -324,7 +327,7 @@ public void DumpPacketUnlink(BusId busId, bool reply, UsbIpHeader header)
// zeros / protocol / TCP Length
UpdateChecksum(ref checksum, bytes, offset);
}
BinaryPrimitives.WriteUInt16BigEndian(bytes.AsSpan(36, 2), (ushort)~checksum);
BinaryPrimitives.WriteUInt16BigEndian(bytes.AsSpan(36, 2), unchecked((ushort)~checksum));
}

BlockChannel.Writer.WriteAsync(CreateEnhancedPacketBlock(1, bytes)).AsTask().Wait();
Expand Down Expand Up @@ -397,6 +400,12 @@ ulong GetTimestamp()
return TimestampBase + (ulong)Stopwatch.Elapsed.Ticks;
}

static byte[] TimestampToBytes(ulong value)
{
// timestamps are written high 32-bits first, irrespective of endianness
return [.. BitConverter.GetBytes((uint)(value >> 32)), .. BitConverter.GetBytes(unchecked((uint)value))];
}

static void AddOption(BinaryWriter block, ushort code, byte[] data)
{
Pad(block);
Expand Down Expand Up @@ -469,8 +478,8 @@ byte[] CreateEnhancedPacketBlock(uint interfaceId, byte[] data)

using var block = CreateBlock(6);
block.Write(interfaceId);
block.Write((uint)(timestamp >> 32));
block.Write((uint)timestamp);
// timestamps are written high 32-bits first, irrespective of endianness
block.Write(TimestampToBytes(timestamp));
block.Write(captureLength); // captured packet length
block.Write(data.Length); // original packet length
block.Write(data[0..captureLength]);
Expand All @@ -483,10 +492,10 @@ byte[] CreateInterfaceStatisticsBlock()

using var block = CreateBlock(5);
block.Write(0); // interface ID
block.Write((uint)(timestamp >> 32));
block.Write((uint)timestamp);
AddOption(block, 2, [.. BitConverter.GetBytes((uint)(TimestampBase >> 32)), .. BitConverter.GetBytes((uint)TimestampBase)]); // isb_starttime
AddOption(block, 3, [.. BitConverter.GetBytes((uint)(timestamp >> 32)), .. BitConverter.GetBytes((uint)timestamp)]); // isb_endtime
// timestamps are written high 32-bits first, irrespective of endianness
block.Write(TimestampToBytes(timestamp));
AddOption(block, 2, TimestampToBytes(TimestampBase)); // isb_starttime
AddOption(block, 3, TimestampToBytes(timestamp)); // isb_endtime
AddOption(block, 4, TotalPacketsWritten); // isb_ifrecv
AddOption(block, 5, 0ul); // isb_ifdrop
AddOption(block, 6, TotalPacketsWritten); // isb_filteraccept
Expand Down

0 comments on commit b2e1eb1

Please sign in to comment.