[PATCH net-next] af-packet: new flag to indicate all csums are good

From: Victor Julien
Date: Mon Jun 01 2020 - 16:55:32 EST

Introduce a new flag (TP_STATUS_CSUM_UNNECESSARY) to indicate
that the driver has completely validated the checksums in the packet.

The flag differs from TP_STATUS_CSUM_VALID in that it will only
be set if all the layers are valid, while TP_STATUS_CSUM_VALID is
set as well if only the IP layer is valid.

The name is derived from the skb->ip_summed setting CHECKSUM_UNNECESSARY.

Security tools such as Suricata, Snort, Zeek/Bro need to know not
only that a packet has not been corrupted, but also that the
checksums are correct. Without this an attacker could send a packet,
for example a TCP RST packet, that would be accepted by the
security tool, but rejected by the end host.

To avoid this scenario tools will have to (re)calcultate/validate
the checksum as well.

This patch has been tested with Suricata with the virtio driver,
where it reduced the ammount of time spent in the Suricata TCP
checksum validation to about half.

Signed-off-by: Victor Julien <victor@xxxxxxxxxxxx>
Documentation/networking/packet_mmap.rst | 6 ++++++
include/uapi/linux/if_packet.h | 1 +
net/packet/af_packet.c | 3 +++
3 files changed, 10 insertions(+)

diff --git a/Documentation/networking/packet_mmap.rst b/Documentation/networking/packet_mmap.rst
index 6c009ceb1183..f670292e6d95 100644
--- a/Documentation/networking/packet_mmap.rst
+++ b/Documentation/networking/packet_mmap.rst
@@ -472,6 +472,12 @@ TP_STATUS_CSUM_VALID This flag indicates that at least the transport
validated on the kernel side. If the flag is not set
then we are free to check the checksum by ourselves
provided that TP_STATUS_CSUMNOTREADY is also not set.
+TP_STATUS_CSUM_UNNECESSARY This flag indicates that the driver validated all
+ the packets csums. If it is not set it might be that
+ the driver doesn't support this, or that one of the
+ layers csums is bad. TP_STATUS_CSUM_VALID may still
+ be set if the transport layer csum is correct or
+ if the driver supports only this mode.
====================== =======================================================

for convenience there are also the following defines::
diff --git a/include/uapi/linux/if_packet.h b/include/uapi/linux/if_packet.h
index 3d884d68eb30..76a5c762e2e0 100644
--- a/include/uapi/linux/if_packet.h
+++ b/include/uapi/linux/if_packet.h
@@ -113,6 +113,7 @@ struct tpacket_auxdata {
#define TP_STATUS_BLK_TMO (1 << 5)
#define TP_STATUS_VLAN_TPID_VALID (1 << 6) /* auxdata has valid tp_vlan_tpid */
#define TP_STATUS_CSUM_VALID (1 << 7)

/* Tx ring - header status */
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 29bd405adbbd..5dd8bad9bc23 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -2215,6 +2215,9 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,

if (skb->ip_summed == CHECKSUM_PARTIAL)
+ else if (skb->pkt_type != PACKET_OUTGOING &&
+ skb->ip_summed == CHECKSUM_UNNECESSARY)
else if (skb->pkt_type != PACKET_OUTGOING &&
(skb->ip_summed == CHECKSUM_COMPLETE ||