Accepting request 677282 from network

- Supplement the openssh and libx11 together to ensure this package
  is installed on machines where there is X stack

- Handle brace expansion in scp when checking that filenames sent
  by the server side match what the client requested [bsc#1125687]
  * openssh-7.9p1-brace-expansion.patch

- 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

- Change the askpass wrapper to not use x11 interface:
  * by default we use the -gnome UI (which is gtk3 only, no gnome dep)
  * if desktop is KDE/LxQt we use ksshaskpass

OBS-URL: https://build.opensuse.org/request/show/677282
OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/openssh?expand=0&rev=128
This commit is contained in:
Stephan Kulow 2019-02-25 16:46:44 +00:00 committed by Git OBS Bridge
commit 44f9d7c40f
10 changed files with 953 additions and 382 deletions

View File

@ -0,0 +1,348 @@
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: [PATCH] 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(-)
Index: openssh-7.9p1/scp.c
===================================================================
--- openssh-7.9p1.orig/scp.c
+++ openssh-7.9p1/scp.c
@@ -627,6 +627,253 @@ parse_scp_uri(const char *uri, char **us
return r;
}
+/* 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(int argc, char **argv)
{
@@ -990,7 +1237,8 @@ sink(int argc, char **argv, const char *
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;
+ char **patterns = NULL;
+ size_t n, npatterns = 0;
struct timeval tv[2];
#define atime tv[0]
@@ -1020,16 +1268,13 @@ sink(int argc, char **argv, const char *
* 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 {
@@ -1055,7 +1300,7 @@ sink(int argc, char **argv, const char *
}
if (buf[0] == 'E') {
(void) atomicio(vwrite, remout, "", 1);
- return;
+ goto done;
}
if (ch == '\n')
*--cp = 0;
@@ -1130,9 +1375,14 @@ sink(int argc, char **argv, const char *
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;
@@ -1291,7 +1541,15 @@ bad: run_err("%s: %s", np, strerror(er
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);
}

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,9 @@
-------------------------------------------------------------------
Thu Feb 14 10:36:03 UTC 2019 - Tomáš Chvátal <tchvatal@suse.com>
- Supplement the openssh and libx11 together to ensure this package
is installed on machines where there is X stack
-------------------------------------------------------------------
Mon Oct 22 08:59:02 UTC 2018 - Pedro Monreal Gonzalez <pmonrealgonzalez@suse.com>

View File

@ -26,12 +26,13 @@ Group: Productivity/Networking/SSH
URL: http://www.openssh.com/
Source: http://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/%{_name}-%{version}.tar.gz
Source42: http://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/%{_name}-%{version}.tar.gz.asc
Requires: %{_name} = %{version}
Supplements: packageand(openssh:libX11-6)
%if 0%{?suse_version} >= 1550
BuildRequires: gtk3-devel
%else
BuildRequires: gtk2-devel
%endif
Requires: %{_name} = %{version}
%description
SSH (Secure Shell) is a program for logging into a remote machine and

View File

@ -1,3 +1,32 @@
-------------------------------------------------------------------
Mon Feb 18 10:01:45 UTC 2019 - Pedro Monreal Gonzalez <pmonrealgonzalez@suse.com>
- Handle brace expansion in scp when checking that filenames sent
by the server side match what the client requested [bsc#1125687]
* openssh-7.9p1-brace-expansion.patch
-------------------------------------------------------------------
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>
- Change the askpass wrapper to not use x11 interface:
* by default we use the -gnome UI (which is gtk3 only, no gnome dep)
* if desktop is KDE/LxQt we use ksshaskpass
-------------------------------------------------------------------
Mon Jan 28 10:34:53 UTC 2019 - Pedro Monreal Gonzalez <pmonrealgonzalez@suse.com>

View File

@ -101,7 +101,10 @@ Patch32: openssh-7.7p1-IPv6_X_forwarding.patch
Patch33: openssh-7.7p1-sftp_print_diagnostic_messages.patch
Patch34: openssh-openssl-1_0_0-compatibility.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
Patch39: openssh-7.9p1-brace-expansion.patch
BuildRequires: audit-devel
BuildRequires: autoconf
BuildRequires: groff

View File

@ -2,49 +2,23 @@
SESSION=
case "$DESKTOP_SESSION" in
kde) SESSION=kde ;;
gnome) SESSION=gnome ;;
esac
if [ -z "$SESSION" ] ; then
WM="${WINDOWMANAGER##*/}"
case "$WM" in
*kde*) SESSION=kde ;;
*gnome*) SESSION=gnome ;;
esac
if [ -n "$KDE_FULL_SESSION" ] ; then
SESSION=kde
fi
if [ -z "$SESSION" ] ; then
if [ -n "$KDE_FULL_SESSION" ] ; then
if [ "$DESKTOP_SESSION" = "lxqt" ]; then
SESSION=kde
fi
if [ -n "$GNOME_DESKTOP_SESSION_ID" ] ; then
SESSION=gnome
fi
fi
GNOME_SSH_ASKPASS="@LIBEXECDIR@/ssh/gnome-ssh-askpass"
KDE_SSH_ASKPASS="@LIBEXECDIR@/ssh/ksshaskpass"
X11_SSH_ASKPASS="@LIBEXECDIR@/ssh/x11-ssh-askpass"
case "$SESSION" in
gnome)
if [ -f $GNOME_SSH_ASKPASS ]; then
exec $GNOME_SSH_ASKPASS ${1+"$@"}
else
exec $X11_SSH_ASKPASS ${1+"$@"}
fi
;;
kde)
if [ -f $KDE_SSH_ASKPASS ]; then
exec $KDE_SSH_ASKPASS ${1+"$@"}
else
exec $X11_SSH_ASKPASS ${1+"$@"}
fi
;;
*)
exec $X11_SSH_ASKPASS ${1+"$@"}
exec $GNOME_SSH_ASKPASS ${1+"$@"}
;;
esac