[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Bug#923486: CVE-2019-6111 not fixed, file transfer of unwanted files by malicious SSH server still possible



Hi Colin, hi Debian LTS team,

On  Fr 01 Mär 2019 13:24:30 CET, Colin Watson wrote:

And yes, it looks OK - I'll upload it to unstable shortly.

I have prepared a backport of this newly added patch [1] (see #923486 for details) to openssh in Debian jessie LTS, but with that patch backported to openssh in Debian jessie, I get a segmentation fault whenever I copy something using the scp cmdline tool (I have of course backported all other patches regarding CVE-2019-6109 and CVE-2019-6111).

I have attached the complete .debdiff between openssh 1:6.7p1-5+deb8u7 (in jessie-security) and my (not-yet-)proposal for 1:6.7p1-5+deb8u8.

The critical patch is CVE-2019-6111-2.patch. With that patch added I get segfaults with scp. Without that patch scp works, but is susceptible to the earlier mentioned exploit for CVE-2019-6111.

I am a bit lost here and would appreciate some ideas about what is going wrong here.

I will only be able to continue on this on Monday, but maybe someone else can offer some genuine input over the weekend. Will be much appreciated.

Thanks+Greets,
Mike

[1] https://anongit.mindrot.org/openssh.git/commit/?id=3d896c157c722bc47adca51a58dca859225b5874
--

mike gabriel aka sunweaver (Debian Developer)
mobile: +49 (1520) 1976 148
landline: +49 (4354) 8390 139

GnuPG Fingerprint: 9BFB AEE8 6C0A A5FF BF22  0782 9AF4 6B30 2577 1B31
mail: sunweaver@debian.org, http://sunweavers.net

diff -Nru openssh-6.7p1/debian/changelog openssh-6.7p1/debian/changelog
--- openssh-6.7p1/debian/changelog	2018-09-12 13:23:59.000000000 +0200
+++ openssh-6.7p1/debian/changelog	2019-02-01 00:45:09.000000000 +0100
@@ -1,3 +1,16 @@
+openssh (1:6.7p1-5+deb8u8) jessie-security; urgency=medium
+
+  * Non-maintainer upload by the LTS Team.
+  * CVE-2018-20685: Disallow empty incoming filename or ones that refer
+    to the current directory; based on report/patch from Harry Sintonen.
+  * CVE-2019-6109: Sanitize scp filenames via snmprintf. To do this we move
+    the progressmeter formatting outside of signal handler context and have the
+    atomicio callback called for EINTR, too.
+  * CVE-2019-6111: Check in scp client that filenames sent during remote->local
+    directory copies satisfy the wildcard specified by the user.
+
+ -- Mike Gabriel <sunweaver@debian.org>  Fri, 01 Feb 2019 00:45:09 +0100
+
 openssh (1:6.7p1-5+deb8u7) jessie-security; urgency=medium
 
   * Add debian/patches/CVE-2016-1908-3.patch: client_x11_get_proto: check if
diff -Nru openssh-6.7p1/debian/patches/CVE-2018-20685.patch openssh-6.7p1/debian/patches/CVE-2018-20685.patch
--- openssh-6.7p1/debian/patches/CVE-2018-20685.patch	1970-01-01 01:00:00.000000000 +0100
+++ openssh-6.7p1/debian/patches/CVE-2018-20685.patch	2019-02-01 00:35:55.000000000 +0100
@@ -0,0 +1,27 @@
+From 6010c0303a422a9c5fa8860c061bf7105eb7f8b2 Mon Sep 17 00:00:00 2001
+From: "djm@openbsd.org" <djm@openbsd.org>
+Date: Fri, 16 Nov 2018 03:03:10 +0000
+Subject: [PATCH] upstream: disallow empty incoming filename or ones that refer
+ to the
+
+current directory; based on report/patch from Harry Sintonen
+
+OpenBSD-Commit-ID: f27651b30eaee2df49540ab68d030865c04f6de9
+
+[sunweaver] - Ported to OpenSSH 1:6.0p1 as found in Debian wheezy (ELTS)
+---
+ scp.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/scp.c
++++ b/scp.c
+@@ -1039,7 +1039,8 @@
+ 			size = size * 10 + (*cp++ - '0');
+ 		if (*cp++ != ' ')
+ 			SCREWUP("size not delimited");
+-		if ((strchr(cp, '/') != NULL) || (strcmp(cp, "..") == 0)) {
++		if (*cp == '\0' || strchr(cp, '/') != NULL ||
++		    strcmp(cp, ".") == 0 || strcmp(cp, "..") == 0) {
+ 			run_err("error: unexpected filename: %s", cp);
+ 			exit(1);
+ 		}
diff -Nru openssh-6.7p1/debian/patches/CVE-2019-6109-1.patch openssh-6.7p1/debian/patches/CVE-2019-6109-1.patch
--- openssh-6.7p1/debian/patches/CVE-2019-6109-1.patch	1970-01-01 01:00:00.000000000 +0100
+++ openssh-6.7p1/debian/patches/CVE-2019-6109-1.patch	2019-01-31 17:17:12.000000000 +0100
@@ -0,0 +1,253 @@
+Backport of:
+
+From 8976f1c4b2721c26e878151f52bdf346dfe2d54c Mon Sep 17 00:00:00 2001
+From: "dtucker@openbsd.org" <dtucker@openbsd.org>
+Date: Wed, 23 Jan 2019 08:01:46 +0000
+Subject: [PATCH] upstream: Sanitize scp filenames via snmprintf. To do this we
+ move
+
+the progressmeter formatting outside of signal handler context and have the
+atomicio callback called for EINTR too.  bz#2434 with contributions from djm
+and jjelen at redhat.com, ok djm@
+
+OpenBSD-Commit-ID: 1af61c1f70e4f3bd8ab140b9f1fa699481db57d8
+---
+ atomicio.c      | 20 ++++++++++++++-----
+ progressmeter.c | 53 ++++++++++++++++++++++---------------------------
+ progressmeter.h |  3 ++-
+ scp.c           |  3 ++-
+ sftp-client.c   | 18 +++++++++--------
+ 5 files changed, 53 insertions(+), 44 deletions(-)
+
+Index: openssh-6.6p1/atomicio.c
+===================================================================
+--- openssh-6.6p1.orig/atomicio.c	2019-01-31 11:14:44.883222450 -0500
++++ openssh-6.6p1/atomicio.c	2019-01-31 11:14:44.883222450 -0500
+@@ -64,9 +64,14 @@ atomicio6(ssize_t (*f) (int, void *, siz
+ 		res = (f) (fd, s + pos, n - pos);
+ 		switch (res) {
+ 		case -1:
+-			if (errno == EINTR)
++			if (errno == EINTR) {
++				/* possible SIGALARM, update callback */
++				if (cb != NULL && cb(cb_arg, 0) == -1) {
++					errno = EINTR;
++					return pos;
++				}
+ 				continue;
+-			if (errno == EAGAIN || errno == EWOULDBLOCK) {
++			} else if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ #ifndef BROKEN_READ_COMPARISON
+ 				(void)poll(&pfd, 1, -1);
+ #endif
+@@ -121,9 +126,14 @@ atomiciov6(ssize_t (*f) (int, const stru
+ 		res = (f) (fd, iov, iovcnt);
+ 		switch (res) {
+ 		case -1:
+-			if (errno == EINTR)
++			if (errno == EINTR) {
++				/* possible SIGALARM, update callback */
++				if (cb != NULL && cb(cb_arg, 0) == -1) {
++					errno = EINTR;
++					return pos;
++				}
+ 				continue;
+-			if (errno == EAGAIN || errno == EWOULDBLOCK) {
++			} else if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ #ifndef BROKEN_READV_COMPARISON
+ 				(void)poll(&pfd, 1, -1);
+ #endif
+Index: openssh-6.6p1/progressmeter.c
+===================================================================
+--- openssh-6.6p1.orig/progressmeter.c	2019-01-31 11:14:44.883222450 -0500
++++ openssh-6.6p1/progressmeter.c	2019-01-31 11:14:44.883222450 -0500
+@@ -31,6 +31,7 @@
+ 
+ #include <errno.h>
+ #include <signal.h>
++#include <stdarg.h>
+ #include <stdio.h>
+ #include <string.h>
+ #include <time.h>
+@@ -39,6 +40,7 @@
+ #include "progressmeter.h"
+ #include "atomicio.h"
+ #include "misc.h"
++#include "utf8.h"
+ 
+ #define DEFAULT_WINSIZE 80
+ #define MAX_WINSIZE 512
+@@ -61,7 +63,7 @@ static void setscreensize(void);
+ void refresh_progress_meter(void);
+ 
+ /* signal handler for updating the progress meter */
+-static void update_progress_meter(int);
++static void sig_alarm(int);
+ 
+ static time_t start;		/* start progress */
+ static time_t last_update;	/* last progress update */
+@@ -74,6 +76,7 @@ static long stalled;		/* how long we hav
+ static int bytes_per_second;	/* current speed in bytes per second */
+ static int win_size;		/* terminal window size */
+ static volatile sig_atomic_t win_resized; /* for window resizing */
++static volatile sig_atomic_t alarm_fired;
+ 
+ /* units for format_size */
+ static const char unit[] = " KMGT";
+@@ -127,9 +130,17 @@ refresh_progress_meter(void)
+ 	off_t bytes_left;
+ 	int cur_speed;
+ 	int hours, minutes, seconds;
+-	int i, len;
+ 	int file_len;
+ 
++	if ((!alarm_fired && !win_resized) || !can_output())
++		return;
++	alarm_fired = 0;
++
++	if (win_resized) {
++		setscreensize();
++		win_resized = 0;
++	}
++
+ 	transferred = *counter - (cur_pos ? cur_pos : start_pos);
+ 	cur_pos = *counter;
+ 	now = monotime();
+@@ -159,16 +170,11 @@ refresh_progress_meter(void)
+ 
+ 	/* filename */
+ 	buf[0] = '\0';
+-	file_len = win_size - 35;
++	file_len = win_size - 36;
+ 	if (file_len > 0) {
+-		len = snprintf(buf, file_len + 1, "\r%s", file);
+-		if (len < 0)
+-			len = 0;
+-		if (len >= file_len + 1)
+-			len = file_len;
+-		for (i = len; i < file_len; i++)
+-			buf[i] = ' ';
+-		buf[file_len] = '\0';
++		buf[0] = '\r';
++		snmprintf(buf+1, sizeof(buf)-1 , &file_len, "%*s",
++		    file_len * -1, file);
+ 	}
+ 
+ 	/* percent of transfer done */
+@@ -229,22 +235,11 @@ refresh_progress_meter(void)
+ 
+ /*ARGSUSED*/
+ static void
+-update_progress_meter(int ignore)
++sig_alarm(int ignore)
+ {
+-	int save_errno;
+-
+-	save_errno = errno;
+-
+-	if (win_resized) {
+-		setscreensize();
+-		win_resized = 0;
+-	}
+-	if (can_output())
+-		refresh_progress_meter();
+-
+-	signal(SIGALRM, update_progress_meter);
++	signal(SIGALRM, sig_alarm);
++	alarm_fired = 1;
+ 	alarm(UPDATE_INTERVAL);
+-	errno = save_errno;
+ }
+ 
+ void
+@@ -260,10 +255,9 @@ start_progress_meter(char *f, off_t file
+ 	bytes_per_second = 0;
+ 
+ 	setscreensize();
+-	if (can_output())
+-		refresh_progress_meter();
++	refresh_progress_meter();
+ 
+-	signal(SIGALRM, update_progress_meter);
++	signal(SIGALRM, sig_alarm);
+ 	signal(SIGWINCH, sig_winch);
+ 	alarm(UPDATE_INTERVAL);
+ }
+@@ -287,6 +281,7 @@ stop_progress_meter(void)
+ static void
+ sig_winch(int sig)
+ {
++	signal(SIGWINCH, sig_winch);
+ 	win_resized = 1;
+ }
+ 
+Index: openssh-6.6p1/progressmeter.h
+===================================================================
+--- openssh-6.6p1.orig/progressmeter.h	2019-01-31 11:14:44.883222450 -0500
++++ openssh-6.6p1/progressmeter.h	2019-01-31 11:15:00.435233556 -0500
+@@ -24,4 +24,5 @@
+  */
+ 
+ void	start_progress_meter(char *, off_t, off_t *);
++void	refresh_progress_meter(void);
+ void	stop_progress_meter(void);
+Index: openssh-6.6p1/scp.c
+===================================================================
+--- openssh-6.6p1.orig/scp.c	2019-01-31 11:14:44.883222450 -0500
++++ openssh-6.6p1/scp.c	2019-01-31 11:14:44.883222450 -0500
+@@ -559,6 +559,7 @@ scpio(void *_cnt, size_t s)
+ 	off_t *cnt = (off_t *)_cnt;
+ 
+ 	*cnt += s;
++	refresh_progress_meter();
+ 	if (limit_kbps > 0)
+ 		bandwidth_limit(&bwlimit, s);
+ 	return 0;
+Index: openssh-6.6p1/sftp-client.c
+===================================================================
+--- openssh-6.6p1.orig/sftp-client.c	2019-01-31 11:14:44.883222450 -0500
++++ openssh-6.6p1/sftp-client.c	2019-01-31 11:17:00.723357486 -0500
+@@ -93,7 +93,9 @@ sftpio(void *_bwlimit, size_t amount)
+ {
+ 	struct bwlimit *bwlimit = (struct bwlimit *)_bwlimit;
+ 
+-	bandwidth_limit(bwlimit, amount);
++	refresh_progress_meter();
++	if (bwlimit != NULL)
++		bandwidth_limit(bwlimit, amount);
+ 	return 0;
+ }
+ 
+@@ -113,8 +115,8 @@ send_msg(struct sftp_conn *conn, Buffer
+ 	iov[1].iov_base = buffer_ptr(m);
+ 	iov[1].iov_len = buffer_len(m);
+ 
+-	if (atomiciov6(writev, conn->fd_out, iov, 2,
+-	    conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_out) !=
++	if (atomiciov6(writev, conn->fd_out, iov, 2, sftpio,
++	    conn->limit_kbps > 0 ? &conn->bwlimit_out : NULL) !=
+ 	    buffer_len(m) + sizeof(mlen))
+ 		fatal("Couldn't send packet: %s", strerror(errno));
+ 
+@@ -127,8 +129,8 @@ get_msg(struct sftp_conn *conn, Buffer *
+ 	u_int msg_len;
+ 
+ 	buffer_append_space(m, 4);
+-	if (atomicio6(read, conn->fd_in, buffer_ptr(m), 4,
+-	    conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_in) != 4) {
++	if (atomicio6(read, conn->fd_in, buffer_ptr(m), 4, sftpio,
++	    conn->limit_kbps > 0 ? &conn->bwlimit_in : NULL) != 4) {
+ 		if (errno == EPIPE)
+ 			fatal("Connection closed");
+ 		else
+@@ -140,8 +142,8 @@ get_msg(struct sftp_conn *conn, Buffer *
+ 		fatal("Received message too long %u", msg_len);
+ 
+ 	buffer_append_space(m, msg_len);
+-	if (atomicio6(read, conn->fd_in, buffer_ptr(m), msg_len,
+-	    conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_in)
++	if (atomicio6(read, conn->fd_in, buffer_ptr(m), msg_len, sftpio,
++	    conn->limit_kbps > 0 ? &conn->bwlimit_in : NULL)
+ 	    != msg_len) {
+ 		if (errno == EPIPE)
+ 			fatal("Connection closed");
diff -Nru openssh-6.7p1/debian/patches/CVE-2019-6109-2.patch openssh-6.7p1/debian/patches/CVE-2019-6109-2.patch
--- openssh-6.7p1/debian/patches/CVE-2019-6109-2.patch	1970-01-01 01:00:00.000000000 +0100
+++ openssh-6.7p1/debian/patches/CVE-2019-6109-2.patch	2019-01-31 17:18:12.000000000 +0100
@@ -0,0 +1,106 @@
+Backport of:
+
+From bdc6c63c80b55bcbaa66b5fde31c1cb1d09a41eb Mon Sep 17 00:00:00 2001
+From: "dtucker@openbsd.org" <dtucker@openbsd.org>
+Date: Thu, 24 Jan 2019 16:52:17 +0000
+Subject: [PATCH] upstream: Have progressmeter force an update at the beginning
+ and
+
+end of each transfer.  Fixes the problem recently introduces where very quick
+transfers do not display the progressmeter at all.  Spotted by naddy@
+
+OpenBSD-Commit-ID: 68dc46c259e8fdd4f5db3ec2a130f8e4590a7a9a
+---
+ progressmeter.c | 13 +++++--------
+ progressmeter.h |  4 ++--
+ scp.c           |  4 ++--
+ sftp-client.c   |  4 ++--
+ 4 files changed, 11 insertions(+), 14 deletions(-)
+
+Index: openssh-6.6p1/progressmeter.c
+===================================================================
+--- openssh-6.6p1.orig/progressmeter.c	2019-01-31 11:17:55.855434181 -0500
++++ openssh-6.6p1/progressmeter.c	2019-01-31 11:17:55.851434175 -0500
+@@ -59,9 +59,6 @@ static void format_rate(char *, int, off
+ static void sig_winch(int);
+ static void setscreensize(void);
+ 
+-/* updates the progressmeter to reflect the current state of the transfer */
+-void refresh_progress_meter(void);
+-
+ /* signal handler for updating the progress meter */
+ static void sig_alarm(int);
+ 
+@@ -120,7 +117,7 @@ format_size(char *buf, int size, off_t b
+ }
+ 
+ void
+-refresh_progress_meter(void)
++refresh_progress_meter(int force_update)
+ {
+ 	char buf[MAX_WINSIZE + 1];
+ 	time_t now;
+@@ -132,7 +129,7 @@ refresh_progress_meter(void)
+ 	int hours, minutes, seconds;
+ 	int file_len;
+ 
+-	if ((!alarm_fired && !win_resized) || !can_output())
++	if ((!force_update && !alarm_fired && !win_resized) || !can_output())
+ 		return;
+ 	alarm_fired = 0;
+ 
+@@ -255,7 +252,7 @@ start_progress_meter(char *f, off_t file
+ 	bytes_per_second = 0;
+ 
+ 	setscreensize();
+-	refresh_progress_meter();
++	refresh_progress_meter(1);
+ 
+ 	signal(SIGALRM, sig_alarm);
+ 	signal(SIGWINCH, sig_winch);
+@@ -272,7 +269,7 @@ stop_progress_meter(void)
+ 
+ 	/* Ensure we complete the progress */
+ 	if (cur_pos != end_pos)
+-		refresh_progress_meter();
++		refresh_progress_meter(1);
+ 
+ 	atomicio(vwrite, STDOUT_FILENO, "\n", 1);
+ }
+Index: openssh-6.6p1/progressmeter.h
+===================================================================
+--- openssh-6.6p1.orig/progressmeter.h	2019-01-31 11:17:55.855434181 -0500
++++ openssh-6.6p1/progressmeter.h	2019-01-31 11:18:07.575451909 -0500
+@@ -24,5 +24,5 @@
+  */
+ 
+ void	start_progress_meter(char *, off_t, off_t *);
+-void	refresh_progress_meter(void);
++void	refresh_progress_meter(int);
+ void	stop_progress_meter(void);
+Index: openssh-6.6p1/scp.c
+===================================================================
+--- openssh-6.6p1.orig/scp.c	2019-01-31 11:17:55.855434181 -0500
++++ openssh-6.6p1/scp.c	2019-01-31 11:17:55.851434175 -0500
+@@ -559,7 +559,7 @@ scpio(void *_cnt, size_t s)
+ 	off_t *cnt = (off_t *)_cnt;
+ 
+ 	*cnt += s;
+-	refresh_progress_meter();
++	refresh_progress_meter(0);
+ 	if (limit_kbps > 0)
+ 		bandwidth_limit(&bwlimit, s);
+ 	return 0;
+Index: openssh-6.6p1/sftp-client.c
+===================================================================
+--- openssh-6.6p1.orig/sftp-client.c	2019-01-31 11:17:55.855434181 -0500
++++ openssh-6.6p1/sftp-client.c	2019-01-31 11:17:55.851434175 -0500
+@@ -93,7 +93,7 @@ sftpio(void *_bwlimit, size_t amount)
+ {
+ 	struct bwlimit *bwlimit = (struct bwlimit *)_bwlimit;
+ 
+-	refresh_progress_meter();
++	refresh_progress_meter(0);
+ 	if (bwlimit != NULL)
+ 		bandwidth_limit(bwlimit, amount);
+ 	return 0;
diff -Nru openssh-6.7p1/debian/patches/CVE-2019-6109-pre1.patch openssh-6.7p1/debian/patches/CVE-2019-6109-pre1.patch
--- openssh-6.7p1/debian/patches/CVE-2019-6109-pre1.patch	1970-01-01 01:00:00.000000000 +0100
+++ openssh-6.7p1/debian/patches/CVE-2019-6109-pre1.patch	2019-02-01 00:45:09.000000000 +0100
@@ -0,0 +1,398 @@
+Description: add utf8.c to get snmprintf
+Origin: backported from OpenSSH 7.7p1
+
+--- a/Makefile.in
++++ b/Makefile.in
+@@ -79,7 +79,7 @@
+ 	compat.o compress.o crc32.o deattack.o fatal.o hostfile.o \
+ 	log.o match.o md-sha256.o moduli.o nchan.o packet.o \
+ 	readpass.o rsa.o ttymodes.o xmalloc.o addrmatch.o \
+-	atomicio.o key.o dispatch.o kex.o mac.o uidswap.o uuencode.o misc.o \
++	atomicio.o key.o dispatch.o kex.o mac.o uidswap.o uuencode.o misc.o utf8.o \
+ 	monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-rsa.o dh.o \
+ 	kexdh.o kexgex.o kexdhc.o kexgexc.o bufec.o kexecdh.o kexecdhc.o \
+ 	kexgssc.o \
+--- /dev/null
++++ b/utf8.c
+@@ -0,0 +1,335 @@
++/* $OpenBSD: utf8.c,v 1.7 2017/05/31 09:15:42 deraadt Exp $ */
++/*
++ * Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org>
++ *
++ * Permission to use, copy, modify, and distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ */
++
++/*
++ * Utility functions for multibyte-character handling,
++ * in particular to sanitize untrusted strings for terminal output.
++ */
++
++#include "includes.h"
++
++#include <sys/types.h>
++#ifdef HAVE_LANGINFO_H
++# include <langinfo.h>
++#endif
++#include <limits.h>
++#include <locale.h>
++#include <stdarg.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS)
++# include <vis.h>
++#endif
++#ifdef HAVE_WCHAR_H
++# include <wchar.h>
++#endif
++
++#include "utf8.h"
++
++static int	 dangerous_locale(void);
++static int	 grow_dst(char **, size_t *, size_t, char **, size_t);
++static int	 vasnmprintf(char **, size_t, int *, const char *, va_list);
++
++
++/*
++ * For US-ASCII and UTF-8 encodings, we can safely recover from
++ * encoding errors and from non-printable characters.  For any
++ * other encodings, err to the side of caution and abort parsing:
++ * For state-dependent encodings, recovery is impossible.
++ * For arbitrary encodings, replacement of non-printable
++ * characters would be non-trivial and too fragile.
++ */
++
++static int
++dangerous_locale(void) {
++	char	*loc;
++
++	loc = nl_langinfo(CODESET);
++	return strcmp(loc, "US-ASCII") != 0 && strcmp(loc, "UTF-8") != 0 &&
++	    strcmp(loc, "ANSI_X3.4-1968") != 0 && strcmp(loc, "646") != 0 &&
++	    strcmp(loc, "") != 0;
++}
++
++static int
++grow_dst(char **dst, size_t *sz, size_t maxsz, char **dp, size_t need)
++{
++	char	*tp;
++	size_t	 tsz;
++
++	if (*dp + need < *dst + *sz)
++		return 0;
++	tsz = *sz + 128;
++	if (tsz > maxsz)
++		tsz = maxsz;
++	if ((tp = realloc(*dst, tsz)) == NULL)
++		return -1;
++	*dp = tp + (*dp - *dst);
++	*dst = tp;
++	*sz = tsz;
++	return 0;
++}
++
++/*
++ * The following two functions limit the number of bytes written,
++ * including the terminating '\0', to sz.  Unless wp is NULL,
++ * they limit the number of display columns occupied to *wp.
++ * Whichever is reached first terminates the output string.
++ * To stay close to the standard interfaces, they return the number of
++ * non-NUL bytes that would have been written if both were unlimited.
++ * If wp is NULL, newline, carriage return, and tab are allowed;
++ * otherwise, the actual number of columns occupied by what was
++ * written is returned in *wp.
++ */
++
++static int
++vasnmprintf(char **str, size_t maxsz, int *wp, const char *fmt, va_list ap)
++{
++	char	*src;	/* Source string returned from vasprintf. */
++	char	*sp;	/* Pointer into src. */
++	char	*dst;	/* Destination string to be returned. */
++	char	*dp;	/* Pointer into dst. */
++	char	*tp;	/* Temporary pointer for dst. */
++	size_t	 sz;	/* Number of bytes allocated for dst. */
++	wchar_t	 wc;	/* Wide character at sp. */
++	int	 len;	/* Number of bytes in the character at sp. */
++	int	 ret;	/* Number of bytes needed to format src. */
++	int	 width;	/* Display width of the character wc. */
++	int	 total_width, max_width, print;
++
++	src = NULL;
++	if ((ret = vasprintf(&src, fmt, ap)) <= 0)
++		goto fail;
++
++	sz = strlen(src) + 1;
++	if ((dst = malloc(sz)) == NULL) {
++		free(src);
++		ret = -1;
++		goto fail;
++	}
++
++	if (maxsz > INT_MAX)
++		maxsz = INT_MAX;
++
++	sp = src;
++	dp = dst;
++	ret = 0;
++	print = 1;
++	total_width = 0;
++	max_width = wp == NULL ? INT_MAX : *wp;
++	while (*sp != '\0') {
++		if ((len = mbtowc(&wc, sp, MB_CUR_MAX)) == -1) {
++			(void)mbtowc(NULL, NULL, MB_CUR_MAX);
++			if (dangerous_locale()) {
++				ret = -1;
++				break;
++			}
++			len = 1;
++			width = -1;
++		} else if (wp == NULL &&
++		    (wc == L'\n' || wc == L'\r' || wc == L'\t')) {
++			/*
++			 * Don't use width uninitialized; the actual
++			 * value doesn't matter because total_width
++			 * is only returned for wp != NULL.
++			 */
++			width = 0;
++		} else if ((width = wcwidth(wc)) == -1 &&
++		    dangerous_locale()) {
++			ret = -1;
++			break;
++		}
++
++		/* Valid, printable character. */
++
++		if (width >= 0) {
++			if (print && (dp - dst >= (int)maxsz - len ||
++			    total_width > max_width - width))
++				print = 0;
++			if (print) {
++				if (grow_dst(&dst, &sz, maxsz,
++				    &dp, len) == -1) {
++					ret = -1;
++					break;
++				}
++				total_width += width;
++				memcpy(dp, sp, len);
++				dp += len;
++			}
++			sp += len;
++			if (ret >= 0)
++				ret += len;
++			continue;
++		}
++
++		/* Escaping required. */
++
++		while (len > 0) {
++			if (print && (dp - dst >= (int)maxsz - 4 ||
++			    total_width > max_width - 4))
++				print = 0;
++			if (print) {
++				if (grow_dst(&dst, &sz, maxsz,
++				    &dp, 4) == -1) {
++					ret = -1;
++					break;
++				}
++				tp = vis(dp, *sp, VIS_OCTAL | VIS_ALL, 0);
++				width = tp - dp;
++				total_width += width;
++				dp = tp;
++			} else
++				width = 4;
++			len--;
++			sp++;
++			if (ret >= 0)
++				ret += width;
++		}
++		if (len > 0)
++			break;
++	}
++	free(src);
++	*dp = '\0';
++	*str = dst;
++	if (wp != NULL)
++		*wp = total_width;
++
++	/*
++	 * If the string was truncated by the width limit but
++	 * would have fit into the size limit, the only sane way
++	 * to report the problem is using the return value, such
++	 * that the usual idiom "if (ret < 0 || ret >= sz) error"
++	 * works as expected.
++	 */
++
++	if (ret < (int)maxsz && !print)
++		ret = -1;
++	return ret;
++
++fail:
++	if (wp != NULL)
++		*wp = 0;
++	if (ret == 0) {
++		*str = src;
++		return 0;
++	} else {
++		*str = NULL;
++		return -1;
++	}
++}
++
++int
++snmprintf(char *str, size_t sz, int *wp, const char *fmt, ...)
++{
++	va_list	 ap;
++	char	*cp;
++	int	 ret;
++
++	va_start(ap, fmt);
++	ret = vasnmprintf(&cp, sz, wp, fmt, ap);
++	va_end(ap);
++	if (cp != NULL) {
++		(void)strlcpy(str, cp, sz);
++		free(cp);
++	} else
++		*str = '\0';
++	return ret;
++}
++
++/*
++ * To stay close to the standard interfaces, the following functions
++ * return the number of non-NUL bytes written.
++ */
++
++int
++vfmprintf(FILE *stream, const char *fmt, va_list ap)
++{
++	char	*str;
++	int	 ret;
++
++	if ((ret = vasnmprintf(&str, INT_MAX, NULL, fmt, ap)) < 0)
++		return -1;
++	if (fputs(str, stream) == EOF)
++		ret = -1;
++	free(str);
++	return ret;
++}
++
++int
++fmprintf(FILE *stream, const char *fmt, ...)
++{
++	va_list	 ap;
++	int	 ret;
++
++	va_start(ap, fmt);
++	ret = vfmprintf(stream, fmt, ap);
++	va_end(ap);
++	return ret;
++}
++
++int
++mprintf(const char *fmt, ...)
++{
++	va_list	 ap;
++	int	 ret;
++
++	va_start(ap, fmt);
++	ret = vfmprintf(stdout, fmt, ap);
++	va_end(ap);
++	return ret;
++}
++
++/*
++ * Set up libc for multibyte output in the user's chosen locale.
++ *
++ * XXX: we are known to have problems with Turkish (i/I confusion) so we
++ *      deliberately fall back to the C locale for now. Longer term we should
++ *      always prefer to select C.[encoding] if possible, but there's no
++ *      standardisation in locales between systems, so we'll need to survey
++ *      what's out there first.
++ */
++void
++msetlocale(void)
++{
++	const char *vars[] = { "LC_ALL", "LC_CTYPE", "LANG", NULL };
++	char *cp;
++	int i;
++
++	/*
++	 * We can't yet cope with dotless/dotted I in Turkish locales,
++	 * so fall back to the C locale for these.
++	 */
++	for (i = 0; vars[i] != NULL; i++) {
++		if ((cp = getenv(vars[i])) == NULL)
++			continue;
++		if (strncasecmp(cp, "TR", 2) != 0)
++			break;
++		/*
++		 * If we're in a UTF-8 locale then prefer to use
++		 * the C.UTF-8 locale (or equivalent) if it exists.
++		 */
++		if ((strcasestr(cp, "UTF-8") != NULL ||
++		    strcasestr(cp, "UTF8") != NULL) &&
++		    (setlocale(LC_CTYPE, "C.UTF-8") != NULL ||
++		    setlocale(LC_CTYPE, "POSIX.UTF-8") != NULL))
++			return;
++		setlocale(LC_CTYPE, "C");
++		return;
++	}
++	/* We can handle this locale */
++	setlocale(LC_CTYPE, "");
++}
+--- /dev/null
++++ b/utf8.h
+@@ -0,0 +1,25 @@
++/* $OpenBSD: utf8.h,v 1.1 2016/05/25 23:48:45 schwarze Exp $ */
++/*
++ * Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org>
++ *
++ * Permission to use, copy, modify, and distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ */
++
++int	 mprintf(const char *, ...)
++	     __attribute__((format(printf, 1, 2)));
++int	 fmprintf(FILE *, const char *, ...)
++	     __attribute__((format(printf, 2, 3)));
++int	 vfmprintf(FILE *, const char *, va_list);
++int	 snmprintf(char *, size_t, int *, const char *, ...)
++	     __attribute__((format(printf, 4, 5)));
++void	 msetlocale(void);
+--- a/configure.ac
++++ b/configure.ac
+@@ -340,6 +340,7 @@
+ 	ia.h \
+ 	iaf.h \
+ 	inttypes.h \
++	langinfo.h \
+ 	limits.h \
+ 	locale.h \
+ 	login.h \
+@@ -392,6 +393,7 @@
+ 	utmp.h \
+ 	utmpx.h \
+ 	vis.h \
++	wchar.h \
+ ])
+ 
+ # lastlog.h requires sys/time.h to be included first on Solaris
diff -Nru openssh-6.7p1/debian/patches/CVE-2019-6109-pre2.patch openssh-6.7p1/debian/patches/CVE-2019-6109-pre2.patch
--- openssh-6.7p1/debian/patches/CVE-2019-6109-pre2.patch	1970-01-01 01:00:00.000000000 +0100
+++ openssh-6.7p1/debian/patches/CVE-2019-6109-pre2.patch	2019-01-31 17:36:03.000000000 +0100
@@ -0,0 +1,133 @@
+From ae9c0d4d5c581b3040d1f16b5c5f4b1cd1616743 Mon Sep 17 00:00:00 2001
+From: Darren Tucker <dtucker@zip.com.au>
+Date: Fri, 3 Jun 2016 16:03:44 +1000
+Subject: [PATCH] Update vis.h and vis.c from OpenBSD.
+
+This will be needed for the upcoming utf8 changes.
+---
+ openbsd-compat/vis.c | 60 +++++++++++++++++++++++++++++++++-----------
+ openbsd-compat/vis.h |  5 +++-
+ 2 files changed, 50 insertions(+), 15 deletions(-)
+
+Index: openssh-6.6p1/openbsd-compat/vis.c
+===================================================================
+--- openssh-6.6p1.orig/openbsd-compat/vis.c	2019-01-31 11:35:35.954123032 -0500
++++ openssh-6.6p1/openbsd-compat/vis.c	2019-01-31 11:35:49.390164333 -0500
+@@ -1,4 +1,4 @@
+-/*	$OpenBSD: vis.c,v 1.19 2005/09/01 17:15:49 millert Exp $ */
++/*	$OpenBSD: vis.c,v 1.25 2015/09/13 11:32:51 guenther Exp $ */
+ /*-
+  * Copyright (c) 1989, 1993
+  *	The Regents of the University of California.  All rights reserved.
+@@ -33,13 +33,24 @@
+ #include "includes.h"
+ #if !defined(HAVE_STRNVIS) || defined(BROKEN_STRNVIS)
+ 
++/*
++ * We want these to override in the BROKEN_STRNVIS case.  TO avoid future sync
++ * problems no-op out the weak symbol definition rather than remove it.
++ */
++#define DEF_WEAK(x)
++
++#include <sys/types.h>
++#include <errno.h>
+ #include <ctype.h>
++#include <limits.h>
+ #include <string.h>
++#include <stdlib.h>
+ 
+ #include "vis.h"
+ 
+ #define	isoctal(c)	(((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
+-#define	isvisible(c)							\
++#define	isvisible(c,flag)						\
++	(((c) == '\\' || (flag & VIS_ALL) == 0) &&			\
+ 	(((u_int)(c) <= UCHAR_MAX && isascii((u_char)(c)) &&		\
+ 	(((c) != '*' && (c) != '?' && (c) != '[' && (c) != '#') ||	\
+ 		(flag & VIS_GLOB) == 0) && isgraph((u_char)(c))) ||	\
+@@ -48,7 +59,7 @@
+ 	((flag & VIS_NL) == 0 && (c) == '\n') ||			\
+ 	((flag & VIS_SAFE) && ((c) == '\b' ||				\
+ 		(c) == '\007' || (c) == '\r' ||				\
+-		isgraph((u_char)(c)))))
++		isgraph((u_char)(c))))))
+ 
+ /*
+  * vis - visually encode characters
+@@ -56,10 +67,11 @@
+ char *
+ vis(char *dst, int c, int flag, int nextc)
+ {
+-	if (isvisible(c)) {
+-		*dst++ = c;
+-		if (c == '\\' && (flag & VIS_NOSLASH) == 0)
++	if (isvisible(c, flag)) {
++		if ((c == '"' && (flag & VIS_DQ) != 0) ||
++		    (c == '\\' && (flag & VIS_NOSLASH) == 0))
+ 			*dst++ = '\\';
++		*dst++ = c;
+ 		*dst = '\0';
+ 		return (dst);
+ 	}
+@@ -136,6 +148,7 @@ done:
+ 	*dst = '\0';
+ 	return (dst);
+ }
++DEF_WEAK(vis);
+ 
+ /*
+  * strvis, strnvis, strvisx - visually encode characters from src into dst
+@@ -161,6 +174,7 @@ strvis(char *dst, const char *src, int f
+ 	*dst = '\0';
+ 	return (dst - start);
+ }
++DEF_WEAK(strvis);
+ 
+ int
+ strnvis(char *dst, const char *src, size_t siz, int flag)
+@@ -171,19 +185,18 @@ strnvis(char *dst, const char *src, size
+ 
+ 	i = 0;
+ 	for (start = dst, end = start + siz - 1; (c = *src) && dst < end; ) {
+-		if (isvisible(c)) {
+-			i = 1;
+-			*dst++ = c;
+-			if (c == '\\' && (flag & VIS_NOSLASH) == 0) {
++		if (isvisible(c, flag)) {
++			if ((c == '"' && (flag & VIS_DQ) != 0) ||
++			    (c == '\\' && (flag & VIS_NOSLASH) == 0)) {
+ 				/* need space for the extra '\\' */
+-				if (dst < end)
+-					*dst++ = '\\';
+-				else {
+-					dst--;
++				if (dst + 1 >= end) {
+ 					i = 2;
+ 					break;
+ 				}
++				*dst++ = '\\';
+ 			}
++			i = 1;
++			*dst++ = c;
+ 			src++;
+ 		} else {
+ 			i = vis(tbuf, c, flag, *++src) - tbuf;
+Index: openssh-6.6p1/openbsd-compat/vis.h
+===================================================================
+--- openssh-6.6p1.orig/openbsd-compat/vis.h	2019-01-31 11:35:35.954123032 -0500
++++ openssh-6.6p1/openbsd-compat/vis.h	2019-01-31 11:35:57.022187828 -0500
+@@ -1,4 +1,4 @@
+-/*	$OpenBSD: vis.h,v 1.11 2005/08/09 19:38:31 millert Exp $	*/
++/*	$OpenBSD: vis.h,v 1.15 2015/07/20 01:52:27 millert Exp $	*/
+ /*	$NetBSD: vis.h,v 1.4 1994/10/26 00:56:41 cgd Exp $	*/
+ 
+ /*-
+@@ -58,6 +58,8 @@
+ #define	VIS_NL		0x10	/* also encode newline */
+ #define	VIS_WHITE	(VIS_SP | VIS_TAB | VIS_NL)
+ #define	VIS_SAFE	0x20	/* only encode "unsafe" characters */
++#define	VIS_DQ		0x200	/* backslash-escape double quotes */
++#define	VIS_ALL		0x400	/* encode all characters */
+ 
+ /*
+  * other
diff -Nru openssh-6.7p1/debian/patches/CVE-2019-6111-1.patch openssh-6.7p1/debian/patches/CVE-2019-6111-1.patch
--- openssh-6.7p1/debian/patches/CVE-2019-6111-1.patch	1970-01-01 01:00:00.000000000 +0100
+++ openssh-6.7p1/debian/patches/CVE-2019-6111-1.patch	2019-02-01 00:45:09.000000000 +0100
@@ -0,0 +1,178 @@
+Backport of:
+
+From 391ffc4b9d31fa1f4ad566499fef9176ff8a07dc Mon Sep 17 00:00:00 2001
+From: "djm@openbsd.org" <djm@openbsd.org>
+Date: Sat, 26 Jan 2019 22:41:28 +0000
+Subject: [PATCH] upstream: check in scp client that filenames sent during
+
+remote->local directory copies satisfy the wildcard specified by the user.
+
+This checking provides some protection against a malicious server
+sending unexpected filenames, but it comes at a risk of rejecting wanted
+files due to differences between client and server wildcard expansion rules.
+
+For this reason, this also adds a new -T flag to disable the check.
+
+reported by Harry Sintonen
+fix approach suggested by markus@;
+has been in snaps for ~1wk courtesy deraadt@
+
+OpenBSD-Commit-ID: 00f44b50d2be8e321973f3c6d014260f8f7a8eda
+---
+ scp.1 | 16 +++++++++++++---
+ scp.c | 39 ++++++++++++++++++++++++++++++---------
+ 2 files changed, 43 insertions(+), 12 deletions(-)
+
+--- a/scp.1
++++ b/scp.1
+@@ -19,7 +19,7 @@
+ .Sh SYNOPSIS
+ .Nm scp
+ .Bk -words
+-.Op Fl 12346BCpqrv
++.Op Fl 12346BCpqrTv
+ .Op Fl c Ar cipher
+ .Op Fl F Ar ssh_config
+ .Op Fl i Ar identity_file
+@@ -209,6 +209,16 @@
+ The program must understand
+ .Xr ssh 1
+ options.
++.It Fl T
++Disable strict filename checking.
++By default when copying files from a remote host to a local directory
++.Nm
++checks that the received filenames match those requested on the command-line
++to prevent the remote end from sending unexpected or unwanted files.
++Because of differences in how various operating systems and shells interpret
++filename wildcards, these checks may cause wanted files to be rejected.
++This option disables these checks at the expense of fully trusting that
++the server will not send unexpected filenames.
+ .It Fl v
+ Verbose mode.
+ Causes
+--- a/scp.c
++++ b/scp.c
+@@ -95,6 +95,7 @@
+ #include <dirent.h>
+ #include <errno.h>
+ #include <fcntl.h>
++#include <fnmatch.h>
+ #include <pwd.h>
+ #include <signal.h>
+ #include <stdarg.h>
+@@ -360,14 +361,14 @@
+ struct passwd *pwd;
+ uid_t userid;
+ int errs, remin, remout;
+-int pflag, iamremote, iamrecursive, targetshouldbedirectory;
++int Tflag, pflag, iamremote, iamrecursive, targetshouldbedirectory;
+ 
+ #define	CMDNEEDS	64
+ char cmd[CMDNEEDS];		/* must hold "rcp -r -p -d\0" */
+ 
+ int response(void);
+ void rsource(char *, struct stat *);
+-void sink(int, char *[]);
++void sink(int, char *[], const char *);
+ void source(int, char *[]);
+ void tolocal(int, char *[]);
+ void toremote(char *, int, char *[]);
+@@ -402,8 +403,9 @@
+ 	addargs(&args, "-oPermitLocalCommand=no");
+ 	addargs(&args, "-oClearAllForwardings=yes");
+ 
+-	fflag = tflag = 0;
+-	while ((ch = getopt(argc, argv, "dfl:prtvBCc:i:P:q12346S:o:F:")) != -1)
++	fflag = Tflag = tflag = 0;
++	while ((ch = getopt(argc, argv,
++	    "dfl:prtTvBCc:i:P:q12346S:o:F:")) != -1) {
+ 		switch (ch) {
+ 		/* User-visible flags. */
+ 		case '1':
+@@ -479,9 +481,13 @@
+ 			setmode(0, O_BINARY);
+ #endif
+ 			break;
++		case 'T':
++			Tflag = 1;
++			break;
+ 		default:
+ 			usage();
+ 		}
++	}
+ 	argc -= optind;
+ 	argv += optind;
+ 
+@@ -502,7 +508,7 @@
+ 	}
+ 	if (tflag) {
+ 		/* Receive data. */
+-		sink(argc, argv);
++		sink(argc, argv, NULL);
+ 		exit(errs != 0);
+ 	}
+ 	if (argc < 2)
+@@ -742,7 +748,7 @@
+ 			continue;
+ 		}
+ 		free(bp);
+-		sink(1, argv + argc - 1);
++		sink(1, argv + argc - 1, src);
+ 		(void) close(remin);
+ 		remin = remout = -1;
+ 	}
+@@ -911,7 +917,7 @@
+ }
+ 
+ void
+-sink(int argc, char **argv)
++sink(int argc, char **argv, const char *src)
+ {
+ 	static BUF buffer;
+ 	struct stat stb;
+@@ -927,6 +933,7 @@
+ 	unsigned long long ull;
+ 	int setimes, targisdir, wrerrno = 0;
+ 	char ch, *cp, *np, *targ, *why, *vect[1], buf[2048];
++	char *src_copy = NULL, *restrict_pattern = NULL;
+ 	struct timeval tv[2];
+ 
+ #define	atime	tv[0]
+@@ -948,6 +955,17 @@
+ 	(void) atomicio(vwrite, remout, "", 1);
+ 	if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode))
+ 		targisdir = 1;
++	if (src != NULL && !iamrecursive && !Tflag) {
++		/*
++		 * Prepare to try to restrict incoming filenames to match
++		 * the requested destination file glob.
++		 */
++		if ((src_copy = strdup(src)) == NULL)
++			fatal("strdup failed");
++		if ((restrict_pattern = strrchr(src_copy, '/')) != NULL) {
++			*restrict_pattern++ = '\0';
++		}
++	}
+ 	for (first = 1;; first = 0) {
+ 		cp = buf;
+ 		if (atomicio(read, remin, cp, 1) != 1)
+@@ -1044,6 +1062,9 @@
+ 			run_err("error: unexpected filename: %s", cp);
+ 			exit(1);
+ 		}
++		if (restrict_pattern != NULL &&
++		    fnmatch(restrict_pattern, cp, 0) != 0)
++			SCREWUP("filename does not match request");
+ 		if (targisdir) {
+ 			static char *namebuf;
+ 			static size_t cursize;
+@@ -1081,7 +1102,7 @@
+ 					goto bad;
+ 			}
+ 			vect[0] = xstrdup(np);
+-			sink(1, vect);
++			sink(1, vect, src);
+ 			if (setimes) {
+ 				setimes = 0;
+ 				if (utimes(vect[0], tv) < 0)
diff -Nru openssh-6.7p1/debian/patches/CVE-2019-6111-2.patch openssh-6.7p1/debian/patches/CVE-2019-6111-2.patch
--- openssh-6.7p1/debian/patches/CVE-2019-6111-2.patch	1970-01-01 01:00:00.000000000 +0100
+++ openssh-6.7p1/debian/patches/CVE-2019-6111-2.patch	2019-02-01 00:45:09.000000000 +0100
@@ -0,0 +1,407 @@
+From 3d896c157c722bc47adca51a58dca859225b5874 Mon Sep 17 00:00:00 2001
+From: "djm@openbsd.org" <djm@openbsd.org>
+Date: Sun, 10 Feb 2019 11:15:52 +0000
+Subject: upstream: when checking that filenames sent by the server side
+
+match what the client requested, be prepared to handle shell-style brace
+alternations, e.g. "{foo,bar}".
+
+"looks good to me" millert@ + in snaps for the last week courtesy
+deraadt@
+
+OpenBSD-Commit-ID: 3b1ce7639b0b25b2248e3a30f561a548f6815f3e
+---
+ scp.c | 282 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 270 insertions(+), 12 deletions(-)
+
+--- a/scp.c
++++ b/scp.c
+@@ -582,6 +582,253 @@
+ 	return (response());
+ }
+ 
++/* Appends a string to an array; returns 0 on success, -1 on alloc failure */
++static int
++append(char *cp, char ***ap, size_t *np)
++{
++       char **tmp;
++
++       if ((tmp = reallocarray(*ap, *np + 1, sizeof(*tmp))) == NULL)
++               return -1;
++       tmp[(*np)] = cp;
++       (*np)++;
++       *ap = tmp;
++       return 0;
++}
++
++/*
++ * Finds the start and end of the first brace pair in the pattern.
++ * returns 0 on success or -1 for invalid patterns.
++ */
++static int
++find_brace(const char *pattern, int *startp, int *endp)
++{
++       int i;
++       int in_bracket, brace_level;
++
++       *startp = *endp = -1;
++       in_bracket = brace_level = 0;
++       for (i = 0; i < INT_MAX && *endp < 0 && pattern[i] != '\0'; i++) {
++               switch (pattern[i]) {
++               case '\\':
++                       /* skip next character */
++                       if (pattern[i + 1] != '\0')
++                               i++;
++                       break;
++               case '[':
++                       in_bracket = 1;
++                       break;
++               case ']':
++                       in_bracket = 0;
++                       break;
++               case '{':
++                       if (in_bracket)
++                               break;
++                       if (pattern[i + 1] == '}') {
++                               /* Protect a single {}, for find(1), like csh */
++                               i++; /* skip */
++                               break;
++                       }
++                       if (*startp == -1)
++                               *startp = i;
++                       brace_level++;
++                       break;
++               case '}':
++                       if (in_bracket)
++                               break;
++                       if (*startp < 0) {
++                               /* Unbalanced brace */
++                               return -1;
++                       }
++                       if (--brace_level <= 0)
++                               *endp = i;
++                       break;
++               }
++       }
++       /* unbalanced brackets/braces */
++       if (*endp < 0 && (*startp >= 0 || in_bracket))
++               return -1;
++       return 0;
++}
++
++/*
++ * Assembles and records a successfully-expanded pattern, returns -1 on
++ * alloc failure.
++ */
++static int
++emit_expansion(const char *pattern, int brace_start, int brace_end,
++    int sel_start, int sel_end, char ***patternsp, size_t *npatternsp)
++{
++       char *cp;
++       int o = 0, tail_len = strlen(pattern + brace_end + 1);
++
++       if ((cp = malloc(brace_start + (sel_end - sel_start) +
++           tail_len + 1)) == NULL)
++               return -1;
++
++       /* Pattern before initial brace */
++       if (brace_start > 0) {
++               memcpy(cp, pattern, brace_start);
++               o = brace_start;
++       }
++       /* Current braced selection */
++       if (sel_end - sel_start > 0) {
++               memcpy(cp + o, pattern + sel_start,
++                   sel_end - sel_start);
++               o += sel_end - sel_start;
++       }
++       /* Remainder of pattern after closing brace */
++       if (tail_len > 0) {
++               memcpy(cp + o, pattern + brace_end + 1, tail_len);
++               o += tail_len;
++       }
++       cp[o] = '\0';
++       if (append(cp, patternsp, npatternsp) != 0) {
++               free(cp);
++               return -1;
++       }
++       return 0;
++}
++
++/*
++ * Expand the first encountered brace in pattern, appending the expanded
++ * patterns it yielded to the *patternsp array.
++ *
++ * Returns 0 on success or -1 on allocation failure.
++ *
++ * Signals whether expansion was performed via *expanded and whether
++ * pattern was invalid via *invalid.
++ */
++static int
++brace_expand_one(const char *pattern, char ***patternsp, size_t *npatternsp,
++    int *expanded, int *invalid)
++{
++       int i;
++       int in_bracket, brace_start, brace_end, brace_level;
++       int sel_start, sel_end;
++
++       *invalid = *expanded = 0;
++
++       if (find_brace(pattern, &brace_start, &brace_end) != 0) {
++               *invalid = 1;
++               return 0;
++       } else if (brace_start == -1)
++               return 0;
++
++       in_bracket = brace_level = 0;
++       for (i = sel_start = brace_start + 1; i < brace_end; i++) {
++               switch (pattern[i]) {
++               case '{':
++                       if (in_bracket)
++                               break;
++                       brace_level++;
++                       break;
++               case '}':
++                       if (in_bracket)
++                               break;
++                       brace_level--;
++                       break;
++               case '[':
++                       in_bracket = 1;
++                       break;
++               case ']':
++                       in_bracket = 0;
++                       break;
++               case '\\':
++                       if (i < brace_end - 1)
++                               i++; /* skip */
++                       break;
++               }
++               if (pattern[i] == ',' || i == brace_end - 1) {
++                       if (in_bracket || brace_level > 0)
++                               continue;
++                       /* End of a selection, emit an expanded pattern */
++
++                       /* Adjust end index for last selection */
++                       sel_end = (i == brace_end - 1) ? brace_end : i;
++                       if (emit_expansion(pattern, brace_start, brace_end,
++                           sel_start, sel_end, patternsp, npatternsp) != 0)
++                               return -1;
++                       /* move on to the next selection */
++                       sel_start = i + 1;
++                       continue;
++               }
++       }
++       if (in_bracket || brace_level > 0) {
++               *invalid = 1;
++               return 0;
++       }
++       /* success */
++       *expanded = 1;
++       return 0;
++}
++
++/* Expand braces from pattern. Returns 0 on success, -1 on failure */
++static int
++brace_expand(const char *pattern, char ***patternsp, size_t *npatternsp)
++{
++       char *cp, *cp2, **active = NULL, **done = NULL;
++       size_t i, nactive = 0, ndone = 0;
++       int ret = -1, invalid = 0, expanded = 0;
++
++       *patternsp = NULL;
++       *npatternsp = 0;
++
++       /* Start the worklist with the original pattern */
++       if ((cp = strdup(pattern)) == NULL)
++               return -1;
++       if (append(cp, &active, &nactive) != 0) {
++               free(cp);
++               return -1;
++       }
++       while (nactive > 0) {
++               cp = active[nactive - 1];
++               nactive--;
++               if (brace_expand_one(cp, &active, &nactive,
++                   &expanded, &invalid) == -1) {
++                       free(cp);
++                       goto fail;
++               }
++               if (invalid)
++                       fatal("%s: invalid brace pattern \"%s\"", __func__, cp);
++               if (expanded) {
++                       /*
++                        * Current entry expanded to new entries on the
++                        * active list; discard the progenitor pattern.
++                        */
++                       free(cp);
++                       continue;
++               }
++               /*
++                * Pattern did not expand; append the finename component to
++                * the completed list
++                */
++               if ((cp2 = strrchr(cp, '/')) != NULL)
++                       *cp2++ = '\0';
++               else
++                       cp2 = cp;
++               if (append(xstrdup(cp2), &done, &ndone) != 0) {
++                       free(cp);
++                       goto fail;
++               }
++               free(cp);
++       }
++       /* success */
++       *patternsp = done;
++       *npatternsp = ndone;
++       done = NULL;
++       ndone = 0;
++       ret = 0;
++ fail:
++       for (i = 0; i < nactive; i++)
++               free(active[i]);
++       free(active);
++       for (i = 0; i < ndone; i++)
++               free(done[i]);
++       free(done);
++       return ret;
++}
++
+ void
+ toremote(char *targ, int argc, char **argv)
+ {
+@@ -933,7 +1180,8 @@
+ 	unsigned long long ull;
+ 	int setimes, targisdir, wrerrno = 0;
+ 	char ch, *cp, *np, *targ, *why, *vect[1], buf[2048];
+-	char *src_copy = NULL, *restrict_pattern = NULL;
++	char **patterns = NULL;
++	size_t n, npatterns = 0;
+ 	struct timeval tv[2];
+ 
+ #define	atime	tv[0]
+@@ -960,16 +1208,13 @@
+ 		 * Prepare to try to restrict incoming filenames to match
+ 		 * the requested destination file glob.
+ 		 */
+-		if ((src_copy = strdup(src)) == NULL)
+-			fatal("strdup failed");
+-		if ((restrict_pattern = strrchr(src_copy, '/')) != NULL) {
+-			*restrict_pattern++ = '\0';
+-		}
++		if (brace_expand(src, &patterns, &npatterns) != 0)
++			fatal("%s: could not expand pattern", __func__);
+ 	}
+ 	for (first = 1;; first = 0) {
+ 		cp = buf;
+ 		if (atomicio(read, remin, cp, 1) != 1)
+-			return;
++			goto done;
+ 		if (*cp++ == '\n')
+ 			SCREWUP("unexpected <newline>");
+ 		do {
+@@ -992,7 +1237,7 @@
+ 		}
+ 		if (buf[0] == 'E') {
+ 			(void) atomicio(vwrite, remout, "", 1);
+-			return;
++			goto done;
+ 		}
+ 		if (ch == '\n')
+ 			*--cp = 0;
+@@ -1062,9 +1307,14 @@
+ 			run_err("error: unexpected filename: %s", cp);
+ 			exit(1);
+ 		}
+-		if (restrict_pattern != NULL &&
+-		    fnmatch(restrict_pattern, cp, 0) != 0)
+-			SCREWUP("filename does not match request");
++		if (npatterns > 0) {
++			for (n = 0; n < npatterns; n++) {
++				if (fnmatch(patterns[n], cp, 0) == 0)
++					break;
++			}
++			if (n >= npatterns)
++				SCREWUP("filename does not match request");
++		}
+ 		if (targisdir) {
+ 			static char *namebuf;
+ 			static size_t cursize;
+@@ -1223,7 +1473,16 @@
+ 			break;
+ 		}
+ 	}
++done:
++	for (n = 0; n < npatterns; n++)
++		free(patterns[n]);
++	free(patterns);
++	return;
+ screwup:
++	for (n = 0; n < npatterns; n++)
++		free(patterns[n]);
++	free(patterns);
++
+ 	run_err("protocol error: %s", why);
+ 	exit(1);
+ }
+--- a/openbsd-compat/Makefile.in
++++ b/openbsd-compat/Makefile.in
+@@ -16,7 +16,7 @@
+ INSTALL=@INSTALL@
+ LDFLAGS=-L. @LDFLAGS@
+ 
+-OPENBSD=base64.o basename.o bcrypt_pbkdf.o bindresvport.o blowfish.o daemon.o dirname.o fmt_scaled.o getcwd.o getgrouplist.o getopt_long.o getrrsetbyname.o glob.o inet_aton.o inet_ntoa.o inet_ntop.o mktemp.o pwcache.o readpassphrase.o realpath.o rresvport.o setenv.o setproctitle.o sha2.o sigact.o strlcat.o strlcpy.o strmode.o strnlen.o strptime.o strsep.o strtonum.o strtoll.o strtoul.o strtoull.o timingsafe_bcmp.o vis.o blowfish.o bcrypt_pbkdf.o explicit_bzero.o
++OPENBSD=base64.o basename.o bcrypt_pbkdf.o bindresvport.o blowfish.o daemon.o dirname.o fmt_scaled.o getcwd.o getgrouplist.o getopt_long.o getrrsetbyname.o glob.o inet_aton.o inet_ntoa.o inet_ntop.o mktemp.o pwcache.o readpassphrase.o reallocarray.o realpath.o rresvport.o setenv.o setproctitle.o sha2.o sigact.o strlcat.o strlcpy.o strmode.o strnlen.o strptime.o strsep.o strtonum.o strtoll.o strtoul.o strtoull.o timingsafe_bcmp.o vis.o blowfish.o bcrypt_pbkdf.o explicit_bzero.o
+ 
+ COMPAT=arc4random.o bsd-asprintf.o bsd-closefrom.o bsd-cray.o bsd-cygwin_util.o bsd-getpeereid.o getrrsetbyname-ldns.o bsd-misc.o bsd-nextstep.o bsd-openpty.o bsd-poll.o bsd-setres_id.o bsd-snprintf.o bsd-statvfs.o bsd-waitpid.o fake-rfc2553.o openssl-compat.o xmmap.o xcrypt.o kludge-fd_set.o
+ 
+--- /dev/null
++++ b/openbsd-compat/reallocarray.c
+@@ -0,0 +1,47 @@
++/*	$OpenBSD: reallocarray.c,v 1.2 2014/12/08 03:45:00 bcook Exp $	*/
++/*
++ * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
++ *
++ * Permission to use, copy, modify, and distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ */
++
++/* OPENBSD ORIGINAL: lib/libc/stdlib/reallocarray.c */
++
++#include "includes.h"
++#ifndef HAVE_REALLOCARRAY
++
++#include <sys/types.h>
++#include <errno.h>
++#ifdef HAVE_STDINT_H
++#include <stdint.h>
++#endif
++#include <stdlib.h>
++
++/*
++ * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
++ * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
++ */
++#define MUL_NO_OVERFLOW	((size_t)1 << (sizeof(size_t) * 4))
++
++void *
++reallocarray(void *optr, size_t nmemb, size_t size)
++{
++	if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
++	    nmemb > 0 && SIZE_MAX / nmemb < size) {
++		errno = ENOMEM;
++		return NULL;
++	}
++	return realloc(optr, size * nmemb);
++}
++#endif /* HAVE_REALLOCARRAY */
++
diff -Nru openssh-6.7p1/debian/patches/series openssh-6.7p1/debian/patches/series
--- openssh-6.7p1/debian/patches/series	2018-09-12 13:23:59.000000000 +0200
+++ openssh-6.7p1/debian/patches/series	2019-02-01 00:45:09.000000000 +0100
@@ -54,3 +54,10 @@
 CVE-2017-15906.patch
 split-allocation-out-of-sshbuf_reserve.patch
 CVE-2016-10011.patch
+CVE-2018-20685.patch
+CVE-2019-6111-1.patch
+CVE-2019-6111-2.patch
+CVE-2019-6109-pre1.patch
+CVE-2019-6109-pre2.patch
+CVE-2019-6109-1.patch
+CVE-2019-6109-2.patch

Attachment: pgpQPG8cJczaB.pgp
Description: Digitale PGP-Signatur


Reply to: