Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

selinux: don't inline slow-path code into avc_has_perm_noaudit()

The selinux AVC paths remain some of the hottest (and deepest) codepaths
at filename lookup time, and we make it worse by having the slow path
cases take up I$ and stack space even when they don't trigger. Gcc
tends to always want to inline functions that are just called once -
never mind that this might make for slower and worse code in the caller.

So this tries to improve on it a bit by making the slow-path cases
explicitly separate functions that are marked noinline, causing gcc to
at least no longer allocate stack space for them unless they are
actually called. It also seems to help register allocation a tiny bit,
since gcc now doesn't take the slow case code into account.

Uninlining the slow path may also allow us to inline the remaining hot
path into the one caller that actually matters: avc_has_perm_flags().
I'll have to look at that separately, but both avc_audit() and
avc_has_perm_noaudit() are now small and lean enough that inlining them
may make sense.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

+38 -14
+38 -14
security/selinux/avc.c
··· 741 741 return rc; 742 742 } 743 743 744 + /* 745 + * Slow-path helper function for avc_has_perm_noaudit, 746 + * when the avc_node lookup fails. We get called with 747 + * the RCU read lock held, and need to return with it 748 + * still held, but drop if for the security compute. 749 + * 750 + * Don't inline this, since it's the slow-path and just 751 + * results in a bigger stack frame. 752 + */ 753 + static noinline struct avc_node *avc_compute_av(u32 ssid, u32 tsid, 754 + u16 tclass, struct av_decision *avd) 755 + { 756 + rcu_read_unlock(); 757 + security_compute_av(ssid, tsid, tclass, avd); 758 + rcu_read_lock(); 759 + return avc_insert(ssid, tsid, tclass, avd); 760 + } 761 + 762 + static noinline int avc_denied(u32 ssid, u32 tsid, 763 + u16 tclass, u32 requested, 764 + unsigned flags, 765 + struct av_decision *avd) 766 + { 767 + if (flags & AVC_STRICT) 768 + return -EACCES; 769 + 770 + if (selinux_enforcing && !(avd->flags & AVD_FLAGS_PERMISSIVE)) 771 + return -EACCES; 772 + 773 + avc_update_node(AVC_CALLBACK_GRANT, requested, ssid, 774 + tsid, tclass, avd->seqno); 775 + return 0; 776 + } 777 + 778 + 744 779 /** 745 780 * avc_has_perm_noaudit - Check permissions but perform no auditing. 746 781 * @ssid: source security identifier ··· 811 776 812 777 node = avc_lookup(ssid, tsid, tclass); 813 778 if (unlikely(!node)) { 814 - rcu_read_unlock(); 815 - security_compute_av(ssid, tsid, tclass, avd); 816 - rcu_read_lock(); 817 - node = avc_insert(ssid, tsid, tclass, avd); 779 + node = avc_compute_av(ssid, tsid, tclass, avd); 818 780 } else { 819 781 memcpy(avd, &node->ae.avd, sizeof(*avd)); 820 782 avd = &node->ae.avd; 821 783 } 822 784 823 785 denied = requested & ~(avd->allowed); 824 - 825 - if (denied) { 826 - if (flags & AVC_STRICT) 827 - rc = -EACCES; 828 - else if (!selinux_enforcing || (avd->flags & AVD_FLAGS_PERMISSIVE)) 829 - avc_update_node(AVC_CALLBACK_GRANT, requested, ssid, 830 - tsid, tclass, avd->seqno); 831 - else 832 - rc = -EACCES; 833 - } 786 + if (unlikely(denied)) 787 + rc = avc_denied(ssid, tsid, tclass, requested, flags, avd); 834 788 835 789 rcu_read_unlock(); 836 790 return rc;