diff options
author | KaiGai Kohei <kaigai@ak.jp.nec.com> | 2009-06-18 04:26:13 -0400 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2009-06-18 10:12:28 -0400 |
commit | 44c2d9bdd7022ca7d240d5adc009296fc1c6ce08 (patch) | |
tree | 33115ee8d7e167d2a26558c2af8e0edfdca099d5 | |
parent | caabbdc07df4249f2ed516b2c3e2d6b0973bcbb3 (diff) |
Add audit messages on type boundary violations
The attached patch adds support to generate audit messages on two cases.
The first one is a case when a multi-thread process tries to switch its
performing security context using setcon(3), but new security context is
not bounded by the old one.
type=SELINUX_ERR msg=audit(1245311998.599:17): \
op=security_bounded_transition result=denied \
oldcontext=system_u:system_r:httpd_t:s0 \
newcontext=system_u:system_r:guest_webapp_t:s0
The other one is a case when security_compute_av() masked any permissions
due to the type boundary violation.
type=SELINUX_ERR msg=audit(1245312836.035:32): \
op=security_compute_av reason=bounds \
scontext=system_u:object_r:user_webapp_t:s0 \
tcontext=system_u:object_r:shadow_t:s0:c0 \
tclass=file perms=getattr,open
Signed-off-by: KaiGai Kohei <kaigai@ak.jp.nec.com>
Acked-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
-rw-r--r-- | security/selinux/avc.c | 2 | ||||
-rw-r--r-- | security/selinux/include/avc.h | 3 | ||||
-rw-r--r-- | security/selinux/ss/services.c | 136 |
3 files changed, 118 insertions, 23 deletions
diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 7f9b5fac8779..4bf5d08a1f5c 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c | |||
@@ -137,7 +137,7 @@ static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass) | |||
137 | * @tclass: target security class | 137 | * @tclass: target security class |
138 | * @av: access vector | 138 | * @av: access vector |
139 | */ | 139 | */ |
140 | void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av) | 140 | static void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av) |
141 | { | 141 | { |
142 | const char **common_pts = NULL; | 142 | const char **common_pts = NULL; |
143 | u32 common_base = 0; | 143 | u32 common_base = 0; |
diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h index d12ff1a9c0aa..46a940d9af67 100644 --- a/security/selinux/include/avc.h +++ b/security/selinux/include/avc.h | |||
@@ -127,9 +127,6 @@ int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid, | |||
127 | u32 events, u32 ssid, u32 tsid, | 127 | u32 events, u32 ssid, u32 tsid, |
128 | u16 tclass, u32 perms); | 128 | u16 tclass, u32 perms); |
129 | 129 | ||
130 | /* Shows permission in human readable form */ | ||
131 | void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av); | ||
132 | |||
133 | /* Exported to selinuxfs */ | 130 | /* Exported to selinuxfs */ |
134 | int avc_get_hash_stats(char *page); | 131 | int avc_get_hash_stats(char *page); |
135 | extern unsigned int avc_cache_threshold; | 132 | extern unsigned int avc_cache_threshold; |
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index cad5765ca1cb..a90cab207d9a 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
@@ -22,6 +22,11 @@ | |||
22 | * | 22 | * |
23 | * Added validation of kernel classes and permissions | 23 | * Added validation of kernel classes and permissions |
24 | * | 24 | * |
25 | * Updated: KaiGai Kohei <kaigai@ak.jp.nec.com> | ||
26 | * | ||
27 | * Added support for bounds domain and audit messaged on masked permissions | ||
28 | * | ||
29 | * Copyright (C) 2008, 2009 NEC Corporation | ||
25 | * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P. | 30 | * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P. |
26 | * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. | 31 | * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. |
27 | * Copyright (C) 2003 - 2004, 2006 Tresys Technology, LLC | 32 | * Copyright (C) 2003 - 2004, 2006 Tresys Technology, LLC |
@@ -279,6 +284,95 @@ mls_ops: | |||
279 | } | 284 | } |
280 | 285 | ||
281 | /* | 286 | /* |
287 | * security_dump_masked_av - dumps masked permissions during | ||
288 | * security_compute_av due to RBAC, MLS/Constraint and Type bounds. | ||
289 | */ | ||
290 | static int dump_masked_av_helper(void *k, void *d, void *args) | ||
291 | { | ||
292 | struct perm_datum *pdatum = d; | ||
293 | char **permission_names = args; | ||
294 | |||
295 | BUG_ON(pdatum->value < 1 || pdatum->value > 32); | ||
296 | |||
297 | permission_names[pdatum->value - 1] = (char *)k; | ||
298 | |||
299 | return 0; | ||
300 | } | ||
301 | |||
302 | static void security_dump_masked_av(struct context *scontext, | ||
303 | struct context *tcontext, | ||
304 | u16 tclass, | ||
305 | u32 permissions, | ||
306 | const char *reason) | ||
307 | { | ||
308 | struct common_datum *common_dat; | ||
309 | struct class_datum *tclass_dat; | ||
310 | struct audit_buffer *ab; | ||
311 | char *tclass_name; | ||
312 | char *scontext_name = NULL; | ||
313 | char *tcontext_name = NULL; | ||
314 | char *permission_names[32]; | ||
315 | int index, length; | ||
316 | bool need_comma = false; | ||
317 | |||
318 | if (!permissions) | ||
319 | return; | ||
320 | |||
321 | tclass_name = policydb.p_class_val_to_name[tclass - 1]; | ||
322 | tclass_dat = policydb.class_val_to_struct[tclass - 1]; | ||
323 | common_dat = tclass_dat->comdatum; | ||
324 | |||
325 | /* init permission_names */ | ||
326 | if (common_dat && | ||
327 | hashtab_map(common_dat->permissions.table, | ||
328 | dump_masked_av_helper, permission_names) < 0) | ||
329 | goto out; | ||
330 | |||
331 | if (hashtab_map(tclass_dat->permissions.table, | ||
332 | dump_masked_av_helper, permission_names) < 0) | ||
333 | goto out; | ||
334 | |||
335 | /* get scontext/tcontext in text form */ | ||
336 | if (context_struct_to_string(scontext, | ||
337 | &scontext_name, &length) < 0) | ||
338 | goto out; | ||
339 | |||
340 | if (context_struct_to_string(tcontext, | ||
341 | &tcontext_name, &length) < 0) | ||
342 | goto out; | ||
343 | |||
344 | /* audit a message */ | ||
345 | ab = audit_log_start(current->audit_context, | ||
346 | GFP_ATOMIC, AUDIT_SELINUX_ERR); | ||
347 | if (!ab) | ||
348 | goto out; | ||
349 | |||
350 | audit_log_format(ab, "op=security_compute_av reason=%s " | ||
351 | "scontext=%s tcontext=%s tclass=%s perms=", | ||
352 | reason, scontext_name, tcontext_name, tclass_name); | ||
353 | |||
354 | for (index = 0; index < 32; index++) { | ||
355 | u32 mask = (1 << index); | ||
356 | |||
357 | if ((mask & permissions) == 0) | ||
358 | continue; | ||
359 | |||
360 | audit_log_format(ab, "%s%s", | ||
361 | need_comma ? "," : "", | ||
362 | permission_names[index] | ||
363 | ? permission_names[index] : "????"); | ||
364 | need_comma = true; | ||
365 | } | ||
366 | audit_log_end(ab); | ||
367 | out: | ||
368 | /* release scontext/tcontext */ | ||
369 | kfree(tcontext_name); | ||
370 | kfree(scontext_name); | ||
371 | |||
372 | return; | ||
373 | } | ||
374 | |||
375 | /* | ||
282 | * security_boundary_permission - drops violated permissions | 376 | * security_boundary_permission - drops violated permissions |
283 | * on boundary constraint. | 377 | * on boundary constraint. |
284 | */ | 378 | */ |
@@ -347,28 +441,12 @@ static void type_attribute_bounds_av(struct context *scontext, | |||
347 | } | 441 | } |
348 | 442 | ||
349 | if (masked) { | 443 | if (masked) { |
350 | struct audit_buffer *ab; | ||
351 | char *stype_name | ||
352 | = policydb.p_type_val_to_name[source->value - 1]; | ||
353 | char *ttype_name | ||
354 | = policydb.p_type_val_to_name[target->value - 1]; | ||
355 | char *tclass_name | ||
356 | = policydb.p_class_val_to_name[tclass - 1]; | ||
357 | |||
358 | /* mask violated permissions */ | 444 | /* mask violated permissions */ |
359 | avd->allowed &= ~masked; | 445 | avd->allowed &= ~masked; |
360 | 446 | ||
361 | /* notice to userspace via audit message */ | 447 | /* audit masked permissions */ |
362 | ab = audit_log_start(current->audit_context, | 448 | security_dump_masked_av(scontext, tcontext, |
363 | GFP_ATOMIC, AUDIT_SELINUX_ERR); | 449 | tclass, masked, "bounds"); |
364 | if (!ab) | ||
365 | return; | ||
366 | |||
367 | audit_log_format(ab, "av boundary violation: " | ||
368 | "source=%s target=%s tclass=%s", | ||
369 | stype_name, ttype_name, tclass_name); | ||
370 | avc_dump_av(ab, tclass, masked); | ||
371 | audit_log_end(ab); | ||
372 | } | 450 | } |
373 | } | 451 | } |
374 | 452 | ||
@@ -711,6 +789,26 @@ int security_bounded_transition(u32 old_sid, u32 new_sid) | |||
711 | } | 789 | } |
712 | index = type->bounds; | 790 | index = type->bounds; |
713 | } | 791 | } |
792 | |||
793 | if (rc) { | ||
794 | char *old_name = NULL; | ||
795 | char *new_name = NULL; | ||
796 | int length; | ||
797 | |||
798 | if (!context_struct_to_string(old_context, | ||
799 | &old_name, &length) && | ||
800 | !context_struct_to_string(new_context, | ||
801 | &new_name, &length)) { | ||
802 | audit_log(current->audit_context, | ||
803 | GFP_ATOMIC, AUDIT_SELINUX_ERR, | ||
804 | "op=security_bounded_transition " | ||
805 | "result=denied " | ||
806 | "oldcontext=%s newcontext=%s", | ||
807 | old_name, new_name); | ||
808 | } | ||
809 | kfree(new_name); | ||
810 | kfree(old_name); | ||
811 | } | ||
714 | out: | 812 | out: |
715 | read_unlock(&policy_rwlock); | 813 | read_unlock(&policy_rwlock); |
716 | 814 | ||