Various bug fixes and tweaks to WPACKET implementation

Also added the WPACKET_cleanup() function to cleanup a WPACKET if we hit
an error.

Reviewed-by: Rich Salz <rsalz@openssl.org>
This commit is contained in:
Matt Caswell 2016-09-08 09:58:29 +01:00
parent fb790f1673
commit 871bc59bc1
2 changed files with 73 additions and 18 deletions

View file

@ -9,6 +9,8 @@
#include "packet_locl.h" #include "packet_locl.h"
#define DEFAULT_BUF_SIZE 256
/* /*
* Allocate bytes in the WPACKET for the output. This reserves the bytes * Allocate bytes in the WPACKET for the output. This reserves the bytes
* and count them as "written", but doesn't actually do the writing. * and count them as "written", but doesn't actually do the writing.
@ -21,18 +23,29 @@ int WPACKET_allocate_bytes(WPACKET *pkt, size_t len, unsigned char **allocbytes)
if (SIZE_MAX - pkt->written < len) if (SIZE_MAX - pkt->written < len)
return 0; return 0;
if (pkt->maxsize > 0 && pkt->written + len > pkt->maxsize) if (pkt->written + len > pkt->maxsize)
return 0; return 0;
if (pkt->buf->length - pkt->written < len) { if (pkt->buf->length - pkt->written < len) {
size_t newlen; size_t newlen;
if (pkt->buf->length > SIZE_MAX / 2) if (pkt->buf->length > SIZE_MAX / 2) {
newlen = SIZE_MAX; newlen = SIZE_MAX;
else } else {
newlen = pkt->buf->length * 2; if (pkt->buf->length == 0)
newlen = DEFAULT_BUF_SIZE;
else
newlen = pkt->buf->length * 2;
}
if (BUF_MEM_grow(pkt->buf, newlen) == 0) if (BUF_MEM_grow(pkt->buf, newlen) == 0)
return 0; return 0;
if (pkt->curr == NULL) {
/*
* Can happen if initialised with a BUF_MEM that hasn't been
* pre-allocated.
*/
pkt->curr = (unsigned char *)pkt->buf->data;
}
} }
pkt->written += len; pkt->written += len;
*allocbytes = pkt->curr; *allocbytes = pkt->curr;
@ -41,6 +54,14 @@ int WPACKET_allocate_bytes(WPACKET *pkt, size_t len, unsigned char **allocbytes)
return 1; return 1;
} }
static size_t maxmaxsize(size_t lenbytes)
{
if (lenbytes >= sizeof(size_t) || lenbytes == 0)
return SIZE_MAX;
else
return ((size_t)1 << (lenbytes * 8)) - 1 + lenbytes;
}
/* /*
* Initialise a WPACKET with the buffer in |buf|. The buffer must exist * Initialise a WPACKET with the buffer in |buf|. The buffer must exist
* for the whole time that the WPACKET is being used. Additionally |lenbytes| of * for the whole time that the WPACKET is being used. Additionally |lenbytes| of
@ -56,7 +77,7 @@ int WPACKET_init_len(WPACKET *pkt, BUF_MEM *buf, size_t lenbytes)
pkt->buf = buf; pkt->buf = buf;
pkt->curr = (unsigned char *)buf->data; pkt->curr = (unsigned char *)buf->data;
pkt->written = 0; pkt->written = 0;
pkt->maxsize = 0; pkt->maxsize = maxmaxsize(lenbytes);
pkt->subs = OPENSSL_zalloc(sizeof(*pkt->subs)); pkt->subs = OPENSSL_zalloc(sizeof(*pkt->subs));
if (pkt->subs == NULL) if (pkt->subs == NULL)
@ -97,13 +118,19 @@ int WPACKET_init(WPACKET *pkt, BUF_MEM *buf)
int WPACKET_set_packet_len(WPACKET *pkt, unsigned char *packet_len, int WPACKET_set_packet_len(WPACKET *pkt, unsigned char *packet_len,
size_t lenbytes) size_t lenbytes)
{ {
size_t maxmax;
/* We only allow this to be set once */ /* We only allow this to be set once */
if (pkt->subs == NULL) if (pkt->subs == NULL || pkt->subs->lenbytes != 0)
return 0; return 0;
pkt->subs->lenbytes = lenbytes; pkt->subs->lenbytes = lenbytes;
pkt->subs->packet_len = packet_len; pkt->subs->packet_len = packet_len;
maxmax = maxmaxsize(lenbytes);
if (pkt->maxsize > maxmax)
pkt->maxsize = maxmax;
return 1; return 1;
} }
@ -196,9 +223,10 @@ int WPACKET_finish(WPACKET *pkt)
ret = wpacket_intern_close(pkt); ret = wpacket_intern_close(pkt);
/* We free up memory no matter whether |ret| is zero or not */ if (ret) {
OPENSSL_free(pkt->subs); OPENSSL_free(pkt->subs);
pkt->subs = NULL; pkt->subs = NULL;
}
return ret; return ret;
} }
@ -271,12 +299,25 @@ int WPACKET_put_bytes(WPACKET *pkt, unsigned int val, size_t bytes)
return 1; return 1;
} }
/* /* Set a maximum size that we will not allow the WPACKET to grow beyond */
* Set a maximum size that we will not allow the WPACKET to grow beyond. If not
* set then there is no maximum.
*/
int WPACKET_set_max_size(WPACKET *pkt, size_t maxsize) int WPACKET_set_max_size(WPACKET *pkt, size_t maxsize)
{ {
WPACKET_SUB *sub;
size_t lenbytes;
if (pkt->subs == NULL)
return 0;
/* Find the WPACKET_SUB for the top level */
for (sub = pkt->subs; sub->parent != NULL; sub = sub->parent);
lenbytes = sub->lenbytes;
if (lenbytes == 0)
lenbytes = sizeof(pkt->maxsize);
if (maxmaxsize(lenbytes) < maxsize || maxsize < pkt->written)
return 0;
pkt->maxsize = maxsize; pkt->maxsize = maxsize;
return 1; return 1;
@ -315,12 +356,12 @@ int WPACKET_sub_memcpy(WPACKET *pkt, const void *src, size_t len, size_t lenbyte
} }
/* /*
* Return the total number of bytes written so far to the underlying buffer. * Return the total number of bytes written so far to the underlying buffer
* This might includes bytes written by a parent WPACKET. * including any storage allocated for length bytes
*/ */
int WPACKET_get_total_written(WPACKET *pkt, size_t *written) int WPACKET_get_total_written(WPACKET *pkt, size_t *written)
{ {
if (pkt->subs == NULL || written == NULL) if (written == NULL)
return 0; return 0;
*written = pkt->written; *written = pkt->written;
@ -341,3 +382,17 @@ int WPACKET_get_length(WPACKET *pkt, size_t *len)
return 1; return 1;
} }
/*
* Release resources in a WPACKET if a failure has occurred.
*/
void WPACKET_cleanup(WPACKET *pkt)
{
WPACKET_SUB *sub, *parent;
for (sub = pkt->subs; sub != NULL; sub = parent) {
parent = sub->parent;
OPENSSL_free(sub);
}
pkt->subs = NULL;
}

View file

@ -584,8 +584,7 @@ struct wpacket_st {
size_t written; size_t written;
/* /*
* Maximum number of bytes we will allow to be written to this WPACKET. Zero * Maximum number of bytes we will allow to be written to this WPACKET.
* if no maximum
*/ */
size_t maxsize; size_t maxsize;
@ -621,6 +620,7 @@ int WPACKET_sub_memcpy(WPACKET *pkt, const void *src, size_t len,
size_t lenbytes); size_t lenbytes);
int WPACKET_get_total_written(WPACKET *pkt, size_t *written); int WPACKET_get_total_written(WPACKET *pkt, size_t *written);
int WPACKET_get_length(WPACKET *pkt, size_t *len); int WPACKET_get_length(WPACKET *pkt, size_t *len);
void WPACKET_cleanup(WPACKET *pkt);
# ifdef __cplusplus # ifdef __cplusplus
} }