# HG changeset patch # User Tomas Kuthan # Date 1475763981 25200 # Node ID f2f4b9922ef9f14161d4836eb57bdcb08e8924a5 # Parent a62a393ea750a9584773298b66501c152726c7de 23223069 problem in UTILITY/OPENSSH diff -r a62a393ea750 -r f2f4b9922ef9 components/openssh/patches/047-login_grace_time_watchdog.patch --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/components/openssh/patches/047-login_grace_time_watchdog.patch Thu Oct 06 07:26:21 2016 -0700 @@ -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 openssh@openssh.com 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);