postgres.git / summary / log / commit / refs

commit    aff71f87ba78e8fe5fb266ecfce692f2e23a5d6a
Author:   Tom Lane <tgl@sss.pgh.pa.us>
Commit:   Noah Misch <noah@leadboat.com>
Date:     Mon May 11 12:13:49 2026 +0000
First released in: 14.23, 15.18, 16.14, 17.10, 18.4

    Fix assorted places that need to use palloc_array().
    
    multirange_recv and BlockRefTableReaderNextRelation were incautious
    about multiplying a possibly-large integer by a factor more than 1
    and then using it as an allocation size.  This is harmless on 64-bit
    systems where we'd compute a size exceeding MaxAllocSize and then
    fail, but on 32-bit systems we could overflow size_t leading to an
    undersized allocation and buffer overrun.
    
    Fix these places by using palloc_array() instead of a handwritten
    multiplication.  (In HEAD, some of them were fixed already, but
    none of that work got back-patched at the time.)
    
    In addition, BlockRefTableReaderNextRelation passes the same value
    to BlockRefTableRead's "int length" parameter.  If built for
    64-bit frontend code, palloc_array() allows a larger array size
    than it otherwise would, potentially allowing that parameter to
    overflow.  Add an explicit check to forestall that and keep the
    behavior the same cross-platform.
    
    Reported-by: Xint Code
    Author: Tom Lane <tgl@sss.pgh.pa.us>
    Backpatch-through: 14
    Security: CVE-2026-6473


src/backend/utils/adt/multirangetypes.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/backend/utils/adt/multirangetypes.c b/src/backend/utils/adt/multirangetypes.c index 4c035911e92..5f98d856422 100644 --- a/src/backend/utils/adt/multirangetypes.c +++ b/src/backend/utils/adt/multirangetypes.c @@ -341,7 +341,7 @@ multirange_recv(PG_FUNCTION_ARGS) Oid mltrngtypoid = PG_GETARG_OID(1); int32 typmod = PG_GETARG_INT32(2); MultirangeIOData *cache; - uint32 range_count; + int32 range_count; RangeType **ranges; MultirangeType *ret; StringInfoData tmpbuf; @@ -349,7 +349,8 @@ multirange_recv(PG_FUNCTION_ARGS) cache = get_multirange_io_data(fcinfo, mltrngtypoid, IOFunc_receive); range_count = pq_getmsgint(buf, 4); - ranges = palloc(range_count * sizeof(RangeType *)); + /* palloc_array will enforce a more-or-less-sane range_count value */ + ranges = palloc_array(RangeType *, range_count); initStringInfo(&tmpbuf); for (int i = 0; i < range_count; i++) @@ -836,7 +837,7 @@ multirange_deserialize(TypeCacheEntry *rangetyp, { int i; - *ranges = palloc(*range_count * sizeof(RangeType *)); + *ranges = palloc_array(RangeType *, *range_count); for (i = 0; i < *range_count; i++) (*ranges)[i] = multirange_get_range(rangetyp, multirange, i); } @@ -1000,7 +1001,7 @@ multirange_constructor2(PG_FUNCTION_ARGS) deconstruct_array(rangeArray, rngtypid, rangetyp->typlen, rangetyp->typbyval, rangetyp->typalign, &elements, &nulls, &range_count); - ranges = palloc0(range_count * sizeof(RangeType *)); + ranges = palloc_array(RangeType *, range_count); for (i = 0; i < range_count; i++) { if (nulls[i]) [parent: f20b840813f5]