Fix contrib/pgstattuple and contrib/pageinspect to prevent attempts to read
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 31 Mar 2009 22:55:41 +0000 (22:55 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 31 Mar 2009 22:55:41 +0000 (22:55 +0000)
temporary tables of other sessions; that is unsafe because of the way our
buffer management works.  Per report from Stuart Bishop.
This is redundant with the bufmgr.c checks in HEAD, but not at all redundant
in the back branches.

contrib/pgstattuple/pgstatindex.c
contrib/pgstattuple/pgstattuple.c

index fe2062f9bd093edc04b3ed38d7a0212763f1569a..c0ac1ae5bfb432136130c13b5dd93d08f9b731ea 100644 (file)
@@ -247,6 +247,16 @@ pgstatindex(PG_FUNCTION_ARGS)
        if (!IS_INDEX(rel) || !IS_BTREE(rel))
                elog(ERROR, "pgstatindex() can be used only on b-tree index.");
 
+       /*
+        * 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 (isOtherTempNamespace(RelationGetNamespace(rel)))
+               ereport(ERROR,
+                               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                errmsg("cannot access temporary tables of other sessions")));
+
        /*-------------------
         * Read a metapage
         *-------------------
@@ -405,16 +415,26 @@ bt_page_stats(PG_FUNCTION_ARGS)
        relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
        rel = relation_openrv(relrv, AccessShareLock);
 
-       CHECK_RELATION_BLOCK_RANGE(rel, blkno);
-
-       buffer = ReadBuffer(rel, blkno);
-
        if (!IS_INDEX(rel) || !IS_BTREE(rel))
                elog(ERROR, "bt_page_stats() can be used only on b-tree index.");
 
+       /*
+        * 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 (isOtherTempNamespace(RelationGetNamespace(rel)))
+               ereport(ERROR,
+                               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                errmsg("cannot access temporary tables of other sessions")));
+
        if (blkno == 0)
                elog(ERROR, "Block 0 is a meta page.");
 
+       CHECK_RELATION_BLOCK_RANGE(rel, blkno);
+
+       buffer = ReadBuffer(rel, blkno);
+
        {
                HeapTuple       tuple;
                TupleDesc       tupleDesc;
@@ -513,9 +533,6 @@ bt_page_items(PG_FUNCTION_ARGS)
                                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                                 (errmsg("must be superuser to use pgstattuple functions"))));
 
-       if (blkno == 0)
-               elog(ERROR, "Block 0 is a meta page.");
-
        if (SRF_IS_FIRSTCALL())
        {
                fctx = SRF_FIRSTCALL_INIT();
@@ -529,13 +546,26 @@ bt_page_items(PG_FUNCTION_ARGS)
                relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
                uargs->rel = relation_openrv(relrv, AccessShareLock);
 
+               if (!IS_INDEX(uargs->rel) || !IS_BTREE(uargs->rel))
+                       elog(ERROR, "bt_page_items() can be used only on b-tree index.");
+
+               /*
+                * 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 (isOtherTempNamespace(RelationGetNamespace(uargs->rel)))
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                        errmsg("cannot access temporary tables of other sessions")));
+
+               if (blkno == 0)
+                       elog(ERROR, "Block 0 is a meta page.");
+
                CHECK_RELATION_BLOCK_RANGE(uargs->rel, blkno);
 
                uargs->buffer = ReadBuffer(uargs->rel, blkno);
 
-               if (!IS_INDEX(uargs->rel) || !IS_BTREE(uargs->rel))
-                       elog(ERROR, "bt_page_items() can be used only on b-tree index.");
-
                uargs->page = BufferGetPage(uargs->buffer);
 
                opaque = (BTPageOpaque) PageGetSpecialPointer(uargs->page);
@@ -651,6 +681,16 @@ bt_metap(PG_FUNCTION_ARGS)
        if (!IS_INDEX(rel) || !IS_BTREE(rel))
                elog(ERROR, "bt_metap() can be used only on b-tree index.");
 
+       /*
+        * 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 (isOtherTempNamespace(RelationGetNamespace(rel)))
+               ereport(ERROR,
+                               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                errmsg("cannot access temporary tables of other sessions")));
+
        buffer = ReadBuffer(rel, 0);
 
        {
@@ -720,6 +760,8 @@ pg_relpages(PG_FUNCTION_ARGS)
        relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
        rel = relation_openrv(relrv, AccessShareLock);
 
+       /* note: this will work OK on non-local temp tables */
+
        relpages = RelationGetNumberOfBlocks(rel);
 
        relation_close(rel, AccessShareLock);
index 2bc2067bbc7d3bc5985021d81f370fd41b622592..4d001cc2a4675f63d926080c634de171fd929ae8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $PostgreSQL: pgsql/contrib/pgstattuple/pgstattuple.c,v 1.25.2.1 2007/08/28 23:11:12 tgl Exp $
+ * $PostgreSQL: pgsql/contrib/pgstattuple/pgstattuple.c,v 1.25.2.2 2009/03/31 22:55:41 tgl Exp $
  *
  * Copyright (c) 2001,2002     Tatsuo Ishii
  *
@@ -201,6 +201,16 @@ pgstat_relation(Relation rel, FunctionCallInfo fcinfo)
 {
        const char *err;
 
+       /*
+        * 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 (isOtherTempNamespace(RelationGetNamespace(rel)))
+               ereport(ERROR,
+                               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                errmsg("cannot access temporary tables of other sessions")));
+
        switch (rel->rd_rel->relkind)
        {
                case RELKIND_RELATION: