aboutsummaryrefslogtreecommitdiffstats
path: root/security/smack/smack_lsm.c
diff options
context:
space:
mode:
authorCasey Schaufler <casey@schaufler-ca.com>2011-09-20 15:24:36 -0400
committerCasey Schaufler <cschaufler@cschaufler-intel.(none)>2011-10-12 17:23:13 -0400
commit272cd7a8c67dd40a31ecff76a503bbb84707f757 (patch)
tree467f83c94eb14f8f34508efe891c0dcc62a7ac24 /security/smack/smack_lsm.c
parent828716c28fe4aa232ea280ea8ed6fb103eefb6ac (diff)
Smack: Rule list lookup performance
This patch is targeted for the smack-next tree. Smack access checks suffer from two significant performance issues. In cases where there are large numbers of rules the search of the single list of rules is wasteful. Comparing the string values of the smack labels is less efficient than a numeric comparison would. These changes take advantage of the Smack label list, which maintains the mapping of Smack labels to secids and optional CIPSO labels. Because the labels are kept perpetually, an access check can be done strictly based on the address of the label in the list without ever looking at the label itself. Rather than keeping one global list of rules the rules with a particular subject label can be based off of that label list entry. The access check need never look at entries that do not use the current subject label. This requires that packets coming off the network with CIPSO direct Smack labels that have never been seen before be treated carefully. The only case where they could be delivered is where the receiving socket has an IPIN star label, so that case is explicitly addressed. On a system with 39,800 rules (200 labels in all permutations) a system with this patch runs an access speed test in 5% of the time of the old version. That should be a best case improvement. If all of the rules are associated with the same subject label and all of the accesses are for processes with that label (unlikely) the improvement is about 30%. Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
Diffstat (limited to 'security/smack/smack_lsm.c')
-rw-r--r--security/smack/smack_lsm.c126
1 files changed, 77 insertions, 49 deletions
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index b9c5e149903b..fb915163f967 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -516,6 +516,8 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
516 const struct qstr *qstr, char **name, 516 const struct qstr *qstr, char **name,
517 void **value, size_t *len) 517 void **value, size_t *len)
518{ 518{
519 struct smack_known *skp;
520 char *csp = smk_of_current();
519 char *isp = smk_of_inode(inode); 521 char *isp = smk_of_inode(inode);
520 char *dsp = smk_of_inode(dir); 522 char *dsp = smk_of_inode(dir);
521 int may; 523 int may;
@@ -527,8 +529,9 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
527 } 529 }
528 530
529 if (value) { 531 if (value) {
532 skp = smk_find_entry(csp);
530 rcu_read_lock(); 533 rcu_read_lock();
531 may = smk_access_entry(smk_of_current(), dsp, &smack_rule_list); 534 may = smk_access_entry(csp, dsp, &skp->smk_rules);
532 rcu_read_unlock(); 535 rcu_read_unlock();
533 536
534 /* 537 /*
@@ -1138,6 +1141,7 @@ static int smack_file_mmap(struct file *file,
1138 unsigned long flags, unsigned long addr, 1141 unsigned long flags, unsigned long addr,
1139 unsigned long addr_only) 1142 unsigned long addr_only)
1140{ 1143{
1144 struct smack_known *skp;
1141 struct smack_rule *srp; 1145 struct smack_rule *srp;
1142 struct task_smack *tsp; 1146 struct task_smack *tsp;
1143 char *sp; 1147 char *sp;
@@ -1170,6 +1174,7 @@ static int smack_file_mmap(struct file *file,
1170 1174
1171 tsp = current_security(); 1175 tsp = current_security();
1172 sp = smk_of_current(); 1176 sp = smk_of_current();
1177 skp = smk_find_entry(sp);
1173 rc = 0; 1178 rc = 0;
1174 1179
1175 rcu_read_lock(); 1180 rcu_read_lock();
@@ -1177,15 +1182,8 @@ static int smack_file_mmap(struct file *file,
1177 * For each Smack rule associated with the subject 1182 * For each Smack rule associated with the subject
1178 * label verify that the SMACK64MMAP also has access 1183 * label verify that the SMACK64MMAP also has access
1179 * to that rule's object label. 1184 * to that rule's object label.
1180 *
1181 * Because neither of the labels comes
1182 * from the networking code it is sufficient
1183 * to compare pointers.
1184 */ 1185 */
1185 list_for_each_entry_rcu(srp, &smack_rule_list, list) { 1186 list_for_each_entry_rcu(srp, &skp->smk_rules, list) {
1186 if (srp->smk_subject != sp)
1187 continue;
1188
1189 osmack = srp->smk_object; 1187 osmack = srp->smk_object;
1190 /* 1188 /*
1191 * Matching labels always allows access. 1189 * Matching labels always allows access.
@@ -1214,7 +1212,8 @@ static int smack_file_mmap(struct file *file,
1214 * If there isn't one a SMACK64MMAP subject 1212 * If there isn't one a SMACK64MMAP subject
1215 * can't have as much access as current. 1213 * can't have as much access as current.
1216 */ 1214 */
1217 mmay = smk_access_entry(msmack, osmack, &smack_rule_list); 1215 skp = smk_find_entry(msmack);
1216 mmay = smk_access_entry(msmack, osmack, &skp->smk_rules);
1218 if (mmay == -ENOENT) { 1217 if (mmay == -ENOENT) {
1219 rc = -EACCES; 1218 rc = -EACCES;
1220 break; 1219 break;
@@ -1711,7 +1710,7 @@ static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags)
1711 1710
1712 ssp->smk_in = csp; 1711 ssp->smk_in = csp;
1713 ssp->smk_out = csp; 1712 ssp->smk_out = csp;
1714 ssp->smk_packet[0] = '\0'; 1713 ssp->smk_packet = NULL;
1715 1714
1716 sk->sk_security = ssp; 1715 sk->sk_security = ssp;
1717 1716
@@ -2813,16 +2812,17 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
2813 return smack_netlabel_send(sock->sk, sip); 2812 return smack_netlabel_send(sock->sk, sip);
2814} 2813}
2815 2814
2816
2817/** 2815/**
2818 * smack_from_secattr - Convert a netlabel attr.mls.lvl/attr.mls.cat pair to smack 2816 * smack_from_secattr - Convert a netlabel attr.mls.lvl/attr.mls.cat pair to smack
2819 * @sap: netlabel secattr 2817 * @sap: netlabel secattr
2820 * @sip: where to put the result 2818 * @ssp: socket security information
2821 * 2819 *
2822 * Copies a smack label into sip 2820 * Returns a pointer to a Smack label found on the label list.
2823 */ 2821 */
2824static void smack_from_secattr(struct netlbl_lsm_secattr *sap, char *sip) 2822static char *smack_from_secattr(struct netlbl_lsm_secattr *sap,
2823 struct socket_smack *ssp)
2825{ 2824{
2825 struct smack_known *skp;
2826 char smack[SMK_LABELLEN]; 2826 char smack[SMK_LABELLEN];
2827 char *sp; 2827 char *sp;
2828 int pcat; 2828 int pcat;
@@ -2852,15 +2852,43 @@ static void smack_from_secattr(struct netlbl_lsm_secattr *sap, char *sip)
2852 * we are already done. WeeHee. 2852 * we are already done. WeeHee.
2853 */ 2853 */
2854 if (sap->attr.mls.lvl == smack_cipso_direct) { 2854 if (sap->attr.mls.lvl == smack_cipso_direct) {
2855 memcpy(sip, smack, SMK_MAXLEN); 2855 /*
2856 return; 2856 * The label sent is usually on the label list.
2857 *
2858 * If it is not we may still want to allow the
2859 * delivery.
2860 *
2861 * If the recipient is accepting all packets
2862 * because it is using the star ("*") label
2863 * for SMACK64IPIN provide the web ("@") label
2864 * so that a directed response will succeed.
2865 * This is not very correct from a MAC point
2866 * of view, but gets around the problem that
2867 * locking prevents adding the newly discovered
2868 * label to the list.
2869 * The case where the recipient is not using
2870 * the star label should obviously fail.
2871 * The easy way to do this is to provide the
2872 * star label as the subject label.
2873 */
2874 skp = smk_find_entry(smack);
2875 if (skp != NULL)
2876 return skp->smk_known;
2877 if (ssp != NULL &&
2878 ssp->smk_in == smack_known_star.smk_known)
2879 return smack_known_web.smk_known;
2880 return smack_known_star.smk_known;
2857 } 2881 }
2858 /* 2882 /*
2859 * Look it up in the supplied table if it is not 2883 * Look it up in the supplied table if it is not
2860 * a direct mapping. 2884 * a direct mapping.
2861 */ 2885 */
2862 smack_from_cipso(sap->attr.mls.lvl, smack, sip); 2886 sp = smack_from_cipso(sap->attr.mls.lvl, smack);
2863 return; 2887 if (sp != NULL)
2888 return sp;
2889 if (ssp != NULL && ssp->smk_in == smack_known_star.smk_known)
2890 return smack_known_web.smk_known;
2891 return smack_known_star.smk_known;
2864 } 2892 }
2865 if ((sap->flags & NETLBL_SECATTR_SECID) != 0) { 2893 if ((sap->flags & NETLBL_SECATTR_SECID) != 0) {
2866 /* 2894 /*
@@ -2875,16 +2903,14 @@ static void smack_from_secattr(struct netlbl_lsm_secattr *sap, char *sip)
2875 * secid is from a fallback. 2903 * secid is from a fallback.
2876 */ 2904 */
2877 BUG_ON(sp == NULL); 2905 BUG_ON(sp == NULL);
2878 strncpy(sip, sp, SMK_MAXLEN); 2906 return sp;
2879 return;
2880 } 2907 }
2881 /* 2908 /*
2882 * Without guidance regarding the smack value 2909 * Without guidance regarding the smack value
2883 * for the packet fall back on the network 2910 * for the packet fall back on the network
2884 * ambient value. 2911 * ambient value.
2885 */ 2912 */
2886 strncpy(sip, smack_net_ambient, SMK_MAXLEN); 2913 return smack_net_ambient;
2887 return;
2888} 2914}
2889 2915
2890/** 2916/**
@@ -2898,7 +2924,6 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
2898{ 2924{
2899 struct netlbl_lsm_secattr secattr; 2925 struct netlbl_lsm_secattr secattr;
2900 struct socket_smack *ssp = sk->sk_security; 2926 struct socket_smack *ssp = sk->sk_security;
2901 char smack[SMK_LABELLEN];
2902 char *csp; 2927 char *csp;
2903 int rc; 2928 int rc;
2904 struct smk_audit_info ad; 2929 struct smk_audit_info ad;
@@ -2911,10 +2936,9 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
2911 netlbl_secattr_init(&secattr); 2936 netlbl_secattr_init(&secattr);
2912 2937
2913 rc = netlbl_skbuff_getattr(skb, sk->sk_family, &secattr); 2938 rc = netlbl_skbuff_getattr(skb, sk->sk_family, &secattr);
2914 if (rc == 0) { 2939 if (rc == 0)
2915 smack_from_secattr(&secattr, smack); 2940 csp = smack_from_secattr(&secattr, ssp);
2916 csp = smack; 2941 else
2917 } else
2918 csp = smack_net_ambient; 2942 csp = smack_net_ambient;
2919 2943
2920 netlbl_secattr_destroy(&secattr); 2944 netlbl_secattr_destroy(&secattr);
@@ -2951,15 +2975,19 @@ static int smack_socket_getpeersec_stream(struct socket *sock,
2951 int __user *optlen, unsigned len) 2975 int __user *optlen, unsigned len)
2952{ 2976{
2953 struct socket_smack *ssp; 2977 struct socket_smack *ssp;
2954 int slen; 2978 char *rcp = "";
2979 int slen = 1;
2955 int rc = 0; 2980 int rc = 0;
2956 2981
2957 ssp = sock->sk->sk_security; 2982 ssp = sock->sk->sk_security;
2958 slen = strlen(ssp->smk_packet) + 1; 2983 if (ssp->smk_packet != NULL) {
2984 rcp = ssp->smk_packet;
2985 slen = strlen(rcp) + 1;
2986 }
2959 2987
2960 if (slen > len) 2988 if (slen > len)
2961 rc = -ERANGE; 2989 rc = -ERANGE;
2962 else if (copy_to_user(optval, ssp->smk_packet, slen) != 0) 2990 else if (copy_to_user(optval, rcp, slen) != 0)
2963 rc = -EFAULT; 2991 rc = -EFAULT;
2964 2992
2965 if (put_user(slen, optlen) != 0) 2993 if (put_user(slen, optlen) != 0)
@@ -2982,8 +3010,8 @@ static int smack_socket_getpeersec_dgram(struct socket *sock,
2982 3010
2983{ 3011{
2984 struct netlbl_lsm_secattr secattr; 3012 struct netlbl_lsm_secattr secattr;
2985 struct socket_smack *sp; 3013 struct socket_smack *ssp = NULL;
2986 char smack[SMK_LABELLEN]; 3014 char *sp;
2987 int family = PF_UNSPEC; 3015 int family = PF_UNSPEC;
2988 u32 s = 0; /* 0 is the invalid secid */ 3016 u32 s = 0; /* 0 is the invalid secid */
2989 int rc; 3017 int rc;
@@ -2998,17 +3026,19 @@ static int smack_socket_getpeersec_dgram(struct socket *sock,
2998 family = sock->sk->sk_family; 3026 family = sock->sk->sk_family;
2999 3027
3000 if (family == PF_UNIX) { 3028 if (family == PF_UNIX) {
3001 sp = sock->sk->sk_security; 3029 ssp = sock->sk->sk_security;
3002 s = smack_to_secid(sp->smk_out); 3030 s = smack_to_secid(ssp->smk_out);
3003 } else if (family == PF_INET || family == PF_INET6) { 3031 } else if (family == PF_INET || family == PF_INET6) {
3004 /* 3032 /*
3005 * Translate what netlabel gave us. 3033 * Translate what netlabel gave us.
3006 */ 3034 */
3035 if (sock != NULL && sock->sk != NULL)
3036 ssp = sock->sk->sk_security;
3007 netlbl_secattr_init(&secattr); 3037 netlbl_secattr_init(&secattr);
3008 rc = netlbl_skbuff_getattr(skb, family, &secattr); 3038 rc = netlbl_skbuff_getattr(skb, family, &secattr);
3009 if (rc == 0) { 3039 if (rc == 0) {
3010 smack_from_secattr(&secattr, smack); 3040 sp = smack_from_secattr(&secattr, ssp);
3011 s = smack_to_secid(smack); 3041 s = smack_to_secid(sp);
3012 } 3042 }
3013 netlbl_secattr_destroy(&secattr); 3043 netlbl_secattr_destroy(&secattr);
3014 } 3044 }
@@ -3056,7 +3086,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
3056 struct netlbl_lsm_secattr secattr; 3086 struct netlbl_lsm_secattr secattr;
3057 struct sockaddr_in addr; 3087 struct sockaddr_in addr;
3058 struct iphdr *hdr; 3088 struct iphdr *hdr;
3059 char smack[SMK_LABELLEN]; 3089 char *sp;
3060 int rc; 3090 int rc;
3061 struct smk_audit_info ad; 3091 struct smk_audit_info ad;
3062 3092
@@ -3067,9 +3097,9 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
3067 netlbl_secattr_init(&secattr); 3097 netlbl_secattr_init(&secattr);
3068 rc = netlbl_skbuff_getattr(skb, family, &secattr); 3098 rc = netlbl_skbuff_getattr(skb, family, &secattr);
3069 if (rc == 0) 3099 if (rc == 0)
3070 smack_from_secattr(&secattr, smack); 3100 sp = smack_from_secattr(&secattr, ssp);
3071 else 3101 else
3072 strncpy(smack, smack_known_huh.smk_known, SMK_MAXLEN); 3102 sp = smack_known_huh.smk_known;
3073 netlbl_secattr_destroy(&secattr); 3103 netlbl_secattr_destroy(&secattr);
3074 3104
3075#ifdef CONFIG_AUDIT 3105#ifdef CONFIG_AUDIT
@@ -3082,7 +3112,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
3082 * Receiving a packet requires that the other end be able to write 3112 * Receiving a packet requires that the other end be able to write
3083 * here. Read access is not required. 3113 * here. Read access is not required.
3084 */ 3114 */
3085 rc = smk_access(smack, ssp->smk_in, MAY_WRITE, &ad); 3115 rc = smk_access(sp, ssp->smk_in, MAY_WRITE, &ad);
3086 if (rc != 0) 3116 if (rc != 0)
3087 return rc; 3117 return rc;
3088 3118
@@ -3090,7 +3120,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
3090 * Save the peer's label in the request_sock so we can later setup 3120 * Save the peer's label in the request_sock so we can later setup
3091 * smk_packet in the child socket so that SO_PEERCRED can report it. 3121 * smk_packet in the child socket so that SO_PEERCRED can report it.
3092 */ 3122 */
3093 req->peer_secid = smack_to_secid(smack); 3123 req->peer_secid = smack_to_secid(sp);
3094 3124
3095 /* 3125 /*
3096 * We need to decide if we want to label the incoming connection here 3126 * We need to decide if we want to label the incoming connection here
@@ -3103,7 +3133,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
3103 if (smack_host_label(&addr) == NULL) { 3133 if (smack_host_label(&addr) == NULL) {
3104 rcu_read_unlock(); 3134 rcu_read_unlock();
3105 netlbl_secattr_init(&secattr); 3135 netlbl_secattr_init(&secattr);
3106 smack_to_secattr(smack, &secattr); 3136 smack_to_secattr(sp, &secattr);
3107 rc = netlbl_req_setattr(req, &secattr); 3137 rc = netlbl_req_setattr(req, &secattr);
3108 netlbl_secattr_destroy(&secattr); 3138 netlbl_secattr_destroy(&secattr);
3109 } else { 3139 } else {
@@ -3125,13 +3155,11 @@ static void smack_inet_csk_clone(struct sock *sk,
3125 const struct request_sock *req) 3155 const struct request_sock *req)
3126{ 3156{
3127 struct socket_smack *ssp = sk->sk_security; 3157 struct socket_smack *ssp = sk->sk_security;
3128 char *smack;
3129 3158
3130 if (req->peer_secid != 0) { 3159 if (req->peer_secid != 0)
3131 smack = smack_from_secid(req->peer_secid); 3160 ssp->smk_packet = smack_from_secid(req->peer_secid);
3132 strncpy(ssp->smk_packet, smack, SMK_MAXLEN); 3161 else
3133 } else 3162 ssp->smk_packet = NULL;
3134 ssp->smk_packet[0] = '\0';
3135} 3163}
3136 3164
3137/* 3165/*