Accepting request 676348 from home:pmonrealgonzalez:branches:network

- Updated security fixes:
  * [bsc#1121816, CVE-2019-6109] Sanitize scp filenames via snmprintf
    and have progressmeter force an update at the beginning and end
    of each transfer. Added patches:
    - openssh-CVE-2019-6109-sanitize-scp-filenames.patch
    - openssh-CVE-2019-6109-force-progressmeter-update.patch
  * [bsc#1121821, CVE-2019-6111] Check in scp client that filenames
    sent during remote->local directory copies satisfy the wildcard
    specified by the user. Added patch:
    - openssh-CVE-2019-6111-scp-client-wildcard.patch
  * Removed openssh-7.9p1-scp-name-validator.patch

OBS-URL: https://build.opensuse.org/request/show/676348
OBS-URL: https://build.opensuse.org/package/show/network/openssh?expand=0&rev=177
This commit is contained in:
Tomáš Chvátal 2019-02-15 09:16:16 +00:00 committed by Git OBS Bridge
parent 05c990c804
commit e882225f5d
6 changed files with 576 additions and 349 deletions

View File

@ -1,348 +0,0 @@
diff --git a/defines.h b/defines.h
index 8f421306..8b4af9b2 100644
--- a/defines.h
+++ b/defines.h
@@ -873,4 +873,10 @@ struct winsize {
# define USE_SYSTEM_GLOB
#endif
+/*
+ * Define to enable additional scp file name validation against
+ * malicious servers.
+ */
+#define USE_SCP_NAME_VALIDATOR 1
+
#endif /* _DEFINES_H */
diff --git a/progressmeter.c b/progressmeter.c
index fe9bf52e..b2a3a38d 100644
--- a/progressmeter.c
+++ b/progressmeter.c
@@ -160,7 +160,10 @@ refresh_progress_meter(void)
buf[0] = '\0';
file_len = win_size - 35;
if (file_len > 0) {
- len = snprintf(buf, file_len + 1, "\r%s", file);
+ char visbuf[MAX_WINSIZE + 1];
+ (void) snmprintf(visbuf, sizeof(visbuf),
+ NULL, "%s", file);
+ len = snprintf(buf, file_len + 1, "\r%s", visbuf);
if (len < 0)
len = 0;
if (len >= file_len + 1)
diff --git a/regress/scp-ssh-wrapper.sh b/regress/scp-ssh-wrapper.sh
index 59f1ff63..dd48a482 100644
--- a/regress/scp-ssh-wrapper.sh
+++ b/regress/scp-ssh-wrapper.sh
@@ -51,6 +51,18 @@ badserver_4)
echo "C755 2 file"
echo "X"
;;
+badserver_5)
+ echo "D0555 0 "
+ echo "X"
+ ;;
+badserver_6)
+ echo "D0555 0 ."
+ echo "X"
+ ;;
+badserver_7)
+ echo "C0755 2 extrafile"
+ echo "X"
+ ;;
*)
set -- $arg
shift
diff --git a/regress/scp.sh b/regress/scp.sh
index 57cc7706..104c89e1 100644
--- a/regress/scp.sh
+++ b/regress/scp.sh
@@ -25,6 +25,7 @@ export SCP # used in scp-ssh-wrapper.scp
scpclean() {
rm -rf ${COPY} ${COPY2} ${DIR} ${DIR2}
mkdir ${DIR} ${DIR2}
+ chmod 755 ${DIR} ${DIR2}
}
verbose "$tid: simple copy local file to local file"
@@ -101,7 +102,7 @@ if [ ! -z "$SUDO" ]; then
$SUDO rm ${DIR2}/copy
fi
-for i in 0 1 2 3 4; do
+for i in 0 1 2 3 4 5 6 7; do
verbose "$tid: disallow bad server #$i"
SCPTESTMODE=badserver_$i
export DIR SCPTESTMODE
@@ -113,6 +114,15 @@ for i in 0 1 2 3 4; do
scpclean
$SCP -r $scpopts somehost:${DATA} ${DIR2} >/dev/null 2>/dev/null
[ -d ${DIR}/dotpathdir ] && fail "allows dir creation outside of subdir"
+
+ scpclean
+ $SCP -pr $scpopts somehost:${DATA} ${DIR2} >/dev/null 2>/dev/null
+ [ ! -w ${DIR2} ] && fail "allows target root attribute change"
+
+ scpclean
+ $SCP $scpopts somehost:${DATA} ${DIR2} >/dev/null 2>/dev/null
+ [ -e ${DIR2}/extrafile ] && fail "allows extranous object creation"
+ rm -f ${DIR2}/extrafile
done
verbose "$tid: detect non-directory target"
diff --git a/scp.c b/scp.c
index eb17c341..da1a3a44 100644
--- a/scp.c
+++ b/scp.c
@@ -17,6 +17,7 @@
/*
* Copyright (c) 1999 Theo de Raadt. All rights reserved.
* Copyright (c) 1999 Aaron Campbell. All rights reserved.
+ * Copyright (c) 2019 Harry Sintonen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -87,6 +88,14 @@
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
+#ifdef USE_SCP_NAME_VALIDATOR
+# include <libgen.h>
+# ifdef USE_SYSTEM_GLOB
+# include <glob.h>
+# else
+# include "openbsd-compat/glob.h"
+# endif
+#endif
#include <sys/wait.h>
#include <sys/uio.h>
@@ -277,6 +286,18 @@ do_cmd(char *host, char *remuser, int port, char *cmd, int *fdin, int *fdout)
close(pout[0]);
dup2(pin[0], 0);
dup2(pout[1], 1);
+ /*
+ * If we're not expecting output to stderr, redirect it to void.
+ * This helps avoiding output manipulation attacks by malicious
+ * servers.
+ */
+ if (!verbose_mode) {
+ int fd = open("/dev/null", O_WRONLY);
+ if (fd != -1) {
+ dup2(fd, 2);
+ close(fd);
+ }
+ }
close(pin[0]);
close(pout[1]);
@@ -380,9 +401,20 @@ int pflag, iamremote, iamrecursive, targetshouldbedirectory;
#define CMDNEEDS 64
char cmd[CMDNEEDS]; /* must hold "rcp -r -p -d\0" */
+#ifdef USE_SCP_NAME_VALIDATOR
+typedef struct {
+ const char *pattern;
+ int depth;
+} SINKDATA;
+#endif
+
int response(void);
void rsource(char *, struct stat *);
+#ifdef USE_SCP_NAME_VALIDATOR
+void sink(int, char *[], SINKDATA *);
+#else
void sink(int, char *[]);
+#endif
void source(int, char *[]);
void tolocal(int, char *[]);
void toremote(int, char *[]);
@@ -536,7 +568,11 @@ main(int argc, char **argv)
}
if (tflag) {
/* Receive data. */
+#ifdef USE_SCP_NAME_VALIDATOR
+ sink(argc, argv, NULL);
+#else
sink(argc, argv);
+#endif
exit(errs != 0);
}
if (argc < 2)
@@ -750,6 +786,9 @@ tolocal(int argc, char **argv)
char *bp, *host = NULL, *src = NULL, *suser = NULL;
arglist alist;
int i, r, sport = -1;
+#ifdef USE_SCP_NAME_VALIDATOR
+ SINKDATA sinkdata;
+#endif
memset(&alist, '\0', sizeof(alist));
alist.list = NULL;
@@ -793,7 +832,13 @@ tolocal(int argc, char **argv)
continue;
}
free(bp);
+#ifdef USE_SCP_NAME_VALIDATOR
+ sinkdata.pattern = basename(xstrdup(src));
+ sinkdata.depth = 0;
+ sink(1, argv + argc - 1, &sinkdata);
+#else
sink(1, argv + argc - 1);
+#endif
(void) close(remin);
remin = remout = -1;
}
@@ -968,8 +1013,71 @@ rsource(char *name, struct stat *statp)
(sizeof(type) == 8 && (val) > INT64_MAX) || \
(sizeof(type) != 4 && sizeof(type) != 8))
+#ifdef USE_SCP_NAME_VALIDATOR
+#ifdef GLOB_ALTDIRFUNC
+struct fakedir {
+ struct dirent de;
+#ifdef BROKEN_ONE_BYTE_DIRENT_D_NAME
+ char denamebuf[256];
+#endif
+ struct dirent tmpde;
+#ifdef BROKEN_ONE_BYTE_DIRENT_D_NAME
+ char tmpdenamebuf[2]; /* only needs to hold "." or ".." */
+#endif
+ int dirindex;
+};
+static struct fakedir fakedir;
+static void
+g_closedir(void *ptr)
+{
+}
+static struct dirent *
+g_readdir(void *ptr)
+{
+ struct fakedir *fd = ptr;
+ switch (fd->dirindex) {
+ case 1:
+ case 2:
+ strcpy(fd->tmpde.d_name, fd->dirindex == 1 ? "." : "..");
+ fd->tmpde.d_type = DT_DIR;
+ fd->tmpde.d_ino = fd->dirindex++;
+ return &fd->tmpde;
+ case 3:
+ fd->de.d_ino = fd->dirindex++;
+ return &fd->de;
+ }
+ return NULL;
+}
+static void *
+g_opendir(const char *name)
+{
+ if (strcmp(name, ".") != 0) {
+ errno = ENOENT;
+ return NULL;
+ }
+ fakedir.dirindex = 1;
+ return &fakedir;
+}
+static int
+g_stat(const char *name, struct stat *st)
+{
+ if (strcmp(name, fakedir.de.d_name) != 0) {
+ errno = ENOENT;
+ return -1;
+ }
+ memset(st, 0, sizeof(*st));
+ st->st_mode = fakedir.de.d_type == DT_DIR ? S_IFDIR : S_IFREG;
+ return 0;
+}
+#endif
+#endif
+
void
+#ifdef USE_SCP_NAME_VALIDATOR
+sink(int argc, char **argv, SINKDATA *sinkdata)
+#else
sink(int argc, char **argv)
+#endif
{
static BUF buffer;
struct stat stb;
@@ -1113,6 +1221,65 @@ sink(int argc, char **argv)
run_err("error: unexpected filename: %s", cp);
exit(1);
}
+
+#ifdef USE_SCP_NAME_VALIDATOR
+ if (sinkdata) {
+ /*
+ * Validate the item name returned by the server for
+ * attempts to modify the current directory attributes.
+ *
+ * Only allow it on root level and only if it was
+ * explicitly requested by using "host:" or "dirname/."
+ */
+ if (strcmp(cp, ".") == 0 &&
+ (sinkdata->depth != 0 || strcmp(sinkdata->pattern, ".") != 0)) {
+ run_err("error: unexpected filename: %s", cp);
+ exit(1);
+ }
+ }
+#ifdef GLOB_ALTDIRFUNC
+ /* Use glob(3) function to validate the item name against
+ * the last path element (stored in sinkdata->pattern).
+ *
+ * We verify that the items returned at the target
+ * directory level (depth 0) match this pattern.
+ *
+ * While a limited check, it will prevent some of the
+ * potential attacks by a malicious server.
+ */
+ if (sinkdata && sinkdata->depth == 0) {
+ glob_t gl;
+ int rc;
+#ifdef BROKEN_ONE_BYTE_DIRENT_D_NAME
+ if (strlen(cp) >= 256) {
+#else
+ if (strlen(cp) >= sizeof(fakedir.de.d_name)) {
+#endif
+ run_err("error: excessively long filename: %s", cp);
+ exit(1);
+ }
+ fakedir.de.d_type = buf[0] == 'D' ? DT_DIR : DT_REG;
+ strcpy(fakedir.de.d_name, cp);
+
+ memset(&gl, 0, sizeof(gl));
+ gl.gl_closedir = g_closedir;
+ gl.gl_readdir = g_readdir;
+ gl.gl_opendir = g_opendir;
+ gl.gl_lstat = g_stat;
+ gl.gl_stat = g_stat;
+
+ rc = glob(sinkdata->pattern, GLOB_ALTDIRFUNC|GLOB_NOSORT, NULL, &gl);
+ globfree(&gl);
+ if (rc != 0) {
+ if (rc == GLOB_NOMATCH)
+ run_err("error: unexpected filename: %s", cp);
+ else
+ run_err("error: glob error %d", rc);
+ exit(1);
+ }
+ }
+#endif
+#endif
if (targisdir) {
static char *namebuf;
static size_t cursize;
@@ -1150,7 +1317,15 @@ sink(int argc, char **argv)
goto bad;
}
vect[0] = xstrdup(np);
+#ifdef USE_SCP_NAME_VALIDATOR
+ if (sinkdata)
+ sinkdata->depth++;
+ sink(1, vect, sinkdata);
+ if (sinkdata)
+ sinkdata->depth--;
+#else
sink(1, vect);
+#endif
if (setimes) {
setimes = 0;
if (utimes(vect[0], tv) < 0)

View File

@ -0,0 +1,110 @@
commit bdc6c63c80b55bcbaa66b5fde31c1cb1d09a41eb
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Thu Jan 24 16:52:17 2019 +0000
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
Index: openssh-7.9p1/progressmeter.c
===================================================================
--- openssh-7.9p1.orig/progressmeter.c
+++ openssh-7.9p1/progressmeter.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: progressmeter.c,v 1.46 2019/01/23 08:01:46 dtucker Exp $ */
+/* $OpenBSD: progressmeter.c,v 1.47 2019/01/24 16:52:17 dtucker Exp $ */
/*
* Copyright (c) 2003 Nils Nordman. All rights reserved.
*
@@ -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];
off_t transferred;
@@ -131,7 +128,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;
@@ -254,7 +251,7 @@ start_progress_meter(const char *f, off_
bytes_per_second = 0;
setscreensize();
- refresh_progress_meter();
+ refresh_progress_meter(1);
signal(SIGALRM, sig_alarm);
signal(SIGWINCH, sig_winch);
@@ -271,7 +268,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-7.9p1/progressmeter.h
===================================================================
--- openssh-7.9p1.orig/progressmeter.h
+++ openssh-7.9p1/progressmeter.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: progressmeter.h,v 1.4 2019/01/23 08:01:46 dtucker Exp $ */
+/* $OpenBSD: progressmeter.h,v 1.5 2019/01/24 16:52:17 dtucker Exp $ */
/*
* Copyright (c) 2002 Nils Nordman. All rights reserved.
*
@@ -24,5 +24,5 @@
*/
void start_progress_meter(const char *, off_t, off_t *);
-void refresh_progress_meter(void);
+void refresh_progress_meter(int);
void stop_progress_meter(void);
Index: openssh-7.9p1/scp.c
===================================================================
--- openssh-7.9p1.orig/scp.c
+++ openssh-7.9p1/scp.c
@@ -585,7 +585,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-7.9p1/sftp-client.c
===================================================================
--- openssh-7.9p1.orig/sftp-client.c
+++ openssh-7.9p1/sftp-client.c
@@ -101,7 +101,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;

View File

@ -0,0 +1,262 @@
commit 8976f1c4b2721c26e878151f52bdf346dfe2d54c
Author: dtucker@openbsd.org <dtucker@openbsd.org>
Date: Wed Jan 23 08:01:46 2019 +0000
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
Index: openssh-7.9p1/atomicio.c
===================================================================
--- openssh-7.9p1.orig/atomicio.c
+++ openssh-7.9p1/atomicio.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: atomicio.c,v 1.28 2016/07/27 23:18:12 djm Exp $ */
+/* $OpenBSD: atomicio.c,v 1.29 2019/01/23 08:01:46 dtucker Exp $ */
/*
* Copyright (c) 2006 Damien Miller. All rights reserved.
* Copyright (c) 2005 Anil Madhavapeddy. All rights reserved.
@@ -65,9 +65,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
@@ -122,9 +127,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-7.9p1/progressmeter.c
===================================================================
--- openssh-7.9p1.orig/progressmeter.c
+++ openssh-7.9p1/progressmeter.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: progressmeter.c,v 1.45 2016/06/30 05:17:05 dtucker Exp $ */
+/* $OpenBSD: progressmeter.c,v 1.46 2019/01/23 08:01:46 dtucker Exp $ */
/*
* Copyright (c) 2003 Nils Nordman. All rights reserved.
*
@@ -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 double start; /* start progress */
static double 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";
@@ -126,9 +129,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_double();
@@ -158,16 +169,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 */
@@ -228,22 +234,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
@@ -259,10 +254,9 @@ start_progress_meter(const char *f, off_
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);
}
@@ -286,6 +280,7 @@ stop_progress_meter(void)
static void
sig_winch(int sig)
{
+ signal(SIGWINCH, sig_winch);
win_resized = 1;
}
Index: openssh-7.9p1/progressmeter.h
===================================================================
--- openssh-7.9p1.orig/progressmeter.h
+++ openssh-7.9p1/progressmeter.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: progressmeter.h,v 1.3 2015/01/14 13:54:13 djm Exp $ */
+/* $OpenBSD: progressmeter.h,v 1.4 2019/01/23 08:01:46 dtucker Exp $ */
/*
* Copyright (c) 2002 Nils Nordman. All rights reserved.
*
@@ -24,4 +24,5 @@
*/
void start_progress_meter(const char *, off_t, off_t *);
+void refresh_progress_meter(void);
void stop_progress_meter(void);
Index: openssh-7.9p1/scp.c
===================================================================
--- openssh-7.9p1.orig/scp.c
+++ openssh-7.9p1/scp.c
@@ -585,6 +585,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-7.9p1/sftp-client.c
===================================================================
--- openssh-7.9p1.orig/sftp-client.c
+++ openssh-7.9p1/sftp-client.c
@@ -101,7 +101,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;
}
@@ -121,8 +123,8 @@ send_msg(struct sftp_conn *conn, struct
iov[1].iov_base = (u_char *)sshbuf_ptr(m);
iov[1].iov_len = sshbuf_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) !=
sshbuf_len(m) + sizeof(mlen))
fatal("Couldn't send packet: %s", strerror(errno));
@@ -138,8 +140,8 @@ get_msg_extended(struct sftp_conn *conn,
if ((r = sshbuf_reserve(m, 4, &p)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
- if (atomicio6(read, conn->fd_in, p, 4,
- conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_in) != 4) {
+ if (atomicio6(read, conn->fd_in, p, 4, sftpio,
+ conn->limit_kbps > 0 ? &conn->bwlimit_in : NULL) != 4) {
if (errno == EPIPE || errno == ECONNRESET)
fatal("Connection closed");
else
@@ -157,8 +159,8 @@ get_msg_extended(struct sftp_conn *conn,
if ((r = sshbuf_reserve(m, msg_len, &p)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
- if (atomicio6(read, conn->fd_in, p, msg_len,
- conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_in)
+ if (atomicio6(read, conn->fd_in, p, msg_len, sftpio,
+ conn->limit_kbps > 0 ? &conn->bwlimit_in : NULL)
!= msg_len) {
if (errno == EPIPE)
fatal("Connection closed");

View File

@ -0,0 +1,186 @@
commit 391ffc4b9d31fa1f4ad566499fef9176ff8a07dc
Author: djm@openbsd.org <djm@openbsd.org>
Date: Sat Jan 26 22:41:28 2019 +0000
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
Index: openssh-7.9p1/scp.1
===================================================================
--- openssh-7.9p1.orig/scp.1
+++ openssh-7.9p1/scp.1
@@ -18,7 +18,7 @@
.Nd secure copy (remote file copy program)
.Sh SYNOPSIS
.Nm scp
-.Op Fl 346BCpqrv
+.Op Fl 346BCpqrTv
.Op Fl c Ar cipher
.Op Fl F Ar ssh_config
.Op Fl i Ar identity_file
@@ -208,6 +208,16 @@ to use for the encrypted connection.
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
Index: openssh-7.9p1/scp.c
===================================================================
--- openssh-7.9p1.orig/scp.c
+++ openssh-7.9p1/scp.c
@@ -94,6 +94,7 @@
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
+#include <fnmatch.h>
#include <limits.h>
#include <locale.h>
#include <pwd.h>
@@ -375,14 +376,14 @@ void verifydir(char *);
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(int, char *[]);
@@ -421,8 +422,9 @@ main(int argc, char **argv)
addargs(&args, "-oRemoteCommand=none");
addargs(&args, "-oRequestTTY=no");
- 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:J:")) != -1) {
switch (ch) {
/* User-visible flags. */
case '1':
@@ -501,9 +503,13 @@ main(int argc, char **argv)
setmode(0, O_BINARY);
#endif
break;
+ case 'T':
+ Tflag = 1;
+ break;
default:
usage();
}
+ }
argc -= optind;
argv += optind;
@@ -534,7 +540,7 @@ main(int argc, char **argv)
}
if (tflag) {
/* Receive data. */
- sink(argc, argv);
+ sink(argc, argv, NULL);
exit(errs != 0);
}
if (argc < 2)
@@ -792,7 +798,7 @@ tolocal(int argc, char **argv)
continue;
}
free(bp);
- sink(1, argv + argc - 1);
+ sink(1, argv + argc - 1, src);
(void) close(remin);
remin = remout = -1;
}
@@ -968,7 +974,7 @@ rsource(char *name, struct stat *statp)
(sizeof(type) != 4 && sizeof(type) != 8))
void
-sink(int argc, char **argv)
+sink(int argc, char **argv, const char *src)
{
static BUF buffer;
struct stat stb;
@@ -984,6 +990,7 @@ sink(int argc, char **argv)
unsigned long long ull;
int setimes, targisdir, wrerrno = 0;
char ch, *cp, *np, *targ, *why, *vect[1], buf[2048], visbuf[2048];
+ char *src_copy = NULL, *restrict_pattern = NULL;
struct timeval tv[2];
#define atime tv[0]
@@ -1008,6 +1015,17 @@ sink(int argc, char **argv)
(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)
@@ -1112,6 +1130,9 @@ sink(int argc, char **argv)
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;
@@ -1149,7 +1170,7 @@ sink(int argc, char **argv)
goto bad;
}
vect[0] = xstrdup(np);
- sink(1, vect);
+ sink(1, vect, src);
if (setimes) {
setimes = 0;
if (utimes(vect[0], tv) < 0)
@@ -1317,7 +1338,7 @@ void
usage(void)
{
(void) fprintf(stderr,
- "usage: scp [-346BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file]\n"
+ "usage: scp [-346BCpqrTv] [-c cipher] [-F ssh_config] [-i identity_file]\n"
" [-l limit] [-o ssh_option] [-P port] [-S program] source ... target\n");
exit(1);
}

View File

@ -1,3 +1,18 @@
-------------------------------------------------------------------
Thu Feb 14 15:27:53 UTC 2019 - Pedro Monreal Gonzalez <pmonrealgonzalez@suse.com>
- Updated security fixes:
* [bsc#1121816, CVE-2019-6109] Sanitize scp filenames via snmprintf
and have progressmeter force an update at the beginning and end
of each transfer. Added patches:
- openssh-CVE-2019-6109-sanitize-scp-filenames.patch
- openssh-CVE-2019-6109-force-progressmeter-update.patch
* [bsc#1121821, CVE-2019-6111] Check in scp client that filenames
sent during remote->local directory copies satisfy the wildcard
specified by the user. Added patch:
- openssh-CVE-2019-6111-scp-client-wildcard.patch
* Removed openssh-7.9p1-scp-name-validator.patch
------------------------------------------------------------------- -------------------------------------------------------------------
Thu Feb 14 10:29:20 UTC 2019 - Tomáš Chvátal <tchvatal@suse.com> Thu Feb 14 10:29:20 UTC 2019 - Tomáš Chvátal <tchvatal@suse.com>

View File

@ -101,7 +101,9 @@ Patch32: openssh-7.7p1-IPv6_X_forwarding.patch
Patch33: openssh-7.7p1-sftp_print_diagnostic_messages.patch Patch33: openssh-7.7p1-sftp_print_diagnostic_messages.patch
Patch34: openssh-openssl-1_0_0-compatibility.patch Patch34: openssh-openssl-1_0_0-compatibility.patch
Patch35: openssh-7.9p1-CVE-2018-20685.patch Patch35: openssh-7.9p1-CVE-2018-20685.patch
Patch36: openssh-7.9p1-scp-name-validator.patch Patch36: openssh-CVE-2019-6109-sanitize-scp-filenames.patch
Patch37: openssh-CVE-2019-6109-force-progressmeter-update.patch
Patch38: openssh-CVE-2019-6111-scp-client-wildcard.patch
BuildRequires: audit-devel BuildRequires: audit-devel
BuildRequires: autoconf BuildRequires: autoconf
BuildRequires: groff BuildRequires: groff