1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-07-06 22:12: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

22
ssh.c
View File

@ -133,6 +133,8 @@ struct Ssh {
Pinger *pinger;
char *deferred_abort_message;
bool need_random_unref;
};
@ -555,6 +557,24 @@ void ssh_user_close(Ssh *ssh, const char *fmt, ...)
}
}
void ssh_deferred_abort_callback(void *vctx)
{
Ssh *ssh = (Ssh *)vctx;
char *msg = ssh->deferred_abort_message;
ssh->deferred_abort_message = NULL;
ssh_sw_abort(ssh, msg);
sfree(msg);
}
void ssh_sw_abort_deferred(Ssh *ssh, const char *fmt, ...)
{
if (!ssh->deferred_abort_message) {
GET_FORMATTED_MSG;
ssh->deferred_abort_message = msg;
queue_toplevel_callback(ssh_deferred_abort_callback, ssh);
}
}
static void ssh_socket_log(Plug *plug, int type, SockAddr *addr, int port,
const char *error_msg, int error_code)
{
@ -915,6 +935,8 @@ static void ssh_free(Backend *be)
ssh_gss_cleanup(ssh->gss_state.libs);
#endif
sfree(ssh->deferred_abort_message);
delete_callbacks_for_context(ssh); /* likely to catch ic_out_raw */
need_random_unref = ssh->need_random_unref;