tls: make input buffer grow as needed
As it turns out, it goes only up to "inbuf_size:4608" for kernel.org - fixed 18kb buffer was x4 larger than necessary. Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
9731ca7611
commit
3916139ac4
132
networking/tls.c
132
networking/tls.c
@ -181,6 +181,42 @@ enum {
|
||||
OUTBUF_PFX = 8 + AES_BLOCKSIZE, /* header + IV */
|
||||
OUTBUF_SFX = SHA256_OUTSIZE + AES_BLOCKSIZE, /* MAC + padding */
|
||||
MAX_OUTBUF = MAX_TLS_RECORD - OUTBUF_PFX - OUTBUF_SFX,
|
||||
|
||||
// RFC 5246
|
||||
// | 6.2.1. Fragmentation
|
||||
// | The record layer fragments information blocks into TLSPlaintext
|
||||
// | records carrying data in chunks of 2^14 bytes or less. Client
|
||||
// | message boundaries are not preserved in the record layer (i.e.,
|
||||
// | multiple client messages of the same ContentType MAY be coalesced
|
||||
// | into a single TLSPlaintext record, or a single message MAY be
|
||||
// | fragmented across several records)
|
||||
// |...
|
||||
// | length
|
||||
// | The length (in bytes) of the following TLSPlaintext.fragment.
|
||||
// | The length MUST NOT exceed 2^14.
|
||||
// |...
|
||||
// | 6.2.2. Record Compression and Decompression
|
||||
// |...
|
||||
// | Compression must be lossless and may not increase the content length
|
||||
// | by more than 1024 bytes. If the decompression function encounters a
|
||||
// | TLSCompressed.fragment that would decompress to a length in excess of
|
||||
// | 2^14 bytes, it MUST report a fatal decompression failure error.
|
||||
// |...
|
||||
// | length
|
||||
// | The length (in bytes) of the following TLSCompressed.fragment.
|
||||
// | The length MUST NOT exceed 2^14 + 1024.
|
||||
// |...
|
||||
// | 6.2.3. Record Payload Protection
|
||||
// | The encryption and MAC functions translate a TLSCompressed
|
||||
// | structure into a TLSCiphertext. The decryption functions reverse
|
||||
// | the process. The MAC of the record also includes a sequence
|
||||
// | number so that missing, extra, or repeated messages are
|
||||
// | detectable.
|
||||
// |...
|
||||
// | length
|
||||
// | The length (in bytes) of the following TLSCiphertext.fragment.
|
||||
// | The length MUST NOT exceed 2^14 + 2048.
|
||||
MAX_INBUF = (1 << 14) + 2048,
|
||||
};
|
||||
|
||||
struct record_hdr {
|
||||
@ -218,36 +254,10 @@ typedef struct tls_state {
|
||||
int outbuf_size;
|
||||
uint8_t *outbuf;
|
||||
|
||||
// RFC 5246
|
||||
// | 6.2.1. Fragmentation
|
||||
// | The record layer fragments information blocks into TLSPlaintext
|
||||
// | records carrying data in chunks of 2^14 bytes or less. Client
|
||||
// | message boundaries are not preserved in the record layer (i.e.,
|
||||
// | multiple client messages of the same ContentType MAY be coalesced
|
||||
// | into a single TLSPlaintext record, or a single message MAY be
|
||||
// | fragmented across several records)
|
||||
// |...
|
||||
// | length
|
||||
// | The length (in bytes) of the following TLSPlaintext.fragment.
|
||||
// | The length MUST NOT exceed 2^14.
|
||||
// |...
|
||||
// | 6.2.2. Record Compression and Decompression
|
||||
// |...
|
||||
// | Compression must be lossless and may not increase the content length
|
||||
// | by more than 1024 bytes. If the decompression function encounters a
|
||||
// | TLSCompressed.fragment that would decompress to a length in excess of
|
||||
// | 2^14 bytes, it MUST report a fatal decompression failure error.
|
||||
// |...
|
||||
// | length
|
||||
// | The length (in bytes) of the following TLSCompressed.fragment.
|
||||
// | The length MUST NOT exceed 2^14 + 1024.
|
||||
//
|
||||
// Since our buffer also contains 5-byte headers, make it a bit bigger:
|
||||
int insize;
|
||||
int tail;
|
||||
//needed?
|
||||
uint64_t align____;
|
||||
uint8_t inbuf[20*1024];
|
||||
int inbuf_size;
|
||||
int ofs_to_buffered;
|
||||
int buffered_size;
|
||||
uint8_t *inbuf;
|
||||
} tls_state_t;
|
||||
|
||||
|
||||
@ -483,10 +493,21 @@ static tls_state_t *new_tls_state(void)
|
||||
|
||||
static void tls_error_die(tls_state_t *tls)
|
||||
{
|
||||
dump_tls_record(tls->inbuf, tls->insize + tls->tail);
|
||||
dump_tls_record(tls->inbuf, tls->ofs_to_buffered + tls->buffered_size);
|
||||
bb_error_msg_and_die("TODO: useful diagnostic about %p", tls);
|
||||
}
|
||||
|
||||
#if 0 //UNUSED
|
||||
static void tls_free_inbuf(tls_state_t *tls)
|
||||
{
|
||||
if (tls->buffered_size == 0) {
|
||||
free(tls->inbuf);
|
||||
tls->inbuf_size = 0;
|
||||
tls->inbuf = NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void tls_free_outbuf(tls_state_t *tls)
|
||||
{
|
||||
free(tls->outbuf);
|
||||
@ -683,13 +704,13 @@ static void xwrite_and_update_handshake_hash(tls_state_t *tls, unsigned size)
|
||||
|
||||
static int tls_has_buffered_record(tls_state_t *tls)
|
||||
{
|
||||
int buffered = tls->tail;
|
||||
int buffered = tls->buffered_size;
|
||||
struct record_hdr *xhdr;
|
||||
int rec_size;
|
||||
|
||||
if (buffered < RECHDR_LEN)
|
||||
return 0;
|
||||
xhdr = (void*)(tls->inbuf + tls->insize);
|
||||
xhdr = (void*)(tls->inbuf + tls->ofs_to_buffered);
|
||||
rec_size = RECHDR_LEN + (0x100 * xhdr->len16_hi + xhdr->len16_lo);
|
||||
if (buffered < rec_size)
|
||||
return 0;
|
||||
@ -704,23 +725,25 @@ static int tls_xread_record(tls_state_t *tls)
|
||||
int target;
|
||||
|
||||
again:
|
||||
dbg("insize:%u tail:%u\n", tls->insize, tls->tail);
|
||||
total = tls->tail;
|
||||
dbg("ofs_to_buffered:%u buffered_size:%u\n", tls->ofs_to_buffered, tls->buffered_size);
|
||||
total = tls->buffered_size;
|
||||
if (total != 0) {
|
||||
memmove(tls->inbuf, tls->inbuf + tls->insize, total);
|
||||
//dbg("<< remaining at %d [%d] ", tls->insize, total);
|
||||
memmove(tls->inbuf, tls->inbuf + tls->ofs_to_buffered, total);
|
||||
//dbg("<< remaining at %d [%d] ", tls->ofs_to_buffered, total);
|
||||
//dump_raw_in("<< %s\n", tls->inbuf, total);
|
||||
}
|
||||
errno = 0;
|
||||
target = sizeof(tls->inbuf);
|
||||
target = MAX_INBUF;
|
||||
for (;;) {
|
||||
if (total >= RECHDR_LEN && target == sizeof(tls->inbuf)) {
|
||||
int rem;
|
||||
|
||||
if (total >= RECHDR_LEN && target == MAX_INBUF) {
|
||||
xhdr = (void*)tls->inbuf;
|
||||
target = RECHDR_LEN + (0x100 * xhdr->len16_hi + xhdr->len16_lo);
|
||||
if (target >= sizeof(tls->inbuf)) {
|
||||
if (target > MAX_INBUF) {
|
||||
/* malformed input (too long): yell and die */
|
||||
tls->tail = 0;
|
||||
tls->insize = total;
|
||||
tls->buffered_size = 0;
|
||||
tls->ofs_to_buffered = total;
|
||||
tls_error_die(tls);
|
||||
}
|
||||
/* can also check type/proto_maj/proto_min here */
|
||||
@ -732,12 +755,22 @@ static int tls_xread_record(tls_state_t *tls)
|
||||
/* if total >= target, we have a full packet (and possibly more)... */
|
||||
if (total - target >= 0)
|
||||
break;
|
||||
sz = safe_read(tls->fd, tls->inbuf + total, sizeof(tls->inbuf) - total);
|
||||
/* input buffer is grown only as needed */
|
||||
rem = tls->inbuf_size - total;
|
||||
if (rem == 0) {
|
||||
tls->inbuf_size += MAX_INBUF / 8;
|
||||
if (tls->inbuf_size > MAX_INBUF)
|
||||
tls->inbuf_size = MAX_INBUF;
|
||||
dbg("inbuf_size:%d\n", tls->inbuf_size);
|
||||
rem = tls->inbuf_size - total;
|
||||
tls->inbuf = xrealloc(tls->inbuf, tls->inbuf_size);
|
||||
}
|
||||
sz = safe_read(tls->fd, tls->inbuf + total, rem);
|
||||
if (sz <= 0) {
|
||||
if (sz == 0 && total == 0) {
|
||||
/* "Abrupt" EOF, no TLS shutdown (seen from kernel.org) */
|
||||
dbg("EOF (without TLS shutdown) from peer\n");
|
||||
tls->tail = 0;
|
||||
tls->buffered_size = 0;
|
||||
goto end;
|
||||
}
|
||||
bb_perror_msg_and_die("short read, have only %d", total);
|
||||
@ -745,10 +778,10 @@ static int tls_xread_record(tls_state_t *tls)
|
||||
dump_raw_in("<< %s\n", tls->inbuf + total, sz);
|
||||
total += sz;
|
||||
}
|
||||
tls->tail = total - target;
|
||||
tls->insize = target;
|
||||
//dbg("<< stashing at %d [%d] ", tls->insize, tls->tail);
|
||||
//dump_hex("<< %s\n", tls->inbuf + tls->insize, tls->tail);
|
||||
tls->buffered_size = total - target;
|
||||
tls->ofs_to_buffered = target;
|
||||
//dbg("<< stashing at %d [%d] ", tls->ofs_to_buffered, tls->buffered_size);
|
||||
//dump_hex("<< %s\n", tls->inbuf + tls->ofs_to_buffered, tls->buffered_size);
|
||||
|
||||
sz = target - RECHDR_LEN;
|
||||
|
||||
@ -1547,7 +1580,7 @@ int tls_main(int argc UNUSED_PARAM, char **argv)
|
||||
* doubt it's ok to do it "raw"
|
||||
*/
|
||||
FD_CLR(STDIN_FILENO, &readfds);
|
||||
tls_free_outbuf(tls);
|
||||
tls_free_outbuf(tls); /* mem usage optimization */
|
||||
} else {
|
||||
if (nread == inbuf_size) {
|
||||
/* TLS has per record overhead, if input comes fast,
|
||||
@ -1570,6 +1603,7 @@ int tls_main(int argc UNUSED_PARAM, char **argv)
|
||||
*/
|
||||
//FD_CLR(cfd, &readfds);
|
||||
//close(STDOUT_FILENO);
|
||||
//tls_free_inbuf(tls); /* mem usage optimization */
|
||||
//continue;
|
||||
break;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user