Exposed sshd -- looping sshd-auth

Darren Tucker dtucker at dtucker.net
Tue Sep 22 10:04:23 AEST 2026


Hi.

On Mon, 21 Sept 2026 at 16:28, Havard Eidnes via openssh-unix-dev
<openssh-unix-dev at mindrot.org> wrote:
> as my alter ego, he at NetBSD.org, I posted this problem report to
> NetBSD's problem report collection:
>
>   https://gnats.netbsd.org/60563
>
> In short: an Internet-exposed sshd running newish OpenSSH but
> which dis-allows any keyboard-interactive / password logins seems
> to be vulnerable to what I call a mild DoS attack, in that it may
> be triggered into doing a fairly tight system call loop until the
> parent process says "enough" or a self-imposed CPU time resource
> limit of 10 minutes is reached.
[...]

You can reproduce this pretty easily: start sshd in debug mode
(/path/to/sshd -ddd -p 2022) then point telnet at the port.  As long
as the telnet is connected the CPU will spin.

Anyway, it's the result of an old workaround and using atomicio in a
new context (ie, this one):
https://github.com/openssh/openssh-portable/commit/f5bbd3b657
BROKEN_READ_COMPARISON on NetBSD, which does this in atomicio.c:

#ifndef BROKEN_READ_COMPARISON
        pfd.events = f == read ? POLLIN : POLLOUT;
#else
        pfd.events = POLLIN|POLLOUT;
#endif

So atomicio() is actually saying this is readable or writeable, hence
the hard loop.

I don't recall exactly why the comparison of read() function pointers
didn't work at the time, but I've seen other "functions" like writev
actually be macros on some platforms.  You can confirm this by
removing BROKEN_READ_COMPARISON from config.h and recompiling.  I
don't know if this will resurface the problems that prompted the
change in the first place, though.


--
Darren Tucker (dtucker at dtucker.net)
GPG key 11EAA6FA / A86E 3E07 5B19 5880 E860  37F4 9357 ECEF 11EA A6FA
    Good judgement comes with experience. Unfortunately, the experience
usually comes from bad judgement.


More information about the openssh-unix-dev mailing list