Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit e6f1e56

Browse files
committed
Make inherited TRUNCATE perform access permission checks on parent table only.
Previously, TRUNCATE command through a parent table checked the permissions on not only the parent table but also the children tables inherited from it. This was a bug and inherited queries should perform access permission checks on the parent table only. This commit fixes that bug. Back-patch to all supported branches. Author: Amit Langote Reviewed-by: Fujii Masao Discussion: https://postgr.es/m/CAHGQGwFHdSvifhJE+-GSNqUHSfbiKxaeQQ7HGcYz6SC2n_oDcg@mail.gmail.com
1 parent b0afdca commit e6f1e56

File tree

3 files changed

+60
-7
lines changed

3 files changed

+60
-7
lines changed

src/backend/commands/tablecmds.c

+25-7
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,7 @@ struct DropRelationCallbackState
304304
((child_is_partition) ? DEPENDENCY_AUTO : DEPENDENCY_NORMAL)
305305

306306
static void truncate_check_rel(Oid relid, Form_pg_class reltuple);
307+
static void truncate_check_perms(Oid relid, Form_pg_class reltuple);
307308
static void truncate_check_activity(Relation rel);
308309
static void RangeVarCallbackForTruncate(const RangeVar *relation,
309310
Oid relId, Oid oldRelId, void *arg);
@@ -1615,6 +1616,12 @@ ExecuteTruncate(TruncateStmt *stmt)
16151616
continue;
16161617
}
16171618

1619+
/*
1620+
* Inherited TRUNCATE commands perform access
1621+
* permission checks on the parent table only.
1622+
* So we skip checking the children's permissions
1623+
* and don't call truncate_check_perms() here.
1624+
*/
16181625
truncate_check_rel(RelationGetRelid(rel), rel->rd_rel);
16191626
truncate_check_activity(rel);
16201627

@@ -1701,6 +1708,7 @@ ExecuteTruncateGuts(List *explicit_rels, List *relids, List *relids_logged,
17011708
(errmsg("truncate cascades to table \"%s\"",
17021709
RelationGetRelationName(rel))));
17031710
truncate_check_rel(relid, rel->rd_rel);
1711+
truncate_check_perms(relid, rel->rd_rel);
17041712
truncate_check_activity(rel);
17051713
rels = lappend(rels, rel);
17061714
relids = lappend_oid(relids, relid);
@@ -1951,7 +1959,6 @@ ExecuteTruncateGuts(List *explicit_rels, List *relids, List *relids_logged,
19511959
static void
19521960
truncate_check_rel(Oid relid, Form_pg_class reltuple)
19531961
{
1954-
AclResult aclresult;
19551962
char *relname = NameStr(reltuple->relname);
19561963

19571964
/*
@@ -1965,12 +1972,6 @@ truncate_check_rel(Oid relid, Form_pg_class reltuple)
19651972
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
19661973
errmsg("\"%s\" is not a table", relname)));
19671974

1968-
/* Permissions checks */
1969-
aclresult = pg_class_aclcheck(relid, GetUserId(), ACL_TRUNCATE);
1970-
if (aclresult != ACLCHECK_OK)
1971-
aclcheck_error(aclresult, get_relkind_objtype(reltuple->relkind),
1972-
relname);
1973-
19741975
if (!allowSystemTableMods && IsSystemClass(relid, reltuple))
19751976
ereport(ERROR,
19761977
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
@@ -1980,6 +1981,22 @@ truncate_check_rel(Oid relid, Form_pg_class reltuple)
19801981
InvokeObjectTruncateHook(relid);
19811982
}
19821983

1984+
/*
1985+
* Check that current user has the permission to truncate given relation.
1986+
*/
1987+
static void
1988+
truncate_check_perms(Oid relid, Form_pg_class reltuple)
1989+
{
1990+
char *relname = NameStr(reltuple->relname);
1991+
AclResult aclresult;
1992+
1993+
/* Permissions checks */
1994+
aclresult = pg_class_aclcheck(relid, GetUserId(), ACL_TRUNCATE);
1995+
if (aclresult != ACLCHECK_OK)
1996+
aclcheck_error(aclresult, get_relkind_objtype(reltuple->relkind),
1997+
relname);
1998+
}
1999+
19832000
/*
19842001
* Set of extra sanity checks to check if a given relation is safe to
19852002
* truncate. This is split with truncate_check_rel() as
@@ -15292,6 +15309,7 @@ RangeVarCallbackForTruncate(const RangeVar *relation,
1529215309
elog(ERROR, "cache lookup failed for relation %u", relId);
1529315310

1529415311
truncate_check_rel(relId, (Form_pg_class) GETSTRUCT(tuple));
15312+
truncate_check_perms(relId, (Form_pg_class) GETSTRUCT(tuple));
1529515313

1529615314
ReleaseSysCache(tuple);
1529715315
}

src/test/regress/expected/privileges.out

+21
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,27 @@ SELECT tableoid FROM atestp2; -- ok
695695
----------
696696
(0 rows)
697697

698+
-- child's permissions do not apply when operating on parent
699+
SET SESSION AUTHORIZATION regress_priv_user1;
700+
REVOKE ALL ON atestc FROM regress_priv_user2;
701+
GRANT ALL ON atestp1 TO regress_priv_user2;
702+
SET SESSION AUTHORIZATION regress_priv_user2;
703+
SELECT f2 FROM atestp1; -- ok
704+
f2
705+
----
706+
(0 rows)
707+
708+
SELECT f2 FROM atestc; -- fail
709+
ERROR: permission denied for table atestc
710+
DELETE FROM atestp1; -- ok
711+
DELETE FROM atestc; -- fail
712+
ERROR: permission denied for table atestc
713+
UPDATE atestp1 SET f1 = 1; -- ok
714+
UPDATE atestc SET f1 = 1; -- fail
715+
ERROR: permission denied for table atestc
716+
TRUNCATE atestp1; -- ok
717+
TRUNCATE atestc; -- fail
718+
ERROR: permission denied for table atestc
698719
-- privileges on functions, languages
699720
-- switch to superuser
700721
\c -

src/test/regress/sql/privileges.sql

+14
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,20 @@ SELECT fy FROM atestp2; -- ok
446446
SELECT atestp2 FROM atestp2; -- ok
447447
SELECT tableoid FROM atestp2; -- ok
448448

449+
-- child's permissions do not apply when operating on parent
450+
SET SESSION AUTHORIZATION regress_priv_user1;
451+
REVOKE ALL ON atestc FROM regress_priv_user2;
452+
GRANT ALL ON atestp1 TO regress_priv_user2;
453+
SET SESSION AUTHORIZATION regress_priv_user2;
454+
SELECT f2 FROM atestp1; -- ok
455+
SELECT f2 FROM atestc; -- fail
456+
DELETE FROM atestp1; -- ok
457+
DELETE FROM atestc; -- fail
458+
UPDATE atestp1 SET f1 = 1; -- ok
459+
UPDATE atestc SET f1 = 1; -- fail
460+
TRUNCATE atestp1; -- ok
461+
TRUNCATE atestc; -- fail
462+
449463
-- privileges on functions, languages
450464

451465
-- switch to superuser

0 commit comments

Comments
 (0)