fix: harden DiskANN against type confusion and invalid vector datums - #280
Open
mostafa wants to merge 7 commits into
Open
fix: harden DiskANN against type confusion and invalid vector datums#280mostafa wants to merge 7 commits into
mostafa wants to merge 7 commits into
Conversation
Bind vector DiskANN operator classes with @extschema:vector@ so extension install/upgrade cannot pick up a schema-shadowed non-vector type, and fail loudly if an existing opclass is already bound wrongly.
Require pgvector's vector type before index build/open, reject negative or oversized typmods and inconsistent metapage dimensions, and check detoasted datum size against the embedded dimension before constructing any slice. Also implement amvalidate for the vector DiskANN operator classes.
There was a problem hiding this comment.
Pull request overview
Hardens DiskANN against schema-shadowed vector types and malformed vector/index metadata.
Changes:
- Schema-qualifies pgvector operator classes and validates bindings.
- Adds index type, typmod, metapage, and datum-layout checks.
- Implements operator-class validation.
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 17 comments.
Show a summary per file
| File | Description |
|---|---|
pgvectorscale/src/access_method/vector_type.rs |
Adds vector OID and layout validation. |
pgvectorscale/src/access_method/pg_vector.rs |
Validates detoasted vector data. |
pgvectorscale/src/access_method/mod.rs |
Hardens opclasses and amvalidate. |
pgvectorscale/src/access_method/meta_page.rs |
Validates index metadata on creation/open. |
pgvectorscale/src/access_method/build.rs |
Validates index type and typmod. |
pgvectorscale/sql/vectorscale--0.8.0--0.9.0.sql |
Hardens upgrade opclasses. |
pgvectorscale/sql/vectorscale--0.7.1--0.8.0.sql |
Hardens upgrade opclasses. |
pgvectorscale/sql/vectorscale--0.7.0--0.7.1.sql |
Hardens upgrade opclasses. |
pgvectorscale/sql/vectorscale--0.6.0--0.7.0.sql |
Hardens upgrade opclasses. |
pgvectorscale/sql/vectorscale--0.5.1--0.6.0.sql |
Hardens upgrade opclasses. |
pgvectorscale/sql/vectorscale--0.5.0--0.5.1.sql |
Hardens upgrade opclasses. |
pgvectorscale/sql/vectorscale--0.4.0--0.5.0.sql |
Hardens upgrade opclasses. |
pgvectorscale/sql/vectorscale--0.3.0--0.4.0.sql |
Hardens upgrade opclasses. |
pgvectorscale/sql/vectorscale--0.2.0--0.3.0.sql |
Hardens upgrade opclasses. |
pgvectorscale/sql/vectorscale--0.0.2--0.2.0.sql |
Hardens upgrade opclasses. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Make opclass binding portable across supported PostgreSQL versions, reject stale/malformed type metadata, and add upgrade and regression coverage.
Keep option parsing coverage compatible with the new invariant that indexed dimensions cannot exceed the vector's full dimension.
mostafa
marked this pull request as ready for review
August 12, 2026 13:24
erimatnor
reviewed
Aug 13, 2026
Resolve pgvector objects through safely quoted dynamic SQL while retaining PostgreSQL's standard extension execution context.
Rely on qualified fresh-install bindings and the blocking 0.9.0 upgrade validation instead of runtime checks that cannot observe supported poisoned states.
svenklemm
reviewed
Aug 15, 2026
|
|
||
| -- Register the operator with the system catalogs for proper selectivity estimation | ||
| -- This is done by adding entries to pg_amop for the array_ops operator class | ||
| EXECUTE format( |
Member
There was a problem hiding this comment.
Suggested change
| EXECUTE pg_catalog.format( |
svenklemm
reviewed
Aug 15, 2026
Comment on lines
260
to
263
| SELECT 1 FROM pg_catalog.pg_operator | ||
| WHERE oprname = '&&' | ||
| AND oprleft = 'smallint[]'::regtype | ||
| AND oprright = 'smallint[]'::regtype |
Member
There was a problem hiding this comment.
Suggested change
| SELECT 1 FROM pg_catalog.pg_operator | |
| WHERE oprname = '&&' | |
| AND oprnamespace = '@extschema@'::regnamespace | |
| AND oprleft = 'smallint[]'::regtype | |
| AND oprright = 'smallint[]'::regtype |
Member
|
Keep in mind that amvalidate is not called by postgres to validate, but instead it is used in testing/has to be called explicitly. |
svenklemm
reviewed
Aug 15, 2026
Comment on lines
+35
to
+68
| DO $$ | ||
| DECLARE | ||
| expected_vector_type oid; | ||
| BEGIN | ||
| SELECT t.oid | ||
| INTO STRICT expected_vector_type | ||
| FROM pg_catalog.pg_extension e | ||
| JOIN pg_catalog.pg_type t | ||
| ON t.typnamespace = e.extnamespace | ||
| AND t.typname = 'vector' | ||
| WHERE e.extname = 'vector'; | ||
|
|
||
| IF EXISTS ( | ||
| SELECT 1 | ||
| FROM pg_catalog.pg_opclass c | ||
| JOIN pg_catalog.pg_am am ON am.oid = c.opcmethod | ||
| WHERE am.amname = 'diskann' | ||
| AND c.opcnamespace = ( | ||
| SELECT oid | ||
| FROM pg_catalog.pg_namespace | ||
| WHERE nspname = '@extschema@' | ||
| ) | ||
| AND c.opcname IN ( | ||
| 'vector_cosine_ops', | ||
| 'vector_l2_ops', | ||
| 'vector_ip_ops' | ||
| ) | ||
| AND c.opcintype IS DISTINCT FROM expected_vector_type | ||
| ) THEN | ||
| RAISE EXCEPTION | ||
| 'diskann: a vector operator class is not bound to pgvector''s vector type; drop the affected operator class and recreate the extension objects'; | ||
| END IF; | ||
| END; | ||
| $$; |
Member
There was a problem hiding this comment.
looks like this doesnt catch all variants:
CREATE SCHEMA real_vector;
CREATE EXTENSION vector WITH SCHEMA real_vector;
CREATE SCHEMA evil;
CREATE FUNCTION evil.fake_dist(real_vector.vector, real_vector.vector)
RETURNS float8 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
AS $$ SELECT 0::float8 $$;
CREATE OPERATOR evil.<=> (
LEFTARG = real_vector.vector, -- genuine
RIGHTARG = real_vector.vector, -- genuine
FUNCTION = evil.fake_dist);
CREATE EXTENSION vectorscale VERSION '0.9.0' WITH SCHEMA evil;
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
search_path.amvalidatefor the vector DiskANN operator classes.Vulnerability
DiskANN operator-class SQL used unqualified
vector/operators, so a pre-created type in the extension target schema could capture the binding. Combined with unvalidated typmod-to-dimension conversion and using the embeddeddimas a slice length without a size check, attacker-controlled bytes could reach native DiskANN paths, causing a backend crash, memory disclosure, or out-of-bounds write. Further privilege-escalation impact was reported for the detoast path.Root cause
Why this change is safe
vector(N)indexes retain positive typmods and matching datum layouts, so the native checks are no-ops for supported configurations.Potential side effects
vector(N)typmod can no longer create DiskANN indexes.Validation
amvalidate.