jonathancammack / rpms / openssh

Forked from rpms/openssh 8 months ago
Clone

Blame SOURCES/openssh-6.6p1-ssh-agent-and-xsecurity-bypass.patch

674526
diff -up openssh-6.6p1/channels.c.security openssh-6.6p1/channels.c
674526
--- openssh-6.6p1/channels.c.security	2015-07-01 19:27:08.521162690 +0200
674526
+++ openssh-6.6p1/channels.c	2015-07-01 19:27:08.597162521 +0200
674526
@@ -151,6 +151,9 @@ static char *x11_saved_proto = NULL;
674526
 static char *x11_saved_data = NULL;
674526
 static u_int x11_saved_data_len = 0;
674526
 
674526
+/* Deadline after which all X11 connections are refused */
674526
+static u_int x11_refuse_time;
674526
+
674526
 /*
674526
  * Fake X11 authentication data.  This is what the server will be sending us;
674526
  * we should replace any occurrences of this by the real data.
674526
@@ -894,6 +897,13 @@ x11_open_helper(Buffer *b)
674526
 	u_char *ucp;
674526
 	u_int proto_len, data_len;
674526
 
674526
+	/* Is this being called after the refusal deadline? */
674526
+	if (x11_refuse_time != 0 && (u_int)monotime() >= x11_refuse_time) {
674526
+		verbose("Rejected X11 connection after ForwardX11Timeout "
674526
+		    "expired");
674526
+		return -1;
674526
+	}
674526
+
674526
 	/* Check if the fixed size part of the packet is in buffer. */
674526
 	if (buffer_len(b) < 12)
674526
 		return 0;
674526
@@ -1457,6 +1467,12 @@ channel_set_reuseaddr(int fd)
674526
 		error("setsockopt SO_REUSEADDR fd %d: %s", fd, strerror(errno));
674526
 }
674526
 
674526
+void
674526
+channel_set_x11_refuse_time(u_int refuse_time)
674526
+{
674526
+	x11_refuse_time = refuse_time;
674526
+}
674526
+
674526
 /*
674526
  * This socket is listening for connections to a forwarded TCP/IP port.
674526
  */
674526
diff -up openssh-6.6p1/channels.h.security openssh-6.6p1/channels.h
674526
--- openssh-6.6p1/channels.h.security	2015-07-01 19:27:08.597162521 +0200
674526
+++ openssh-6.6p1/channels.h	2015-07-01 19:43:32.900950560 +0200
674526
@@ -279,6 +279,7 @@ int	 permitopen_port(const char *);
674526
 
674526
 /* x11 forwarding */
674526
 
674526
+void	 channel_set_x11_refuse_time(u_int);
674526
 int	 x11_connect_display(void);
674526
 int	 x11_create_display_inet(int, int, int, u_int *, int **);
674526
 void     x11_input_open(int, u_int32_t, void *);
674526
diff -up openssh-6.6p1/clientloop.c.security openssh-6.6p1/clientloop.c
674526
--- openssh-6.6p1/clientloop.c.security	2015-07-01 19:27:08.540162648 +0200
674526
+++ openssh-6.6p1/clientloop.c	2015-07-01 19:44:51.139761508 +0200
674526
@@ -164,7 +164,7 @@ static int connection_in;	/* Connection
674526
 static int connection_out;	/* Connection to server (output). */
674526
 static int need_rekeying;	/* Set to non-zero if rekeying is requested. */
674526
 static int session_closed;	/* In SSH2: login session closed. */
674526
-static int x11_refuse_time;	/* If >0, refuse x11 opens after this time. */
674526
+static u_int x11_refuse_time;	/* If >0, refuse x11 opens after this time. */
674526
 
674526
 static void client_init_dispatch(void);
674526
 int	session_ident = -1;
674526
@@ -302,7 +302,8 @@ client_x11_display_valid(const char *dis
674526
 	return 1;
674526
 }
674526
 
674526
-#define SSH_X11_PROTO "MIT-MAGIC-COOKIE-1"
674526
+#define SSH_X11_PROTO		"MIT-MAGIC-COOKIE-1"
674526
+#define X11_TIMEOUT_SLACK	60
674526
 void
674526
 client_x11_get_proto(const char *display, const char *xauth_path,
674526
     u_int trusted, u_int timeout, char **_proto, char **_data)
674526
@@ -315,7 +316,7 @@ client_x11_get_proto(const char *display
674526
 	int got_data = 0, generated = 0, do_unlink = 0, i;
674526
 	char *xauthdir, *xauthfile;
674526
 	struct stat st;
674526
-	u_int now;
674526
+	u_int now, x11_timeout_real;
674526
 
674526
 	xauthdir = xauthfile = NULL;
674526
 	*_proto = proto;
674526
@@ -348,6 +349,15 @@ client_x11_get_proto(const char *display
674526
 			xauthdir = xmalloc(MAXPATHLEN);
674526
 			xauthfile = xmalloc(MAXPATHLEN);
674526
 			mktemp_proto(xauthdir, MAXPATHLEN);
674526
+			/*
674526
+			 * The authentication cookie should briefly outlive
674526
+			 * ssh's willingness to forward X11 connections to
674526
+			 * avoid nasty fail-open behaviour in the X server.
674526
+			 */
674526
+			if (timeout >= UINT_MAX - X11_TIMEOUT_SLACK)
674526
+				x11_timeout_real = UINT_MAX;
674526
+			else
674526
+				x11_timeout_real = timeout + X11_TIMEOUT_SLACK;
674526
 			if (mkdtemp(xauthdir) != NULL) {
674526
 				do_unlink = 1;
674526
 				snprintf(xauthfile, MAXPATHLEN, "%s/xauthfile",
674526
@@ -355,17 +365,20 @@ client_x11_get_proto(const char *display
674526
 				snprintf(cmd, sizeof(cmd),
674526
 				    "%s -f %s generate %s " SSH_X11_PROTO
674526
 				    " untrusted timeout %u 2>" _PATH_DEVNULL,
674526
-				    xauth_path, xauthfile, display, timeout);
674526
+				    xauth_path, xauthfile, display,
674526
+				    x11_timeout_real);
674526
 				debug2("x11_get_proto: %s", cmd);
674526
-				if (system(cmd) == 0)
674526
-					generated = 1;
674526
 				if (x11_refuse_time == 0) {
674526
 					now = monotime() + 1;
674526
 					if (UINT_MAX - timeout < now)
674526
 						x11_refuse_time = UINT_MAX;
674526
 					else
674526
 						x11_refuse_time = now + timeout;
674526
+					channel_set_x11_refuse_time(
674526
+					    x11_refuse_time);
674526
 				}
674526
+				if (system(cmd) == 0)
674526
+					generated = 1;
674526
 			}
674526
 		}
674526
 
674526
@@ -1884,7 +1897,7 @@ client_request_x11(const char *request_t
674526
 		    "malicious server.");
674526
 		return NULL;
674526
 	}
674526
-	if (x11_refuse_time != 0 && monotime() >= x11_refuse_time) {
674526
+	if (x11_refuse_time != 0 && (u_int)monotime() >= x11_refuse_time) {
674526
 		verbose("Rejected X11 connection after ForwardX11Timeout "
674526
 		    "expired");
674526
 		return NULL;
674526
diff -up openssh-6.6p1/ssh-agent.c.security openssh-6.6p1/ssh-agent.c
674526
--- openssh-6.6p1/ssh-agent.c.security	2015-07-01 19:27:08.597162521 +0200
674526
+++ openssh-6.6p1/ssh-agent.c	2015-07-01 19:42:35.691088800 +0200
674526
@@ -64,6 +64,9 @@
674526
 #include <time.h>
674526
 #include <string.h>
674526
 #include <unistd.h>
674526
+#ifdef HAVE_UTIL_H
674526
+#include <util.h>
674526
+#endif
674526
 
674526
 #include "xmalloc.h"
674526
 #include "ssh.h"
674526
@@ -129,8 +130,12 @@ char socket_name[MAXPATHLEN];
674526
 char socket_dir[MAXPATHLEN];
674526
 
674526
 /* locking */
674526
+#define LOCK_SIZE	32
674526
+#define LOCK_SALT_SIZE	16
674526
+#define LOCK_ROUNDS	1
674526
 int locked = 0;
674526
-char *lock_passwd = NULL;
674526
+char lock_passwd[LOCK_SIZE];
674526
+char lock_salt[LOCK_SALT_SIZE];
674526
 
674526
 extern char *__progname;
674526
 
674526
@@ -548,22 +553,45 @@ send:
674526
 static void
674526
 process_lock_agent(SocketEntry *e, int lock)
674526
 {
674526
-	int success = 0;
674526
-	char *passwd;
674526
+	int success = 0, delay;
674526
+	char *passwd, passwdhash[LOCK_SIZE];
674526
+	static u_int fail_count = 0;
674526
+	size_t pwlen;
674526
 
674526
 	passwd = buffer_get_string(&e->request, NULL);
674526
-	if (locked && !lock && strcmp(passwd, lock_passwd) == 0) {
674526
-		locked = 0;
674526
-		explicit_bzero(lock_passwd, strlen(lock_passwd));
674526
-		free(lock_passwd);
674526
-		lock_passwd = NULL;
674526
-		success = 1;
674526
+	pwlen = strlen(passwd);
674526
+	if (pwlen == 0) {
674526
+		debug("empty password not supported");
674526
+	} else if (locked && !lock) {
674526
+		if (bcrypt_pbkdf(passwd, pwlen, lock_salt, sizeof(lock_salt),
674526
+		    passwdhash, sizeof(passwdhash), LOCK_ROUNDS) < 0)
674526
+			fatal("bcrypt_pbkdf");
674526
+		if (timingsafe_bcmp(passwdhash, lock_passwd, LOCK_SIZE) == 0) {
674526
+			debug("agent unlocked");
674526
+			locked = 0;
674526
+			fail_count = 0;
674526
+			explicit_bzero(lock_passwd, sizeof(lock_passwd));
674526
+			success = 1;
674526
+		} else {
674526
+			/* delay in 0.1s increments up to 10s */
674526
+			if (fail_count < 100)
674526
+				fail_count++;
674526
+			delay = 100000 * fail_count;
674526
+			debug("unlock failed, delaying %0.1lf seconds",
674526
+			    (double)delay/1000000);
674526
+			usleep(delay);
674526
+		}
674526
+		explicit_bzero(passwdhash, sizeof(passwdhash));
674526
 	} else if (!locked && lock) {
674526
+		debug("agent locked");
674526
 		locked = 1;
674526
-		lock_passwd = xstrdup(passwd);
674526
+		arc4random_buf(lock_salt, sizeof(lock_salt));
674526
+		if (bcrypt_pbkdf(passwd, pwlen, lock_salt, sizeof(lock_salt),
674526
+		    lock_passwd, sizeof(lock_passwd), LOCK_ROUNDS) < 0)
674526
+			fatal("bcrypt_pbkdf");
674526
 		success = 1;
674526
 	}
674526
-	explicit_bzero(passwd, strlen(passwd));
674526
+	explicit_bzero(passwd, pwlen);
674526
 	free(passwd);
674526
 
674526
 	buffer_put_int(&e->output, 1);