]> git.ipfire.org Git - thirdparty/openssh-portable.git/commitdiff
upstream: Fix mistracking of MaxStartups process exits in some
authordjm@openbsd.org <djm@openbsd.org>
Fri, 4 Jul 2025 09:51:01 +0000 (09:51 +0000)
committerDamien Miller <djm@mindrot.org>
Fri, 4 Jul 2025 09:52:19 +0000 (19:52 +1000)
situations. At worst, this can cause all MaxStartups slots to fill and sshd
to refuse new connections.

Diagnosis by xnor; ok dtucker@

OpenBSD-Commit-ID: 10273033055552557196730f898ed6308b36a78d

sshd.c

diff --git a/sshd.c b/sshd.c
index 4a93e29e4c0470f65454dab46df365277bbb67d0..d721a5de36a47a166f7e97556d04feb91d6506d6 100644 (file)
--- a/sshd.c
+++ b/sshd.c
@@ -289,8 +289,10 @@ child_finish(struct early_child *child)
 {
        if (children_active == 0)
                fatal_f("internal error: children_active underflow");
-       if (child->pipefd != -1)
+       if (child->pipefd != -1) {
+               srclimit_done(child->pipefd);
                close(child->pipefd);
+       }
        sshbuf_free(child->config);
        sshbuf_free(child->keys);
        free(child->id);
@@ -311,6 +313,7 @@ child_close(struct early_child *child, int force_final, int quiet)
        if (!quiet)
                debug_f("enter%s", force_final ? " (forcing)" : "");
        if (child->pipefd != -1) {
+               srclimit_done(child->pipefd);
                close(child->pipefd);
                child->pipefd = -1;
        }
@@ -1039,7 +1042,6 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s,
                        if (ret <= 0) {
                                if (children[i].early)
                                        listening--;
-                               srclimit_done(children[i].pipefd);
                                child_close(&(children[i]), 0, 0);
                                continue;
                        }
@@ -1078,23 +1080,19 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s,
                                }
                                /* FALLTHROUGH */
                        case 0:
-                               /* child exited preauth */
+                               /* child closed pipe */
                                if (children[i].early)
                                        listening--;
-                               srclimit_done(children[i].pipefd);
+                               debug3_f("child %lu for %s closed pipe",
+                                   (long)children[i].pid, children[i].id);
                                child_close(&(children[i]), 0, 0);
                                break;
                        case 1:
                                if (children[i].config) {
                                        error_f("startup pipe %d (fd=%d)"
-                                           " early read", i, children[i].pipefd);
-                                       if (children[i].early)
-                                               listening--;
-                                       if (children[i].pid > 0)
-                                               kill(children[i].pid, SIGTERM);
-                                       srclimit_done(children[i].pipefd);
-                                       child_close(&(children[i]), 0, 0);
-                                       break;
+                                           " early read",
+                                           i, children[i].pipefd);
+                                       goto problem_child;
                                }
                                if (children[i].early && c == '\0') {
                                        /* child has finished preliminaries */
@@ -1114,6 +1112,12 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s,
                                            "child %ld for %s in state %d",
                                            (int)c, (long)children[i].pid,
                                            children[i].id, children[i].early);
+ problem_child:
+                                       if (children[i].early)
+                                               listening--;
+                                       if (children[i].pid > 0)
+                                               kill(children[i].pid, SIGTERM);
+                                       child_close(&(children[i]), 0, 0);
                                }
                                break;
                        }