mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-10 09:58:01 +00:00
Remove data and maxlen fields from PktIn.
These were only used in the rdpkt coroutines, during construction of the incoming packet; once it's complete, they're never touched again. So really they should have been fields in the rdpkt coroutines' state - and now they are. The new memory allocation strategy for incoming packets is to defer creation of the returned pktin structure until we know how big its data buffer will really need to be, and then use snew_plus to make the PktIn and the payload block in the same allocation. When we have to read and keep some amount of the packet before allocating the returned structure, we do it by having a persistent buffer in the rdpkt state, which is retained for the whole connection and only freed once in ssh_free.
This commit is contained in:
parent
bf3c9df54a
commit
ea04bf3da9
233
ssh.c
233
ssh.c
@ -674,8 +674,6 @@ struct PktIn {
|
|||||||
int refcount;
|
int refcount;
|
||||||
int type;
|
int type;
|
||||||
unsigned long sequence; /* SSH-2 incoming sequence number */
|
unsigned long sequence; /* SSH-2 incoming sequence number */
|
||||||
unsigned char *data; /* allocated storage */
|
|
||||||
long maxlen; /* amount of storage allocated for `data' */
|
|
||||||
long encrypted_len; /* for SSH-2 total-size counting */
|
long encrypted_len; /* for SSH-2 total-size counting */
|
||||||
BinarySource_IMPLEMENTATION;
|
BinarySource_IMPLEMENTATION;
|
||||||
};
|
};
|
||||||
@ -807,21 +805,26 @@ static int pq_empty_on_to_front_of(struct PacketQueue *src,
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct rdpkt1_state_tag {
|
struct rdpkt1_state_tag {
|
||||||
long len, pad, biglen, length;
|
long len, pad, biglen, length, maxlen;
|
||||||
|
unsigned char *data;
|
||||||
unsigned long realcrc, gotcrc;
|
unsigned long realcrc, gotcrc;
|
||||||
int chunk;
|
int chunk;
|
||||||
PktIn *pktin;
|
PktIn *pktin;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct rdpkt2_state_tag {
|
struct rdpkt2_state_tag {
|
||||||
long len, pad, payload, packetlen, maclen, length;
|
long len, pad, payload, packetlen, maclen, length, maxlen;
|
||||||
|
unsigned char *buf;
|
||||||
|
size_t bufsize;
|
||||||
|
unsigned char *data;
|
||||||
int cipherblk;
|
int cipherblk;
|
||||||
unsigned long incoming_sequence;
|
unsigned long incoming_sequence;
|
||||||
PktIn *pktin;
|
PktIn *pktin;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct rdpkt2_bare_state_tag {
|
struct rdpkt2_bare_state_tag {
|
||||||
long packetlen;
|
long packetlen, maxlen;
|
||||||
|
unsigned char *data;
|
||||||
unsigned long incoming_sequence;
|
unsigned long incoming_sequence;
|
||||||
PktIn *pktin;
|
PktIn *pktin;
|
||||||
};
|
};
|
||||||
@ -1373,11 +1376,9 @@ static void c_write_str(Ssh ssh, const char *buf)
|
|||||||
|
|
||||||
static void ssh_unref_packet(PktIn *pkt)
|
static void ssh_unref_packet(PktIn *pkt)
|
||||||
{
|
{
|
||||||
if (--pkt->refcount <= 0) {
|
if (--pkt->refcount <= 0)
|
||||||
sfree(pkt->data);
|
|
||||||
sfree(pkt);
|
sfree(pkt);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static void ssh_free_pktout(PktOut *pkt)
|
static void ssh_free_pktout(PktOut *pkt)
|
||||||
{
|
{
|
||||||
@ -1507,12 +1508,7 @@ static void ssh1_rdpkt(Ssh ssh)
|
|||||||
crBegin(ssh->ssh1_rdpkt_crstate);
|
crBegin(ssh->ssh1_rdpkt_crstate);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
st->pktin = snew(PktIn);
|
st->maxlen = 0;
|
||||||
st->pktin->data = NULL;
|
|
||||||
st->pktin->maxlen = 0;
|
|
||||||
st->pktin->refcount = 1;
|
|
||||||
|
|
||||||
st->pktin->type = 0;
|
|
||||||
st->length = 0;
|
st->length = 0;
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -1533,14 +1529,20 @@ static void ssh1_rdpkt(Ssh ssh)
|
|||||||
crStopV;
|
crStopV;
|
||||||
}
|
}
|
||||||
|
|
||||||
st->pktin->maxlen = st->biglen;
|
/*
|
||||||
st->pktin->data = snewn(st->biglen, unsigned char);
|
* Allocate the packet to return, now we know its length.
|
||||||
|
*/
|
||||||
|
st->pktin = snew_plus(PktIn, st->biglen);
|
||||||
|
st->pktin->refcount = 1;
|
||||||
|
st->pktin->type = 0;
|
||||||
|
|
||||||
|
st->maxlen = st->biglen;
|
||||||
|
st->data = snew_plus_get_aux(st->pktin);
|
||||||
|
|
||||||
crMaybeWaitUntilV(bufchain_try_fetch_consume(
|
crMaybeWaitUntilV(bufchain_try_fetch_consume(
|
||||||
&ssh->incoming_data,
|
&ssh->incoming_data, st->data, st->biglen));
|
||||||
st->pktin->data, st->biglen));
|
|
||||||
|
|
||||||
if (ssh->cipher && detect_attack(ssh->crcda_ctx, st->pktin->data,
|
if (ssh->cipher && detect_attack(ssh->crcda_ctx, st->data,
|
||||||
st->biglen, NULL)) {
|
st->biglen, NULL)) {
|
||||||
bombout(("Network attack (CRC compensation) detected!"));
|
bombout(("Network attack (CRC compensation) detected!"));
|
||||||
ssh_unref_packet(st->pktin);
|
ssh_unref_packet(st->pktin);
|
||||||
@ -1548,10 +1550,10 @@ static void ssh1_rdpkt(Ssh ssh)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ssh->cipher)
|
if (ssh->cipher)
|
||||||
ssh->cipher->decrypt(ssh->v1_cipher_ctx, st->pktin->data, st->biglen);
|
ssh->cipher->decrypt(ssh->v1_cipher_ctx, st->data, st->biglen);
|
||||||
|
|
||||||
st->realcrc = crc32_compute(st->pktin->data, st->biglen - 4);
|
st->realcrc = crc32_compute(st->data, st->biglen - 4);
|
||||||
st->gotcrc = GET_32BIT(st->pktin->data + st->biglen - 4);
|
st->gotcrc = GET_32BIT(st->data + st->biglen - 4);
|
||||||
if (st->gotcrc != st->realcrc) {
|
if (st->gotcrc != st->realcrc) {
|
||||||
bombout(("Incorrect CRC received on packet"));
|
bombout(("Incorrect CRC received on packet"));
|
||||||
ssh_unref_packet(st->pktin);
|
ssh_unref_packet(st->pktin);
|
||||||
@ -1562,33 +1564,36 @@ static void ssh1_rdpkt(Ssh ssh)
|
|||||||
unsigned char *decompblk;
|
unsigned char *decompblk;
|
||||||
int decomplen;
|
int decomplen;
|
||||||
if (!zlib_decompress_block(ssh->sc_comp_ctx,
|
if (!zlib_decompress_block(ssh->sc_comp_ctx,
|
||||||
st->pktin->data + st->pad,
|
st->data + st->pad, st->length + 1,
|
||||||
st->length + 1,
|
|
||||||
&decompblk, &decomplen)) {
|
&decompblk, &decomplen)) {
|
||||||
bombout(("Zlib decompression encountered invalid data"));
|
bombout(("Zlib decompression encountered invalid data"));
|
||||||
ssh_unref_packet(st->pktin);
|
ssh_unref_packet(st->pktin);
|
||||||
crStopV;
|
crStopV;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (st->pktin->maxlen < st->pad + decomplen) {
|
if (st->maxlen < st->pad + decomplen) {
|
||||||
st->pktin->maxlen = st->pad + decomplen;
|
PktIn *old_pktin = st->pktin;
|
||||||
st->pktin->data = sresize(st->pktin->data, st->pktin->maxlen,
|
|
||||||
unsigned char);
|
st->maxlen = st->pad + decomplen;
|
||||||
|
st->pktin = snew_plus(PktIn, st->maxlen);
|
||||||
|
*st->pktin = *old_pktin; /* structure copy */
|
||||||
|
st->data = snew_plus_get_aux(st->pktin);
|
||||||
|
|
||||||
|
smemclr(old_pktin, st->biglen);
|
||||||
|
sfree(old_pktin);
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(st->pktin->data + st->pad, decompblk, decomplen);
|
memcpy(st->data + st->pad, decompblk, decomplen);
|
||||||
sfree(decompblk);
|
sfree(decompblk);
|
||||||
st->length = decomplen - 1;
|
st->length = decomplen - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
st->pktin->type = st->pktin->data[st->pad];
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now we know the bounds of the semantic content of the
|
* Now we can find the bounds of the semantic content of the
|
||||||
* packet, excluding the initial type byte.
|
* packet, and the initial type byte.
|
||||||
*/
|
*/
|
||||||
BinarySource_INIT(st->pktin, st->pktin->data + st->pad + 1,
|
st->pktin->type = st->data[st->pad];
|
||||||
st->length);
|
BinarySource_INIT(st->pktin, st->data + st->pad + 1, st->length);
|
||||||
|
|
||||||
if (ssh->logctx)
|
if (ssh->logctx)
|
||||||
ssh1_log_incoming_packet(ssh, st->pktin);
|
ssh1_log_incoming_packet(ssh, st->pktin);
|
||||||
@ -1753,13 +1758,11 @@ static void ssh2_rdpkt(Ssh ssh)
|
|||||||
|
|
||||||
crBegin(ssh->ssh2_rdpkt_crstate);
|
crBegin(ssh->ssh2_rdpkt_crstate);
|
||||||
|
|
||||||
while (1) {
|
st->buf = NULL;
|
||||||
st->pktin = snew(PktIn);
|
st->bufsize = 0;
|
||||||
st->pktin->data = NULL;
|
|
||||||
st->pktin->maxlen = 0;
|
|
||||||
st->pktin->refcount = 1;
|
|
||||||
|
|
||||||
st->pktin->type = 0;
|
while (1) {
|
||||||
|
st->maxlen = 0;
|
||||||
st->length = 0;
|
st->length = 0;
|
||||||
if (ssh->sccipher)
|
if (ssh->sccipher)
|
||||||
st->cipherblk = ssh->sccipher->blksize;
|
st->cipherblk = ssh->sccipher->blksize;
|
||||||
@ -1789,14 +1792,18 @@ static void ssh2_rdpkt(Ssh ssh)
|
|||||||
* detecting it before we decrypt anything.
|
* detecting it before we decrypt anything.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* May as well allocate the whole lot now. */
|
/*
|
||||||
st->pktin->data = snewn(OUR_V2_PACKETLIMIT + st->maclen,
|
* Make sure we have buffer space for a maximum-size packet.
|
||||||
unsigned char);
|
*/
|
||||||
|
int buflimit = OUR_V2_PACKETLIMIT + st->maclen;
|
||||||
|
if (st->bufsize < buflimit) {
|
||||||
|
st->bufsize = buflimit;
|
||||||
|
st->buf = sresize(st->buf, st->bufsize, unsigned char);
|
||||||
|
}
|
||||||
|
|
||||||
/* Read an amount corresponding to the MAC. */
|
/* Read an amount corresponding to the MAC. */
|
||||||
crMaybeWaitUntilV(bufchain_try_fetch_consume(
|
crMaybeWaitUntilV(bufchain_try_fetch_consume(
|
||||||
&ssh->incoming_data,
|
&ssh->incoming_data, st->buf, st->maclen));
|
||||||
st->pktin->data, st->maclen));
|
|
||||||
|
|
||||||
st->packetlen = 0;
|
st->packetlen = 0;
|
||||||
ssh->scmac->start(ssh->sc_mac_ctx);
|
ssh->scmac->start(ssh->sc_mac_ctx);
|
||||||
@ -1807,51 +1814,59 @@ static void ssh2_rdpkt(Ssh ssh)
|
|||||||
/* Read another cipher-block's worth, and tack it onto the end. */
|
/* Read another cipher-block's worth, and tack it onto the end. */
|
||||||
crMaybeWaitUntilV(bufchain_try_fetch_consume(
|
crMaybeWaitUntilV(bufchain_try_fetch_consume(
|
||||||
&ssh->incoming_data,
|
&ssh->incoming_data,
|
||||||
st->pktin->data + (st->packetlen +
|
st->buf + (st->packetlen + st->maclen),
|
||||||
st->maclen),
|
|
||||||
st->cipherblk));
|
st->cipherblk));
|
||||||
/* Decrypt one more block (a little further back in the stream). */
|
/* Decrypt one more block (a little further back in the stream). */
|
||||||
ssh->sccipher->decrypt(ssh->sc_cipher_ctx,
|
ssh->sccipher->decrypt(ssh->sc_cipher_ctx,
|
||||||
st->pktin->data + st->packetlen,
|
st->buf + st->packetlen,
|
||||||
st->cipherblk);
|
st->cipherblk);
|
||||||
/* Feed that block to the MAC. */
|
/* Feed that block to the MAC. */
|
||||||
put_data(ssh->sc_mac_bs,
|
put_data(ssh->sc_mac_bs,
|
||||||
st->pktin->data + st->packetlen, st->cipherblk);
|
st->buf + st->packetlen, st->cipherblk);
|
||||||
st->packetlen += st->cipherblk;
|
st->packetlen += st->cipherblk;
|
||||||
/* See if that gives us a valid packet. */
|
/* See if that gives us a valid packet. */
|
||||||
if (ssh->scmac->verresult(ssh->sc_mac_ctx,
|
if (ssh->scmac->verresult(ssh->sc_mac_ctx,
|
||||||
st->pktin->data + st->packetlen) &&
|
st->buf + st->packetlen) &&
|
||||||
((st->len = toint(GET_32BIT(st->pktin->data))) ==
|
((st->len = toint(GET_32BIT(st->buf))) ==
|
||||||
st->packetlen-4))
|
st->packetlen-4))
|
||||||
break;
|
break;
|
||||||
if (st->packetlen >= OUR_V2_PACKETLIMIT) {
|
if (st->packetlen >= OUR_V2_PACKETLIMIT) {
|
||||||
bombout(("No valid incoming packet found"));
|
bombout(("No valid incoming packet found"));
|
||||||
ssh_unref_packet(st->pktin);
|
|
||||||
crStopV;
|
crStopV;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
st->pktin->maxlen = st->packetlen + st->maclen;
|
st->maxlen = st->packetlen + st->maclen;
|
||||||
st->pktin->data = sresize(st->pktin->data, st->pktin->maxlen,
|
|
||||||
unsigned char);
|
/*
|
||||||
|
* Now transfer the data into an output packet.
|
||||||
|
*/
|
||||||
|
st->pktin = snew_plus(PktIn, st->maxlen);
|
||||||
|
st->pktin->refcount = 1;
|
||||||
|
st->pktin->type = 0;
|
||||||
|
st->data = snew_plus_get_aux(st->pktin);
|
||||||
|
memcpy(st->data, st->buf, st->maxlen);
|
||||||
} else if (ssh->scmac && ssh->scmac_etm) {
|
} else if (ssh->scmac && ssh->scmac_etm) {
|
||||||
st->pktin->data = snewn(4, unsigned char);
|
if (st->bufsize < 4) {
|
||||||
|
st->bufsize = 4;
|
||||||
|
st->buf = sresize(st->buf, st->bufsize, unsigned char);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* OpenSSH encrypt-then-MAC mode: the packet length is
|
* OpenSSH encrypt-then-MAC mode: the packet length is
|
||||||
* unencrypted, unless the cipher supports length encryption.
|
* unencrypted, unless the cipher supports length encryption.
|
||||||
*/
|
*/
|
||||||
crMaybeWaitUntilV(bufchain_try_fetch_consume(
|
crMaybeWaitUntilV(bufchain_try_fetch_consume(
|
||||||
&ssh->incoming_data, st->pktin->data, 4));
|
&ssh->incoming_data, st->buf, 4));
|
||||||
|
|
||||||
/* Cipher supports length decryption, so do it */
|
/* Cipher supports length decryption, so do it */
|
||||||
if (ssh->sccipher && (ssh->sccipher->flags & SSH_CIPHER_SEPARATE_LENGTH)) {
|
if (ssh->sccipher && (ssh->sccipher->flags & SSH_CIPHER_SEPARATE_LENGTH)) {
|
||||||
/* Keep the packet the same though, so the MAC passes */
|
/* Keep the packet the same though, so the MAC passes */
|
||||||
unsigned char len[4];
|
unsigned char len[4];
|
||||||
memcpy(len, st->pktin->data, 4);
|
memcpy(len, st->buf, 4);
|
||||||
ssh->sccipher->decrypt_length(ssh->sc_cipher_ctx, len, 4, st->incoming_sequence);
|
ssh->sccipher->decrypt_length(ssh->sc_cipher_ctx, len, 4, st->incoming_sequence);
|
||||||
st->len = toint(GET_32BIT(len));
|
st->len = toint(GET_32BIT(len));
|
||||||
} else {
|
} else {
|
||||||
st->len = toint(GET_32BIT(st->pktin->data));
|
st->len = toint(GET_32BIT(st->buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1861,7 +1876,6 @@ static void ssh2_rdpkt(Ssh ssh)
|
|||||||
if (st->len < 0 || st->len > OUR_V2_PACKETLIMIT ||
|
if (st->len < 0 || st->len > OUR_V2_PACKETLIMIT ||
|
||||||
st->len % st->cipherblk != 0) {
|
st->len % st->cipherblk != 0) {
|
||||||
bombout(("Incoming packet length field was garbled"));
|
bombout(("Incoming packet length field was garbled"));
|
||||||
ssh_unref_packet(st->pktin);
|
|
||||||
crStopV;
|
crStopV;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1871,24 +1885,26 @@ static void ssh2_rdpkt(Ssh ssh)
|
|||||||
st->packetlen = st->len + 4;
|
st->packetlen = st->len + 4;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocate memory for the rest of the packet.
|
* Allocate the packet to return, now we know its length.
|
||||||
*/
|
*/
|
||||||
st->pktin->maxlen = st->packetlen + st->maclen;
|
st->pktin = snew_plus(PktIn, OUR_V2_PACKETLIMIT + st->maclen);
|
||||||
st->pktin->data = sresize(st->pktin->data, st->pktin->maxlen,
|
st->pktin->refcount = 1;
|
||||||
unsigned char);
|
st->pktin->type = 0;
|
||||||
|
st->data = snew_plus_get_aux(st->pktin);
|
||||||
|
memcpy(st->data, st->buf, 4);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read the remainder of the packet.
|
* Read the remainder of the packet.
|
||||||
*/
|
*/
|
||||||
crMaybeWaitUntilV(bufchain_try_fetch_consume(
|
crMaybeWaitUntilV(bufchain_try_fetch_consume(
|
||||||
&ssh->incoming_data, st->pktin->data + 4,
|
&ssh->incoming_data, st->data + 4,
|
||||||
st->packetlen + st->maclen - 4));
|
st->packetlen + st->maclen - 4));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check the MAC.
|
* Check the MAC.
|
||||||
*/
|
*/
|
||||||
if (ssh->scmac
|
if (ssh->scmac
|
||||||
&& !ssh->scmac->verify(ssh->sc_mac_ctx, st->pktin->data,
|
&& !ssh->scmac->verify(ssh->sc_mac_ctx, st->data,
|
||||||
st->len + 4, st->incoming_sequence)) {
|
st->len + 4, st->incoming_sequence)) {
|
||||||
bombout(("Incorrect MAC received on packet"));
|
bombout(("Incorrect MAC received on packet"));
|
||||||
ssh_unref_packet(st->pktin);
|
ssh_unref_packet(st->pktin);
|
||||||
@ -1898,10 +1914,12 @@ static void ssh2_rdpkt(Ssh ssh)
|
|||||||
/* Decrypt everything between the length field and the MAC. */
|
/* Decrypt everything between the length field and the MAC. */
|
||||||
if (ssh->sccipher)
|
if (ssh->sccipher)
|
||||||
ssh->sccipher->decrypt(ssh->sc_cipher_ctx,
|
ssh->sccipher->decrypt(ssh->sc_cipher_ctx,
|
||||||
st->pktin->data + 4,
|
st->data + 4, st->packetlen - 4);
|
||||||
st->packetlen - 4);
|
|
||||||
} else {
|
} else {
|
||||||
st->pktin->data = snewn(st->cipherblk, unsigned char);
|
if (st->bufsize < st->cipherblk) {
|
||||||
|
st->bufsize = st->cipherblk;
|
||||||
|
st->buf = sresize(st->buf, st->bufsize, unsigned char);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Acquire and decrypt the first block of the packet. This will
|
* Acquire and decrypt the first block of the packet. This will
|
||||||
@ -1909,16 +1927,16 @@ static void ssh2_rdpkt(Ssh ssh)
|
|||||||
*/
|
*/
|
||||||
crMaybeWaitUntilV(bufchain_try_fetch_consume(
|
crMaybeWaitUntilV(bufchain_try_fetch_consume(
|
||||||
&ssh->incoming_data,
|
&ssh->incoming_data,
|
||||||
st->pktin->data, st->cipherblk));
|
st->buf, st->cipherblk));
|
||||||
|
|
||||||
if (ssh->sccipher)
|
if (ssh->sccipher)
|
||||||
ssh->sccipher->decrypt(ssh->sc_cipher_ctx,
|
ssh->sccipher->decrypt(ssh->sc_cipher_ctx,
|
||||||
st->pktin->data, st->cipherblk);
|
st->buf, st->cipherblk);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now get the length figure.
|
* Now get the length figure.
|
||||||
*/
|
*/
|
||||||
st->len = toint(GET_32BIT(st->pktin->data));
|
st->len = toint(GET_32BIT(st->buf));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* _Completely_ silly lengths should be stomped on before they
|
* _Completely_ silly lengths should be stomped on before they
|
||||||
@ -1937,31 +1955,34 @@ static void ssh2_rdpkt(Ssh ssh)
|
|||||||
st->packetlen = st->len + 4;
|
st->packetlen = st->len + 4;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocate memory for the rest of the packet.
|
* Allocate the packet to return, now we know its length.
|
||||||
*/
|
*/
|
||||||
st->pktin->maxlen = st->packetlen + st->maclen;
|
st->maxlen = st->packetlen + st->maclen;
|
||||||
st->pktin->data = sresize(st->pktin->data, st->pktin->maxlen,
|
st->pktin = snew_plus(PktIn, st->maxlen);
|
||||||
unsigned char);
|
st->pktin->refcount = 1;
|
||||||
|
st->pktin->type = 0;
|
||||||
|
st->data = snew_plus_get_aux(st->pktin);
|
||||||
|
memcpy(st->data, st->buf, st->cipherblk);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read and decrypt the remainder of the packet.
|
* Read and decrypt the remainder of the packet.
|
||||||
*/
|
*/
|
||||||
crMaybeWaitUntilV(bufchain_try_fetch_consume(
|
crMaybeWaitUntilV(bufchain_try_fetch_consume(
|
||||||
&ssh->incoming_data,
|
&ssh->incoming_data,
|
||||||
st->pktin->data + st->cipherblk,
|
st->data + st->cipherblk,
|
||||||
st->packetlen + st->maclen - st->cipherblk));
|
st->packetlen + st->maclen - st->cipherblk));
|
||||||
|
|
||||||
/* Decrypt everything _except_ the MAC. */
|
/* Decrypt everything _except_ the MAC. */
|
||||||
if (ssh->sccipher)
|
if (ssh->sccipher)
|
||||||
ssh->sccipher->decrypt(ssh->sc_cipher_ctx,
|
ssh->sccipher->decrypt(ssh->sc_cipher_ctx,
|
||||||
st->pktin->data + st->cipherblk,
|
st->data + st->cipherblk,
|
||||||
st->packetlen - st->cipherblk);
|
st->packetlen - st->cipherblk);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check the MAC.
|
* Check the MAC.
|
||||||
*/
|
*/
|
||||||
if (ssh->scmac
|
if (ssh->scmac
|
||||||
&& !ssh->scmac->verify(ssh->sc_mac_ctx, st->pktin->data,
|
&& !ssh->scmac->verify(ssh->sc_mac_ctx, st->data,
|
||||||
st->len + 4, st->incoming_sequence)) {
|
st->len + 4, st->incoming_sequence)) {
|
||||||
bombout(("Incorrect MAC received on packet"));
|
bombout(("Incorrect MAC received on packet"));
|
||||||
ssh_unref_packet(st->pktin);
|
ssh_unref_packet(st->pktin);
|
||||||
@ -1969,7 +1990,7 @@ static void ssh2_rdpkt(Ssh ssh)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Get and sanity-check the amount of random padding. */
|
/* Get and sanity-check the amount of random padding. */
|
||||||
st->pad = st->pktin->data[4];
|
st->pad = st->data[4];
|
||||||
if (st->pad < 4 || st->len - st->pad < 1) {
|
if (st->pad < 4 || st->len - st->pad < 1) {
|
||||||
bombout(("Invalid padding length on received packet"));
|
bombout(("Invalid padding length on received packet"));
|
||||||
ssh_unref_packet(st->pktin);
|
ssh_unref_packet(st->pktin);
|
||||||
@ -1996,16 +2017,21 @@ static void ssh2_rdpkt(Ssh ssh)
|
|||||||
int newlen;
|
int newlen;
|
||||||
if (ssh->sccomp &&
|
if (ssh->sccomp &&
|
||||||
ssh->sccomp->decompress(ssh->sc_comp_ctx,
|
ssh->sccomp->decompress(ssh->sc_comp_ctx,
|
||||||
st->pktin->data + 5, st->length - 5,
|
st->data + 5, st->length - 5,
|
||||||
&newpayload, &newlen)) {
|
&newpayload, &newlen)) {
|
||||||
if (st->pktin->maxlen < newlen + 5) {
|
if (st->maxlen < newlen + 5) {
|
||||||
st->pktin->maxlen = newlen + 5;
|
PktIn *old_pktin = st->pktin;
|
||||||
st->pktin->data = sresize(st->pktin->data,
|
|
||||||
st->pktin->maxlen,
|
st->maxlen = newlen + 5;
|
||||||
unsigned char);
|
st->pktin = snew_plus(PktIn, st->maxlen);
|
||||||
|
*st->pktin = *old_pktin; /* structure copy */
|
||||||
|
st->data = snew_plus_get_aux(st->pktin);
|
||||||
|
|
||||||
|
smemclr(old_pktin, st->packetlen + st->maclen);
|
||||||
|
sfree(old_pktin);
|
||||||
}
|
}
|
||||||
st->length = 5 + newlen;
|
st->length = 5 + newlen;
|
||||||
memcpy(st->pktin->data + 5, newpayload, newlen);
|
memcpy(st->data + 5, newpayload, newlen);
|
||||||
sfree(newpayload);
|
sfree(newpayload);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2019,14 +2045,15 @@ static void ssh2_rdpkt(Ssh ssh)
|
|||||||
ssh2_msg_something_unimplemented(ssh, st->pktin);
|
ssh2_msg_something_unimplemented(ssh, st->pktin);
|
||||||
crStopV;
|
crStopV;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now we can identify the semantic content of the packet,
|
* Now we can identify the semantic content of the packet,
|
||||||
* and also the initial type byte.
|
* and also the initial type byte.
|
||||||
*/
|
*/
|
||||||
st->pktin->type = st->pktin->data[5];
|
st->pktin->type = st->data[5];
|
||||||
st->length -= 6;
|
st->length -= 6;
|
||||||
assert(st->length >= 0); /* one last double-check */
|
assert(st->length >= 0); /* one last double-check */
|
||||||
BinarySource_INIT(st->pktin, st->pktin->data + 6, st->length);
|
BinarySource_INIT(st->pktin, st->data + 6, st->length);
|
||||||
|
|
||||||
if (ssh->logctx)
|
if (ssh->logctx)
|
||||||
ssh2_log_incoming_packet(ssh, st->pktin);
|
ssh2_log_incoming_packet(ssh, st->pktin);
|
||||||
@ -2079,10 +2106,13 @@ static void ssh2_bare_connection_rdpkt(Ssh ssh)
|
|||||||
crStopV;
|
crStopV;
|
||||||
}
|
}
|
||||||
|
|
||||||
st->pktin = snew(PktIn);
|
/*
|
||||||
st->pktin->maxlen = 0;
|
* Allocate the packet to return, now we know its length.
|
||||||
|
*/
|
||||||
|
st->pktin = snew_plus(PktIn, st->packetlen);
|
||||||
|
st->maxlen = 0;
|
||||||
st->pktin->refcount = 1;
|
st->pktin->refcount = 1;
|
||||||
st->pktin->data = snewn(st->packetlen, unsigned char);
|
st->data = snew_plus_get_aux(st->pktin);
|
||||||
|
|
||||||
st->pktin->encrypted_len = st->packetlen;
|
st->pktin->encrypted_len = st->packetlen;
|
||||||
|
|
||||||
@ -2092,15 +2122,14 @@ static void ssh2_bare_connection_rdpkt(Ssh ssh)
|
|||||||
* Read the remainder of the packet.
|
* Read the remainder of the packet.
|
||||||
*/
|
*/
|
||||||
crMaybeWaitUntilV(bufchain_try_fetch_consume(
|
crMaybeWaitUntilV(bufchain_try_fetch_consume(
|
||||||
&ssh->incoming_data,
|
&ssh->incoming_data, st->data, st->packetlen));
|
||||||
st->pktin->data, st->packetlen));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* pktin->body and pktin->length should identify the semantic
|
* The data we just read is precisely the initial type byte
|
||||||
* content of the packet, excluding the initial type byte.
|
* followed by the packet payload.
|
||||||
*/
|
*/
|
||||||
st->pktin->type = st->pktin->data[0];
|
st->pktin->type = st->data[0];
|
||||||
BinarySource_INIT(st->pktin, st->pktin->data + 1, st->packetlen - 1);
|
BinarySource_INIT(st->pktin, st->data + 1, st->packetlen - 1);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Log incoming packet, possibly omitting sensitive fields.
|
* Log incoming packet, possibly omitting sensitive fields.
|
||||||
@ -12045,6 +12074,7 @@ static const char *ssh_init(void *frontend_handle, void **backend_handle,
|
|||||||
ssh->ssh1_rdpkt_crstate = 0;
|
ssh->ssh1_rdpkt_crstate = 0;
|
||||||
ssh->ssh2_rdpkt_crstate = 0;
|
ssh->ssh2_rdpkt_crstate = 0;
|
||||||
ssh->ssh2_bare_rdpkt_crstate = 0;
|
ssh->ssh2_bare_rdpkt_crstate = 0;
|
||||||
|
ssh->rdpkt2_state.buf = NULL;
|
||||||
ssh->do_ssh1_connection_crstate = 0;
|
ssh->do_ssh1_connection_crstate = 0;
|
||||||
ssh->do_ssh_init_state = NULL;
|
ssh->do_ssh_init_state = NULL;
|
||||||
ssh->do_ssh_connection_init_state = NULL;
|
ssh->do_ssh_connection_init_state = NULL;
|
||||||
@ -12205,6 +12235,11 @@ static void ssh_free(void *handle)
|
|||||||
dh_cleanup(ssh->kex_ctx);
|
dh_cleanup(ssh->kex_ctx);
|
||||||
sfree(ssh->savedhost);
|
sfree(ssh->savedhost);
|
||||||
|
|
||||||
|
if (ssh->rdpkt2_state.buf) {
|
||||||
|
smemclr(ssh->rdpkt2_state.buf, ssh->rdpkt2_state.bufsize);
|
||||||
|
sfree(ssh->rdpkt2_state.buf);
|
||||||
|
}
|
||||||
|
|
||||||
while (ssh->queuelen-- > 0)
|
while (ssh->queuelen-- > 0)
|
||||||
ssh_free_pktout(ssh->queue[ssh->queuelen]);
|
ssh_free_pktout(ssh->queue[ssh->queuelen]);
|
||||||
sfree(ssh->queue);
|
sfree(ssh->queue);
|
||||||
|
Loading…
Reference in New Issue
Block a user