diff options
author | djm@openbsd.org <djm@openbsd.org> | 2018-10-04 07:47:35 +0000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2018-10-04 17:50:22 +1000 |
commit | e0d6501e86734c48c8c503f81e1c0926e98c5c4c (patch) | |
tree | 94ba740e9fa6cc8ea015aa1ea49e63addc345301 /nchan.c | |
parent | 6f1aabb128246f445e33b8844fad3de9cb1d18cb (diff) |
upstream: when the peer sends a channel-close message, make sure we
close the local extended read fd (stderr) along with the regular read fd
(stdout). Avoids weird stuck processed in multiplexing mode.
Report and analysis by Nelson Elhage and Geoffrey Thomas in bz#2863
ok dtucker@ markus@
OpenBSD-Commit-ID: a48a2467fe938de4de69d2e7193d5fa701f12ae9
Diffstat (limited to 'nchan.c')
-rw-r--r-- | nchan.c | 24 |
1 files changed, 23 insertions, 1 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: nchan.c,v 1.68 2018/10/04 00:10:11 djm Exp $ */ | 1 | /* $OpenBSD: nchan.c,v 1.69 2018/10/04 07:47:35 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -80,6 +80,7 @@ static void chan_send_eow2(struct ssh *, Channel *); | |||
80 | /* helper */ | 80 | /* helper */ |
81 | static void chan_shutdown_write(struct ssh *, Channel *); | 81 | static void chan_shutdown_write(struct ssh *, Channel *); |
82 | static void chan_shutdown_read(struct ssh *, Channel *); | 82 | static void chan_shutdown_read(struct ssh *, Channel *); |
83 | static void chan_shutdown_extended_read(struct ssh *, Channel *); | ||
83 | 84 | ||
84 | static const char *ostates[] = { "open", "drain", "wait_ieof", "closed" }; | 85 | static const char *ostates[] = { "open", "drain", "wait_ieof", "closed" }; |
85 | static const char *istates[] = { "open", "drain", "wait_oclose", "closed" }; | 86 | static const char *istates[] = { "open", "drain", "wait_oclose", "closed" }; |
@@ -289,11 +290,13 @@ chan_rcvd_oclose(struct ssh *ssh, Channel *c) | |||
289 | switch (c->istate) { | 290 | switch (c->istate) { |
290 | case CHAN_INPUT_OPEN: | 291 | case CHAN_INPUT_OPEN: |
291 | chan_shutdown_read(ssh, c); | 292 | chan_shutdown_read(ssh, c); |
293 | chan_shutdown_extended_read(ssh, c); | ||
292 | chan_set_istate(c, CHAN_INPUT_CLOSED); | 294 | chan_set_istate(c, CHAN_INPUT_CLOSED); |
293 | break; | 295 | break; |
294 | case CHAN_INPUT_WAIT_DRAIN: | 296 | case CHAN_INPUT_WAIT_DRAIN: |
295 | if (!(c->flags & CHAN_LOCAL)) | 297 | if (!(c->flags & CHAN_LOCAL)) |
296 | chan_send_eof2(ssh, c); | 298 | chan_send_eof2(ssh, c); |
299 | chan_shutdown_extended_read(ssh, c); | ||
297 | chan_set_istate(c, CHAN_INPUT_CLOSED); | 300 | chan_set_istate(c, CHAN_INPUT_CLOSED); |
298 | break; | 301 | break; |
299 | } | 302 | } |
@@ -422,3 +425,22 @@ chan_shutdown_read(struct ssh *ssh, Channel *c) | |||
422 | } | 425 | } |
423 | } | 426 | } |
424 | } | 427 | } |
428 | |||
429 | static void | ||
430 | chan_shutdown_extended_read(struct ssh *ssh, Channel *c) | ||
431 | { | ||
432 | if (c->type == SSH_CHANNEL_LARVAL || c->efd == -1) | ||
433 | return; | ||
434 | if (c->extended_usage != CHAN_EXTENDED_READ && | ||
435 | c->extended_usage != CHAN_EXTENDED_IGNORE) | ||
436 | return; | ||
437 | debug2("channel %d: %s (i%d o%d sock %d wfd %d efd %d [%s])", | ||
438 | c->self, __func__, c->istate, c->ostate, c->sock, c->rfd, c->efd, | ||
439 | channel_format_extended_usage(c)); | ||
440 | if (channel_close_fd(ssh, &c->efd) < 0) { | ||
441 | logit("channel %d: %s: close() failed for " | ||
442 | "extended fd %d [i%d o%d]: %.100s", | ||
443 | c->self, __func__, c->efd, c->istate, c->ostate, | ||
444 | strerror(errno)); | ||
445 | } | ||
446 | } | ||