{"record":{"id":"a1504ae9f97585b9","repo":"slackhq/nebula","slug":"errpackettooshort-a1504a","errorCode":"errPacketTooShort","errorMessage":"packet too short","messagePattern":"packet too short","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"overlay/tio/virtio/segment_linux.go","lineNumber":65,"sourceCode":"\tipv6AddrsEnd      = 40 // end of dst address (ipv6SrcOff + 2*16)\n)\n\n// Byte offsets inside a TCP header (relative to its start, i.e. csumStart).\nconst (\n\ttcpSeqOff      = 4\n\ttcpDataOffOff  = 12 // upper nibble is header len in 32-bit words\n\ttcpFlagsOff    = 13\n\ttcpChecksumOff = 16\n)\n\n// UDP header is fixed at 8 bytes: {sport, dport, length, checksum}.\nconst (\n\tudpHeaderLen   = 8\n\tudpLengthOff   = 4\n\tudpChecksumOff = 6\n)\n\nvar errPacketTooShort = errors.New(\"packet too short\")\n\n// tcpFinPshMask is cleared on every segment except the last of a TSO burst.\nconst tcpFinPshMask = 0x09 // FIN(0x01) | PSH(0x08)\n\n// tcpCwrFlag is cleared on every segment except the first.\n// Per RFC 3168 §6.1.2 the CWR bit signals a one-shot transition (the sender just halved its window)\n// and must appear on the first segment of a TSO burst only.\nconst tcpCwrFlag = 0x80\n\n// CheckValid rejects packets whose virtio_net_hdr/IP combination would\n// cause a downstream miscompute. The TUN should never emit RSC_INFO and\n// the GSO type must agree with the IP version nibble.\nfunc CheckValid(pkt []byte, hdr Hdr) error {\n\tif hdr.Flags&unix.VIRTIO_NET_HDR_F_RSC_INFO != 0 {\n\t\treturn fmt.Errorf(\"virtio RSC_INFO flag not supported on TUN reads\")\n\t}\n\tif len(pkt) < ipv4HeaderMinLen {\n\t\treturn errPacketTooShort","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/overlay/tio/virtio/segment_linux.go#L47-L83","documentation":"errPacketTooShort is returned by CheckValid in the virtio TSO segmentation code when a packet is shorter than the minimum IPv4 header length, or is IPv6 but shorter than the fixed IPv6 header (40 bytes), so header fields cannot be read safely during segmentation. It protects the TSO segmenter from out-of-bounds reads.","triggerScenarios":"CheckValid(pkt) is called with len(pkt) < ipv4HeaderMinLen, or with IP version 6 (pkt[0]>>4 == 6) and len(pkt) < ipv6FixedLen. This happens when the host hands the virtio ring a malformed/truncated packet marked for GSO/TSO segmentation.","commonSituations":"Guest driver bugs emitting short descriptors; corrupted virtio ring entries; packets truncated by MTU/mergeable-buffer misconfiguration; fuzzing or hostile guests sending malformed frames to the vhost device.","solutions":["Drop the offending packet and increment a malformed-packet counter rather than attempting segmentation.","Validate packet length before passing it to the TSO path; only segment packets with complete IP headers.","Check virtio guest driver version/mergeable Rx buffer negotiation — mismatches can produce short buffers.","Audit vring buffer sizes vs MTU to ensure a full max-size frame always fits in one descriptor chain.","If it comes from a hypervisor/guest update, roll back or fix the emitting driver."],"exampleFix":"// before: assume all ring packets are segmentable\nfor _, pkt := range pkts {\n    if err := seg.CheckValid(pkt); err != nil {\n        return err\n    }\n}\n// after: skip and count short packets\nfor _, pkt := range pkts {\n    if err := seg.CheckValid(pkt); err != nil {\n        if errors.Is(err, errPacketTooShort) {\n            stats.Malformed++\n            continue\n        }\n        return err\n    }\n}","handlingStrategy":"validation","validationCode":"func canSegment(pkt []byte) bool {\n    if len(pkt) < ipv4HeaderMinLen {\n        return false\n    }\n    if v := pkt[0] >> 4; v == 6 {\n        return len(pkt) >= ipv6FixedLen\n    } else if v != 4 {\n        return false\n    }\n    return true\n}\nif !canSegment(pkt) {\n    stats.Malformed++\n    return // skip CheckValid/segmentation\n}","typeGuard":null,"tryCatchPattern":"if err := seg.CheckValid(pkt); err != nil {\n    if errors.Is(err, errPacketTooShort) {\n        stats.Malformed++\n        return nil // drop, keep processing ring\n    }\n    return err\n}","preventionTips":["Length-check packets against ipv4HeaderMinLen/ipv6FixedLen before the TSO path.","Verify virtio mergeable-buffer and GSO negotiation with the guest driver.","Size vring descriptor chains to fit full max-MTU frames.","Drop-and-count malformed frames instead of failing the whole Rx loop."],"tags":["linux","virtio","tso","packet-parsing","network"],"backgroundTag":"packet-too-short","analyzedSha":"dd8f660c0ac37903ec4080ca4d3c861ba9342ceb","analyzedAt":"2026-09-03T11:13:55.444Z","contentChangedAt":"2026-09-03T11:13:55.444Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}