From f339e8eebf39d352e2d1fe4ae627bf6694ba5eab Mon Sep 17 00:00:00 2001 From: jmestwa-coder Date: Sun, 5 Apr 2026 19:42:05 +0530 Subject: [PATCH] prevent overflow in array and list allocation size calculations --- src/core/ngx_array.c | 82 +++++++++++++++++++++++++++++++++++--------- src/core/ngx_array.h | 21 +++++++++++- src/core/ngx_list.c | 13 +++++-- src/core/ngx_list.h | 21 +++++++++++- 4 files changed, 116 insertions(+), 21 deletions(-) diff --git a/src/core/ngx_array.c b/src/core/ngx_array.c index 4ea226f06..6b115ac28 100644 --- a/src/core/ngx_array.c +++ b/src/core/ngx_array.c @@ -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; } diff --git a/src/core/ngx_array.h b/src/core/ngx_array.h index a0f2a7440..db5cd58a9 100644 --- a/src/core/ngx_array.h +++ b/src/core/ngx_array.h @@ -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; } diff --git a/src/core/ngx_list.c b/src/core/ngx_list.c index d0eb15930..2462fcd04 100644 --- a/src/core/ngx_list.c +++ b/src/core/ngx_list.c @@ -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; diff --git a/src/core/ngx_list.h b/src/core/ngx_list.h index e0fe6436b..8287e6378 100644 --- a/src/core/ngx_list.h +++ b/src/core/ngx_list.h @@ -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; }