From c61dcc4c6db8778e5c821b7ff5518e53eb55d6fe Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Fri, 28 Aug 2026 12:44:09 -0700 Subject: [PATCH 1/3] scoutfs: fix minor comment typos Fix a few comment typos. Signed-off-by: Zach Brown --- kmod/src/net.c | 2 +- kmod/src/server.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kmod/src/net.c b/kmod/src/net.c index 8ff4a22d..2a5003d0 100644 --- a/kmod/src/net.c +++ b/kmod/src/net.c @@ -344,7 +344,7 @@ static inline u8 net_err_from_host(struct super_block *sb, int error) /* * Shutdown the connection. This is called by many contexts including - * work that most complete to finish shutting down. We queue specific + * work that must complete to finish shutting down. We queue specific * shutdown work that can wait on all the connection's other work. * We're sure to only queue the shutdown work once. */ diff --git a/kmod/src/server.c b/kmod/src/server.c index 73a8bfa7..8e809ac8 100644 --- a/kmod/src/server.c +++ b/kmod/src/server.c @@ -3897,7 +3897,7 @@ static void queue_farewell_work(struct server_info *server) * response shuts down the connection. * * If a client reconnects they'll send their previously received - * serer_term in their greeting request. + * server_term in their greeting request. * * XXX The logic of this has gotten convoluted. The lock server can * send a recovery request so it needs to be called after the core net From 2b3f4e29a9b173a54f9d9fae48536c511b908a14 Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Fri, 28 Aug 2026 12:45:50 -0700 Subject: [PATCH 2/3] scoutfs: ignore connections without greeting A connecting client must send a greeting message so the server can get their RID and start processing. The server acted on connections that hadn't received a greeting with the RID. It would print messages and would try to fence these connections' client if it disconnected. The server never received the RID, though, so there was nothing to fence. The server would shut down if either fencing raised an error or when the net stack called its notify_down callback with a 0 RID. And all of this is actively triggered in the field by port scans that send either nothing or garbage down connections to the ports that they're sweeping. We fix all this by ignoring the connections until we receive a RID. We don't print the accepted or closed messages, free the connection if it disconnects, and don't call the notify up or down methods. Signed-off-by: Zach Brown --- kmod/src/net.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/kmod/src/net.c b/kmod/src/net.c index 2a5003d0..96c0e6d1 100644 --- a/kmod/src/net.c +++ b/kmod/src/net.c @@ -1007,7 +1007,7 @@ static void scoutfs_net_destroy_worker(struct work_struct *work) WARN_ON_ONCE(!list_empty(&conn->accepted_list)); /* tell callers that accepted connection finally done */ - if (conn->listening_conn && conn->notify_down) + if (conn->listening_conn && conn->notify_down && test_conn_fl(conn, valid_greeting)) conn->notify_down(sb, conn, conn->info, conn->rid); list_splice_init(&conn->resend_queue, &conn->send_queue); @@ -1179,10 +1179,6 @@ static void scoutfs_net_listen_worker(struct work_struct *work) continue; } - scoutfs_info(sb, "server accepted "SIN_FMT" -> "SIN_FMT, - SIN_ARG(&acc_conn->sockname), - SIN_ARG(&acc_conn->peername)); - /* acc_conn isn't visible, conn unlock orders stores */ spin_lock(&conn->lock); @@ -1303,13 +1299,15 @@ static void scoutfs_net_shutdown_worker(struct work_struct *work) trace_scoutfs_net_shutdown_work_enter(sb, 0, 0); trace_scoutfs_conn_shutdown_start(conn); - /* connected and accepted conns print a message */ - if (conn->peername.sin_port != 0) + /* (racy) connected client and accepted server with greeting print a message */ + if (conn->peername.sin_port != 0 && + (!conn->listening_conn || test_conn_fl(conn, valid_greeting))) { scoutfs_info(sb, "%s "SIN_FMT" -> "SIN_FMT, conn->listening_conn ? "server closing" : "client disconnected", SIN_ARG(&conn->sockname), SIN_ARG(&conn->peername)); + } /* ensure that sockets return errors, wakes blocked socket work */ if (conn->sock) @@ -1386,9 +1384,10 @@ static void scoutfs_net_shutdown_worker(struct work_struct *work) /* resolve racing with listener shutdown with locked shutting_down */ if (conn->listening_conn && (test_conn_fl(conn->listening_conn, shutting_down) || - test_conn_fl(conn, saw_farewell))) { + test_conn_fl(conn, saw_farewell) || + !test_conn_fl(conn, valid_greeting))) { - /* free accepted sockets after farewell or listener shutdown */ + /* free accepted sockets after farewell, listener shutdown, or invalid greeting */ spin_unlock(&conn->lock); destroy_conn(conn); @@ -1886,6 +1885,9 @@ restart: spin_unlock(&conn->lock); + scoutfs_info(sb, "server accepted "SIN_FMT" -> "SIN_FMT, + SIN_ARG(&conn->sockname), SIN_ARG(&conn->peername)); + /* only call notify_up the first time we see the rid */ if (conn->notify_up && first_contact) conn->notify_up(sb, conn, conn->info, rid); From 4c267f88c68f27af0701afb691f22055ee132530 Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Fri, 28 Aug 2026 13:10:49 -0700 Subject: [PATCH 3/3] scoutfs: add portscan test Signed-off-by: Zach Brown --- tests/golden/portscan | 3 +++ tests/sequence | 1 + tests/tests/portscan.sh | 31 +++++++++++++++++++++++++++++++ 3 files changed, 35 insertions(+) create mode 100644 tests/golden/portscan create mode 100644 tests/tests/portscan.sh diff --git a/tests/golden/portscan b/tests/golden/portscan new file mode 100644 index 00000000..acd95f46 --- /dev/null +++ b/tests/golden/portscan @@ -0,0 +1,3 @@ +== make sure unknown disconnect doesn't shut down server +should be leader: 1 +should still be leader: 1 diff --git a/tests/sequence b/tests/sequence index 401b36a4..05e9c1e5 100644 --- a/tests/sequence +++ b/tests/sequence @@ -65,4 +65,5 @@ block-stale-reads.sh freed-list-wedge.sh inode-deletion.sh renameat2-noreplace.sh +portscan.sh xfstests.sh diff --git a/tests/tests/portscan.sh b/tests/tests/portscan.sh new file mode 100644 index 00000000..38fce852 --- /dev/null +++ b/tests/tests/portscan.sh @@ -0,0 +1,31 @@ +# +# Make sure the server ignores connections that aren't participating. +# + +t_require_commands nc + +echo "== make sure unknown disconnect doesn't shut down server" +# get server addr [1] and port [1] +sv=$(t_server_nr) +addrs=($(grep "peer 0.0.0.0" $(t_debugfs_path $sv)/connections | \ + awk -F"[: ]" '{print $2,$3}')) + +# verify that the server is leader and record its term +echo "should be leader: $(cat $(t_sysfs_path $sv)/quorum/is_leader)" +before=$(awk '($1 == "term") { print $2 }' < $(t_sysfs_path $sv)/quorum/status) + +# send junk +echo " " | nc ${addrs[0]} ${addrs[1]} + +# make sure the server is still leader with the same term +echo "should still be leader: $(cat $(t_sysfs_path $sv)/quorum/is_leader)" +after=$(awk '($1 == "term") { print $2 }' < $(t_sysfs_path $sv)/quorum/status) + +if [ -z "$before" -o -z "$after" ]; then + echo "couldn't find terms: before '$before', or after '$after'" +fi +if [ "$before" != "$after" ]; then + echo "term before $before != term after $after" +fi + +t_pass