[SCM] PostGIS branch stable-3.2 updated. 3.2.10-6-g69525adbe
git at osgeo.org
git at osgeo.org
Mon Jun 8 16:45:45 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 69525adbe50c6f70eb7198d8aad88e4e64c9d111 (commit)
via c800a006fe796d913ec8463c693a3c11655bbdab (commit)
from 94610531f03c30c733853704569ba1bd963151d8 (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 69525adbe50c6f70eb7198d8aad88e4e64c9d111
Author: Paul Ramsey <pramsey at cleverelephant.ca>
Date: Mon Jun 8 15:55:39 2026 -0700
NEWS item for flatgeobuf fix
diff --git a/NEWS b/NEWS
index 91cb13bd6..01e2752ca 100644
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,7 @@ PostGIS 3.2.11
* Bug Fixes *
- #5899, pg_upgrade issue for non-standard geography SRID (Paul Ramsey)
+ - Flatgeobuf schema mismatch vulnerability (NeuroWinter)
PostGIS 3.2.10
commit c800a006fe796d913ec8463c693a3c11655bbdab
Author: Paul Ramsey <pramsey at cleverelephant.ca>
Date: Wed May 27 21:52:25 2026 +0000
Check that user-provided flatbuffer schema matches
The flatbuffer import maps an incoming file to a provided
table schema, and the consistency of those two schemes
needs to be checked before data are copied across.
diff --git a/postgis/flatgeobuf.c b/postgis/flatgeobuf.c
index 545442f31..d8eea1562 100644
--- a/postgis/flatgeobuf.c
+++ b/postgis/flatgeobuf.c
@@ -288,8 +288,6 @@ static void decode_properties(struct flatgeobuf_decode_ctx *ctx, Datum *values,
POSTGIS_DEBUGF(3, "flatgeobuf: decode_properties from byte array with length %d at offset %d", size, offset);
- // TODO: init isnull
-
if (size > 0 && size < (sizeof(uint16_t) + sizeof(uint8_t)))
elog(ERROR, "flatgeobuf: decode_properties: Unexpected properties data size %d", size);
while (offset + 1 < size) {
@@ -390,7 +388,10 @@ static void decode_properties(struct flatgeobuf_decode_ctx *ctx, Datum *values,
if (offset + sizeof(float) > size)
elog(ERROR, "flatgeobuf: decode_properties: Invalid size for float value");
memcpy(&value, data + offset, sizeof(float));
- values[ci] = Float4GetDatum(value);
+ if (getBaseType(TupleDescAttr(ctx->tupdesc, ci)->atttypid) == FLOAT8OID)
+ values[ci] = Float8GetDatum((double) value);
+ else
+ values[ci] = Float4GetDatum(value);
offset += sizeof(float);
break;
}
@@ -459,9 +460,10 @@ void flatgeobuf_decode_row(struct flatgeobuf_decode_ctx *ctx)
HeapTuple heapTuple;
uint32_t natts = ctx->tupdesc->natts;
- Datum *values = palloc0(natts * sizeof(Datum *));
- bool *isnull = palloc0(natts * sizeof(bool *));
-
+ Datum *values = palloc0(natts * sizeof(Datum));
+ bool *isnull = palloc0(natts * sizeof(bool));
+ for (uint32_t j = 0; j < natts; j++) isnull[j] = true;
+ isnull[0] = false;
values[0] = Int32GetDatum(ctx->fid);
if (flatgeobuf_decode_feature(ctx->ctx))
@@ -469,6 +471,7 @@ void flatgeobuf_decode_row(struct flatgeobuf_decode_ctx *ctx)
if (ctx->ctx->lwgeom != NULL) {
values[1] = PointerGetDatum(geometry_serialize(ctx->ctx->lwgeom));
+ isnull[1] = false;
} else {
POSTGIS_DEBUG(3, "geometry is null");
isnull[1] = true;
diff --git a/postgis/lwgeom_in_flatgeobuf.c b/postgis/lwgeom_in_flatgeobuf.c
index ac460ff7a..773b50f98 100644
--- a/postgis/lwgeom_in_flatgeobuf.c
+++ b/postgis/lwgeom_in_flatgeobuf.c
@@ -67,6 +67,60 @@ static char *get_pgtype(uint8_t column_type) {
elog(ERROR, "unknown column_type %d", column_type);
}
+static const char *
+flatgeobuf_type_name(uint8_t fgb_type)
+{
+ /* Names match FlatGeobuf::EnumNamesColumnType() in header_generated.h */
+ static const char * const names[] = {
+ "Byte", "UByte", "Bool", "Short", "UShort",
+ "Int", "UInt", "Long", "ULong",
+ "Float", "Double", "String", "Json", "DateTime", "Binary"
+ };
+ if (fgb_type >= sizeof(names) / sizeof(names[0]))
+ return "unknown";
+ return names[fgb_type];
+}
+
+static bool
+flatgeobuf_type_compatible(uint8_t fgb_type, Oid pgtype)
+{
+ switch (fgb_type)
+ {
+ case flatgeobuf_column_type_bool:
+ return pgtype == BOOLOID;
+ /* small integer types: allow widening into larger signed ints */
+ case flatgeobuf_column_type_byte:
+ case flatgeobuf_column_type_ubyte:
+ case flatgeobuf_column_type_short:
+ case flatgeobuf_column_type_ushort:
+ return pgtype == INT2OID || pgtype == INT4OID || pgtype == INT8OID;
+ /* int32: allow widening to bigint */
+ case flatgeobuf_column_type_int:
+ return pgtype == INT4OID || pgtype == INT8OID;
+ /* uint32 max exceeds INT4, must land in bigint */
+ case flatgeobuf_column_type_uint:
+ return pgtype == INT8OID;
+ case flatgeobuf_column_type_long:
+ case flatgeobuf_column_type_ulong:
+ return pgtype == INT8OID;
+ /* float: allow widening to double (explicit conversion handled in decode) */
+ case flatgeobuf_column_type_float:
+ return pgtype == FLOAT4OID || pgtype == FLOAT8OID;
+ case flatgeobuf_column_type_double:
+ return pgtype == FLOAT8OID;
+ case flatgeobuf_column_type_string:
+ return pgtype == TEXTOID || pgtype == VARCHAROID;
+ case flatgeobuf_column_type_datetime:
+ return pgtype == DATEOID || pgtype == TIMEOID ||
+ pgtype == TIMESTAMPOID || pgtype == TIMESTAMPTZOID;
+ case flatgeobuf_column_type_json:
+ return pgtype == JSONBOID;
+ case flatgeobuf_column_type_binary:
+ return pgtype == BYTEAOID;
+ }
+ return false;
+}
+
PG_FUNCTION_INFO_V1(pgis_tablefromflatgeobuf);
Datum pgis_tablefromflatgeobuf(PG_FUNCTION_ARGS)
{
@@ -192,7 +246,29 @@ Datum pgis_fromflatgeobuf(PG_FUNCTION_ARGS)
SRF_RETURN_DONE(funcctx);
}
- // TODO: get table and verify structure against header
+ /* Validate that the file schema matches the caller-supplied composite type.
+ * tupdesc positions 0 (fid) and 1 (geom) are fixed; file columns start at 2. */
+ if (ctx->ctx->columns_size != (uint32_t)(tupdesc->natts - 2))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATATYPE_MISMATCH),
+ errmsg("flatgeobuf: column count mismatch: "
+ "file has %u columns, target type has %d",
+ ctx->ctx->columns_size, tupdesc->natts - 2)));
+
+ for (uint16_t col_i = 0; col_i < ctx->ctx->columns_size; col_i++)
+ {
+ flatgeobuf_column *col = ctx->ctx->columns[col_i];
+ Oid pgtype = getBaseType(TupleDescAttr(tupdesc, col_i + 2)->atttypid);
+ if (!flatgeobuf_type_compatible(col->type, pgtype))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATATYPE_MISMATCH),
+ errmsg("flatgeobuf: column \"%s\" type mismatch: "
+ "file type \"%s\" is not compatible with PostgreSQL type %s",
+ col->name,
+ flatgeobuf_type_name(col->type),
+ format_type_be(pgtype))));
+ }
+
MemoryContextSwitchTo(oldcontext);
}
-----------------------------------------------------------------------
Summary of changes:
NEWS | 1 +
postgis/flatgeobuf.c | 15 ++++----
postgis/lwgeom_in_flatgeobuf.c | 78 +++++++++++++++++++++++++++++++++++++++++-
3 files changed, 87 insertions(+), 7 deletions(-)
hooks/post-receive
--
PostGIS
More information about the postgis-tickets
mailing list