1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 17:38:00 +00:00

Revert premature queuing of channel messages.

At the point where the do_ssh2_connection coroutine rewrites lots of
dispatch table entries to point to things other than itself, there's a
possibility that it's too late, because some packets of those types
have already arrived and been put into pq_ssh2_connection. So you'd
get weird errors like 'Strange packet received: type 94', in which the
only thing that's strange is why packet 94 might conceivably be
unexpected, since it's SSH_MSG_CHANNEL_DATA!

(I observed this when 'plink host -nc otherhost:port' became a sharing
downstream, but I have no reason to think that's the only circumstance
where this can possibly occur, or even a reliable one. It just
happened to have the right timing.)

I'm not completely sure this is the _best_ solution, but it seems to
work: at the point when I rewrite the dispatch table, I also return
the whole of the connection packet queue to the main queue, so that
it'll be run through the dispatch table a second time which will
effectively filter out any packets that we've just installed new
handlers for.
This commit is contained in:
Simon Tatham 2018-05-25 21:17:09 +01:00
parent 8c7eddc9a1
commit b95a6dece6

29
ssh.c
View File

@ -805,6 +805,25 @@ static void pq_clear(struct PacketQueue *pq)
ssh_unref_packet(pkt);
}
static int pq_empty_on_to_front_of(struct PacketQueue *src,
struct PacketQueue *dest)
{
struct PacketQueueNode *srcfirst, *srclast;
if (src->end.next == &src->end)
return FALSE;
srcfirst = src->end.next;
srclast = src->end.prev;
srcfirst->prev = &dest->end;
srclast->next = dest->end.next;
srcfirst->prev->next = srcfirst;
srclast->next->prev = srclast;
src->end.next = src->end.prev = &src->end;
return TRUE;
}
struct rdpkt1_state_tag {
long len, pad, biglen;
unsigned long realcrc, gotcrc;
@ -11471,6 +11490,16 @@ static void do_ssh2_connection(void *vctx)
ssh->packet_dispatch[SSH2_MSG_CHANNEL_SUCCESS] = ssh2_msg_channel_response;
ssh->packet_dispatch[SSH2_MSG_CHANNEL_FAILURE] = ssh2_msg_channel_response;
/*
* Put our current pending packet queue back to the front of
* pq_full, and then schedule a callback to re-process those
* packets (if any). That way, anything already in our queue that
* matches any of the table entries we've just modified will go to
* the right handler function, and won't come here to confuse us.
*/
if (pq_empty_on_to_front_of(&ssh->pq_ssh2_connection, &ssh->pq_full))
queue_idempotent_callback(&ssh->pq_full_consumer);
/*
* Now the connection protocol is properly up and running, with
* all those dispatch table entries, so it's safe to let