{"record":{"id":"2126dfe85a44a98f","repo":"slackhq/nebula","slug":"header-len-d-exceeds-max-d","errorCode":null,"errorMessage":"header len %d exceeds max %d","messagePattern":"header len (.+?) exceeds max (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"overlay/tio/virtio/segment_linux.go","lineNumber":225,"sourceCode":"\treturn sum\n}\n\n// SegmentTCP walks a TSO superpacket pkt, yielding each segment as a slice into pkt.\n// Per-segment plaintext is laid out by stamping a copy of the original L3+L4 header into pkt at offset i*gsoSize,\n// where it sits immediately before that segment's payload chunk in the original buffer.\n// pkt is consumed by this call and must not be inspected by the caller after the final yield.\nfunc SegmentTCP(pkt []byte, hdrLenU, csumStartU, gsoSizeU uint16, yield func(seg []byte) error) error {\n\tif gsoSizeU == 0 {\n\t\treturn fmt.Errorf(\"gso_size is zero\")\n\t}\n\tif csumStartU == 0 {\n\t\treturn fmt.Errorf(\"csum_start is zero\")\n\t}\n\n\theaderLen := int(hdrLenU)\n\tcsumStart := int(csumStartU)\n\tif headerLen > maxSegHdrLen {\n\t\treturn fmt.Errorf(\"header len %d exceeds max %d\", headerLen, maxSegHdrLen)\n\t}\n\tisV4 := pkt[0]>>4 == 4\n\n\ttcpHdrLen := int(pkt[csumStart+tcpDataOffOff]>>4) * 4\n\tpayLen := len(pkt) - headerLen\n\tgsoSize := int(gsoSizeU)\n\tnumSeg := segCount(payLen, gsoSize)\n\n\torigSeq := binary.BigEndian.Uint32(pkt[csumStart+tcpSeqOff : csumStart+tcpSeqOff+4])\n\torigFlags := pkt[csumStart+tcpFlagsOff]\n\n\tbaseProtoSum := basePseudoSum(pkt, isV4, unix.IPPROTO_TCP)\n\tbaseTcpHdrSum := baseTCPHdrSum(pkt, csumStart, headerLen)\n\n\tvar origIPID uint16\n\tvar baseIPHdrSum uint32\n\tif isV4 {\n\t\torigIPID = binary.BigEndian.Uint16(pkt[ipv4IDOff : ipv4IDOff+2])","sourceCodeStart":207,"sourceCodeEnd":243,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/overlay/tio/virtio/segment_linux.go#L207-L243","documentation":"SegmentTCP stamps a copy of the L3+L4 headers in front of every segment. maxSegHdrLen caps how large that per-segment header can be (worst case IPv4/IPv6 plus options plus TCP options). If the caller-supplied hdrLenU exceeds this cap the function refuses rather than write out-of-bounds or misaligned headers.","triggerScenarios":"Calling SegmentTCP with hdrLenU > maxSegHdrLen — e.g. hdrLen was computed from a corrupted header stack, includes payload bytes, or the caller passed len(pkt) instead of the header length.","commonSituations":"Malformed packets with pathological IP option chains; a parsing bug that added the payload length into hdrLen; confusion between hdrLen (L3+L4) and csumStart (L4 offset) values when wiring up the call; raw-captured frames with garbage after the link layer.","solutions":["Pass hdrLenU as the exact L3 header length + TCP header length (csumStart + TCP data offset), not the whole packet length.","Sanity-check hdrLen <= 128 (or the library's maxSegHdrLen) before calling; drop the packet if exceeded as malformed.","Verify IPv4 IHL and TCP data-offset nibbles are within 4..15 when you compute them, otherwise discard the frame upstream.","Confirm you are not double-counting link-layer bytes in hdrLen."],"exampleFix":"// before\nhdrLen := uint16(len(pkt)) // wrong: whole packet\nseg.SegmentTCP(pkt, hdrLen, csumStart, gsoSize, yield)\n// after\ntcpHdrLen := int(pkt[csumStart+tcpDataOffOff]>>4) * 4\nhdrLen := uint16(csumStart + tcpHdrLen)\nif hdrLen > seg.MaxSegHdrLen { return errors.New(\"header too large\") }\nseg.SegmentTCP(pkt, hdrLen, csumStart, gsoSize, yield)","handlingStrategy":"validation","validationCode":"tcpHdrLen := int(pkt[csumStart+12]>>4) * 4\nhdrLen := uint16(csumStart + tcpHdrLen)\nif hdrLen > 128 { // maxSegHdrLen\n    return fmt.Errorf(\"implausible header length %d; dropping\", hdrLen)\n}\nsegmenter.SegmentTCP(pkt, hdrLen, csumStart, gsoSize, yield)","typeGuard":"func plausibleHdrLen(hdrLen uint16) bool { return hdrLen >= 40 && hdrLen <= 128 }","tryCatchPattern":"err := segmenter.SegmentTCP(pkt, hdrLen, csumStart, gsoSize, yield)\nif err != nil {\n    if strings.Contains(err.Error(), \"exceeds max\") {\n        log.Warn(\"oversized segment header; dropping malformed frame\")\n        return nil\n    }\n    return err\n}","preventionTips":["Compute hdrLen as L3 header length + TCP data-offset length, never as the packet length.","Clamp and sanity-check IP IHL and TCP data-offset nibbles (<= 15) during header parsing.","Don't include link-layer or VLAN bytes in hdrLen unless the library expects them.","Treat oversized hdrLen as evidence of corruption and drop the frame upstream."],"tags":["network","tcp","segmentation","header-length","packet-parsing"],"backgroundTag":"header-length-exceeds-max","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"}