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: sunwea...@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 <sunwea...@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: "d...@openbsd.org" <d...@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: "dtuc...@openbsd.org" <dtuc...@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: "dtuc...@openbsd.org" <dtuc...@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 <schwa...@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 <schwa...@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 <dtuc...@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: "d...@openbsd.org" <d...@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: "d...@openbsd.org" <d...@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 <o...@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
pgpRX4_t2x0dQ.pgp
Description: Digitale PGP-Signatur