[SCM] PostGIS branch stable-3.2 updated. 3.2.10-85-gb7d2b6038e
git at osgeo.org
git at osgeo.org
Mon Jul 27 12:08:50 PDT 2026
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "PostGIS".
The branch, stable-3.2 has been updated
via b7d2b6038e674dfea02e41b067e4776de3c60c55 (commit)
via 180a77f361177564109b39ec58f3dbd557bd37f3 (commit)
via 6ab484dc748f5f8cf7212899f6cef59d881ce963 (commit)
via a761dc4d47a4138161b0f33a193ea804d31afc45 (commit)
from 15c7d6378e5de6629a392495ac226513bdfd8752 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit b7d2b6038e674dfea02e41b067e4776de3c60c55
Merge: 15c7d6378e 180a77f361
Author: Darafei Praliaskouski <komzpa at gmail.com>
Date: Mon Jul 27 12:08:49 2026 -0700
Merge pull request 'Backport safety fixes to stable-3.2' (!541) from Komzpa/postgis:backport/20260726-stable-3.2-safety-fixes into stable-3.2
Reviewed-on: https://gitea.osgeo.org/postgis/postgis/pulls/541
commit 180a77f361177564109b39ec58f3dbd557bd37f3
Author: Darafei Praliaskouski <me at komzpa.net>
Date: Sun Jul 26 21:35:41 2026 +0400
Drop master-only NURBS validator from stable GSERIALIZED port
Stable branches do not define NURBSCURVETYPE, so the NURBS-specific validator from the master GSERIALIZED hardening patch is not a branch-capability match. Keep the payload checks for geometry types present on the stable line.
(cherry picked from commit de00ccc19b0fee48f8dbbc8b521510382624c099)
(cherry picked from commit ef6a551e0a2a3420ad5106579c0126e56152c0ec)
diff --git a/liblwgeom/gserialized2.c b/liblwgeom/gserialized2.c
index e27940fecb..78995b4825 100644
--- a/liblwgeom/gserialized2.c
+++ b/liblwgeom/gserialized2.c
@@ -440,37 +440,6 @@ gserialized2_validate_geometry_buffer(uint8_t *data_ptr, uint8_t *data_end, lwfl
break;
}
- case NURBSCURVETYPE: {
- uint32_t nweights, nknots;
- size_t weight_bytes, knot_bytes, point_bytes;
- consumed = 6 * sizeof(uint32_t);
- if (!gserialized2_range_available(data_ptr, data_end, consumed))
- {
- lwerror("%s: GSERIALIZED NURBS header exceeds payload size", __func__);
- return LW_FAILURE;
- }
- nweights =
- gserialized2_read_uint32_checked(data_ptr + 3 * sizeof(uint32_t), data_end, "NURBS weight count");
- nknots =
- gserialized2_read_uint32_checked(data_ptr + 4 * sizeof(uint32_t), data_end, "NURBS knot count");
- if (gserialized2_checked_mul((size_t)nweights, sizeof(double), &weight_bytes) == LW_FAILURE ||
- gserialized2_checked_mul((size_t)nknots, sizeof(double), &knot_bytes) == LW_FAILURE)
- {
- lwerror("%s: GSERIALIZED NURBS vector size overflows", __func__);
- return LW_FAILURE;
- }
- if (gserialized2_pointarray_payload_size(count, lwflags, &point_bytes) == LW_FAILURE)
- return LW_FAILURE;
- if (gserialized2_checked_add(consumed, weight_bytes, &consumed) == LW_FAILURE ||
- gserialized2_checked_add(consumed, knot_bytes, &consumed) == LW_FAILURE ||
- gserialized2_checked_add(consumed, point_bytes, &consumed) == LW_FAILURE)
- {
- lwerror("%s: GSERIALIZED NURBS size overflows", __func__);
- return LW_FAILURE;
- }
- break;
- }
-
default:
lwerror("Unknown geometry type: %d - %s", type, lwtype_name(type));
return LW_FAILURE;
commit 6ab484dc748f5f8cf7212899f6cef59d881ce963
Author: Darafei Praliaskouski <me at komzpa.net>
Date: Sun Jul 26 16:14:42 2026 +0300
Fix raster geotransform invalid reads
Port the stable-applicable part of the Valgrind finding: RASTER_getGeotransform read raster offsets after destroying the deserialized raster. The rt_band_init_value zero-cell fix from master does not apply because stable-3.5 does not have that helper.
Ported-from: https://gitea.osgeo.org/postgis/postgis/commit/5692dfe21b854899ee738f278651e58e63532652
(cherry picked from commit 0181cd4411467c12ac96a935bacb7da98ddac027)
(cherry picked from commit 9a28f6f533371ab341ef560cca869b235e839812)
(cherry picked from commit eb93d7f3165a29937e0ea77d31d0afc05ab30ca7)
(cherry picked from commit cee7083a3767adeb890272a16b7c762f7383ca6b)
diff --git a/NEWS b/NEWS
index 4c6cedf531..6eb559d0b3 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,8 @@ PostGIS 3.2.11
- GT-522, Reject malformed GSERIALIZED payload counts before deserializing
geometry data (Darafei Praliaskouski)
+ - GT-523, [raster] Fix invalid reads in geotransform property access
+ (Darafei Praliaskouski)
- #6094, [upgrade] Avoid legacy string literal warnings in downgrade checks
with standard_conforming_strings off (Darafei Praliaskouski)
- [upgrade] Fix ST_TileEnvelope upgrade marker syntax
diff --git a/raster/rt_pg/rtpg_raster_properties.c b/raster/rt_pg/rtpg_raster_properties.c
index 032e4975e9..c2717585e0 100644
--- a/raster/rt_pg/rtpg_raster_properties.c
+++ b/raster/rt_pg/rtpg_raster_properties.c
@@ -445,10 +445,8 @@ Datum RASTER_getGeotransform(PG_FUNCTION_ARGS)
double jmag;
double theta_i;
double theta_ij;
- /*
double xoffset;
double yoffset;
- */
TupleDesc result_tuple; /* for returning a composite */
Datum values[VALUES_LENGTH];
@@ -478,6 +476,8 @@ Datum RASTER_getGeotransform(PG_FUNCTION_ARGS)
rt_raster_get_y_skew(raster),
rt_raster_get_y_scale(raster),
&imag, &jmag, &theta_i, &theta_ij) ;
+ xoffset = rt_raster_get_x_offset(raster);
+ yoffset = rt_raster_get_y_offset(raster);
rt_raster_destroy(raster);
PG_FREE_IF_COPY(pgraster, 0);
@@ -501,8 +501,8 @@ Datum RASTER_getGeotransform(PG_FUNCTION_ARGS)
values[1] = Float8GetDatum(jmag);
values[2] = Float8GetDatum(theta_i);
values[3] = Float8GetDatum(theta_ij);
- values[4] = Float8GetDatum(rt_raster_get_x_offset(raster));
- values[5] = Float8GetDatum(rt_raster_get_y_offset(raster));
+ values[4] = Float8GetDatum(xoffset);
+ values[5] = Float8GetDatum(yoffset);
memset(nulls, FALSE, sizeof(bool) * VALUES_LENGTH);
commit a761dc4d47a4138161b0f33a193ea804d31afc45
Author: Darafei Praliaskouski <me at komzpa.net>
Date: Sun Jul 26 14:43:56 2026 +0400
Harden GSERIALIZED payload readers
(cherry picked from commit 62cff7ebdd8a76e61231b379026a41dd6e49b436)
diff --git a/NEWS b/NEWS
index 6c6396e6d9..4c6cedf531 100644
--- a/NEWS
+++ b/NEWS
@@ -3,6 +3,8 @@ PostGIS 3.2.11
* Bug Fixes *
+ - GT-522, Reject malformed GSERIALIZED payload counts before deserializing
+ geometry data (Darafei Praliaskouski)
- #6094, [upgrade] Avoid legacy string literal warnings in downgrade checks
with standard_conforming_strings off (Darafei Praliaskouski)
- [upgrade] Fix ST_TileEnvelope upgrade marker syntax
diff --git a/liblwgeom/cunit/cu_gserialized1.c b/liblwgeom/cunit/cu_gserialized1.c
index 66cc0a55e8..4afe2294c7 100644
--- a/liblwgeom/cunit/cu_gserialized1.c
+++ b/liblwgeom/cunit/cu_gserialized1.c
@@ -1252,6 +1252,47 @@ test_gserialized1_peek_first_point(void)
CU_ASSERT(peek1_point_helper("POLYGON((0 0, 1 1, 1 0, 0 0))", &p) == LW_FAILURE);
}
+static void
+assert_gserialized1_malformed_rejected(GSERIALIZED *g)
+{
+ LWGEOM *geom;
+ GBOX box;
+ POINT4D point;
+
+ memset(&box, 0, sizeof(box));
+ memset(&point, 0, sizeof(point));
+
+ cu_error_msg_reset();
+ geom = lwgeom_from_gserialized1(g);
+ CU_ASSERT_PTR_NULL(geom);
+ CU_ASSERT_NOT_EQUAL(strlen(cu_error_msg), 0);
+
+ CU_ASSERT_TRUE(gserialized1_is_empty(g));
+ CU_ASSERT_EQUAL(gserialized1_peek_gbox_p(g, &box), LW_FAILURE);
+ CU_ASSERT_EQUAL(gserialized1_peek_first_point(g, &point), LW_FAILURE);
+}
+
+static void
+test_gserialized1_malformed_declared_size(void)
+{
+ LWGEOM *lwgeom = lwgeom_from_wkt("POINT(1 1)", LW_PARSER_CHECK_NONE);
+ GSERIALIZED *g;
+ size_t size = 0;
+
+ CU_ASSERT_PTR_NOT_NULL_FATAL(lwgeom);
+ g = gserialized1_from_lwgeom(lwgeom, &size);
+ CU_ASSERT_PTR_NOT_NULL_FATAL(g);
+
+ LWSIZE_SET(g->size, 0);
+ assert_gserialized1_malformed_rejected(g);
+
+ LWSIZE_SET(g->size, offsetof(GSERIALIZED, data) - 1);
+ assert_gserialized1_malformed_rejected(g);
+
+ lwfree(g);
+ lwgeom_free(lwgeom);
+}
+
/*
** Used by test harness to register the tests in this file.
*/
@@ -1286,4 +1327,5 @@ void gserialized1_suite_setup(void)
PG_ADD_TEST(suite, test_gbox_same_2d);
PG_ADD_TEST(suite, test_signum_macro);
PG_ADD_TEST(suite, test_gserialized1_peek_first_point);
+ PG_ADD_TEST(suite, test_gserialized1_malformed_declared_size);
}
diff --git a/liblwgeom/cunit/cu_gserialized2.c b/liblwgeom/cunit/cu_gserialized2.c
index 6f8217c15a..3dc36a09a4 100644
--- a/liblwgeom/cunit/cu_gserialized2.c
+++ b/liblwgeom/cunit/cu_gserialized2.c
@@ -509,6 +509,133 @@ test_gserialized2_peek_first_point(void)
CU_ASSERT(peek2_point_helper("POLYGON((0 0, 1 1, 1 0, 0 0))", &p) == LW_FAILURE);
}
+static GSERIALIZED *
+gserialized2_from_hexbytes(const char *hex)
+{
+ uint8_t *bytes;
+ size_t size;
+ GSERIALIZED *g;
+
+ size = strlen(hex) / 2;
+ bytes = bytes_from_hexbytes(hex, strlen(hex));
+ g = lwalloc(size);
+ memcpy(g, bytes, size);
+ lwfree(bytes);
+ return g;
+}
+
+static void
+test_gserialized2_malformed_collection_count(void)
+{
+ const char *hex =
+ "8001000000000044000000000000803f0000000000000040"
+ "070000000200000001000000f03f000000000000f03f";
+ GSERIALIZED *g = gserialized2_from_hexbytes(hex);
+ LWGEOM *geom;
+
+ cu_error_msg_reset();
+ geom = lwgeom_from_gserialized2(g);
+
+ CU_ASSERT_PTR_NULL(geom);
+ CU_ASSERT_NOT_EQUAL(strlen(cu_error_msg), 0);
+
+ lwfree(g);
+}
+
+static void
+assert_gserialized2_malformed_rejected(GSERIALIZED *g)
+{
+ LWGEOM *geom;
+ GBOX box;
+ POINT4D point;
+
+ memset(&box, 0, sizeof(box));
+ memset(&point, 0, sizeof(point));
+
+ cu_error_msg_reset();
+ geom = lwgeom_from_gserialized2(g);
+ CU_ASSERT_PTR_NULL(geom);
+ CU_ASSERT_NOT_EQUAL(strlen(cu_error_msg), 0);
+
+ CU_ASSERT_TRUE(gserialized2_is_empty(g));
+ CU_ASSERT_EQUAL(gserialized2_peek_gbox_p(g, &box), LW_FAILURE);
+ CU_ASSERT_EQUAL(gserialized2_peek_first_point(g, &point), LW_FAILURE);
+}
+
+static void
+test_gserialized2_malformed_declared_size(void)
+{
+ const char *declared_size_0 =
+ "0000000000000044000000000000803f0000000000000040"
+ "070000000200000001000000f03f000000000000f03f";
+ const char *declared_size_23 =
+ "5c00000000000044000000000000803f0000000000000040"
+ "070000000200000001000000f03f000000000000f03f";
+ GSERIALIZED *g;
+
+ g = gserialized2_from_hexbytes(declared_size_0);
+ assert_gserialized2_malformed_rejected(g);
+ lwfree(g);
+
+ g = gserialized2_from_hexbytes(declared_size_23);
+ assert_gserialized2_malformed_rejected(g);
+ lwfree(g);
+}
+
+static void
+test_gserialized2_malformed_short_allocation(void)
+{
+#if defined(POSTGIS_ASAN_ALLOCATOR_SIZE)
+ const char *hex = "8001000000000044";
+ uint8_t *bytes = bytes_from_hexbytes(hex, strlen(hex));
+ GSERIALIZED *g = malloc(strlen(hex) / 2);
+
+ CU_ASSERT_PTR_NOT_NULL_FATAL(g);
+ memcpy(g, bytes, strlen(hex) / 2);
+ assert_gserialized2_malformed_rejected(g);
+
+ free(g);
+ lwfree(bytes);
+#else
+ CU_PASS("shorter-than-declared allocation validation requires AddressSanitizer allocation metadata");
+#endif
+}
+
+static void
+test_gserialized2_wkb_roundtrip_float_rounded_box(void)
+{
+ const char *hex =
+ "0102000000030000000000000000000000000000f03f0000000000000040"
+ "0101000000000000000f03f0000000000000040000000000000f03f";
+ size_t wkb_size = strlen(hex) / 2;
+ uint8_t *wkb = bytes_from_hexbytes(hex, strlen(hex));
+ LWGEOM *input = lwgeom_from_wkb(wkb, wkb_size, LW_PARSER_CHECK_NONE);
+ GSERIALIZED *serialized;
+ LWGEOM *roundtrip;
+ size_t serialized_size = 0;
+ GBOX input_box;
+ GBOX roundtrip_box;
+
+ CU_ASSERT_PTR_NOT_NULL_FATAL(input);
+ serialized = gserialized2_from_lwgeom(input, &serialized_size);
+ CU_ASSERT_PTR_NOT_NULL_FATAL(serialized);
+ roundtrip = lwgeom_from_gserialized2(serialized);
+ CU_ASSERT_PTR_NOT_NULL_FATAL(roundtrip);
+
+ CU_ASSERT_EQUAL(serialized_size, LWSIZE_GET(serialized->size));
+ CU_ASSERT_PTR_NOT_NULL(input->bbox);
+ CU_ASSERT_PTR_NOT_NULL(roundtrip->bbox);
+ CU_ASSERT_FALSE(gbox_same(input->bbox, roundtrip->bbox));
+ CU_ASSERT_EQUAL(lwgeom_calculate_gbox_cartesian(input, &input_box), LW_SUCCESS);
+ CU_ASSERT_EQUAL(lwgeom_calculate_gbox_cartesian(roundtrip, &roundtrip_box), LW_SUCCESS);
+ CU_ASSERT_TRUE(gbox_same(&input_box, &roundtrip_box));
+
+ lwgeom_free(input);
+ lwgeom_free(roundtrip);
+ lwfree(serialized);
+ lwfree(wkb);
+}
+
/*
** Used by test harness to register the tests in this file.
*/
@@ -527,4 +654,8 @@ void gserialized2_suite_setup(void)
PG_ADD_TEST(suite, test_gserialized2_peek_gbox_p_fails_for_unsupported_cases);
PG_ADD_TEST(suite, test_gserialized2_extended_flags);
PG_ADD_TEST(suite, test_gserialized2_peek_first_point);
+ PG_ADD_TEST(suite, test_gserialized2_malformed_collection_count);
+ PG_ADD_TEST(suite, test_gserialized2_malformed_declared_size);
+ PG_ADD_TEST(suite, test_gserialized2_malformed_short_allocation);
+ PG_ADD_TEST(suite, test_gserialized2_wkb_roundtrip_float_rounded_box);
}
diff --git a/liblwgeom/gserialized1.c b/liblwgeom/gserialized1.c
index 1a87ccf527..e4f7c57ce3 100644
--- a/liblwgeom/gserialized1.c
+++ b/liblwgeom/gserialized1.c
@@ -30,13 +30,37 @@
#include "gserialized1.h"
#include <stddef.h>
+#if defined(__has_feature)
+#if __has_feature(address_sanitizer)
+#define POSTGIS_ASAN_ALLOCATOR_SIZE 1
+#endif
+#endif
+#if defined(__SANITIZE_ADDRESS__)
+#define POSTGIS_ASAN_ALLOCATOR_SIZE 1
+#endif
+#if defined(POSTGIS_ASAN_ALLOCATOR_SIZE)
+#include <sanitizer/allocator_interface.h>
+#endif
/***********************************************************************
* GSERIALIZED metadata utility functions.
*/
static int gserialized1_read_gbox_p(const GSERIALIZED *g, GBOX *gbox);
+static int gserialized1_payload_bounds(const GSERIALIZED *g, uint8_t **start, uint8_t **end);
+static int gserialized1_validate_geometry_buffer(uint8_t *data_ptr, uint8_t *data_end, lwflags_t lwflags, size_t *size);
+static size_t
+gserialized1_buffer_size(const GSERIALIZED *g)
+{
+ size_t gsize = LWSIZE_GET(g->size);
+#if defined(POSTGIS_ASAN_ALLOCATOR_SIZE)
+ size_t allocated_size = __sanitizer_get_allocated_size(g);
+ if (allocated_size > 0 && allocated_size < gsize)
+ return allocated_size;
+#endif
+ return gsize;
+}
lwflags_t gserialized1_get_lwflags(const GSERIALIZED *g)
{
@@ -132,6 +156,13 @@ static uint32_t gserialized1_header_size(const GSERIALIZED *gser)
uint32_t gserialized1_get_type(const GSERIALIZED *g)
{
uint32_t *ptr;
+ size_t hsz = gserialized1_header_size(g);
+ size_t gsize = gserialized1_buffer_size(g);
+ if (gsize < hsz + sizeof(uint32_t))
+ {
+ lwerror("%s: GSERIALIZED too small for geometry type", __func__);
+ return 0;
+ }
ptr = (uint32_t*)(g->data);
if ( G1FLAGS_GET_BBOX(g->gflags) )
{
@@ -142,19 +173,19 @@ uint32_t gserialized1_get_type(const GSERIALIZED *g)
int32_t gserialized1_get_srid(const GSERIALIZED *s)
{
- int32_t srid = 0;
- srid = srid | (s->srid[0] << 16);
- srid = srid | (s->srid[1] << 8);
- srid = srid | s->srid[2];
- /* Only the first 21 bits are set. Slide up and back to pull
- the negative bits down, if we need them. */
- srid = (srid<<11)>>11;
+ uint32_t srid = 0;
+ srid = srid | ((uint32_t)s->srid[0] << 16);
+ srid = srid | ((uint32_t)s->srid[1] << 8);
+ srid = srid | (uint32_t)s->srid[2];
+ /* Only the first 21 bits are set. Sign-extend without signed shift UB. */
+ if (srid & 0x00100000)
+ srid |= 0xFFE00000;
/* 0 is our internal unknown value. We'll map back and forth here for now */
if ( srid == 0 )
return SRID_UNKNOWN;
else
- return srid;
+ return (int32_t)srid;
}
void gserialized1_set_srid(GSERIALIZED *s, int32_t srid)
@@ -173,6 +204,204 @@ void gserialized1_set_srid(GSERIALIZED *s, int32_t srid)
s->srid[2] = (srid & 0x000000FF);
}
+static int
+gserialized1_range_available(const uint8_t *ptr, const uint8_t *end, size_t len)
+{
+ return ptr <= end && len <= (size_t)(end - ptr);
+}
+
+static int
+gserialized1_checked_mul(size_t a, size_t b, size_t *out)
+{
+ if (a != 0 && b > SIZE_MAX / a)
+ return LW_FAILURE;
+ *out = a * b;
+ return LW_SUCCESS;
+}
+
+static int
+gserialized1_checked_add(size_t a, size_t b, size_t *out)
+{
+ if (b > SIZE_MAX - a)
+ return LW_FAILURE;
+ *out = a + b;
+ return LW_SUCCESS;
+}
+
+static int
+gserialized1_payload_bounds(const GSERIALIZED *g, uint8_t **start, uint8_t **end)
+{
+ size_t hsz;
+ size_t gsize;
+
+ if (!g)
+ return LW_FAILURE;
+
+ hsz = gserialized1_header_size(g);
+ gsize = gserialized1_buffer_size(g);
+ if (gsize < hsz)
+ return LW_FAILURE;
+
+ if (start)
+ *start = (uint8_t *)g + hsz;
+ if (end)
+ *end = (uint8_t *)g + gsize;
+ return LW_SUCCESS;
+}
+
+static uint32_t
+gserialized1_read_uint32_checked(uint8_t *ptr, uint8_t *end, const char *field)
+{
+ uint32_t value = 0;
+ if (!gserialized1_range_available(ptr, end, sizeof(uint32_t)))
+ {
+ lwerror("%s: GSERIALIZED too small for %s", __func__, field);
+ return 0;
+ }
+ memcpy(&value, ptr, sizeof(uint32_t));
+ return value;
+}
+
+static int
+gserialized1_pointarray_payload_size(uint32_t npoints, lwflags_t lwflags, size_t *nbytes)
+{
+ if (gserialized1_checked_mul((size_t)npoints, sizeof(double) * FLAGS_NDIMS(lwflags), nbytes) == LW_FAILURE)
+ {
+ lwerror("%s: GSERIALIZED point count overflows payload size", __func__);
+ return LW_FAILURE;
+ }
+ return LW_SUCCESS;
+}
+
+static int
+gserialized1_validate_geometry_buffer(uint8_t *data_ptr, uint8_t *data_end, lwflags_t lwflags, size_t *size)
+{
+ uint32_t type, count;
+ size_t consumed = 0;
+
+ if (!gserialized1_range_available(data_ptr, data_end, 2 * sizeof(uint32_t)))
+ {
+ lwerror("%s: GSERIALIZED geometry payload is too short", __func__);
+ return LW_FAILURE;
+ }
+
+ type = gserialized1_read_uint32_checked(data_ptr, data_end, "geometry type");
+ count = gserialized1_read_uint32_checked(data_ptr + sizeof(uint32_t), data_end, "geometry count");
+
+ switch (type)
+ {
+ case POINTTYPE:
+ if (count > 1)
+ {
+ lwerror("%s: invalid point count %u", __func__, count);
+ return LW_FAILURE;
+ }
+ /* fall through */
+ case LINETYPE:
+ case CIRCSTRINGTYPE:
+ case TRIANGLETYPE: {
+ size_t point_bytes;
+ if (gserialized1_pointarray_payload_size(count, lwflags, &point_bytes) == LW_FAILURE)
+ return LW_FAILURE;
+ consumed = 2 * sizeof(uint32_t) + point_bytes;
+ break;
+ }
+
+ case POLYGONTYPE: {
+ size_t ring_counts_size, ring_counts_padded_size, point_bytes_sum = 0;
+ uint8_t *ring_counts = data_ptr + 2 * sizeof(uint32_t);
+ uint32_t i;
+
+ if (gserialized1_checked_mul((size_t)count, sizeof(uint32_t), &ring_counts_size) == LW_FAILURE)
+ {
+ lwerror("%s: GSERIALIZED ring count overflows payload size", __func__);
+ return LW_FAILURE;
+ }
+ ring_counts_padded_size = ring_counts_size + ((count % 2) ? sizeof(uint32_t) : 0);
+ if (!gserialized1_range_available(ring_counts, data_end, ring_counts_padded_size))
+ {
+ lwerror("%s: GSERIALIZED polygon ring table exceeds payload size", __func__);
+ return LW_FAILURE;
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ size_t ring_point_bytes;
+ uint32_t npoints = gserialized1_read_uint32_checked(
+ ring_counts + i * sizeof(uint32_t), data_end, "ring point count");
+ if (gserialized1_pointarray_payload_size(npoints, lwflags, &ring_point_bytes) == LW_FAILURE)
+ return LW_FAILURE;
+ if (gserialized1_checked_add(point_bytes_sum, ring_point_bytes, &point_bytes_sum) == LW_FAILURE)
+ {
+ lwerror("%s: GSERIALIZED polygon coordinate size overflows", __func__);
+ return LW_FAILURE;
+ }
+ }
+ consumed = 2 * sizeof(uint32_t) + ring_counts_padded_size;
+ if (gserialized1_checked_add(consumed, point_bytes_sum, &consumed) == LW_FAILURE)
+ {
+ lwerror("%s: GSERIALIZED polygon size overflows", __func__);
+ return LW_FAILURE;
+ }
+ break;
+ }
+
+ case MULTIPOINTTYPE:
+ case MULTILINETYPE:
+ case MULTIPOLYGONTYPE:
+ case COMPOUNDTYPE:
+ case CURVEPOLYTYPE:
+ case MULTICURVETYPE:
+ case MULTISURFACETYPE:
+ case POLYHEDRALSURFACETYPE:
+ case TINTYPE:
+ case COLLECTIONTYPE: {
+ uint32_t i;
+ uint8_t *subgeom_ptr = data_ptr + 2 * sizeof(uint32_t);
+ lwflags_t subflags = lwflags;
+ FLAGS_SET_BBOX(subflags, 0);
+ for (i = 0; i < count; i++)
+ {
+ size_t subsize = 0;
+ uint32_t subtype =
+ gserialized1_read_uint32_checked(subgeom_ptr, data_end, "collection subtype");
+ if (!lwcollection_allows_subtype(type, subtype))
+ {
+ lwerror("Invalid subtype (%s) for collection type (%s)",
+ lwtype_name(subtype),
+ lwtype_name(type));
+ return LW_FAILURE;
+ }
+ if (gserialized1_validate_geometry_buffer(subgeom_ptr, data_end, subflags, &subsize) ==
+ LW_FAILURE)
+ return LW_FAILURE;
+ if (subsize == 0)
+ {
+ lwerror("%s: GSERIALIZED collection member has zero size", __func__);
+ return LW_FAILURE;
+ }
+ subgeom_ptr += subsize;
+ }
+ consumed = (size_t)(subgeom_ptr - data_ptr);
+ break;
+ }
+
+ default:
+ lwerror("Unknown geometry type: %d - %s", type, lwtype_name(type));
+ return LW_FAILURE;
+ }
+
+ if (!gserialized1_range_available(data_ptr, data_end, consumed))
+ {
+ lwerror("%s: GSERIALIZED geometry payload exceeds declared size", __func__);
+ return LW_FAILURE;
+ }
+
+ if (size)
+ *size = consumed;
+ return LW_SUCCESS;
+}
+
static size_t gserialized1_is_empty_recurse(const uint8_t *p, int *isempty);
static size_t gserialized1_is_empty_recurse(const uint8_t *p, int *isempty)
{
@@ -203,13 +432,17 @@ static size_t gserialized1_is_empty_recurse(const uint8_t *p, int *isempty)
int gserialized1_is_empty(const GSERIALIZED *g)
{
- uint8_t *p = (uint8_t*)g;
+ uint8_t *p, *end;
int isempty = 0;
assert(g);
- p += 8; /* Skip varhdr and srid/flags */
- if(gserialized1_has_bbox(g))
- p += gserialized1_box_size(g); /* Skip the box */
+ if (gserialized1_payload_bounds(g, &p, &end) == LW_FAILURE)
+ {
+ lwerror("%s: invalid GSERIALIZED header size", __func__);
+ return LW_TRUE;
+ }
+ if (gserialized1_validate_geometry_buffer(p, end, gserialized1_get_lwflags(g), NULL) == LW_FAILURE)
+ return LW_TRUE;
gserialized1_is_empty_recurse(p, &isempty);
return isempty;
@@ -254,6 +487,8 @@ int gserialized1_read_gbox_p(const GSERIALIZED *g, GBOX *gbox)
/* Null input! */
if ( ! ( g && gbox ) ) return LW_FAILURE;
+ if (gserialized1_buffer_size(g) < offsetof(GSERIALIZED, data) + gserialized1_box_size(g))
+ return LW_FAILURE;
/* Initialize the flags on the box */
gbox->flags = gserialized1_get_lwflags(g);
@@ -298,7 +533,16 @@ int gserialized1_read_gbox_p(const GSERIALIZED *g, GBOX *gbox)
int
gserialized1_peek_gbox_p(const GSERIALIZED *g, GBOX *gbox)
{
- uint32_t type = gserialized1_get_type(g);
+ uint32_t type;
+ uint8_t *geometry_start = NULL;
+ uint8_t *geometry_end = NULL;
+
+ if (gserialized1_payload_bounds(g, &geometry_start, &geometry_end) == LW_FAILURE)
+ return LW_FAILURE;
+ if (gserialized1_validate_geometry_buffer(geometry_start, geometry_end, gserialized1_get_lwflags(g), NULL) ==
+ LW_FAILURE)
+ return LW_FAILURE;
+ type = gserialized1_get_type(g);
/* Peeking doesn't help if you already have a box or are geodetic */
if ( G1FLAGS_GET_GEODETIC(g->gflags) || G1FLAGS_GET_BBOX(g->gflags) )
@@ -491,11 +735,14 @@ gserialized1_copy_point(double *dptr, lwflags_t flags, POINT4D *out_point)
int
gserialized1_peek_first_point(const GSERIALIZED *g, POINT4D *out_point)
{
- uint8_t *geometry_start = ((uint8_t *)g->data);
- if (gserialized1_has_bbox(g))
- {
- geometry_start += gserialized1_box_size(g);
- }
+ uint8_t *geometry_start = NULL;
+ uint8_t *geometry_end = NULL;
+
+ if (gserialized1_payload_bounds(g, &geometry_start, &geometry_end) == LW_FAILURE)
+ return LW_FAILURE;
+ if (gserialized1_validate_geometry_buffer(geometry_start, geometry_end, gserialized1_get_lwflags(g), NULL) ==
+ LW_FAILURE)
+ return LW_FAILURE;
uint32_t isEmpty = (((uint32_t *)geometry_start)[1]) == 0;
if (isEmpty)
@@ -1454,14 +1701,19 @@ LWGEOM* lwgeom_from_gserialized1(const GSERIALIZED *g)
assert(g);
srid = gserialized1_get_srid(g);
- lwtype = gserialized1_get_type(g);
lwflags = gserialized1_get_lwflags(g);
- LWDEBUGF(4, "Got type %d (%s), srid=%d", lwtype, lwtype_name(lwtype), srid);
+ if (gserialized1_payload_bounds(g, &data_ptr, NULL) == LW_FAILURE)
+ {
+ lwerror("%s: invalid GSERIALIZED header size", __func__);
+ return NULL;
+ }
+ if (gserialized1_validate_geometry_buffer(
+ data_ptr, (uint8_t *)g + gserialized1_buffer_size(g), lwflags, NULL) == LW_FAILURE)
+ return NULL;
+ lwtype = gserialized1_get_type(g);
- data_ptr = (uint8_t*)g->data;
- if (FLAGS_GET_BBOX(lwflags))
- data_ptr += gbox_serialized_size(lwflags);
+ LWDEBUGF(4, "Got type %d (%s), srid=%d", lwtype, lwtype_name(lwtype), srid);
lwgeom = lwgeom_from_gserialized1_buffer(data_ptr, lwflags, &size);
@@ -1495,6 +1747,8 @@ const float * gserialized1_get_float_box_p(const GSERIALIZED *g, size_t *ndims)
*ndims = G1FLAGS_NDIMS_BOX(g->gflags);
if (!g) return NULL;
if (!G1FLAGS_GET_BBOX(g->gflags)) return NULL;
+ if (gserialized1_buffer_size(g) < offsetof(GSERIALIZED, data) + gserialized1_box_size(g))
+ return NULL;
return (const float *)(g->data);
}
@@ -1604,4 +1858,3 @@ GSERIALIZED* gserialized1_drop_gbox(GSERIALIZED *g)
return g_out;
}
-
diff --git a/liblwgeom/gserialized2.c b/liblwgeom/gserialized2.c
index ddf8250ed4..e27940fecb 100644
--- a/liblwgeom/gserialized2.c
+++ b/liblwgeom/gserialized2.c
@@ -48,18 +48,43 @@
#include "gserialized2.h"
#include <stddef.h>
+#if defined(__has_feature)
+#if __has_feature(address_sanitizer)
+#define POSTGIS_ASAN_ALLOCATOR_SIZE 1
+#endif
+#endif
+#if defined(__SANITIZE_ADDRESS__)
+#define POSTGIS_ASAN_ALLOCATOR_SIZE 1
+#endif
+#if defined(POSTGIS_ASAN_ALLOCATOR_SIZE)
+#include <sanitizer/allocator_interface.h>
+#endif
/***********************************************************************
* GSERIALIZED metadata utility functions.
*/
static int gserialized2_read_gbox_p(const GSERIALIZED *g, GBOX *gbox);
+static int gserialized2_payload_bounds(const GSERIALIZED *g, uint8_t **start, uint8_t **end);
+static int gserialized2_validate_geometry_buffer(uint8_t *data_ptr, uint8_t *data_end, lwflags_t lwflags, size_t *size);
+static size_t
+gserialized2_buffer_size(const GSERIALIZED *g)
+{
+ size_t gsize = LWSIZE_GET(g->size);
+#if defined(POSTGIS_ASAN_ALLOCATOR_SIZE)
+ size_t allocated_size = __sanitizer_get_allocated_size(g);
+ if (allocated_size > 0 && allocated_size < gsize)
+ return allocated_size;
+#endif
+ return gsize;
+}
lwflags_t gserialized2_get_lwflags(const GSERIALIZED *g)
{
lwflags_t lwflags = 0;
uint8_t gflags = g->gflags;
+ size_t gsize = gserialized2_buffer_size(g);
FLAGS_SET_Z(lwflags, G2FLAGS_GET_Z(gflags));
FLAGS_SET_M(lwflags, G2FLAGS_GET_M(gflags));
FLAGS_SET_BBOX(lwflags, G2FLAGS_GET_BBOX(gflags));
@@ -67,6 +92,11 @@ lwflags_t gserialized2_get_lwflags(const GSERIALIZED *g)
if (G2FLAGS_GET_EXTENDED(gflags))
{
uint64_t xflags = 0;
+ if (gsize < offsetof(GSERIALIZED, data) + sizeof(uint64_t))
+ {
+ lwerror("%s: GSERIALIZED too small for extended flags", __func__);
+ return lwflags;
+ }
memcpy(&xflags, g->data, sizeof(uint64_t));
FLAGS_SET_SOLID(lwflags, xflags & G2FLAG_X_SOLID);
}
@@ -185,24 +215,31 @@ uint32_t gserialized2_max_header_size(void)
uint32_t gserialized2_get_type(const GSERIALIZED *g)
{
uint8_t *ptr = gserialized2_get_geometry_p(g);
+ size_t hsz = gserialized2_header_size(g);
+ size_t gsize = gserialized2_buffer_size(g);
+ if (gsize < hsz + sizeof(uint32_t))
+ {
+ lwerror("%s: GSERIALIZED too small for geometry type", __func__);
+ return 0;
+ }
return *((uint32_t*)(ptr));
}
int32_t gserialized2_get_srid(const GSERIALIZED *g)
{
- int32_t srid = 0;
- srid = srid | (g->srid[0] << 16);
- srid = srid | (g->srid[1] << 8);
- srid = srid | (g->srid[2]);
- /* Only the first 21 bits are set. Slide up and back to pull
- the negative bits down, if we need them. */
- srid = (srid<<11)>>11;
+ uint32_t srid = 0;
+ srid = srid | ((uint32_t)g->srid[0] << 16);
+ srid = srid | ((uint32_t)g->srid[1] << 8);
+ srid = srid | (uint32_t)g->srid[2];
+ /* Only the first 21 bits are set. Sign-extend without signed shift UB. */
+ if (srid & 0x00100000)
+ srid |= 0xFFE00000;
/* 0 is our internal unknown value. We'll map back and forth here for now */
if (srid == 0)
return SRID_UNKNOWN;
else
- return srid;
+ return (int32_t)srid;
}
void gserialized2_set_srid(GSERIALIZED *g, int32_t srid)
@@ -221,6 +258,235 @@ void gserialized2_set_srid(GSERIALIZED *g, int32_t srid)
g->srid[2] = (srid & 0x000000FF);
}
+static int
+gserialized2_range_available(const uint8_t *ptr, const uint8_t *end, size_t len)
+{
+ return ptr <= end && len <= (size_t)(end - ptr);
+}
+
+static int
+gserialized2_checked_mul(size_t a, size_t b, size_t *out)
+{
+ if (a != 0 && b > SIZE_MAX / a)
+ return LW_FAILURE;
+ *out = a * b;
+ return LW_SUCCESS;
+}
+
+static int
+gserialized2_checked_add(size_t a, size_t b, size_t *out)
+{
+ if (b > SIZE_MAX - a)
+ return LW_FAILURE;
+ *out = a + b;
+ return LW_SUCCESS;
+}
+
+static int
+gserialized2_payload_bounds(const GSERIALIZED *g, uint8_t **start, uint8_t **end)
+{
+ size_t hsz;
+ size_t gsize;
+
+ if (!g)
+ return LW_FAILURE;
+
+ hsz = gserialized2_header_size(g);
+ gsize = gserialized2_buffer_size(g);
+ if (gsize < hsz)
+ return LW_FAILURE;
+
+ if (start)
+ *start = (uint8_t *)g + hsz;
+ if (end)
+ *end = (uint8_t *)g + gsize;
+ return LW_SUCCESS;
+}
+
+static uint32_t
+gserialized2_read_uint32_checked(uint8_t *ptr, uint8_t *end, const char *field)
+{
+ uint32_t value = 0;
+ if (!gserialized2_range_available(ptr, end, sizeof(uint32_t)))
+ {
+ lwerror("%s: GSERIALIZED too small for %s", __func__, field);
+ return 0;
+ }
+ memcpy(&value, ptr, sizeof(uint32_t));
+ return value;
+}
+
+static int
+gserialized2_pointarray_payload_size(uint32_t npoints, lwflags_t lwflags, size_t *nbytes)
+{
+ if (gserialized2_checked_mul((size_t)npoints, sizeof(double) * FLAGS_NDIMS(lwflags), nbytes) == LW_FAILURE)
+ {
+ lwerror("%s: GSERIALIZED point count overflows payload size", __func__);
+ return LW_FAILURE;
+ }
+ return LW_SUCCESS;
+}
+
+static int
+gserialized2_validate_geometry_buffer(uint8_t *data_ptr, uint8_t *data_end, lwflags_t lwflags, size_t *size)
+{
+ uint32_t type, count;
+ size_t consumed = 0;
+
+ if (!gserialized2_range_available(data_ptr, data_end, 2 * sizeof(uint32_t)))
+ {
+ lwerror("%s: GSERIALIZED geometry payload is too short", __func__);
+ return LW_FAILURE;
+ }
+
+ type = gserialized2_read_uint32_checked(data_ptr, data_end, "geometry type");
+ count = gserialized2_read_uint32_checked(data_ptr + sizeof(uint32_t), data_end, "geometry count");
+
+ switch (type)
+ {
+ case POINTTYPE:
+ if (count > 1)
+ {
+ lwerror("%s: invalid point count %u", __func__, count);
+ return LW_FAILURE;
+ }
+ /* fall through */
+ case LINETYPE:
+ case CIRCSTRINGTYPE:
+ case TRIANGLETYPE: {
+ size_t point_bytes;
+ if (gserialized2_pointarray_payload_size(count, lwflags, &point_bytes) == LW_FAILURE)
+ return LW_FAILURE;
+ consumed = 2 * sizeof(uint32_t) + point_bytes;
+ break;
+ }
+
+ case POLYGONTYPE: {
+ size_t ring_counts_size, ring_counts_padded_size, point_bytes_sum = 0;
+ uint8_t *ring_counts = data_ptr + 2 * sizeof(uint32_t);
+ uint32_t i;
+
+ if (gserialized2_checked_mul((size_t)count, sizeof(uint32_t), &ring_counts_size) == LW_FAILURE)
+ {
+ lwerror("%s: GSERIALIZED ring count overflows payload size", __func__);
+ return LW_FAILURE;
+ }
+ ring_counts_padded_size = ring_counts_size + ((count % 2) ? sizeof(uint32_t) : 0);
+ if (!gserialized2_range_available(ring_counts, data_end, ring_counts_padded_size))
+ {
+ lwerror("%s: GSERIALIZED polygon ring table exceeds payload size", __func__);
+ return LW_FAILURE;
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ size_t ring_point_bytes;
+ uint32_t npoints = gserialized2_read_uint32_checked(
+ ring_counts + i * sizeof(uint32_t), data_end, "ring point count");
+ if (gserialized2_pointarray_payload_size(npoints, lwflags, &ring_point_bytes) == LW_FAILURE)
+ return LW_FAILURE;
+ if (gserialized2_checked_add(point_bytes_sum, ring_point_bytes, &point_bytes_sum) == LW_FAILURE)
+ {
+ lwerror("%s: GSERIALIZED polygon coordinate size overflows", __func__);
+ return LW_FAILURE;
+ }
+ }
+ consumed = 2 * sizeof(uint32_t) + ring_counts_padded_size;
+ if (gserialized2_checked_add(consumed, point_bytes_sum, &consumed) == LW_FAILURE)
+ {
+ lwerror("%s: GSERIALIZED polygon size overflows", __func__);
+ return LW_FAILURE;
+ }
+ break;
+ }
+
+ case MULTIPOINTTYPE:
+ case MULTILINETYPE:
+ case MULTIPOLYGONTYPE:
+ case COMPOUNDTYPE:
+ case CURVEPOLYTYPE:
+ case MULTICURVETYPE:
+ case MULTISURFACETYPE:
+ case POLYHEDRALSURFACETYPE:
+ case TINTYPE:
+ case COLLECTIONTYPE: {
+ uint32_t i;
+ uint8_t *subgeom_ptr = data_ptr + 2 * sizeof(uint32_t);
+ lwflags_t subflags = lwflags;
+ FLAGS_SET_BBOX(subflags, 0);
+ for (i = 0; i < count; i++)
+ {
+ size_t subsize = 0;
+ uint32_t subtype =
+ gserialized2_read_uint32_checked(subgeom_ptr, data_end, "collection subtype");
+ if (!lwcollection_allows_subtype(type, subtype))
+ {
+ lwerror("Invalid subtype (%s) for collection type (%s)",
+ lwtype_name(subtype),
+ lwtype_name(type));
+ return LW_FAILURE;
+ }
+ if (gserialized2_validate_geometry_buffer(subgeom_ptr, data_end, subflags, &subsize) ==
+ LW_FAILURE)
+ return LW_FAILURE;
+ if (subsize == 0)
+ {
+ lwerror("%s: GSERIALIZED collection member has zero size", __func__);
+ return LW_FAILURE;
+ }
+ subgeom_ptr += subsize;
+ }
+ consumed = (size_t)(subgeom_ptr - data_ptr);
+ break;
+ }
+
+ case NURBSCURVETYPE: {
+ uint32_t nweights, nknots;
+ size_t weight_bytes, knot_bytes, point_bytes;
+ consumed = 6 * sizeof(uint32_t);
+ if (!gserialized2_range_available(data_ptr, data_end, consumed))
+ {
+ lwerror("%s: GSERIALIZED NURBS header exceeds payload size", __func__);
+ return LW_FAILURE;
+ }
+ nweights =
+ gserialized2_read_uint32_checked(data_ptr + 3 * sizeof(uint32_t), data_end, "NURBS weight count");
+ nknots =
+ gserialized2_read_uint32_checked(data_ptr + 4 * sizeof(uint32_t), data_end, "NURBS knot count");
+ if (gserialized2_checked_mul((size_t)nweights, sizeof(double), &weight_bytes) == LW_FAILURE ||
+ gserialized2_checked_mul((size_t)nknots, sizeof(double), &knot_bytes) == LW_FAILURE)
+ {
+ lwerror("%s: GSERIALIZED NURBS vector size overflows", __func__);
+ return LW_FAILURE;
+ }
+ if (gserialized2_pointarray_payload_size(count, lwflags, &point_bytes) == LW_FAILURE)
+ return LW_FAILURE;
+ if (gserialized2_checked_add(consumed, weight_bytes, &consumed) == LW_FAILURE ||
+ gserialized2_checked_add(consumed, knot_bytes, &consumed) == LW_FAILURE ||
+ gserialized2_checked_add(consumed, point_bytes, &consumed) == LW_FAILURE)
+ {
+ lwerror("%s: GSERIALIZED NURBS size overflows", __func__);
+ return LW_FAILURE;
+ }
+ break;
+ }
+
+ default:
+ lwerror("Unknown geometry type: %d - %s", type, lwtype_name(type));
+ return LW_FAILURE;
+ }
+
+ if (!gserialized2_range_available(data_ptr, data_end, consumed))
+ {
+ lwerror("%s: GSERIALIZED geometry payload exceeds declared size", __func__);
+ return LW_FAILURE;
+ }
+
+ if (size)
+ *size = consumed;
+ return LW_SUCCESS;
+}
+
static size_t gserialized2_is_empty_recurse(const uint8_t *p, int *isempty);
static size_t gserialized2_is_empty_recurse(const uint8_t *p, int *isempty)
{
@@ -285,7 +551,14 @@ static size_t gserialized2_is_empty_recurse(const uint8_t *p, int *isempty)
int gserialized2_is_empty(const GSERIALIZED *g)
{
int isempty = LW_TRUE;
- uint8_t *p = gserialized2_get_geometry_p(g);
+ uint8_t *p, *end;
+ if (gserialized2_payload_bounds(g, &p, &end) == LW_FAILURE)
+ {
+ lwerror("%s: invalid GSERIALIZED header size", __func__);
+ return LW_TRUE;
+ }
+ if (gserialized2_validate_geometry_buffer(p, end, gserialized2_get_lwflags(g), NULL) == LW_FAILURE)
+ return LW_TRUE;
gserialized2_is_empty_recurse(p, &isempty);
return isempty;
}
@@ -329,6 +602,8 @@ const float * gserialized2_get_float_box_p(const GSERIALIZED *g, size_t *ndims)
{
uint8_t *ptr = (uint8_t*)(g->data);
size_t bndims = G2FLAGS_NDIMS_BOX(g->gflags);
+ size_t box_offset = offsetof(GSERIALIZED, data);
+ size_t box_size = gserialized2_box_size(g);
if (ndims)
*ndims = bndims;
@@ -339,7 +614,13 @@ const float * gserialized2_get_float_box_p(const GSERIALIZED *g, size_t *ndims)
/* Advance past optional extended flags */
if (gserialized2_has_extended(g))
+ {
ptr += 8;
+ box_offset += 8;
+ }
+
+ if (gserialized2_buffer_size(g) < box_offset + box_size)
+ return NULL;
return (const float *)(ptr);
}
@@ -358,6 +639,8 @@ int gserialized2_read_gbox_p(const GSERIALIZED *g, GBOX *gbox)
{
int i = 0;
const float *fbox = gserialized2_get_float_box_p(g, NULL);
+ if (!fbox)
+ return LW_FAILURE;
gbox->xmin = fbox[i++];
gbox->xmax = fbox[i++];
gbox->ymin = fbox[i++];
@@ -393,10 +676,20 @@ int gserialized2_read_gbox_p(const GSERIALIZED *g, GBOX *gbox)
int
gserialized2_peek_gbox_p(const GSERIALIZED *g, GBOX *gbox)
{
- uint32_t type = gserialized2_get_type(g);
- uint8_t *geometry_start = gserialized2_get_geometry_p(g);
- double *dptr = (double *)(geometry_start);
- int32_t *iptr = (int32_t *)(geometry_start);
+ uint32_t type;
+ uint8_t *geometry_start = NULL;
+ uint8_t *geometry_end = NULL;
+ double *dptr = NULL;
+ int32_t *iptr = NULL;
+
+ if (gserialized2_payload_bounds(g, &geometry_start, &geometry_end) == LW_FAILURE)
+ return LW_FAILURE;
+ if (gserialized2_validate_geometry_buffer(geometry_start, geometry_end, gserialized2_get_lwflags(g), NULL) ==
+ LW_FAILURE)
+ return LW_FAILURE;
+ type = gserialized2_get_type(g);
+ dptr = (double *)(geometry_start);
+ iptr = (int32_t *)(geometry_start);
/* Peeking doesn't help if you already have a box or are geodetic */
if (G2FLAGS_GET_GEODETIC(g->gflags) || G2FLAGS_GET_BBOX(g->gflags))
@@ -581,7 +874,14 @@ gserialized2_copy_point(double *dptr, lwflags_t flags, POINT4D *out_point)
int
gserialized2_peek_first_point(const GSERIALIZED *g, POINT4D *out_point)
{
- uint8_t *geometry_start = gserialized2_get_geometry_p(g);
+ uint8_t *geometry_start = NULL;
+ uint8_t *geometry_end = NULL;
+
+ if (gserialized2_payload_bounds(g, &geometry_start, &geometry_end) == LW_FAILURE)
+ return LW_FAILURE;
+ if (gserialized2_validate_geometry_buffer(geometry_start, geometry_end, gserialized2_get_lwflags(g), NULL) ==
+ LW_FAILURE)
+ return LW_FAILURE;
uint32_t isEmpty = (((uint32_t *)geometry_start)[1]) == 0;
if (isEmpty)
@@ -1542,22 +1842,19 @@ LWGEOM* lwgeom_from_gserialized2(const GSERIALIZED *g)
assert(g);
srid = gserialized2_get_srid(g);
- lwtype = gserialized2_get_type(g);
lwflags = gserialized2_get_lwflags(g);
- LWDEBUGF(4, "Got type %d (%s), srid=%d", lwtype, lwtype_name(lwtype), srid);
-
- data_ptr = (uint8_t*)g->data;
-
- /* Skip optional flags */
- if (G2FLAGS_GET_EXTENDED(g->gflags))
+ if (gserialized2_payload_bounds(g, &data_ptr, NULL) == LW_FAILURE)
{
- data_ptr += sizeof(uint64_t);
+ lwerror("%s: invalid GSERIALIZED header size", __func__);
+ return NULL;
}
+ if (gserialized2_validate_geometry_buffer(
+ data_ptr, (uint8_t *)g + gserialized2_buffer_size(g), lwflags, NULL) == LW_FAILURE)
+ return NULL;
+ lwtype = gserialized2_get_type(g);
- /* Skip over optional bounding box */
- if (FLAGS_GET_BBOX(lwflags))
- data_ptr += gbox_serialized_size(lwflags);
+ LWDEBUGF(4, "Got type %d (%s), srid=%d", lwtype, lwtype_name(lwtype), srid);
lwgeom = lwgeom_from_gserialized2_buffer(data_ptr, lwflags, &size, srid);
-----------------------------------------------------------------------
Summary of changes:
NEWS | 4 +
liblwgeom/cunit/cu_gserialized1.c | 42 +++++
liblwgeom/cunit/cu_gserialized2.c | 131 ++++++++++++++
liblwgeom/gserialized1.c | 301 +++++++++++++++++++++++++++++---
liblwgeom/gserialized2.c | 316 +++++++++++++++++++++++++++++++---
raster/rt_pg/rtpg_raster_properties.c | 8 +-
6 files changed, 749 insertions(+), 53 deletions(-)
hooks/post-receive
--
PostGIS
More information about the postgis-tickets
mailing list