diff options
| author | David Gibson <david@gibson.dropbear.id.au> | 2026-01-30 15:41:04 +1100 |
|---|---|---|
| committer | Stefano Brivio <sbrivio@redhat.com> | 2026-01-31 03:56:57 +0100 |
| commit | 768baf42f1485a7f7c867c8eb3a7e5ddcddb9d86 (patch) | |
| tree | 2cea93eeb10033b7e600348ff6883545263d946e | |
| parent | 3581ded2007a1219579fbb1f2cde0b016edd2a96 (diff) | |
| download | passt-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.c | 31 | ||||
| -rw-r--r-- | tcp_splice.c | 3 |
2 files changed, 26 insertions, 8 deletions
@@ -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)); } } |
