mirror of
https://github.com/nginx/nginx.git
synced 2026-05-13 09:36:42 +00:00
prevent overflow in array and list allocation size calculations
This commit is contained in:
parent
920dc099c1
commit
f339e8eebf
4 changed files with 116 additions and 21 deletions
|
|
@ -30,12 +30,15 @@ ngx_array_create(ngx_pool_t *p, ngx_uint_t n, size_t size)
|
|||
void
|
||||
ngx_array_destroy(ngx_array_t *a)
|
||||
{
|
||||
size_t size;
|
||||
ngx_pool_t *p;
|
||||
|
||||
p = a->pool;
|
||||
|
||||
if ((u_char *) a->elts + a->size * a->nalloc == p->d.last) {
|
||||
p->d.last -= a->size * a->nalloc;
|
||||
if (ngx_array_calc_size(a->nalloc, a->size, &size) == NGX_OK
|
||||
&& (u_char *) a->elts + size == p->d.last)
|
||||
{
|
||||
p->d.last -= size;
|
||||
}
|
||||
|
||||
if ((u_char *) a + sizeof(ngx_array_t) == p->d.last) {
|
||||
|
|
@ -48,19 +51,21 @@ void *
|
|||
ngx_array_push(ngx_array_t *a)
|
||||
{
|
||||
void *elt, *new;
|
||||
size_t size;
|
||||
size_t size, alloc;
|
||||
ngx_pool_t *p;
|
||||
|
||||
if (a->nelts == a->nalloc) {
|
||||
|
||||
/* the array is full */
|
||||
|
||||
size = a->size * a->nalloc;
|
||||
if (ngx_array_calc_size(a->nalloc, a->size, &size) != NGX_OK) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p = a->pool;
|
||||
|
||||
if ((u_char *) a->elts + size == p->d.last
|
||||
&& p->d.last + a->size <= p->d.end)
|
||||
&& a->size <= (size_t) (p->d.end - p->d.last))
|
||||
{
|
||||
/*
|
||||
* the array allocation is the last in the pool
|
||||
|
|
@ -73,7 +78,15 @@ ngx_array_push(ngx_array_t *a)
|
|||
} else {
|
||||
/* allocate a new array */
|
||||
|
||||
new = ngx_palloc(p, 2 * size);
|
||||
if (a->nalloc > (ngx_uint_t) -1 / 2) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ngx_array_calc_size(2, size, &alloc) != NGX_OK) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
new = ngx_palloc(p, alloc);
|
||||
if (new == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -84,7 +97,11 @@ ngx_array_push(ngx_array_t *a)
|
|||
}
|
||||
}
|
||||
|
||||
elt = (u_char *) a->elts + a->size * a->nelts;
|
||||
if (ngx_array_calc_size(a->nelts, a->size, &size) != NGX_OK) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
elt = (u_char *) a->elts + size;
|
||||
a->nelts++;
|
||||
|
||||
return elt;
|
||||
|
|
@ -95,20 +112,33 @@ void *
|
|||
ngx_array_push_n(ngx_array_t *a, ngx_uint_t n)
|
||||
{
|
||||
void *elt, *new;
|
||||
size_t size;
|
||||
size_t size, alloc;
|
||||
ngx_uint_t nelts;
|
||||
ngx_uint_t nalloc;
|
||||
ngx_pool_t *p;
|
||||
|
||||
size = n * a->size;
|
||||
if (ngx_array_calc_size(n, a->size, &size) != NGX_OK) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (a->nelts + n > a->nalloc) {
|
||||
nelts = a->nelts + n;
|
||||
|
||||
if (nelts < a->nelts) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (nelts > a->nalloc) {
|
||||
|
||||
/* the array is full */
|
||||
|
||||
p = a->pool;
|
||||
|
||||
if ((u_char *) a->elts + a->size * a->nalloc == p->d.last
|
||||
&& p->d.last + size <= p->d.end)
|
||||
if (ngx_array_calc_size(a->nalloc, a->size, &alloc) != NGX_OK) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((u_char *) a->elts + alloc == p->d.last
|
||||
&& size <= (size_t) (p->d.end - p->d.last))
|
||||
{
|
||||
/*
|
||||
* the array allocation is the last in the pool
|
||||
|
|
@ -121,21 +151,39 @@ ngx_array_push_n(ngx_array_t *a, ngx_uint_t n)
|
|||
} else {
|
||||
/* allocate a new array */
|
||||
|
||||
nalloc = 2 * ((n >= a->nalloc) ? n : a->nalloc);
|
||||
nalloc = (n >= a->nalloc) ? n : a->nalloc;
|
||||
|
||||
new = ngx_palloc(p, nalloc * a->size);
|
||||
if (nalloc > (ngx_uint_t) -1 / 2) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
nalloc *= 2;
|
||||
|
||||
if (ngx_array_calc_size(nalloc, a->size, &alloc) != NGX_OK) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
new = ngx_palloc(p, alloc);
|
||||
if (new == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ngx_memcpy(new, a->elts, a->nelts * a->size);
|
||||
if (ngx_array_calc_size(a->nelts, a->size, &alloc) != NGX_OK) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ngx_memcpy(new, a->elts, alloc);
|
||||
a->elts = new;
|
||||
a->nalloc = nalloc;
|
||||
}
|
||||
}
|
||||
|
||||
elt = (u_char *) a->elts + a->size * a->nelts;
|
||||
a->nelts += n;
|
||||
if (ngx_array_calc_size(a->nelts, a->size, &size) != NGX_OK) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
elt = (u_char *) a->elts + size;
|
||||
a->nelts = nelts;
|
||||
|
||||
return elt;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,9 +28,24 @@ void *ngx_array_push(ngx_array_t *a);
|
|||
void *ngx_array_push_n(ngx_array_t *a, ngx_uint_t n);
|
||||
|
||||
|
||||
static ngx_inline ngx_int_t
|
||||
ngx_array_calc_size(ngx_uint_t n, size_t size, size_t *total)
|
||||
{
|
||||
if (size && n > NGX_MAX_SIZE_T_VALUE / size) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
*total = (size_t) n * size;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_inline ngx_int_t
|
||||
ngx_array_init(ngx_array_t *array, ngx_pool_t *pool, ngx_uint_t n, size_t size)
|
||||
{
|
||||
size_t alloc;
|
||||
|
||||
/*
|
||||
* set "array->nelts" before "array->elts", otherwise MSVC thinks
|
||||
* that "array->nelts" may be used without having been initialized
|
||||
|
|
@ -41,7 +56,11 @@ ngx_array_init(ngx_array_t *array, ngx_pool_t *pool, ngx_uint_t n, size_t size)
|
|||
array->nalloc = n;
|
||||
array->pool = pool;
|
||||
|
||||
array->elts = ngx_palloc(pool, n * size);
|
||||
if (ngx_array_calc_size(n, size, &alloc) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
array->elts = ngx_palloc(pool, alloc);
|
||||
if (array->elts == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ void *
|
|||
ngx_list_push(ngx_list_t *l)
|
||||
{
|
||||
void *elt;
|
||||
size_t size;
|
||||
ngx_list_part_t *last;
|
||||
|
||||
last = l->last;
|
||||
|
|
@ -44,7 +45,11 @@ ngx_list_push(ngx_list_t *l)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
last->elts = ngx_palloc(l->pool, l->nalloc * l->size);
|
||||
if (ngx_list_calc_size(l->nalloc, l->size, &size) != NGX_OK) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
last->elts = ngx_palloc(l->pool, size);
|
||||
if (last->elts == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -56,7 +61,11 @@ ngx_list_push(ngx_list_t *l)
|
|||
l->last = last;
|
||||
}
|
||||
|
||||
elt = (char *) last->elts + l->size * last->nelts;
|
||||
if (ngx_list_calc_size(last->nelts, l->size, &size) != NGX_OK) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
elt = (char *) last->elts + size;
|
||||
last->nelts++;
|
||||
|
||||
return elt;
|
||||
|
|
|
|||
|
|
@ -33,10 +33,29 @@ typedef struct {
|
|||
|
||||
ngx_list_t *ngx_list_create(ngx_pool_t *pool, ngx_uint_t n, size_t size);
|
||||
|
||||
|
||||
static ngx_inline ngx_int_t
|
||||
ngx_list_calc_size(ngx_uint_t n, size_t size, size_t *total)
|
||||
{
|
||||
if (size && n > NGX_MAX_SIZE_T_VALUE / size) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
*total = (size_t) n * size;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
static ngx_inline ngx_int_t
|
||||
ngx_list_init(ngx_list_t *list, ngx_pool_t *pool, ngx_uint_t n, size_t size)
|
||||
{
|
||||
list->part.elts = ngx_palloc(pool, n * size);
|
||||
size_t alloc;
|
||||
|
||||
if (ngx_list_calc_size(n, size, &alloc) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
list->part.elts = ngx_palloc(pool, alloc);
|
||||
if (list->part.elts == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue