jrgemignani opened a new pull request, #2561:
URL: https://github.com/apache/age/pull/2561

   The global graph cache that backs variable-length edge (VLE) and 
shortest-path traversal is populated with a direct heap scan (table_beginscan + 
heap_getnext). That scan does not go through the planner or executor, so the 
row-level security policies and table privileges that MATCH receives 
automatically are not applied to traversal: it reads every vertex and edge 
regardless of the current role's policies or grants.
   
   Add age.enforce_rls_in_traversal (bool, PGC_SUSET, default on). When on:
   
   * SELECT privilege is checked on every label table before it is read 
(pg_class_aclcheck, with a pg_attribute_aclcheck fallback so column-level 
grants are honored the same way the executor honors them).
   
   * When RLS is active on a label for the current role, that label is loaded 
through SPI (SELECT ... FROM ONLY <label>) with a batched read-only cursor so 
the planner applies the policies. Otherwise the direct-scan path is used, now 
behind the privilege check. Properties are still fetched lazily by TID: only 
policy-visible rows are loaded, so the later heap_fetch reads only authorized 
tuples, which covers shortest_path as well.
   
   When off, the previous direct-scan behavior is restored, leaving operators a 
single escape hatch.
   
   To match MATCH's inner-join behavior, the edge loaders drop any edge whose 
start or end vertex was filtered out by a vertex policy rather than leaving a 
dangling edge in the cache.
   
   Cache validity:
   
   * A cache that applied RLS is not reused across statements 
(loaded_with_rls), because policies can depend on session state such as 
current_setting() that is not covered by the version, snapshot, role, and GUC 
cache keys. Graphs that do not use RLS are unaffected.
   
   * is_ggctx_invalid checks the role and GUC keys before the graph 
version-counter fast path, so a role or GUC change forces a rebuild even in 
DSM/SHMEM mode.
   
   * The version counter tracks only graph data changes, so an enforced non-RLS 
cache could otherwise survive a GRANT/REVOKE or policy/RLS DDL on a label table 
and serve stale permissions. A relcache callback keyed by label-table OID 
(table/column privileges, policies, RLS flags), plus pg_authid and 
pg_auth_members syscache callbacks (BYPASSRLS, role membership), now mark such 
caches stale so they are rebuilt and re-authorized.
   
   Re-entrancy and cleanup:
   
   * The context is built detached and attached only after a successful load, 
so a policy expression that re-enters traversal cannot observe a half-built 
cache, and a failed load frees the partial context instead of leaving it in 
TopMemoryContext.
   
   * On attach, an existing context for the same graph is reused only if it is 
still valid for the current role and GUC, so a re-entrant traversal reached 
through a SECURITY DEFINER policy cannot be handed a context loaded as another 
role. If discarding an incompatible context reports a missing entry, that error 
is raised after first freeing the freshly built context.
   
   * Each loader frees the transient label-name list from get_ag_labels_names() 
on both the normal and error paths; it is allocated in TopMemoryContext and 
would otherwise accumulate on every rebuild.
   
   Adds regression test rls_vle covering policy and privilege enforcement, the 
opt-out GUC, per-role cache invalidation, a session current_setting() policy, 
and privilege-metadata invalidation.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to