1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-07-04 04:52:47 -05:00

mainchan.c: rewrite handling of open-failure aborts.

This is another case where a stale pointer bug could have arisen from
a toplevel callback going off after an object was freed.

But here, just adding delete_callbacks_for_context wouldn't help. The
actual context parameter for the callback wasn't mainchan itself; it
was a tiny separate object, allocated to hold just the parameters of
the function the callback wanted to call. So if _those_ parameters
became stale before the callback was triggered, then even
delete_callbacks_for_context wouldn't have been able to help.

Also, mainchan itself would have been freed moments after this
callback was queued, so moving it to be a callback on mainchan itself
wouldn't help.

Solution: move the callback right out to Ssh, by introducing a new
ssh_sw_abort_deferred() which is just like ssh_sw_abort but does its
main work in a toplevel callback. Then ssh.c's existing call to
delete_callbacks_for_context will clean it up if necessary.
This commit is contained in:
Simon Tatham
2019-04-20 08:22:00 +01:00
parent 108baae60e
commit f99aeb3129
3 changed files with 25 additions and 22 deletions

View File

@ -334,33 +334,13 @@ static void mainchan_ready(mainchan *mc)
queue_idempotent_callback(&mc->ppl->ic_process_queue);
}
struct mainchan_open_failure_abort_ctx {
Ssh *ssh;
char *abort_message;
};
static void mainchan_open_failure_abort(void *vctx)
{
struct mainchan_open_failure_abort_ctx *ctx =
(struct mainchan_open_failure_abort_ctx *)vctx;
ssh_sw_abort(
ctx->ssh, "Server refused to open main channel: %s",
ctx->abort_message);
sfree(ctx->abort_message);
sfree(ctx);
}
static void mainchan_open_failure(Channel *chan, const char *errtext)
{
assert(chan->vt == &mainchan_channelvt);
mainchan *mc = container_of(chan, mainchan, chan);
struct mainchan_open_failure_abort_ctx *ctx =
snew(struct mainchan_open_failure_abort_ctx);
ctx->ssh = mc->ppl->ssh;
ctx->abort_message = dupstr(errtext);
queue_toplevel_callback(mainchan_open_failure_abort, ctx);
ssh_sw_abort_deferred(mc->ppl->ssh,
"Server refused to open main channel: %s", errtext);
}
static size_t mainchan_send(Channel *chan, bool is_stderr,