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=GCww1Uz9; 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 1874A5A0265 for ; Fri, 06 Mar 2026 09:25:11 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1772785509; 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=OM/Bbo0a28HoHhaIhsRC9IwGV7INAyhaGFx2je2+R0M=; b=GCww1Uz988bm8VjOUP3bcolPWkS5yH6+uD56Kt/espQrJcRyQULMmcOaGzGQLohxOPChlM YAqhuxTLX1fZVzppduWpFRFSH0bEgtvgOQYbKUdIqGSbvHcAT0F9pqW41CuswyMzlKeu9l 2cZVtjCrubk+whYrISaEX86+INy5NmE= Received: from mail-wm1-f69.google.com (mail-wm1-f69.google.com [209.85.128.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-630-seeDde16P-qhnTl1pR70ew-1; Fri, 06 Mar 2026 03:25:08 -0500 X-MC-Unique: seeDde16P-qhnTl1pR70ew-1 X-Mimecast-MFC-AGG-ID: seeDde16P-qhnTl1pR70ew_1772785507 Received: by mail-wm1-f69.google.com with SMTP id 5b1f17b1804b1-48378df3469so64118845e9.1 for ; Fri, 06 Mar 2026 00:25:08 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1772785507; x=1773390307; h=date:content-transfer-encoding:mime-version:organization:references :in-reply-to:message-id:subject:cc:to:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=OM/Bbo0a28HoHhaIhsRC9IwGV7INAyhaGFx2je2+R0M=; b=RiByqvHPHWxawI7MhQNeS8ODvY4/I8Z0nAQiyAvhGuRTjqlTbwwajUso7lEbvEmkDs UqFUxgN3/HbQIwWE9wlbMMgcUmUlDv0eeM7ZDQJQTs/uK9oJTQgI3sU3yZOUrLSQZKaS lXJNlfd0OGy9BFsY5kNrwnkFCbJOAtLhDrVuppHZ9e2/FIO0aQn8A1Z+NHB9lKsU+d5P W+gXBzvE18up4mgQpCV6pfOllS9vONlw5JP71iTlAC6hvxmgW7WiCG+yPDDhRfoS/ov9 euILc1nUgKxhkx6/MCvf1AHNxTr6ZAnza+nkK6TjmxHl9am3iGApM+fJLBm2FCCabitr P4qg== X-Gm-Message-State: AOJu0Yz/h/RUWSwaKuTgTZNTBY2HRzI4jferyKl5r8kdV5cmPzMOgXdU jM7lqyLqDBpudWWx+isp8KhEqFFpwoaMJgTcQm/sRyEzyXJLoFN4tEePY3DvpL85qnWXXKfNHxZ SQdehqP5p7/L2eaQKM6bUPiQKv/0eby1BjYOzW6rJdm5TBvwvJFdh8A== X-Gm-Gg: ATEYQzz2WmZqD1IzQ9IxrPz3Je/E+VC5wELXHpa9kex+sxpRNIw1FPz7x7I+mGyc6NB 5BURAP/z5Mtdu7L6VoZugkM3tkSGiHVdPGXZGRS8SM40WwBVCY3SIBQR/OgGvyQbn+A+C/gGqeb eK1lJmVvxwP/xgC1/eecB5yePlYPvUXuOXYYVkVYiuE+MwLLGtUA55gOrba1K4yE+rQ6CmISrT2 cjTEkfBcD5bYg68Jhr/jzZqKgkcxtmvx9/wCPZSstTml5mgwyB3dYGnLTGYz/m7UgdL4wSKOC6w mIuQISiQVv3wN7asUtw3Ne9B8LBZpea8v9VkXxseBuINth3WOr4z5hRnIRFfKyuzJlT7GLqufYa 5bbccKREE+7VVc+uBsZDEDtiQ3WFilVFicWN57lUQBNtbggxXhg== X-Received: by 2002:a05:600c:a4f:b0:47e:e981:78b4 with SMTP id 5b1f17b1804b1-4852674e8damr18962865e9.12.1772785506901; Fri, 06 Mar 2026 00:25:06 -0800 (PST) X-Received: by 2002:a05:600c:a4f:b0:47e:e981:78b4 with SMTP id 5b1f17b1804b1-4852674e8damr18962495e9.12.1772785506419; Fri, 06 Mar 2026 00:25:06 -0800 (PST) Received: from maya.myfinge.rs (ifcgrfdd.trafficplex.cloud. [176.103.220.4]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-485276b0adasm17819235e9.10.2026.03.06.00.25.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 06 Mar 2026 00:25:05 -0800 (PST) From: Stefano Brivio To: Laurent Vivier Subject: Re: [PATCH v3] iov: Add iov_truncate() helper and use it in vu handlers Message-ID: <20260306092504.54432a5f@elisabeth> In-Reply-To: References: <20260305125648.3720714-1-lvivier@redhat.com> <20260306083530.56648725@elisabeth> Organization: Red Hat X-Mailer: Claws Mail 4.2.0 (GTK 3.24.49; x86_64-pc-linux-gnu) MIME-Version: 1.0 Date: Fri, 06 Mar 2026 09:25:05 +0100 (CET) X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: jXuukJxsvw45eKq6NnlYu9hvcnModQrdMQmJMPVyECg_1772785507 X-Mimecast-Originator: redhat.com Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit Message-ID-Hash: F6PGMM2P5HQ3QBZHOPSZ2E4WJBHA4F66 X-Message-ID-Hash: F6PGMM2P5HQ3QBZHOPSZ2E4WJBHA4F66 X-MailFrom: sbrivio@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: passt-dev@passt.top, David Gibson 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: On Fri, 6 Mar 2026 09:17:32 +0100 Laurent Vivier wrote: > On 3/6/26 08:35, Stefano Brivio wrote: > > On Thu, 5 Mar 2026 13:56:48 +0100 > > Laurent Vivier wrote: > > > >> Add a generic iov_truncate() function that truncates an IO vector to a > >> given number of bytes, returning the number of iov entries that contain > >> data after truncation. > >> > >> Use it in udp_vu_sock_recv() and tcp_vu_sock_recv() to replace the > >> open-coded truncation logic that adjusted iov entries after recvmsg(). > >> Also convert the direct iov_len assignment in tcp_vu_send_flag() to use > >> iov_truncate() for consistency. > >> > >> Signed-off-by: Laurent Vivier > >> --- > >> > >> Notes: > >> v3: use in tcp_vu_send_flag() too > >> v2: use iov_truncate() in udp_vu_sock_recv() too > >> > >> iov.c | 22 ++++++++++++++++++++++ > >> iov.h | 1 + > >> tcp_vu.c | 14 +++----------- > >> udp_vu.c | 12 +++--------- > >> 4 files changed, 29 insertions(+), 20 deletions(-) > >> > >> diff --git a/iov.c b/iov.c > >> index ad726daa4cd8..31a3f5bc29e5 100644 > >> --- a/iov.c > >> +++ b/iov.c > >> @@ -147,6 +147,28 @@ size_t iov_size(const struct iovec *iov, size_t iov_cnt) > >> return len; > >> } > >> > >> +/** > >> + * iov_truncate() - Truncate an IO vector to a given number of bytes > >> + * @iov: IO vector (modified) > >> + * @iov_cnt: Number of entries in @iov > >> + * @size: Total number of bytes to keep > >> + * > >> + * Return: number of iov entries that contain data after truncation > >> + */ > >> +size_t iov_truncate(struct iovec *iov, size_t iov_cnt, size_t size) > >> +{ > >> + size_t i, offset; > >> + > >> + i = iov_skip_bytes(iov, iov_cnt, size, &offset); > >> + > >> + if (i < iov_cnt) { > >> + iov[i].iov_len = offset; > >> + i += !!offset; > >> + } > >> + > >> + return i; > >> +} > >> + > >> /** > >> * iov_tail_prune() - Remove any unneeded buffers from an IOV tail > >> * @tail: IO vector tail (modified) > >> diff --git a/iov.h b/iov.h > >> index d1ab91a94e22..b4e50b0fca5a 100644 > >> --- a/iov.h > >> +++ b/iov.h > >> @@ -29,6 +29,7 @@ size_t iov_from_buf(const struct iovec *iov, size_t iov_cnt, > >> size_t iov_to_buf(const struct iovec *iov, size_t iov_cnt, > >> size_t offset, void *buf, size_t bytes); > >> size_t iov_size(const struct iovec *iov, size_t iov_cnt); > >> +size_t iov_truncate(struct iovec *iov, size_t iov_cnt, size_t size); > >> > >> /* > >> * DOC: Theory of Operation, struct iov_tail > >> diff --git a/tcp_vu.c b/tcp_vu.c > >> index 88be232dca66..8ca4170f13f6 100644 > >> --- a/tcp_vu.c > >> +++ b/tcp_vu.c > >> @@ -131,7 +131,7 @@ int tcp_vu_send_flag(const struct ctx *c, struct tcp_tap_conn *conn, int flags) > >> return ret; > >> } > >> > >> - flags_elem[0].in_sg[0].iov_len = hdrlen + optlen; > >> + iov_truncate(&flags_iov[0], 1, hdrlen + optlen); > >> payload = IOV_TAIL(flags_elem[0].in_sg, 1, hdrlen); > >> > >> if (flags & KEEPALIVE) > >> @@ -192,9 +192,9 @@ static ssize_t tcp_vu_sock_recv(const struct ctx *c, struct vu_virtq *vq, > >> struct msghdr mh_sock = { 0 }; > >> uint16_t mss = MSS_GET(conn); > >> int s = conn->sock; > >> - ssize_t ret, len; > >> size_t hdrlen; > >> int elem_cnt; > >> + ssize_t ret; > >> int i; > >> > >> *iov_cnt = 0; > >> @@ -247,15 +247,7 @@ static ssize_t tcp_vu_sock_recv(const struct ctx *c, struct vu_virtq *vq, > >> ret -= already_sent; > >> > >> /* adjust iov number and length of the last iov */ > >> - len = ret; > >> - for (i = 0; len && i < elem_cnt; i++) { > >> - struct iovec *iov = &elem[i].in_sg[0]; > >> - > >> - if (iov->iov_len > (size_t)len) > >> - iov->iov_len = len; > >> - > >> - len -= iov->iov_len; > >> - } > >> + i = iov_truncate(&iov_vu[DISCARD_IOV_NUM], elem_cnt, ret); > > > > I had a quick look, but I couldn't figure this out. This causes > > Coverity Scan to report: > > > > /home/sbrivio/passt/tcp_vu.c:457:3: > > Type: Overflowed constant (INTEGER_OVERFLOW) > > > > /home/sbrivio/passt/tcp_vu.c:355:2: > > 1. path: Condition "!vu_queue_enabled(vq)", taking false branch. > > /home/sbrivio/passt/tcp_vu.c:355:2: > > 2. path: Condition "!vu_queue_started(vq)", taking false branch. > > /home/sbrivio/passt/tcp_vu.c:362:2: > > 3. path: Condition "0U /* (uint32_t)0 */ - (uint32_t)already_sent - 1 < (16777216U /* 1 << 16 + 8 */)", taking false branch. > > /home/sbrivio/passt/tcp_vu.c:374:2: > > 4. path: Condition "!wnd_scaled", taking false branch. > > /home/sbrivio/passt/tcp_vu.c:374:2: > > 5. path: Condition "already_sent >= wnd_scaled", taking false branch. > > /home/sbrivio/passt/tcp_vu.c:388:2: > > 6. path: Condition "v6", taking true branch. > > /home/sbrivio/passt/tcp_vu.c:390:2: > > 7. path: Condition "len < 0", taking false branch. > > /home/sbrivio/passt/tcp_vu.c:402:2: > > 8. path: Condition "!len", taking false branch. > > /home/sbrivio/passt/tcp_vu.c:425:2: > > 9. path: Condition "log_trace", taking true branch. > > /home/sbrivio/passt/tcp_vu.c:426:2: > > 10. path: Condition "log_trace", taking true branch. > > /home/sbrivio/passt/tcp_vu.c:439:2: > > 11. path: Condition "v6", taking true branch. > > /home/sbrivio/passt/tcp_vu.c:439:2: > > 12. function_return: Function "tcp_vu_hdrlen(v6)" returns 86. > > /home/sbrivio/passt/tcp_vu.c:439:2: > > 13. known_value_assign: "hdrlen" = "tcp_vu_hdrlen(v6)", its value is now 86. > > /home/sbrivio/passt/tcp_vu.c:440:2: > > 14. path: Condition "i < head_cnt", taking true branch. > > /home/sbrivio/passt/tcp_vu.c:443:3: > > 15. function_return: Function "iov_size(iov, buf_cnt)" returns 0. > > /home/sbrivio/passt/tcp_vu.c:443:3: > > 16. known_value_assign: "dlen" = "iov_size(iov, buf_cnt) - hdrlen", its value is now 18446744073709551530. > > /home/sbrivio/passt/tcp_vu.c:450:3: > > 17. path: Condition "previous_dlen != dlen", taking true branch. > > /home/sbrivio/passt/tcp_vu.c:454:3: > > 18. path: Condition "!*c->pcap", taking false branch. > > /home/sbrivio/passt/tcp_vu.c:457:3: > > 19. overflow_const: Expression "dlen + hdrlen", where "dlen" is known to be equal to -86, and "hdrlen" is known to be equal to 86, underflows the type of "dlen + hdrlen", which is type "unsigned long". > > > > if iov_size(iov, buf_cnt) = 0 and hdrlen = 86 (all unsigned) > "dlen" = "iov_size(iov, buf_cnt) - hdrlen", its value is now 18446744073709551530 (see > 16.) (i.e. -hdrlen, unsigned -86) > so "dlen + hdrlen" overflows (I guess). I was also thinking it was something like that but: > > Try: > diff --git a/tcp_vu.c b/tcp_vu.c > index 8ca4170f13f6..787ee004a66a 100644 > --- a/tcp_vu.c > +++ b/tcp_vu.c > @@ -440,7 +440,7 @@ int tcp_vu_data_from_sock(const struct ctx *c, struct tcp_tap_conn *conn) > for (i = 0, previous_dlen = -1, check = NULL; i < head_cnt; i++) { > struct iovec *iov = &elem[head[i]].in_sg[0]; > int buf_cnt = head[i + 1] - head[i]; > - ssize_t dlen = iov_size(iov, buf_cnt) - hdrlen; > + ssize_t dlen = (ssize_t)iov_size(iov, buf_cnt) - hdrlen; > bool push = i == head_cnt - 1; > size_t l2len; ...still not happy because of how we use dlen later (I think?): /home/sbrivio/passt/tcp_vu.c:457:3: Type: Overflowed constant (INTEGER_OVERFLOW) /home/sbrivio/passt/tcp_vu.c:355:2: 1. path: Condition "!vu_queue_enabled(vq)", taking false branch. /home/sbrivio/passt/tcp_vu.c:355:2: 2. path: Condition "!vu_queue_started(vq)", taking false branch. /home/sbrivio/passt/tcp_vu.c:362:2: 3. path: Condition "0U /* (uint32_t)0 */ - (uint32_t)already_sent - 1 < (16777216U /* 1 << 16 + 8 */)", taking false branch. /home/sbrivio/passt/tcp_vu.c:374:2: 4. path: Condition "!wnd_scaled", taking false branch. /home/sbrivio/passt/tcp_vu.c:374:2: 5. path: Condition "already_sent >= wnd_scaled", taking false branch. /home/sbrivio/passt/tcp_vu.c:388:2: 6. path: Condition "v6", taking true branch. /home/sbrivio/passt/tcp_vu.c:390:2: 7. path: Condition "len < 0", taking false branch. /home/sbrivio/passt/tcp_vu.c:402:2: 8. path: Condition "!len", taking false branch. /home/sbrivio/passt/tcp_vu.c:425:2: 9. path: Condition "log_trace", taking true branch. /home/sbrivio/passt/tcp_vu.c:426:2: 10. path: Condition "log_trace", taking true branch. /home/sbrivio/passt/tcp_vu.c:439:2: 11. path: Condition "v6", taking true branch. /home/sbrivio/passt/tcp_vu.c:440:2: 12. path: Condition "i < head_cnt", taking true branch. /home/sbrivio/passt/tcp_vu.c:443:3: 13. known_value_assign: "dlen" = "(ssize_t)iov_size(iov, buf_cnt) - hdrlen", its value is now 18446744073709551530. /home/sbrivio/passt/tcp_vu.c:450:3: 14. path: Condition "previous_dlen != dlen", taking true branch. /home/sbrivio/passt/tcp_vu.c:454:3: 15. path: Condition "!*c->pcap", taking false branch. /home/sbrivio/passt/tcp_vu.c:457:3: 16. overflow_const: Expression "dlen + hdrlen", where "dlen" is known to be equal to -86, and "hdrlen" is known to be equal to 86, underflows the type of "dlen + hdrlen", which is type "unsigned long". /home/sbrivio/passt/conf.c:2373:4: Type: Untrusted value as argument (TAINTED_SCALAR) -- Stefano