mirror of
https://github.com/postgres/postgres.git
synced 2025-07-28 23:42:10 +03:00
Revoke PUBLIC CREATE from public schema, now owned by pg_database_owner.
This switches the default ACL to what the documentation has recommended since CVE-2018-1058. Upgrades will carry forward any old ownership and ACL. Sites that declined the 2018 recommendation should take a fresh look. Recipes for commissioning a new database cluster from scratch may need to create a schema, grant more privileges, etc. Out-of-tree test suites may require such updates. Reviewed by Peter Eisentraut. Discussion: https://postgr.es/m/20201031163518.GB4039133@rfd.leadboat.com
This commit is contained in:
@ -1633,8 +1633,7 @@ setup_privileges(FILE *cmdfd)
|
||||
CppAsString2(RELKIND_VIEW) ", " CppAsString2(RELKIND_MATVIEW) ", "
|
||||
CppAsString2(RELKIND_SEQUENCE) ")"
|
||||
" AND relacl IS NULL;\n\n",
|
||||
"GRANT USAGE ON SCHEMA pg_catalog TO PUBLIC;\n\n",
|
||||
"GRANT CREATE, USAGE ON SCHEMA public TO PUBLIC;\n\n",
|
||||
"GRANT USAGE ON SCHEMA pg_catalog, public TO PUBLIC;\n\n",
|
||||
"REVOKE ALL ON pg_largeobject FROM PUBLIC;\n\n",
|
||||
"INSERT INTO pg_init_privs "
|
||||
" (objoid, classoid, objsubid, initprivs, privtype)"
|
||||
|
@ -1623,11 +1623,12 @@ selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout)
|
||||
* no-mans-land between being a system object and a user object.
|
||||
* CREATE SCHEMA would fail, so its DUMP_COMPONENT_DEFINITION is just
|
||||
* a comment and an indication of ownership. If the owner is the
|
||||
* default, that DUMP_COMPONENT_DEFINITION is superfluous.
|
||||
* default, omit that superfluous DUMP_COMPONENT_DEFINITION. Before
|
||||
* v15, the default owner was BOOTSTRAP_SUPERUSERID.
|
||||
*/
|
||||
nsinfo->create = false;
|
||||
nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
|
||||
if (nsinfo->nspowner == BOOTSTRAP_SUPERUSERID)
|
||||
if (nsinfo->nspowner == ROLE_PG_DATABASE_OWNER)
|
||||
nsinfo->dobj.dump &= ~DUMP_COMPONENT_DEFINITION;
|
||||
nsinfo->dobj.dump_contains = DUMP_COMPONENT_ALL;
|
||||
}
|
||||
@ -4850,21 +4851,26 @@ getNamespaces(Archive *fout, int *numNamespaces)
|
||||
PQExpBuffer init_racl_subquery = createPQExpBuffer();
|
||||
|
||||
/*
|
||||
* Bypass pg_init_privs.initprivs for the public schema. Dropping and
|
||||
* recreating the schema detaches it from its pg_init_privs row, but
|
||||
* an empty destination database starts with this ACL nonetheless.
|
||||
* Also, we support dump/reload of public schema ownership changes.
|
||||
* ALTER SCHEMA OWNER filters nspacl through aclnewowner(), but
|
||||
* initprivs continues to reflect the initial owner (the bootstrap
|
||||
* superuser). Hence, synthesize the value that nspacl will have
|
||||
* after the restore's ALTER SCHEMA OWNER.
|
||||
* Bypass pg_init_privs.initprivs for the public schema, for several
|
||||
* reasons. First, dropping and recreating the schema detaches it
|
||||
* from its pg_init_privs row, but an empty destination database
|
||||
* starts with this ACL nonetheless. Second, we support dump/reload
|
||||
* of public schema ownership changes. ALTER SCHEMA OWNER filters
|
||||
* nspacl through aclnewowner(), but initprivs continues to reflect
|
||||
* the initial owner. Hence, synthesize the value that nspacl will
|
||||
* have after the restore's ALTER SCHEMA OWNER. Third, this makes the
|
||||
* destination database match the source's ACL, even if the latter was
|
||||
* an initdb-default ACL, which changed in v15. An upgrade pulls in
|
||||
* changes to most system object ACLs that the DBA had not customized.
|
||||
* We've made the public schema depart from that, because changing its
|
||||
* ACL so easily breaks applications.
|
||||
*/
|
||||
buildACLQueries(acl_subquery, racl_subquery, init_acl_subquery,
|
||||
init_racl_subquery, "n.nspacl", "n.nspowner",
|
||||
"CASE WHEN n.nspname = 'public' THEN array["
|
||||
" format('%s=UC/%s', "
|
||||
" n.nspowner::regrole, n.nspowner::regrole),"
|
||||
" format('=UC/%s', n.nspowner::regrole)]::aclitem[] "
|
||||
" format('=U/%s', n.nspowner::regrole)]::aclitem[] "
|
||||
"ELSE pip.initprivs END",
|
||||
"'n'", dopt->binary_upgrade);
|
||||
|
||||
|
@ -628,7 +628,9 @@ my %tests = (
|
||||
},
|
||||
|
||||
'ALTER SCHEMA public OWNER TO' => {
|
||||
# see test "REVOKE CREATE ON SCHEMA public" for causative create_sql
|
||||
create_order => 15,
|
||||
create_sql =>
|
||||
'ALTER SCHEMA public OWNER TO "regress_quoted \"" role";',
|
||||
regexp => qr/^ALTER SCHEMA public OWNER TO .+;/m,
|
||||
like => {
|
||||
%full_runs, section_pre_data => 1,
|
||||
@ -3472,17 +3474,12 @@ my %tests = (
|
||||
unlike => { no_privs => 1, },
|
||||
},
|
||||
|
||||
'REVOKE CREATE ON SCHEMA public FROM public' => {
|
||||
'REVOKE ALL ON SCHEMA public' => {
|
||||
create_order => 16,
|
||||
create_sql => '
|
||||
REVOKE CREATE ON SCHEMA public FROM public;
|
||||
ALTER SCHEMA public OWNER TO "regress_quoted \"" role";
|
||||
REVOKE ALL ON SCHEMA public FROM "regress_quoted \"" role";',
|
||||
regexp => qr/^
|
||||
\QREVOKE ALL ON SCHEMA public FROM "regress_quoted \E\\""\ role";
|
||||
\n\QREVOKE ALL ON SCHEMA public FROM PUBLIC;\E
|
||||
\n\QGRANT USAGE ON SCHEMA public TO PUBLIC;\E
|
||||
/xm,
|
||||
create_sql =>
|
||||
'REVOKE ALL ON SCHEMA public FROM "regress_quoted \"" role";',
|
||||
regexp =>
|
||||
qr/^REVOKE ALL ON SCHEMA public FROM "regress_quoted \\"" role";/m,
|
||||
like => { %full_runs, section_pre_data => 1, },
|
||||
unlike => { no_privs => 1, },
|
||||
},
|
||||
|
@ -53,6 +53,6 @@
|
||||
*/
|
||||
|
||||
/* yyyymmddN */
|
||||
#define CATALOG_VERSION_NO 202109061
|
||||
#define CATALOG_VERSION_NO 202109101
|
||||
|
||||
#endif
|
||||
|
@ -21,6 +21,6 @@
|
||||
# update dumpNamespace() if changing this descr
|
||||
{ oid => '2200', oid_symbol => 'PG_PUBLIC_NAMESPACE',
|
||||
descr => 'standard public schema',
|
||||
nspname => 'public', nspacl => '_null_' },
|
||||
nspname => 'public', nspowner => 'pg_database_owner', nspacl => '_null_' },
|
||||
|
||||
]
|
||||
|
@ -25,6 +25,9 @@ CREATE EXTENSION plperl;
|
||||
CREATE EXTENSION plperlu; -- fail
|
||||
ERROR: permission denied to create extension "plperlu"
|
||||
HINT: Must be superuser to create this extension.
|
||||
CREATE SCHEMA plperl_setup_scratch;
|
||||
SET search_path = plperl_setup_scratch;
|
||||
GRANT ALL ON SCHEMA plperl_setup_scratch TO regress_user2;
|
||||
CREATE FUNCTION foo1() returns int language plperl as '1;';
|
||||
SELECT foo1();
|
||||
foo1
|
||||
@ -34,6 +37,7 @@ SELECT foo1();
|
||||
|
||||
-- Must reconnect to avoid failure with non-MULTIPLICITY Perl interpreters
|
||||
\c -
|
||||
SET search_path = plperl_setup_scratch;
|
||||
SET ROLE regress_user1;
|
||||
-- Should be able to change privileges on the language
|
||||
revoke all on language plperl from public;
|
||||
|
@ -27,12 +27,16 @@ SET ROLE regress_user1;
|
||||
|
||||
CREATE EXTENSION plperl;
|
||||
CREATE EXTENSION plperlu; -- fail
|
||||
CREATE SCHEMA plperl_setup_scratch;
|
||||
SET search_path = plperl_setup_scratch;
|
||||
GRANT ALL ON SCHEMA plperl_setup_scratch TO regress_user2;
|
||||
|
||||
CREATE FUNCTION foo1() returns int language plperl as '1;';
|
||||
SELECT foo1();
|
||||
|
||||
-- Must reconnect to avoid failure with non-MULTIPLICITY Perl interpreters
|
||||
\c -
|
||||
SET search_path = plperl_setup_scratch;
|
||||
|
||||
SET ROLE regress_user1;
|
||||
|
||||
|
@ -388,7 +388,7 @@ CREATE INDEX k ON testschema.tablespace_acl (c) TABLESPACE regress_tblspace;
|
||||
ALTER TABLE testschema.tablespace_acl OWNER TO regress_tablespace_user2;
|
||||
|
||||
SET SESSION ROLE regress_tablespace_user2;
|
||||
CREATE TABLE tablespace_table (i int) TABLESPACE regress_tblspace; -- fail
|
||||
CREATE TEMP TABLE tablespace_table (i int) TABLESPACE regress_tblspace; -- fail
|
||||
ALTER TABLE testschema.tablespace_acl ALTER c TYPE bigint;
|
||||
REINDEX (TABLESPACE regress_tblspace) TABLE tablespace_table; -- fail
|
||||
REINDEX (TABLESPACE regress_tblspace, CONCURRENTLY) TABLE tablespace_table; -- fail
|
||||
@ -409,3 +409,6 @@ DROP SCHEMA testschema CASCADE;
|
||||
|
||||
DROP ROLE regress_tablespace_user1;
|
||||
DROP ROLE regress_tablespace_user2;
|
||||
|
||||
-- Rest of this suite can use the public schema freely.
|
||||
GRANT ALL ON SCHEMA public TO public;
|
||||
|
@ -908,7 +908,7 @@ CREATE TABLE testschema.tablespace_acl (c int);
|
||||
CREATE INDEX k ON testschema.tablespace_acl (c) TABLESPACE regress_tblspace;
|
||||
ALTER TABLE testschema.tablespace_acl OWNER TO regress_tablespace_user2;
|
||||
SET SESSION ROLE regress_tablespace_user2;
|
||||
CREATE TABLE tablespace_table (i int) TABLESPACE regress_tblspace; -- fail
|
||||
CREATE TEMP TABLE tablespace_table (i int) TABLESPACE regress_tblspace; -- fail
|
||||
ERROR: permission denied for tablespace regress_tblspace
|
||||
ALTER TABLE testschema.tablespace_acl ALTER c TYPE bigint;
|
||||
REINDEX (TABLESPACE regress_tblspace) TABLE tablespace_table; -- fail
|
||||
@ -934,3 +934,5 @@ drop cascades to table testschema.atable
|
||||
drop cascades to table testschema.tablespace_acl
|
||||
DROP ROLE regress_tablespace_user1;
|
||||
DROP ROLE regress_tablespace_user2;
|
||||
-- Rest of this suite can use the public schema freely.
|
||||
GRANT ALL ON SCHEMA public TO public;
|
||||
|
Reference in New Issue
Block a user