aboutgitcodebugslistschat
diff options
context:
space:
mode:
authorDavid Gibson <david@gibson.dropbear.id.au>2026-01-30 15:41:04 +1100
committerStefano Brivio <sbrivio@redhat.com>2026-01-31 03:56:57 +0100
commit768baf42f1485a7f7c867c8eb3a7e5ddcddb9d86 (patch)
tree2cea93eeb10033b7e600348ff6883545263d946e
parent3581ded2007a1219579fbb1f2cde0b016edd2a96 (diff)
downloadpasst-768baf42f1485a7f7c867c8eb3a7e5ddcddb9d86.tar
passt-768baf42f1485a7f7c867c8eb3a7e5ddcddb9d86.tar.gz
passt-768baf42f1485a7f7c867c8eb3a7e5ddcddb9d86.tar.bz2
passt-768baf42f1485a7f7c867c8eb3a7e5ddcddb9d86.tar.lz
passt-768baf42f1485a7f7c867c8eb3a7e5ddcddb9d86.tar.xz
passt-768baf42f1485a7f7c867c8eb3a7e5ddcddb9d86.tar.zst
passt-768baf42f1485a7f7c867c8eb3a7e5ddcddb9d86.zip
tcp, tcp_splice: Check for failures of shutdown(2)
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 <david@gibson.dropbear.id.au> Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
-rw-r--r--tcp.c31
-rw-r--r--tcp_splice.c3
2 files changed, 26 insertions, 8 deletions
diff --git a/tcp.c b/tcp.c
index 0be871a..9dd02cd 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 8806523..d60981c 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));
}
}