Skip to content

Commit 2930078

Browse files
committed
Reserve the "pg_" namespace for roles
This will prevent users from creating roles which begin with "pg_" and will check for those roles before allowing an upgrade using pg_upgrade. This will allow for default roles to be provided at initdb time. Reviews by José Luis Tallón and Robert Haas
1 parent fa6075e commit 2930078

File tree

21 files changed

+226
-13
lines changed

21 files changed

+226
-13
lines changed

doc/src/sgml/ref/psql-ref.sgml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1365,13 +1365,15 @@ testdb=>
13651365

13661366

13671367
<varlistentry>
1368-
<term><literal>\dg[+] [ <link linkend="APP-PSQL-patterns"><replaceable class="parameter">pattern</replaceable></link> ]</literal></term>
1368+
<term><literal>\dg[S+] [ <link linkend="APP-PSQL-patterns"><replaceable class="parameter">pattern</replaceable></link> ]</literal></term>
13691369
<listitem>
13701370
<para>
13711371
Lists database roles.
13721372
(Since the concepts of <quote>users</> and <quote>groups</> have been
13731373
unified into <quote>roles</>, this command is now equivalent to
13741374
<literal>\du</literal>.)
1375+
By default, only user-created roles are shown; supply the
1376+
<literal>S</literal> modifier to include system roles.
13751377
If <replaceable class="parameter">pattern</replaceable> is specified,
13761378
only those roles whose names match the pattern are listed.
13771379
If the form <literal>\dg+</literal> is used, additional information
@@ -1525,13 +1527,15 @@ testdb=&gt;
15251527
</varlistentry>
15261528

15271529
<varlistentry>
1528-
<term><literal>\du[+] [ <link linkend="APP-PSQL-patterns"><replaceable class="parameter">pattern</replaceable></link> ]</literal></term>
1530+
<term><literal>\du[S+] [ <link linkend="APP-PSQL-patterns"><replaceable class="parameter">pattern</replaceable></link> ]</literal></term>
15291531
<listitem>
15301532
<para>
15311533
Lists database roles.
15321534
(Since the concepts of <quote>users</> and <quote>groups</> have been
15331535
unified into <quote>roles</>, this command is now equivalent to
15341536
<literal>\dg</literal>.)
1537+
By default, only user-created roles are shown; supply the
1538+
<literal>S</literal> modifier to include system roles.
15351539
If <replaceable class="parameter">pattern</replaceable> is specified,
15361540
only those roles whose names match the pattern are listed.
15371541
If the form <literal>\du+</literal> is used, additional information

src/backend/catalog/aclchk.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,9 @@ ExecuteGrantStmt(GrantStmt *stmt)
423423
grantee_uid = ACL_ID_PUBLIC;
424424
break;
425425
default:
426+
if (!IsBootstrapProcessingMode())
427+
check_rolespec_name((Node *) grantee,
428+
"Cannot GRANT or REVOKE privileges to or from a reserved role.");
426429
grantee_uid = get_rolespec_oid((Node *) grantee, false);
427430
break;
428431
}
@@ -918,6 +921,8 @@ ExecAlterDefaultPrivilegesStmt(AlterDefaultPrivilegesStmt *stmt)
918921
grantee_uid = ACL_ID_PUBLIC;
919922
break;
920923
default:
924+
check_rolespec_name((Node *) grantee,
925+
"Cannot GRANT or REVOKE default privileges to or from a reserved role.");
921926
grantee_uid = get_rolespec_oid((Node *) grantee, false);
922927
break;
923928
}
@@ -1008,6 +1013,8 @@ ExecAlterDefaultPrivilegesStmt(AlterDefaultPrivilegesStmt *stmt)
10081013
{
10091014
RoleSpec *rolespec = lfirst(rolecell);
10101015

1016+
check_rolespec_name((Node *) rolespec,
1017+
"Cannot alter default privileges for reserved role.");
10111018
iacls.roleid = get_rolespec_oid((Node *) rolespec, false);
10121019

10131020
/*

src/backend/catalog/catalog.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,8 +184,9 @@ IsToastNamespace(Oid namespaceId)
184184
* True iff name starts with the pg_ prefix.
185185
*
186186
* For some classes of objects, the prefix pg_ is reserved for
187-
* system objects only. As of 8.0, this is only true for
188-
* schema and tablespace names.
187+
* system objects only. As of 8.0, this was only true for
188+
* schema and tablespace names. With 9.6, this is also true
189+
* for roles.
189190
*/
190191
bool
191192
IsReservedName(const char *name)

src/backend/commands/alter.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -747,6 +747,9 @@ ExecAlterOwnerStmt(AlterOwnerStmt *stmt)
747747
{
748748
Oid newowner = get_rolespec_oid(stmt->newowner, false);
749749

750+
check_rolespec_name(stmt->newowner,
751+
"Cannot make reserved roles owners of objects.");
752+
750753
switch (stmt->objectType)
751754
{
752755
case OBJECT_DATABASE:

src/backend/commands/foreigncmds.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1148,6 +1148,10 @@ CreateUserMapping(CreateUserMappingStmt *stmt)
11481148
else
11491149
useId = get_rolespec_oid(stmt->user, false);
11501150

1151+
/* Additional check to protect reserved role names */
1152+
check_rolespec_name(stmt->user,
1153+
"Cannot specify reserved role as mapping user.");
1154+
11511155
/* Check that the server exists. */
11521156
srv = GetForeignServerByName(stmt->servername, false);
11531157

@@ -1248,6 +1252,10 @@ AlterUserMapping(AlterUserMappingStmt *stmt)
12481252
else
12491253
useId = get_rolespec_oid(stmt->user, false);
12501254

1255+
/* Additional check to protect reserved role names */
1256+
check_rolespec_name(stmt->user,
1257+
"Cannot alter reserved role mapping user.");
1258+
12511259
srv = GetForeignServerByName(stmt->servername, false);
12521260

12531261
umId = GetSysCacheOid2(USERMAPPINGUSERSERVER,
@@ -1337,6 +1345,11 @@ RemoveUserMapping(DropUserMappingStmt *stmt)
13371345
else
13381346
{
13391347
useId = get_rolespec_oid(stmt->user, stmt->missing_ok);
1348+
1349+
/* Additional check to protect reserved role names */
1350+
check_rolespec_name(stmt->user,
1351+
"Cannot remove reserved role mapping user.");
1352+
13401353
if (!OidIsValid(useId))
13411354
{
13421355
/*

src/backend/commands/policy.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,13 @@ policy_role_list_to_array(List *roles, int *num_roles)
176176
return role_oids;
177177
}
178178
else
179+
{
180+
/* Additional check to protect reserved role names */
181+
check_rolespec_name((Node *) spec,
182+
"Cannot specify reserved role as policy target");
179183
role_oids[i++] =
180184
ObjectIdGetDatum(get_rolespec_oid((Node *) spec, false));
185+
}
181186
}
182187

183188
return role_oids;

src/backend/commands/schemacmds.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString)
6565
else
6666
owner_uid = saved_uid;
6767

68+
/* Additional check to protect reserved role names */
69+
check_rolespec_name(stmt->authrole,
70+
"Cannot specify reserved role as owner.");
71+
6872
/* fill schema name with the user name if not specified */
6973
if (!schemaName)
7074
{

src/backend/commands/tablecmds.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3566,6 +3566,8 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
35663566
(List *) cmd->def, lockmode);
35673567
break;
35683568
case AT_ChangeOwner: /* ALTER OWNER */
3569+
check_rolespec_name(cmd->newowner,
3570+
"Cannot specify reserved role as owner.");
35693571
ATExecChangeOwner(RelationGetRelid(rel),
35703572
get_rolespec_oid(cmd->newowner, false),
35713573
false, lockmode);

src/backend/commands/tablespace.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,10 @@ CreateTableSpace(CreateTableSpaceStmt *stmt)
256256
else
257257
ownerId = GetUserId();
258258

259+
/* Additional check to protect reserved role names */
260+
check_rolespec_name(stmt->owner,
261+
"Cannot specify reserved role as owner.");
262+
259263
/* Unix-ify the offered path, and strip any trailing slashes */
260264
location = pstrdup(stmt->location);
261265
canonicalize_path(location);

src/backend/commands/user.c

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "access/htup_details.h"
1818
#include "access/xact.h"
1919
#include "catalog/binary_upgrade.h"
20+
#include "catalog/catalog.h"
2021
#include "catalog/dependency.h"
2122
#include "catalog/indexing.h"
2223
#include "catalog/objectaccess.h"
@@ -311,6 +312,17 @@ CreateRole(CreateRoleStmt *stmt)
311312
errmsg("permission denied to create role")));
312313
}
313314

315+
/*
316+
* Check that the user is not trying to create a role in the reserved
317+
* "pg_" namespace.
318+
*/
319+
if (IsReservedName(stmt->role))
320+
ereport(ERROR,
321+
(errcode(ERRCODE_RESERVED_NAME),
322+
errmsg("role name \"%s\" is reserved",
323+
stmt->role),
324+
errdetail("Role names starting with \"pg_\" are reserved.")));
325+
314326
/*
315327
* Check the pg_authid relation to be certain the role doesn't already
316328
* exist.
@@ -507,6 +519,9 @@ AlterRole(AlterRoleStmt *stmt)
507519
DefElem *dbypassRLS = NULL;
508520
Oid roleid;
509521

522+
check_rolespec_name(stmt->role,
523+
"Cannot alter reserved roles.");
524+
510525
/* Extract options from the statement node tree */
511526
foreach(option, stmt->options)
512527
{
@@ -857,6 +872,9 @@ AlterRoleSet(AlterRoleSetStmt *stmt)
857872

858873
if (stmt->role)
859874
{
875+
check_rolespec_name(stmt->role,
876+
"Cannot alter reserved roles.");
877+
860878
roletuple = get_rolespec_tuple(stmt->role);
861879
roleid = HeapTupleGetOid(roletuple);
862880

@@ -1117,6 +1135,7 @@ RenameRole(const char *oldname, const char *newname)
11171135
int i;
11181136
Oid roleid;
11191137
ObjectAddress address;
1138+
Form_pg_authid authform;
11201139

11211140
rel = heap_open(AuthIdRelationId, RowExclusiveLock);
11221141
dsc = RelationGetDescr(rel);
@@ -1136,6 +1155,7 @@ RenameRole(const char *oldname, const char *newname)
11361155
*/
11371156

11381157
roleid = HeapTupleGetOid(oldtuple);
1158+
authform = (Form_pg_authid) GETSTRUCT(oldtuple);
11391159

11401160
if (roleid == GetSessionUserId())
11411161
ereport(ERROR,
@@ -1146,6 +1166,24 @@ RenameRole(const char *oldname, const char *newname)
11461166
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
11471167
errmsg("current user cannot be renamed")));
11481168

1169+
/*
1170+
* Check that the user is not trying to rename a system role and
1171+
* not trying to rename a role into the reserved "pg_" namespace.
1172+
*/
1173+
if (IsReservedName(NameStr(authform->rolname)))
1174+
ereport(ERROR,
1175+
(errcode(ERRCODE_RESERVED_NAME),
1176+
errmsg("role name \"%s\" is reserved",
1177+
NameStr(authform->rolname)),
1178+
errdetail("Role names starting with \"pg_\" are reserved.")));
1179+
1180+
if (IsReservedName(newname))
1181+
ereport(ERROR,
1182+
(errcode(ERRCODE_RESERVED_NAME),
1183+
errmsg("role name \"%s\" is reserved",
1184+
newname),
1185+
errdetail("Role names starting with \"pg_\" are reserved.")));
1186+
11491187
/* make sure the new name doesn't exist */
11501188
if (SearchSysCacheExists1(AUTHNAME, CStringGetDatum(newname)))
11511189
ereport(ERROR,
@@ -1224,10 +1262,18 @@ GrantRole(GrantRoleStmt *stmt)
12241262
ListCell *item;
12251263

12261264
if (stmt->grantor)
1265+
{
1266+
check_rolespec_name(stmt->grantor,
1267+
"Cannot specify reserved role as grantor.");
12271268
grantor = get_rolespec_oid(stmt->grantor, false);
1269+
}
12281270
else
12291271
grantor = GetUserId();
12301272

1273+
foreach(item, stmt->grantee_roles)
1274+
check_rolespec_name(lfirst(item),
1275+
"Cannot GRANT roles to a reserved role.");
1276+
12311277
grantee_ids = roleSpecsToIds(stmt->grantee_roles);
12321278

12331279
/* AccessShareLock is enough since we aren't modifying pg_authid */
@@ -1318,6 +1364,9 @@ ReassignOwnedObjects(ReassignOwnedStmt *stmt)
13181364
errmsg("permission denied to reassign objects")));
13191365
}
13201366

1367+
check_rolespec_name(stmt->newrole,
1368+
"Cannot specify reserved role as owner.");
1369+
13211370
/* Must have privileges on the receiving side too */
13221371
newrole = get_rolespec_oid(stmt->newrole, false);
13231372

0 commit comments

Comments
 (0)