aboutsummaryrefslogtreecommitdiffstats
path: root/security/selinux/avc.c
diff options
context:
space:
mode:
authorGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
committerGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
commitc71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch)
treeecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /security/selinux/avc.c
parentea53c912f8a86a8567697115b6a0d8152beee5c8 (diff)
parent6a00f206debf8a5c8899055726ad127dbeeed098 (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.c63
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)
42do { \
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
357static int avc_latest_notif_update(int seqno, int is_insert) 352static 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 */
484void avc_audit(u32 ssid, u32 tsid, 480int 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)
741int avc_has_perm_noaudit(u32 ssid, u32 tsid, 752int 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 */
805int avc_has_perm(u32 ssid, u32 tsid, u16 tclass, 809int 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