Try to decouple directions of delayed compression.

I ran 'git push' too soon on the last commit; after a bit more thought
I realise that I didn't get the logic quite right in the case where
one direction of the connection negotiates delayed compression and the
other negotiates ordinary or no compression.

For a start, we only need to worry about temporarily delaying outgoing
packets to avoid the race condition if delayed compression applies to
_outgoing_ packets - that can be disabled in the case where delayed
compression is inbound only (though that is admittedly unlikely).

Secondly, that means that detecting USERAUTH_SUCCESS to enable
compression has to happen even if the output blockage wasn't in place.

Thirdly, if we're independently enabling delayed compression in the
two directions, we should only print an Event Log entry for the one we
actually did!

This revised version is probably more robust, although for the moment
all of this is theoretical - I haven't tested against a server
implementing unidirectional delayed compression.
This commit is contained in:
Simon Tatham 2018-10-07 12:56:57 +01:00
Родитель 4c8c41b7a0
Коммит 34df99907a
1 изменённых файлов: 31 добавлений и 48 удалений

Просмотреть файл

@ -575,63 +575,30 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp)
continue;
}
if (s->pending_compression && userauth_range(type)) {
if (type == SSH2_MSG_USERAUTH_SUCCESS) {
/*
* Another one: if we were configured with OpenSSH's
* deferred compression which is triggered on receipt
* of USERAUTH_SUCCESS, and we're currently
* anticipating the next packet perhaps _being_
* USERAUTH_SUCCESS, then we do some special handling.
* of USERAUTH_SUCCESS, then this is the moment to
* turn on compression.
*/
if (type == SSH2_MSG_USERAUTH_SUCCESS) {
/*
* Success! This is the moment to turn on
* compression.
*/
s->pending_compression = FALSE;
if (s->in.pending_compression) {
s->in_decomp =
ssh_decompressor_new(s->in.pending_compression);
bpp_logevent(("Initialised delayed %s decompression",
ssh_decompressor_alg(
s->in_decomp)->text_name));
s->in.pending_compression = NULL;
}
if (s->out.pending_compression) {
s->out_comp =
ssh_compressor_new(s->out.pending_compression);
s->in.pending_compression = NULL;
bpp_logevent(("Initialised delayed %s compression",
ssh_compressor_alg(
s->out_comp)->text_name));
s->out.pending_compression = NULL;
if (s->out_comp)
bpp_logevent(("Initialised delayed %s compression",
ssh_compressor_alg(
s->out_comp)->text_name));
if (s->in_decomp)
bpp_logevent(("Initialised delayed %s decompression",
ssh_decompressor_alg(
s->in_decomp)->text_name));
/*
* Also, since we will have temporarily disabled
* output queue processing (for fear of having
* some asynchronous thing like an IGNORE message
* cross in transit with USERAUTH_SUCCESS coming
* the other way, leaving its compresssion status
* in doubt), we should schedule a run of the
* output queue now, to release any pending
* packets.
*/
queue_idempotent_callback(&s->bpp.ic_out_pq);
} else {
/*
* This message indicates that we're not about to
* see USERAUTH_SUCCESS (i.e. turn on compression)
* just yet, so we turn off the outgoing packet
* blockage and release any queued output packets,
* so that we can make another attempt to
* authenticate.
*/
s->pending_compression = FALSE;
queue_idempotent_callback(&s->bpp.ic_out_pq);
}
}
if (type == SSH2_MSG_USERAUTH_SUCCESS) {
/*
* Whether or not we were doing delayed compression in
* _this_ set of crypto parameters, we should set a
@ -641,6 +608,23 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp)
*/
s->seen_userauth_success = TRUE;
}
if (s->pending_compression && userauth_range(type)) {
/*
* Receiving any userauth message at all indicates
* that we're not about to turn on delayed compression
* - either because we just _have_ done, or because
* this message is a USERAUTH_FAILURE or some kind of
* intermediate 'please send more data' continuation
* message. Either way, we turn off the outgoing
* packet blockage for now, and release any queued
* output packets, so that we can make another attempt
* to authenticate. The next userauth packet we send
* will re-block the output direction.
*/
s->pending_compression = FALSE;
queue_idempotent_callback(&s->bpp.ic_out_pq);
}
}
}
@ -895,8 +879,7 @@ static void ssh2_bpp_handle_output(BinaryPacketProtocol *bpp)
ssh2_bpp_format_packet(s, pkt);
ssh_free_pktout(pkt);
if (n_userauth == 0 &&
(s->out.pending_compression || s->in.pending_compression)) {
if (n_userauth == 0 && s->out.pending_compression) {
/*
* This is the last userauth packet in the queue, so
* unless our side decides to send another one in future,