From c788ec02fd2695faeb8dc791335cced849065714 Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Thu, 26 Jul 2018 14:12:38 +0900
Subject: [PATCH 3/3] Restrict access to system-wide REINDEX for non-privileged
 users

A database owner running a system-wide REINDEX has the possibility to
also do the operation on critical system catalogs, which can cause a
PostgreSQL to go unresponsive or even block authentication.  This commit
makes sure that a user running a REINDEX SYSTEM or DATABASE only works
on the following relations:
- The user is a superuser
- The user is the table owner
- The user is the database owner, only if the relation worked on is not
shared.

Author: Michael Paquier
Discussion: https://postgr.es/m/152512087100.19803.12733865831237526317@wrigleys.postgresql.org
---
 doc/src/sgml/ref/reindex.sgml    |  3 ++-
 src/backend/commands/indexcmds.c | 10 ++++++++++
 2 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/doc/src/sgml/ref/reindex.sgml b/doc/src/sgml/ref/reindex.sgml
index 1c21fafb80..5cd1c56352 100644
--- a/doc/src/sgml/ref/reindex.sgml
+++ b/doc/src/sgml/ref/reindex.sgml
@@ -227,7 +227,8 @@ REINDEX [ ( VERBOSE ) ] { INDEX | TABLE | SCHEMA | DATABASE | SYSTEM } <replacea
    Reindexing a single index or table requires being the owner of that
    index or table.  Reindexing a database requires being the owner of
    the database (note that the owner can therefore rebuild indexes of
-   tables owned by other users).  Of course, superusers can always
+   tables owned by other users).  Reindexing a shared catalog requires
+   being the owner of that shared catalog.  Of course, superusers can always
    reindex anything.
   </para>
 
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b9dad9672e..1bfc34bc70 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -2415,6 +2415,16 @@ ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind,
 			!IsSystemClass(relid, classtuple))
 			continue;
 
+		/*
+		 * We allow the user to reindex a table if he is superuser, the table
+		 * owner, or the database owner (but in the latter case, only if it's not
+		 * a shared relation).
+		 */
+		if (!(pg_class_ownercheck(relid, GetUserId()) ||
+			  (pg_database_ownercheck(MyDatabaseId, GetUserId()) &&
+			   !classtuple->relisshared)))
+			continue;
+
 		/* Save the list of relation OIDs in private context */
 		old = MemoryContextSwitchTo(private_context);
 
-- 
2.18.0

