Skip to content
Permalink
Browse files Browse the repository at this point in the history
NetKVM: BZ#1169718: More rigoruous testing of incoming packet
Signed-off-by: Joseph Hindin <yhindin@rehat.com>
  • Loading branch information
Joseph Hindin authored and vrozenfe committed Dec 19, 2014
1 parent 7410b96 commit fbfa4d1
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 12 deletions.
10 changes: 8 additions & 2 deletions NetKVM/Common/ParaNdis-Common.cpp
Expand Up @@ -2222,11 +2222,10 @@ tChecksumCheckResult ParaNdis_CheckRxChecksum(
ULONG ulDataOffset)
{
tOffloadSettingsFlags f = pContext->Offload.flags;
tChecksumCheckResult res, resIp;
tChecksumCheckResult res;
tTcpIpPacketParsingResult ppr;
ULONG flagsToCalculate = 0;
res.value = 0;
resIp.value = 0;

//VIRTIO_NET_HDR_F_NEEDS_CSUM - we need to calculate TCP/UDP CS
//VIRTIO_NET_HDR_F_DATA_VALID - host tells us TCP/UDP CS is OK
Expand All @@ -2250,6 +2249,13 @@ tChecksumCheckResult ParaNdis_CheckRxChecksum(

ppr = ParaNdis_CheckSumVerify(pPacketPages, ulPacketLength - ETH_HEADER_SIZE, ulDataOffset + ETH_HEADER_SIZE, flagsToCalculate, __FUNCTION__);

if (ppr.ipCheckSum == ppresIPTooShort || ppr.xxpStatus == ppresXxpIncomplete)
{
res.flags.IpOK = FALSE;
res.flags.IpFailed = TRUE;
return res;
}

if (virtioFlags & VIRTIO_NET_HDR_F_DATA_VALID)
{
pContext->extraStatistics.framesRxCSHwOK++;
Expand Down
50 changes: 40 additions & 10 deletions NetKVM/Common/sw-offload.cpp
Expand Up @@ -156,19 +156,21 @@ ProcessTCPHeader(tTcpIpPacketParsingResult _res, PVOID pIpHeader, ULONG len, USH
ULONG tcpipDataAt;
tTcpIpPacketParsingResult res = _res;
tcpipDataAt = ipHeaderSize + sizeof(TCPHeader);
res.xxpStatus = ppresXxpIncomplete;
res.TcpUdp = ppresIsTCP;

if (len >= tcpipDataAt)
{
TCPHeader *pTcpHeader = (TCPHeader *)RtlOffsetToPointer(pIpHeader, ipHeaderSize);
res.xxpStatus = ppresXxpKnown;
res.xxpFull = TRUE;
tcpipDataAt = ipHeaderSize + TCP_HEADER_LENGTH(pTcpHeader);
res.XxpIpHeaderSize = tcpipDataAt;
}
else
{
DPrintf(2, ("tcp: %d < min headers %d\n", len, tcpipDataAt));
res.xxpFull = FALSE;
res.xxpStatus = ppresXxpIncomplete;
}
return res;
}
Expand All @@ -178,42 +180,67 @@ ProcessUDPHeader(tTcpIpPacketParsingResult _res, PVOID pIpHeader, ULONG len, USH
{
tTcpIpPacketParsingResult res = _res;
ULONG udpDataStart = ipHeaderSize + sizeof(UDPHeader);
res.xxpStatus = ppresXxpIncomplete;
res.TcpUdp = ppresIsUDP;
res.XxpIpHeaderSize = udpDataStart;
if (len >= udpDataStart)
{
UDPHeader *pUdpHeader = (UDPHeader *)RtlOffsetToPointer(pIpHeader, ipHeaderSize);
USHORT datagramLength = swap_short(pUdpHeader->udp_length);
res.xxpStatus = ppresXxpKnown;
res.xxpFull = TRUE;
// may be full or not, but the datagram length is known
DPrintf(2, ("udp: len %d, datagramLength %d\n", len, datagramLength));
}
else
{
res.xxpFull = FALSE;
res.xxpStatus = ppresXxpIncomplete;
}
return res;
}

static __inline tTcpIpPacketParsingResult
QualifyIpPacket(IPHeader *pIpHeader, ULONG len)
{
tTcpIpPacketParsingResult res;
res.value = 0;

if (len < 4)
{
res.ipStatus = ppresNotIP;
return res;
}

UCHAR ver_len = pIpHeader->v4.ip_verlen;
UCHAR ip_version = (ver_len & 0xF0) >> 4;
USHORT ipHeaderSize = 0;
USHORT fullLength = 0;
res.value = 0;

if (ip_version == 4)
{
if (len < sizeof(IPv4Header))
{
res.ipStatus = ppresNotIP;
return res;
}
ipHeaderSize = (ver_len & 0xF) << 2;
fullLength = swap_short(pIpHeader->v4.ip_length);
DPrintf(3, ("ip_version %d, ipHeaderSize %d, protocol %d, iplen %d\n",
ip_version, ipHeaderSize, pIpHeader->v4.ip_protocol, fullLength));
DPrintf(3, ("ip_version %d, ipHeaderSize %d, protocol %d, iplen %d, L2 payload length %d\n",
ip_version, ipHeaderSize, pIpHeader->v4.ip_protocol, fullLength, len));

res.ipStatus = (ipHeaderSize >= sizeof(IPv4Header)) ? ppresIPV4 : ppresNotIP;
if (len < ipHeaderSize) res.ipCheckSum = ppresIPTooShort;
if (fullLength) {}
else
if (res.ipStatus == ppresNotIP)
{
DPrintf(2, ("ip v.%d, iplen %d\n", ip_version, fullLength));
return res;
}

if (ipHeaderSize >= fullLength || len < fullLength)
{
DPrintf(2, ("[%s] - truncated packet - ip_version %d, ipHeaderSize %d, protocol %d, iplen %d, L2 payload length %d\n",
ip_version, ipHeaderSize, pIpHeader->v4.ip_protocol, fullLength, len));
res.ipCheckSum = ppresIPTooShort;
return res;
}
}
else if (ip_version == 6)
Expand Down Expand Up @@ -291,7 +318,7 @@ QualifyIpPacket(IPHeader *pIpHeader, ULONG len)
if (res.ipStatus == ppresIPV4)
{
res.ipHeaderSize = ipHeaderSize;
res.xxpFull = len >= fullLength ? 1 : 0;

// bit "more fragments" or fragment offset mean the packet is fragmented
res.IsFragment = (pIpHeader->v4.ip_offset & ~0xC0) != 0;
switch (pIpHeader->v4.ip_protocol)
Expand Down Expand Up @@ -615,6 +642,9 @@ tTcpIpPacketParsingResult ParaNdis_CheckSumVerify(
IPHeader *pIpHeader = (IPHeader *) RtlOffsetToPointer(pDataPages[0].Virtual, ulStartOffset);

tTcpIpPacketParsingResult res = QualifyIpPacket(pIpHeader, ulDataLength);
if (res.ipStatus == ppresNotIP || res.ipCheckSum == ppresIPTooShort)
return res;

if (res.ipStatus == ppresIPV4)
{
if (flags & pcrIpChecksum)
Expand Down

0 comments on commit fbfa4d1

Please sign in to comment.