From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: passt.top; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: passt.top; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=IUzkujZk; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by passt.top (Postfix) with ESMTPS id DDBB05A0269 for ; Wed, 13 May 2026 13:52:40 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1778673159; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=vkHHlB/0vFX/6JZW3VNo9dl1ypMsk2lYhUAJ1UADLw4=; b=IUzkujZkHB9vSuhOMBXyRLuWpEmGVsAmr4zVNgi3djUViA1U3wr4UieK9PqHw4ELmBE67o 5dc6S9qWYtVMjzFP9nv+/m6teG0SBDdVOEv+k7NtfXENS4A4gry675XBO0bHfVSCEBaXj5 1iAXvvqSYtjnsAWx+7YB24njsb0kpvU= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-592-Ak6DZtZWPkWNiInQ-opQiw-1; Wed, 13 May 2026 07:52:36 -0400 X-MC-Unique: Ak6DZtZWPkWNiInQ-opQiw-1 X-Mimecast-MFC-AGG-ID: Ak6DZtZWPkWNiInQ-opQiw_1778673156 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 7598D195609F; Wed, 13 May 2026 11:52:35 +0000 (UTC) Received: from lenovo-t14s.redhat.corp (headnet01.pony-001.prod.iad2.dc.redhat.com [10.2.32.101]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id AD2771955D84; Wed, 13 May 2026 11:52:33 +0000 (UTC) From: Laurent Vivier To: passt-dev@passt.top Subject: [PATCH v4 06/10] checksum: Pass explicit L4 length to checksum functions Date: Wed, 13 May 2026 13:52:14 +0200 Message-ID: <20260513115218.1662850-7-lvivier@redhat.com> In-Reply-To: <20260513115218.1662850-1-lvivier@redhat.com> References: <20260513115218.1662850-1-lvivier@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: vE6Ld-FHQOEQXugheqd4eg_JwxvlEFGwmLPWszXAsxU_1778673156 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: 8bit content-type: text/plain; charset="US-ASCII"; x-default=true Message-ID-Hash: NQXRWBNC2TCR4TLBOD27ZS55JOG6GX64 X-Message-ID-Hash: NQXRWBNC2TCR4TLBOD27ZS55JOG6GX64 X-MailFrom: lvivier@redhat.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Laurent Vivier , David Gibson , Jon Maloy X-Mailman-Version: 3.3.8 Precedence: list List-Id: Development discussion and patches for passt Archived-At: Archived-At: List-Archive: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: The iov_tail passed to csum_iov_tail() may contain padding or trailing data beyond the actual L4 payload. Rather than relying on iov_tail_size() to determine how many bytes to checksum, pass the length explicitly so that only the relevant payload bytes are included in the checksum computation. Signed-off-by: Laurent Vivier Reviewed-by: David Gibson Reviewed-by: Jon Maloy --- checksum.c | 43 +++++++++++++++++++++++++------------------ checksum.h | 6 +++--- tap.c | 4 ++-- tcp.c | 12 +++++++----- udp.c | 5 +++-- udp_vu.c | 21 +++++++++------------ 6 files changed, 49 insertions(+), 42 deletions(-) diff --git a/checksum.c b/checksum.c index 828f9ecc9c02..7c62e42d6d4c 100644 --- a/checksum.c +++ b/checksum.c @@ -182,21 +182,22 @@ static uint16_t csum(const void *buf, size_t len, uint32_t init) * @saddr: IPv4 source address * @daddr: IPv4 destination address * @data: UDP payload (as IO vector tail) + * @dlen: UDP payload length */ void csum_udp4(struct udphdr *udp4hr, struct in_addr saddr, struct in_addr daddr, - struct iov_tail *data) + struct iov_tail *data, size_t dlen) { /* UDP checksums are optional, so don't bother */ udp4hr->check = 0; if (UDP4_REAL_CHECKSUMS) { - uint16_t l4len = iov_tail_size(data) + sizeof(struct udphdr); - uint32_t psum = proto_ipv4_header_psum(l4len, IPPROTO_UDP, - saddr, daddr); + uint32_t psum = proto_ipv4_header_psum(sizeof(*udp4hr) + dlen, + IPPROTO_UDP, saddr, + daddr); - psum = csum_unfolded(udp4hr, sizeof(struct udphdr), psum); - udp4hr->check = csum_iov_tail(data, psum); + psum = csum_unfolded(udp4hr, sizeof(*udp4hr), psum); + udp4hr->check = csum_iov_tail(data, psum, dlen); } } @@ -245,19 +246,19 @@ uint32_t proto_ipv6_header_psum(uint16_t payload_len, uint8_t protocol, * @saddr: Source address * @daddr: Destination address * @data: UDP payload (as IO vector tail) + * @dlen: UDP payload length */ void csum_udp6(struct udphdr *udp6hr, const struct in6_addr *saddr, const struct in6_addr *daddr, - struct iov_tail *data) + struct iov_tail *data, size_t dlen) { - uint16_t l4len = iov_tail_size(data) + sizeof(struct udphdr); - uint32_t psum = proto_ipv6_header_psum(l4len, IPPROTO_UDP, - saddr, daddr); + uint32_t psum = proto_ipv6_header_psum(dlen + sizeof(*udp6hr), + IPPROTO_UDP, saddr, daddr); udp6hr->check = 0; - psum = csum_unfolded(udp6hr, sizeof(struct udphdr), psum); - udp6hr->check = csum_iov_tail(data, psum); + psum = csum_unfolded(udp6hr, sizeof(*udp6hr), psum); + udp6hr->check = csum_iov_tail(data, psum, dlen); } /** @@ -604,20 +605,26 @@ uint32_t csum_unfolded(const void *buf, size_t len, uint32_t init) /** * csum_iov_tail() - Calculate unfolded checksum for the tail of an IO vector * @tail: IO vector tail to checksum - * @init Initial 32-bit checksum, 0 for no pre-computed checksum + * @init: Initial 32-bit checksum, 0 for no pre-computed checksum + * @len: Number of bytes to checksum from @tail * * Return: 16-bit folded, complemented checksum */ -uint16_t csum_iov_tail(struct iov_tail *tail, uint32_t init) +uint16_t csum_iov_tail(struct iov_tail *tail, uint32_t init, size_t len) { if (iov_tail_prune(tail)) { - size_t i; + size_t i, n; + n = MIN(len, tail->iov[0].iov_len - tail->off); init = csum_unfolded((char *)tail->iov[0].iov_base + tail->off, - tail->iov[0].iov_len - tail->off, init); - for (i = 1; i < tail->cnt; i++) { + n, init); + len -= n; + + for (i = 1; len && i < tail->cnt; i++) { const struct iovec *iov = &tail->iov[i]; - init = csum_unfolded(iov->iov_base, iov->iov_len, init); + n = MIN(len, iov->iov_len); + init = csum_unfolded(iov->iov_base, n, init); + len -= n; } } return (uint16_t)~csum_fold(init); diff --git a/checksum.h b/checksum.h index 4e3b098db072..6270f1457a73 100644 --- a/checksum.h +++ b/checksum.h @@ -21,18 +21,18 @@ uint32_t proto_ipv4_header_psum(uint16_t l4len, uint8_t protocol, struct in_addr saddr, struct in_addr daddr); void csum_udp4(struct udphdr *udp4hr, struct in_addr saddr, struct in_addr daddr, - struct iov_tail *data); + struct iov_tail *data, size_t dlen); void csum_icmp4(struct icmphdr *icmp4hr, const void *payload, size_t dlen); uint32_t proto_ipv6_header_psum(uint16_t payload_len, uint8_t protocol, const struct in6_addr *saddr, const struct in6_addr *daddr); void csum_udp6(struct udphdr *udp6hr, const struct in6_addr *saddr, const struct in6_addr *daddr, - struct iov_tail *data); + struct iov_tail *data, size_t dlen); void csum_icmp6(struct icmp6hdr *icmp6hr, const struct in6_addr *saddr, const struct in6_addr *daddr, const void *payload, size_t dlen); uint32_t csum_unfolded(const void *buf, size_t len, uint32_t init); -uint16_t csum_iov_tail(struct iov_tail *tail, uint32_t init); +uint16_t csum_iov_tail(struct iov_tail *tail, uint32_t init, size_t len); #endif /* CHECKSUM_H */ diff --git a/tap.c b/tap.c index 0920a325980e..412766c7c762 100644 --- a/tap.c +++ b/tap.c @@ -251,7 +251,7 @@ void *tap_push_uh4(struct udphdr *uh, struct in_addr src, in_port_t sport, uh->source = htons(sport); uh->dest = htons(dport); uh->len = htons(l4len); - csum_udp4(uh, src, dst, &payload); + csum_udp4(uh, src, dst, &payload, dlen); return (char *)uh + sizeof(*uh); } @@ -356,7 +356,7 @@ void *tap_push_uh6(struct udphdr *uh, uh->source = htons(sport); uh->dest = htons(dport); uh->len = htons(l4len); - csum_udp6(uh, src, dst, &payload); + csum_udp6(uh, src, dst, &payload, dlen); return (char *)uh + sizeof(*uh); } diff --git a/tcp.c b/tcp.c index d6a9ba28a531..9ab67e5a69ec 100644 --- a/tcp.c +++ b/tcp.c @@ -809,13 +809,14 @@ static void tcp_sock_set_nodelay(int s) * @psum: Unfolded partial checksum of the IPv4 or IPv6 pseudo-header * @th: TCP header (updated) * @payload: TCP payload + * @dlen: TCP payload length */ static void tcp_update_csum(uint32_t psum, struct tcphdr *th, - struct iov_tail *payload) + struct iov_tail *payload, size_t dlen) { th->check = 0; psum = csum_unfolded(th, sizeof(*th), psum); - th->check = csum_iov_tail(payload, psum); + th->check = csum_iov_tail(payload, psum, dlen); } /** @@ -952,7 +953,8 @@ size_t tcp_fill_headers(const struct ctx *c, struct tcp_tap_conn *conn, bool no_tcp_csum) { const struct flowside *tapside = TAPFLOW(conn); - size_t l4len = iov_tail_size(payload) + sizeof(*th); + size_t dlen = iov_tail_size(payload); + size_t l4len = dlen + sizeof(*th); uint8_t *omac = conn->f.tap_omac; size_t l3len = l4len; uint32_t psum = 0; @@ -1013,7 +1015,7 @@ size_t tcp_fill_headers(const struct ctx *c, struct tcp_tap_conn *conn, if (no_tcp_csum) th->check = 0; else - tcp_update_csum(psum, th, payload); + tcp_update_csum(psum, th, payload, dlen); return MAX(l3len + sizeof(struct ethhdr), ETH_ZLEN); } @@ -2225,7 +2227,7 @@ static void tcp_rst_no_conn(const struct ctx *c, int af, rsth->ack = 1; } - tcp_update_csum(psum, rsth, &payload); + tcp_update_csum(psum, rsth, &payload, 0); rst_l2len = ((char *)rsth - buf) + sizeof(*rsth); tap_send_single(c, buf, rst_l2len); } diff --git a/udp.c b/udp.c index 52260b934e60..66dc7766868c 100644 --- a/udp.c +++ b/udp.c @@ -289,7 +289,7 @@ size_t udp_update_hdr4(struct iphdr *ip4h, struct udp_payload_t *bp, .iov_len = dlen }; struct iov_tail data = IOV_TAIL(&iov, 1, 0); - csum_udp4(&bp->uh, *src, *dst, &data); + csum_udp4(&bp->uh, *src, *dst, &data, dlen); } return l4len; @@ -334,7 +334,8 @@ size_t udp_update_hdr6(struct ipv6hdr *ip6h, struct udp_payload_t *bp, .iov_len = dlen }; struct iov_tail data = IOV_TAIL(&iov, 1, 0); - csum_udp6(&bp->uh, &toside->oaddr.a6, &toside->eaddr.a6, &data); + csum_udp6(&bp->uh, &toside->oaddr.a6, &toside->eaddr.a6, &data, + dlen); } return l4len; diff --git a/udp_vu.c b/udp_vu.c index 96c65803a0ea..523447a81fae 100644 --- a/udp_vu.c +++ b/udp_vu.c @@ -105,14 +105,11 @@ static ssize_t udp_vu_sock_recv(struct iovec *iov, size_t *cnt, int s, bool v6) * @iov: IO vector for the frame (including vnet header) * @toside: Address information for one side of the flow * @dlen: Packet data length - * - * Return: Layer-4 length */ -static size_t udp_vu_prepare(const struct ctx *c, const struct iovec *iov, +static void udp_vu_prepare(const struct ctx *c, const struct iovec *iov, const struct flowside *toside, ssize_t dlen) { struct ethhdr *eh; - size_t l4len; /* ethernet header */ eh = vu_eth(iov[0].iov_base); @@ -129,7 +126,7 @@ static size_t udp_vu_prepare(const struct ctx *c, const struct iovec *iov, *iph = (struct iphdr)L2_BUF_IP4_INIT(IPPROTO_UDP); - l4len = udp_update_hdr4(iph, bp, toside, dlen, true); + udp_update_hdr4(iph, bp, toside, dlen, true); } else { struct ipv6hdr *ip6h = vu_ip(iov[0].iov_base); struct udp_payload_t *bp = vu_payloadv6(iov[0].iov_base); @@ -138,10 +135,8 @@ static size_t udp_vu_prepare(const struct ctx *c, const struct iovec *iov, *ip6h = (struct ipv6hdr)L2_BUF_IP6_INIT(IPPROTO_UDP); - l4len = udp_update_hdr6(ip6h, bp, toside, dlen, true); + udp_update_hdr6(ip6h, bp, toside, dlen, true); } - - return l4len; } /** @@ -149,9 +144,10 @@ static size_t udp_vu_prepare(const struct ctx *c, const struct iovec *iov, * @toside: Address information for one side of the flow * @iov: IO vector for the frame * @cnt: Number of IO vector entries + * @dlen: Data length */ static void udp_vu_csum(const struct flowside *toside, const struct iovec *iov, - size_t cnt) + size_t cnt, size_t dlen) { const struct in_addr *src4 = inany_v4(&toside->oaddr); const struct in_addr *dst4 = inany_v4(&toside->eaddr); @@ -162,11 +158,12 @@ static void udp_vu_csum(const struct flowside *toside, const struct iovec *iov, if (src4 && dst4) { bp = vu_payloadv4(base); data = IOV_TAIL(iov, cnt, (char *)&bp->data - base); - csum_udp4(&bp->uh, *src4, *dst4, &data); + csum_udp4(&bp->uh, *src4, *dst4, &data, dlen); } else { bp = vu_payloadv6(base); data = IOV_TAIL(iov, cnt, (char *)&bp->data - base); - csum_udp6(&bp->uh, &toside->oaddr.a6, &toside->eaddr.a6, &data); + csum_udp6(&bp->uh, &toside->oaddr.a6, &toside->eaddr.a6, &data, + dlen); } } @@ -229,7 +226,7 @@ void udp_vu_sock_to_tap(const struct ctx *c, int s, int n, flow_sidx_t tosidx) if (iov_cnt > 0) { udp_vu_prepare(c, iov_vu, toside, dlen); if (*c->pcap) { - udp_vu_csum(toside, iov_vu, iov_cnt); + udp_vu_csum(toside, iov_vu, iov_cnt, dlen); pcap_iov(iov_vu, iov_cnt, VNET_HLEN); } vu_flush(vdev, vq, elem, elem_used); -- 2.54.0