summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordtucker@openbsd.org <dtucker@openbsd.org>2019-01-23 08:01:46 +0000
committerColin Watson <cjwatson@debian.org>2019-02-08 15:38:28 +0000
commit11b88754cadcad0ba79b4ffcc127223248dccb54 (patch)
tree2c9793f792675bc79de7f7a3bcae66cdfaa719ca
parentdee21e97428e69d30e2d15c71f3e7cc08bf8e4f8 (diff)
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 CVE-2019-6109 Origin: backport, https://anongit.mindrot.org/openssh.git/commit/?id=8976f1c4b2721c26e878151f52bdf346dfe2d54c Bug-Debian: https://bugs.debian.org/793412 Last-Update: 2019-02-08 Patch-Name: sanitize-scp-filenames-via-snmprintf.patch
-rw-r--r--atomicio.c20
-rw-r--r--progressmeter.c53
-rw-r--r--progressmeter.h3
-rw-r--r--scp.c1
-rw-r--r--sftp-client.c16
5 files changed, 51 insertions, 42 deletions
diff --git a/atomicio.c b/atomicio.c
index f854a06f5..d91bd7621 100644
--- a/atomicio.c
+++ b/atomicio.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: atomicio.c,v 1.28 2016/07/27 23:18:12 djm Exp $ */ 1/* $OpenBSD: atomicio.c,v 1.29 2019/01/23 08:01:46 dtucker Exp $ */
2/* 2/*
3 * Copyright (c) 2006 Damien Miller. All rights reserved. 3 * Copyright (c) 2006 Damien Miller. All rights reserved.
4 * Copyright (c) 2005 Anil Madhavapeddy. All rights reserved. 4 * Copyright (c) 2005 Anil Madhavapeddy. All rights reserved.
@@ -65,9 +65,14 @@ atomicio6(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n,
65 res = (f) (fd, s + pos, n - pos); 65 res = (f) (fd, s + pos, n - pos);
66 switch (res) { 66 switch (res) {
67 case -1: 67 case -1:
68 if (errno == EINTR) 68 if (errno == EINTR) {
69 /* possible SIGALARM, update callback */
70 if (cb != NULL && cb(cb_arg, 0) == -1) {
71 errno = EINTR;
72 return pos;
73 }
69 continue; 74 continue;
70 if (errno == EAGAIN || errno == EWOULDBLOCK) { 75 } else if (errno == EAGAIN || errno == EWOULDBLOCK) {
71#ifndef BROKEN_READ_COMPARISON 76#ifndef BROKEN_READ_COMPARISON
72 (void)poll(&pfd, 1, -1); 77 (void)poll(&pfd, 1, -1);
73#endif 78#endif
@@ -122,9 +127,14 @@ atomiciov6(ssize_t (*f) (int, const struct iovec *, int), int fd,
122 res = (f) (fd, iov, iovcnt); 127 res = (f) (fd, iov, iovcnt);
123 switch (res) { 128 switch (res) {
124 case -1: 129 case -1:
125 if (errno == EINTR) 130 if (errno == EINTR) {
131 /* possible SIGALARM, update callback */
132 if (cb != NULL && cb(cb_arg, 0) == -1) {
133 errno = EINTR;
134 return pos;
135 }
126 continue; 136 continue;
127 if (errno == EAGAIN || errno == EWOULDBLOCK) { 137 } else if (errno == EAGAIN || errno == EWOULDBLOCK) {
128#ifndef BROKEN_READV_COMPARISON 138#ifndef BROKEN_READV_COMPARISON
129 (void)poll(&pfd, 1, -1); 139 (void)poll(&pfd, 1, -1);
130#endif 140#endif
diff --git a/progressmeter.c b/progressmeter.c
index fe9bf52e4..add462dde 100644
--- a/progressmeter.c
+++ b/progressmeter.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: progressmeter.c,v 1.45 2016/06/30 05:17:05 dtucker Exp $ */ 1/* $OpenBSD: progressmeter.c,v 1.46 2019/01/23 08:01:46 dtucker Exp $ */
2/* 2/*
3 * Copyright (c) 2003 Nils Nordman. All rights reserved. 3 * Copyright (c) 2003 Nils Nordman. All rights reserved.
4 * 4 *
@@ -31,6 +31,7 @@
31 31
32#include <errno.h> 32#include <errno.h>
33#include <signal.h> 33#include <signal.h>
34#include <stdarg.h>
34#include <stdio.h> 35#include <stdio.h>
35#include <string.h> 36#include <string.h>
36#include <time.h> 37#include <time.h>
@@ -39,6 +40,7 @@
39#include "progressmeter.h" 40#include "progressmeter.h"
40#include "atomicio.h" 41#include "atomicio.h"
41#include "misc.h" 42#include "misc.h"
43#include "utf8.h"
42 44
43#define DEFAULT_WINSIZE 80 45#define DEFAULT_WINSIZE 80
44#define MAX_WINSIZE 512 46#define MAX_WINSIZE 512
@@ -61,7 +63,7 @@ static void setscreensize(void);
61void refresh_progress_meter(void); 63void refresh_progress_meter(void);
62 64
63/* signal handler for updating the progress meter */ 65/* signal handler for updating the progress meter */
64static void update_progress_meter(int); 66static void sig_alarm(int);
65 67
66static double start; /* start progress */ 68static double start; /* start progress */
67static double last_update; /* last progress update */ 69static double last_update; /* last progress update */
@@ -74,6 +76,7 @@ static long stalled; /* how long we have been stalled */
74static int bytes_per_second; /* current speed in bytes per second */ 76static int bytes_per_second; /* current speed in bytes per second */
75static int win_size; /* terminal window size */ 77static int win_size; /* terminal window size */
76static volatile sig_atomic_t win_resized; /* for window resizing */ 78static volatile sig_atomic_t win_resized; /* for window resizing */
79static volatile sig_atomic_t alarm_fired;
77 80
78/* units for format_size */ 81/* units for format_size */
79static const char unit[] = " KMGT"; 82static const char unit[] = " KMGT";
@@ -126,9 +129,17 @@ refresh_progress_meter(void)
126 off_t bytes_left; 129 off_t bytes_left;
127 int cur_speed; 130 int cur_speed;
128 int hours, minutes, seconds; 131 int hours, minutes, seconds;
129 int i, len;
130 int file_len; 132 int file_len;
131 133
134 if ((!alarm_fired && !win_resized) || !can_output())
135 return;
136 alarm_fired = 0;
137
138 if (win_resized) {
139 setscreensize();
140 win_resized = 0;
141 }
142
132 transferred = *counter - (cur_pos ? cur_pos : start_pos); 143 transferred = *counter - (cur_pos ? cur_pos : start_pos);
133 cur_pos = *counter; 144 cur_pos = *counter;
134 now = monotime_double(); 145 now = monotime_double();
@@ -158,16 +169,11 @@ refresh_progress_meter(void)
158 169
159 /* filename */ 170 /* filename */
160 buf[0] = '\0'; 171 buf[0] = '\0';
161 file_len = win_size - 35; 172 file_len = win_size - 36;
162 if (file_len > 0) { 173 if (file_len > 0) {
163 len = snprintf(buf, file_len + 1, "\r%s", file); 174 buf[0] = '\r';
164 if (len < 0) 175 snmprintf(buf+1, sizeof(buf)-1 , &file_len, "%*s",
165 len = 0; 176 file_len * -1, file);
166 if (len >= file_len + 1)
167 len = file_len;
168 for (i = len; i < file_len; i++)
169 buf[i] = ' ';
170 buf[file_len] = '\0';
171 } 177 }
172 178
173 /* percent of transfer done */ 179 /* percent of transfer done */
@@ -228,22 +234,11 @@ refresh_progress_meter(void)
228 234
229/*ARGSUSED*/ 235/*ARGSUSED*/
230static void 236static void
231update_progress_meter(int ignore) 237sig_alarm(int ignore)
232{ 238{
233 int save_errno; 239 signal(SIGALRM, sig_alarm);
234 240 alarm_fired = 1;
235 save_errno = errno;
236
237 if (win_resized) {
238 setscreensize();
239 win_resized = 0;
240 }
241 if (can_output())
242 refresh_progress_meter();
243
244 signal(SIGALRM, update_progress_meter);
245 alarm(UPDATE_INTERVAL); 241 alarm(UPDATE_INTERVAL);
246 errno = save_errno;
247} 242}
248 243
249void 244void
@@ -259,10 +254,9 @@ start_progress_meter(const char *f, off_t filesize, off_t *ctr)
259 bytes_per_second = 0; 254 bytes_per_second = 0;
260 255
261 setscreensize(); 256 setscreensize();
262 if (can_output()) 257 refresh_progress_meter();
263 refresh_progress_meter();
264 258
265 signal(SIGALRM, update_progress_meter); 259 signal(SIGALRM, sig_alarm);
266 signal(SIGWINCH, sig_winch); 260 signal(SIGWINCH, sig_winch);
267 alarm(UPDATE_INTERVAL); 261 alarm(UPDATE_INTERVAL);
268} 262}
@@ -286,6 +280,7 @@ stop_progress_meter(void)
286static void 280static void
287sig_winch(int sig) 281sig_winch(int sig)
288{ 282{
283 signal(SIGWINCH, sig_winch);
289 win_resized = 1; 284 win_resized = 1;
290} 285}
291 286
diff --git a/progressmeter.h b/progressmeter.h
index bf179dca6..8f6678060 100644
--- a/progressmeter.h
+++ b/progressmeter.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: progressmeter.h,v 1.3 2015/01/14 13:54:13 djm Exp $ */ 1/* $OpenBSD: progressmeter.h,v 1.4 2019/01/23 08:01:46 dtucker Exp $ */
2/* 2/*
3 * Copyright (c) 2002 Nils Nordman. All rights reserved. 3 * Copyright (c) 2002 Nils Nordman. All rights reserved.
4 * 4 *
@@ -24,4 +24,5 @@
24 */ 24 */
25 25
26void start_progress_meter(const char *, off_t, off_t *); 26void start_progress_meter(const char *, off_t, off_t *);
27void refresh_progress_meter(void);
27void stop_progress_meter(void); 28void stop_progress_meter(void);
diff --git a/scp.c b/scp.c
index 7163d33dc..80308573c 100644
--- a/scp.c
+++ b/scp.c
@@ -593,6 +593,7 @@ scpio(void *_cnt, size_t s)
593 off_t *cnt = (off_t *)_cnt; 593 off_t *cnt = (off_t *)_cnt;
594 594
595 *cnt += s; 595 *cnt += s;
596 refresh_progress_meter();
596 if (limit_kbps > 0) 597 if (limit_kbps > 0)
597 bandwidth_limit(&bwlimit, s); 598 bandwidth_limit(&bwlimit, s);
598 return 0; 599 return 0;
diff --git a/sftp-client.c b/sftp-client.c
index 4986d6d8d..2bc698f86 100644
--- a/sftp-client.c
+++ b/sftp-client.c
@@ -101,7 +101,9 @@ sftpio(void *_bwlimit, size_t amount)
101{ 101{
102 struct bwlimit *bwlimit = (struct bwlimit *)_bwlimit; 102 struct bwlimit *bwlimit = (struct bwlimit *)_bwlimit;
103 103
104 bandwidth_limit(bwlimit, amount); 104 refresh_progress_meter();
105 if (bwlimit != NULL)
106 bandwidth_limit(bwlimit, amount);
105 return 0; 107 return 0;
106} 108}
107 109
@@ -121,8 +123,8 @@ send_msg(struct sftp_conn *conn, struct sshbuf *m)
121 iov[1].iov_base = (u_char *)sshbuf_ptr(m); 123 iov[1].iov_base = (u_char *)sshbuf_ptr(m);
122 iov[1].iov_len = sshbuf_len(m); 124 iov[1].iov_len = sshbuf_len(m);
123 125
124 if (atomiciov6(writev, conn->fd_out, iov, 2, 126 if (atomiciov6(writev, conn->fd_out, iov, 2, sftpio,
125 conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_out) != 127 conn->limit_kbps > 0 ? &conn->bwlimit_out : NULL) !=
126 sshbuf_len(m) + sizeof(mlen)) 128 sshbuf_len(m) + sizeof(mlen))
127 fatal("Couldn't send packet: %s", strerror(errno)); 129 fatal("Couldn't send packet: %s", strerror(errno));
128 130
@@ -138,8 +140,8 @@ get_msg_extended(struct sftp_conn *conn, struct sshbuf *m, int initial)
138 140
139 if ((r = sshbuf_reserve(m, 4, &p)) != 0) 141 if ((r = sshbuf_reserve(m, 4, &p)) != 0)
140 fatal("%s: buffer error: %s", __func__, ssh_err(r)); 142 fatal("%s: buffer error: %s", __func__, ssh_err(r));
141 if (atomicio6(read, conn->fd_in, p, 4, 143 if (atomicio6(read, conn->fd_in, p, 4, sftpio,
142 conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_in) != 4) { 144 conn->limit_kbps > 0 ? &conn->bwlimit_in : NULL) != 4) {
143 if (errno == EPIPE || errno == ECONNRESET) 145 if (errno == EPIPE || errno == ECONNRESET)
144 fatal("Connection closed"); 146 fatal("Connection closed");
145 else 147 else
@@ -157,8 +159,8 @@ get_msg_extended(struct sftp_conn *conn, struct sshbuf *m, int initial)
157 159
158 if ((r = sshbuf_reserve(m, msg_len, &p)) != 0) 160 if ((r = sshbuf_reserve(m, msg_len, &p)) != 0)
159 fatal("%s: buffer error: %s", __func__, ssh_err(r)); 161 fatal("%s: buffer error: %s", __func__, ssh_err(r));
160 if (atomicio6(read, conn->fd_in, p, msg_len, 162 if (atomicio6(read, conn->fd_in, p, msg_len, sftpio,
161 conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_in) 163 conn->limit_kbps > 0 ? &conn->bwlimit_in : NULL)
162 != msg_len) { 164 != msg_len) {
163 if (errno == EPIPE) 165 if (errno == EPIPE)
164 fatal("Connection closed"); 166 fatal("Connection closed");