From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: passt.top; dmarc=none (p=none dis=none) header.from=gibson.dropbear.id.au Authentication-Results: passt.top; dkim=pass (2048-bit key; secure) header.d=gibson.dropbear.id.au header.i=@gibson.dropbear.id.au header.a=rsa-sha256 header.s=202512 header.b=unNlOl8U; dkim-atps=neutral Received: from mail.ozlabs.org (gandalf.ozlabs.org [150.107.74.76]) by passt.top (Postfix) with ESMTPS id 575B25A0623 for ; Fri, 30 Jan 2026 05:41:09 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gibson.dropbear.id.au; s=202512; t=1769748065; bh=EJo0qSQWfDxz2yeREPzhuoiD6iFKvxDzPsejQ7zP1F0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=unNlOl8UGhGOLOuzVMRZQ/Vn+JOxUVSBmc1YeKcsr/BcF9z7MSUGHyX+5e9+lOBaQ bZU8ROkyQKCi9Oja61uRf472dx5oJ8joMLbMGuaBPMKAVaK+5gt2e8Sa1qpLs8tanc IUSBOiaz25euz705fAD2vucT38oCw+CtEctX1RC1S6ba7PkfsurWF5U5X/0KRKU98o UHF/NzaXhl58KnYSP+Ta04oNvTsNFiIXVgVH2hxd2xLzUaRLhVtKMVGlPu+GSbpLd5 MMjQ0TvFOzAUof/Kik6y18cLZmZ+/66OIWXAV2jOA5XGawlXnfWcUotv+jEzr6MeZH AiAI8aOzO/qLw== Received: by gandalf.ozlabs.org (Postfix, from userid 1007) id 4f2Ncd4dzNz4w9j; Fri, 30 Jan 2026 15:41:05 +1100 (AEDT) From: David Gibson To: passt-dev@passt.top, Stefano Brivio Subject: [PATCH v2 3/3] tcp, tcp_splice: Check for failures of shutdown(2) Date: Fri, 30 Jan 2026 15:41:04 +1100 Message-ID: <20260130044104.1793253-4-david@gibson.dropbear.id.au> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260130044104.1793253-1-david@gibson.dropbear.id.au> References: <20260130044104.1793253-1-david@gibson.dropbear.id.au> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Message-ID-Hash: PXGBNVMJFJZMBHRMR65QM233PTWWZA37 X-Message-ID-Hash: PXGBNVMJFJZMBHRMR65QM233PTWWZA37 X-MailFrom: dgibson@gandalf.ozlabs.org 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: 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: shutdown(2) should never fail, unless we give it bad parameters (e.g. passing it an fd which isn't a connected socket). However, if it ever did, we'd currently ignore the error and carry on which could lead to very confusing behaviour. In the interests of debugability, check for failure of shutdown(2), log an error and: - during runtime, reset the affected connection - during migration, fail the migration Signed-off-by: David Gibson --- tcp.c | 31 ++++++++++++++++++++++++------- tcp_splice.c | 3 ++- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/tcp.c b/tcp.c index 0be871a4..9dd02cd8 100644 --- a/tcp.c +++ b/tcp.c @@ -2284,7 +2284,11 @@ int tcp_tap_handler(const struct ctx *c, uint8_t pif, sa_family_t af, if (th->fin) { conn->seq_from_tap++; - shutdown(conn->sock, SHUT_WR); + if (shutdown(conn->sock, SHUT_WR) < 0) { + flow_dbg_perror(conn, "shutdown() failed"); + goto reset; + } + tcp_send_flag(c, conn, ACK); conn_event(c, conn, SOCK_FIN_SENT); @@ -2359,7 +2363,11 @@ int tcp_tap_handler(const struct ctx *c, uint8_t pif, sa_family_t af, socklen_t sl; struct tcp_info tinfo; - shutdown(conn->sock, SHUT_WR); + if (shutdown(conn->sock, SHUT_WR) < 0) { + flow_dbg_perror(conn, "shutdown() failed"); + goto reset; + } + conn_event(c, conn, SOCK_FIN_SENT); tcp_send_flag(c, conn, ACK); ack_due = 0; @@ -3831,10 +3839,15 @@ int tcp_flow_migrate_target_ext(struct ctx *c, struct tcp_tap_conn *conn, int fd int v; v = TCP_SEND_QUEUE; - if (setsockopt(s, SOL_TCP, TCP_REPAIR_QUEUE, &v, sizeof(v))) + if (setsockopt(s, SOL_TCP, TCP_REPAIR_QUEUE, &v, sizeof(v))) { flow_perror(conn, "Selecting repair queue"); - else - shutdown(s, SHUT_WR); + } else { + if (shutdown(s, SHUT_WR) < 0) { + flow_perror(conn, + "Repair mode shutdown() failed"); + goto fail; + } + } } if (tcp_flow_repair_wnd(conn, &t)) @@ -3861,8 +3874,12 @@ int tcp_flow_migrate_target_ext(struct ctx *c, struct tcp_tap_conn *conn, int fd * Call shutdown(x, SHUT_WR) *not* in repair mode, which moves us to * TCP_FIN_WAIT1. */ - if (t.tcpi_state == TCP_FIN_WAIT1) - shutdown(s, SHUT_WR); + if (t.tcpi_state == TCP_FIN_WAIT1) { + if (shutdown(s, SHUT_WR) < 0) { + flow_perror(conn, "Post-repair shutdown() failed"); + goto fail; + } + } if (tcp_set_peek_offset(conn, peek_offset)) goto fail; diff --git a/tcp_splice.c b/tcp_splice.c index 8806523a..d60981ca 100644 --- a/tcp_splice.c +++ b/tcp_splice.c @@ -627,7 +627,8 @@ retry: flow_foreach_sidei(sidei) { if ((conn->events & FIN_RCVD(sidei)) && !(conn->events & FIN_SENT(!sidei))) { - shutdown(conn->s[!sidei], SHUT_WR); + if (shutdown(conn->s[!sidei], SHUT_WR) < 0) + goto reset; conn_event(conn, FIN_SENT(!sidei)); } } -- 2.52.0