Обсуждение: [PATCH] intarray: prevent crash in _int_matchsel on invalid query_int input
[PATCH] intarray: prevent crash in _int_matchsel on invalid query_int input
От
Eugeny Goryachev
Дата:
Hi,
The selectivity function _int_matchsel() in contrib/intarray
assumes that the right-hand argument is a valid query_int datum.
If a malformed or binary-incompatible value is passed (for example,
via an implicit cast from a user-defined type created WITHOUT FUNCTION),
the function may dereference an invalid pointer and crash.
Specifically, _int_matchsel() calls DatumGetQueryTypeP() and
immediately accesses the resulting structure without validating
the datum size or structure integrity.
This patch adds a minimal size check before dereferencing the
query pointer. If the datum is not a valid query_int value,
an ERROR with ERRCODE_DATATYPE_MISMATCH is raised instead of
causing a backend crash.
A regression test is included to demonstrate the issue using a
fake type that is implicitly cast to query_int.
Patch attached.
Regards,
Eugeny Goryachev
From f7f108be286872e7e380e0f11b636d03407758c4 Mon Sep 17 00:00:00 2001
The selectivity function _int_matchsel() in contrib/intarray
assumes that the right-hand argument is a valid query_int datum.
If a malformed or binary-incompatible value is passed (for example,
via an implicit cast from a user-defined type created WITHOUT FUNCTION),
the function may dereference an invalid pointer and crash.
Specifically, _int_matchsel() calls DatumGetQueryTypeP() and
immediately accesses the resulting structure without validating
the datum size or structure integrity.
This patch adds a minimal size check before dereferencing the
query pointer. If the datum is not a valid query_int value,
an ERROR with ERRCODE_DATATYPE_MISMATCH is raised instead of
causing a backend crash.
A regression test is included to demonstrate the issue using a
fake type that is implicitly cast to query_int.
Patch attached.
Regards,
Eugeny Goryachev
From f7f108be286872e7e380e0f11b636d03407758c4 Mon Sep 17 00:00:00 2001
From: Eugeny Goryachev <e.goryachev@mti-lab.com>
Date: Wed, 4 Mar 2026 12:22:33 +0300
Subject: [PATCH] Fix intarray segfault
---
contrib/intarray/Makefile | 4 +-
contrib/intarray/_int_selfuncs.c | 5 +++
contrib/intarray/expected/fake_query_type.out | 38 ++++++++++++++++
contrib/intarray/sql/fake_query_type.sql | 43 +++++++++++++++++++
4 files changed, 89 insertions(+), 1 deletion(-)
create mode 100644 contrib/intarray/expected/fake_query_type.out
create mode 100644 contrib/intarray/sql/fake_query_type.sql
diff --git a/contrib/intarray/Makefile b/contrib/intarray/Makefile
index 3817c1669ab..c064c091047 100644
--- a/contrib/intarray/Makefile
+++ b/contrib/intarray/Makefile
@@ -17,7 +17,9 @@ DATA = intarray--1.4--1.5.sql intarray--1.3--1.4.sql intarray--1.2--1.3.sql \
intarray--1.0--1.1.sql
PGFILEDESC = "intarray - functions and operators for arrays of integers"
-REGRESS = _int
+REGRESS = \
+ _int \
+ fake_query_type
ifdef USE_PGXS
PG_CONFIG = pg_config
diff --git a/contrib/intarray/_int_selfuncs.c b/contrib/intarray/_int_selfuncs.c
index f75da3a09d2..26e715cfce6 100644
--- a/contrib/intarray/_int_selfuncs.c
+++ b/contrib/intarray/_int_selfuncs.c
@@ -186,6 +186,11 @@ _int_matchsel(PG_FUNCTION_ARGS)
query = DatumGetQueryTypeP(((Const *) other)->constvalue);
+ if (VARSIZE(query) < HDRSIZEQT)
+ ereport(ERROR,
+ (errcode(ERRCODE_DATATYPE_MISMATCH),
+ errmsg("argument must be of type querytype")));
+
/* Empty query matches nothing */
if (query->size == 0)
{
diff --git a/contrib/intarray/expected/fake_query_type.out b/contrib/intarray/expected/fake_query_type.out
new file mode 100644
index 00000000000..c3cc64eb2dd
--- /dev/null
+++ b/contrib/intarray/expected/fake_query_type.out
@@ -0,0 +1,38 @@
+-- test for missing type validation in _int_matchsel
+CREATE FUNCTION fake_query_int_in(cstring)
+RETURNS fake_query_int
+AS 'textin'
+LANGUAGE internal IMMUTABLE STRICT;
+NOTICE: type "fake_query_int" is not yet defined
+DETAIL: Creating a shell type definition.
+CREATE FUNCTION fake_query_int_out(fake_query_int)
+RETURNS cstring
+AS 'textout'
+LANGUAGE internal IMMUTABLE STRICT;
+NOTICE: argument type fake_query_int is only a shell
+CREATE TYPE fake_query_int (
+ INPUT = fake_query_int_in,
+ OUTPUT = fake_query_int_out,
+ LIKE = text
+);
+CREATE CAST (fake_query_int AS query_int)
+WITHOUT FUNCTION
+AS IMPLICIT;
+CREATE OR REPLACE FUNCTION fake_query_int_match(integer[], fake_query_int)
+RETURNS boolean
+AS $$
+ SELECT $1 @@ $2::query_int;
+$$ LANGUAGE sql IMMUTABLE;
+CREATE OPERATOR @@ (
+ LEFTARG = integer[],
+ RIGHTARG = fake_query_int,
+ PROCEDURE = fake_query_int_match,
+ RESTRICT = _int_matchsel
+);
+CREATE TABLE test_arr (
+ id serial,
+ arr integer[]
+);
+SELECT * FROM test_arr
+WHERE arr @@ '1&2'::fake_query_int;
+ERROR: argument must be of type querytype
diff --git a/contrib/intarray/sql/fake_query_type.sql b/contrib/intarray/sql/fake_query_type.sql
new file mode 100644
index 00000000000..a36c6eee1d4
--- /dev/null
+++ b/contrib/intarray/sql/fake_query_type.sql
@@ -0,0 +1,43 @@
+-- test for missing type validation in _int_matchsel
+
+CREATE FUNCTION fake_query_int_in(cstring)
+RETURNS fake_query_int
+AS 'textin'
+LANGUAGE internal IMMUTABLE STRICT;
+
+CREATE FUNCTION fake_query_int_out(fake_query_int)
+RETURNS cstring
+AS 'textout'
+LANGUAGE internal IMMUTABLE STRICT;
+
+CREATE TYPE fake_query_int (
+ INPUT = fake_query_int_in,
+ OUTPUT = fake_query_int_out,
+ LIKE = text
+);
+
+CREATE CAST (fake_query_int AS query_int)
+WITHOUT FUNCTION
+AS IMPLICIT;
+
+CREATE OR REPLACE FUNCTION fake_query_int_match(integer[], fake_query_int)
+RETURNS boolean
+AS $$
+ SELECT $1 @@ $2::query_int;
+$$ LANGUAGE sql IMMUTABLE;
+
+CREATE OPERATOR @@ (
+ LEFTARG = integer[],
+ RIGHTARG = fake_query_int,
+ PROCEDURE = fake_query_int_match,
+ RESTRICT = _int_matchsel
+);
+
+
+CREATE TABLE test_arr (
+ id serial,
+ arr integer[]
+);
+
+SELECT * FROM test_arr
+WHERE arr @@ '1&2'::fake_query_int;
--
2.42.4
Eugeny Goryachev <gorcom2012@gmail.com> writes:
> The selectivity function _int_matchsel() in contrib/intarray
> assumes that the right-hand argument is a valid query_int datum.
> If a malformed or binary-incompatible value is passed (for example,
> via an implicit cast from a user-defined type created WITHOUT FUNCTION),
> the function may dereference an invalid pointer and crash.
Didn't we fix that in CVE-2026-2004?
regards, tom lane