aboutsummaryrefslogtreecommitdiffstats
path: root/security/selinux/avc.c
diff options
context:
space:
mode:
authorEric Paris <eparis@redhat.com>2011-04-21 20:23:20 -0400
committerEric Paris <eparis@redhat.com>2011-04-25 16:24:41 -0400
commit0dc1ba24f7fff659725eecbba2c9ad679a0954cd (patch)
treead5831b52b38ca8157dd3ba4e5dfb75768bd372f /security/selinux/avc.c
parent1c9904297451f558191e211a48d8838b4bf792b0 (diff)
SELINUX: Make selinux cache VFS RCU walks safe
Now that the security modules can decide whether they support the dcache RCU walk or not it's possible to make selinux a bit more RCU friendly. The SELinux AVC and security server access decision code is RCU safe. A specific piece of the LSM audit code may not be RCU safe. This patch makes the VFS RCU walk retry if it would hit the non RCU safe chunk of code. It will normally just work under RCU. This is done simply by passing the VFS RCU state as a flag down into the avc_audit() code and returning ECHILD there if it would have an issue. Based-on-patch-by: Andi Kleen <ak@linux.intel.com> Signed-off-by: Eric Paris <eparis@redhat.com>
Diffstat (limited to 'security/selinux/avc.c')
-rw-r--r--security/selinux/avc.c36
1 files changed, 29 insertions, 7 deletions
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index 9da6420e2056..1d027e29ce8d 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -471,6 +471,7 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a)
471 * @avd: access vector decisions 471 * @avd: access vector decisions
472 * @result: result from avc_has_perm_noaudit 472 * @result: result from avc_has_perm_noaudit
473 * @a: auxiliary audit data 473 * @a: auxiliary audit data
474 * @flags: VFS walk flags
474 * 475 *
475 * Audit the granting or denial of permissions in accordance 476 * Audit the granting or denial of permissions in accordance
476 * with the policy. This function is typically called by 477 * with the policy. This function is typically called by
@@ -481,9 +482,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 482 * be performed under a lock, to allow the lock to be released
482 * before calling the auditing code. 483 * before calling the auditing code.
483 */ 484 */
484void avc_audit(u32 ssid, u32 tsid, 485int avc_audit(u32 ssid, u32 tsid,
485 u16 tclass, u32 requested, 486 u16 tclass, u32 requested,
486 struct av_decision *avd, int result, struct common_audit_data *a) 487 struct av_decision *avd, int result, struct common_audit_data *a,
488 unsigned flags)
487{ 489{
488 struct common_audit_data stack_data; 490 struct common_audit_data stack_data;
489 u32 denied, audited; 491 u32 denied, audited;
@@ -515,11 +517,24 @@ void avc_audit(u32 ssid, u32 tsid,
515 else 517 else
516 audited = requested & avd->auditallow; 518 audited = requested & avd->auditallow;
517 if (!audited) 519 if (!audited)
518 return; 520 return 0;
521
519 if (!a) { 522 if (!a) {
520 a = &stack_data; 523 a = &stack_data;
521 COMMON_AUDIT_DATA_INIT(a, NONE); 524 COMMON_AUDIT_DATA_INIT(a, NONE);
522 } 525 }
526
527 /*
528 * When in a RCU walk do the audit on the RCU retry. This is because
529 * the collection of the dname in an inode audit message is not RCU
530 * safe. Note this may drop some audits when the situation changes
531 * during retry. However this is logically just as if the operation
532 * happened a little later.
533 */
534 if ((a->type == LSM_AUDIT_DATA_FS) &&
535 (flags & IPERM_FLAG_RCU))
536 return -ECHILD;
537
523 a->selinux_audit_data.tclass = tclass; 538 a->selinux_audit_data.tclass = tclass;
524 a->selinux_audit_data.requested = requested; 539 a->selinux_audit_data.requested = requested;
525 a->selinux_audit_data.ssid = ssid; 540 a->selinux_audit_data.ssid = ssid;
@@ -529,6 +544,7 @@ void avc_audit(u32 ssid, u32 tsid,
529 a->lsm_pre_audit = avc_audit_pre_callback; 544 a->lsm_pre_audit = avc_audit_pre_callback;
530 a->lsm_post_audit = avc_audit_post_callback; 545 a->lsm_post_audit = avc_audit_post_callback;
531 common_lsm_audit(a); 546 common_lsm_audit(a);
547 return 0;
532} 548}
533 549
534/** 550/**
@@ -793,6 +809,7 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid,
793 * @tclass: target security class 809 * @tclass: target security class
794 * @requested: requested permissions, interpreted based on @tclass 810 * @requested: requested permissions, interpreted based on @tclass
795 * @auditdata: auxiliary audit data 811 * @auditdata: auxiliary audit data
812 * @flags: VFS walk flags
796 * 813 *
797 * Check the AVC to determine whether the @requested permissions are granted 814 * Check the AVC to determine whether the @requested permissions are granted
798 * for the SID pair (@ssid, @tsid), interpreting the permissions 815 * for the SID pair (@ssid, @tsid), interpreting the permissions
@@ -802,14 +819,19 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid,
802 * permissions are granted, -%EACCES if any permissions are denied, or 819 * permissions are granted, -%EACCES if any permissions are denied, or
803 * another -errno upon other errors. 820 * another -errno upon other errors.
804 */ 821 */
805int avc_has_perm(u32 ssid, u32 tsid, u16 tclass, 822int avc_has_perm_flags(u32 ssid, u32 tsid, u16 tclass,
806 u32 requested, struct common_audit_data *auditdata) 823 u32 requested, struct common_audit_data *auditdata,
824 unsigned flags)
807{ 825{
808 struct av_decision avd; 826 struct av_decision avd;
809 int rc; 827 int rc, rc2;
810 828
811 rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, 0, &avd); 829 rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, 0, &avd);
812 avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata); 830
831 rc2 = avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata,
832 flags);
833 if (rc2)
834 return rc2;
813 return rc; 835 return rc;
814} 836}
815 837