CVE-2024-6387 in 60 seconds
OpenSSH’s sshd is the server process that accepts remote SSH connections. A client is allowed a
limited time to authenticate. If that time expires, the operating system delivers a SIGALRM
signal so sshd can terminate the unfinished session.
In Portable OpenSSH 8.5p1 through 9.7p1, that alarm handler called logging code. Logging looks
harmless, but on glibc-based Linux systems syslog() can call complex memory-management functions
such as malloc() and free(). A signal can interrupt the normal program at almost any instant —
including while the same heap allocator is halfway through updating its internal state.
If the alarm arrived during that narrow window, the handler could enter the allocator a second time before the first operation finished. The immediate result might be a crash. With carefully shaped SSH messages and many repeated timing attempts, however, Qualys demonstrated that this inconsistent heap state could be turned into unauthenticated remote code execution as root on a 32-bit Linux/glibc target.
The attack path was:
remote client opens an SSH connection
-> client deliberately does not complete authentication
-> LoginGraceTime expires and SIGALRM interrupts sshd
-> signal handler calls unsafe logging code
-> syslog re-enters malloc/free while heap state may be incomplete
-> repeated attempts try to win the timing race
-> attacker-controlled heap corruption may reach code execution as root
No valid username, password, or SSH key was required to reach the vulnerable path. The difficulty was timing: the attacker had to make the signal arrive during a tiny unsafe window and repeat the attempt enough times to overcome ASLR and connection limits.
What are sshd, LoginGraceTime, and SIGALRM?
sshd is OpenSSH’s internet-facing server daemon. It starts processing a connection before the
remote user has authenticated because it must negotiate the protocol and examine authentication
messages. Some of this pre-authentication work occurs in a privileged process.
LoginGraceTime is the maximum time a client may spend authenticating. The usual upstream default
was 120 seconds. When the deadline expires, sshd receives SIGALRM, an asynchronous operating-
system signal.
“Asynchronous” is the important word. An ordinary function call happens at a point chosen by the program. A signal handler can begin while an unrelated operation is temporarily holding a lock or has only half-updated a data structure. POSIX therefore permits only a small set of async-signal-safe operations inside a handler. General logging is not one of them.
The vulnerability did not exist because SSH had a timeout. It existed because timeout handling performed work that was unsafe in an asynchronous and privileged execution context.
What happened?
The public record supports the following chronology:
- In 2006, OpenSSH fixed CVE-2006-5051 by making the fatal signal path terminate with
_exit(1)instead of reaching unsafe logging behavior. - An October 2020 logging refactor accidentally removed the
DO_LOG_SAFE_IN_SIGHANDcondition that preserved that special behavior. The regression entered Portable OpenSSH 8.5p1. - When an unauthenticated client exceeded
LoginGraceTime,grace_alarm_handler()could once again reachsigdie()and, on affected platforms, non-async-signal-safe logging functions. - Qualys reconstructed the old bug class and demonstrated exploitation against a current 32-bit Debian Linux/glibc environment. Their laboratory attack needed roughly 10,000 race attempts and, with the tested limits and ASLR, averaged six to eight hours for a root shell.
- OpenSSH published version 9.8/9.8p1 on 1 July 2024. The new design performs minimal termination in the alarm handler and moves logging and per-source penalty work into normal listener context.
The name regreSSHion reflects this history: a security property fixed in 2006 was lost during a later refactor. The old vulnerable source was not copied back verbatim; the guarantee established by the old fix disappeared.
Who was actually affected?
The upstream affected range was Portable OpenSSH 8.5p1 through 9.7p1 inclusive. That version range is a starting point, not a complete exposure decision. Practical risk also depended on:
- an internet-reachable
sshdprocess; - a platform whose logging path was not async-signal-safe, notably glibc-based Linux;
- a package without a vendor backport or downstream change that removed the vulnerable path;
LoginGraceTimeandMaxStartupssettings that allowed repeated pre-authentication attempts;- architecture, allocator behavior, ASLR, network stability, and attack time.
OpenSSH stated that successful root code execution had been demonstrated on 32-bit Linux/glibc with ASLR. At the time of the 9.8 release, 64-bit exploitation was believed possible but had not been demonstrated. Non-glibc systems had not been fully examined. OpenBSD was explicitly unaffected because its signal-time logging path used a safer implementation.
Distribution package versions must be checked through the vendor, not only through the SSH banner. For example, Ubuntu fixed affected supported releases with backported package updates whose version numbers remained below 9.8p1. Conversely, an upstream-looking version does not prove that a specific downstream build was exploitable with Qualys’s demonstrated method.
What I verified
- In
grace_alarm_handler(), the vulnerable path calledsigdie()and formatted a timeout message; the patch replaces it with_exit(EXIT_LOGIN_GRACE). - The listener later recognizes
EXIT_LOGIN_GRACEinchild_reap(), logs synchronously, and applies the source penalty outside the signal handler. - I checked the 9.8 release notes and the public technical advisory against the patch to separate the code fact from platform-specific exploitability claims.
- This is a static reproduction of the fixed control flow. I did not perform timing attempts, allocator manipulation, or exploit testing against any SSH service.
Deep dive: why logging from SIGALRM can corrupt the heap
Normal function calls are sequenced. A function updates its state, calls another function, and returns when its invariants are restored. An asynchronous signal is different: the handler may run while the interrupted code temporarily holds a lock, owns a half-updated allocator structure, or has changed global state that is not yet consistent.
POSIX therefore defines a small set of async-signal-safe operations. General logging is not among
them. On affected glibc systems, syslog() can allocate and free memory. If the alarm interrupts
the main authentication path during its own allocator operation, the handler may enter the same
allocator again against transient state.
Crashes are the easiest visible outcome, but not the security boundary. The Qualys research showed that carefully repeated connections could shape and interrupt allocator activity on a 32-bit Linux/glibc target, eventually reaching unauthenticated code execution as root. OpenSSH’s 9.8 notes report an average of six to eight hours in the demonstrated laboratory configuration and state that 64-bit exploitation was believed possible but had not been demonstrated at release.
These conditions should be preserved rather than simplified into “all SSH servers are instantly
rootable.” Platform libc, architecture, ASLR behavior, downstream patches, LoginGraceTime, and
connection limits change practical reachability. They do not remove the underlying unsafe handler.
The regression was a lost invariant, not a reverted patch
The 2006 correction made the fatal signal path call _exit(1) rather than unsafe logging logic.
Qualys traced the regression to an October 2020 logging infrastructure change. The refactor removed
the DO_LOG_SAFE_IN_SIGHAND guard from the function reached by the alarm handler.
This is an important patch-analysis pattern. A security fix often establishes an invariant that is larger than the exact diff: “the signal handler performs only safe termination.” Years later, a maintainer can reorganize logging correctly for ordinary callers while unknowingly reconnecting an exceptional caller with stricter rules.
Tests that assert only a historical line or macro survives are fragile. The durable regression test must identify the special calling context and prove that every path from it remains async-signal-safe.
Why privilege separation did not contain this path
OpenSSH uses privilege separation extensively, but the vulnerable operation occurred before authentication completed in a privileged server process. A remote client did not need a valid account or credential to keep a connection open until the grace timer expired.
This illustrates a common assessment error: a product can have excellent sandboxing and still retain a narrow privileged path for setup, monitoring, or teardown. Security analysis must map the specific process and lifecycle phase executing the vulnerable code. “The application is sandboxed” is not evidence until the affected instruction is placed inside that sandbox.
The 9.8p1 fix moves work out of the handler
The public fix was part of a broader server restructuring and per-source penalty work. Instead of
performing unsafe cleanup and logging inside the alarm handler, the design moves meaningful work to
the listener, where it can run synchronously. A minimal backport can also make sshsigdie() terminate
with _exit(1) and omit the unsafe formatting and logging path.
The fix is architectural, not a timing adjustment. Increasing or decreasing LoginGraceTime may
alter attack economics, but it does not make an unsafe signal handler safe. Connection throttling
is useful defense in depth; patching removes the root cause.
Evidence matrix
| Question | What I checked | Confidence | Limit |
|---|---|---|---|
| Which modern versions regressed? | I matched OpenSSH and Qualys records identifying Portable OpenSSH 8.5p1 through 9.7p1. | High | Vendor backports and platform-specific changes must be checked separately. |
| What triggers the path? | I traced LoginGraceTime expiration to the SIGALRM handler before authentication completes. | High | Practical timing depends on configuration and network behavior. |
| Why is logging dangerous there? | I confirmed the old handler reaches logging that is not async-signal-safe and may re-enter allocator operations. | High | Exact libc internals vary by platform. |
| Was remote root execution demonstrated? | I reviewed Qualys’s 32-bit Linux/glibc lab result; I did not repeat it. | High | The release record did not demonstrate the same result on 64-bit targets. |
| Why is OpenBSD excluded? | I checked OpenSSH’s note that OpenBSD uses a safer logging path and is not vulnerable. | High | Other non-glibc systems require their own analysis. |
| What does 9.8p1 change? | Unsafe handler work is removed or shifted into synchronous listener processing. | High | Distribution packages may express the fix with an older-looking version. |
Safe validation without racing sshd
Start with the vendor package record. Capture the server’s Portable OpenSSH version, operating system, architecture, libc, package revision, and the distribution’s CVE status. Do not decide from the SSH banner alone: vendors can hide versions, backport fixes, or apply downstream patches that change reachability.
For source validation, inspect the vendor’s sshsigdie() or equivalent patch. The fixed assertion
is structural: the alarm handler must not format messages, call general logging, allocate memory, or
perform other non-async-signal-safe work. It should terminate safely or communicate minimal state
to code that handles it synchronously.
A controlled regression test can launch an instrumented, non-production build in an isolated lab, allow an unauthenticated connection to exceed the grace period, and observe the handler’s call set. The test passes when the signal path reaches only allowed operations. There is no need to tune packet timing, corrupt a heap, or seek code execution.
Use these negative controls:
- the same observation against 9.8p1;
- a vendor build with a documented backport despite an older upstream version;
- a platform whose advisory marks it unaffected;
- a normal synchronous logging event, proving that logging still works outside the handler;
- a configuration with the deadline disabled, treated only as reachability comparison—not a fix.
Repeated unauthenticated connections against an internet-facing service are not an appropriate verification method. They can exhaust resources and resemble exploitation. Static patch proof plus one bounded lab observation provides clearer evidence with less operational risk.
My conclusion
Upgrade to OpenSSH 9.8p1 or the distribution package that explicitly backports CVE-2024-6387. Before maintenance completes, connection-rate controls and reduced exposure can lower risk, but they should be documented as temporary compensating controls rather than remediation.
My conclusion is that the durable fix is the smaller signal handler, not a more careful logger. The handler now exits with a minimal signal-safe operation, while ordinary code performs logging later. Refactors that touch shared logging or cleanup code must explicitly re-check exceptional callers such as signal handlers instead of assuming ordinary call rules still apply.
Public sources
- OpenSSH 9.8 release notes
- Qualys: regreSSHion technical advisory
- OpenSSH portable fix commit
- Ubuntu CVE record and fixed package status
- CVE.org record for CVE-2024-6387
Evidence used for this analysis
Version and exploitation status can change; follow the linked vendor records.
The author completed a technical review. This does not, by itself, claim lab reproduction.
