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