openssh: add upstream patches, including CVE-2019-6111
[feed/packages.git] / net / openssh / patches / 0005-check-filenames-in-scp-client.patch
1 From 125924e47db3713a85a70e0f8d6c23818d2ea054 Mon Sep 17 00:00:00 2001
2 From: "djm@openbsd.org" <djm@openbsd.org>
3 Date: Sat, 26 Jan 2019 22:41:28 +0000
4 Subject: upstream: check in scp client that filenames sent during
5
6 remote->local directory copies satisfy the wildcard specified by the user.
7
8 This checking provides some protection against a malicious server
9 sending unexpected filenames, but it comes at a risk of rejecting wanted
10 files due to differences between client and server wildcard expansion rules.
11
12 For this reason, this also adds a new -T flag to disable the check.
13
14 reported by Harry Sintonen
15 fix approach suggested by markus@;
16 has been in snaps for ~1wk courtesy deraadt@
17
18 OpenBSD-Commit-ID: 00f44b50d2be8e321973f3c6d014260f8f7a8eda
19
20 CVE-2019-6111
21
22 Origin: backport, https://anongit.mindrot.org/openssh.git/commit/?id=391ffc4b9d31fa1f4ad566499fef9176ff8a07dc
23 Last-Update: 2019-02-08
24
25 Patch-Name: check-filenames-in-scp-client.patch
26 ---
27 scp.1 | 12 +++++++++++-
28 scp.c | 37 +++++++++++++++++++++++++++++--------
29 2 files changed, 40 insertions(+), 9 deletions(-)
30
31 diff --git a/scp.1 b/scp.1
32 index 0e5cc1b2d..397e77091 100644
33 --- a/scp.1
34 +++ b/scp.1
35 @@ -18,7 +18,7 @@
36 .Nd secure copy (remote file copy program)
37 .Sh SYNOPSIS
38 .Nm scp
39 -.Op Fl 346BCpqrv
40 +.Op Fl 346BCpqrTv
41 .Op Fl c Ar cipher
42 .Op Fl F Ar ssh_config
43 .Op Fl i Ar identity_file
44 @@ -208,6 +208,16 @@ to use for the encrypted connection.
45 The program must understand
46 .Xr ssh 1
47 options.
48 +.It Fl T
49 +Disable strict filename checking.
50 +By default when copying files from a remote host to a local directory
51 +.Nm
52 +checks that the received filenames match those requested on the command-line
53 +to prevent the remote end from sending unexpected or unwanted files.
54 +Because of differences in how various operating systems and shells interpret
55 +filename wildcards, these checks may cause wanted files to be rejected.
56 +This option disables these checks at the expense of fully trusting that
57 +the server will not send unexpected filenames.
58 .It Fl v
59 Verbose mode.
60 Causes
61 diff --git a/scp.c b/scp.c
62 index 1971c80cd..035037bcc 100644
63 --- a/scp.c
64 +++ b/scp.c
65 @@ -94,6 +94,7 @@
66 #include <dirent.h>
67 #include <errno.h>
68 #include <fcntl.h>
69 +#include <fnmatch.h>
70 #include <limits.h>
71 #include <locale.h>
72 #include <pwd.h>
73 @@ -383,14 +384,14 @@ void verifydir(char *);
74 struct passwd *pwd;
75 uid_t userid;
76 int errs, remin, remout;
77 -int pflag, iamremote, iamrecursive, targetshouldbedirectory;
78 +int Tflag, pflag, iamremote, iamrecursive, targetshouldbedirectory;
79
80 #define CMDNEEDS 64
81 char cmd[CMDNEEDS]; /* must hold "rcp -r -p -d\0" */
82
83 int response(void);
84 void rsource(char *, struct stat *);
85 -void sink(int, char *[]);
86 +void sink(int, char *[], const char *);
87 void source(int, char *[]);
88 void tolocal(int, char *[]);
89 void toremote(int, char *[]);
90 @@ -429,8 +430,9 @@ main(int argc, char **argv)
91 addargs(&args, "-oRemoteCommand=none");
92 addargs(&args, "-oRequestTTY=no");
93
94 - fflag = tflag = 0;
95 - while ((ch = getopt(argc, argv, "dfl:prtvBCc:i:P:q12346S:o:F:")) != -1)
96 + fflag = Tflag = tflag = 0;
97 + while ((ch = getopt(argc, argv,
98 + "dfl:prtTvBCc:i:P:q12346S:o:F:")) != -1) {
99 switch (ch) {
100 /* User-visible flags. */
101 case '1':
102 @@ -509,9 +511,13 @@ main(int argc, char **argv)
103 setmode(0, O_BINARY);
104 #endif
105 break;
106 + case 'T':
107 + Tflag = 1;
108 + break;
109 default:
110 usage();
111 }
112 + }
113 argc -= optind;
114 argv += optind;
115
116 @@ -542,7 +548,7 @@ main(int argc, char **argv)
117 }
118 if (tflag) {
119 /* Receive data. */
120 - sink(argc, argv);
121 + sink(argc, argv, NULL);
122 exit(errs != 0);
123 }
124 if (argc < 2)
125 @@ -800,7 +806,7 @@ tolocal(int argc, char **argv)
126 continue;
127 }
128 free(bp);
129 - sink(1, argv + argc - 1);
130 + sink(1, argv + argc - 1, src);
131 (void) close(remin);
132 remin = remout = -1;
133 }
134 @@ -976,7 +982,7 @@ rsource(char *name, struct stat *statp)
135 (sizeof(type) != 4 && sizeof(type) != 8))
136
137 void
138 -sink(int argc, char **argv)
139 +sink(int argc, char **argv, const char *src)
140 {
141 static BUF buffer;
142 struct stat stb;
143 @@ -992,6 +998,7 @@ sink(int argc, char **argv)
144 unsigned long long ull;
145 int setimes, targisdir, wrerrno = 0;
146 char ch, *cp, *np, *targ, *why, *vect[1], buf[2048], visbuf[2048];
147 + char *src_copy = NULL, *restrict_pattern = NULL;
148 struct timeval tv[2];
149
150 #define atime tv[0]
151 @@ -1016,6 +1023,17 @@ sink(int argc, char **argv)
152 (void) atomicio(vwrite, remout, "", 1);
153 if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode))
154 targisdir = 1;
155 + if (src != NULL && !iamrecursive && !Tflag) {
156 + /*
157 + * Prepare to try to restrict incoming filenames to match
158 + * the requested destination file glob.
159 + */
160 + if ((src_copy = strdup(src)) == NULL)
161 + fatal("strdup failed");
162 + if ((restrict_pattern = strrchr(src_copy, '/')) != NULL) {
163 + *restrict_pattern++ = '\0';
164 + }
165 + }
166 for (first = 1;; first = 0) {
167 cp = buf;
168 if (atomicio(read, remin, cp, 1) != 1)
169 @@ -1120,6 +1138,9 @@ sink(int argc, char **argv)
170 run_err("error: unexpected filename: %s", cp);
171 exit(1);
172 }
173 + if (restrict_pattern != NULL &&
174 + fnmatch(restrict_pattern, cp, 0) != 0)
175 + SCREWUP("filename does not match request");
176 if (targisdir) {
177 static char *namebuf;
178 static size_t cursize;
179 @@ -1157,7 +1178,7 @@ sink(int argc, char **argv)
180 goto bad;
181 }
182 vect[0] = xstrdup(np);
183 - sink(1, vect);
184 + sink(1, vect, src);
185 if (setimes) {
186 setimes = 0;
187 if (utimes(vect[0], tv) < 0)