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 /security | |
| 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>
Diffstat (limited to 'security')
| -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 | ||
