Allow pg_read_all_stats to read pg_stat_progress_*

Started by Andrey M. Borodinover 5 years ago11 messages
#1Andrey M. Borodin
x4mmm@yandex-team.ru
1 attachment(s)

Hi!

One of our users asked me why they cannot read details of pg_stat_progress_vacuum while they have pg_read_all_stats role.
Maybe I'm missing something, but I think they should be able to read stats...

PFA fix.
This affects pg_stat_progress_analyze, pg_stat_progress_basebackup, pg_stat_progress_cluster, pg_stat_progress_create_index and pg_stat_progress_vacuum.

With patch
postgres=# set role pg_read_all_stats ;
postgres=> select * from pg_stat_progress_vacuum ;
pid | datid | datname | relid | phase | heap_blks_total | heap_blks_scanned | heap_blks_vacuumed | index_vacuum_count | max_dead_tuples | num_dead_tuples
-------+-------+----------+-------+---------------+-----------------+-------------------+--------------------+--------------------+-----------------+-----------------
76331 | 12923 | postgres | 1247 | scanning heap | 10 | 1 | 0 | 0 | 2910 | 0
(1 row)

Without patch
postgres=# set role pg_read_all_stats ;
SET
postgres=> select * from pg_stat_progress_vacuum ;
pid | datid | datname | relid | phase | heap_blks_total | heap_blks_scanned | heap_blks_vacuumed | index_vacuum_count | max_dead_tuples | num_dead_tuples
-------+-------+----------+-------+-------+-----------------+-------------------+--------------------+--------------------+-----------------+-----------------
76331 | 12923 | postgres | | | | | | | |
(1 row)

Thanks!

Best regards, Andrey Borodin.

Attachments:

allow_read_all_stats.diffapplication/octet-stream; name=allow_read_all_stats.diff; x-unix-mode=0644Download
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index cea01534a5..3571a9bf2e 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -450,6 +450,7 @@ pg_stat_get_progress_info(PG_FUNCTION_ARGS)
 	ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
 	MemoryContext per_query_ctx;
 	MemoryContext oldcontext;
+	Oid			user_id = GetUserId();
 
 	/* check to see if caller supports us returning a tuplestore */
 	if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
@@ -521,7 +522,8 @@ pg_stat_get_progress_info(PG_FUNCTION_ARGS)
 		values[1] = ObjectIdGetDatum(beentry->st_databaseid);
 
 		/* show rest of the values including relid only to role members */
-		if (has_privs_of_role(GetUserId(), beentry->st_userid))
+		if (has_privs_of_role(user_id, beentry->st_userid) ||
+			is_member_of_role(user_id, DEFAULT_ROLE_READ_ALL_STATS))
 		{
 			values[2] = ObjectIdGetDatum(beentry->st_progress_command_target);
 			for (i = 0; i < PGSTAT_NUM_PROGRESS_PARAM; i++)
#2Magnus Hagander
magnus@hagander.net
In reply to: Andrey M. Borodin (#1)
1 attachment(s)
Re: Allow pg_read_all_stats to read pg_stat_progress_*

On Wed, Apr 15, 2020 at 9:14 AM Andrey M. Borodin <x4mmm@yandex-team.ru>
wrote:

Hi!

One of our users asked me why they cannot read details of
pg_stat_progress_vacuum while they have pg_read_all_stats role.
Maybe I'm missing something, but I think they should be able to read
stats...

PFA fix.
This affects pg_stat_progress_analyze, pg_stat_progress_basebackup,
pg_stat_progress_cluster, pg_stat_progress_create_index and
pg_stat_progress_vacuum.

With patch
postgres=# set role pg_read_all_stats ;
postgres=> select * from pg_stat_progress_vacuum ;
pid | datid | datname | relid | phase | heap_blks_total |
heap_blks_scanned | heap_blks_vacuumed | index_vacuum_count |
max_dead_tuples | num_dead_tuples

-------+-------+----------+-------+---------------+-----------------+-------------------+--------------------+--------------------+-----------------+-----------------
76331 | 12923 | postgres | 1247 | scanning heap | 10 |
1 | 0 | 0 | 2910 |
0
(1 row)

Without patch
postgres=# set role pg_read_all_stats ;
SET
postgres=> select * from pg_stat_progress_vacuum ;
pid | datid | datname | relid | phase | heap_blks_total |
heap_blks_scanned | heap_blks_vacuumed | index_vacuum_count |
max_dead_tuples | num_dead_tuples

-------+-------+----------+-------+-------+-----------------+-------------------+--------------------+--------------------+-----------------+-----------------
76331 | 12923 | postgres | | | |
| | | |

(1 row)

I think that makes perfect sense. The documentation explicitly says "can
read all pg_stat_* views", which is clearly wrong -- so either the code or
the docs should be fixed, and it looks like it's the code that should be
fixed to me.

As for the patch, one could argue that we should just store the resulting
boolean instead of re-running the check (e.g. have a "bool
has_stats_privilege" or such), but perhaps that's an unnecessary
micro-optimization, like the attached.

--
Magnus Hagander
Me: https://www.hagander.net/ <http://www.hagander.net/&gt;
Work: https://www.redpill-linpro.com/ <http://www.redpill-linpro.com/&gt;

Attachments:

allow_read_all_stats2.difftext/x-patch; charset=US-ASCII; name=allow_read_all_stats2.diffDownload
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 175f4fd26b..60fc94d89c 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -466,6 +466,7 @@ pg_stat_get_progress_info(PG_FUNCTION_ARGS)
 	ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
 	MemoryContext per_query_ctx;
 	MemoryContext oldcontext;
+	bool		has_stats_role = is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_STATS);
 
 	/* check to see if caller supports us returning a tuplestore */
 	if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
@@ -537,7 +538,8 @@ pg_stat_get_progress_info(PG_FUNCTION_ARGS)
 		values[1] = ObjectIdGetDatum(beentry->st_databaseid);
 
 		/* show rest of the values including relid only to role members */
-		if (has_privs_of_role(GetUserId(), beentry->st_userid))
+		if (has_stats_role ||
+			has_privs_of_role(GetUserId(), beentry->st_userid))
 		{
 			values[2] = ObjectIdGetDatum(beentry->st_progress_command_target);
 			for (i = 0; i < PGSTAT_NUM_PROGRESS_PARAM; i++)
#3Andrey M. Borodin
x4mmm@yandex-team.ru
In reply to: Magnus Hagander (#2)
Re: Allow pg_read_all_stats to read pg_stat_progress_*

15 апр. 2020 г., в 15:25, Magnus Hagander <magnus@hagander.net> написал(а):

I think that makes perfect sense. The documentation explicitly says "can read all pg_stat_* views", which is clearly wrong -- so either the code or the docs should be fixed, and it looks like it's the code that should be fixed to me.

Should it be bug or v14 feature?

Also pgstatfuncs.c contains a lot more checks of has_privs_of_role(GetUserId(), beentry->st_userid).
Maybe grant them all?

As for the patch, one could argue that we should just store the resulting boolean instead of re-running the check (e.g. have a "bool has_stats_privilege" or such), but perhaps that's an unnecessary micro-optimization, like the attached.

Looks good to me.

Thanks!

Best regards, Andrey Borodin.

#4Kyotaro Horiguchi
horikyota.ntt@gmail.com
In reply to: Andrey M. Borodin (#3)
Re: Allow pg_read_all_stats to read pg_stat_progress_*

At Wed, 15 Apr 2020 15:58:05 +0500, "Andrey M. Borodin" <x4mmm@yandex-team.ru> wrote in

15 апр. 2020 г., в 15:25, Magnus Hagander <magnus@hagander.net> написал(а):
I think that makes perfect sense. The documentation explicitly says "can read all pg_stat_* views", which is clearly wrong -- so either the code or the docs should be fixed, and it looks like it's the code that should be fixed to me.

Should it be bug or v14 feature?

Also pgstatfuncs.c contains a lot more checks of has_privs_of_role(GetUserId(), beentry->st_userid).
Maybe grant them all?

As for the patch, one could argue that we should just store the resulting boolean instead of re-running the check (e.g. have a "bool has_stats_privilege" or such), but perhaps that's an unnecessary micro-optimization, like the attached.

Looks good to me.

pg_stat_get_activty checks (has_privs_of_role() ||
is_member_of_role()) in-place for every entry. It's not necessary but
I suppose that doing the same thing for pg_stat_progress_info might be
better.

It's another issue, but pg_stat_get_backend_* functions don't consider
pg_read_all_stats. I suppose that the functions should work under the
same criteria to pg_stat views, and maybe explicitly documented?

If we do that, it may be better that we define "PGSTAT_VIEW_PRIV()" or
something like and replace the all occurances of the idiomatic
condition with it.

regards.

--
Kyotaro Horiguchi
NTT Open Source Software Center

#5Magnus Hagander
magnus@hagander.net
In reply to: Kyotaro Horiguchi (#4)
1 attachment(s)
Re: Allow pg_read_all_stats to read pg_stat_progress_*

On Thu, Apr 16, 2020 at 7:05 AM Kyotaro Horiguchi <horikyota.ntt@gmail.com>
wrote:

At Wed, 15 Apr 2020 15:58:05 +0500, "Andrey M. Borodin" <
x4mmm@yandex-team.ru> wrote in

15 апр. 2020 г., в 15:25, Magnus Hagander <magnus@hagander.net>

написал(а):

I think that makes perfect sense. The documentation explicitly says

"can read all pg_stat_* views", which is clearly wrong -- so either the
code or the docs should be fixed, and it looks like it's the code that
should be fixed to me.

Should it be bug or v14 feature?

Also pgstatfuncs.c contains a lot more checks of

has_privs_of_role(GetUserId(), beentry->st_userid).

Maybe grant them all?

As for the patch, one could argue that we should just store the

resulting boolean instead of re-running the check (e.g. have a "bool
has_stats_privilege" or such), but perhaps that's an unnecessary
micro-optimization, like the attached.

Looks good to me.

pg_stat_get_activty checks (has_privs_of_role() ||
is_member_of_role()) in-place for every entry. It's not necessary but
I suppose that doing the same thing for pg_stat_progress_info might be
better.

From a result perspective, it shouldn't make a difference though, should
it? It's a micro-optimization, but it might not have an actual performance
effect in reality as well, but the result should always be the same?

(FWIW, pg_stat_statements has a coding pattern similar to the one I
suggested in the patch)

It's another issue, but pg_stat_get_backend_* functions don't consider
pg_read_all_stats. I suppose that the functions should work under the
same criteria to pg_stat views, and maybe explicitly documented?

That's a good question. They haven't been documented to do so, but it
certainly seems *weird* that the same information should be available
through a view like pg_stat_activity, but not through the functions.

I would guess this was simply forgotten in 25fff40798f -- I don't recall
any discussion about it. The commit message specifically says
pg_database_size() and pg_tablespace_size(), but mentions nothing about
pg_stat_*.

If we do that, it may be better that we define "PGSTAT_VIEW_PRIV()" or
something like and replace the all occurances of the idiomatic
condition with it.

You mean something like the attached?

--
Magnus Hagander
Me: https://www.hagander.net/ <http://www.hagander.net/&gt;
Work: https://www.redpill-linpro.com/ <http://www.redpill-linpro.com/&gt;

Attachments:

allow_read_all_stats3.difftext/x-patch; charset=US-ASCII; name=allow_read_all_stats3.diffDownload
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 175f4fd26b..446044609e 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -33,6 +33,8 @@
 
 #define UINT32_ACCESS_ONCE(var)		 ((uint32)(*((volatile uint32 *)&(var))))
 
+#define HAS_PGSTAT_PERMISSIONS(role)	 (is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_STATS) || has_privs_of_role(GetUserId(), role))
+
 /* Global bgwriter statistics, from bgwriter.c */
 extern PgStat_MsgBgWriter bgwriterStats;
 
@@ -537,7 +539,7 @@ pg_stat_get_progress_info(PG_FUNCTION_ARGS)
 		values[1] = ObjectIdGetDatum(beentry->st_databaseid);
 
 		/* show rest of the values including relid only to role members */
-		if (has_privs_of_role(GetUserId(), beentry->st_userid))
+		if (HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
 		{
 			values[2] = ObjectIdGetDatum(beentry->st_progress_command_target);
 			for (i = 0; i < PGSTAT_NUM_PROGRESS_PARAM; i++)
@@ -669,8 +671,7 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 			nulls[16] = true;
 
 		/* 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))
+		if (HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
 		{
 			SockAddr	zero_clientaddr;
 			char	   *clipped_activity;
@@ -1007,7 +1008,7 @@ pg_stat_get_backend_activity(PG_FUNCTION_ARGS)
 
 	if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
 		activity = "<backend information not available>";
-	else if (!has_privs_of_role(GetUserId(), beentry->st_userid))
+	else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
 		activity = "<insufficient privilege>";
 	else if (*(beentry->st_activity_raw) == '\0')
 		activity = "<command string not enabled>";
@@ -1031,7 +1032,7 @@ pg_stat_get_backend_wait_event_type(PG_FUNCTION_ARGS)
 
 	if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
 		wait_event_type = "<backend information not available>";
-	else if (!has_privs_of_role(GetUserId(), beentry->st_userid))
+	else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
 		wait_event_type = "<insufficient privilege>";
 	else if ((proc = BackendPidGetProc(beentry->st_procpid)) != NULL)
 		wait_event_type = pgstat_get_wait_event_type(proc->wait_event_info);
@@ -1052,7 +1053,7 @@ pg_stat_get_backend_wait_event(PG_FUNCTION_ARGS)
 
 	if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
 		wait_event = "<backend information not available>";
-	else if (!has_privs_of_role(GetUserId(), beentry->st_userid))
+	else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
 		wait_event = "<insufficient privilege>";
 	else if ((proc = BackendPidGetProc(beentry->st_procpid)) != NULL)
 		wait_event = pgstat_get_wait_event(proc->wait_event_info);
@@ -1074,7 +1075,7 @@ pg_stat_get_backend_activity_start(PG_FUNCTION_ARGS)
 	if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
 		PG_RETURN_NULL();
 
-	if (!has_privs_of_role(GetUserId(), beentry->st_userid))
+	else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
 		PG_RETURN_NULL();
 
 	result = beentry->st_activity_start_timestamp;
@@ -1100,7 +1101,7 @@ pg_stat_get_backend_xact_start(PG_FUNCTION_ARGS)
 	if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
 		PG_RETURN_NULL();
 
-	if (!has_privs_of_role(GetUserId(), beentry->st_userid))
+	else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
 		PG_RETURN_NULL();
 
 	result = beentry->st_xact_start_timestamp;
@@ -1122,7 +1123,7 @@ pg_stat_get_backend_start(PG_FUNCTION_ARGS)
 	if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
 		PG_RETURN_NULL();
 
-	if (!has_privs_of_role(GetUserId(), beentry->st_userid))
+	else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
 		PG_RETURN_NULL();
 
 	result = beentry->st_proc_start_timestamp;
@@ -1146,7 +1147,7 @@ pg_stat_get_backend_client_addr(PG_FUNCTION_ARGS)
 	if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
 		PG_RETURN_NULL();
 
-	if (!has_privs_of_role(GetUserId(), beentry->st_userid))
+	else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
 		PG_RETURN_NULL();
 
 	/* A zeroed client addr means we don't know */
@@ -1193,7 +1194,7 @@ pg_stat_get_backend_client_port(PG_FUNCTION_ARGS)
 	if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
 		PG_RETURN_NULL();
 
-	if (!has_privs_of_role(GetUserId(), beentry->st_userid))
+	else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
 		PG_RETURN_NULL();
 
 	/* A zeroed client addr means we don't know */
#6Kyotaro Horiguchi
horikyota.ntt@gmail.com
In reply to: Magnus Hagander (#5)
Re: Allow pg_read_all_stats to read pg_stat_progress_*

At Thu, 16 Apr 2020 14:46:00 +0200, Magnus Hagander <magnus@hagander.net> wrote in

On Thu, Apr 16, 2020 at 7:05 AM Kyotaro Horiguchi <horikyota.ntt@gmail.com>
wrote:

At Wed, 15 Apr 2020 15:58:05 +0500, "Andrey M. Borodin" <
x4mmm@yandex-team.ru> wrote in

15 апр. 2020 г., в 15:25, Magnus Hagander <magnus@hagander.net>

написал(а):

I think that makes perfect sense. The documentation explicitly says

"can read all pg_stat_* views", which is clearly wrong -- so either the
code or the docs should be fixed, and it looks like it's the code that
should be fixed to me.

Should it be bug or v14 feature?

Also pgstatfuncs.c contains a lot more checks of

has_privs_of_role(GetUserId(), beentry->st_userid).

Maybe grant them all?

As for the patch, one could argue that we should just store the

resulting boolean instead of re-running the check (e.g. have a "bool
has_stats_privilege" or such), but perhaps that's an unnecessary
micro-optimization, like the attached.

Looks good to me.

pg_stat_get_activty checks (has_privs_of_role() ||
is_member_of_role()) in-place for every entry. It's not necessary but
I suppose that doing the same thing for pg_stat_progress_info might be
better.

From a result perspective, it shouldn't make a difference though, should
it? It's a micro-optimization, but it might not have an actual performance
effect in reality as well, but the result should always be the same?

(FWIW, pg_stat_statements has a coding pattern similar to the one I
suggested in the patch)

As a priciple, I prefer the "optimized" (or pg_stat_statements')
pattern because that style suggests that the privilege is (shold be)
same to all entries, not because that it might be a bit faster. My
suggestion above is just from "same style with a nearby code". But at
least the v2 code introduces the third style (mixture of in-place and
pre-evaluated) seemed a kind of ad-hoc.

It's another issue, but pg_stat_get_backend_* functions don't consider
pg_read_all_stats. I suppose that the functions should work under the
same criteria to pg_stat views, and maybe explicitly documented?

That's a good question. They haven't been documented to do so, but it
certainly seems *weird* that the same information should be available
through a view like pg_stat_activity, but not through the functions.

I would guess this was simply forgotten in 25fff40798f -- I don't recall
any discussion about it. The commit message specifically says
pg_database_size() and pg_tablespace_size(), but mentions nothing about
pg_stat_*.

Yeah. pg_database_size() ERRORs out for insufficient privileges. On
the other hand pg_stat_* returns "<insufficient privilege>" not
ERRORing out.

For example, pg_stat_get_backend_wait_event_type is documented as

https://www.postgresql.org/docs/current/monitoring-stats.html#MONITORING-STATS-BACKEND-FUNCS-TABLE

"Wait event type name if backend is currently waiting, otherwise
NULL. See Table 27.4 for details."

I would read this as "If the function returns non-null value, the
returned value represents the wait event type mentioned in Table
27.4", but, "<insufficient privilege>" is not a wait event type. I
think something like "text-returning functions may return some
out-of-the-domain strings like "<insufficient privilege>" under
corresponding conditions".

If we do that, it may be better that we define "PGSTAT_VIEW_PRIV()" or
something like and replace the all occurances of the idiomatic
condition with it.

You mean something like the attached?

Exactly. It looks good to me. Thanks!

regards.

--
Kyotaro Horiguchi
NTT Open Source Software Center

#7Andrey M. Borodin
x4mmm@yandex-team.ru
In reply to: Magnus Hagander (#5)
Re: Allow pg_read_all_stats to read pg_stat_progress_*

16 апр. 2020 г., в 17:46, Magnus Hagander <magnus@hagander.net> написал(а):

If we do that, it may be better that we define "PGSTAT_VIEW_PRIV()" or
something like and replace the all occurances of the idiomatic
condition with it.

You mean something like the attached?

<allow_read_all_stats3.diff>

Is it correct that we use DEFAULT_ROLE_READ_ALL_STATS regardless of inheritance? I'm not familiar with what is inherited and what is not, so I think it's better to ask explicitly.

+#define HAS_PGSTAT_PERMISSIONS(role) (is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_STATS) || has_privs_of_role(GetUserId(), role))

Besides this, the patch looks good to me.
Thanks!

Best regards, Andrey Borodin,

#8Magnus Hagander
magnus@hagander.net
In reply to: Andrey M. Borodin (#7)
Re: Allow pg_read_all_stats to read pg_stat_progress_*

On Mon, Apr 20, 2020 at 12:43 PM Andrey M. Borodin <x4mmm@yandex-team.ru>
wrote:

16 апр. 2020 г., в 17:46, Magnus Hagander <magnus@hagander.net>

написал(а):

If we do that, it may be better that we define "PGSTAT_VIEW_PRIV()" or
something like and replace the all occurances of the idiomatic
condition with it.

You mean something like the attached?

<allow_read_all_stats3.diff>

Is it correct that we use DEFAULT_ROLE_READ_ALL_STATS regardless of
inheritance? I'm not familiar with what is inherited and what is not, so I
think it's better to ask explicitly.

+#define HAS_PGSTAT_PERMISSIONS(role) (is_member_of_role(GetUserId(),
DEFAULT_ROLE_READ_ALL_STATS) || has_privs_of_role(GetUserId(), role))

It is consistent with all the other uses of DEFAULT_ROLE_READ_ALL_STATS
that I can find.

Besides this, the patch looks good to me.

Thanks, I've pushed it now.

--
Magnus Hagander
Me: https://www.hagander.net/ <http://www.hagander.net/&gt;
Work: https://www.redpill-linpro.com/ <http://www.redpill-linpro.com/&gt;

#9Stephen Frost
sfrost@snowman.net
In reply to: Magnus Hagander (#8)
Re: Allow pg_read_all_stats to read pg_stat_progress_*

Greetings,

* Magnus Hagander (magnus@hagander.net) wrote:

On Mon, Apr 20, 2020 at 12:43 PM Andrey M. Borodin <x4mmm@yandex-team.ru>
wrote:

16 апр. 2020 г., в 17:46, Magnus Hagander <magnus@hagander.net>

написал(а):

If we do that, it may be better that we define "PGSTAT_VIEW_PRIV()" or
something like and replace the all occurances of the idiomatic
condition with it.

You mean something like the attached?

<allow_read_all_stats3.diff>

Is it correct that we use DEFAULT_ROLE_READ_ALL_STATS regardless of
inheritance? I'm not familiar with what is inherited and what is not, so I
think it's better to ask explicitly.

+#define HAS_PGSTAT_PERMISSIONS(role) (is_member_of_role(GetUserId(),
DEFAULT_ROLE_READ_ALL_STATS) || has_privs_of_role(GetUserId(), role))

It is consistent with all the other uses of DEFAULT_ROLE_READ_ALL_STATS
that I can find.

Ugh. That doesn't make it correct though.. We really should be using
has_privs_of_role() for these cases (and that goes for all of the
default role cases- some of which are correct and others are not, it
seems).

Thanks,

Stephen

#10Tom Lane
tgl@sss.pgh.pa.us
In reply to: Stephen Frost (#9)
Re: Allow pg_read_all_stats to read pg_stat_progress_*

Stephen Frost <sfrost@snowman.net> writes:

Ugh. That doesn't make it correct though.. We really should be using
has_privs_of_role() for these cases (and that goes for all of the
default role cases- some of which are correct and others are not, it
seems).

I have a different concern about this patch: while reading statistical
values is fine, do we REALLY want pg_read_all_stats to enable
pg_stat_get_activity(), ie viewing other sessions' command strings?
That opens security considerations that don't seem to me to be covered
by the description of the role.

regards, tom lane

#11Magnus Hagander
magnus@hagander.net
In reply to: Tom Lane (#10)
Re: Allow pg_read_all_stats to read pg_stat_progress_*

On Mon, Apr 20, 2020 at 4:12 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:

Stephen Frost <sfrost@snowman.net> writes:

Ugh. That doesn't make it correct though.. We really should be using
has_privs_of_role() for these cases (and that goes for all of the
default role cases- some of which are correct and others are not, it
seems).

I have a different concern about this patch: while reading statistical
values is fine, do we REALLY want pg_read_all_stats to enable
pg_stat_get_activity(), ie viewing other sessions' command strings?
That opens security considerations that don't seem to me to be covered
by the description of the role.

It already did allow that, and that's fully documented.

The patch only adds the ability to get at it through functions, but not
through views. (And the pg_stat_progress_* views).

The pg_stat_activity change is only:
@@ -669,8 +671,7 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
nulls[16] = true;

                /* 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))
+               if (HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
                {
                        SockAddr        zero_clientaddr;
                        char       *clipped_activity;

Which moves the check into the macro, but doesn't change how it works.

--
Magnus Hagander
Me: https://www.hagander.net/ <http://www.hagander.net/&gt;
Work: https://www.redpill-linpro.com/ <http://www.redpill-linpro.com/&gt;