mirror of
https://github.com/postgres/postgres.git
synced 2025-07-20 05:03:10 +03:00
Update sepgsql to add mandatory access control for TRUNCATE
Use SELinux "db_table: { truncate }" to check if permission is granted to TRUNCATE. Update example SELinux policy to grant needed permission for TRUNCATE. Add new regression test to demonstrate a positive and negative cases. Test will only be run if the loaded SELinux policy has the "db_table: { truncate }" permission. Makes use of recent commit which added object TRUNCATE hook. Patch by Yuli Khodorkovskiy with minor editorialization by me. Not back-patched because the object TRUNCATE hook was not. Author: Yuli Khodorkovskiy Reviewed-by: Joe Conway Discussion: https://postgr.es/m/CAFL5wJcomybj1Xdw7qWmPJRpGuFukKgNrDb6uVBaCMgYS9dkaA%40mail.gmail.com
This commit is contained in:
46
contrib/sepgsql/expected/truncate.out
Normal file
46
contrib/sepgsql/expected/truncate.out
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
--
|
||||||
|
-- Regression Test for TRUNCATE
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- Setup
|
||||||
|
--
|
||||||
|
CREATE TABLE julio_claudians (name text, birth_date date);
|
||||||
|
SECURITY LABEL ON TABLE julio_claudians IS 'system_u:object_r:sepgsql_regtest_foo_table_t:s0';
|
||||||
|
INSERT INTO julio_claudians VALUES ('Augustus', 'September 23, 63 BC'), ('Tiberius', 'November 16, 42 BC'), ('Caligula', 'August 31, 0012'), ('Claudius', 'August 1, 0010'), ('Nero', 'December 15, 0037');
|
||||||
|
CREATE TABLE flavians (name text, birth_date date);
|
||||||
|
SECURITY LABEL ON TABLE flavians IS 'system_u:object_r:sepgsql_table_t:s0';
|
||||||
|
INSERT INTO flavians VALUES ('Vespasian', 'November 17, 0009'), ('Titus', 'December 30, 0039'), ('Domitian', 'October 24, 0051');
|
||||||
|
SELECT * from julio_claudians;
|
||||||
|
name | birth_date
|
||||||
|
----------+---------------
|
||||||
|
Augustus | 09-23-0063 BC
|
||||||
|
Tiberius | 11-16-0042 BC
|
||||||
|
Caligula | 08-31-0012
|
||||||
|
Claudius | 08-01-0010
|
||||||
|
Nero | 12-15-0037
|
||||||
|
(5 rows)
|
||||||
|
|
||||||
|
SELECT * from flavians;
|
||||||
|
name | birth_date
|
||||||
|
-----------+------------
|
||||||
|
Vespasian | 11-17-0009
|
||||||
|
Titus | 12-30-0039
|
||||||
|
Domitian | 10-24-0051
|
||||||
|
(3 rows)
|
||||||
|
|
||||||
|
TRUNCATE TABLE julio_claudians; -- ok
|
||||||
|
TRUNCATE TABLE flavians; -- failed
|
||||||
|
ERROR: SELinux: security policy violation
|
||||||
|
SELECT * from julio_claudians;
|
||||||
|
name | birth_date
|
||||||
|
------+------------
|
||||||
|
(0 rows)
|
||||||
|
|
||||||
|
SELECT * from flavians;
|
||||||
|
name | birth_date
|
||||||
|
-----------+------------
|
||||||
|
Vespasian | 11-17-0009
|
||||||
|
Titus | 12-30-0039
|
||||||
|
Domitian | 10-24-0051
|
||||||
|
(3 rows)
|
||||||
|
|
@ -188,6 +188,20 @@ sepgsql_object_access(ObjectAccessType access,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case OAT_TRUNCATE:
|
||||||
|
{
|
||||||
|
switch (classId)
|
||||||
|
{
|
||||||
|
case RelationRelationId:
|
||||||
|
sepgsql_relation_truncate(objectId);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* Ignore unsupported object classes */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case OAT_POST_ALTER:
|
case OAT_POST_ALTER:
|
||||||
{
|
{
|
||||||
ObjectAccessPostAlter *pa_arg = arg;
|
ObjectAccessPostAlter *pa_arg = arg;
|
||||||
|
@ -516,6 +516,46 @@ sepgsql_relation_drop(Oid relOid)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* sepgsql_relation_truncate
|
||||||
|
*
|
||||||
|
* Check privileges to TRUNCATE the supplied relation.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
sepgsql_relation_truncate(Oid relOid)
|
||||||
|
{
|
||||||
|
ObjectAddress object;
|
||||||
|
char *audit_name;
|
||||||
|
uint16_t tclass = 0;
|
||||||
|
char relkind = get_rel_relkind(relOid);
|
||||||
|
|
||||||
|
switch (relkind)
|
||||||
|
{
|
||||||
|
case RELKIND_RELATION:
|
||||||
|
case RELKIND_PARTITIONED_TABLE:
|
||||||
|
tclass = SEPG_CLASS_DB_TABLE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* ignore other relkinds */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* check db_table:{truncate} permission
|
||||||
|
*/
|
||||||
|
object.classId = RelationRelationId;
|
||||||
|
object.objectId = relOid;
|
||||||
|
object.objectSubId = 0;
|
||||||
|
audit_name = getObjectIdentity(&object);
|
||||||
|
|
||||||
|
sepgsql_avc_check_perms(&object,
|
||||||
|
tclass,
|
||||||
|
SEPG_DB_TABLE__TRUNCATE,
|
||||||
|
audit_name,
|
||||||
|
true);
|
||||||
|
pfree(audit_name);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* sepgsql_relation_relabel
|
* sepgsql_relation_relabel
|
||||||
*
|
*
|
||||||
|
@ -359,6 +359,9 @@ static struct
|
|||||||
{
|
{
|
||||||
"lock", SEPG_DB_TABLE__LOCK
|
"lock", SEPG_DB_TABLE__LOCK
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"truncate", SEPG_DB_TABLE__TRUNCATE
|
||||||
|
},
|
||||||
{
|
{
|
||||||
NULL, 0UL
|
NULL, 0UL
|
||||||
},
|
},
|
||||||
|
@ -150,6 +150,14 @@ allow sepgsql_regtest_var_t sepgsql_regtest_var_table_t:db_table { getattr selec
|
|||||||
allow sepgsql_regtest_var_t sepgsql_regtest_var_table_t:db_column { getattr select update insert };
|
allow sepgsql_regtest_var_t sepgsql_regtest_var_table_t:db_column { getattr select update insert };
|
||||||
allow sepgsql_regtest_var_t sepgsql_regtest_var_table_t:db_tuple { select update insert delete };
|
allow sepgsql_regtest_var_t sepgsql_regtest_var_table_t:db_tuple { select update insert delete };
|
||||||
|
|
||||||
|
optional_policy(`
|
||||||
|
gen_require(`
|
||||||
|
class db_table { truncate };
|
||||||
|
')
|
||||||
|
|
||||||
|
allow sepgsql_regtest_superuser_t sepgsql_regtest_foo_table_t:db_table { truncate };
|
||||||
|
')
|
||||||
|
|
||||||
optional_policy(`
|
optional_policy(`
|
||||||
gen_require(`
|
gen_require(`
|
||||||
role unconfined_r;
|
role unconfined_r;
|
||||||
|
@ -145,6 +145,7 @@
|
|||||||
#define SEPG_DB_TABLE__INSERT (1<<8)
|
#define SEPG_DB_TABLE__INSERT (1<<8)
|
||||||
#define SEPG_DB_TABLE__DELETE (1<<9)
|
#define SEPG_DB_TABLE__DELETE (1<<9)
|
||||||
#define SEPG_DB_TABLE__LOCK (1<<10)
|
#define SEPG_DB_TABLE__LOCK (1<<10)
|
||||||
|
#define SEPG_DB_TABLE__TRUNCATE (1<<11)
|
||||||
|
|
||||||
#define SEPG_DB_SEQUENCE__CREATE (SEPG_DB_DATABASE__CREATE)
|
#define SEPG_DB_SEQUENCE__CREATE (SEPG_DB_DATABASE__CREATE)
|
||||||
#define SEPG_DB_SEQUENCE__DROP (SEPG_DB_DATABASE__DROP)
|
#define SEPG_DB_SEQUENCE__DROP (SEPG_DB_DATABASE__DROP)
|
||||||
@ -312,6 +313,7 @@ extern void sepgsql_attribute_relabel(Oid relOid, AttrNumber attnum,
|
|||||||
extern void sepgsql_attribute_setattr(Oid relOid, AttrNumber attnum);
|
extern void sepgsql_attribute_setattr(Oid relOid, AttrNumber attnum);
|
||||||
extern void sepgsql_relation_post_create(Oid relOid);
|
extern void sepgsql_relation_post_create(Oid relOid);
|
||||||
extern void sepgsql_relation_drop(Oid relOid);
|
extern void sepgsql_relation_drop(Oid relOid);
|
||||||
|
extern void sepgsql_relation_truncate(Oid relOid);
|
||||||
extern void sepgsql_relation_relabel(Oid relOid, const char *seclabel);
|
extern void sepgsql_relation_relabel(Oid relOid, const char *seclabel);
|
||||||
extern void sepgsql_relation_setattr(Oid relOid);
|
extern void sepgsql_relation_setattr(Oid relOid);
|
||||||
|
|
||||||
|
24
contrib/sepgsql/sql/truncate.sql
Normal file
24
contrib/sepgsql/sql/truncate.sql
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
--
|
||||||
|
-- Regression Test for TRUNCATE
|
||||||
|
--
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Setup
|
||||||
|
--
|
||||||
|
CREATE TABLE julio_claudians (name text, birth_date date);
|
||||||
|
SECURITY LABEL ON TABLE julio_claudians IS 'system_u:object_r:sepgsql_regtest_foo_table_t:s0';
|
||||||
|
INSERT INTO julio_claudians VALUES ('Augustus', 'September 23, 63 BC'), ('Tiberius', 'November 16, 42 BC'), ('Caligula', 'August 31, 0012'), ('Claudius', 'August 1, 0010'), ('Nero', 'December 15, 0037');
|
||||||
|
|
||||||
|
CREATE TABLE flavians (name text, birth_date date);
|
||||||
|
SECURITY LABEL ON TABLE flavians IS 'system_u:object_r:sepgsql_table_t:s0';
|
||||||
|
|
||||||
|
INSERT INTO flavians VALUES ('Vespasian', 'November 17, 0009'), ('Titus', 'December 30, 0039'), ('Domitian', 'October 24, 0051');
|
||||||
|
|
||||||
|
SELECT * from julio_claudians;
|
||||||
|
SELECT * from flavians;
|
||||||
|
|
||||||
|
TRUNCATE TABLE julio_claudians; -- ok
|
||||||
|
TRUNCATE TABLE flavians; -- failed
|
||||||
|
|
||||||
|
SELECT * from julio_claudians;
|
||||||
|
SELECT * from flavians;
|
@ -287,6 +287,20 @@ echo "found ${NUM}"
|
|||||||
echo
|
echo
|
||||||
echo "============== running sepgsql regression tests =============="
|
echo "============== running sepgsql regression tests =============="
|
||||||
|
|
||||||
make REGRESS="label dml ddl alter misc" REGRESS_OPTS="--launcher ./launcher" installcheck
|
tests="label dml ddl alter misc"
|
||||||
|
|
||||||
|
# Check if the truncate permission exists in the loaded policy, and if so,
|
||||||
|
# run the truncate test
|
||||||
|
#
|
||||||
|
# Testing the TRUNCATE regression test can be done by manually adding
|
||||||
|
# the permission with CIL if necessary:
|
||||||
|
# sudo semodule -cE base
|
||||||
|
# sudo sed -i -E 's/(class db_table.*?) \)/\1 truncate\)/' base.cil
|
||||||
|
# sudo semodule -i base.cil
|
||||||
|
|
||||||
|
if [ -f /sys/fs/selinux/class/db_table/perms/truncate ]; then
|
||||||
|
tests+=" truncate"
|
||||||
|
fi
|
||||||
|
|
||||||
|
make REGRESS="$tests" REGRESS_OPTS="--launcher ./launcher" installcheck
|
||||||
# exit with the exit code provided by "make"
|
# exit with the exit code provided by "make"
|
||||||
|
Reference in New Issue
Block a user