upstream: Add channel_force_close()

This will forcibly close an open channel by simulating read/write errors,
draining the IO buffers and calling the detach function.

Previously the detach function was only ever called during channel garbage
collection, but there was no way to signal the user of a channel (e.g.
session.c) that its channel was being closed deliberately (vs. by the
usual state-machine logic). So this adds an extra "force" argument to the
channel cleanup callback to indicate this condition.

ok markus dtucker

OpenBSD-Commit-ID: 23052707a42bdc62fda2508636e624afd466324b
This commit is contained in:
djm@openbsd.org 2023-01-06 02:39:59 +00:00 committed by Damien Miller
parent d478cdc7ad
commit c60438158a
No known key found for this signature in database
7 changed files with 50 additions and 40 deletions

View File

@ -1,4 +1,4 @@
/* $OpenBSD: channels.c,v 1.422 2023/01/06 02:38:23 djm Exp $ */
/* $OpenBSD: channels.c,v 1.423 2023/01/06 02:39:59 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -1222,6 +1222,29 @@ x11_open_helper(struct ssh *ssh, struct sshbuf *b)
return 1;
}
void
channel_force_close(struct ssh *ssh, Channel *c, int abandon)
{
debug3_f("channel %d: forcibly closing", c->self);
if (c->istate == CHAN_INPUT_OPEN)
chan_read_failed(ssh, c);
if (c->istate == CHAN_INPUT_WAIT_DRAIN) {
sshbuf_reset(c->input);
chan_ibuf_empty(ssh, c);
}
if (c->ostate == CHAN_OUTPUT_OPEN ||
c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
sshbuf_reset(c->output);
chan_write_failed(ssh, c);
}
if (c->detach_user)
c->detach_user(ssh, c->self, 1, NULL);
if (c->efd != -1)
channel_close_fd(ssh, c, &c->efd);
if (abandon)
c->type = SSH_CHANNEL_ABANDONED;
}
static void
channel_pre_x11_open(struct ssh *ssh, Channel *c)
{
@ -1233,15 +1256,11 @@ channel_pre_x11_open(struct ssh *ssh, Channel *c)
c->type = SSH_CHANNEL_OPEN;
channel_pre_open(ssh, c);
} else if (ret == -1) {
logit("X11 connection rejected because of wrong authentication.");
logit("X11 connection rejected because of wrong "
"authentication.");
debug2("X11 rejected %d i%d/o%d",
c->self, c->istate, c->ostate);
chan_read_failed(ssh, c);
sshbuf_reset(c->input);
chan_ibuf_empty(ssh, c);
sshbuf_reset(c->output);
chan_write_failed(ssh, c);
debug2("X11 closed %d i%d/o%d", c->self, c->istate, c->ostate);
channel_force_close(ssh, c, 0);
}
}
@ -1591,11 +1610,7 @@ static void
rdynamic_close(struct ssh *ssh, Channel *c)
{
c->type = SSH_CHANNEL_OPEN;
chan_read_failed(ssh, c);
sshbuf_reset(c->input);
chan_ibuf_empty(ssh, c);
sshbuf_reset(c->output);
chan_write_failed(ssh, c);
channel_force_close(ssh, c, 0);
}
/* reverse dynamic port forwarding */
@ -2395,7 +2410,7 @@ channel_garbage_collect(struct ssh *ssh, Channel *c)
return;
debug2("channel %d: gc: notify user", c->self);
c->detach_user(ssh, c->self, NULL);
c->detach_user(ssh, c->self, 0, NULL);
/* if we still have a callback */
if (c->detach_user != NULL)
return;

View File

@ -1,4 +1,4 @@
/* $OpenBSD: channels.h,v 1.144 2023/01/06 02:38:23 djm Exp $ */
/* $OpenBSD: channels.h,v 1.145 2023/01/06 02:39:59 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -88,7 +88,7 @@ typedef struct Channel Channel;
struct fwd_perm_list;
typedef void channel_open_fn(struct ssh *, int, int, void *);
typedef void channel_callback_fn(struct ssh *, int, void *);
typedef void channel_callback_fn(struct ssh *, int, int, void *);
typedef int channel_infilter_fn(struct ssh *, struct Channel *, char *, int);
typedef void channel_filter_cleanup_fn(struct ssh *, int, void *);
typedef u_char *channel_outfilter_fn(struct ssh *, struct Channel *,
@ -281,6 +281,7 @@ void channel_set_fds(struct ssh *, int, int, int, int, int,
void channel_free(struct ssh *, Channel *);
void channel_free_all(struct ssh *);
void channel_stop_listening(struct ssh *);
void channel_force_close(struct ssh *, Channel *, int);
void channel_send_open(struct ssh *, int);
void channel_request_start(struct ssh *, int, char *, int);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: clientloop.c,v 1.386 2023/01/06 02:38:23 djm Exp $ */
/* $OpenBSD: clientloop.c,v 1.387 2023/01/06 02:39:59 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -1033,15 +1033,7 @@ process_escapes(struct ssh *ssh, Channel *c,
efc->escape_char)) != 0)
fatal_fr(r, "sshbuf_putf");
if (c && c->ctl_chan != -1) {
chan_read_failed(ssh, c);
chan_write_failed(ssh, c);
if (c->detach_user) {
c->detach_user(ssh,
c->self, NULL);
}
c->type = SSH_CHANNEL_ABANDONED;
sshbuf_reset(c->input);
chan_ibuf_empty(ssh, c);
channel_force_close(ssh, c, 1);
return 0;
} else
quit_pending = 1;
@ -1267,7 +1259,7 @@ client_simple_escape_filter(struct ssh *ssh, Channel *c, char *buf, int len)
}
static void
client_channel_closed(struct ssh *ssh, int id, void *arg)
client_channel_closed(struct ssh *ssh, int id, int force, void *arg)
{
channel_cancel_cleanup(ssh, id);
session_closed = 1;

6
mux.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: mux.c,v 1.94 2022/06/03 04:30:47 djm Exp $ */
/* $OpenBSD: mux.c,v 1.95 2023/01/06 02:39:59 djm Exp $ */
/*
* Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org>
*
@ -188,7 +188,7 @@ static const struct {
/* Cleanup callback fired on closure of mux client _session_ channel */
/* ARGSUSED */
static void
mux_master_session_cleanup_cb(struct ssh *ssh, int cid, void *unused)
mux_master_session_cleanup_cb(struct ssh *ssh, int cid, int force, void *unused)
{
Channel *cc, *c = channel_by_id(ssh, cid);
@ -210,7 +210,7 @@ mux_master_session_cleanup_cb(struct ssh *ssh, int cid, void *unused)
/* Cleanup callback fired on closure of mux client _control_ channel */
/* ARGSUSED */
static void
mux_master_control_cleanup_cb(struct ssh *ssh, int cid, void *unused)
mux_master_control_cleanup_cb(struct ssh *ssh, int cid, int force, void *unused)
{
Channel *sc, *c = channel_by_id(ssh, cid);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: session.c,v 1.330 2022/02/08 08:59:12 dtucker Exp $ */
/* $OpenBSD: session.c,v 1.331 2023/01/06 02:39:59 djm Exp $ */
/*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
@ -2335,7 +2335,7 @@ session_close_x11(struct ssh *ssh, int id)
}
static void
session_close_single_x11(struct ssh *ssh, int id, void *arg)
session_close_single_x11(struct ssh *ssh, int id, int force, void *arg)
{
Session *s;
u_int i;
@ -2469,7 +2469,7 @@ session_close_by_pid(struct ssh *ssh, pid_t pid, int status)
* the session 'child' itself dies
*/
void
session_close_by_channel(struct ssh *ssh, int id, void *arg)
session_close_by_channel(struct ssh *ssh, int id, int force, void *arg)
{
Session *s = session_by_channel(id);
u_int i;
@ -2482,11 +2482,13 @@ session_close_by_channel(struct ssh *ssh, int id, void *arg)
if (s->pid != 0) {
debug_f("channel %d: has child, ttyfd %d", id, s->ttyfd);
/*
* delay detach of session, but release pty, since
* the fd's to the child are already closed
* delay detach of session (unless this is a forced close),
* but release pty, since the fd's to the child are already
* closed
*/
if (s->ttyfd != -1)
session_pty_cleanup(s);
if (!force)
return;
}
/* detach by removing callback */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: session.h,v 1.36 2018/10/02 12:40:07 djm Exp $ */
/* $OpenBSD: session.h,v 1.37 2023/01/06 02:39:59 djm Exp $ */
/*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
@ -70,7 +70,7 @@ int session_open(Authctxt *, int);
void session_unused(int);
int session_input_channel_req(struct ssh *, Channel *, const char *);
void session_close_by_pid(struct ssh *ssh, pid_t, int);
void session_close_by_channel(struct ssh *, int, void *);
void session_close_by_channel(struct ssh *, int, int, void *);
void session_destroy_all(struct ssh *, void (*)(Session *));
void session_pty_cleanup2(Session *);

4
ssh.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssh.c,v 1.581 2022/12/09 00:22:29 dtucker Exp $ */
/* $OpenBSD: ssh.c,v 1.582 2023/01/06 02:39:59 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -1855,7 +1855,7 @@ ssh_confirm_remote_forward(struct ssh *ssh, int type, u_int32_t seq, void *ctxt)
}
static void
client_cleanup_stdio_fwd(struct ssh *ssh, int id, void *arg)
client_cleanup_stdio_fwd(struct ssh *ssh, int id, int force, void *arg)
{
debug("stdio forwarding: done");
cleanup_exit(0);