Skip to content

Commit bd81f7f

Browse files
authored
[PGPRO-5673] add missing grants (caused by CVE-2018-1058 fixes #415 P… (#441)
* [PGPRO-5673] add missing grants (caused by CVE-2018-1058 fixes #415 PGPRO-5315) * tests.backup.BackupTest.test_missing_replication_permission_1: fix test for changed 14s output * tests.backup.BackupTest.test_missing_replication_permission: fix test for 9.5 * tests.checkdb.CheckdbTest.test_checkdb_with_least_privileges: remove grant for nonexistent (in 10) bt_index_check(regclass, bool) * tests.checkdb.CheckdbTest.test_checkdb_with_least_privileges: remove grant for nonexistent (in 9.5) pg_catalog.pg_control_system() * tests.checkdb.CheckdbTest.test_checkdb_with_least_privileges: remove grant for nonexistent (in amcheck_next) bt_index_check(regclass) * adapt tests/restore.py to Python-3.5 (used in travis tests) * skip issue_313 test
1 parent f7a81aa commit bd81f7f

File tree

5 files changed

+78
-25
lines changed

5 files changed

+78
-25
lines changed

doc/pgprobackup.xml

+4
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,7 @@ BEGIN;
606606
CREATE ROLE backup WITH LOGIN;
607607
GRANT USAGE ON SCHEMA pg_catalog TO backup;
608608
GRANT EXECUTE ON FUNCTION pg_catalog.current_setting(text) TO backup;
609+
GRANT EXECUTE ON FUNCTION pg_catalog.set_config(text, text, boolean) TO backup;
609610
GRANT EXECUTE ON FUNCTION pg_catalog.pg_is_in_recovery() TO backup;
610611
GRANT EXECUTE ON FUNCTION pg_catalog.pg_start_backup(text, boolean) TO backup;
611612
GRANT EXECUTE ON FUNCTION pg_catalog.pg_stop_backup() TO backup;
@@ -624,6 +625,7 @@ BEGIN;
624625
CREATE ROLE backup WITH LOGIN;
625626
GRANT USAGE ON SCHEMA pg_catalog TO backup;
626627
GRANT EXECUTE ON FUNCTION pg_catalog.current_setting(text) TO backup;
628+
GRANT EXECUTE ON FUNCTION pg_catalog.set_config(text, text, boolean) TO backup;
627629
GRANT EXECUTE ON FUNCTION pg_catalog.pg_is_in_recovery() TO backup;
628630
GRANT EXECUTE ON FUNCTION pg_catalog.pg_start_backup(text, boolean, boolean) TO backup;
629631
GRANT EXECUTE ON FUNCTION pg_catalog.pg_stop_backup(boolean) TO backup;
@@ -644,6 +646,7 @@ BEGIN;
644646
CREATE ROLE backup WITH LOGIN;
645647
GRANT USAGE ON SCHEMA pg_catalog TO backup;
646648
GRANT EXECUTE ON FUNCTION pg_catalog.current_setting(text) TO backup;
649+
GRANT EXECUTE ON FUNCTION pg_catalog.set_config(text, text, boolean) TO backup;
647650
GRANT EXECUTE ON FUNCTION pg_catalog.pg_is_in_recovery() TO backup;
648651
GRANT EXECUTE ON FUNCTION pg_catalog.pg_start_backup(text, boolean, boolean) TO backup;
649652
GRANT EXECUTE ON FUNCTION pg_catalog.pg_stop_backup(boolean, boolean) TO backup;
@@ -5531,6 +5534,7 @@ BEGIN;
55315534
CREATE ROLE backup WITH LOGIN REPLICATION;
55325535
GRANT USAGE ON SCHEMA pg_catalog TO backup;
55335536
GRANT EXECUTE ON FUNCTION pg_catalog.current_setting(text) TO backup;
5537+
GRANT EXECUTE ON FUNCTION pg_catalog.set_config(text, text, boolean) TO backup;
55345538
GRANT EXECUTE ON FUNCTION pg_catalog.pg_is_in_recovery() TO backup;
55355539
GRANT EXECUTE ON FUNCTION pg_catalog.pg_start_backup(text, boolean, boolean) TO backup;
55365540
GRANT EXECUTE ON FUNCTION pg_catalog.pg_stop_backup(boolean, boolean) TO backup;

tests/backup.py

+24-16
Original file line numberDiff line numberDiff line change
@@ -2020,10 +2020,12 @@ def test_backup_with_least_privileges_role(self):
20202020
"GRANT SELECT ON TABLE pg_catalog.pg_proc TO backup; "
20212021
"GRANT SELECT ON TABLE pg_catalog.pg_extension TO backup; "
20222022
"GRANT SELECT ON TABLE pg_catalog.pg_database TO backup; " # for partial restore, checkdb and ptrack
2023+
"GRANT EXECUTE ON FUNCTION pg_catalog.oideq(oid, oid) TO backup; "
20232024
"GRANT EXECUTE ON FUNCTION pg_catalog.nameeq(name, name) TO backup; "
20242025
"GRANT EXECUTE ON FUNCTION pg_catalog.textout(text) TO backup; "
20252026
"GRANT EXECUTE ON FUNCTION pg_catalog.timestamptz(timestamp with time zone, integer) TO backup; "
20262027
"GRANT EXECUTE ON FUNCTION pg_catalog.current_setting(text) TO backup; "
2028+
"GRANT EXECUTE ON FUNCTION pg_catalog.set_config(text, text, boolean) TO backup; "
20272029
"GRANT EXECUTE ON FUNCTION pg_catalog.pg_is_in_recovery() TO backup; "
20282030
"GRANT EXECUTE ON FUNCTION pg_catalog.pg_start_backup(text, boolean) TO backup; "
20292031
"GRANT EXECUTE ON FUNCTION pg_catalog.pg_stop_backup() TO backup; "
@@ -2053,10 +2055,12 @@ def test_backup_with_least_privileges_role(self):
20532055
"GRANT SELECT ON TABLE pg_catalog.pg_extension TO backup; "
20542056
"GRANT SELECT ON TABLE pg_catalog.pg_proc TO backup; "
20552057
"GRANT SELECT ON TABLE pg_catalog.pg_database TO backup; " # for partial restore, checkdb and ptrack
2058+
"GRANT EXECUTE ON FUNCTION pg_catalog.oideq(oid, oid) TO backup; "
20562059
"GRANT EXECUTE ON FUNCTION pg_catalog.nameeq(name, name) TO backup; "
20572060
"GRANT EXECUTE ON FUNCTION pg_catalog.textout(text) TO backup; "
20582061
"GRANT EXECUTE ON FUNCTION pg_catalog.timestamptz(timestamp with time zone, integer) TO backup; "
20592062
"GRANT EXECUTE ON FUNCTION pg_catalog.current_setting(text) TO backup; "
2063+
"GRANT EXECUTE ON FUNCTION pg_catalog.set_config(text, text, boolean) TO backup; "
20602064
"GRANT EXECUTE ON FUNCTION pg_catalog.pg_is_in_recovery() TO backup; "
20612065
"GRANT EXECUTE ON FUNCTION pg_catalog.pg_control_system() TO backup; "
20622066
"GRANT EXECUTE ON FUNCTION pg_catalog.pg_start_backup(text, boolean, boolean) TO backup; "
@@ -2091,8 +2095,10 @@ def test_backup_with_least_privileges_role(self):
20912095
"GRANT SELECT ON TABLE pg_catalog.pg_proc TO backup; "
20922096
"GRANT SELECT ON TABLE pg_catalog.pg_extension TO backup; "
20932097
"GRANT SELECT ON TABLE pg_catalog.pg_database TO backup; " # for partial restore, checkdb and ptrack
2098+
"GRANT EXECUTE ON FUNCTION pg_catalog.oideq(oid, oid) TO backup; "
20942099
"GRANT EXECUTE ON FUNCTION pg_catalog.nameeq(name, name) TO backup; "
20952100
"GRANT EXECUTE ON FUNCTION pg_catalog.current_setting(text) TO backup; "
2101+
"GRANT EXECUTE ON FUNCTION pg_catalog.set_config(text, text, boolean) TO backup; "
20962102
"GRANT EXECUTE ON FUNCTION pg_catalog.pg_is_in_recovery() TO backup; "
20972103
"GRANT EXECUTE ON FUNCTION pg_catalog.pg_control_system() TO backup; "
20982104
"GRANT EXECUTE ON FUNCTION pg_catalog.pg_start_backup(text, boolean, boolean) TO backup; "
@@ -3249,10 +3255,7 @@ def test_missing_replication_permission(self):
32493255
if ProbackupTest.enterprise:
32503256
node.safe_psql(
32513257
"backupdb",
3252-
"GRANT EXECUTE ON FUNCTION pg_catalog.pgpro_edition() TO backup")
3253-
3254-
node.safe_psql(
3255-
"backupdb",
3258+
"GRANT EXECUTE ON FUNCTION pg_catalog.pgpro_edition() TO backup; "
32563259
"GRANT EXECUTE ON FUNCTION pg_catalog.pgpro_version() TO backup")
32573260

32583261
sleep(2)
@@ -3270,9 +3273,11 @@ def test_missing_replication_permission(self):
32703273
"\n Output: {0} \n CMD: {1}".format(
32713274
repr(self.output), self.cmd))
32723275
except ProbackupException as e:
3273-
self.assertIn(
3274-
"FATAL: must be superuser or replication role to start walsender",
3276+
# 9.5: ERROR: must be superuser or replication role to run a backup
3277+
# >=9.6: FATAL: must be superuser or replication role to start walsender
3278+
self.assertRegex(
32753279
e.message,
3280+
"ERROR: must be superuser or replication role to run a backup|FATAL: must be superuser or replication role to start walsender",
32763281
"\n Unexpected Error Message: {0}\n CMD: {1}".format(
32773282
repr(e.message), self.cmd))
32783283

@@ -3330,7 +3335,8 @@ def test_missing_replication_permission_1(self):
33303335
"GRANT EXECUTE ON FUNCTION pg_catalog.pg_start_backup(text, boolean) TO backup; "
33313336
"GRANT EXECUTE ON FUNCTION pg_catalog.pg_stop_backup() TO backup; "
33323337
"GRANT EXECUTE ON FUNCTION pg_catalog.txid_current_snapshot() TO backup; "
3333-
"GRANT EXECUTE ON FUNCTION pg_catalog.txid_snapshot_xmax(txid_snapshot) TO backup;")
3338+
"GRANT EXECUTE ON FUNCTION pg_catalog.txid_snapshot_xmax(txid_snapshot) TO backup;"
3339+
)
33343340
# PG 9.6
33353341
elif self.get_version(node) > 90600 and self.get_version(node) < 100000:
33363342
node.safe_psql(
@@ -3353,7 +3359,8 @@ def test_missing_replication_permission_1(self):
33533359
"GRANT EXECUTE ON FUNCTION pg_catalog.pg_switch_xlog() TO backup; "
33543360
"GRANT EXECUTE ON FUNCTION pg_catalog.pg_last_xlog_replay_location() TO backup; "
33553361
"GRANT EXECUTE ON FUNCTION pg_catalog.txid_current_snapshot() TO backup; "
3356-
"GRANT EXECUTE ON FUNCTION pg_catalog.txid_snapshot_xmax(txid_snapshot) TO backup;")
3362+
"GRANT EXECUTE ON FUNCTION pg_catalog.txid_snapshot_xmax(txid_snapshot) TO backup;"
3363+
)
33573364
# >= 10
33583365
else:
33593366
node.safe_psql(
@@ -3381,10 +3388,7 @@ def test_missing_replication_permission_1(self):
33813388
if ProbackupTest.enterprise:
33823389
node.safe_psql(
33833390
"backupdb",
3384-
"GRANT EXECUTE ON FUNCTION pg_catalog.pgpro_edition() TO backup")
3385-
3386-
node.safe_psql(
3387-
"backupdb",
3391+
"GRANT EXECUTE ON FUNCTION pg_catalog.pgpro_edition() TO backup; "
33883392
"GRANT EXECUTE ON FUNCTION pg_catalog.pgpro_version() TO backup")
33893393

33903394
replica.promote()
@@ -3398,10 +3402,14 @@ def test_missing_replication_permission_1(self):
33983402
self.assertIn(
33993403
'WARNING: Valid full backup on current timeline 2 is not found, trying to look up on previous timelines',
34003404
output)
3401-
3402-
self.assertIn(
3403-
'WARNING: could not connect to database backupdb: FATAL: must be superuser or replication role to start walsender',
3404-
output)
3405+
3406+
# Messages before 14
3407+
# 'WARNING: could not connect to database backupdb: FATAL: must be superuser or replication role to start walsender'
3408+
# Messages for >=14
3409+
# 'WARNING: could not connect to database backupdb: connection to server on socket "/tmp/.s.PGSQL.30983" failed: FATAL: must be superuser or replication role to start walsender'
3410+
self.assertRegex(
3411+
output,
3412+
r'WARNING: could not connect to database backupdb: (connection to server on socket "/tmp/.s.PGSQL.\d+" failed: ){0,1}FATAL: must be superuser or replication role to start walsender')
34053413

34063414
# Clean after yourself
34073415
self.del_test_dir(module_name, fname)

tests/checkdb.py

+31-4
Original file line numberDiff line numberDiff line change
@@ -562,15 +562,14 @@ def test_checkdb_with_least_privileges(self):
562562
'GRANT SELECT ON TABLE pg_catalog.pg_index TO backup; '
563563
'GRANT SELECT ON TABLE pg_catalog.pg_namespace TO backup; '
564564
'GRANT EXECUTE ON FUNCTION pg_catalog.current_setting(text) TO backup; '
565+
'GRANT EXECUTE ON FUNCTION pg_catalog.set_config(text, text, boolean) TO backup; '
565566
'GRANT EXECUTE ON FUNCTION pg_catalog.nameeq(name, name) TO backup; '
566567
'GRANT EXECUTE ON FUNCTION pg_catalog.namene(name, name) TO backup; '
567568
'GRANT EXECUTE ON FUNCTION pg_catalog.int8(integer) TO backup; '
568569
'GRANT EXECUTE ON FUNCTION pg_catalog.oideq(oid, oid) TO backup; '
569570
'GRANT EXECUTE ON FUNCTION pg_catalog.charne("char", "char") TO backup; '
570571
'GRANT EXECUTE ON FUNCTION pg_catalog.pg_is_in_recovery() TO backup; '
571-
'GRANT EXECUTE ON FUNCTION pg_catalog.pg_control_system() TO backup; '
572-
'GRANT EXECUTE ON FUNCTION bt_index_check(regclass) TO backup; '
573-
'GRANT EXECUTE ON FUNCTION bt_index_check(regclass, bool) TO backup;'
572+
'GRANT EXECUTE ON FUNCTION bt_index_check(regclass, bool) TO backup;' # amcheck-next function
574573
)
575574
# PG 9.6
576575
elif self.get_version(node) > 90600 and self.get_version(node) < 100000:
@@ -588,6 +587,7 @@ def test_checkdb_with_least_privileges(self):
588587
'GRANT SELECT ON TABLE pg_catalog.pg_index TO backup; '
589588
'GRANT SELECT ON TABLE pg_catalog.pg_namespace TO backup; '
590589
'GRANT EXECUTE ON FUNCTION pg_catalog.current_setting(text) TO backup; '
590+
'GRANT EXECUTE ON FUNCTION pg_catalog.set_config(text, text, boolean) TO backup; '
591591
'GRANT EXECUTE ON FUNCTION pg_catalog.nameeq(name, name) TO backup; '
592592
'GRANT EXECUTE ON FUNCTION pg_catalog.namene(name, name) TO backup; '
593593
'GRANT EXECUTE ON FUNCTION pg_catalog.int8(integer) TO backup; '
@@ -598,7 +598,33 @@ def test_checkdb_with_least_privileges(self):
598598
# 'GRANT EXECUTE ON FUNCTION bt_index_check(regclass) TO backup; '
599599
'GRANT EXECUTE ON FUNCTION bt_index_check(regclass, bool) TO backup;'
600600
)
601-
# >= 10
601+
# PG 10
602+
elif self.get_version(node) > 100000 and self.get_version(node) < 110000:
603+
node.safe_psql(
604+
'backupdb',
605+
'CREATE ROLE backup WITH LOGIN; '
606+
'GRANT CONNECT ON DATABASE backupdb to backup; '
607+
'GRANT USAGE ON SCHEMA pg_catalog TO backup; '
608+
'GRANT USAGE ON SCHEMA public TO backup; '
609+
'GRANT SELECT ON TABLE pg_catalog.pg_proc TO backup; '
610+
'GRANT SELECT ON TABLE pg_catalog.pg_extension TO backup; '
611+
'GRANT SELECT ON TABLE pg_catalog.pg_database TO backup; '
612+
'GRANT SELECT ON TABLE pg_catalog.pg_am TO backup; '
613+
'GRANT SELECT ON TABLE pg_catalog.pg_class TO backup; '
614+
'GRANT SELECT ON TABLE pg_catalog.pg_index TO backup; '
615+
'GRANT SELECT ON TABLE pg_catalog.pg_namespace TO backup; '
616+
'GRANT EXECUTE ON FUNCTION pg_catalog.current_setting(text) TO backup; '
617+
'GRANT EXECUTE ON FUNCTION pg_catalog.set_config(text, text, boolean) TO backup; '
618+
'GRANT EXECUTE ON FUNCTION pg_catalog.nameeq(name, name) TO backup; '
619+
'GRANT EXECUTE ON FUNCTION pg_catalog.namene(name, name) TO backup; '
620+
'GRANT EXECUTE ON FUNCTION pg_catalog.int8(integer) TO backup; '
621+
'GRANT EXECUTE ON FUNCTION pg_catalog.oideq(oid, oid) TO backup; '
622+
'GRANT EXECUTE ON FUNCTION pg_catalog.charne("char", "char") TO backup; '
623+
'GRANT EXECUTE ON FUNCTION pg_catalog.pg_is_in_recovery() TO backup; '
624+
'GRANT EXECUTE ON FUNCTION pg_catalog.pg_control_system() TO backup; '
625+
'GRANT EXECUTE ON FUNCTION bt_index_check(regclass) TO backup;'
626+
)
627+
# >= 11
602628
else:
603629
node.safe_psql(
604630
'backupdb',
@@ -614,6 +640,7 @@ def test_checkdb_with_least_privileges(self):
614640
'GRANT SELECT ON TABLE pg_catalog.pg_index TO backup; '
615641
'GRANT SELECT ON TABLE pg_catalog.pg_namespace TO backup; '
616642
'GRANT EXECUTE ON FUNCTION pg_catalog.current_setting(text) TO backup; '
643+
'GRANT EXECUTE ON FUNCTION pg_catalog.set_config(text, text, boolean) TO backup; '
617644
'GRANT EXECUTE ON FUNCTION pg_catalog.nameeq(name, name) TO backup; '
618645
'GRANT EXECUTE ON FUNCTION pg_catalog.namene(name, name) TO backup; '
619646
'GRANT EXECUTE ON FUNCTION pg_catalog.int8(integer) TO backup; '

tests/ptrack.py

+6
Original file line numberDiff line numberDiff line change
@@ -402,10 +402,12 @@ def test_ptrack_unprivileged(self):
402402
"GRANT USAGE ON SCHEMA pg_catalog TO backup; "
403403
"GRANT SELECT ON TABLE pg_catalog.pg_proc TO backup; "
404404
"GRANT SELECT ON TABLE pg_catalog.pg_database TO backup; " # for partial restore, checkdb and ptrack
405+
"GRANT EXECUTE ON FUNCTION pg_catalog.oideq(oid, oid) TO backup; "
405406
"GRANT EXECUTE ON FUNCTION pg_catalog.nameeq(name, name) TO backup; "
406407
"GRANT EXECUTE ON FUNCTION pg_catalog.textout(text) TO backup; "
407408
"GRANT EXECUTE ON FUNCTION pg_catalog.timestamptz(timestamp with time zone, integer) TO backup; "
408409
"GRANT EXECUTE ON FUNCTION pg_catalog.current_setting(text) TO backup; "
410+
"GRANT EXECUTE ON FUNCTION pg_catalog.set_config(text, text, boolean) TO backup; "
409411
"GRANT EXECUTE ON FUNCTION pg_catalog.pg_is_in_recovery() TO backup; "
410412
"GRANT EXECUTE ON FUNCTION pg_catalog.pg_start_backup(text, boolean) TO backup; "
411413
"GRANT EXECUTE ON FUNCTION pg_catalog.pg_stop_backup() TO backup; "
@@ -434,10 +436,12 @@ def test_ptrack_unprivileged(self):
434436
"GRANT USAGE ON SCHEMA pg_catalog TO backup; "
435437
"GRANT SELECT ON TABLE pg_catalog.pg_proc TO backup; "
436438
"GRANT SELECT ON TABLE pg_catalog.pg_database TO backup; " # for partial restore, checkdb and ptrack
439+
"GRANT EXECUTE ON FUNCTION pg_catalog.oideq(oid, oid) TO backup; "
437440
"GRANT EXECUTE ON FUNCTION pg_catalog.nameeq(name, name) TO backup; "
438441
"GRANT EXECUTE ON FUNCTION pg_catalog.textout(text) TO backup; "
439442
"GRANT EXECUTE ON FUNCTION pg_catalog.timestamptz(timestamp with time zone, integer) TO backup; "
440443
"GRANT EXECUTE ON FUNCTION pg_catalog.current_setting(text) TO backup; "
444+
"GRANT EXECUTE ON FUNCTION pg_catalog.set_config(text, text, boolean) TO backup; "
441445
"GRANT EXECUTE ON FUNCTION pg_catalog.pg_is_in_recovery() TO backup; "
442446
"GRANT EXECUTE ON FUNCTION pg_catalog.pg_control_system() TO backup; "
443447
"GRANT EXECUTE ON FUNCTION pg_catalog.pg_start_backup(text, boolean, boolean) TO backup; "
@@ -470,8 +474,10 @@ def test_ptrack_unprivileged(self):
470474
"GRANT USAGE ON SCHEMA pg_catalog TO backup; "
471475
"GRANT SELECT ON TABLE pg_catalog.pg_proc TO backup; "
472476
"GRANT SELECT ON TABLE pg_catalog.pg_database TO backup; " # for partial restore, checkdb and ptrack
477+
"GRANT EXECUTE ON FUNCTION pg_catalog.oideq(oid, oid) TO backup; "
473478
"GRANT EXECUTE ON FUNCTION pg_catalog.nameeq(name, name) TO backup; "
474479
"GRANT EXECUTE ON FUNCTION pg_catalog.current_setting(text) TO backup; "
480+
"GRANT EXECUTE ON FUNCTION pg_catalog.set_config(text, text, boolean) TO backup; "
475481
"GRANT EXECUTE ON FUNCTION pg_catalog.pg_is_in_recovery() TO backup; "
476482
"GRANT EXECUTE ON FUNCTION pg_catalog.pg_control_system() TO backup; "
477483
"GRANT EXECUTE ON FUNCTION pg_catalog.pg_start_backup(text, boolean, boolean) TO backup; "

0 commit comments

Comments
 (0)