{"record":{"id":"4e676d0439f31237","repo":"slackhq/nebula","slug":"csum-start-is-zero","errorCode":null,"errorMessage":"csum_start is zero","messagePattern":"csum_start is zero","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"overlay/tio/virtio/segment_linux.go","lineNumber":219,"sourceCode":"\tsum += uint32(^uint16(seq >> 16))\n\tsum += uint32(^uint16(seq))\n\tsum += uint32(^flags)\n\tsum += uint32(^binary.BigEndian.Uint16(pkt[csumStart+tcpChecksumOff : csumStart+tcpChecksumOff+2]))\n\tsum = (sum & 0xffff) + (sum >> 16)\n\tsum = (sum & 0xffff) + (sum >> 16)\n\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)","sourceCodeStart":201,"sourceCodeEnd":237,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/overlay/tio/virtio/segment_linux.go#L201-L237","documentation":"SegmentTCP uses csumStart as the offset of the L4 (TCP) header within each stamped segment and to bound a valid IPv4 IHL. csum_start == 0 would place the TCP header at offset 0, overlapping the L3 header, which is never valid; the function rejects it immediately.","triggerScenarios":"Calling SegmentTCP with csumStartU == 0 — the virtio-net header's csum_start field was 0 (packet is not a partially-checksummed/GSO packet), or the caller passed a zero-valued struct field by mistake.","commonSituations":"Routing non-offload packets into the segmentation path; zeroed virtio-net header because checksum offload wasn't negotiated; wrong struct layout/endianness when parsing the header; passing literal 0 as a placeholder for 'no offload'.","solutions":["Only call SegmentTCP for packets whose virtio-net header has VIRTIO_NET_HDR_F_NEEDS_CSUM set (csum_start > 0); otherwise handle the packet normally.","Check that csum_start is read at the correct offset and byte order from the virtio-net header.","Validate hdrLen < csumStart <= len(pkt)-TCP header before the call.","If constructing headers yourself, set csum_start to the actual L4 offset (e.g. 20 for plain IPv4+TCP)."],"exampleFix":"// before\nseg.SegmentTCP(pkt, hdrLen, 0, gsoSize, yield) // placeholder csum_start\n// after\nif !gsoHdr.NeedsCsum || gsoHdr.CsumStart == 0 {\n    return errors.New(\"packet has no checksum offload metadata\")\n}\nseg.SegmentTCP(pkt, hdrLen, gsoHdr.CsumStart, gsoHdr.GsoSize, yield)","handlingStrategy":"validation","validationCode":"if gsoHdr.CsumStart == 0 || gsoHdr.CsumStart <= gsoHdr.HdrLen {\n    // not a needs-csum packet; do not call SegmentTCP\n    return handleWithoutOffload(pkt)\n}","typeGuard":"func needsCsum(vhdr VirtioNetHdr) bool { return vhdr.CsumStart > 0 && vhdr.GsoSize > 0 }","tryCatchPattern":"err := segmenter.SegmentTCP(pkt, hdrLen, csumStart, gsoSize, yield)\nif err != nil {\n    if strings.Contains(err.Error(), \"csum_start is zero\") {\n        return errors.New(\"packet lacks checksum-offload metadata; use normal TX path\")\n    }\n    return err\n}","preventionTips":["Gate segmentation on the VIRTIO_NET_HDR_F_NEEDS_CSUM flag, not on raw field values.","Read csum_start at the correct offset/endianness from the virtio-net header.","Never pass 0 as a placeholder csumStart; compute it from the actual L4 offset.","Log-and-drop packets with csum_start == 0 at the RX boundary instead of pushing them downstream."],"tags":["network","tcp","offload","segmentation","packet-parsing"],"backgroundTag":"csum-start-zero","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"}