contrib/sepgsql/expected/label.out | 2 +- contrib/sepgsql/expected/misc.out | 151 ++++++++++++++++++++ contrib/sepgsql/hooks.c | 193 +------------------------ contrib/sepgsql/label.c | 277 ++++++++++++++++++++++++++++++++++-- contrib/sepgsql/selinux.c | 6 + contrib/sepgsql/sepgsql-regtest.te | 36 ++++- contrib/sepgsql/sepgsql.h | 4 +- contrib/sepgsql/sql/label.sql | 2 +- contrib/sepgsql/sql/misc.sql | 67 +++++++++ 9 files changed, 531 insertions(+), 207 deletions(-) diff --git a/contrib/sepgsql/expected/label.out b/contrib/sepgsql/expected/label.out index bac169f..073ad4f 100644 --- a/contrib/sepgsql/expected/label.out +++ b/contrib/sepgsql/expected/label.out @@ -26,7 +26,7 @@ CREATE FUNCTION f4 () RETURNS text AS 'SELECT sepgsql_getcon()' LANGUAGE sql; SECURITY LABEL ON FUNCTION f4() - IS 'system_u:object_r:sepgsql_regtest_trusted_proc_exec_t:s0'; + IS 'system_u:object_r:sepgsql_nosuch_trusted_proc_exec_t:s0'; -- -- Tests for default labeling behavior -- diff --git a/contrib/sepgsql/expected/misc.out b/contrib/sepgsql/expected/misc.out index 329852c..3f1213f 100644 --- a/contrib/sepgsql/expected/misc.out +++ b/contrib/sepgsql/expected/misc.out @@ -3,3 +3,154 @@ -- LOAD '$libdir/sepgsql'; -- failed ERROR: SELinux: LOAD is not permitted +-- +-- Permission checks related to SET sepgsql.client_label +-- +-- try to degrade client label +CREATE OR REPLACE FUNCTION regtest_setcon_1() + RETURNS bool LANGUAGE SQL + AS 'SET sepgsql.client_label = ''unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0:c1,c3,c5''; + VALUES(true)'; +-- try to upgrade client label +CREATE OR REPLACE FUNCTION regtest_setcon_2() + RETURNS bool LANGUAGE SQL + AS 'SET sepgsql.client_label = ''unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0:c0.c255''; + VALUES(true)'; +-- try to reset client label +CREATE OR REPLACE FUNCTION regtest_resetcon() + RETURNS bool LANGUAGE SQL + AS 'RESET sepgsql.client_label; VALUES(true)'; +SECURITY LABEL ON FUNCTION regtest_setcon_1() + IS 'system_u:object_r:sepgsql_regtest_trusted_proc_exec_t:s0'; +SECURITY LABEL ON FUNCTION regtest_setcon_2() + IS 'system_u:object_r:sepgsql_regtest_trusted_proc_exec_t:s0'; +SECURITY LABEL ON FUNCTION regtest_resetcon() + IS 'system_u:object_r:sepgsql_regtest_trusted_proc_exec_t:s0'; +SELECT sepgsql_getcon(); -- confirm client privilege + sepgsql_getcon +--------------------------------------------------- + unconfined_u:unconfined_r:unconfined_t:s0:c0.c255 +(1 row) + +SET sepgsql.client_label = 'unconfined_u:unconfined_r:unconfined_t:s0:c0.c15'; -- OK +SHOW sepgsql.client_label; + sepgsql.client_label +-------------------------------------------------- + unconfined_u:unconfined_r:unconfined_t:s0:c0.c15 +(1 row) + +RESET sepgsql.client_label; -- failed +ERROR: SELinux: security policy violation +SHOW sepgsql.client_label; + sepgsql.client_label +-------------------------------------------------- + unconfined_u:unconfined_r:unconfined_t:s0:c0.c15 +(1 row) + +-- perform as sepgsql_regtest_user_t domai +SET sepgsql.client_label = 'unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0:c0.c15'; -- OK +SHOW sepgsql.client_label; + sepgsql.client_label +------------------------------------------------------------ + unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0:c0.c15 +(1 row) + +SET sepgsql.client_label = 'unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0'; -- failed +ERROR: SELinux: security policy violation +SHOW sepgsql.client_label; + sepgsql.client_label +------------------------------------------------------------ + unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0:c0.c15 +(1 row) + +RESET sepgsql.client_label; -- failed +ERROR: SELinux: security policy violation +SHOW sepgsql.client_label; + sepgsql.client_label +------------------------------------------------------------ + unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0:c0.c15 +(1 row) + +SELECT regtest_setcon_1(); -- OK + regtest_setcon_1 +------------------ + t +(1 row) + +SHOW sepgsql.client_label; + sepgsql.client_label +-------------------------------------------------------------- + unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0:c1,c3,c5 +(1 row) + +SELECT regtest_setcon_2(); -- failed +ERROR: SELinux: security policy violation +CONTEXT: SQL function "regtest_setcon_2" statement 1 +SHOW sepgsql.client_label; + sepgsql.client_label +-------------------------------------------------------------- + unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0:c1,c3,c5 +(1 row) + +SELECT regtest_resetcon(); -- failed +ERROR: SELinux: security policy violation +CONTEXT: SQL function "regtest_resetcon" statement 1 +SHOW sepgsql.client_label; + sepgsql.client_label +-------------------------------------------------------------- + unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0:c1,c3,c5 +(1 row) + +SELECT sepgsql_getcon(); -- confirm client privilege + sepgsql_getcon +------------------------------------------------------------ + unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0:c0.c15 +(1 row) + +SELECT regtest_setcon_1(); -- OK + regtest_setcon_1 +------------------ + t +(1 row) + +SHOW sepgsql.client_label; + sepgsql.client_label +-------------------------------------------------------------- + unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0:c1,c3,c5 +(1 row) + +SELECT sepgsql_getcon(); -- confirm client privilege + sepgsql_getcon +------------------------------------------------------------ + unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0:c0.c15 +(1 row) + +SELECT regtest_setcon_2(); -- failed +ERROR: SELinux: security policy violation +CONTEXT: SQL function "regtest_setcon_2" statement 1 +SHOW sepgsql.client_label; + sepgsql.client_label +------------------------------------------------------------ + unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0:c0.c15 +(1 row) + +SELECT sepgsql_getcon(); -- confirm client privilege + sepgsql_getcon +------------------------------------------------------------ + unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0:c0.c15 +(1 row) + +RESET sepgsql.client_label; -- failed +ERROR: SELinux: security policy violation +SELECT regtest_resetcon(); -- OK + regtest_resetcon +------------------ + t +(1 row) + +SHOW sepgsql.client_label; + sepgsql.client_label +------------------------------------------------------------ + unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0:c0.c15 +(1 row) + diff --git a/contrib/sepgsql/hooks.c b/contrib/sepgsql/hooks.c index 47437ba..10a9096 100644 --- a/contrib/sepgsql/hooks.c +++ b/contrib/sepgsql/hooks.c @@ -18,7 +18,6 @@ #include "commands/seclabel.h" #include "executor/executor.h" #include "fmgr.h" -#include "libpq/auth.h" #include "miscadmin.h" #include "tcop/utility.h" #include "utils/guc.h" @@ -36,10 +35,7 @@ void _PG_init(void); * Saved hook entries (if stacked) */ static object_access_hook_type next_object_access_hook = NULL; -static ClientAuthentication_hook_type next_client_auth_hook = NULL; static ExecutorCheckPerms_hook_type next_exec_check_perms_hook = NULL; -static needs_fmgr_hook_type next_needs_fmgr_hook = NULL; -static fmgr_hook_type next_fmgr_hook = NULL; static ProcessUtility_hook_type next_ProcessUtility_hook = NULL; static ExecutorStart_hook_type next_ExecutorStart_hook = NULL; @@ -82,48 +78,6 @@ sepgsql_get_debug_audit(void) } /* - * sepgsql_client_auth - * - * Entrypoint of the client authentication hook. - * It switches the client label according to getpeercon(), and the current - * performing mode according to the GUC setting. - */ -static void -sepgsql_client_auth(Port *port, int status) -{ - char *context; - - if (next_client_auth_hook) - (*next_client_auth_hook) (port, status); - - /* - * In the case when authentication failed, the supplied socket shall be - * closed soon, so we don't need to do anything here. - */ - if (status != STATUS_OK) - return; - - /* - * Getting security label of the peer process using API of libselinux. - */ - if (getpeercon_raw(port->sock, &context) < 0) - ereport(FATAL, - (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("SELinux: unable to get peer label: %m"))); - - sepgsql_set_client_label(context); - - /* - * Switch the current performing mode from INTERNAL to either DEFAULT or - * PERMISSIVE. - */ - if (sepgsql_permissive) - sepgsql_set_mode(SEPGSQL_MODE_PERMISSIVE); - else - sepgsql_set_mode(SEPGSQL_MODE_DEFAULT); -} - -/* * sepgsql_object_access * * Entrypoint of the object_access_hook. This routine performs as @@ -221,121 +175,6 @@ sepgsql_exec_check_perms(List *rangeTabls, bool abort) } /* - * sepgsql_needs_fmgr_hook - * - * It informs the core whether the supplied function is trusted procedure, - * or not. If true, sepgsql_fmgr_hook shall be invoked at start, end, and - * abort time of function invocation. - */ -static bool -sepgsql_needs_fmgr_hook(Oid functionId) -{ - ObjectAddress object; - - if (next_needs_fmgr_hook && - (*next_needs_fmgr_hook) (functionId)) - return true; - - /* - * SELinux needs the function to be called via security_definer wrapper, - * if this invocation will take a domain-transition. We call these - * functions as trusted-procedure, if the security policy has a rule that - * switches security label of the client on execution. - */ - if (sepgsql_avc_trusted_proc(functionId) != NULL) - return true; - - /* - * Even if not a trusted-procedure, this function should not be inlined - * unless the client has db_procedure:{execute} permission. Please note - * that it shall be actually failed later because of same reason with - * ACL_EXECUTE. - */ - object.classId = ProcedureRelationId; - object.objectId = functionId; - object.objectSubId = 0; - if (!sepgsql_avc_check_perms(&object, - SEPG_CLASS_DB_PROCEDURE, - SEPG_DB_PROCEDURE__EXECUTE, - SEPGSQL_AVC_NOAUDIT, false)) - return true; - - return false; -} - -/* - * sepgsql_fmgr_hook - * - * It switches security label of the client on execution of trusted - * procedures. - */ -static void -sepgsql_fmgr_hook(FmgrHookEventType event, - FmgrInfo *flinfo, Datum *private) -{ - struct - { - char *old_label; - char *new_label; - Datum next_private; - } *stack; - - switch (event) - { - case FHET_START: - stack = (void *) DatumGetPointer(*private); - if (!stack) - { - MemoryContext oldcxt; - - oldcxt = MemoryContextSwitchTo(flinfo->fn_mcxt); - stack = palloc(sizeof(*stack)); - stack->old_label = NULL; - stack->new_label = sepgsql_avc_trusted_proc(flinfo->fn_oid); - stack->next_private = 0; - - MemoryContextSwitchTo(oldcxt); - - /* - * process:transition permission between old and new label, - * when user tries to switch security label of the client - * on execution of trusted procedure. - */ - if (stack->new_label) - sepgsql_avc_check_perms_label(stack->new_label, - SEPG_CLASS_PROCESS, - SEPG_PROCESS__TRANSITION, - NULL, true); - - *private = PointerGetDatum(stack); - } - Assert(!stack->old_label); - if (stack->new_label) - stack->old_label = sepgsql_set_client_label(stack->new_label); - - if (next_fmgr_hook) - (*next_fmgr_hook) (event, flinfo, &stack->next_private); - break; - - case FHET_END: - case FHET_ABORT: - stack = (void *) DatumGetPointer(*private); - - if (next_fmgr_hook) - (*next_fmgr_hook) (event, flinfo, &stack->next_private); - - if (stack->old_label) - sepgsql_set_client_label(stack->old_label); - stack->old_label = NULL; - break; - - default: - elog(ERROR, "unexpected event type: %d", (int) event); - break; - } -} - -/* * sepgsql_executor_start * * It saves contextual information during ExecutorStart to distinguish @@ -465,8 +304,6 @@ sepgsql_utility_command(Node *parsetree, void _PG_init(void) { - char *context; - /* * We allow to load the SE-PostgreSQL module on single-user-mode or * shared_preload_libraries settings only. @@ -522,33 +359,16 @@ _PG_init(void) NULL, NULL); - /* - * Set up dummy client label. - * - * XXX - note that PostgreSQL launches background worker process like - * autovacuum without authentication steps. So, we initialize sepgsql_mode - * with SEPGSQL_MODE_INTERNAL, and client_label with the security context - * of server process. Later, it also launches background of user session. - * In this case, the process is always hooked on post-authentication, and - * we can initialize the sepgsql_mode and client_label correctly. - */ - if (getcon_raw(&context) < 0) - ereport(ERROR, - (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("SELinux: failed to get server security label: %m"))); - sepgsql_set_client_label(context); - /* Initialize userspace access vector cache */ sepgsql_avc_init(); + /* Initialize security label of database client and related hooks */ + sepgsql_init_client_label(); + /* Security label provider hook */ register_label_provider(SEPGSQL_LABEL_TAG, sepgsql_object_relabel); - /* Client authentication hook */ - next_client_auth_hook = ClientAuthentication_hook; - ClientAuthentication_hook = sepgsql_client_auth; - /* Object access hook */ next_object_access_hook = object_access_hook; object_access_hook = sepgsql_object_access; @@ -557,13 +377,6 @@ _PG_init(void) next_exec_check_perms_hook = ExecutorCheckPerms_hook; ExecutorCheckPerms_hook = sepgsql_exec_check_perms; - /* Trusted procedure hooks */ - next_needs_fmgr_hook = needs_fmgr_hook; - needs_fmgr_hook = sepgsql_needs_fmgr_hook; - - next_fmgr_hook = fmgr_hook; - fmgr_hook = sepgsql_fmgr_hook; - /* ProcessUtility hook */ next_ProcessUtility_hook = ProcessUtility_hook; ProcessUtility_hook = sepgsql_utility_command; diff --git a/contrib/sepgsql/label.c b/contrib/sepgsql/label.c index 2ab7a6f..a9ed8b8 100644 --- a/contrib/sepgsql/label.c +++ b/contrib/sepgsql/label.c @@ -22,10 +22,12 @@ #include "catalog/pg_proc.h" #include "commands/dbcommands.h" #include "commands/seclabel.h" +#include "libpq/auth.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "utils/builtins.h" #include "utils/fmgroids.h" +#include "utils/guc.h" #include "utils/lsyscache.h" #include "utils/rel.h" #include "utils/tqual.h" @@ -35,26 +37,283 @@ #include /* - * client_label + * Hooks related to security label of the database client + */ +static ClientAuthentication_hook_type next_client_auth_hook = NULL; +static needs_fmgr_hook_type next_needs_fmgr_hook = NULL; +static fmgr_hook_type next_fmgr_hook = NULL; + +/* + * client_label_* * - * security label of the client process + * security label of the database client; that can be overwritten on the case + * when user assigned a particular security label on sepgsql.client_label GUC, + * or user executed a trusted procedures. */ -static char *client_label = NULL; +static char *client_label_peer = NULL; +static char *client_label_guc = NULL; +static char *client_label_func = NULL; char * sepgsql_get_client_label(void) { - return client_label; + if (client_label_func) + return client_label_func; + if (client_label_guc) + return client_label_guc; + return client_label_peer; } -char * -sepgsql_set_client_label(char *new_label) +/* + * sepgsql_assign_client_label + * + * It is a callback on assignment of sepgsql.client_label guc; to check + * client's capability to set this variable and permission of dynamic domain + * transition from current label to the new one. + */ +static void +sepgsql_assign_client_label(const char *newval, void *extra) +{ + const char *tcontext; + + /* + * In case of GUC RESET, the client must be allowed to translate from + * the current label to the original one being configured on client + * authentication hook. If no allowed, user cannot revert his domain. + */ + if (!newval) + tcontext = client_label_peer; + else + { + if (security_check_context_raw((security_context_t) newval) < 0) + ereport(ERROR, + (errcode(ERRCODE_INVALID_NAME), + errmsg("SELinux: invalid security label: \"%s\"", + newval))); + tcontext = newval; + } + + /* + * check process:{setcurrent} permission + */ + sepgsql_avc_check_perms_label(sepgsql_get_client_label(), + SEPG_CLASS_PROCESS, + SEPG_PROCESS__SETCURRENT, + NULL, + true); + + /* + * check process:{dyntransition} permission + */ + sepgsql_avc_check_perms_label(tcontext, + SEPG_CLASS_PROCESS, + SEPG_PROCESS__DYNTRANSITION, + NULL, + true); +} + +/* + * sepgsql_client_auth + * + * Entrypoint of the client authentication hook. + * It switches the client label according to getpeercon(), and the current + * performing mode according to the GUC setting. + */ +static void +sepgsql_client_auth(Port *port, int status) +{ + if (next_client_auth_hook) + (*next_client_auth_hook) (port, status); + + /* + * In the case when authentication failed, the supplied socket shall be + * closed soon, so we don't need to do anything here. + */ + if (status != STATUS_OK) + return; + + /* + * Getting security label of the peer process using API of libselinux. + */ + if (getpeercon_raw(port->sock, &client_label_peer) < 0) + ereport(FATAL, + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("SELinux: unable to get peer label: %m"))); + + /* + * Switch the current performing mode from INTERNAL to either DEFAULT or + * PERMISSIVE. + */ + if (sepgsql_get_permissive()) + sepgsql_set_mode(SEPGSQL_MODE_PERMISSIVE); + else + sepgsql_set_mode(SEPGSQL_MODE_DEFAULT); +} + +/* + * sepgsql_needs_fmgr_hook + * + * It informs the core whether the supplied function is trusted procedure, + * or not. If true, sepgsql_fmgr_hook shall be invoked at start, end, and + * abort time of function invocation. + */ +static bool +sepgsql_needs_fmgr_hook(Oid functionId) +{ + ObjectAddress object; + + if (next_needs_fmgr_hook && + (*next_needs_fmgr_hook) (functionId)) + return true; + + /* + * SELinux needs the function to be called via security_definer wrapper, + * if this invocation will take a domain-transition. We call these + * functions as trusted-procedure, if the security policy has a rule that + * switches security label of the client on execution. + */ + if (sepgsql_avc_trusted_proc(functionId) != NULL) + return true; + + /* + * Even if not a trusted-procedure, this function should not be inlined + * unless the client has db_procedure:{execute} permission. Please note + * that it shall be actually failed later because of same reason with + * ACL_EXECUTE. + */ + object.classId = ProcedureRelationId; + object.objectId = functionId; + object.objectSubId = 0; + if (!sepgsql_avc_check_perms(&object, + SEPG_CLASS_DB_PROCEDURE, + SEPG_DB_PROCEDURE__EXECUTE, + SEPGSQL_AVC_NOAUDIT, false)) + return true; + + return false; +} + +/* + * sepgsql_fmgr_hook + * + * It switches security label of the client on execution of trusted + * procedures. + */ +static void +sepgsql_fmgr_hook(FmgrHookEventType event, + FmgrInfo *flinfo, Datum *private) { - char *old_label = client_label; + struct + { + char *old_label; + char *new_label; + Datum next_private; + } *stack; + + switch (event) + { + case FHET_START: + stack = (void *) DatumGetPointer(*private); + if (!stack) + { + MemoryContext oldcxt; + + oldcxt = MemoryContextSwitchTo(flinfo->fn_mcxt); + stack = palloc(sizeof(*stack)); + stack->old_label = NULL; + stack->new_label = sepgsql_avc_trusted_proc(flinfo->fn_oid); + stack->next_private = 0; + + MemoryContextSwitchTo(oldcxt); + + /* + * process:transition permission between old and new label, + * when user tries to switch security label of the client + * on execution of trusted procedure. + */ + if (stack->new_label) + sepgsql_avc_check_perms_label(stack->new_label, + SEPG_CLASS_PROCESS, + SEPG_PROCESS__TRANSITION, + NULL, true); + + *private = PointerGetDatum(stack); + } + Assert(!stack->old_label); + if (stack->new_label) + { + stack->old_label = client_label_func; + client_label_func = stack->new_label; + } + if (next_fmgr_hook) + (*next_fmgr_hook) (event, flinfo, &stack->next_private); + break; + + case FHET_END: + case FHET_ABORT: + stack = (void *) DatumGetPointer(*private); + + if (next_fmgr_hook) + (*next_fmgr_hook) (event, flinfo, &stack->next_private); - client_label = new_label; + if (stack->new_label) + { + client_label_func = stack->old_label; + stack->old_label = NULL; + } + break; - return old_label; + default: + elog(ERROR, "unexpected event type: %d", (int) event); + break; + } +} + +/* + * sepgsql_init_client_label + * + * It initializes GUC variable on security label of the database client, + * then set up hooks related to client authentication and trusted procedures. + */ +void +sepgsql_init_client_label(void) +{ + /* + * Set up dummy client label. + * + * XXX - note that PostgreSQL launches background worker process like + * autovacuum without authentication steps. So, we initialize sepgsql_mode + * with SEPGSQL_MODE_INTERNAL, and client_label with the security context + * of server process. Later, it also launches background of user session. + * In this case, the process is always hooked on post-authentication, and + * we can initialize the sepgsql_mode and client_label correctly. + */ + if (getcon_raw(&client_label_peer) < 0) + ereport(ERROR, + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("SELinux: failed to get server security label: %m"))); + + DefineCustomStringVariable("sepgsql.client_label", + "security label of the database client", + NULL, + &client_label_guc, + NULL, + PGC_USERSET, + GUC_NOT_IN_SAMPLE, + NULL, + sepgsql_assign_client_label, + (GucShowHook) sepgsql_get_client_label); + + /* Client authentication hook */ + next_client_auth_hook = ClientAuthentication_hook; + ClientAuthentication_hook = sepgsql_client_auth; + + /* Trusted procedure hooks */ + next_needs_fmgr_hook = needs_fmgr_hook; + needs_fmgr_hook = sepgsql_needs_fmgr_hook; + + next_fmgr_hook = fmgr_hook; + fmgr_hook = sepgsql_fmgr_hook; } /* diff --git a/contrib/sepgsql/selinux.c b/contrib/sepgsql/selinux.c index 8819b8c..0652e29 100644 --- a/contrib/sepgsql/selinux.c +++ b/contrib/sepgsql/selinux.c @@ -46,6 +46,12 @@ static struct "transition", SEPG_PROCESS__TRANSITION }, { + "dyntransition", SEPG_PROCESS__DYNTRANSITION + }, + { + "setcurrent", SEPG_PROCESS__SETCURRENT + }, + { NULL, 0UL } } diff --git a/contrib/sepgsql/sepgsql-regtest.te b/contrib/sepgsql/sepgsql-regtest.te index a8fe247..1d489cd 100644 --- a/contrib/sepgsql/sepgsql-regtest.te +++ b/contrib/sepgsql/sepgsql-regtest.te @@ -1,4 +1,4 @@ -policy_module(sepgsql-regtest, 1.03) +policy_module(sepgsql-regtest, 1.04) gen_require(` all_userspace_class_perms @@ -17,6 +17,8 @@ gen_tunable(sepgsql_regression_test_mode, false) # type sepgsql_regtest_trusted_proc_exec_t; postgresql_procedure_object(sepgsql_regtest_trusted_proc_exec_t) +type sepgsql_nosuch_trusted_proc_exec_t; +postgresql_procedure_object(sepgsql_nosuch_trusted_proc_exec_t) # # Test domains for database administrators @@ -53,6 +55,15 @@ optional_policy(` ') # +# Dummy domain for non-exist users +# +role sepgsql_regtest_nosuch_r; +userdom_base_user_template(sepgsql_regtest_nosuch) +optional_policy(` + postgresql_role(sepgsql_regtest_nosuch_r, sepgsql_regtest_nosuch_t) +') + +# # Rules to launch psql in the dummy domains # optional_policy(` @@ -62,11 +73,13 @@ optional_policy(` type sepgsql_trusted_proc_t; ') tunable_policy(`sepgsql_regression_test_mode',` - allow unconfined_t sepgsql_regtest_dba_t : process { transition }; - allow unconfined_t sepgsql_regtest_user_t : process { transition }; + allow unconfined_t self : process { setcurrent dyntransition }; + allow unconfined_t sepgsql_regtest_dba_t : process { transition dyntransition }; + allow unconfined_t sepgsql_regtest_user_t : process { transition dyntransition}; ') role unconfined_r types sepgsql_regtest_dba_t; role unconfined_r types sepgsql_regtest_user_t; + role unconfined_r types sepgsql_regtest_nosuch_t; role unconfined_r types sepgsql_trusted_proc_t; ') @@ -76,12 +89,25 @@ optional_policy(` optional_policy(` # These rules intends sepgsql_regtest_user_t domain to translate # sepgsql_regtest_dba_t on execution of procedures labeled as - # sepgsql_regtest_trusted_proc_exec_t, but does not allow transition - # permission from sepgsql_regtest_user_t to sepgsql_regtest_dba_t. + # sepgsql_regtest_trusted_proc_exec_t. + # And, also allows to translate from sepgsql_regtest_dba_t to + # sepgsql_regtest_user_t via SET sepgsql.client_label. # gen_require(` attribute sepgsql_client_type; ') allow sepgsql_client_type sepgsql_regtest_trusted_proc_exec_t:db_procedure { getattr execute install }; + allow sepgsql_regtest_user_t sepgsql_regtest_dba_t : process { transition }; type_transition sepgsql_regtest_user_t sepgsql_regtest_trusted_proc_exec_t:process sepgsql_regtest_dba_t; + + allow sepgsql_regtest_dba_t self : process { setcurrent }; + allow sepgsql_regtest_dba_t sepgsql_regtest_user_t : process { dyntransition }; + + # These rules intends sepgsql_regtest_user_t domain to translate + # sepgsql_regtest_nosuch_t on execution of procedures labeled as + # sepgsql_nosuch_trusted_proc_exec_t, without permissions to + # translate to sepgsql_nosuch_trusted_proc_exec_t. + # + allow sepgsql_client_type sepgsql_nosuch_trusted_proc_exec_t:db_procedure { getattr execute install }; + type_transition sepgsql_regtest_user_t sepgsql_nosuch_trusted_proc_exec_t:process sepgsql_regtest_nosuch_t; ') diff --git a/contrib/sepgsql/sepgsql.h b/contrib/sepgsql/sepgsql.h index c93da7a..c97488a 100644 --- a/contrib/sepgsql/sepgsql.h +++ b/contrib/sepgsql/sepgsql.h @@ -57,6 +57,8 @@ * Internally used code of access vectors */ #define SEPG_PROCESS__TRANSITION (1<<0) +#define SEPG_PROCESS__DYNTRANSITION (1<<1) +#define SEPG_PROCESS__SETCURRENT (1<<2) #define SEPG_FILE__READ (1<<0) #define SEPG_FILE__WRITE (1<<1) @@ -267,7 +269,7 @@ extern void sepgsql_avc_init(void); * label.c */ extern char *sepgsql_get_client_label(void); -extern char *sepgsql_set_client_label(char *new_label); +extern void sepgsql_init_client_label(void); extern char *sepgsql_get_label(Oid relOid, Oid objOid, int32 subId); extern void sepgsql_object_relabel(const ObjectAddress *object, diff --git a/contrib/sepgsql/sql/label.sql b/contrib/sepgsql/sql/label.sql index 2b18412..6a9df77 100644 --- a/contrib/sepgsql/sql/label.sql +++ b/contrib/sepgsql/sql/label.sql @@ -31,7 +31,7 @@ CREATE FUNCTION f4 () RETURNS text AS 'SELECT sepgsql_getcon()' LANGUAGE sql; SECURITY LABEL ON FUNCTION f4() - IS 'system_u:object_r:sepgsql_regtest_trusted_proc_exec_t:s0'; + IS 'system_u:object_r:sepgsql_nosuch_trusted_proc_exec_t:s0'; -- -- Tests for default labeling behavior diff --git a/contrib/sepgsql/sql/misc.sql b/contrib/sepgsql/sql/misc.sql index a46d8a6..2beae52 100644 --- a/contrib/sepgsql/sql/misc.sql +++ b/contrib/sepgsql/sql/misc.sql @@ -3,3 +3,70 @@ -- LOAD '$libdir/sepgsql'; -- failed + + +-- +-- Permission checks related to SET sepgsql.client_label +-- + +-- try to degrade client label +CREATE OR REPLACE FUNCTION regtest_setcon_1() + RETURNS bool LANGUAGE SQL + AS 'SET sepgsql.client_label = ''unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0:c1,c3,c5''; + VALUES(true)'; +-- try to upgrade client label +CREATE OR REPLACE FUNCTION regtest_setcon_2() + RETURNS bool LANGUAGE SQL + AS 'SET sepgsql.client_label = ''unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0:c0.c255''; + VALUES(true)'; +-- try to reset client label +CREATE OR REPLACE FUNCTION regtest_resetcon() + RETURNS bool LANGUAGE SQL + AS 'RESET sepgsql.client_label; VALUES(true)'; + +SECURITY LABEL ON FUNCTION regtest_setcon_1() + IS 'system_u:object_r:sepgsql_regtest_trusted_proc_exec_t:s0'; +SECURITY LABEL ON FUNCTION regtest_setcon_2() + IS 'system_u:object_r:sepgsql_regtest_trusted_proc_exec_t:s0'; +SECURITY LABEL ON FUNCTION regtest_resetcon() + IS 'system_u:object_r:sepgsql_regtest_trusted_proc_exec_t:s0'; + +-- @SECURITY-CONTEXT=unconfined_u:unconfined_r:unconfined_t:s0:c0.c255 +SET sepgsql.client_label = 'unconfined_u:unconfined_r:unconfined_t:s0:c0.c15'; -- OK +SHOW sepgsql.client_label; + +RESET sepgsql.client_label; -- failed +SHOW sepgsql.client_label; + +-- perform as sepgsql_regtest_user_t domain +SET sepgsql.client_label = 'unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0:c0.c15'; -- OK +SHOW sepgsql.client_label; + +SET sepgsql.client_label = 'unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0'; -- failed +SHOW sepgsql.client_label; + +RESET sepgsql.client_label; -- failed +SHOW sepgsql.client_label; + +SELECT regtest_setcon_1(); -- OK +SHOW sepgsql.client_label; + +SELECT regtest_setcon_2(); -- failed +SHOW sepgsql.client_label; + +SELECT regtest_resetcon(); -- failed +SHOW sepgsql.client_label; + +-- @SECURITY-CONTEXT=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0:c0.c15 +SELECT regtest_setcon_1(); -- OK +SHOW sepgsql.client_label; + +-- @SECURITY-CONTEXT=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0:c0.c15 +SELECT regtest_setcon_2(); -- failed +SHOW sepgsql.client_label; + +-- @SECURITY-CONTEXT=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0:c0.c15 +RESET sepgsql.client_label; -- failed + +SELECT regtest_resetcon(); -- OK +SHOW sepgsql.client_label;