Skip to content

Commit f8a54e9

Browse files
committed
sepgsql: Enforce db_procedure:{execute} permission.
To do this, we add an additional object access hook type, OAT_FUNCTION_EXECUTE. KaiGai Kohei
1 parent d017bf4 commit f8a54e9

File tree

16 files changed

+220
-21
lines changed

16 files changed

+220
-21
lines changed

contrib/sepgsql/expected/label.out

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,23 +131,40 @@ SELECT sepgsql_getcon(); -- confirm client privilege
131131
unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0
132132
(1 row)
133133

134+
SET sepgsql.debug_audit = true;
135+
SET client_min_messages = log;
134136
SELECT f1(); -- normal procedure
137+
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()"
138+
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()"
139+
CONTEXT: SQL function "f1" statement 1
135140
f1
136141
-----------------------------------------------------
137142
unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0
138143
(1 row)
139144

140145
SELECT f2(); -- trusted procedure
146+
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()"
147+
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()"
148+
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
149+
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()"
150+
CONTEXT: SQL function "f2" statement 1
141151
f2
142152
-----------------------------------------------------
143153
unconfined_u:unconfined_r:sepgsql_trusted_proc_t:s0
144154
(1 row)
145155

146156
SELECT f3(); -- trusted procedure that raises an error
157+
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()"
158+
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()"
159+
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
147160
ERROR: an exception from f3()
148161
SELECT f4(); -- failed on domain transition
162+
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()"
163+
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()"
164+
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
149165
ERROR: SELinux: security policy violation
150166
SELECT sepgsql_getcon(); -- client's label must be restored
167+
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()"
151168
sepgsql_getcon
152169
-----------------------------------------------------
153170
unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0

contrib/sepgsql/expected/misc.out

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,70 @@
33
--
44
LOAD '$libdir/sepgsql'; -- failed
55
ERROR: SELinux: LOAD is not permitted
6+
--
7+
-- Permissions to execute functions
8+
--
9+
CREATE TABLE t1 (x int, y text);
10+
INSERT INTO t1 (SELECT x, md5(x::text) FROM generate_series(1,100) x);
11+
SET sepgsql.debug_audit = on;
12+
SET client_min_messages = log;
13+
-- regular function and operators
14+
SELECT * FROM t1 WHERE x > 50 AND y like '%64%';
15+
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"
16+
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"
17+
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"
18+
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)"
19+
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)"
20+
x | y
21+
-----+----------------------------------
22+
77 | 28dd2c7955ce926456240b2ff0100bde
23+
89 | 7647966b7343c29048673252e490f736
24+
90 | 8613985ec49eb8f757ae6439e879bb2a
25+
91 | 54229abfcfa5649e7003b83dd4755294
26+
99 | ac627ab1ccbdb62ec96e702f07f6425b
27+
100 | f899139df5e1059396431415e770c6dd
28+
(6 rows)
29+
30+
-- aggregate function
31+
SELECT MIN(x), AVG(x) FROM t1;
32+
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"
33+
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"
34+
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)"
35+
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)"
36+
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[])"
37+
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)"
38+
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)"
39+
min | avg
40+
-----+---------------------
41+
1 | 50.5000000000000000
42+
(1 row)
43+
44+
-- window function
45+
SELECT row_number() OVER (order by x), * FROM t1 WHERE y like '%86%';
46+
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"
47+
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"
48+
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"
49+
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()"
50+
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)"
51+
row_number | x | y
52+
------------+----+----------------------------------
53+
1 | 2 | c81e728d9d4c2f636f067f89cc14862c
54+
2 | 17 | 70efdf2ec9b086079795c442636b55fb
55+
3 | 22 | b6d767d2f8ed5d21a44b0e5886680cb9
56+
4 | 27 | 02e74f10e0327ad868d138f2b4fdd6f0
57+
5 | 33 | 182be0c5cdcd5072bb1864cdee4d3d6e
58+
6 | 43 | 17e62166fc8586dfa4d1bc0e1742c08b
59+
7 | 54 | a684eceee76fc522773286a895bc8436
60+
8 | 73 | d2ddea18f00665ce8623e36bd4e3c7c5
61+
9 | 76 | fbd7939d674997cdb4692d34de8633c4
62+
10 | 89 | 7647966b7343c29048673252e490f736
63+
11 | 90 | 8613985ec49eb8f757ae6439e879bb2a
64+
12 | 94 | f4b9ec30ad9f68f89b29639786cb62ef
65+
(12 rows)
66+
67+
RESET sepgsql.debug_audit;
68+
RESET client_min_messages;
69+
--
70+
-- Cleanup
71+
--
72+
DROP TABLE IF EXISTS t1 CASCADE;

contrib/sepgsql/hooks.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,13 @@ sepgsql_object_access(ObjectAccessType access,
255255
}
256256
break;
257257

258+
case OAT_FUNCTION_EXECUTE:
259+
{
260+
Assert(classId == ProcedureRelationId);
261+
sepgsql_proc_execute(objectId);
262+
}
263+
break;
264+
258265
default:
259266
elog(ERROR, "unexpected object access type: %d", (int) access);
260267
break;

contrib/sepgsql/label.c

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,8 @@ sepgsql_needs_fmgr_hook(Oid functionId)
303303
object.objectSubId = 0;
304304
if (!sepgsql_avc_check_perms(&object,
305305
SEPG_CLASS_DB_PROCEDURE,
306-
SEPG_DB_PROCEDURE__EXECUTE,
306+
SEPG_DB_PROCEDURE__EXECUTE |
307+
SEPG_DB_PROCEDURE__ENTRYPOINT,
307308
SEPGSQL_AVC_NOAUDIT, false))
308309
return true;
309310

@@ -347,13 +348,31 @@ sepgsql_fmgr_hook(FmgrHookEventType event,
347348
* process:transition permission between old and new label,
348349
* when user tries to switch security label of the client on
349350
* execution of trusted procedure.
351+
*
352+
* Also, db_procedure:entrypoint permission should be checked
353+
* whether this procedure can perform as an entrypoint of the
354+
* trusted procedure, or not.
355+
* Note that db_procedure:execute permission shall be checked
356+
* individually.
350357
*/
351358
if (stack->new_label)
359+
{
360+
ObjectAddress object;
361+
362+
object.classId = ProcedureRelationId;
363+
object.objectId = flinfo->fn_oid;
364+
object.objectSubId = 0;
365+
sepgsql_avc_check_perms(&object,
366+
SEPG_CLASS_DB_PROCEDURE,
367+
SEPG_DB_PROCEDURE__ENTRYPOINT,
368+
getObjectDescription(&object),
369+
true);
370+
352371
sepgsql_avc_check_perms_label(stack->new_label,
353372
SEPG_CLASS_PROCESS,
354373
SEPG_PROCESS__TRANSITION,
355374
NULL, true);
356-
375+
}
357376
*private = PointerGetDatum(stack);
358377
}
359378
Assert(!stack->old_label);

contrib/sepgsql/proc.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,3 +307,29 @@ sepgsql_proc_setattr(Oid functionId)
307307
systable_endscan(sscan);
308308
heap_close(rel, AccessShareLock);
309309
}
310+
311+
/*
312+
* sepgsql_proc_execute
313+
*
314+
* It checks privileges to execute the supplied function
315+
*/
316+
void
317+
sepgsql_proc_execute(Oid functionId)
318+
{
319+
ObjectAddress object;
320+
char *audit_name;
321+
322+
/*
323+
* check db_procedure:{execute} permission
324+
*/
325+
object.classId = ProcedureRelationId;
326+
object.objectId = functionId;
327+
object.objectSubId = 0;
328+
audit_name = getObjectDescription(&object);
329+
sepgsql_avc_check_perms(&object,
330+
SEPG_CLASS_DB_PROCEDURE,
331+
SEPG_DB_PROCEDURE__EXECUTE,
332+
audit_name,
333+
true);
334+
pfree(audit_name);
335+
}

contrib/sepgsql/sepgsql-regtest.te

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
policy_module(sepgsql-regtest, 1.06)
1+
policy_module(sepgsql-regtest, 1.07)
22

33
gen_require(`
44
all_userspace_class_perms
@@ -172,25 +172,14 @@ optional_policy(`
172172
#
173173
# Rule to execute original trusted procedures
174174
#
175-
# XXX - sepgsql_client_type contains any valid client types, so we allow
176-
# them to execute the original trusted procedure at once.
175+
# These rules intends to allow any valid client types to launch trusted-
176+
# procedures (including ones causes domain transition to invalid domain)
177+
# being labeled as sepgsql_regtest_trusted_proc_exec_t and
178+
# sepgsql_nosuch_trusted_proc_exec_t.
177179
#
178180
optional_policy(`
179181
gen_require(`
180182
attribute sepgsql_client_type;
181183
')
182-
allow sepgsql_client_type { sepgsql_regtest_trusted_proc_exec_t sepgsql_nosuch_trusted_proc_exec_t }:db_procedure { getattr execute };
183-
184-
# These rules intends sepgsql_regtest_user_t domain to translate
185-
# sepgsql_regtest_dba_t on execution of procedures labeled as
186-
# sepgsql_regtest_trusted_proc_exec_t.
187-
#
188-
# allow sepgsql_client_type sepgsql_regtest_trusted_proc_exec_t:db_procedure { getattr execute };
189-
190-
# These rules intends sepgsql_regtest_user_t domain to translate
191-
# sepgsql_regtest_nosuch_t on execution of procedures labeled as
192-
# sepgsql_nosuch_trusted_proc_exec_t, without permissions to
193-
# translate to sepgsql_nosuch_trusted_proc_exec_t.
194-
#
195-
# allow sepgsql_client_type sepgsql_nosuch_trusted_proc_exec_t:db_procedure { getattr execute install };
184+
allow sepgsql_client_type { sepgsql_regtest_trusted_proc_exec_t sepgsql_nosuch_trusted_proc_exec_t }:db_procedure { getattr execute entrypoint };
196185
')

contrib/sepgsql/sepgsql.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,5 +328,6 @@ extern void sepgsql_proc_post_create(Oid functionId);
328328
extern void sepgsql_proc_drop(Oid functionId);
329329
extern void sepgsql_proc_relabel(Oid functionId, const char *seclabel);
330330
extern void sepgsql_proc_setattr(Oid functionId);
331+
extern void sepgsql_proc_execute(Oid functionId);
331332

332333
#endif /* SEPGSQL_H */

contrib/sepgsql/sql/label.sql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ SECURITY LABEL ON COLUMN t2.b
9797
-- Tests for Trusted Procedures
9898
--
9999
-- @SECURITY-CONTEXT=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0
100+
SET sepgsql.debug_audit = true;
101+
SET client_min_messages = log;
100102
SELECT f1(); -- normal procedure
101103
SELECT f2(); -- trusted procedure
102104
SELECT f3(); -- trusted procedure that raises an error

contrib/sepgsql/sql/misc.sql

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,28 @@
33
--
44

55
LOAD '$libdir/sepgsql'; -- failed
6+
7+
--
8+
-- Permissions to execute functions
9+
--
10+
CREATE TABLE t1 (x int, y text);
11+
INSERT INTO t1 (SELECT x, md5(x::text) FROM generate_series(1,100) x);
12+
13+
SET sepgsql.debug_audit = on;
14+
SET client_min_messages = log;
15+
16+
-- regular function and operators
17+
SELECT * FROM t1 WHERE x > 50 AND y like '%64%';
18+
19+
-- aggregate function
20+
SELECT MIN(x), AVG(x) FROM t1;
21+
22+
-- window function
23+
SELECT row_number() OVER (order by x), * FROM t1 WHERE y like '%86%';
24+
25+
RESET sepgsql.debug_audit;
26+
RESET client_min_messages;
27+
--
28+
-- Cleanup
29+
--
30+
DROP TABLE IF EXISTS t1 CASCADE;

doc/src/sgml/sepgsql.sgml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -393,8 +393,11 @@ UPDATE t1 SET x = 2, y = md5sum(y) WHERE z = 100;
393393
</para>
394394

395395
<para>
396-
For functions, <literal>db_procedure:{execute}</> is defined, but is not
397-
checked in this version.
396+
For functions, <literal>db_procedure:{execute}</> will be checked when
397+
user tries to execute a function as a part of query, or using fast-path
398+
invocation. If this function is a trusted procedure, it also checks
399+
<literal>db_procedure:{entrypoint}</> permission to check whether it
400+
can perform as entrypoint of trusted procedure.
398401
</para>
399402

400403
<para>

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy