From 0f05840bf4c256b838eca8f1be9d7b5be82ccd0e Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Thu, 28 Mar 2013 15:38:35 -0400 Subject: [PATCH] Allow sepgsql labels to depend on object name. The main change here is to call security_compute_create_name_raw() rather than security_compute_create_raw(). This ups the minimum requirement for libselinux from 2.0.99 to 2.1.10, but it looks like most distributions will have picked that up before 9.3 is out. KaiGai Kohei --- configure | 24 ++++++++++---------- configure.in | 4 ++-- contrib/sepgsql/database.c | 3 ++- contrib/sepgsql/expected/label.out | 35 +++++++++++++++++++++++++++--- contrib/sepgsql/proc.c | 3 ++- contrib/sepgsql/relation.c | 9 +++++--- contrib/sepgsql/schema.c | 13 +++++++---- contrib/sepgsql/selinux.c | 11 ++++++---- contrib/sepgsql/sepgsql-regtest.te | 17 ++++++++++++++- contrib/sepgsql/sepgsql.h | 3 ++- contrib/sepgsql/sql/label.sql | 11 +++++++--- contrib/sepgsql/uavc.c | 4 ++-- doc/src/sgml/sepgsql.sgml | 7 +++--- 13 files changed, 104 insertions(+), 40 deletions(-) diff --git a/configure b/configure index 9efd866059..b391308d81 100755 --- a/configure +++ b/configure @@ -9710,9 +9710,9 @@ fi # for contrib/sepgsql if test "$with_selinux" = yes; then -{ $as_echo "$as_me:$LINENO: checking for selinux_status_open in -lselinux" >&5 -$as_echo_n "checking for selinux_status_open in -lselinux... " >&6; } -if test "${ac_cv_lib_selinux_selinux_status_open+set}" = set; then +{ $as_echo "$as_me:$LINENO: checking for security_compute_create_name in -lselinux" >&5 +$as_echo_n "checking for security_compute_create_name in -lselinux... " >&6; } +if test "${ac_cv_lib_selinux_security_compute_create_name+set}" = set; then $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -9730,11 +9730,11 @@ cat >>conftest.$ac_ext <<_ACEOF #ifdef __cplusplus extern "C" #endif -char selinux_status_open (); +char security_compute_create_name (); int main () { -return selinux_status_open (); +return security_compute_create_name (); ; return 0; } @@ -9760,12 +9760,12 @@ $as_echo "$ac_try_echo") >&5 test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then - ac_cv_lib_selinux_selinux_status_open=yes + ac_cv_lib_selinux_security_compute_create_name=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 - ac_cv_lib_selinux_selinux_status_open=no + ac_cv_lib_selinux_security_compute_create_name=no fi rm -rf conftest.dSYM @@ -9773,9 +9773,9 @@ rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_selinux_selinux_status_open" >&5 -$as_echo "$ac_cv_lib_selinux_selinux_status_open" >&6; } -if test "x$ac_cv_lib_selinux_selinux_status_open" = x""yes; then +{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_selinux_security_compute_create_name" >&5 +$as_echo "$ac_cv_lib_selinux_security_compute_create_name" >&6; } +if test "x$ac_cv_lib_selinux_security_compute_create_name" = x""yes; then cat >>confdefs.h <<_ACEOF #define HAVE_LIBSELINUX 1 _ACEOF @@ -9783,8 +9783,8 @@ _ACEOF LIBS="-lselinux $LIBS" else - { { $as_echo "$as_me:$LINENO: error: library 'libselinux', version 2.0.99 or newer, is required for SELinux support" >&5 -$as_echo "$as_me: error: library 'libselinux', version 2.0.99 or newer, is required for SELinux support" >&2;} + { { $as_echo "$as_me:$LINENO: error: library 'libselinux', version 2.1.10 or newer, is required for SELinux support" >&5 +$as_echo "$as_me: error: library 'libselinux', version 2.1.10 or newer, is required for SELinux support" >&2;} { (exit 1); exit 1; }; } fi diff --git a/configure.in b/configure.in index f31f7efda0..f81fda7564 100644 --- a/configure.in +++ b/configure.in @@ -952,8 +952,8 @@ fi # for contrib/sepgsql if test "$with_selinux" = yes; then - AC_CHECK_LIB(selinux, selinux_status_open, [], - [AC_MSG_ERROR([library 'libselinux', version 2.0.99 or newer, is required for SELinux support])]) + AC_CHECK_LIB(selinux, security_compute_create_name, [], + [AC_MSG_ERROR([library 'libselinux', version 2.1.10 or newer, is required for SELinux support])]) fi # for contrib/uuid-ossp diff --git a/contrib/sepgsql/database.c b/contrib/sepgsql/database.c index 64d37a3ca9..91e6c4f441 100644 --- a/contrib/sepgsql/database.c +++ b/contrib/sepgsql/database.c @@ -92,7 +92,8 @@ sepgsql_database_post_create(Oid databaseId, const char *dtemplate) ncontext = sepgsql_compute_create(sepgsql_get_client_label(), tcontext, - SEPG_CLASS_DB_DATABASE); + SEPG_CLASS_DB_DATABASE, + NameStr(datForm->datname)); /* * check db_database:{create} permission diff --git a/contrib/sepgsql/expected/label.out b/contrib/sepgsql/expected/label.out index d4a6f8ae96..0a15f279f8 100644 --- a/contrib/sepgsql/expected/label.out +++ b/contrib/sepgsql/expected/label.out @@ -64,10 +64,16 @@ SELECT sepgsql_getcon(); -- confirm client privilege CREATE TABLE t3 (s int, t text); INSERT INTO t3 VALUES (1, 'sss'), (2, 'ttt'), (3, 'uuu'); +SELECT sepgsql_getcon(); -- confirm client privilege + sepgsql_getcon +---------------------------------------------------- + unconfined_u:unconfined_r:sepgsql_regtest_dba_t:s0 +(1 row) + +CREATE TABLE t4 (m int, n text); +INSERT INTO t4 VALUES (1,'mmm'), (2,'nnn'), (3,'ooo'); SELECT objtype, objname, label FROM pg_seclabels - WHERE provider = 'selinux' - AND objtype in ('table', 'column') - AND objname in ('t1', 't2', 't3'); + WHERE provider = 'selinux' AND objtype = 'table' AND objname in ('t1', 't2', 't3'); objtype | objname | label ---------+---------+----------------------------------------------- table | t1 | unconfined_u:object_r:sepgsql_table_t:s0 @@ -75,6 +81,28 @@ SELECT objtype, objname, label FROM pg_seclabels table | t3 | unconfined_u:object_r:user_sepgsql_table_t:s0 (3 rows) +SELECT objtype, objname, label FROM pg_seclabels + WHERE provider = 'selinux' AND objtype = 'column' AND (objname like 't3.%' OR objname like 't4.%'); + objtype | objname | label +---------+-------------+----------------------------------------------- + column | t3.t | unconfined_u:object_r:user_sepgsql_table_t:s0 + column | t3.s | unconfined_u:object_r:user_sepgsql_table_t:s0 + column | t3.ctid | unconfined_u:object_r:user_sepgsql_table_t:s0 + column | t3.xmin | unconfined_u:object_r:user_sepgsql_table_t:s0 + column | t3.cmin | unconfined_u:object_r:user_sepgsql_table_t:s0 + column | t3.xmax | unconfined_u:object_r:user_sepgsql_table_t:s0 + column | t3.cmax | unconfined_u:object_r:user_sepgsql_table_t:s0 + column | t3.tableoid | unconfined_u:object_r:user_sepgsql_table_t:s0 + column | t4.n | unconfined_u:object_r:sepgsql_table_t:s0 + column | t4.m | unconfined_u:object_r:sepgsql_table_t:s0 + column | t4.ctid | unconfined_u:object_r:sepgsql_sysobj_t:s0 + column | t4.xmin | unconfined_u:object_r:sepgsql_sysobj_t:s0 + column | t4.cmin | unconfined_u:object_r:sepgsql_sysobj_t:s0 + column | t4.xmax | unconfined_u:object_r:sepgsql_sysobj_t:s0 + column | t4.cmax | unconfined_u:object_r:sepgsql_sysobj_t:s0 + column | t4.tableoid | unconfined_u:object_r:sepgsql_sysobj_t:s0 +(16 rows) + -- -- Tests for SECURITY LABEL -- @@ -456,6 +484,7 @@ SELECT sepgsql_getcon(); -- confirm client privilege DROP TABLE IF EXISTS t1 CASCADE; DROP TABLE IF EXISTS t2 CASCADE; DROP TABLE IF EXISTS t3 CASCADE; +DROP TABLE IF EXISTS t4 CASCADE; DROP FUNCTION IF EXISTS f1() CASCADE; DROP FUNCTION IF EXISTS f2() CASCADE; DROP FUNCTION IF EXISTS f3() CASCADE; diff --git a/contrib/sepgsql/proc.c b/contrib/sepgsql/proc.c index 53b941d855..afc37553f2 100644 --- a/contrib/sepgsql/proc.c +++ b/contrib/sepgsql/proc.c @@ -95,7 +95,8 @@ sepgsql_proc_post_create(Oid functionId) tcontext = sepgsql_get_label(NamespaceRelationId, proForm->pronamespace, 0); ncontext = sepgsql_compute_create(scontext, tcontext, - SEPG_CLASS_DB_PROCEDURE); + SEPG_CLASS_DB_PROCEDURE, + NameStr(proForm->proname)); /* * check db_procedure:{create (install)} permission diff --git a/contrib/sepgsql/relation.c b/contrib/sepgsql/relation.c index 8bcaa41d31..dd4593dd3a 100644 --- a/contrib/sepgsql/relation.c +++ b/contrib/sepgsql/relation.c @@ -88,7 +88,8 @@ sepgsql_attribute_post_create(Oid relOid, AttrNumber attnum) scontext = sepgsql_get_client_label(); tcontext = sepgsql_get_label(RelationRelationId, relOid, 0); ncontext = sepgsql_compute_create(scontext, tcontext, - SEPG_CLASS_DB_COLUMN); + SEPG_CLASS_DB_COLUMN, + NameStr(attForm->attname)); /* * check db_column:{create} permission @@ -309,7 +310,8 @@ sepgsql_relation_post_create(Oid relOid) scontext = sepgsql_get_client_label(); tcontext = sepgsql_get_label(NamespaceRelationId, classForm->relnamespace, 0); - rcontext = sepgsql_compute_create(scontext, tcontext, tclass); + rcontext = sepgsql_compute_create(scontext, tcontext, tclass, + NameStr(classForm->relname)); /* * check db_xxx:{create} permission @@ -363,7 +365,8 @@ sepgsql_relation_post_create(Oid relOid) ccontext = sepgsql_compute_create(scontext, rcontext, - SEPG_CLASS_DB_COLUMN); + SEPG_CLASS_DB_COLUMN, + NameStr(attForm->attname)); /* * check db_column:{create} permission diff --git a/contrib/sepgsql/schema.c b/contrib/sepgsql/schema.c index ecdfd738d9..74e16678cb 100644 --- a/contrib/sepgsql/schema.c +++ b/contrib/sepgsql/schema.c @@ -42,6 +42,7 @@ sepgsql_schema_post_create(Oid namespaceId) char *tcontext; char *ncontext; char audit_name[NAMEDATALEN + 20]; + const char *nsp_name; ObjectAddress object; Form_pg_namespace nspForm; @@ -67,17 +68,21 @@ sepgsql_schema_post_create(Oid namespaceId) elog(ERROR, "catalog lookup failed for namespace %u", namespaceId); nspForm = (Form_pg_namespace) GETSTRUCT(tuple); + nsp_name = NameStr(nspForm->nspname); + if (strncmp(nsp_name, "pg_temp_", 8) == 0) + nsp_name = "pg_temp"; + else if (strncmp(nsp_name, "pg_toast_temp_", 14) == 0) + nsp_name = "pg_toast_temp"; tcontext = sepgsql_get_label(DatabaseRelationId, MyDatabaseId, 0); ncontext = sepgsql_compute_create(sepgsql_get_client_label(), tcontext, - SEPG_CLASS_DB_SCHEMA); - + SEPG_CLASS_DB_SCHEMA, + nsp_name); /* * check db_schema:{create} */ - snprintf(audit_name, sizeof(audit_name), - "schema %s", NameStr(nspForm->nspname)); + snprintf(audit_name, sizeof(audit_name), "schema %s", nsp_name); sepgsql_avc_check_perms_label(ncontext, SEPG_CLASS_DB_SCHEMA, SEPG_DB_SCHEMA__CREATE, diff --git a/contrib/sepgsql/selinux.c b/contrib/sepgsql/selinux.c index f70254f2a7..863f0c143f 100644 --- a/contrib/sepgsql/selinux.c +++ b/contrib/sepgsql/selinux.c @@ -836,7 +836,8 @@ sepgsql_compute_avd(const char *scontext, char * sepgsql_compute_create(const char *scontext, const char *tcontext, - uint16 tclass) + uint16 tclass, + const char *objname) { security_context_t ncontext; security_class_t tclass_ex; @@ -853,9 +854,11 @@ sepgsql_compute_create(const char *scontext, * Ask SELinux what is the default context for the given object class on a * pair of security contexts */ - if (security_compute_create_raw((security_context_t) scontext, - (security_context_t) tcontext, - tclass_ex, &ncontext) < 0) + if (security_compute_create_name_raw((security_context_t) scontext, + (security_context_t) tcontext, + tclass_ex, + objname, + &ncontext) < 0) ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("SELinux could not compute a new context: " diff --git a/contrib/sepgsql/sepgsql-regtest.te b/contrib/sepgsql/sepgsql-regtest.te index d872945074..790c4e85bb 100644 --- a/contrib/sepgsql/sepgsql-regtest.te +++ b/contrib/sepgsql/sepgsql-regtest.te @@ -1,4 +1,4 @@ -policy_module(sepgsql-regtest, 1.04) +policy_module(sepgsql-regtest, 1.05) gen_require(` all_userspace_class_perms @@ -43,6 +43,21 @@ allow sepgsql_regtest_dba_t sepgsql_regtest_user_t : process { dyntransition }; allow sepgsql_regtest_dba_t sepgsql_regtest_foo_t : process { dyntransition }; allow sepgsql_regtest_dba_t sepgsql_regtest_var_t : process { dyntransition }; +# special rule for system columns +optional_policy(` + gen_require(` + attribute sepgsql_table_type; + type sepgsql_sysobj_t; + ') + type_transition sepgsql_regtest_dba_t sepgsql_table_type:db_column sepgsql_sysobj_t "ctid"; + type_transition sepgsql_regtest_dba_t sepgsql_table_type:db_column sepgsql_sysobj_t "oid"; + type_transition sepgsql_regtest_dba_t sepgsql_table_type:db_column sepgsql_sysobj_t "xmin"; + type_transition sepgsql_regtest_dba_t sepgsql_table_type:db_column sepgsql_sysobj_t "xmax"; + type_transition sepgsql_regtest_dba_t sepgsql_table_type:db_column sepgsql_sysobj_t "cmin"; + type_transition sepgsql_regtest_dba_t sepgsql_table_type:db_column sepgsql_sysobj_t "cmax"; + type_transition sepgsql_regtest_dba_t sepgsql_table_type:db_column sepgsql_sysobj_t "tableoid"; +') + # # Dummy domain for unpriv users # diff --git a/contrib/sepgsql/sepgsql.h b/contrib/sepgsql/sepgsql.h index d4ee94be5a..f7448cdeb6 100644 --- a/contrib/sepgsql/sepgsql.h +++ b/contrib/sepgsql/sepgsql.h @@ -239,7 +239,8 @@ extern void sepgsql_compute_avd(const char *scontext, extern char *sepgsql_compute_create(const char *scontext, const char *tcontext, - uint16 tclass); + uint16 tclass, + const char *objname); extern bool sepgsql_check_perms(const char *scontext, const char *tcontext, diff --git a/contrib/sepgsql/sql/label.sql b/contrib/sepgsql/sql/label.sql index e63b5f691d..6201cd7721 100644 --- a/contrib/sepgsql/sql/label.sql +++ b/contrib/sepgsql/sql/label.sql @@ -71,10 +71,14 @@ SECURITY LABEL ON TABLE var_tbl CREATE TABLE t3 (s int, t text); INSERT INTO t3 VALUES (1, 'sss'), (2, 'ttt'), (3, 'uuu'); +-- @SECURITY-CONTEXT=unconfined_u:unconfined_r:sepgsql_regtest_dba_t:s0 +CREATE TABLE t4 (m int, n text); +INSERT INTO t4 VALUES (1,'mmm'), (2,'nnn'), (3,'ooo'); + SELECT objtype, objname, label FROM pg_seclabels - WHERE provider = 'selinux' - AND objtype in ('table', 'column') - AND objname in ('t1', 't2', 't3'); + WHERE provider = 'selinux' AND objtype = 'table' AND objname in ('t1', 't2', 't3'); +SELECT objtype, objname, label FROM pg_seclabels + WHERE provider = 'selinux' AND objtype = 'column' AND (objname like 't3.%' OR objname like 't4.%'); -- -- Tests for SECURITY LABEL @@ -229,6 +233,7 @@ SELECT sepgsql_getcon(); DROP TABLE IF EXISTS t1 CASCADE; DROP TABLE IF EXISTS t2 CASCADE; DROP TABLE IF EXISTS t3 CASCADE; +DROP TABLE IF EXISTS t4 CASCADE; DROP FUNCTION IF EXISTS f1() CASCADE; DROP FUNCTION IF EXISTS f2() CASCADE; DROP FUNCTION IF EXISTS f3() CASCADE; diff --git a/contrib/sepgsql/uavc.c b/contrib/sepgsql/uavc.c index 84839c4867..4e67aa02d1 100644 --- a/contrib/sepgsql/uavc.c +++ b/contrib/sepgsql/uavc.c @@ -250,10 +250,10 @@ sepgsql_avc_compute(const char *scontext, const char *tcontext, uint16 tclass) { if (!ucontext) ncontext = sepgsql_compute_create(scontext, tcontext, - SEPG_CLASS_PROCESS); + SEPG_CLASS_PROCESS, NULL); else ncontext = sepgsql_compute_create(scontext, ucontext, - SEPG_CLASS_PROCESS); + SEPG_CLASS_PROCESS, NULL); if (strcmp(scontext, ncontext) == 0) { pfree(ncontext); diff --git a/doc/src/sgml/sepgsql.sgml b/doc/src/sgml/sepgsql.sgml index 5ee08e1dee..7c7f953f91 100644 --- a/doc/src/sgml/sepgsql.sgml +++ b/doc/src/sgml/sepgsql.sgml @@ -63,7 +63,7 @@ sepgsql can only be used on Linux 2.6.28 or higher with SELinux enabled. It is not available on any other platform. You will also need - libselinux 2.0.99 or higher and + libselinux 2.1.10 or higher and selinux-policy 3.9.13 or higher (although some distributions may backport the necessary rules into older policy versions). @@ -326,8 +326,9 @@ $ sudo semodule -r sepgsql-regtest When sepgsql is in use, security labels are automatically assigned to supported database objects at creation time. This label is called a default security label, and is decided according - to the system security policy, which takes as input the creator's label - and the label assigned to the new object's parent object. + to the system security policy, which takes as input the creator's label, + the label assigned to the new object's parent object and optionally name + of the constructed object.