1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-27 12:41:57 +03:00

sepgsql: Enforce db_procedure:{execute} permission.

To do this, we add an additional object access hook type,
OAT_FUNCTION_EXECUTE.

KaiGai Kohei
This commit is contained in:
Robert Haas
2013-04-12 08:55:56 -04:00
parent d017bf41a3
commit f8a54e936b
16 changed files with 220 additions and 21 deletions

View File

@ -131,23 +131,40 @@ SELECT sepgsql_getcon(); -- confirm client privilege
unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0
(1 row)
SET sepgsql.debug_audit = true;
SET client_min_messages = log;
SELECT f1(); -- normal procedure
LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=unconfined_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function f1()"
LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function sepgsql_getcon()"
CONTEXT: SQL function "f1" statement 1
f1
-----------------------------------------------------
unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0
(1 row)
SELECT f2(); -- trusted procedure
LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=system_u:object_r:sepgsql_trusted_proc_exec_t:s0 tclass=db_procedure name="function f2()"
LOG: SELinux: allowed { entrypoint } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=system_u:object_r:sepgsql_trusted_proc_exec_t:s0 tclass=db_procedure name="function f2()"
LOG: SELinux: allowed { transition } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=unconfined_u:unconfined_r:sepgsql_trusted_proc_t:s0 tclass=process
LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_trusted_proc_t:s0 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function sepgsql_getcon()"
CONTEXT: SQL function "f2" statement 1
f2
-----------------------------------------------------
unconfined_u:unconfined_r:sepgsql_trusted_proc_t:s0
(1 row)
SELECT f3(); -- trusted procedure that raises an error
LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=system_u:object_r:sepgsql_trusted_proc_exec_t:s0 tclass=db_procedure name="function f3()"
LOG: SELinux: allowed { entrypoint } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=system_u:object_r:sepgsql_trusted_proc_exec_t:s0 tclass=db_procedure name="function f3()"
LOG: SELinux: allowed { transition } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=unconfined_u:unconfined_r:sepgsql_trusted_proc_t:s0 tclass=process
ERROR: an exception from f3()
SELECT f4(); -- failed on domain transition
LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=system_u:object_r:sepgsql_nosuch_trusted_proc_exec_t:s0 tclass=db_procedure name="function f4()"
LOG: SELinux: allowed { entrypoint } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=system_u:object_r:sepgsql_nosuch_trusted_proc_exec_t:s0 tclass=db_procedure name="function f4()"
LOG: SELinux: denied { transition } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=unconfined_u:unconfined_r:sepgsql_regtest_nosuch_t:s0 tclass=process
ERROR: SELinux: security policy violation
SELECT sepgsql_getcon(); -- client's label must be restored
LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function sepgsql_getcon()"
sepgsql_getcon
-----------------------------------------------------
unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0

View File

@ -3,3 +3,70 @@
--
LOAD '$libdir/sepgsql'; -- failed
ERROR: SELinux: LOAD is not permitted
--
-- Permissions to execute functions
--
CREATE TABLE t1 (x int, y text);
INSERT INTO t1 (SELECT x, md5(x::text) FROM generate_series(1,100) x);
SET sepgsql.debug_audit = on;
SET client_min_messages = log;
-- regular function and operators
SELECT * FROM t1 WHERE x > 50 AND y like '%64%';
LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="public.t1"
LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table t1 column x"
LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table t1 column y"
LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function int4gt(integer,integer)"
LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function textlike(text,text)"
x | y
-----+----------------------------------
77 | 28dd2c7955ce926456240b2ff0100bde
89 | 7647966b7343c29048673252e490f736
90 | 8613985ec49eb8f757ae6439e879bb2a
91 | 54229abfcfa5649e7003b83dd4755294
99 | ac627ab1ccbdb62ec96e702f07f6425b
100 | f899139df5e1059396431415e770c6dd
(6 rows)
-- aggregate function
SELECT MIN(x), AVG(x) FROM t1;
LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="public.t1"
LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table t1 column x"
LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function avg(integer)"
LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function int4_avg_accum(bigint[],integer)"
LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function int8_avg(bigint[])"
LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function min(integer)"
LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function int4smaller(integer,integer)"
min | avg
-----+---------------------
1 | 50.5000000000000000
(1 row)
-- window function
SELECT row_number() OVER (order by x), * FROM t1 WHERE y like '%86%';
LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="public.t1"
LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table t1 column x"
LOG: SELinux: allowed { select } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table t1 column y"
LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function row_number()"
LOG: SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function textlike(text,text)"
row_number | x | y
------------+----+----------------------------------
1 | 2 | c81e728d9d4c2f636f067f89cc14862c
2 | 17 | 70efdf2ec9b086079795c442636b55fb
3 | 22 | b6d767d2f8ed5d21a44b0e5886680cb9
4 | 27 | 02e74f10e0327ad868d138f2b4fdd6f0
5 | 33 | 182be0c5cdcd5072bb1864cdee4d3d6e
6 | 43 | 17e62166fc8586dfa4d1bc0e1742c08b
7 | 54 | a684eceee76fc522773286a895bc8436
8 | 73 | d2ddea18f00665ce8623e36bd4e3c7c5
9 | 76 | fbd7939d674997cdb4692d34de8633c4
10 | 89 | 7647966b7343c29048673252e490f736
11 | 90 | 8613985ec49eb8f757ae6439e879bb2a
12 | 94 | f4b9ec30ad9f68f89b29639786cb62ef
(12 rows)
RESET sepgsql.debug_audit;
RESET client_min_messages;
--
-- Cleanup
--
DROP TABLE IF EXISTS t1 CASCADE;

View File

@ -255,6 +255,13 @@ sepgsql_object_access(ObjectAccessType access,
}
break;
case OAT_FUNCTION_EXECUTE:
{
Assert(classId == ProcedureRelationId);
sepgsql_proc_execute(objectId);
}
break;
default:
elog(ERROR, "unexpected object access type: %d", (int) access);
break;

View File

@ -303,7 +303,8 @@ sepgsql_needs_fmgr_hook(Oid functionId)
object.objectSubId = 0;
if (!sepgsql_avc_check_perms(&object,
SEPG_CLASS_DB_PROCEDURE,
SEPG_DB_PROCEDURE__EXECUTE,
SEPG_DB_PROCEDURE__EXECUTE |
SEPG_DB_PROCEDURE__ENTRYPOINT,
SEPGSQL_AVC_NOAUDIT, false))
return true;
@ -347,13 +348,31 @@ sepgsql_fmgr_hook(FmgrHookEventType event,
* process:transition permission between old and new label,
* when user tries to switch security label of the client on
* execution of trusted procedure.
*
* Also, db_procedure:entrypoint permission should be checked
* whether this procedure can perform as an entrypoint of the
* trusted procedure, or not.
* Note that db_procedure:execute permission shall be checked
* individually.
*/
if (stack->new_label)
{
ObjectAddress object;
object.classId = ProcedureRelationId;
object.objectId = flinfo->fn_oid;
object.objectSubId = 0;
sepgsql_avc_check_perms(&object,
SEPG_CLASS_DB_PROCEDURE,
SEPG_DB_PROCEDURE__ENTRYPOINT,
getObjectDescription(&object),
true);
sepgsql_avc_check_perms_label(stack->new_label,
SEPG_CLASS_PROCESS,
SEPG_PROCESS__TRANSITION,
NULL, true);
}
*private = PointerGetDatum(stack);
}
Assert(!stack->old_label);

View File

@ -307,3 +307,29 @@ sepgsql_proc_setattr(Oid functionId)
systable_endscan(sscan);
heap_close(rel, AccessShareLock);
}
/*
* sepgsql_proc_execute
*
* It checks privileges to execute the supplied function
*/
void
sepgsql_proc_execute(Oid functionId)
{
ObjectAddress object;
char *audit_name;
/*
* check db_procedure:{execute} permission
*/
object.classId = ProcedureRelationId;
object.objectId = functionId;
object.objectSubId = 0;
audit_name = getObjectDescription(&object);
sepgsql_avc_check_perms(&object,
SEPG_CLASS_DB_PROCEDURE,
SEPG_DB_PROCEDURE__EXECUTE,
audit_name,
true);
pfree(audit_name);
}

View File

@ -1,4 +1,4 @@
policy_module(sepgsql-regtest, 1.06)
policy_module(sepgsql-regtest, 1.07)
gen_require(`
all_userspace_class_perms
@ -172,25 +172,14 @@ optional_policy(`
#
# Rule to execute original trusted procedures
#
# XXX - sepgsql_client_type contains any valid client types, so we allow
# them to execute the original trusted procedure at once.
# These rules intends to allow any valid client types to launch trusted-
# procedures (including ones causes domain transition to invalid domain)
# being labeled as sepgsql_regtest_trusted_proc_exec_t and
# sepgsql_nosuch_trusted_proc_exec_t.
#
optional_policy(`
gen_require(`
attribute sepgsql_client_type;
')
allow sepgsql_client_type { sepgsql_regtest_trusted_proc_exec_t sepgsql_nosuch_trusted_proc_exec_t }:db_procedure { getattr execute };
# 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.
#
# allow sepgsql_client_type sepgsql_regtest_trusted_proc_exec_t:db_procedure { getattr execute };
# 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 };
allow sepgsql_client_type { sepgsql_regtest_trusted_proc_exec_t sepgsql_nosuch_trusted_proc_exec_t }:db_procedure { getattr execute entrypoint };
')

View File

@ -328,5 +328,6 @@ extern void sepgsql_proc_post_create(Oid functionId);
extern void sepgsql_proc_drop(Oid functionId);
extern void sepgsql_proc_relabel(Oid functionId, const char *seclabel);
extern void sepgsql_proc_setattr(Oid functionId);
extern void sepgsql_proc_execute(Oid functionId);
#endif /* SEPGSQL_H */

View File

@ -97,6 +97,8 @@ SECURITY LABEL ON COLUMN t2.b
-- Tests for Trusted Procedures
--
-- @SECURITY-CONTEXT=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0
SET sepgsql.debug_audit = true;
SET client_min_messages = log;
SELECT f1(); -- normal procedure
SELECT f2(); -- trusted procedure
SELECT f3(); -- trusted procedure that raises an error

View File

@ -3,3 +3,28 @@
--
LOAD '$libdir/sepgsql'; -- failed
--
-- Permissions to execute functions
--
CREATE TABLE t1 (x int, y text);
INSERT INTO t1 (SELECT x, md5(x::text) FROM generate_series(1,100) x);
SET sepgsql.debug_audit = on;
SET client_min_messages = log;
-- regular function and operators
SELECT * FROM t1 WHERE x > 50 AND y like '%64%';
-- aggregate function
SELECT MIN(x), AVG(x) FROM t1;
-- window function
SELECT row_number() OVER (order by x), * FROM t1 WHERE y like '%86%';
RESET sepgsql.debug_audit;
RESET client_min_messages;
--
-- Cleanup
--
DROP TABLE IF EXISTS t1 CASCADE;