diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /security/selinux/avc.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'security/selinux/avc.c')
-rw-r--r-- | security/selinux/avc.c | 63 |
1 files changed, 36 insertions, 27 deletions
diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 9da6420e2056..d515b2128a4e 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c | |||
@@ -38,11 +38,7 @@ | |||
38 | #define AVC_CACHE_RECLAIM 16 | 38 | #define AVC_CACHE_RECLAIM 16 |
39 | 39 | ||
40 | #ifdef CONFIG_SECURITY_SELINUX_AVC_STATS | 40 | #ifdef CONFIG_SECURITY_SELINUX_AVC_STATS |
41 | #define avc_cache_stats_incr(field) \ | 41 | #define avc_cache_stats_incr(field) this_cpu_inc(avc_cache_stats.field) |
42 | do { \ | ||
43 | per_cpu(avc_cache_stats, get_cpu()).field++; \ | ||
44 | put_cpu(); \ | ||
45 | } while (0) | ||
46 | #else | 42 | #else |
47 | #define avc_cache_stats_incr(field) do {} while (0) | 43 | #define avc_cache_stats_incr(field) do {} while (0) |
48 | #endif | 44 | #endif |
@@ -347,11 +343,10 @@ static struct avc_node *avc_lookup(u32 ssid, u32 tsid, u16 tclass) | |||
347 | node = avc_search_node(ssid, tsid, tclass); | 343 | node = avc_search_node(ssid, tsid, tclass); |
348 | 344 | ||
349 | if (node) | 345 | if (node) |
350 | avc_cache_stats_incr(hits); | 346 | return node; |
351 | else | ||
352 | avc_cache_stats_incr(misses); | ||
353 | 347 | ||
354 | return node; | 348 | avc_cache_stats_incr(misses); |
349 | return NULL; | ||
355 | } | 350 | } |
356 | 351 | ||
357 | static int avc_latest_notif_update(int seqno, int is_insert) | 352 | static int avc_latest_notif_update(int seqno, int is_insert) |
@@ -471,6 +466,7 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a) | |||
471 | * @avd: access vector decisions | 466 | * @avd: access vector decisions |
472 | * @result: result from avc_has_perm_noaudit | 467 | * @result: result from avc_has_perm_noaudit |
473 | * @a: auxiliary audit data | 468 | * @a: auxiliary audit data |
469 | * @flags: VFS walk flags | ||
474 | * | 470 | * |
475 | * Audit the granting or denial of permissions in accordance | 471 | * Audit the granting or denial of permissions in accordance |
476 | * with the policy. This function is typically called by | 472 | * with the policy. This function is typically called by |
@@ -481,9 +477,10 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a) | |||
481 | * be performed under a lock, to allow the lock to be released | 477 | * be performed under a lock, to allow the lock to be released |
482 | * before calling the auditing code. | 478 | * before calling the auditing code. |
483 | */ | 479 | */ |
484 | void avc_audit(u32 ssid, u32 tsid, | 480 | int avc_audit(u32 ssid, u32 tsid, |
485 | u16 tclass, u32 requested, | 481 | u16 tclass, u32 requested, |
486 | struct av_decision *avd, int result, struct common_audit_data *a) | 482 | struct av_decision *avd, int result, struct common_audit_data *a, |
483 | unsigned flags) | ||
487 | { | 484 | { |
488 | struct common_audit_data stack_data; | 485 | struct common_audit_data stack_data; |
489 | u32 denied, audited; | 486 | u32 denied, audited; |
@@ -515,11 +512,24 @@ void avc_audit(u32 ssid, u32 tsid, | |||
515 | else | 512 | else |
516 | audited = requested & avd->auditallow; | 513 | audited = requested & avd->auditallow; |
517 | if (!audited) | 514 | if (!audited) |
518 | return; | 515 | return 0; |
516 | |||
519 | if (!a) { | 517 | if (!a) { |
520 | a = &stack_data; | 518 | a = &stack_data; |
521 | COMMON_AUDIT_DATA_INIT(a, NONE); | 519 | COMMON_AUDIT_DATA_INIT(a, NONE); |
522 | } | 520 | } |
521 | |||
522 | /* | ||
523 | * When in a RCU walk do the audit on the RCU retry. This is because | ||
524 | * the collection of the dname in an inode audit message is not RCU | ||
525 | * safe. Note this may drop some audits when the situation changes | ||
526 | * during retry. However this is logically just as if the operation | ||
527 | * happened a little later. | ||
528 | */ | ||
529 | if ((a->type == LSM_AUDIT_DATA_INODE) && | ||
530 | (flags & IPERM_FLAG_RCU)) | ||
531 | return -ECHILD; | ||
532 | |||
523 | a->selinux_audit_data.tclass = tclass; | 533 | a->selinux_audit_data.tclass = tclass; |
524 | a->selinux_audit_data.requested = requested; | 534 | a->selinux_audit_data.requested = requested; |
525 | a->selinux_audit_data.ssid = ssid; | 535 | a->selinux_audit_data.ssid = ssid; |
@@ -529,6 +539,7 @@ void avc_audit(u32 ssid, u32 tsid, | |||
529 | a->lsm_pre_audit = avc_audit_pre_callback; | 539 | a->lsm_pre_audit = avc_audit_pre_callback; |
530 | a->lsm_post_audit = avc_audit_post_callback; | 540 | a->lsm_post_audit = avc_audit_post_callback; |
531 | common_lsm_audit(a); | 541 | common_lsm_audit(a); |
542 | return 0; | ||
532 | } | 543 | } |
533 | 544 | ||
534 | /** | 545 | /** |
@@ -741,10 +752,9 @@ int avc_ss_reset(u32 seqno) | |||
741 | int avc_has_perm_noaudit(u32 ssid, u32 tsid, | 752 | int avc_has_perm_noaudit(u32 ssid, u32 tsid, |
742 | u16 tclass, u32 requested, | 753 | u16 tclass, u32 requested, |
743 | unsigned flags, | 754 | unsigned flags, |
744 | struct av_decision *in_avd) | 755 | struct av_decision *avd) |
745 | { | 756 | { |
746 | struct avc_node *node; | 757 | struct avc_node *node; |
747 | struct av_decision avd_entry, *avd; | ||
748 | int rc = 0; | 758 | int rc = 0; |
749 | u32 denied; | 759 | u32 denied; |
750 | 760 | ||
@@ -753,20 +763,13 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid, | |||
753 | rcu_read_lock(); | 763 | rcu_read_lock(); |
754 | 764 | ||
755 | node = avc_lookup(ssid, tsid, tclass); | 765 | node = avc_lookup(ssid, tsid, tclass); |
756 | if (!node) { | 766 | if (unlikely(!node)) { |
757 | rcu_read_unlock(); | 767 | rcu_read_unlock(); |
758 | |||
759 | if (in_avd) | ||
760 | avd = in_avd; | ||
761 | else | ||
762 | avd = &avd_entry; | ||
763 | |||
764 | security_compute_av(ssid, tsid, tclass, avd); | 768 | security_compute_av(ssid, tsid, tclass, avd); |
765 | rcu_read_lock(); | 769 | rcu_read_lock(); |
766 | node = avc_insert(ssid, tsid, tclass, avd); | 770 | node = avc_insert(ssid, tsid, tclass, avd); |
767 | } else { | 771 | } else { |
768 | if (in_avd) | 772 | memcpy(avd, &node->ae.avd, sizeof(*avd)); |
769 | memcpy(in_avd, &node->ae.avd, sizeof(*in_avd)); | ||
770 | avd = &node->ae.avd; | 773 | avd = &node->ae.avd; |
771 | } | 774 | } |
772 | 775 | ||
@@ -793,6 +796,7 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid, | |||
793 | * @tclass: target security class | 796 | * @tclass: target security class |
794 | * @requested: requested permissions, interpreted based on @tclass | 797 | * @requested: requested permissions, interpreted based on @tclass |
795 | * @auditdata: auxiliary audit data | 798 | * @auditdata: auxiliary audit data |
799 | * @flags: VFS walk flags | ||
796 | * | 800 | * |
797 | * Check the AVC to determine whether the @requested permissions are granted | 801 | * Check the AVC to determine whether the @requested permissions are granted |
798 | * for the SID pair (@ssid, @tsid), interpreting the permissions | 802 | * for the SID pair (@ssid, @tsid), interpreting the permissions |
@@ -802,14 +806,19 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid, | |||
802 | * permissions are granted, -%EACCES if any permissions are denied, or | 806 | * permissions are granted, -%EACCES if any permissions are denied, or |
803 | * another -errno upon other errors. | 807 | * another -errno upon other errors. |
804 | */ | 808 | */ |
805 | int avc_has_perm(u32 ssid, u32 tsid, u16 tclass, | 809 | int avc_has_perm_flags(u32 ssid, u32 tsid, u16 tclass, |
806 | u32 requested, struct common_audit_data *auditdata) | 810 | u32 requested, struct common_audit_data *auditdata, |
811 | unsigned flags) | ||
807 | { | 812 | { |
808 | struct av_decision avd; | 813 | struct av_decision avd; |
809 | int rc; | 814 | int rc, rc2; |
810 | 815 | ||
811 | rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, 0, &avd); | 816 | rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, 0, &avd); |
812 | avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata); | 817 | |
818 | rc2 = avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata, | ||
819 | flags); | ||
820 | if (rc2) | ||
821 | return rc2; | ||
813 | return rc; | 822 | return rc; |
814 | } | 823 | } |
815 | 824 | ||