<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">diff --git a/sshd.c b/sshd.c
index fab0d98..aa8a8bf 100644
--- a/sshd.c
+++ b/sshd.c
@@ -592,10 +592,79 @@ privsep_preauth(struct ssh *ssh)
 		/* Arrange for logging to be sent to the monitor */
 		set_log_handler(mm_log_handler, pmonitor);
 
+#ifdef __APPLE_SANDBOX_NAMED_EXTERNAL__
+		/*
+		 * ssh_sandbox_child() has the side-effect of disabling opening
+		 * new files. This is a security precaution to prevent the
+		 * child process from leaking data or opening new sockets, but
+		 * clashes with newer OpenSSL implementations.
+		 *
+		 * Generally, OpenSSL wants to read new entropy from the system
+		 * for each reseeding operation (and, by extension, through any
+		 * operation that might trigger an internal reseeding, like
+		 * requesting random bytes).
+		 *
+		 * The current OpenSSL port only enables the default set of
+		 * system entropy - which means reading in data from crypto
+		 * devices like /dev/{,u,s}random and /dev/hwrng.
+		 *
+		 * To speed things up, OpenSSL tries to open file descriptors
+		 * to the listed devices and caches the result, i.e., the open
+		 * file descriptor. Those are normally kept open UNLESS a
+		 * reading error occurred OR no random bytes were returned.
+		 *
+		 * In a quite scary move, OpenSSL versions prior to 1.1.1
+		 * didn't fail when getting system entropy wasn't successful
+		 * and also added some "pseudo-random" data like the PID,
+		 * user id and current time to the entropy pool, which was
+		 * often enough to seed the PRNG.
+		 *
+		 * More recent versions have a rewritten PRNG/DRBG core and,
+		 * crucially, stricter rules when it comes to acquiring system
+		 * entropy - this is now strictly required and no other data
+		 * is mixed into the pool.
+		 *
+		 * OpenSSH generally tries (or intends) to leave crypto devices
+		 * (which should one of the earliest open devices) alone and
+		 * not close their FD on re-exec, but that doesn't seem to
+		 * work. Although OpenSSL is initialized very early in the
+		 * main() call chain, which SHOULD lead to open file
+		 * descriptors to crypto devices, on a typical OS X/macOS
+		 * system, /dev/urandom is opened as FD 6, which is above any
+		 * FD that would be preserved after a re-exec operation.
+		 *
+		 * This leads to the child process having no open file
+		 * descriptors to /dev/urandom, activating the sandbox,
+		 * setting the number of open files to zero and subsequently
+		 * effectively breaking OpenSSL 1.1.1+.
+		 *
+		 * We'll work around that by reseeding the PRNGs before
+		 * enabling the sandbox, which has the side-effect of opening
+		 * a file descriptor to /dev/urandom and keeping it open.
+		 *
+		 * There is a slight catch: errors in reading from the FD or a
+		 * read count of zero (i.e., the device not returning any data)
+		 * will lead to the FD being closed again without a way to be
+		 * re-opened.
+		 *
+		 * We can take this risk, as this should realistically not
+		 * happen. Even if it does, that only means that the child
+		 * process will fail to read random data and hence terminate
+		 * with an error - showing the same symptoms the workaround
+		 * is intended to fix, but nothing worse.
+		 */
+		reseed_prngs();
+
+		/* We need to do this before we chroot() so we can read sshd.sb and libsandbox.dylib */
+		if (box != NULL)
+			ssh_sandbox_child(box);
+#endif
 		privsep_preauth_child();
 		setproctitle("%s", "[net]");
+#ifndef __APPLE_SANDBOX_NAMED_EXTERNAL__
 		if (box != NULL)
 			ssh_sandbox_child(box);
+#endif
 
 		return 0;
 	}
</pre></body></html>