This is an automated email from the ASF dual-hosted git repository.

my-ship-it pushed a commit to branch REL_2_STABLE
in repository https://gitbox.apache.org/repos/asf/cloudberry.git

commit 9d83dc1d7fb9487e2134b3e4192ef18f5ea505b7
Author: Tom Lane <[email protected]>
AuthorDate: Mon May 11 05:13:49 2026 -0700

    Make palloc_array() and friends safe against integer overflow.
    
    Sufficiently large "count" arguments could result in undetected
    overflow, causing the allocated memory chunk to be much smaller
    than what the caller will subsequently write into it.  This is
    unlikely to be a hazard with 64-bit size_t but can sometimes
    happen on 32-bit builds, primarily where a function allocates
    workspace that's significantly larger than its input data.
    Rather than trying to patch the at-risk callers piecemeal,
    let's just redefine these macros so that they always check.
    
    To do that, move the longstanding add_size() and mul_size() functions
    into palloc.h and mcxt.c, and adjust them to not be specific to
    shared-memory allocation.  Then invent palloc_mul(), palloc0_mul(),
    palloc_mul_extended() to use these functions.  Actually, the latter
    use inlined copies to save one function call.  repalloc_array() gets
    similar treatment.  I didn't bother trying to inline the calls for
    repalloc0_array() though.
    
    In v14 and v15, this also adds repalloc_extended(), which previously
    was only available in v16 and up.
    
    We need copies of all this in fe_memutils.[hc] as well, since that
    module also provides palloc_array() etc.
    
    Reported-by: Xint Code
    Author: Tom Lane <[email protected]>
    Reviewed-by: Masahiko Sawada <[email protected]>
    Backpatch-through: 14
    Security: CVE-2026-6473
---
 src/backend/utils/mmgr/mcxt.c    | 126 +++++++++++++++++++++++++++++++++++++++
 src/include/common/fe_memutils.h |  11 +++-
 src/include/utils/palloc.h       |   1 +
 3 files changed, 137 insertions(+), 1 deletion(-)

diff --git a/src/backend/utils/mmgr/mcxt.c b/src/backend/utils/mmgr/mcxt.c
index 9a13e46c7dd..202d12ae607 100644
--- a/src/backend/utils/mmgr/mcxt.c
+++ b/src/backend/utils/mmgr/mcxt.c
@@ -1615,6 +1615,132 @@ repalloc_mul_extended(void *p, Size s1, Size s2, int 
flags)
        return repalloc_extended(p, req, flags);
 }
 
+/*
+ * Support for safe calculation of memory request sizes
+ *
+ * These functions perform the requested calculation, but throw error if the
+ * result overflows.
+ *
+ * An important property of these functions is that if an argument was a
+ * negative signed int before promotion (implying overflow in calculating it)
+ * we will detect that as an error.  That happens because we reject results
+ * larger than SIZE_MAX / 2 later on, in the actual allocation step.
+ */
+Size
+add_size(Size s1, Size s2)
+{
+       Size            result;
+
+       if (unlikely(pg_add_size_overflow(s1, s2, &result)))
+               add_size_error(s1, s2);
+       return result;
+}
+
+static pg_noinline void
+add_size_error(Size s1, Size s2)
+{
+       ereport(ERROR,
+                       (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+                        errmsg("invalid memory allocation request size %zu + 
%zu",
+                                       s1, s2)));
+}
+
+Size
+mul_size(Size s1, Size s2)
+{
+       Size            result;
+
+       if (unlikely(pg_mul_size_overflow(s1, s2, &result)))
+               mul_size_error(s1, s2);
+       return result;
+}
+
+static pg_noinline void
+mul_size_error(Size s1, Size s2)
+{
+       ereport(ERROR,
+                       (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+                        errmsg("invalid memory allocation request size %zu * 
%zu",
+                                       s1, s2)));
+}
+
+/*
+ * palloc_mul
+ *             Equivalent to palloc(mul_size(s1, s2)).
+ */
+void *
+palloc_mul(Size s1, Size s2)
+{
+       /* inline mul_size() for efficiency */
+       Size            req;
+
+       if (unlikely(pg_mul_size_overflow(s1, s2, &req)))
+               mul_size_error(s1, s2);
+       return palloc(req);
+}
+
+/*
+ * palloc0_mul
+ *             Equivalent to palloc0(mul_size(s1, s2)).
+ *
+ * This is comparable to standard calloc's behavior.
+ */
+void *
+palloc0_mul(Size s1, Size s2)
+{
+       /* inline mul_size() for efficiency */
+       Size            req;
+
+       if (unlikely(pg_mul_size_overflow(s1, s2, &req)))
+               mul_size_error(s1, s2);
+       return palloc0(req);
+}
+
+/*
+ * palloc_mul_extended
+ *             Equivalent to palloc_extended(mul_size(s1, s2), flags).
+ */
+void *
+palloc_mul_extended(Size s1, Size s2, int flags)
+{
+       /* inline mul_size() for efficiency */
+       Size            req;
+
+       if (unlikely(pg_mul_size_overflow(s1, s2, &req)))
+               mul_size_error(s1, s2);
+       return palloc_extended(req, flags);
+}
+
+/*
+ * repalloc_mul
+ *             Equivalent to repalloc(p, mul_size(s1, s2)).
+ */
+void *
+repalloc_mul(void *p, Size s1, Size s2)
+{
+       /* inline mul_size() for efficiency */
+       Size            req;
+
+       if (unlikely(pg_mul_size_overflow(s1, s2, &req)))
+               mul_size_error(s1, s2);
+       return repalloc(p, req);
+}
+
+/*
+ * repalloc_mul_extended
+ *             Equivalent to repalloc_extended(p, mul_size(s1, s2), flags).
+ */
+void *
+repalloc_mul_extended(void *p, Size s1, Size s2, int flags)
+{
+       /* inline mul_size() for efficiency */
+       Size            req;
+
+       if (unlikely(pg_mul_size_overflow(s1, s2, &req)))
+               mul_size_error(s1, s2);
+       return repalloc_extended(p, req, flags);
+}
+
 /*
  * MemoryContextAllocHuge
  *             Allocate (possibly-expansive) space within the specified 
context.
diff --git a/src/include/common/fe_memutils.h b/src/include/common/fe_memutils.h
index 34863ca54b0..c906f564d5c 100644
--- a/src/include/common/fe_memutils.h
+++ b/src/include/common/fe_memutils.h
@@ -51,6 +51,16 @@ extern void *pg_malloc0_mul(Size s1, Size s2);
 extern void *pg_malloc_mul_extended(Size s1, Size s2, int flags);
 extern void *pg_realloc_mul(void *p, Size s1, Size s2);
 
+/*
+ * Support for safe calculation of memory request sizes
+ */
+extern Size add_size(Size s1, Size s2);
+extern Size mul_size(Size s1, Size s2);
+extern void *pg_malloc_mul(Size s1, Size s2);
+extern void *pg_malloc0_mul(Size s1, Size s2);
+extern void *pg_malloc_mul_extended(Size s1, Size s2, int flags);
+extern void *pg_realloc_mul(void *p, Size s1, Size s2);
+
 /*
  * Variants with easier notation and more type safety
  */
@@ -93,7 +103,6 @@ extern void *repalloc_mul(void *p, Size s1, Size s2);
 #define palloc0_array(type, count) ((type *) palloc0_mul(sizeof(type), count))
 #define palloc_array_extended(type, count, flags) ((type *) 
palloc_mul_extended(sizeof(type), count, flags))
 #define repalloc_array(pointer, type, count) ((type *) repalloc_mul(pointer, 
sizeof(type), count))
-#define repalloc_array_extended(pointer, type, count, flags) ((type *) 
repalloc_mul_extended(pointer, sizeof(type), count, flags))
 
 /* sprintf into a palloc'd buffer --- these are in psprintf.c */
 extern char *psprintf(const char *fmt,...) pg_attribute_printf(1, 2);
diff --git a/src/include/utils/palloc.h b/src/include/utils/palloc.h
index 815bd5e24ae..f2c0a173c25 100644
--- a/src/include/utils/palloc.h
+++ b/src/include/utils/palloc.h
@@ -175,6 +175,7 @@ pg_nodiscard extern void *repalloc_mul_extended(void *p, 
Size s1, Size s2,
  * objects of type "type"
  */
 #define repalloc_array(pointer, type, count) ((type *) repalloc_mul(pointer, 
sizeof(type), count))
+#define repalloc0_array(pointer, type, oldcount, count) ((type *) 
repalloc0(pointer, mul_size(sizeof(type), oldcount), mul_size(sizeof(type), 
count)))
 #define repalloc_array_extended(pointer, type, count, flags) ((type *) 
repalloc_mul_extended(pointer, sizeof(type), count, flags))
 
 /*


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to