diff --git a/contrib/pg_buffercache/Makefile b/contrib/pg_buffercache/Makefile index 497dbeb2297735ed436326912ff3121ffe8e53d7..18f7a8745247837d2d20727d9614526497e494e8 100644 --- a/contrib/pg_buffercache/Makefile +++ b/contrib/pg_buffercache/Makefile @@ -4,8 +4,9 @@ MODULE_big = pg_buffercache OBJS = pg_buffercache_pages.o $(WIN32RES) EXTENSION = pg_buffercache -DATA = pg_buffercache--1.2.sql pg_buffercache--1.1--1.2.sql \ - pg_buffercache--1.0--1.1.sql pg_buffercache--unpackaged--1.0.sql +DATA = pg_buffercache--1.2.sql pg_buffercache--1.2--1.3.sql \ + pg_buffercache--1.1--1.2.sql pg_buffercache--1.0--1.1.sql \ + pg_buffercache--unpackaged--1.0.sql PGFILEDESC = "pg_buffercache - monitoring of shared buffer cache in real-time" ifdef USE_PGXS diff --git a/contrib/pg_buffercache/pg_buffercache--1.2--1.3.sql b/contrib/pg_buffercache/pg_buffercache--1.2--1.3.sql new file mode 100644 index 0000000000000000000000000000000000000000..b37ef0112e3dffd25a2e77d663c59002cb93d8a1 --- /dev/null +++ b/contrib/pg_buffercache/pg_buffercache--1.2--1.3.sql @@ -0,0 +1,7 @@ +/* contrib/pg_buffercache/pg_buffercache--1.2--1.3.sql */ + +-- complain if script is sourced in psql, rather than via ALTER EXTENSION +\echo Use "ALTER EXTENSION pg_buffercache UPDATE TO '1.3'" to load this file. \quit + +GRANT EXECUTE ON FUNCTION pg_buffercache_pages() TO pg_monitor; +GRANT SELECT ON pg_buffercache TO pg_monitor; diff --git a/contrib/pg_buffercache/pg_buffercache.control b/contrib/pg_buffercache/pg_buffercache.control index a4d664f3fa7c1c583fc7b4424c7df4437fc3c0a3..8c060ae9abff9bbdfffa39c993c4835f6c5e3b25 100644 --- a/contrib/pg_buffercache/pg_buffercache.control +++ b/contrib/pg_buffercache/pg_buffercache.control @@ -1,5 +1,5 @@ # pg_buffercache extension comment = 'examine the shared buffer cache' -default_version = '1.2' +default_version = '1.3' module_pathname = '$libdir/pg_buffercache' relocatable = true diff --git a/contrib/pg_freespacemap/Makefile b/contrib/pg_freespacemap/Makefile index 7bc0e9555df871ffabde9c5533776acfcd7567e0..0a2f000ec666eac2cafe417ca35d8a374eb7980b 100644 --- a/contrib/pg_freespacemap/Makefile +++ b/contrib/pg_freespacemap/Makefile @@ -4,8 +4,8 @@ MODULE_big = pg_freespacemap OBJS = pg_freespacemap.o $(WIN32RES) EXTENSION = pg_freespacemap -DATA = pg_freespacemap--1.1.sql pg_freespacemap--1.0--1.1.sql \ - pg_freespacemap--unpackaged--1.0.sql +DATA = pg_freespacemap--1.1.sql pg_freespacemap--1.1--1.2.sql \ + pg_freespacemap--1.0--1.1.sql pg_freespacemap--unpackaged--1.0.sql PGFILEDESC = "pg_freespacemap - monitoring of free space map" ifdef USE_PGXS diff --git a/contrib/pg_freespacemap/pg_freespacemap--1.1--1.2.sql b/contrib/pg_freespacemap/pg_freespacemap--1.1--1.2.sql new file mode 100644 index 0000000000000000000000000000000000000000..f558defadde16fc5678826a68bd9359e717f9ea6 --- /dev/null +++ b/contrib/pg_freespacemap/pg_freespacemap--1.1--1.2.sql @@ -0,0 +1,7 @@ +/* contrib/pg_freespacemap/pg_freespacemap--1.1--1.2.sql */ + +-- complain if script is sourced in psql, rather than via ALTER EXTENSION +\echo Use "ALTER EXTENSION pg_freespacemap UPDATE TO '1.2'" to load this file. \quit + +GRANT EXECUTE ON FUNCTION pg_freespace(regclass, bigint) TO pg_stat_scan_tables; +GRANT EXECUTE ON FUNCTION pg_freespace(regclass) TO pg_stat_scan_tables; diff --git a/contrib/pg_freespacemap/pg_freespacemap.control b/contrib/pg_freespacemap/pg_freespacemap.control index 764db30d18e11cdeff441f1a92ac1b2de62311dc..ac8fc5050a91702a188f31ca9ddd34efed316b11 100644 --- a/contrib/pg_freespacemap/pg_freespacemap.control +++ b/contrib/pg_freespacemap/pg_freespacemap.control @@ -1,5 +1,5 @@ # pg_freespacemap extension comment = 'examine the free space map (FSM)' -default_version = '1.1' +default_version = '1.2' module_pathname = '$libdir/pg_freespacemap' relocatable = true diff --git a/contrib/pg_stat_statements/Makefile b/contrib/pg_stat_statements/Makefile index 298951a5f50030633b3e0ececae2835e5d45b64b..39b368b70eb5dadc1abbf9e2df48936ce8493f3e 100644 --- a/contrib/pg_stat_statements/Makefile +++ b/contrib/pg_stat_statements/Makefile @@ -4,9 +4,10 @@ MODULE_big = pg_stat_statements OBJS = pg_stat_statements.o $(WIN32RES) EXTENSION = pg_stat_statements -DATA = pg_stat_statements--1.4.sql pg_stat_statements--1.3--1.4.sql \ - pg_stat_statements--1.2--1.3.sql pg_stat_statements--1.1--1.2.sql \ - pg_stat_statements--1.0--1.1.sql pg_stat_statements--unpackaged--1.0.sql +DATA = pg_stat_statements--1.4.sql pg_stat_statements--1.4--1.5.sql \ + pg_stat_statements--1.3--1.4.sql pg_stat_statements--1.2--1.3.sql \ + pg_stat_statements--1.1--1.2.sql pg_stat_statements--1.0--1.1.sql \ + pg_stat_statements--unpackaged--1.0.sql PGFILEDESC = "pg_stat_statements - execution statistics of SQL statements" LDFLAGS_SL += $(filter -lm, $(LIBS)) diff --git a/contrib/pg_stat_statements/pg_stat_statements--1.4--1.5.sql b/contrib/pg_stat_statements/pg_stat_statements--1.4--1.5.sql new file mode 100644 index 0000000000000000000000000000000000000000..9c76122a2b76b5a2aefab525ae01e0c24a19d8cf --- /dev/null +++ b/contrib/pg_stat_statements/pg_stat_statements--1.4--1.5.sql @@ -0,0 +1,6 @@ +/* contrib/pg_stat_statements/pg_stat_statements--1.4--1.5.sql */ + +-- complain if script is sourced in psql, rather than via ALTER EXTENSION +\echo Use "ALTER EXTENSION pg_stat_statements UPDATE TO '1.5'" to load this file. \quit + +GRANT EXECUTE ON FUNCTION pg_stat_statements_reset() TO pg_read_all_stats; diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c index cd4c16e9d2c055bf004880c2565dd9ed8a6d1089..c3002618524a5735fdf2dab864c1128adb0911a2 100644 --- a/contrib/pg_stat_statements/pg_stat_statements.c +++ b/contrib/pg_stat_statements/pg_stat_statements.c @@ -62,6 +62,7 @@ #include <unistd.h> #include "access/hash.h" +#include "catalog/pg_authid.h" #include "executor/instrument.h" #include "funcapi.h" #include "mb/pg_wchar.h" @@ -1391,7 +1392,7 @@ pg_stat_statements_internal(FunctionCallInfo fcinfo, MemoryContext per_query_ctx; MemoryContext oldcontext; Oid userid = GetUserId(); - bool is_superuser = superuser(); + bool is_allowed_role = false; char *qbuffer = NULL; Size qbuffer_size = 0; Size extent = 0; @@ -1399,6 +1400,9 @@ pg_stat_statements_internal(FunctionCallInfo fcinfo, HASH_SEQ_STATUS hash_seq; pgssEntry *entry; + /* Superusers or members of pg_read_all_stats members are allowed */ + is_allowed_role = is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_STATS); + /* hash table must exist already */ if (!pgss || !pgss_hash) ereport(ERROR, @@ -1541,7 +1545,7 @@ pg_stat_statements_internal(FunctionCallInfo fcinfo, values[i++] = ObjectIdGetDatum(entry->key.userid); values[i++] = ObjectIdGetDatum(entry->key.dbid); - if (is_superuser || entry->key.userid == userid) + if (is_allowed_role || entry->key.userid == userid) { if (api_version >= PGSS_V1_2) values[i++] = Int64GetDatumFast(queryid); diff --git a/contrib/pg_stat_statements/pg_stat_statements.control b/contrib/pg_stat_statements/pg_stat_statements.control index 24038f56b17c17ff276b4e14f15b3981f424f769..193fcdfafa03265680e8f345cda3d8b8af82e1f8 100644 --- a/contrib/pg_stat_statements/pg_stat_statements.control +++ b/contrib/pg_stat_statements/pg_stat_statements.control @@ -1,5 +1,5 @@ # pg_stat_statements extension comment = 'track execution statistics of all SQL statements executed' -default_version = '1.4' +default_version = '1.5' module_pathname = '$libdir/pg_stat_statements' relocatable = true diff --git a/contrib/pg_visibility/Makefile b/contrib/pg_visibility/Makefile index bc429444260c10412ce20bde5635c32a61bb72aa..21d787ddf78650788dd275430b626bb3a7f5f92b 100644 --- a/contrib/pg_visibility/Makefile +++ b/contrib/pg_visibility/Makefile @@ -4,7 +4,8 @@ MODULE_big = pg_visibility OBJS = pg_visibility.o $(WIN32RES) EXTENSION = pg_visibility -DATA = pg_visibility--1.1.sql pg_visibility--1.0--1.1.sql +DATA = pg_visibility--1.1.sql pg_visibility--1.1--1.2.sql \ + pg_visibility--1.0--1.1.sql PGFILEDESC = "pg_visibility - page visibility information" REGRESS = pg_visibility diff --git a/contrib/pg_visibility/pg_visibility--1.1--1.2.sql b/contrib/pg_visibility/pg_visibility--1.1--1.2.sql new file mode 100644 index 0000000000000000000000000000000000000000..a5a4fe7ca852e2fea4a62c533d6a393a420911e8 --- /dev/null +++ b/contrib/pg_visibility/pg_visibility--1.1--1.2.sql @@ -0,0 +1,13 @@ +/* contrib/pg_visibility/pg_visibility--1.1--1.2.sql */ + +-- complain if script is sourced in psql, rather than via ALTER EXTENSION +\echo Use "ALTER EXTENSION pg_visibility UPDATE TO '1.2'" to load this file. \quit + +-- Allow use of monitoring functions by pg_monitor members +GRANT EXECUTE ON FUNCTION pg_visibility_map(regclass, bigint) TO pg_stat_scan_tables; +GRANT EXECUTE ON FUNCTION pg_visibility(regclass, bigint) TO pg_stat_scan_tables; +GRANT EXECUTE ON FUNCTION pg_visibility_map(regclass) TO pg_stat_scan_tables; +GRANT EXECUTE ON FUNCTION pg_visibility(regclass) TO pg_stat_scan_tables; +GRANT EXECUTE ON FUNCTION pg_visibility_map_summary(regclass) TO pg_stat_scan_tables; +GRANT EXECUTE ON FUNCTION pg_check_frozen(regclass) TO pg_stat_scan_tables; +GRANT EXECUTE ON FUNCTION pg_check_visible(regclass) TO pg_stat_scan_tables; diff --git a/contrib/pg_visibility/pg_visibility.control b/contrib/pg_visibility/pg_visibility.control index f93ed0176ec5722b215ee8859b96ceddcf5ba38b..3cffa08b015ed8757fc361b4fb3b9c3dda424e39 100644 --- a/contrib/pg_visibility/pg_visibility.control +++ b/contrib/pg_visibility/pg_visibility.control @@ -1,5 +1,5 @@ # pg_visibility extension comment = 'examine the visibility map (VM) and page-level visibility info' -default_version = '1.1' +default_version = '1.2' module_pathname = '$libdir/pg_visibility' relocatable = true diff --git a/contrib/pgrowlocks/pgrowlocks.c b/contrib/pgrowlocks/pgrowlocks.c index db9e0349a0390868150d15a0c44d5c01a2a5b02f..31b8626e3a086aed45d8fa993d12ee998483daf7 100644 --- a/contrib/pgrowlocks/pgrowlocks.c +++ b/contrib/pgrowlocks/pgrowlocks.c @@ -28,6 +28,7 @@ #include "access/relscan.h" #include "access/xact.h" #include "catalog/namespace.h" +#include "catalog/pg_authid.h" #include "funcapi.h" #include "miscadmin.h" #include "storage/bufmgr.h" @@ -98,9 +99,11 @@ pgrowlocks(PG_FUNCTION_ARGS) relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname)); rel = heap_openrv(relrv, AccessShareLock); - /* check permissions: must have SELECT on table */ - aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(), - ACL_SELECT); + /* check permissions: must have SELECT on table or be in pg_stat_scan_tables */ + aclresult = (pg_class_aclcheck(RelationGetRelid(rel), GetUserId(), + ACL_SELECT) || + is_member_of_role(GetUserId(), DEFAULT_ROLE_STAT_SCAN_TABLES); + if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_CLASS, RelationGetRelationName(rel)); diff --git a/contrib/pgstattuple/pgstattuple--1.4--1.5.sql b/contrib/pgstattuple/pgstattuple--1.4--1.5.sql index 84e112e1c2f0bebb276bc61e22e8e659c28d4cf5..05ae51fa4bb9827398df0f2c481a19733427e950 100644 --- a/contrib/pgstattuple/pgstattuple--1.4--1.5.sql +++ b/contrib/pgstattuple/pgstattuple--1.4--1.5.sql @@ -17,6 +17,7 @@ AS 'MODULE_PATHNAME', 'pgstattuple_v1_5' LANGUAGE C STRICT PARALLEL SAFE; REVOKE EXECUTE ON FUNCTION pgstattuple(text) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgstattuple(text) TO pg_stat_scan_tables; CREATE OR REPLACE FUNCTION pgstatindex(IN relname text, OUT version INT, @@ -33,6 +34,7 @@ AS 'MODULE_PATHNAME', 'pgstatindex_v1_5' LANGUAGE C STRICT PARALLEL SAFE; REVOKE EXECUTE ON FUNCTION pgstatindex(text) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgstatindex(text) TO pg_stat_scan_tables; CREATE OR REPLACE FUNCTION pg_relpages(IN relname text) RETURNS BIGINT @@ -40,6 +42,7 @@ AS 'MODULE_PATHNAME', 'pg_relpages_v1_5' LANGUAGE C STRICT PARALLEL SAFE; REVOKE EXECUTE ON FUNCTION pg_relpages(text) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pg_relpages(text) TO pg_stat_scan_tables; /* New stuff in 1.1 begins here */ @@ -51,6 +54,7 @@ AS 'MODULE_PATHNAME', 'pgstatginindex_v1_5' LANGUAGE C STRICT PARALLEL SAFE; REVOKE EXECUTE ON FUNCTION pgstatginindex(regclass) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgstatginindex(regclass) TO pg_stat_scan_tables; /* New stuff in 1.2 begins here */ @@ -68,6 +72,7 @@ AS 'MODULE_PATHNAME', 'pgstattuplebyid_v1_5' LANGUAGE C STRICT PARALLEL SAFE; REVOKE EXECUTE ON FUNCTION pgstattuple(regclass) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgstattuple(regclass) TO pg_stat_scan_tables; CREATE OR REPLACE FUNCTION pgstatindex(IN relname regclass, OUT version INT, @@ -84,6 +89,7 @@ AS 'MODULE_PATHNAME', 'pgstatindexbyid_v1_5' LANGUAGE C STRICT PARALLEL SAFE; REVOKE EXECUTE ON FUNCTION pgstatindex(regclass) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgstatindex(regclass) TO pg_stat_scan_tables; CREATE OR REPLACE FUNCTION pg_relpages(IN relname regclass) RETURNS BIGINT @@ -91,6 +97,7 @@ AS 'MODULE_PATHNAME', 'pg_relpagesbyid_v1_5' LANGUAGE C STRICT PARALLEL SAFE; REVOKE EXECUTE ON FUNCTION pg_relpages(regclass) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pg_relpages(regclass) TO pg_stat_scan_tables; /* New stuff in 1.3 begins here */ @@ -109,6 +116,7 @@ AS 'MODULE_PATHNAME', 'pgstattuple_approx_v1_5' LANGUAGE C STRICT PARALLEL SAFE; REVOKE EXECUTE ON FUNCTION pgstattuple_approx(regclass) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgstattuple_approx(regclass) TO pg_stat_scan_tables; /* New stuff in 1.5 begins here */ @@ -125,3 +133,4 @@ AS 'MODULE_PATHNAME', 'pgstathashindex' LANGUAGE C STRICT PARALLEL SAFE; REVOKE EXECUTE ON FUNCTION pgstathashindex(regclass) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pgstathashindex(regclass) TO pg_stat_scan_tables; diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index ac39c639edcbbc05b3b18c31cc5ab6b99b93efeb..65ba919e7b82f76296c86b0e48dd54b0db66d674 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -10221,15 +10221,17 @@ SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx <entry><type>text</type></entry> <entry>Configuration file the current value was set in (null for values set from sources other than configuration files, or when - examined by a non-superuser); - helpful when using <literal>include</> directives in configuration files</entry> + examined by a user who is neither a superuser or a member of + <literal>pg_read_all_settings</literal>); helpful when using + <literal>include</> directives in configuration files</entry> </row> <row> <entry><structfield>sourceline</structfield></entry> <entry><type>integer</type></entry> <entry>Line number within the configuration file the current value was set at (null for values set from sources other than configuration files, - or when examined by a non-superuser) + or when examined by a user who is neither a superuser or a member of + <literal>pg_read_all_settings</literal>). </entry> </row> <row> diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 78508d74ece1ff63837babe7dfc03727ece27512..076be587eacf17a5589441452e08c70906a565c1 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -19408,9 +19408,11 @@ postgres=# SELECT * FROM pg_walfile_name_offset(pg_stop_backup()); accept the OID or name of a database or tablespace, and return the total disk space used therein. To use <function>pg_database_size</function>, you must have <literal>CONNECT</> permission on the specified database - (which is granted by default). To use <function>pg_tablespace_size</>, - you must have <literal>CREATE</> permission on the specified tablespace, - unless it is the default tablespace for the current database. + (which is granted by default), or be a member of the <literal>pg_read_all_stats</> + role. To use <function>pg_tablespace_size</>, you must have + <literal>CREATE</> permission on the specified tablespace, or be a member + of the <literal>pg_read_all_stats</> role unless it is the default tablespace for + the current database. </para> <para> @@ -19736,7 +19738,8 @@ postgres=# SELECT * FROM pg_walfile_name_offset(pg_stop_backup()); <entry><type>setof record</type></entry> <entry> List the name, size, and last modification time of files in the log - directory. Access may be granted to non-superuser roles. + directory. Access is granted to members of the <literal>pg_monitor</> + role and may be granted to other non-superuser roles. </entry> </row> <row> @@ -19746,7 +19749,8 @@ postgres=# SELECT * FROM pg_walfile_name_offset(pg_stop_backup()); <entry><type>setof record</type></entry> <entry> List the name, size, and last modification time of files in the WAL - directory. Access may be granted to non-superuser roles. + directory. Access is granted to members of the <literal>pg_monitor</> + role and may be granted to other non-superuser roles. </entry> </row> <row> @@ -19807,8 +19811,8 @@ postgres=# SELECT * FROM pg_walfile_name_offset(pg_stop_backup()); <para> <function>pg_ls_logdir</> returns the name, size, and last modified time (mtime) of each file in the log directory. By default, only superusers - can use this function, but access may be granted to others using - <command>GRANT</command>. + and members of the <literal>pg_monitor</> role can use this function. + Access may be granted to others using <command>GRANT</command>. </para> <indexterm> @@ -19817,8 +19821,9 @@ postgres=# SELECT * FROM pg_walfile_name_offset(pg_stop_backup()); <para> <function>pg_ls_waldir</> returns the name, size, and last modified time (mtime) of each file in the write ahead log (WAL) directory. By - default only superusers can use this function, but access may be granted - to others using <command>GRANT</command>. + default only superusers and members of the <literal>pg_monitor</> role + can use this function. Access may be granted to others using + <command>GRANT</command>. </para> <indexterm> diff --git a/doc/src/sgml/pgbuffercache.sgml b/doc/src/sgml/pgbuffercache.sgml index b261a4dbe0a5d924bb50d774beef50253bb732f9..4e53009ae073b69b1545b48141e5a511554ec3e4 100644 --- a/doc/src/sgml/pgbuffercache.sgml +++ b/doc/src/sgml/pgbuffercache.sgml @@ -24,8 +24,9 @@ </para> <para> - By default public access is revoked from both of these, just in case there - are security issues lurking. + By default use is restricted to superusers and members of the + <literal>pg_read_all_stats</literal> role. Access may be granted to others + using <command>GRANT</command>. </para> <sect2> diff --git a/doc/src/sgml/pgfreespacemap.sgml b/doc/src/sgml/pgfreespacemap.sgml index f2f99d571efaecafd73d911ef2fd3c2787ae8bd6..43e154a2f3aa7fcc9f70957294054143879e0ecc 100644 --- a/doc/src/sgml/pgfreespacemap.sgml +++ b/doc/src/sgml/pgfreespacemap.sgml @@ -16,8 +16,9 @@ </para> <para> - By default public access is revoked from the functions, just in case - there are security issues lurking. + By default use is restricted to superusers and members of the + <literal>pg_stat_scan_tables</literal> role. Access may be granted to others + using <command>GRANT</command>. </para> <sect2> diff --git a/doc/src/sgml/pgrowlocks.sgml b/doc/src/sgml/pgrowlocks.sgml index d73511579c43c066362658f180e4bf4c0bc65896..65d532e081041dac7162af172face346584997ef 100644 --- a/doc/src/sgml/pgrowlocks.sgml +++ b/doc/src/sgml/pgrowlocks.sgml @@ -12,6 +12,13 @@ locking information for a specified table. </para> + <para> + By default use is restricted to superusers, members of the + <literal>pg_stat_scan_tables</literal> role, and users with + <literal>SELECT</literal> permissions on the table. + </para> + + <sect2> <title>Overview</title> diff --git a/doc/src/sgml/pgstatstatements.sgml b/doc/src/sgml/pgstatstatements.sgml index 082994cae00bb4210c5ecd6bd51416a3017ae5e0..2d55d3bdad45342f9e7e4998b7597fd46572f44e 100644 --- a/doc/src/sgml/pgstatstatements.sgml +++ b/doc/src/sgml/pgstatstatements.sgml @@ -226,10 +226,11 @@ </table> <para> - For security reasons, non-superusers are not allowed to see the SQL - text or <structfield>queryid</structfield> of queries executed by other users. - They can see the statistics, however, if the view has been installed in their - database. + For security reasons, only superusers and members of the + <literal>pg_read_all_stats<literal> role are allowed to see the SQL text and + <structfield>queryid</structfield> of queries executed by other users. + Other users can see the statistics, however, if the view has been installed + in their database. </para> <para> diff --git a/doc/src/sgml/pgstattuple.sgml b/doc/src/sgml/pgstattuple.sgml index 62b1a6f4794c9255ba5884d75db45cbe068045c7..141d8e225fb225fd3aa37fd1951a212e7fc6cc01 100644 --- a/doc/src/sgml/pgstattuple.sgml +++ b/doc/src/sgml/pgstattuple.sgml @@ -16,7 +16,8 @@ As these functions return detailed page-level information, only the superuser has EXECUTE privileges on them upon installation. After the functions have been installed, users may issue <command>GRANT</command> commands to change - the privileges on the functions to allow non-superusers to execute them. See + the privileges on the functions to allow non-superusers to execute them. Members + of the <literal>pg_stat_scan_tables</literal> role are granted access by default. See the description of the <xref linkend="sql-grant"> command for specifics. </para> diff --git a/doc/src/sgml/pgvisibility.sgml b/doc/src/sgml/pgvisibility.sgml index fd486696fc1e10eb1ec9a8cb0265623d5330b1b5..d466a3bce8626728b3255dfafe99331ccc2635fe 100644 --- a/doc/src/sgml/pgvisibility.sgml +++ b/doc/src/sgml/pgvisibility.sgml @@ -140,7 +140,10 @@ </variablelist> <para> - By default, these functions are executable only by superusers. + By default, these functions are executable only by superusers and members of the + <literal>pg_stat_scan_tables</literal> role, with the exception of + <function>pg_truncate_visibility_map(relation regclass)</function> which can only + be executed by superusers. </para> </sect2> diff --git a/doc/src/sgml/user-manag.sgml b/doc/src/sgml/user-manag.sgml index 7eaefe58c2fe03a8d9fd2c0d88d49bee96b8b96e..914f1505abdf24c3ce6fa99f9ee09637520ccff4 100644 --- a/doc/src/sgml/user-manag.sgml +++ b/doc/src/sgml/user-manag.sgml @@ -515,14 +515,50 @@ DROP ROLE doomed_role; </row> </thead> <tbody> + <row> + <entry>pg_read_all_settings</entry> + <entry>Read all configuration variables, even those normally visible only to + superusers.</entry> + </row> + <row> + <entry>pg_read_all_stats</entry> + <entry>Read all pg_stat_* views and use various statistics related extensions, + even those normally visible only to superusers.</entry> + </row> + <row> + <entry>pg_stat_scan_tables</entry> + <entry>Execute monitoring functions that may take AccessShareLocks on tables, + potentially for a long time.</entry> + </row> <row> <entry>pg_signal_backend</entry> <entry>Send signals to other backends (eg: cancel query, terminate).</entry> </row> + <row> + <entry>pg_monitor</entry> + <entry>Read/execute various monitoring views and functions. + This role is a member of <literal>pg_read_all_settings</literal>, + <literal>pg_read_all_stats</literal> and + <literal>pg_stat_scan_tables</literal>.</entry> + </row> </tbody> </tgroup> </table> + <para> + The <literal>pg_monitor</literal>, <literal>pg_read_all_settings</literal>, + <literal>pg_read_all_stats</literal> and <literal>pg_stat_scan_tables</literal> + roles are intended to allow administrators to easily configure a role for the + purpose of monitoring the database server. They grant a set of common privileges + allowing the role to read various useful configuration settings, statistics and + other system information normally restricted to superusers. + </para> + + <para> + Care should be taken when granting these roles to ensure they are only used where + needed to perform the desired monitoring. + </para> + <para> Administrators can grant access to these roles to users using the GRANT command: diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index d357c8b8fdbeadbe90a1cdc48500730140af77e0..0217f3992f35a7affbb2dce9d4b31fdc81512ca6 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -1148,3 +1148,9 @@ REVOKE EXECUTE ON FUNCTION pg_stat_reset_single_function_counters(oid) FROM publ REVOKE EXECUTE ON FUNCTION pg_ls_logdir() FROM public; REVOKE EXECUTE ON FUNCTION pg_ls_waldir() FROM public; +GRANT EXECUTE ON FUNCTION pg_ls_logdir() TO pg_monitor; +GRANT EXECUTE ON FUNCTION pg_ls_waldir() TO pg_monitor; + +GRANT pg_read_all_settings TO pg_monitor; +GRANT pg_read_all_stats TO pg_monitor; +GRANT pg_stat_scan_tables TO pg_monitor; diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c index 771ac305c348221ae6accc2a6467c6a28b62e79f..df93265c20eb013e697aa9418caafa0faee19b27 100644 --- a/src/backend/replication/walreceiver.c +++ b/src/backend/replication/walreceiver.c @@ -50,6 +50,7 @@ #include "access/timeline.h" #include "access/transam.h" #include "access/xlog_internal.h" +#include "catalog/pg_authid.h" #include "catalog/pg_type.h" #include "funcapi.h" #include "libpq/pqformat.h" @@ -1421,7 +1422,7 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS) /* Fetch values */ values[0] = Int32GetDatum(walrcv->pid); - if (!superuser()) + if (!is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_STATS)) { /* * Only superusers can see details. Other users only get the pid value diff --git a/src/backend/utils/adt/dbsize.c b/src/backend/utils/adt/dbsize.c index 58923912eb7792a0cbb81d63230a1e2081788a60..6d56638208b5bda914c9eeb8e8a40e3e190b34e9 100644 --- a/src/backend/utils/adt/dbsize.c +++ b/src/backend/utils/adt/dbsize.c @@ -17,6 +17,7 @@ #include "access/htup_details.h" #include "catalog/catalog.h" #include "catalog/namespace.h" +#include "catalog/pg_authid.h" #include "catalog/pg_tablespace.h" #include "commands/dbcommands.h" #include "commands/tablespace.h" @@ -88,11 +89,17 @@ calculate_database_size(Oid dbOid) char pathname[MAXPGPATH]; AclResult aclresult; - /* User must have connect privilege for target database */ + /* + * User must have connect privilege for target database + * or be a member of pg_read_all_stats + */ aclresult = pg_database_aclcheck(dbOid, GetUserId(), ACL_CONNECT); - if (aclresult != ACLCHECK_OK) + if (aclresult != ACLCHECK_OK && + !is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_STATS)) + { aclcheck_error(aclresult, ACL_KIND_DATABASE, get_database_name(dbOid)); + } /* Shared storage in pg_global is not counted */ @@ -172,11 +179,12 @@ calculate_tablespace_size(Oid tblspcOid) AclResult aclresult; /* - * User must have CREATE privilege for target tablespace, either - * explicitly granted or implicitly because it is default for current - * database. + * User must be a member of pg_read_all_stats or have CREATE privilege for + * target tablespace, either explicitly granted or implicitly because + * it is default for current database. */ - if (tblspcOid != MyDatabaseTableSpace) + if (tblspcOid != MyDatabaseTableSpace && + !is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_STATS)) { aclresult = pg_tablespace_aclcheck(tblspcOid, GetUserId(), ACL_CREATE); if (aclresult != ACLCHECK_OK) diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c index dd2b924d0af355babeeb2844e71c56372e34e7e9..e0cae1ba1e85cff2e3b08d92d1bdfd9b09ced927 100644 --- a/src/backend/utils/adt/pgstatfuncs.c +++ b/src/backend/utils/adt/pgstatfuncs.c @@ -15,6 +15,7 @@ #include "postgres.h" #include "access/htup_details.h" +#include "catalog/pg_authid.h" #include "catalog/pg_type.h" #include "common/ip.h" #include "funcapi.h" @@ -658,8 +659,9 @@ pg_stat_get_activity(PG_FUNCTION_ARGS) nulls[19] = nulls[20] = nulls[21] = nulls[22] = nulls[23] = true; } - /* Values only available to role member */ - if (has_privs_of_role(GetUserId(), beentry->st_userid)) + /* Values only available to role member or pg_read_all_stats */ + if (has_privs_of_role(GetUserId(), beentry->st_userid) || + is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_STATS)) { SockAddr zero_clientaddr; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index e9d561b185e4e59ab242c8e0f1999eb5fe37983a..8b5f064d4ebc1ff3817af9e2155a8cbba7c25c61 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -34,6 +34,7 @@ #include "access/xact.h" #include "access/xlog_internal.h" #include "catalog/namespace.h" +#include "catalog/pg_authid.h" #include "commands/async.h" #include "commands/prepare.h" #include "commands/user.h" @@ -6689,10 +6690,11 @@ GetConfigOption(const char *name, bool missing_ok, bool restrict_superuser) } if (restrict_superuser && (record->flags & GUC_SUPERUSER_ONLY) && - !superuser()) + !is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_SETTINGS)) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("must be superuser to examine \"%s\"", name))); + errmsg("must be superuser or a member of pg_read_all_settings to examine \"%s\"", + name))); switch (record->vartype) { @@ -6737,10 +6739,12 @@ GetConfigOptionResetString(const char *name) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("unrecognized configuration parameter \"%s\"", name))); - if ((record->flags & GUC_SUPERUSER_ONLY) && !superuser()) + if ((record->flags & GUC_SUPERUSER_ONLY) && + !is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_SETTINGS)) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("must be superuser to examine \"%s\"", name))); + errmsg("must be superuser or a member of pg_read_all_settings to examine \"%s\"", + name))); switch (record->vartype) { @@ -8027,10 +8031,12 @@ GetConfigOptionByName(const char *name, const char **varname, bool missing_ok) errmsg("unrecognized configuration parameter \"%s\"", name))); } - if ((record->flags & GUC_SUPERUSER_ONLY) && !superuser()) + if ((record->flags & GUC_SUPERUSER_ONLY) && + !is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_SETTINGS)) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("must be superuser to examine \"%s\"", name))); + errmsg("must be superuser or a member of pg_read_all_settings to examine \"%s\"", + name))); if (varname) *varname = record->name; @@ -8056,7 +8062,8 @@ GetConfigOptionByNum(int varnum, const char **values, bool *noshow) if (noshow) { if ((conf->flags & GUC_NO_SHOW_ALL) || - ((conf->flags & GUC_SUPERUSER_ONLY) && !superuser())) + ((conf->flags & GUC_SUPERUSER_ONLY) && + !is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_SETTINGS))) *noshow = true; else *noshow = false; diff --git a/src/include/catalog/pg_authid.h b/src/include/catalog/pg_authid.h index def71edaa89b230329dfe6720ada39e25ce13cf8..a6c5c02cebd76515313e4b1c9cf075e4815d2808 100644 --- a/src/include/catalog/pg_authid.h +++ b/src/include/catalog/pg_authid.h @@ -99,10 +99,18 @@ typedef FormData_pg_authid *Form_pg_authid; * ---------------- */ DATA(insert OID = 10 ( "POSTGRES" t t t t t t t -1 _null_ _null_)); +DATA(insert OID = 3373 ( "pg_monitor" f t f f f f f -1 _null_ _null_)); +DATA(insert OID = 3374 ( "pg_read_all_settings" f t f f f f f -1 _null_ _null_)); +DATA(insert OID = 3375 ( "pg_read_all_stats" f t f f f f f -1 _null_ _null_)); +DATA(insert OID = 3377 ( "pg_stat_scan_tables" f t f f f f f -1 _null_ _null_)); DATA(insert OID = 4200 ( "pg_signal_backend" f t f f f f f -1 _null_ _null_)); #define BOOTSTRAP_SUPERUSERID 10 +#define DEFAULT_ROLE_MONITOR 3373 +#define DEFAULT_ROLE_READ_ALL_SETTINGS 3374 +#define DEFAULT_ROLE_READ_ALL_STATS 3375 +#define DEFAULT_ROLE_STAT_SCAN_TABLES 3377 #define DEFAULT_ROLE_SIGNAL_BACKENDID 4200 #endif /* PG_AUTHID_H */