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

reshke pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cloudberry.git

commit beddb699d6379f094104600aed91f65672842f84
Author: Tom Lane <[email protected]>
AuthorDate: Mon Feb 9 09:57:44 2026 -0500

    Guard against unexpected dimensions of oidvector/int2vector.
    
    These data types are represented like full-fledged arrays, but
    functions that deal specifically with these types assume that the
    array is 1-dimensional and contains no nulls.  However, there are
    cast pathways that allow general oid[] or int2[] arrays to be cast
    to these types, allowing these expectations to be violated.  This
    can be exploited to cause server memory disclosure or SIGSEGV.
    Fix by installing explicit checks in functions that accept these
    types.
    
    Reported-by: Altan Birler <[email protected]>
    Author: Tom Lane <[email protected]>
    Reviewed-by: Noah Misch <[email protected]>
    Security: CVE-2026-2003
    Backpatch-through: 14
---
 src/backend/access/hash/hashfunc.c     |  2 ++
 src/backend/access/nbtree/nbtcompare.c |  3 +++
 src/backend/utils/adt/format_type.c    |  6 +++++-
 src/backend/utils/adt/int.c            | 31 ++++++++++++++++++++++++++++++-
 src/backend/utils/adt/oid.c            | 31 ++++++++++++++++++++++++++++++-
 src/include/utils/builtins.h           |  1 +
 src/test/regress/expected/arrays.out   |  5 +++++
 src/test/regress/sql/arrays.sql        |  4 ++++
 8 files changed, 80 insertions(+), 3 deletions(-)

diff --git a/src/backend/access/hash/hashfunc.c 
b/src/backend/access/hash/hashfunc.c
index ac21884162f..933aa42ffc9 100644
--- a/src/backend/access/hash/hashfunc.c
+++ b/src/backend/access/hash/hashfunc.c
@@ -235,6 +235,7 @@ hashoidvector(PG_FUNCTION_ARGS)
 {
        oidvector  *key = (oidvector *) PG_GETARG_POINTER(0);
 
+       check_valid_oidvector(key);
        return hash_any((unsigned char *) key->values, key->dim1 * sizeof(Oid));
 }
 
@@ -243,6 +244,7 @@ hashoidvectorextended(PG_FUNCTION_ARGS)
 {
        oidvector  *key = (oidvector *) PG_GETARG_POINTER(0);
 
+       check_valid_oidvector(key);
        return hash_any_extended((unsigned char *) key->values,
                                                         key->dim1 * 
sizeof(Oid),
                                                         PG_GETARG_INT64(1));
diff --git a/src/backend/access/nbtree/nbtcompare.c 
b/src/backend/access/nbtree/nbtcompare.c
index 976a2cc6447..720733b75d2 100644
--- a/src/backend/access/nbtree/nbtcompare.c
+++ b/src/backend/access/nbtree/nbtcompare.c
@@ -299,6 +299,9 @@ btoidvectorcmp(PG_FUNCTION_ARGS)
        oidvector  *b = (oidvector *) PG_GETARG_POINTER(1);
        int                     i;
 
+       check_valid_oidvector(a);
+       check_valid_oidvector(b);
+
        /* We arbitrarily choose to sort first by vector length */
        if (a->dim1 != b->dim1)
                PG_RETURN_INT32(a->dim1 - b->dim1);
diff --git a/src/backend/utils/adt/format_type.c 
b/src/backend/utils/adt/format_type.c
index 12402a06379..a9054d11b0c 100644
--- a/src/backend/utils/adt/format_type.c
+++ b/src/backend/utils/adt/format_type.c
@@ -444,11 +444,15 @@ oidvectortypes(PG_FUNCTION_ARGS)
 {
        oidvector  *oidArray = (oidvector *) PG_GETARG_POINTER(0);
        char       *result;
-       int                     numargs = oidArray->dim1;
+       int                     numargs;
        int                     num;
        size_t          total;
        size_t          left;
 
+       /* validate input before fetching dim1 */
+       check_valid_oidvector(oidArray);
+       numargs = oidArray->dim1;
+
        total = 20 * numargs + 1;
        result = palloc(total);
        result[0] = '\0';
diff --git a/src/backend/utils/adt/int.c b/src/backend/utils/adt/int.c
index 44d1c7ad0c4..f9a08257ac3 100644
--- a/src/backend/utils/adt/int.c
+++ b/src/backend/utils/adt/int.c
@@ -134,6 +134,30 @@ buildint2vector(const int16 *int2s, int n)
        return result;
 }
 
+/*
+ * validate that an array object meets the restrictions of int2vector
+ *
+ * We need this because there are pathways by which a general int2[] array can
+ * be cast to int2vector, allowing the type's restrictions to be violated.
+ * All code that receives an int2vector as a SQL parameter should check this.
+ */
+static void
+check_valid_int2vector(const int2vector *int2Array)
+{
+       /*
+        * We insist on ndim == 1 and dataoffset == 0 (that is, no nulls) 
because
+        * otherwise the array's layout will not be what calling code expects.  
We
+        * needn't be picky about the index lower bound though.  Checking 
elemtype
+        * is just paranoia.
+        */
+       if (int2Array->ndim != 1 ||
+               int2Array->dataoffset != 0 ||
+               int2Array->elemtype != INT2OID)
+               ereport(ERROR,
+                               (errcode(ERRCODE_DATATYPE_MISMATCH),
+                                errmsg("array is not a valid int2vector")));
+}
+
 /*
  *             int2vectorin                    - converts "num num ..." to 
internal form
  */
@@ -208,10 +232,14 @@ int2vectorout(PG_FUNCTION_ARGS)
 {
        int2vector *int2Array = (int2vector *) PG_GETARG_POINTER(0);
        int                     num,
-                               nnums = int2Array->dim1;
+                               nnums;
        char       *rp;
        char       *result;
 
+       /* validate input before fetching dim1 */
+       check_valid_int2vector(int2Array);
+       nnums = int2Array->dim1;
+
        /* assumes sign, 5 digits, ' ' */
        rp = result = (char *) palloc(nnums * 7 + 1);
        for (num = 0; num < nnums; num++)
@@ -272,6 +300,7 @@ int2vectorrecv(PG_FUNCTION_ARGS)
 Datum
 int2vectorsend(PG_FUNCTION_ARGS)
 {
+       /* We don't do check_valid_int2vector, since array_send won't care */
        return array_send(fcinfo);
 }
 
diff --git a/src/backend/utils/adt/oid.c b/src/backend/utils/adt/oid.c
index 3f7af5b3a06..066511443cf 100644
--- a/src/backend/utils/adt/oid.c
+++ b/src/backend/utils/adt/oid.c
@@ -106,6 +106,30 @@ buildoidvector(const Oid *oids, int n)
        return result;
 }
 
+/*
+ * validate that an array object meets the restrictions of oidvector
+ *
+ * We need this because there are pathways by which a general oid[] array can
+ * be cast to oidvector, allowing the type's restrictions to be violated.
+ * All code that receives an oidvector as a SQL parameter should check this.
+ */
+void
+check_valid_oidvector(const oidvector *oidArray)
+{
+       /*
+        * We insist on ndim == 1 and dataoffset == 0 (that is, no nulls) 
because
+        * otherwise the array's layout will not be what calling code expects.  
We
+        * needn't be picky about the index lower bound though.  Checking 
elemtype
+        * is just paranoia.
+        */
+       if (oidArray->ndim != 1 ||
+               oidArray->dataoffset != 0 ||
+               oidArray->elemtype != OIDOID)
+               ereport(ERROR,
+                               (errcode(ERRCODE_DATATYPE_MISMATCH),
+                                errmsg("array is not a valid oidvector")));
+}
+
 /*
  *             oidvectorin                     - converts "num num ..." to 
internal form
  */
@@ -158,10 +182,14 @@ oidvectorout(PG_FUNCTION_ARGS)
 {
        oidvector  *oidArray = (oidvector *) PG_GETARG_POINTER(0);
        int                     num,
-                               nnums = oidArray->dim1;
+                               nnums;
        char       *rp;
        char       *result;
 
+       /* validate input before fetching dim1 */
+       check_valid_oidvector(oidArray);
+       nnums = oidArray->dim1;
+
        /* assumes sign, 10 digits, ' ' */
        rp = result = (char *) palloc(nnums * 12 + 1);
        for (num = 0; num < nnums; num++)
@@ -224,6 +252,7 @@ oidvectorrecv(PG_FUNCTION_ARGS)
 Datum
 oidvectorsend(PG_FUNCTION_ARGS)
 {
+       /* We don't do check_valid_oidvector, since array_send won't care */
        return array_send(fcinfo);
 }
 
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index cb309ede6ae..bcba170c327 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -70,6 +70,7 @@ extern int64 get_size_from_segDBs(const char *cmd);
 
 /* oid.c */
 extern oidvector *buildoidvector(const Oid *oids, int n);
+extern void check_valid_oidvector(const oidvector *oidArray);
 extern Oid     oidparse(Node *node);
 
 /* pseudotypes.c */
diff --git a/src/test/regress/expected/arrays.out 
b/src/test/regress/expected/arrays.out
index 20b401a9ef9..bf69c337ec2 100644
--- a/src/test/regress/expected/arrays.out
+++ b/src/test/regress/expected/arrays.out
@@ -1601,6 +1601,11 @@ select '[0:1]={1.1,2.2}'::float8[];
 (1 row)
 
 -- all of the above should be accepted
+-- some day we might allow these cases, but for now they're errors:
+select array[]::oidvector;
+ERROR:  array is not a valid oidvector
+select array[]::int2vector;
+ERROR:  array is not a valid int2vector
 -- tests for array aggregates
 CREATE TEMP TABLE arraggtest ( f1 INT[], f2 TEXT[][], f3 FLOAT[]) DISTRIBUTED 
RANDOMLY;
 INSERT INTO arraggtest (f1, f2, f3) VALUES
diff --git a/src/test/regress/sql/arrays.sql b/src/test/regress/sql/arrays.sql
index aabbd6f92de..075e6949846 100644
--- a/src/test/regress/sql/arrays.sql
+++ b/src/test/regress/sql/arrays.sql
@@ -502,6 +502,10 @@ select array[]::text[];
 select '[0:1]={1.1,2.2}'::float8[];
 -- all of the above should be accepted
 
+-- some day we might allow these cases, but for now they're errors:
+select array[]::oidvector;
+select array[]::int2vector;
+
 -- tests for array aggregates
 CREATE TEMP TABLE arraggtest ( f1 INT[], f2 TEXT[][], f3 FLOAT[]) DISTRIBUTED 
RANDOMLY;
 


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

Reply via email to