You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

258 lines
7.4 KiB

  1. From 11b88754cadcad0ba79b4ffcc127223248dccb54 Mon Sep 17 00:00:00 2001
  2. From: "dtucker@openbsd.org" <dtucker@openbsd.org>
  3. Date: Wed, 23 Jan 2019 08:01:46 +0000
  4. Subject: upstream: Sanitize scp filenames via snmprintf. To do this we move
  5. the progressmeter formatting outside of signal handler context and have the
  6. atomicio callback called for EINTR too. bz#2434 with contributions from djm
  7. and jjelen at redhat.com, ok djm@
  8. OpenBSD-Commit-ID: 1af61c1f70e4f3bd8ab140b9f1fa699481db57d8
  9. CVE-2019-6109
  10. Origin: backport, https://anongit.mindrot.org/openssh.git/commit/?id=8976f1c4b2721c26e878151f52bdf346dfe2d54c
  11. Bug-Debian: https://bugs.debian.org/793412
  12. Last-Update: 2019-02-08
  13. Patch-Name: sanitize-scp-filenames-via-snmprintf.patch
  14. ---
  15. atomicio.c | 20 ++++++++++++++-----
  16. progressmeter.c | 53 ++++++++++++++++++++++---------------------------
  17. progressmeter.h | 3 ++-
  18. scp.c | 1 +
  19. sftp-client.c | 16 ++++++++-------
  20. 5 files changed, 51 insertions(+), 42 deletions(-)
  21. diff --git a/atomicio.c b/atomicio.c
  22. index f854a06f5..d91bd7621 100644
  23. --- a/atomicio.c
  24. +++ b/atomicio.c
  25. @@ -65,9 +65,14 @@ atomicio6(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n,
  26. res = (f) (fd, s + pos, n - pos);
  27. switch (res) {
  28. case -1:
  29. - if (errno == EINTR)
  30. + if (errno == EINTR) {
  31. + /* possible SIGALARM, update callback */
  32. + if (cb != NULL && cb(cb_arg, 0) == -1) {
  33. + errno = EINTR;
  34. + return pos;
  35. + }
  36. continue;
  37. - if (errno == EAGAIN || errno == EWOULDBLOCK) {
  38. + } else if (errno == EAGAIN || errno == EWOULDBLOCK) {
  39. #ifndef BROKEN_READ_COMPARISON
  40. (void)poll(&pfd, 1, -1);
  41. #endif
  42. @@ -122,9 +127,14 @@ atomiciov6(ssize_t (*f) (int, const struct iovec *, int), int fd,
  43. res = (f) (fd, iov, iovcnt);
  44. switch (res) {
  45. case -1:
  46. - if (errno == EINTR)
  47. + if (errno == EINTR) {
  48. + /* possible SIGALARM, update callback */
  49. + if (cb != NULL && cb(cb_arg, 0) == -1) {
  50. + errno = EINTR;
  51. + return pos;
  52. + }
  53. continue;
  54. - if (errno == EAGAIN || errno == EWOULDBLOCK) {
  55. + } else if (errno == EAGAIN || errno == EWOULDBLOCK) {
  56. #ifndef BROKEN_READV_COMPARISON
  57. (void)poll(&pfd, 1, -1);
  58. #endif
  59. diff --git a/progressmeter.c b/progressmeter.c
  60. index fe9bf52e4..add462dde 100644
  61. --- a/progressmeter.c
  62. +++ b/progressmeter.c
  63. @@ -31,6 +31,7 @@
  64. #include <errno.h>
  65. #include <signal.h>
  66. +#include <stdarg.h>
  67. #include <stdio.h>
  68. #include <string.h>
  69. #include <time.h>
  70. @@ -39,6 +40,7 @@
  71. #include "progressmeter.h"
  72. #include "atomicio.h"
  73. #include "misc.h"
  74. +#include "utf8.h"
  75. #define DEFAULT_WINSIZE 80
  76. #define MAX_WINSIZE 512
  77. @@ -61,7 +63,7 @@ static void setscreensize(void);
  78. void refresh_progress_meter(void);
  79. /* signal handler for updating the progress meter */
  80. -static void update_progress_meter(int);
  81. +static void sig_alarm(int);
  82. static double start; /* start progress */
  83. static double last_update; /* last progress update */
  84. @@ -74,6 +76,7 @@ static long stalled; /* how long we have been stalled */
  85. static int bytes_per_second; /* current speed in bytes per second */
  86. static int win_size; /* terminal window size */
  87. static volatile sig_atomic_t win_resized; /* for window resizing */
  88. +static volatile sig_atomic_t alarm_fired;
  89. /* units for format_size */
  90. static const char unit[] = " KMGT";
  91. @@ -126,9 +129,17 @@ refresh_progress_meter(void)
  92. off_t bytes_left;
  93. int cur_speed;
  94. int hours, minutes, seconds;
  95. - int i, len;
  96. int file_len;
  97. + if ((!alarm_fired && !win_resized) || !can_output())
  98. + return;
  99. + alarm_fired = 0;
  100. +
  101. + if (win_resized) {
  102. + setscreensize();
  103. + win_resized = 0;
  104. + }
  105. +
  106. transferred = *counter - (cur_pos ? cur_pos : start_pos);
  107. cur_pos = *counter;
  108. now = monotime_double();
  109. @@ -158,16 +169,11 @@ refresh_progress_meter(void)
  110. /* filename */
  111. buf[0] = '\0';
  112. - file_len = win_size - 35;
  113. + file_len = win_size - 36;
  114. if (file_len > 0) {
  115. - len = snprintf(buf, file_len + 1, "\r%s", file);
  116. - if (len < 0)
  117. - len = 0;
  118. - if (len >= file_len + 1)
  119. - len = file_len;
  120. - for (i = len; i < file_len; i++)
  121. - buf[i] = ' ';
  122. - buf[file_len] = '\0';
  123. + buf[0] = '\r';
  124. + snmprintf(buf+1, sizeof(buf)-1 , &file_len, "%*s",
  125. + file_len * -1, file);
  126. }
  127. /* percent of transfer done */
  128. @@ -228,22 +234,11 @@ refresh_progress_meter(void)
  129. /*ARGSUSED*/
  130. static void
  131. -update_progress_meter(int ignore)
  132. +sig_alarm(int ignore)
  133. {
  134. - int save_errno;
  135. -
  136. - save_errno = errno;
  137. -
  138. - if (win_resized) {
  139. - setscreensize();
  140. - win_resized = 0;
  141. - }
  142. - if (can_output())
  143. - refresh_progress_meter();
  144. -
  145. - signal(SIGALRM, update_progress_meter);
  146. + signal(SIGALRM, sig_alarm);
  147. + alarm_fired = 1;
  148. alarm(UPDATE_INTERVAL);
  149. - errno = save_errno;
  150. }
  151. void
  152. @@ -259,10 +254,9 @@ start_progress_meter(const char *f, off_t filesize, off_t *ctr)
  153. bytes_per_second = 0;
  154. setscreensize();
  155. - if (can_output())
  156. - refresh_progress_meter();
  157. + refresh_progress_meter();
  158. - signal(SIGALRM, update_progress_meter);
  159. + signal(SIGALRM, sig_alarm);
  160. signal(SIGWINCH, sig_winch);
  161. alarm(UPDATE_INTERVAL);
  162. }
  163. @@ -286,6 +280,7 @@ stop_progress_meter(void)
  164. static void
  165. sig_winch(int sig)
  166. {
  167. + signal(SIGWINCH, sig_winch);
  168. win_resized = 1;
  169. }
  170. diff --git a/progressmeter.h b/progressmeter.h
  171. index bf179dca6..8f6678060 100644
  172. --- a/progressmeter.h
  173. +++ b/progressmeter.h
  174. @@ -24,4 +24,5 @@
  175. */
  176. void start_progress_meter(const char *, off_t, off_t *);
  177. +void refresh_progress_meter(void);
  178. void stop_progress_meter(void);
  179. diff --git a/scp.c b/scp.c
  180. index 7163d33dc..80308573c 100644
  181. --- a/scp.c
  182. +++ b/scp.c
  183. @@ -593,6 +593,7 @@ scpio(void *_cnt, size_t s)
  184. off_t *cnt = (off_t *)_cnt;
  185. *cnt += s;
  186. + refresh_progress_meter();
  187. if (limit_kbps > 0)
  188. bandwidth_limit(&bwlimit, s);
  189. return 0;
  190. diff --git a/sftp-client.c b/sftp-client.c
  191. index 4986d6d8d..2bc698f86 100644
  192. --- a/sftp-client.c
  193. +++ b/sftp-client.c
  194. @@ -101,7 +101,9 @@ sftpio(void *_bwlimit, size_t amount)
  195. {
  196. struct bwlimit *bwlimit = (struct bwlimit *)_bwlimit;
  197. - bandwidth_limit(bwlimit, amount);
  198. + refresh_progress_meter();
  199. + if (bwlimit != NULL)
  200. + bandwidth_limit(bwlimit, amount);
  201. return 0;
  202. }
  203. @@ -121,8 +123,8 @@ send_msg(struct sftp_conn *conn, struct sshbuf *m)
  204. iov[1].iov_base = (u_char *)sshbuf_ptr(m);
  205. iov[1].iov_len = sshbuf_len(m);
  206. - if (atomiciov6(writev, conn->fd_out, iov, 2,
  207. - conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_out) !=
  208. + if (atomiciov6(writev, conn->fd_out, iov, 2, sftpio,
  209. + conn->limit_kbps > 0 ? &conn->bwlimit_out : NULL) !=
  210. sshbuf_len(m) + sizeof(mlen))
  211. fatal("Couldn't send packet: %s", strerror(errno));
  212. @@ -138,8 +140,8 @@ get_msg_extended(struct sftp_conn *conn, struct sshbuf *m, int initial)
  213. if ((r = sshbuf_reserve(m, 4, &p)) != 0)
  214. fatal("%s: buffer error: %s", __func__, ssh_err(r));
  215. - if (atomicio6(read, conn->fd_in, p, 4,
  216. - conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_in) != 4) {
  217. + if (atomicio6(read, conn->fd_in, p, 4, sftpio,
  218. + conn->limit_kbps > 0 ? &conn->bwlimit_in : NULL) != 4) {
  219. if (errno == EPIPE || errno == ECONNRESET)
  220. fatal("Connection closed");
  221. else
  222. @@ -157,8 +159,8 @@ get_msg_extended(struct sftp_conn *conn, struct sshbuf *m, int initial)
  223. if ((r = sshbuf_reserve(m, msg_len, &p)) != 0)
  224. fatal("%s: buffer error: %s", __func__, ssh_err(r));
  225. - if (atomicio6(read, conn->fd_in, p, msg_len,
  226. - conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_in)
  227. + if (atomicio6(read, conn->fd_in, p, msg_len, sftpio,
  228. + conn->limit_kbps > 0 ? &conn->bwlimit_in : NULL)
  229. != msg_len) {
  230. if (errno == EPIPE)
  231. fatal("Connection closed");