aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/arrayutils.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2021-05-10 10:44:38 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2021-05-10 10:44:38 -0400
commitf02b9085ad2f6fefd9c5cdf85579cb9f0ff0f0ea (patch)
tree5f62efd8e2156c24cb6f4bc25b4f22a991ab284e /src/backend/utils/adt/arrayutils.c
parent6206454bdac1ccd6f6ed9d811e1a1139e663a8b9 (diff)
downloadpostgresql-f02b9085ad2f6fefd9c5cdf85579cb9f0ff0f0ea.tar.gz
postgresql-f02b9085ad2f6fefd9c5cdf85579cb9f0ff0f0ea.zip
Prevent integer overflows in array subscripting calculations.
While we were (mostly) careful about ensuring that the dimensions of arrays aren't large enough to cause integer overflow, the lower bound values were generally not checked. This allows situations where lower_bound + dimension overflows an integer. It seems that that's harmless so far as array reading is concerned, except that array elements with subscripts notionally exceeding INT_MAX are inaccessible. However, it confuses various array-assignment logic, resulting in a potential for memory stomps. Fix by adding checks that array lower bounds aren't large enough to cause lower_bound + dimension to overflow. (Note: this results in disallowing cases where the last subscript position would be exactly INT_MAX. In principle we could probably allow that, but there's a lot of code that computes lower_bound + dimension and would need adjustment. It seems doubtful that it's worth the trouble/risk to allow it.) Somewhat independently of that, array_set_element() was careless about possible overflow when checking the subscript of a fixed-length array, creating a different route to memory stomps. Fix that too. Security: CVE-2021-32027
Diffstat (limited to 'src/backend/utils/adt/arrayutils.c')
-rw-r--r--src/backend/utils/adt/arrayutils.c31
1 files changed, 31 insertions, 0 deletions
diff --git a/src/backend/utils/adt/arrayutils.c b/src/backend/utils/adt/arrayutils.c
index 2a6a05718f8..6988edd9361 100644
--- a/src/backend/utils/adt/arrayutils.c
+++ b/src/backend/utils/adt/arrayutils.c
@@ -16,6 +16,7 @@
#include "postgres.h"
#include "catalog/pg_type.h"
+#include "common/int.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/memutils.h"
@@ -112,6 +113,36 @@ ArrayGetNItems(int ndim, const int *dims)
}
/*
+ * Verify sanity of proposed lower-bound values for an array
+ *
+ * The lower-bound values must not be so large as to cause overflow when
+ * calculating subscripts, e.g. lower bound 2147483640 with length 10
+ * must be disallowed. We actually insist that dims[i] + lb[i] be
+ * computable without overflow, meaning that an array with last subscript
+ * equal to INT_MAX will be disallowed.
+ *
+ * It is assumed that the caller already called ArrayGetNItems, so that
+ * overflowed (negative) dims[] values have been eliminated.
+ */
+void
+ArrayCheckBounds(int ndim, const int *dims, const int *lb)
+{
+ int i;
+
+ for (i = 0; i < ndim; i++)
+ {
+ /* PG_USED_FOR_ASSERTS_ONLY prevents variable-isn't-read warnings */
+ int32 sum PG_USED_FOR_ASSERTS_ONLY;
+
+ if (pg_add_s32_overflow(dims[i], lb[i], &sum))
+ ereport(ERROR,
+ (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+ errmsg("array lower bound is too large: %d",
+ lb[i])));
+ }
+}
+
+/*
* Compute ranges (sub-array dimensions) for an array slice
*
* We assume caller has validated slice endpoints, so overflow is impossible