--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/components/openssh/patches/047-login_grace_time_watchdog.patch Wed Nov 16 12:17:49 2016 -0800
@@ -0,0 +1,165 @@
+#
+# Implements watchdog process, which backs up login_grace_time alarm.
+#
+# If the main process is hung in a syscall, SIGALRM is queued but not
+# delivered and the connection stays unauthenticated for too long.
+#
+# Function start_grace_watchdog forks of a watchdog process, that sends the
+# main process a SIGTERM, if it does neither authenticate nor exit before
+# (login_grace_time + GRACE_WATCHDOG_THRESHOLD).
+# If the main process does not react to SIGTERM, SIGKILL is sent after
+# additional GRACE_WATCHDOG_THRESHOLD seconds.
+#
+# Patch source: in-house
+# Reported to [email protected] as security issue.
+#
+# Per agreement with upstream developers, filed:
+# https://bugzilla.mindrot.org/show_bug.cgi?id=2615
+#
+diff -pur old/sshd.c new/sshd.c
+--- old/sshd.c
++++ new/sshd.c
+@@ -252,9 +252,16 @@ Buffer loginmsg;
+ /* Unprivileged user */
+ struct passwd *privsep_pw = NULL;
+
++/* Pid of process backing up login_grace_time alarm. */
++pid_t grace_watchdog_pid = -1;
++
++/* Time in seconds */
++#define GRACE_WATCHDOG_THRESHOLD 10
++
+ /* Prototypes for various functions defined later in this file. */
+ void destroy_sensitive_data(void);
+ void demote_sensitive_data(void);
++static void stop_grace_watchdog(void);
+
+ #ifdef WITH_SSH1
+ static void do_ssh1_kex(void);
+@@ -369,12 +376,98 @@ grace_alarm_handler(int sig)
+ signal(SIGTERM, SIG_IGN);
+ kill(0, SIGTERM);
+ }
++ stop_grace_watchdog();
+
+ /* Log error and exit. */
+ sigdie("Timeout before authentication for %s port %d",
+ ssh_remote_ipaddr(active_state), ssh_remote_port(active_state));
+ }
+
++static inline void
++sleep_reliably(unsigned int seconds)
++{
++ while (seconds > 0)
++ seconds = sleep(seconds);
++}
++
++/*
++ * Implements watchdog process, which backs up login_grace_time alarm.
++ *
++ * If the main process is hung in a syscall, SIGALRM is queued but not
++ * delivered and the connection stays unauthenticated for too long.
++ *
++ * This function forks off a watchdog process, which sends the main process
++ * a SIGTERM, if it does neither authenticate nor exit before
++ * (login_grace_time + GRACE_WATCHDOG_THRESHOLD).
++ * If the main process does not react to SIGTERM, SIGKILL is sent after
++ * additional GRACE_WATCHDOG_THRESHOLD seconds.
++ */
++static void
++start_grace_watchdog(int login_grace_time)
++{
++ pid_t ppid = getpid();
++
++ if (login_grace_time == 0)
++ return;
++
++ if (grace_watchdog_pid != -1) {
++ error("login_grace_time watchdog process already running");
++ return;
++ }
++
++ grace_watchdog_pid = fork();
++ if (grace_watchdog_pid == -1)
++ fatal("fork of login_grace_time watchdog process failed");
++ else if (grace_watchdog_pid > 0)
++ return;
++
++ /* child */
++
++ /* close open fds, including client socket and startup_pipe */
++ closefrom(3);
++
++ /* kill the monitor with SIGTERM after timeout + threshold */
++ sleep_reliably(login_grace_time + GRACE_WATCHDOG_THRESHOLD);
++ if (getppid() != ppid) {
++ debug("login_grace_time watchdog still active, "
++ "but watched process %d already exited.", (int)ppid);
++ exit(0);
++ }
++ error("Timeout before authentication for %s. Killing process %d "
++ "with SIGTERM.", ssh_remote_ipaddr(active_state), (int)ppid);
++ kill(ppid, SIGTERM);
++
++ /* if neccessary, kill it with SIGKILL */
++ sleep_reliably(GRACE_WATCHDOG_THRESHOLD);
++ if (getppid() != ppid)
++ exit(0);
++ error("Watched process %d did not respond to SIGTERM. "
++ "Killing it with SIGKILL.", (int)ppid);
++ kill(ppid, SIGKILL);
++
++ /* give up */
++ sleep_reliably(GRACE_WATCHDOG_THRESHOLD);
++ if (getppid() == ppid) {
++ error("login_grace_time watchdog failed to kill %d", (int)ppid);
++ exit(255);
++ }
++ exit(0);
++}
++
++/* kill grace watchdog process */
++static void
++stop_grace_watchdog()
++{
++ if (grace_watchdog_pid == -1) {
++ debug3("login_grace_time watchdog process not running");
++ return;
++ }
++
++ kill(grace_watchdog_pid, SIGTERM);
++ grace_watchdog_pid = -1;
++}
++
++
+ /*
+ * Signal handler for the key regeneration alarm. Note that this
+ * alarm only occurs in the daemon waiting for connections, and it does not
+@@ -723,6 +816,7 @@ privsep_preauth(Authctxt *authctxt)
+ /* child */
+ close(pmonitor->m_sendfd);
+ close(pmonitor->m_log_recvfd);
++ grace_watchdog_pid = -1;
+
+ /* Arrange for logging to be sent to the monitor */
+ set_log_handler(mm_log_handler, pmonitor);
+@@ -2235,8 +2329,10 @@ main(int ac, char **av)
+ * are about to discover the bug.
+ */
+ signal(SIGALRM, grace_alarm_handler);
+- if (!debug_flag)
++ if (!debug_flag) {
+ alarm(options.login_grace_time);
++ start_grace_watchdog(options.login_grace_time);
++ }
+
+ sshd_exchange_identification(ssh, sock_in, sock_out);
+
+@@ -2302,6 +2398,7 @@ main(int ac, char **av)
+ */
+ alarm(0);
+ signal(SIGALRM, SIG_DFL);
++ stop_grace_watchdog();
+ authctxt->authenticated = 1;
+ if (startup_pipe != -1) {
+ close(startup_pipe);