contrib/sepgsql/expected/create.out | 13 +++++++- contrib/sepgsql/proc.c | 55 +++++++++++++++++++++++++++++++---- contrib/sepgsql/sql/create.sql | 7 ++++ 3 files changed, 68 insertions(+), 7 deletions(-) diff --git a/contrib/sepgsql/expected/create.out b/contrib/sepgsql/expected/create.out index d2c30f0..ec52700 100644 --- a/contrib/sepgsql/expected/create.out +++ b/contrib/sepgsql/expected/create.out @@ -42,12 +42,23 @@ LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_ CREATE SEQUENCE regtest_seq; LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema" LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_seq_t:s0 tclass=db_sequence name="sequence regtest_seq" +CREATE FUNCTION regtest_func(text,int[]) RETURNS bool LANGUAGE plpgsql + AS 'BEGIN RAISE NOTICE ''regtest_func => %'', $1; RETURN true; END'; +LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema" +LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function regtest_func(text,integer[])" +CREATE AGGREGATE regtest_agg (*) ( + sfunc = int8inc, stype = int8, initcond = '0' +); +LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema" +LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function regtest_agg()" -- -- clean-up -- DROP DATABASE IF EXISTS regtest_sepgsql_test_database; DROP SCHEMA IF EXISTS regtest_schema CASCADE; -NOTICE: drop cascades to 3 other objects +NOTICE: drop cascades to 5 other objects DETAIL: drop cascades to table regtest_table drop cascades to view regtest_view drop cascades to sequence regtest_seq +drop cascades to function regtest_func(text,integer[]) +drop cascades to function regtest_agg() diff --git a/contrib/sepgsql/proc.c b/contrib/sepgsql/proc.c index 9630d45..14231c4 100644 --- a/contrib/sepgsql/proc.c +++ b/contrib/sepgsql/proc.c @@ -18,6 +18,7 @@ #include "catalog/pg_namespace.h" #include "catalog/pg_proc.h" #include "commands/seclabel.h" +#include "utils/builtins.h" #include "utils/fmgroids.h" #include "utils/lsyscache.h" #include "utils/tqual.h" @@ -37,11 +38,13 @@ sepgsql_proc_post_create(Oid functionId) ScanKeyData skey; SysScanDesc sscan; HeapTuple tuple; - Oid namespaceId; - ObjectAddress object; char *scontext; char *tcontext; char *ncontext; + int i; + StringInfoData audit_name; + ObjectAddress object; + Form_pg_proc proForm; /* * Fetch namespace of the new procedure. Because pg_proc entry is not @@ -61,21 +64,54 @@ sepgsql_proc_post_create(Oid functionId) if (!HeapTupleIsValid(tuple)) elog(ERROR, "catalog lookup failed for proc %u", functionId); - namespaceId = ((Form_pg_proc) GETSTRUCT(tuple))->pronamespace; + proForm = (Form_pg_proc) GETSTRUCT(tuple); + + /* + * check db_schema:{add_name} permission of the namespace + */ + object.classId = NamespaceRelationId; + object.objectId = proForm->pronamespace; + object.objectSubId = 0; + sepgsql_avc_check_perms(&object, + SEPG_CLASS_DB_SCHEMA, + SEPG_DB_SCHEMA__ADD_NAME, + getObjectDescription(&object), + true); + /* + * XXX - db_language:{implement} also should be checked here + */ - systable_endscan(sscan); - heap_close(rel, AccessShareLock); /* * Compute a default security label when we create a new procedure object * under the specified namespace. */ scontext = sepgsql_get_client_label(); - tcontext = sepgsql_get_label(NamespaceRelationId, namespaceId, 0); + tcontext = sepgsql_get_label(NamespaceRelationId, + proForm->pronamespace, 0); ncontext = sepgsql_compute_create(scontext, tcontext, SEPG_CLASS_DB_PROCEDURE); /* + * check db_procedure:{create} permission + */ + initStringInfo(&audit_name); + appendStringInfo(&audit_name, "function %s(", NameStr(proForm->proname)); + for (i=0; i < proForm->pronargs; i++) + { + Oid typeoid = proForm->proargtypes.values[i]; + if (i > 0) + appendStringInfoChar(&audit_name, ','); + appendStringInfoString(&audit_name, format_type_be(typeoid)); + } + appendStringInfoChar(&audit_name, ')'); + + sepgsql_avc_check_perms_label(ncontext, + SEPG_CLASS_DB_PROCEDURE, + SEPG_DB_PROCEDURE__CREATE, + audit_name.data, + true); + /* * Assign the default security label on a new procedure */ object.classId = ProcedureRelationId; @@ -83,6 +119,13 @@ sepgsql_proc_post_create(Oid functionId) object.objectSubId = 0; SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, ncontext); + /* + * Cleanup + */ + systable_endscan(sscan); + heap_close(rel, AccessShareLock); + + pfree(audit_name.data); pfree(tcontext); pfree(ncontext); } diff --git a/contrib/sepgsql/sql/create.sql b/contrib/sepgsql/sql/create.sql index 9cb2b60..512c114 100644 --- a/contrib/sepgsql/sql/create.sql +++ b/contrib/sepgsql/sql/create.sql @@ -25,6 +25,13 @@ CREATE VIEW regtest_view AS SELECT * FROM regtest_table WHERE x < 100; CREATE SEQUENCE regtest_seq; +CREATE FUNCTION regtest_func(text,int[]) RETURNS bool LANGUAGE plpgsql + AS 'BEGIN RAISE NOTICE ''regtest_func => %'', $1; RETURN true; END'; + +CREATE AGGREGATE regtest_agg (*) ( + sfunc = int8inc, stype = int8, initcond = '0' +); + -- -- clean-up --