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:
parent
d017bf41a3
commit
f8a54e936b
|
@ -131,23 +131,40 @@ SELECT sepgsql_getcon(); -- confirm client privilege
|
||||||
unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0
|
unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
SET sepgsql.debug_audit = true;
|
||||||
|
SET client_min_messages = log;
|
||||||
SELECT f1(); -- normal procedure
|
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
|
f1
|
||||||
-----------------------------------------------------
|
-----------------------------------------------------
|
||||||
unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0
|
unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT f2(); -- trusted procedure
|
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
|
f2
|
||||||
-----------------------------------------------------
|
-----------------------------------------------------
|
||||||
unconfined_u:unconfined_r:sepgsql_trusted_proc_t:s0
|
unconfined_u:unconfined_r:sepgsql_trusted_proc_t:s0
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT f3(); -- trusted procedure that raises an error
|
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()
|
ERROR: an exception from f3()
|
||||||
SELECT f4(); -- failed on domain transition
|
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
|
ERROR: SELinux: security policy violation
|
||||||
SELECT sepgsql_getcon(); -- client's label must be restored
|
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
|
sepgsql_getcon
|
||||||
-----------------------------------------------------
|
-----------------------------------------------------
|
||||||
unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0
|
unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0
|
||||||
|
|
|
@ -3,3 +3,70 @@
|
||||||
--
|
--
|
||||||
LOAD '$libdir/sepgsql'; -- failed
|
LOAD '$libdir/sepgsql'; -- failed
|
||||||
ERROR: SELinux: LOAD is not permitted
|
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;
|
||||||
|
|
|
@ -255,6 +255,13 @@ sepgsql_object_access(ObjectAccessType access,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case OAT_FUNCTION_EXECUTE:
|
||||||
|
{
|
||||||
|
Assert(classId == ProcedureRelationId);
|
||||||
|
sepgsql_proc_execute(objectId);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
elog(ERROR, "unexpected object access type: %d", (int) access);
|
elog(ERROR, "unexpected object access type: %d", (int) access);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -303,7 +303,8 @@ sepgsql_needs_fmgr_hook(Oid functionId)
|
||||||
object.objectSubId = 0;
|
object.objectSubId = 0;
|
||||||
if (!sepgsql_avc_check_perms(&object,
|
if (!sepgsql_avc_check_perms(&object,
|
||||||
SEPG_CLASS_DB_PROCEDURE,
|
SEPG_CLASS_DB_PROCEDURE,
|
||||||
SEPG_DB_PROCEDURE__EXECUTE,
|
SEPG_DB_PROCEDURE__EXECUTE |
|
||||||
|
SEPG_DB_PROCEDURE__ENTRYPOINT,
|
||||||
SEPGSQL_AVC_NOAUDIT, false))
|
SEPGSQL_AVC_NOAUDIT, false))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -347,13 +348,31 @@ sepgsql_fmgr_hook(FmgrHookEventType event,
|
||||||
* process:transition permission between old and new label,
|
* process:transition permission between old and new label,
|
||||||
* when user tries to switch security label of the client on
|
* when user tries to switch security label of the client on
|
||||||
* execution of trusted procedure.
|
* 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)
|
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,
|
sepgsql_avc_check_perms_label(stack->new_label,
|
||||||
SEPG_CLASS_PROCESS,
|
SEPG_CLASS_PROCESS,
|
||||||
SEPG_PROCESS__TRANSITION,
|
SEPG_PROCESS__TRANSITION,
|
||||||
NULL, true);
|
NULL, true);
|
||||||
|
}
|
||||||
*private = PointerGetDatum(stack);
|
*private = PointerGetDatum(stack);
|
||||||
}
|
}
|
||||||
Assert(!stack->old_label);
|
Assert(!stack->old_label);
|
||||||
|
|
|
@ -307,3 +307,29 @@ sepgsql_proc_setattr(Oid functionId)
|
||||||
systable_endscan(sscan);
|
systable_endscan(sscan);
|
||||||
heap_close(rel, AccessShareLock);
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
policy_module(sepgsql-regtest, 1.06)
|
policy_module(sepgsql-regtest, 1.07)
|
||||||
|
|
||||||
gen_require(`
|
gen_require(`
|
||||||
all_userspace_class_perms
|
all_userspace_class_perms
|
||||||
|
@ -172,25 +172,14 @@ optional_policy(`
|
||||||
#
|
#
|
||||||
# Rule to execute original trusted procedures
|
# Rule to execute original trusted procedures
|
||||||
#
|
#
|
||||||
# XXX - sepgsql_client_type contains any valid client types, so we allow
|
# These rules intends to allow any valid client types to launch trusted-
|
||||||
# them to execute the original trusted procedure at once.
|
# 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(`
|
optional_policy(`
|
||||||
gen_require(`
|
gen_require(`
|
||||||
attribute sepgsql_client_type;
|
attribute sepgsql_client_type;
|
||||||
')
|
')
|
||||||
allow sepgsql_client_type { sepgsql_regtest_trusted_proc_exec_t sepgsql_nosuch_trusted_proc_exec_t }:db_procedure { getattr execute };
|
allow sepgsql_client_type { sepgsql_regtest_trusted_proc_exec_t sepgsql_nosuch_trusted_proc_exec_t }:db_procedure { getattr execute entrypoint };
|
||||||
|
|
||||||
# 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 };
|
|
||||||
')
|
')
|
||||||
|
|
|
@ -328,5 +328,6 @@ extern void sepgsql_proc_post_create(Oid functionId);
|
||||||
extern void sepgsql_proc_drop(Oid functionId);
|
extern void sepgsql_proc_drop(Oid functionId);
|
||||||
extern void sepgsql_proc_relabel(Oid functionId, const char *seclabel);
|
extern void sepgsql_proc_relabel(Oid functionId, const char *seclabel);
|
||||||
extern void sepgsql_proc_setattr(Oid functionId);
|
extern void sepgsql_proc_setattr(Oid functionId);
|
||||||
|
extern void sepgsql_proc_execute(Oid functionId);
|
||||||
|
|
||||||
#endif /* SEPGSQL_H */
|
#endif /* SEPGSQL_H */
|
||||||
|
|
|
@ -97,6 +97,8 @@ SECURITY LABEL ON COLUMN t2.b
|
||||||
-- Tests for Trusted Procedures
|
-- Tests for Trusted Procedures
|
||||||
--
|
--
|
||||||
-- @SECURITY-CONTEXT=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0
|
-- @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 f1(); -- normal procedure
|
||||||
SELECT f2(); -- trusted procedure
|
SELECT f2(); -- trusted procedure
|
||||||
SELECT f3(); -- trusted procedure that raises an error
|
SELECT f3(); -- trusted procedure that raises an error
|
||||||
|
|
|
@ -3,3 +3,28 @@
|
||||||
--
|
--
|
||||||
|
|
||||||
LOAD '$libdir/sepgsql'; -- failed
|
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;
|
||||||
|
|
|
@ -393,8 +393,11 @@ UPDATE t1 SET x = 2, y = md5sum(y) WHERE z = 100;
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
For functions, <literal>db_procedure:{execute}</> is defined, but is not
|
For functions, <literal>db_procedure:{execute}</> will be checked when
|
||||||
checked in this version.
|
user tries to execute a function as a part of query, or using fast-path
|
||||||
|
invocation. If this function is a trusted procedure, it also checks
|
||||||
|
<literal>db_procedure:{entrypoint}</> permission to check whether it
|
||||||
|
can perform as entrypoint of trusted procedure.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
#include "catalog/objectaccess.h"
|
#include "catalog/objectaccess.h"
|
||||||
#include "catalog/pg_namespace.h"
|
#include "catalog/pg_namespace.h"
|
||||||
|
#include "catalog/pg_proc.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Hook on object accesses. This is intended as infrastructure for security
|
* Hook on object accesses. This is intended as infrastructure for security
|
||||||
|
@ -109,3 +110,19 @@ RunNamespaceSearchHook(Oid objectId, bool ereport_on_violation)
|
||||||
|
|
||||||
return ns_arg.result;
|
return ns_arg.result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RunFunctionExecuteHook
|
||||||
|
*
|
||||||
|
* It is entrypoint of OAT_FUNCTION_EXECUTE event
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
RunFunctionExecuteHook(Oid objectId)
|
||||||
|
{
|
||||||
|
/* caller should check, but just in case... */
|
||||||
|
Assert(object_access_hook != NULL);
|
||||||
|
|
||||||
|
(*object_access_hook)(OAT_FUNCTION_EXECUTE,
|
||||||
|
ProcedureRelationId, objectId, 0,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
#include "access/htup_details.h"
|
#include "access/htup_details.h"
|
||||||
#include "access/nbtree.h"
|
#include "access/nbtree.h"
|
||||||
#include "access/tupconvert.h"
|
#include "access/tupconvert.h"
|
||||||
|
#include "catalog/objectaccess.h"
|
||||||
#include "catalog/pg_type.h"
|
#include "catalog/pg_type.h"
|
||||||
#include "commands/typecmds.h"
|
#include "commands/typecmds.h"
|
||||||
#include "executor/execdebug.h"
|
#include "executor/execdebug.h"
|
||||||
|
@ -1289,6 +1290,7 @@ init_fcache(Oid foid, Oid input_collation, FuncExprState *fcache,
|
||||||
aclresult = pg_proc_aclcheck(foid, GetUserId(), ACL_EXECUTE);
|
aclresult = pg_proc_aclcheck(foid, GetUserId(), ACL_EXECUTE);
|
||||||
if (aclresult != ACLCHECK_OK)
|
if (aclresult != ACLCHECK_OK)
|
||||||
aclcheck_error(aclresult, ACL_KIND_PROC, get_func_name(foid));
|
aclcheck_error(aclresult, ACL_KIND_PROC, get_func_name(foid));
|
||||||
|
InvokeFunctionExecuteHook(foid);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Safety check on nargs. Under normal circumstances this should never
|
* Safety check on nargs. Under normal circumstances this should never
|
||||||
|
@ -4223,6 +4225,7 @@ ExecEvalArrayCoerceExpr(ArrayCoerceExprState *astate,
|
||||||
if (aclresult != ACLCHECK_OK)
|
if (aclresult != ACLCHECK_OK)
|
||||||
aclcheck_error(aclresult, ACL_KIND_PROC,
|
aclcheck_error(aclresult, ACL_KIND_PROC,
|
||||||
get_func_name(acoerce->elemfuncid));
|
get_func_name(acoerce->elemfuncid));
|
||||||
|
InvokeFunctionExecuteHook(acoerce->elemfuncid);
|
||||||
|
|
||||||
/* Set up the primary fmgr lookup information */
|
/* Set up the primary fmgr lookup information */
|
||||||
fmgr_info_cxt(acoerce->elemfuncid, &(astate->elemfunc),
|
fmgr_info_cxt(acoerce->elemfuncid, &(astate->elemfunc),
|
||||||
|
|
|
@ -79,6 +79,7 @@
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include "access/htup_details.h"
|
#include "access/htup_details.h"
|
||||||
|
#include "catalog/objectaccess.h"
|
||||||
#include "catalog/pg_aggregate.h"
|
#include "catalog/pg_aggregate.h"
|
||||||
#include "catalog/pg_proc.h"
|
#include "catalog/pg_proc.h"
|
||||||
#include "catalog/pg_type.h"
|
#include "catalog/pg_type.h"
|
||||||
|
@ -1625,6 +1626,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
|
||||||
if (aclresult != ACLCHECK_OK)
|
if (aclresult != ACLCHECK_OK)
|
||||||
aclcheck_error(aclresult, ACL_KIND_PROC,
|
aclcheck_error(aclresult, ACL_KIND_PROC,
|
||||||
get_func_name(aggref->aggfnoid));
|
get_func_name(aggref->aggfnoid));
|
||||||
|
InvokeFunctionExecuteHook(aggref->aggfnoid);
|
||||||
|
|
||||||
peraggstate->transfn_oid = transfn_oid = aggform->aggtransfn;
|
peraggstate->transfn_oid = transfn_oid = aggform->aggtransfn;
|
||||||
peraggstate->finalfn_oid = finalfn_oid = aggform->aggfinalfn;
|
peraggstate->finalfn_oid = finalfn_oid = aggform->aggfinalfn;
|
||||||
|
@ -1647,6 +1649,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
|
||||||
if (aclresult != ACLCHECK_OK)
|
if (aclresult != ACLCHECK_OK)
|
||||||
aclcheck_error(aclresult, ACL_KIND_PROC,
|
aclcheck_error(aclresult, ACL_KIND_PROC,
|
||||||
get_func_name(transfn_oid));
|
get_func_name(transfn_oid));
|
||||||
|
InvokeFunctionExecuteHook(transfn_oid);
|
||||||
if (OidIsValid(finalfn_oid))
|
if (OidIsValid(finalfn_oid))
|
||||||
{
|
{
|
||||||
aclresult = pg_proc_aclcheck(finalfn_oid, aggOwner,
|
aclresult = pg_proc_aclcheck(finalfn_oid, aggOwner,
|
||||||
|
@ -1654,6 +1657,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
|
||||||
if (aclresult != ACLCHECK_OK)
|
if (aclresult != ACLCHECK_OK)
|
||||||
aclcheck_error(aclresult, ACL_KIND_PROC,
|
aclcheck_error(aclresult, ACL_KIND_PROC,
|
||||||
get_func_name(finalfn_oid));
|
get_func_name(finalfn_oid));
|
||||||
|
InvokeFunctionExecuteHook(finalfn_oid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include "access/htup_details.h"
|
#include "access/htup_details.h"
|
||||||
|
#include "catalog/objectaccess.h"
|
||||||
#include "catalog/pg_aggregate.h"
|
#include "catalog/pg_aggregate.h"
|
||||||
#include "catalog/pg_proc.h"
|
#include "catalog/pg_proc.h"
|
||||||
#include "catalog/pg_type.h"
|
#include "catalog/pg_type.h"
|
||||||
|
@ -1559,6 +1560,7 @@ ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags)
|
||||||
if (aclresult != ACLCHECK_OK)
|
if (aclresult != ACLCHECK_OK)
|
||||||
aclcheck_error(aclresult, ACL_KIND_PROC,
|
aclcheck_error(aclresult, ACL_KIND_PROC,
|
||||||
get_func_name(wfunc->winfnoid));
|
get_func_name(wfunc->winfnoid));
|
||||||
|
InvokeFunctionExecuteHook(wfunc->winfnoid);
|
||||||
|
|
||||||
/* Fill in the perfuncstate data */
|
/* Fill in the perfuncstate data */
|
||||||
perfuncstate->wfuncstate = wfuncstate;
|
perfuncstate->wfuncstate = wfuncstate;
|
||||||
|
@ -1767,6 +1769,7 @@ initialize_peragg(WindowAggState *winstate, WindowFunc *wfunc,
|
||||||
if (aclresult != ACLCHECK_OK)
|
if (aclresult != ACLCHECK_OK)
|
||||||
aclcheck_error(aclresult, ACL_KIND_PROC,
|
aclcheck_error(aclresult, ACL_KIND_PROC,
|
||||||
get_func_name(transfn_oid));
|
get_func_name(transfn_oid));
|
||||||
|
InvokeFunctionExecuteHook(transfn_oid);
|
||||||
if (OidIsValid(finalfn_oid))
|
if (OidIsValid(finalfn_oid))
|
||||||
{
|
{
|
||||||
aclresult = pg_proc_aclcheck(finalfn_oid, aggOwner,
|
aclresult = pg_proc_aclcheck(finalfn_oid, aggOwner,
|
||||||
|
@ -1774,6 +1777,7 @@ initialize_peragg(WindowAggState *winstate, WindowFunc *wfunc,
|
||||||
if (aclresult != ACLCHECK_OK)
|
if (aclresult != ACLCHECK_OK)
|
||||||
aclcheck_error(aclresult, ACL_KIND_PROC,
|
aclcheck_error(aclresult, ACL_KIND_PROC,
|
||||||
get_func_name(finalfn_oid));
|
get_func_name(finalfn_oid));
|
||||||
|
InvokeFunctionExecuteHook(finalfn_oid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -362,6 +362,7 @@ HandleFunctionRequest(StringInfo msgBuf)
|
||||||
if (aclresult != ACLCHECK_OK)
|
if (aclresult != ACLCHECK_OK)
|
||||||
aclcheck_error(aclresult, ACL_KIND_PROC,
|
aclcheck_error(aclresult, ACL_KIND_PROC,
|
||||||
get_func_name(fid));
|
get_func_name(fid));
|
||||||
|
InvokeFunctionExecuteHook(fid);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Prepare function call info block and insert arguments.
|
* Prepare function call info block and insert arguments.
|
||||||
|
|
|
@ -31,6 +31,12 @@
|
||||||
* a particular namespace. This event is equivalent to usage permission
|
* a particular namespace. This event is equivalent to usage permission
|
||||||
* on a schema under the default access control mechanism.
|
* on a schema under the default access control mechanism.
|
||||||
*
|
*
|
||||||
|
* OAT_FUNCTION_EXECUTE should be invoked prior to function execution.
|
||||||
|
* This event is almost equivalent to execute permission on functions,
|
||||||
|
* except for the case when execute permission is checked during object
|
||||||
|
* creation or altering, because OAT_POST_CREATE or OAT_POST_ALTER are
|
||||||
|
* sufficient for extensions to track these kind of checks.
|
||||||
|
*
|
||||||
* Other types may be added in the future.
|
* Other types may be added in the future.
|
||||||
*/
|
*/
|
||||||
typedef enum ObjectAccessType
|
typedef enum ObjectAccessType
|
||||||
|
@ -39,6 +45,7 @@ typedef enum ObjectAccessType
|
||||||
OAT_DROP,
|
OAT_DROP,
|
||||||
OAT_POST_ALTER,
|
OAT_POST_ALTER,
|
||||||
OAT_NAMESPACE_SEARCH,
|
OAT_NAMESPACE_SEARCH,
|
||||||
|
OAT_FUNCTION_EXECUTE,
|
||||||
} ObjectAccessType;
|
} ObjectAccessType;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -129,6 +136,7 @@ extern void RunObjectDropHook(Oid classId, Oid objectId, int subId,
|
||||||
extern void RunObjectPostAlterHook(Oid classId, Oid objectId, int subId,
|
extern void RunObjectPostAlterHook(Oid classId, Oid objectId, int subId,
|
||||||
Oid auxiliaryId, bool is_internal);
|
Oid auxiliaryId, bool is_internal);
|
||||||
extern bool RunNamespaceSearchHook(Oid objectId, bool ereport_on_volation);
|
extern bool RunNamespaceSearchHook(Oid objectId, bool ereport_on_volation);
|
||||||
|
extern void RunFunctionExecuteHook(Oid objectId);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The following macros are wrappers around the functions above; these should
|
* The following macros are wrappers around the functions above; these should
|
||||||
|
@ -170,4 +178,10 @@ extern bool RunNamespaceSearchHook(Oid objectId, bool ereport_on_volation);
|
||||||
? true \
|
? true \
|
||||||
: RunNamespaceSearchHook((objectId), (ereport_on_violation)))
|
: RunNamespaceSearchHook((objectId), (ereport_on_violation)))
|
||||||
|
|
||||||
|
#define InvokeFunctionExecuteHook(objectId) \
|
||||||
|
do { \
|
||||||
|
if (object_access_hook) \
|
||||||
|
RunFunctionExecuteHook(objectId); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
#endif /* OBJECTACCESS_H */
|
#endif /* OBJECTACCESS_H */
|
||||||
|
|
Loading…
Reference in New Issue