diff options
Diffstat (limited to 'security/selinux/avc.c')
-rw-r--r-- | security/selinux/avc.c | 130 |
1 files changed, 24 insertions, 106 deletions
diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 8ee42b2a5f19..68d82daed257 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c | |||
@@ -65,14 +65,8 @@ struct avc_cache { | |||
65 | }; | 65 | }; |
66 | 66 | ||
67 | struct avc_callback_node { | 67 | struct avc_callback_node { |
68 | int (*callback) (u32 event, u32 ssid, u32 tsid, | 68 | int (*callback) (u32 event); |
69 | u16 tclass, u32 perms, | ||
70 | u32 *out_retained); | ||
71 | u32 events; | 69 | u32 events; |
72 | u32 ssid; | ||
73 | u32 tsid; | ||
74 | u16 tclass; | ||
75 | u32 perms; | ||
76 | struct avc_callback_node *next; | 70 | struct avc_callback_node *next; |
77 | }; | 71 | }; |
78 | 72 | ||
@@ -436,9 +430,9 @@ static void avc_audit_pre_callback(struct audit_buffer *ab, void *a) | |||
436 | { | 430 | { |
437 | struct common_audit_data *ad = a; | 431 | struct common_audit_data *ad = a; |
438 | audit_log_format(ab, "avc: %s ", | 432 | audit_log_format(ab, "avc: %s ", |
439 | ad->selinux_audit_data->slad->denied ? "denied" : "granted"); | 433 | ad->selinux_audit_data->denied ? "denied" : "granted"); |
440 | avc_dump_av(ab, ad->selinux_audit_data->slad->tclass, | 434 | avc_dump_av(ab, ad->selinux_audit_data->tclass, |
441 | ad->selinux_audit_data->slad->audited); | 435 | ad->selinux_audit_data->audited); |
442 | audit_log_format(ab, " for "); | 436 | audit_log_format(ab, " for "); |
443 | } | 437 | } |
444 | 438 | ||
@@ -452,25 +446,23 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a) | |||
452 | { | 446 | { |
453 | struct common_audit_data *ad = a; | 447 | struct common_audit_data *ad = a; |
454 | audit_log_format(ab, " "); | 448 | audit_log_format(ab, " "); |
455 | avc_dump_query(ab, ad->selinux_audit_data->slad->ssid, | 449 | avc_dump_query(ab, ad->selinux_audit_data->ssid, |
456 | ad->selinux_audit_data->slad->tsid, | 450 | ad->selinux_audit_data->tsid, |
457 | ad->selinux_audit_data->slad->tclass); | 451 | ad->selinux_audit_data->tclass); |
458 | } | 452 | } |
459 | 453 | ||
460 | /* This is the slow part of avc audit with big stack footprint */ | 454 | /* This is the slow part of avc audit with big stack footprint */ |
461 | static noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass, | 455 | noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass, |
462 | u32 requested, u32 audited, u32 denied, | 456 | u32 requested, u32 audited, u32 denied, |
463 | struct common_audit_data *a, | 457 | struct common_audit_data *a, |
464 | unsigned flags) | 458 | unsigned flags) |
465 | { | 459 | { |
466 | struct common_audit_data stack_data; | 460 | struct common_audit_data stack_data; |
467 | struct selinux_audit_data sad = {0,}; | 461 | struct selinux_audit_data sad; |
468 | struct selinux_late_audit_data slad; | ||
469 | 462 | ||
470 | if (!a) { | 463 | if (!a) { |
471 | a = &stack_data; | 464 | a = &stack_data; |
472 | COMMON_AUDIT_DATA_INIT(a, NONE); | 465 | a->type = LSM_AUDIT_DATA_NONE; |
473 | a->selinux_audit_data = &sad; | ||
474 | } | 466 | } |
475 | 467 | ||
476 | /* | 468 | /* |
@@ -484,104 +476,34 @@ static noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass, | |||
484 | (flags & MAY_NOT_BLOCK)) | 476 | (flags & MAY_NOT_BLOCK)) |
485 | return -ECHILD; | 477 | return -ECHILD; |
486 | 478 | ||
487 | slad.tclass = tclass; | 479 | sad.tclass = tclass; |
488 | slad.requested = requested; | 480 | sad.requested = requested; |
489 | slad.ssid = ssid; | 481 | sad.ssid = ssid; |
490 | slad.tsid = tsid; | 482 | sad.tsid = tsid; |
491 | slad.audited = audited; | 483 | sad.audited = audited; |
492 | slad.denied = denied; | 484 | sad.denied = denied; |
485 | |||
486 | a->selinux_audit_data = &sad; | ||
493 | 487 | ||
494 | a->selinux_audit_data->slad = &slad; | ||
495 | common_lsm_audit(a, avc_audit_pre_callback, avc_audit_post_callback); | 488 | common_lsm_audit(a, avc_audit_pre_callback, avc_audit_post_callback); |
496 | return 0; | 489 | return 0; |
497 | } | 490 | } |
498 | 491 | ||
499 | /** | 492 | /** |
500 | * avc_audit - Audit the granting or denial of permissions. | ||
501 | * @ssid: source security identifier | ||
502 | * @tsid: target security identifier | ||
503 | * @tclass: target security class | ||
504 | * @requested: requested permissions | ||
505 | * @avd: access vector decisions | ||
506 | * @result: result from avc_has_perm_noaudit | ||
507 | * @a: auxiliary audit data | ||
508 | * @flags: VFS walk flags | ||
509 | * | ||
510 | * Audit the granting or denial of permissions in accordance | ||
511 | * with the policy. This function is typically called by | ||
512 | * avc_has_perm() after a permission check, but can also be | ||
513 | * called directly by callers who use avc_has_perm_noaudit() | ||
514 | * in order to separate the permission check from the auditing. | ||
515 | * For example, this separation is useful when the permission check must | ||
516 | * be performed under a lock, to allow the lock to be released | ||
517 | * before calling the auditing code. | ||
518 | */ | ||
519 | inline int avc_audit(u32 ssid, u32 tsid, | ||
520 | u16 tclass, u32 requested, | ||
521 | struct av_decision *avd, int result, struct common_audit_data *a, | ||
522 | unsigned flags) | ||
523 | { | ||
524 | u32 denied, audited; | ||
525 | denied = requested & ~avd->allowed; | ||
526 | if (unlikely(denied)) { | ||
527 | audited = denied & avd->auditdeny; | ||
528 | /* | ||
529 | * a->selinux_audit_data->auditdeny is TRICKY! Setting a bit in | ||
530 | * this field means that ANY denials should NOT be audited if | ||
531 | * the policy contains an explicit dontaudit rule for that | ||
532 | * permission. Take notice that this is unrelated to the | ||
533 | * actual permissions that were denied. As an example lets | ||
534 | * assume: | ||
535 | * | ||
536 | * denied == READ | ||
537 | * avd.auditdeny & ACCESS == 0 (not set means explicit rule) | ||
538 | * selinux_audit_data->auditdeny & ACCESS == 1 | ||
539 | * | ||
540 | * We will NOT audit the denial even though the denied | ||
541 | * permission was READ and the auditdeny checks were for | ||
542 | * ACCESS | ||
543 | */ | ||
544 | if (a && | ||
545 | a->selinux_audit_data->auditdeny && | ||
546 | !(a->selinux_audit_data->auditdeny & avd->auditdeny)) | ||
547 | audited = 0; | ||
548 | } else if (result) | ||
549 | audited = denied = requested; | ||
550 | else | ||
551 | audited = requested & avd->auditallow; | ||
552 | if (likely(!audited)) | ||
553 | return 0; | ||
554 | |||
555 | return slow_avc_audit(ssid, tsid, tclass, | ||
556 | requested, audited, denied, | ||
557 | a, flags); | ||
558 | } | ||
559 | |||
560 | /** | ||
561 | * avc_add_callback - Register a callback for security events. | 493 | * avc_add_callback - Register a callback for security events. |
562 | * @callback: callback function | 494 | * @callback: callback function |
563 | * @events: security events | 495 | * @events: security events |
564 | * @ssid: source security identifier or %SECSID_WILD | ||
565 | * @tsid: target security identifier or %SECSID_WILD | ||
566 | * @tclass: target security class | ||
567 | * @perms: permissions | ||
568 | * | 496 | * |
569 | * Register a callback function for events in the set @events | 497 | * Register a callback function for events in the set @events. |
570 | * related to the SID pair (@ssid, @tsid) | 498 | * Returns %0 on success or -%ENOMEM if insufficient memory |
571 | * and the permissions @perms, interpreting | 499 | * exists to add the callback. |
572 | * @perms based on @tclass. Returns %0 on success or | ||
573 | * -%ENOMEM if insufficient memory exists to add the callback. | ||
574 | */ | 500 | */ |
575 | int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid, | 501 | int __init avc_add_callback(int (*callback)(u32 event), u32 events) |
576 | u16 tclass, u32 perms, | ||
577 | u32 *out_retained), | ||
578 | u32 events, u32 ssid, u32 tsid, | ||
579 | u16 tclass, u32 perms) | ||
580 | { | 502 | { |
581 | struct avc_callback_node *c; | 503 | struct avc_callback_node *c; |
582 | int rc = 0; | 504 | int rc = 0; |
583 | 505 | ||
584 | c = kmalloc(sizeof(*c), GFP_ATOMIC); | 506 | c = kmalloc(sizeof(*c), GFP_KERNEL); |
585 | if (!c) { | 507 | if (!c) { |
586 | rc = -ENOMEM; | 508 | rc = -ENOMEM; |
587 | goto out; | 509 | goto out; |
@@ -589,9 +511,6 @@ int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid, | |||
589 | 511 | ||
590 | c->callback = callback; | 512 | c->callback = callback; |
591 | c->events = events; | 513 | c->events = events; |
592 | c->ssid = ssid; | ||
593 | c->tsid = tsid; | ||
594 | c->perms = perms; | ||
595 | c->next = avc_callbacks; | 514 | c->next = avc_callbacks; |
596 | avc_callbacks = c; | 515 | avc_callbacks = c; |
597 | out: | 516 | out: |
@@ -731,8 +650,7 @@ int avc_ss_reset(u32 seqno) | |||
731 | 650 | ||
732 | for (c = avc_callbacks; c; c = c->next) { | 651 | for (c = avc_callbacks; c; c = c->next) { |
733 | if (c->events & AVC_CALLBACK_RESET) { | 652 | if (c->events & AVC_CALLBACK_RESET) { |
734 | tmprc = c->callback(AVC_CALLBACK_RESET, | 653 | tmprc = c->callback(AVC_CALLBACK_RESET); |
735 | 0, 0, 0, 0, NULL); | ||
736 | /* save the first error encountered for the return | 654 | /* save the first error encountered for the return |
737 | value and continue processing the callbacks */ | 655 | value and continue processing the callbacks */ |
738 | if (!rc) | 656 | if (!rc) |