BUG with accessing to temporary tables of other sessions still exists

First seen: 2026-06-03 13:23:20+00:00 · Messages: 5 · Participants: 3

Latest Update

2026-06-04 · claude-opus-4-6

BUG: Accessing Temporary Tables of Other Sessions via Relation Extension Path

Core Problem

PostgreSQL's temporary table isolation has a gap in its enforcement mechanism. Two prior commits (40927d458fe1 and ce146621f786) added checks to prevent sessions from accessing temporary tables belonging to other sessions, but they placed these checks in ReadBufferExtended. This left an uncovered code path: when a table has zero pages (is empty), the first INSERT doesn't go through ReadBufferExtended at all.

The Architectural Root Cause

The insert path for an empty relation follows:

heap_insert → RelationGetBufferForTuple → RelationAddBlocks → ExtendBufferedRelLocal

When extending a relation (adding new blocks), PostgreSQL bypasses the buffer read path entirely — it extends the relation's storage via smgr and allocates a new buffer directly. This means:

  1. The RELATION_IS_OTHER_TEMP check in ReadBufferExtended is never hit — the code path for extending a relation doesn't read existing blocks; it creates new ones.
  2. A local temp buffer is allocated in the wrong session's buffer pool — the extending session creates a buffer in its own temp_buffers pool for a relation whose physical files belong to another session's temporary tablespace.
  3. Subsequent flush attempts fail catastrophically — when the buffer manager tries to write back this buffer, it attempts to open a file path (e.g., base/5/t3_16386) that doesn't exist in the current session's context, producing ERROR: could not open file.

The second INSERT does fail with the correct error because by then the relation has a page (the one just created), so the code takes the ReadBufferExtended path to find free space on existing pages, hitting the existing check.

Why This Matters Architecturally

PostgreSQL's temp buffer system is fundamentally session-local by design. Each backend maintains its own pool of temporary buffers (temp_buffers) that are never shared via the shared buffer pool. The physical files for temporary relations use session-specific naming (the t prefix with a backend-specific path). Cross-session access to these structures is not just a permissions issue — it's architecturally impossible to do correctly without fundamental redesign. The existing checks are guardrails preventing data corruption and confusing errors, not policy enforcement.

Proposed Solution

The patch adds a RELATION_IS_OTHER_TEMP check inside ExtendBufferedRelLocal() (in src/backend/storage/buffer/localbuf.c). This is strategically chosen because:

The fix is minimal and surgical: a single RELATION_IS_OTHER_TEMP check with the standard error message, placed before any buffer allocation or smgr extension occurs.

Key Design Decisions and Tradeoffs

Why DROP of Other Session's Temp Tables Is Allowed

An important nuance emerges in the discussion: while data access (reading/writing pages) to other sessions' temp tables is prohibited, catalog operations like DROP are intentionally permitted. The rationale is:

  1. The prohibition is technical, not policy-based — the temp_buffers implementation cannot handle cross-session page access; DROP doesn't need to read data pages.
  2. Autovacuum needs this capability — orphaned temporary table cleanup requires the ability to drop temp tables whose owning session has crashed or disconnected.
  3. Administrative use cases exist — DBAs may need to clean up abandoned temp tables.

This distinction (catalog-level operations are fine; page-level access is not) is a deliberate architectural decision documented in the test suite (013_temp_obj_multisession.pl).

Check Placement Strategy

The choice to put the check in ExtendBufferedRelLocal rather than higher up (e.g., in heap_insert or RelationGetBufferForTuple) follows the principle of defense-in-depth at the storage layer boundary. This prevents not just INSERT but any operation that might extend a temp relation (COPY, bulk loading, index creation on temp tables, etc.) from bypassing the check.

Patch Versions