public inbox for [email protected]  
help / color / mirror / Atom feed
From: Jim Jones <[email protected]>
To: Soumya S Murali <[email protected]>
To: Daniil Davydov <[email protected]>
Cc: Tom Lane <[email protected]>
Cc: Stepan Neretin <[email protected]>
Cc: PostgreSQL Hackers <[email protected]>
Subject: Re: Fix bug with accessing to temporary tables of other sessions
Date: Mon, 13 Apr 2026 15:56:09 +0200
Message-ID: <[email protected]> (raw)
In-Reply-To: <CAMtXxw_hBNuAWQUdSRMpoeRVRYr+5+S7p0bSzuqtHxfpzJPd3w@mail.gmail.com>
References: <CAJDiXghdFcZ8=nh4G69te7iRr3Q0uFyXxb3ZdG09_GTNZXwH0g@mail.gmail.com>
	<CAMtXxw_ta_9i=uPJMvGueOBc04crmraJXcyJhN0K=Wu9aa2rog@mail.gmail.com>
	<[email protected]>
	<[email protected]>
	<CAJDiXgh9g4TEyF3kWCiBgHX6QbpATZtxTfrQuBCKxUO5=nZBOw@mail.gmail.com>
	<[email protected]>
	<CAJDiXgihovkP6DMAFyJtYF4JSAjvKmiRVbF5R5n3SA=Yag32_w@mail.gmail.com>
	<CAMtXxw8pHLH9+mG3wxsF8f=Y+pHqTNP8X1UmZQPkRL9pZ5aF2w@mail.gmail.com>
	<[email protected]>
	<[email protected]>
	<CAJDiXgiAObr4c+PTWSS19vcohrFSDLK3MC5FK3TekMB3U3DjfQ@mail.gmail.com>
	<[email protected]>
	<CAJDiXghBO_TqvHOSui8MOxiFmwLT20+SAnH5nW1rpWHk7Jwffg@mail.gmail.com>
	<[email protected]>
	<CAJDiXgi0JFk0f2KWWQkzLBC5P7erX9WP18qqnbi-rjZ-K-P=3w@mail.gmail.com>
	<CAMtXxw_hBNuAWQUdSRMpoeRVRYr+5+S7p0bSzuqtHxfpzJPd3w@mail.gmail.com>

Hi

On 13/04/2026 14:40, Soumya S Murali wrote:
> Please let me know if there are additional scenarios I should
> validate. Looking forward to more feedback.

Thanks for testing it. You can take a look at
012_temp_obj_multisession.pl and check if we missed any path.

Due to changes introduced in b2a17ba7a5d the patch was no longer
applying. See rebased v18 attached.

Best, Jim



Attachments:

  [text/x-patch] v18-0002-Test-cross-session-access-on-temporary-tables.patch (4.3K, 2-v18-0002-Test-cross-session-access-on-temporary-tables.patch)
  download | inline diff:
From 88a3cd38d035075ef09c923ab3c7f358389e1022 Mon Sep 17 00:00:00 2001
From: Jim Jones <[email protected]>
Date: Mon, 13 Apr 2026 15:28:35 +0200
Subject: [PATCH v18 2/2] Test cross-session access on temporary tables

---
 src/test/modules/test_misc/meson.build        |   1 +
 .../test_misc/t/012_temp_obj_multisession.pl  | 109 ++++++++++++++++++
 2 files changed, 110 insertions(+)
 create mode 100644 src/test/modules/test_misc/t/012_temp_obj_multisession.pl

diff --git a/src/test/modules/test_misc/meson.build b/src/test/modules/test_misc/meson.build
index 1b25d98f7f3..a54599cc301 100644
--- a/src/test/modules/test_misc/meson.build
+++ b/src/test/modules/test_misc/meson.build
@@ -20,6 +20,7 @@ tests += {
       't/009_log_temp_files.pl',
       't/010_index_concurrently_upsert.pl',
       't/011_lock_stats.pl',
+      't/012_temp_obj_multisession.pl',
     ],
     # The injection points are cluster-wide, so disable installcheck
     'runningcheck': false,
diff --git a/src/test/modules/test_misc/t/012_temp_obj_multisession.pl b/src/test/modules/test_misc/t/012_temp_obj_multisession.pl
new file mode 100644
index 00000000000..fa8037e4d1e
--- /dev/null
+++ b/src/test/modules/test_misc/t/012_temp_obj_multisession.pl
@@ -0,0 +1,109 @@
+# Copyright (c) 2026, PostgreSQL Global Development Group
+
+use strict;
+use warnings;
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+use PostgreSQL::Test::BackgroundPsql;
+use Test::More;
+
+# Set up a fresh node
+my $node = PostgreSQL::Test::Cluster->new('temp_lock');
+$node->init;
+$node->start;
+
+# Create a long-lived session
+my $psql1 = $node->background_psql('postgres');
+
+$psql1->query_safe(q(CREATE TEMP TABLE foo AS SELECT 42 AS val;));
+
+$psql1->query_safe(q(CREATE INDEX ON foo(val);));
+
+my $tempschema = $node->safe_psql(
+	'postgres',
+	q{
+      SELECT n.nspname
+      FROM pg_class c
+      JOIN pg_namespace n ON n.oid = c.relnamespace
+      WHERE relname = 'foo' AND relpersistence = 't';
+    }
+);
+chomp $tempschema;
+ok($tempschema =~ /^pg_temp_\d+$/, "got temp schema: $tempschema");
+
+
+# SELECT TEMPORARY TABLE from other session
+my ($stdout, $stderr);
+$node->psql(
+	'postgres',
+	"SELECT val FROM $tempschema.foo;",
+	stdout => \$stdout,
+	stderr => \$stderr);
+like(
+	$stderr,
+	qr/cannot access temporary relations of other sessions/,
+	'SELECT on other session temp table is not allowed');
+
+# UPDATE TEMPORARY TABLE from other session
+$node->psql(
+	'postgres',
+	"UPDATE $tempschema.foo SET val = NULL;",
+	stderr => \$stderr);
+like(
+	$stderr,
+	qr/cannot access temporary relations of other sessions/,
+	'UPDATE on other session temp table is not allowed');
+
+# DELETE records from TEMPORARY TABLE from other session
+$node->psql('postgres', "DELETE FROM $tempschema.foo;", stderr => \$stderr);
+like(
+	$stderr,
+	qr/cannot access temporary relations of other sessions/,
+	'DELETE on other session temp table is not allowed');
+
+# TRUNCATE TEMPORARY TABLE from other session
+$node->psql('postgres', "TRUNCATE TABLE $tempschema.foo;",
+	stderr => \$stderr);
+like(
+	$stderr,
+	qr/cannot truncate temporary tables of other sessions/,
+	'TRUNCATE on other session temp table is not allowed');
+
+# INSERT INTO TEMPORARY TABLE from other session
+$node->psql(
+	'postgres',
+	"INSERT INTO $tempschema.foo VALUES (73);",
+	stderr => \$stderr);
+like(
+	$stderr,
+	qr/cannot access temporary relations of other sessions/,
+	'INSERT INTO on other session temp table is not allowed');
+
+# COPY TEMPORARY TABLE from other session
+$node->psql('postgres', "COPY $tempschema.foo TO STDOUT;",
+	stderr => \$stderr);
+like(
+	$stderr,
+	qr/cannot access temporary relations of other sessions/,
+	'COPY on other session temp table is blocked');
+
+# Index scans can use a different code path from the one sequential scans are
+# following. Make sure that we cannot access other sessions' temp tables during
+# index scan either.
+$node->psql(
+	'postgres',
+	"SET enable_seqscan = off; SELECT val FROM $tempschema.foo WHERE val = 42;",
+	stderr => \$stderr);
+like(
+	$stderr,
+	qr/cannot access temporary relations of other sessions/,
+	'index scan on other session temp table is not allowed (exercises ReadBufferExtended path)'
+);
+
+# DROP TEMPORARY TABLE from other session
+$node->safe_psql('postgres', "DROP TABLE $tempschema.foo;");
+
+# Clean up
+$psql1->quit;
+
+done_testing();
-- 
2.43.0



  [text/x-patch] v18-0001-Prevent-access-to-other-sessions-temp-tables.patch (3.2K, 3-v18-0001-Prevent-access-to-other-sessions-temp-tables.patch)
  download | inline diff:
From 635e924e26a772ddccaecc52cb994650f261c290 Mon Sep 17 00:00:00 2001
From: Jim Jones <[email protected]>
Date: Mon, 13 Apr 2026 15:17:20 +0200
Subject: [PATCH v18 1/2] Prevent access to other sessions' temp tables

---
 src/backend/storage/aio/read_stream.c | 10 ++++++++++
 src/backend/storage/buffer/bufmgr.c   | 16 ++++++++++++++--
 2 files changed, 24 insertions(+), 2 deletions(-)

diff --git a/src/backend/storage/aio/read_stream.c b/src/backend/storage/aio/read_stream.c
index 2374b4cd507..6ba6774af95 100644
--- a/src/backend/storage/aio/read_stream.c
+++ b/src/backend/storage/aio/read_stream.c
@@ -776,6 +776,16 @@ read_stream_begin_impl(int flags,
 	uint32		max_possible_buffer_limit;
 	Oid			tablespace_id;
 
+	/*
+	 * Reject attempts to read non-local temporary relations; we would be
+	 * likely to get wrong data since we have no visibility into the owning
+	 * session's local buffers.
+	 */
+	if (rel && RELATION_IS_OTHER_TEMP(rel))
+		ereport(ERROR,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("cannot access temporary relations of other sessions")));
+
 	/*
 	 * Decide how many I/Os we will allow to run at the same time.  This
 	 * number also affects how far we look ahead for opportunities to start
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index 3cc0b0bdd92..70353f1f8e3 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -795,7 +795,7 @@ PrefetchBuffer(Relation reln, ForkNumber forkNum, BlockNumber blockNum)
 		if (RELATION_IS_OTHER_TEMP(reln))
 			ereport(ERROR,
 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-					 errmsg("cannot access temporary tables of other sessions")));
+					 errmsg("cannot access temporary relations of other sessions")));
 
 		/* pass it off to localbuf.c */
 		return PrefetchLocalBuffer(RelationGetSmgr(reln), forkNum, blockNum);
@@ -936,7 +936,7 @@ ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum,
 	if (RELATION_IS_OTHER_TEMP(reln))
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-				 errmsg("cannot access temporary tables of other sessions")));
+				 errmsg("cannot access temporary relations of other sessions")));
 
 	/*
 	 * Read the buffer, and update pgstat counters to reflect a cache hit or
@@ -1292,6 +1292,12 @@ ReadBuffer_common(Relation rel, SMgrRelation smgr, char smgr_persistence,
 	int			flags;
 	char		persistence;
 
+	/* see comments in ReadBufferExtended */
+	if (rel && RELATION_IS_OTHER_TEMP(rel))
+		ereport(ERROR,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("cannot access temporary relations of other sessions")));
+
 	/*
 	 * Backward compatibility path, most code should use ExtendBufferedRel()
 	 * instead, as acquiring the extension lock inside ExtendBufferedRel()
@@ -1382,6 +1388,12 @@ StartReadBuffersImpl(ReadBuffersOperation *operation,
 	Assert(*nblocks > 0);
 	Assert(*nblocks <= MAX_IO_COMBINE_LIMIT);
 
+	/* see comments in ReadBufferExtended */
+	if (operation->rel && RELATION_IS_OTHER_TEMP(operation->rel))
+		ereport(ERROR,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("cannot access temporary relations of other sessions")));
+
 	if (operation->persistence == RELPERSISTENCE_TEMP)
 	{
 		io_context = IOCONTEXT_NORMAL;
-- 
2.43.0



reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: [email protected]
  Cc: [email protected], [email protected], [email protected], [email protected], [email protected]
  Subject: Re: Fix bug with accessing to temporary tables of other sessions
  In-Reply-To: <[email protected]>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox