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_PFX = 8 + AES_BLOCKSIZE, /* header + IV */
|
||||||
OUTBUF_SFX = SHA256_OUTSIZE + AES_BLOCKSIZE, /* MAC + padding */
|
OUTBUF_SFX = SHA256_OUTSIZE + AES_BLOCKSIZE, /* MAC + padding */
|
||||||
MAX_OUTBUF = MAX_TLS_RECORD - OUTBUF_PFX - OUTBUF_SFX,
|
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 {
|
struct record_hdr {
|
||||||
@ -218,36 +254,10 @@ typedef struct tls_state {
|
|||||||
int outbuf_size;
|
int outbuf_size;
|
||||||
uint8_t *outbuf;
|
uint8_t *outbuf;
|
||||||
|
|
||||||
// RFC 5246
|
int inbuf_size;
|
||||||
// | 6.2.1. Fragmentation
|
int ofs_to_buffered;
|
||||||
// | The record layer fragments information blocks into TLSPlaintext
|
int buffered_size;
|
||||||
// | records carrying data in chunks of 2^14 bytes or less. Client
|
uint8_t *inbuf;
|
||||||
// | 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];
|
|
||||||
} tls_state_t;
|
} tls_state_t;
|
||||||
|
|
||||||
|
|
||||||
@ -483,10 +493,21 @@ static tls_state_t *new_tls_state(void)
|
|||||||
|
|
||||||
static void tls_error_die(tls_state_t *tls)
|
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);
|
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)
|
static void tls_free_outbuf(tls_state_t *tls)
|
||||||
{
|
{
|
||||||
free(tls->outbuf);
|
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)
|
static int tls_has_buffered_record(tls_state_t *tls)
|
||||||
{
|
{
|
||||||
int buffered = tls->tail;
|
int buffered = tls->buffered_size;
|
||||||
struct record_hdr *xhdr;
|
struct record_hdr *xhdr;
|
||||||
int rec_size;
|
int rec_size;
|
||||||
|
|
||||||
if (buffered < RECHDR_LEN)
|
if (buffered < RECHDR_LEN)
|
||||||
return 0;
|
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);
|
rec_size = RECHDR_LEN + (0x100 * xhdr->len16_hi + xhdr->len16_lo);
|
||||||
if (buffered < rec_size)
|
if (buffered < rec_size)
|
||||||
return 0;
|
return 0;
|
||||||
@ -704,23 +725,25 @@ static int tls_xread_record(tls_state_t *tls)
|
|||||||
int target;
|
int target;
|
||||||
|
|
||||||
again:
|
again:
|
||||||
dbg("insize:%u tail:%u\n", tls->insize, tls->tail);
|
dbg("ofs_to_buffered:%u buffered_size:%u\n", tls->ofs_to_buffered, tls->buffered_size);
|
||||||
total = tls->tail;
|
total = tls->buffered_size;
|
||||||
if (total != 0) {
|
if (total != 0) {
|
||||||
memmove(tls->inbuf, tls->inbuf + tls->insize, total);
|
memmove(tls->inbuf, tls->inbuf + tls->ofs_to_buffered, total);
|
||||||
//dbg("<< remaining at %d [%d] ", tls->insize, total);
|
//dbg("<< remaining at %d [%d] ", tls->ofs_to_buffered, total);
|
||||||
//dump_raw_in("<< %s\n", tls->inbuf, total);
|
//dump_raw_in("<< %s\n", tls->inbuf, total);
|
||||||
}
|
}
|
||||||
errno = 0;
|
errno = 0;
|
||||||
target = sizeof(tls->inbuf);
|
target = MAX_INBUF;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (total >= RECHDR_LEN && target == sizeof(tls->inbuf)) {
|
int rem;
|
||||||
|
|
||||||
|
if (total >= RECHDR_LEN && target == MAX_INBUF) {
|
||||||
xhdr = (void*)tls->inbuf;
|
xhdr = (void*)tls->inbuf;
|
||||||
target = RECHDR_LEN + (0x100 * xhdr->len16_hi + xhdr->len16_lo);
|
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 */
|
/* malformed input (too long): yell and die */
|
||||||
tls->tail = 0;
|
tls->buffered_size = 0;
|
||||||
tls->insize = total;
|
tls->ofs_to_buffered = total;
|
||||||
tls_error_die(tls);
|
tls_error_die(tls);
|
||||||
}
|
}
|
||||||
/* can also check type/proto_maj/proto_min here */
|
/* 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, we have a full packet (and possibly more)... */
|
||||||
if (total - target >= 0)
|
if (total - target >= 0)
|
||||||
break;
|
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) {
|
||||||
if (sz == 0 && total == 0) {
|
if (sz == 0 && total == 0) {
|
||||||
/* "Abrupt" EOF, no TLS shutdown (seen from kernel.org) */
|
/* "Abrupt" EOF, no TLS shutdown (seen from kernel.org) */
|
||||||
dbg("EOF (without TLS shutdown) from peer\n");
|
dbg("EOF (without TLS shutdown) from peer\n");
|
||||||
tls->tail = 0;
|
tls->buffered_size = 0;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
bb_perror_msg_and_die("short read, have only %d", total);
|
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);
|
dump_raw_in("<< %s\n", tls->inbuf + total, sz);
|
||||||
total += sz;
|
total += sz;
|
||||||
}
|
}
|
||||||
tls->tail = total - target;
|
tls->buffered_size = total - target;
|
||||||
tls->insize = target;
|
tls->ofs_to_buffered = target;
|
||||||
//dbg("<< stashing at %d [%d] ", tls->insize, tls->tail);
|
//dbg("<< stashing at %d [%d] ", tls->ofs_to_buffered, tls->buffered_size);
|
||||||
//dump_hex("<< %s\n", tls->inbuf + tls->insize, tls->tail);
|
//dump_hex("<< %s\n", tls->inbuf + tls->ofs_to_buffered, tls->buffered_size);
|
||||||
|
|
||||||
sz = target - RECHDR_LEN;
|
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"
|
* doubt it's ok to do it "raw"
|
||||||
*/
|
*/
|
||||||
FD_CLR(STDIN_FILENO, &readfds);
|
FD_CLR(STDIN_FILENO, &readfds);
|
||||||
tls_free_outbuf(tls);
|
tls_free_outbuf(tls); /* mem usage optimization */
|
||||||
} else {
|
} else {
|
||||||
if (nread == inbuf_size) {
|
if (nread == inbuf_size) {
|
||||||
/* TLS has per record overhead, if input comes fast,
|
/* 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);
|
//FD_CLR(cfd, &readfds);
|
||||||
//close(STDOUT_FILENO);
|
//close(STDOUT_FILENO);
|
||||||
|
//tls_free_inbuf(tls); /* mem usage optimization */
|
||||||
//continue;
|
//continue;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user