aboutsummaryrefslogtreecommitdiffstats
path: root/security
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
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')
-rw-r--r--security/smack/smack.h18
-rw-r--r--security/smack/smack_access.c113
-rw-r--r--security/smack/smack_lsm.c126
-rw-r--r--security/smack/smackfs.c84
4 files changed, 220 insertions, 121 deletions
diff --git a/security/smack/smack.h b/security/smack/smack.h
index 2b6c6a516123..174d3be9aaee 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -41,9 +41,9 @@ struct superblock_smack {
41}; 41};
42 42
43struct socket_smack { 43struct socket_smack {
44 char *smk_out; /* outbound label */ 44 char *smk_out; /* outbound label */
45 char *smk_in; /* inbound label */ 45 char *smk_in; /* inbound label */
46 char smk_packet[SMK_LABELLEN]; /* TCP peer label */ 46 char *smk_packet; /* TCP peer label */
47}; 47};
48 48
49/* 49/*
@@ -116,13 +116,19 @@ struct smk_netlbladdr {
116 * If there is a cipso value associated with the label it 116 * If there is a cipso value associated with the label it
117 * gets stored here, too. This will most likely be rare as 117 * gets stored here, too. This will most likely be rare as
118 * the cipso direct mapping in used internally. 118 * the cipso direct mapping in used internally.
119 *
120 * Keep the access rules for this subject label here so that
121 * the entire set of rules does not need to be examined every
122 * time.
119 */ 123 */
120struct smack_known { 124struct smack_known {
121 struct list_head list; 125 struct list_head list;
122 char smk_known[SMK_LABELLEN]; 126 char smk_known[SMK_LABELLEN];
123 u32 smk_secid; 127 u32 smk_secid;
124 struct smack_cipso *smk_cipso; 128 struct smack_cipso *smk_cipso;
125 spinlock_t smk_cipsolock; /* for changing cipso map */ 129 spinlock_t smk_cipsolock; /* for changing cipso map */
130 struct list_head smk_rules; /* access rules */
131 struct mutex smk_rules_lock; /* lock for the rules */
126}; 132};
127 133
128/* 134/*
@@ -201,10 +207,11 @@ int smk_access_entry(char *, char *, struct list_head *);
201int smk_access(char *, char *, int, struct smk_audit_info *); 207int smk_access(char *, char *, int, struct smk_audit_info *);
202int smk_curacc(char *, u32, struct smk_audit_info *); 208int smk_curacc(char *, u32, struct smk_audit_info *);
203int smack_to_cipso(const char *, struct smack_cipso *); 209int smack_to_cipso(const char *, struct smack_cipso *);
204void smack_from_cipso(u32, char *, char *); 210char *smack_from_cipso(u32, char *);
205char *smack_from_secid(const u32); 211char *smack_from_secid(const u32);
206char *smk_import(const char *, int); 212char *smk_import(const char *, int);
207struct smack_known *smk_import_entry(const char *, int); 213struct smack_known *smk_import_entry(const char *, int);
214struct smack_known *smk_find_entry(const char *);
208u32 smack_to_secid(const char *); 215u32 smack_to_secid(const char *);
209 216
210/* 217/*
@@ -223,7 +230,6 @@ extern struct smack_known smack_known_star;
223extern struct smack_known smack_known_web; 230extern struct smack_known smack_known_web;
224 231
225extern struct list_head smack_known_list; 232extern struct list_head smack_known_list;
226extern struct list_head smack_rule_list;
227extern struct list_head smk_netlbladdr_list; 233extern struct list_head smk_netlbladdr_list;
228 234
229extern struct security_operations smack_ops; 235extern struct security_operations smack_ops;
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c
index 9637e107f7ea..a885f628f56e 100644
--- a/security/smack/smack_access.c
+++ b/security/smack/smack_access.c
@@ -77,14 +77,19 @@ int log_policy = SMACK_AUDIT_DENIED;
77 * entry is found returns -ENOENT. 77 * entry is found returns -ENOENT.
78 * 78 *
79 * NOTE: 79 * NOTE:
80 * Even though Smack labels are usually shared on smack_list
81 * labels that come in off the network can't be imported
82 * and added to the list for locking reasons.
83 * 80 *
84 * Therefore, it is necessary to check the contents of the labels, 81 * Earlier versions of this function allowed for labels that
85 * not just the pointer values. Of course, in most cases the labels 82 * were not on the label list. This was done to allow for
86 * will be on the list, so checking the pointers may be a worthwhile 83 * labels to come over the network that had never been seen
87 * optimization. 84 * before on this host. Unless the receiving socket has the
85 * star label this will always result in a failure check. The
86 * star labeled socket case is now handled in the networking
87 * hooks so there is no case where the label is not on the
88 * label list. Checking to see if the address of two labels
89 * is the same is now a reliable test.
90 *
91 * Do the object check first because that is more
92 * likely to differ.
88 */ 93 */
89int smk_access_entry(char *subject_label, char *object_label, 94int smk_access_entry(char *subject_label, char *object_label,
90 struct list_head *rule_list) 95 struct list_head *rule_list)
@@ -93,13 +98,10 @@ int smk_access_entry(char *subject_label, char *object_label,
93 struct smack_rule *srp; 98 struct smack_rule *srp;
94 99
95 list_for_each_entry_rcu(srp, rule_list, list) { 100 list_for_each_entry_rcu(srp, rule_list, list) {
96 if (srp->smk_subject == subject_label || 101 if (srp->smk_object == object_label &&
97 strcmp(srp->smk_subject, subject_label) == 0) { 102 srp->smk_subject == subject_label) {
98 if (srp->smk_object == object_label || 103 may = srp->smk_access;
99 strcmp(srp->smk_object, object_label) == 0) { 104 break;
100 may = srp->smk_access;
101 break;
102 }
103 } 105 }
104 } 106 }
105 107
@@ -117,18 +119,12 @@ int smk_access_entry(char *subject_label, char *object_label,
117 * access rule list and returns 0 if the access is permitted, 119 * access rule list and returns 0 if the access is permitted,
118 * non zero otherwise. 120 * non zero otherwise.
119 * 121 *
120 * Even though Smack labels are usually shared on smack_list 122 * Smack labels are shared on smack_list
121 * labels that come in off the network can't be imported
122 * and added to the list for locking reasons.
123 *
124 * Therefore, it is necessary to check the contents of the labels,
125 * not just the pointer values. Of course, in most cases the labels
126 * will be on the list, so checking the pointers may be a worthwhile
127 * optimization.
128 */ 123 */
129int smk_access(char *subject_label, char *object_label, int request, 124int smk_access(char *subject_label, char *object_label, int request,
130 struct smk_audit_info *a) 125 struct smk_audit_info *a)
131{ 126{
127 struct smack_known *skp;
132 int may = MAY_NOT; 128 int may = MAY_NOT;
133 int rc = 0; 129 int rc = 0;
134 130
@@ -137,8 +133,7 @@ int smk_access(char *subject_label, char *object_label, int request,
137 * 133 *
138 * A star subject can't access any object. 134 * A star subject can't access any object.
139 */ 135 */
140 if (subject_label == smack_known_star.smk_known || 136 if (subject_label == smack_known_star.smk_known) {
141 strcmp(subject_label, smack_known_star.smk_known) == 0) {
142 rc = -EACCES; 137 rc = -EACCES;
143 goto out_audit; 138 goto out_audit;
144 } 139 }
@@ -148,33 +143,27 @@ int smk_access(char *subject_label, char *object_label, int request,
148 * An internet subject can access any object. 143 * An internet subject can access any object.
149 */ 144 */
150 if (object_label == smack_known_web.smk_known || 145 if (object_label == smack_known_web.smk_known ||
151 subject_label == smack_known_web.smk_known || 146 subject_label == smack_known_web.smk_known)
152 strcmp(object_label, smack_known_web.smk_known) == 0 ||
153 strcmp(subject_label, smack_known_web.smk_known) == 0)
154 goto out_audit; 147 goto out_audit;
155 /* 148 /*
156 * A star object can be accessed by any subject. 149 * A star object can be accessed by any subject.
157 */ 150 */
158 if (object_label == smack_known_star.smk_known || 151 if (object_label == smack_known_star.smk_known)
159 strcmp(object_label, smack_known_star.smk_known) == 0)
160 goto out_audit; 152 goto out_audit;
161 /* 153 /*
162 * An object can be accessed in any way by a subject 154 * An object can be accessed in any way by a subject
163 * with the same label. 155 * with the same label.
164 */ 156 */
165 if (subject_label == object_label || 157 if (subject_label == object_label)
166 strcmp(subject_label, object_label) == 0)
167 goto out_audit; 158 goto out_audit;
168 /* 159 /*
169 * A hat subject can read any object. 160 * A hat subject can read any object.
170 * A floor object can be read by any subject. 161 * A floor object can be read by any subject.
171 */ 162 */
172 if ((request & MAY_ANYREAD) == request) { 163 if ((request & MAY_ANYREAD) == request) {
173 if (object_label == smack_known_floor.smk_known || 164 if (object_label == smack_known_floor.smk_known)
174 strcmp(object_label, smack_known_floor.smk_known) == 0)
175 goto out_audit; 165 goto out_audit;
176 if (subject_label == smack_known_hat.smk_known || 166 if (subject_label == smack_known_hat.smk_known)
177 strcmp(subject_label, smack_known_hat.smk_known) == 0)
178 goto out_audit; 167 goto out_audit;
179 } 168 }
180 /* 169 /*
@@ -184,8 +173,9 @@ int smk_access(char *subject_label, char *object_label, int request,
184 * good. A negative response from smk_access_entry() 173 * good. A negative response from smk_access_entry()
185 * indicates there is no entry for this pair. 174 * indicates there is no entry for this pair.
186 */ 175 */
176 skp = smk_find_entry(subject_label);
187 rcu_read_lock(); 177 rcu_read_lock();
188 may = smk_access_entry(subject_label, object_label, &smack_rule_list); 178 may = smk_access_entry(subject_label, object_label, &skp->smk_rules);
189 rcu_read_unlock(); 179 rcu_read_unlock();
190 180
191 if (may > 0 && (request & may) == request) 181 if (may > 0 && (request & may) == request)
@@ -344,6 +334,25 @@ void smack_log(char *subject_label, char *object_label, int request,
344static DEFINE_MUTEX(smack_known_lock); 334static DEFINE_MUTEX(smack_known_lock);
345 335
346/** 336/**
337 * smk_find_entry - find a label on the list, return the list entry
338 * @string: a text string that might be a Smack label
339 *
340 * Returns a pointer to the entry in the label list that
341 * matches the passed string.
342 */
343struct smack_known *smk_find_entry(const char *string)
344{
345 struct smack_known *skp;
346
347 list_for_each_entry_rcu(skp, &smack_known_list, list) {
348 if (strncmp(skp->smk_known, string, SMK_MAXLEN) == 0)
349 return skp;
350 }
351
352 return NULL;
353}
354
355/**
347 * smk_import_entry - import a label, return the list entry 356 * smk_import_entry - import a label, return the list entry
348 * @string: a text string that might be a Smack label 357 * @string: a text string that might be a Smack label
349 * @len: the maximum size, or zero if it is NULL terminated. 358 * @len: the maximum size, or zero if it is NULL terminated.
@@ -378,21 +387,17 @@ struct smack_known *smk_import_entry(const char *string, int len)
378 387
379 mutex_lock(&smack_known_lock); 388 mutex_lock(&smack_known_lock);
380 389
381 found = 0; 390 skp = smk_find_entry(smack);
382 list_for_each_entry_rcu(skp, &smack_known_list, list) {
383 if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0) {
384 found = 1;
385 break;
386 }
387 }
388 391
389 if (found == 0) { 392 if (skp == NULL) {
390 skp = kzalloc(sizeof(struct smack_known), GFP_KERNEL); 393 skp = kzalloc(sizeof(struct smack_known), GFP_KERNEL);
391 if (skp != NULL) { 394 if (skp != NULL) {
392 strncpy(skp->smk_known, smack, SMK_MAXLEN); 395 strncpy(skp->smk_known, smack, SMK_MAXLEN);
393 skp->smk_secid = smack_next_secid++; 396 skp->smk_secid = smack_next_secid++;
394 skp->smk_cipso = NULL; 397 skp->smk_cipso = NULL;
398 INIT_LIST_HEAD(&skp->smk_rules);
395 spin_lock_init(&skp->smk_cipsolock); 399 spin_lock_init(&skp->smk_cipsolock);
400 mutex_init(&skp->smk_rules_lock);
396 /* 401 /*
397 * Make sure that the entry is actually 402 * Make sure that the entry is actually
398 * filled before putting it on the list. 403 * filled before putting it on the list.
@@ -480,19 +485,12 @@ u32 smack_to_secid(const char *smack)
480 * smack_from_cipso - find the Smack label associated with a CIPSO option 485 * smack_from_cipso - find the Smack label associated with a CIPSO option
481 * @level: Bell & LaPadula level from the network 486 * @level: Bell & LaPadula level from the network
482 * @cp: Bell & LaPadula categories from the network 487 * @cp: Bell & LaPadula categories from the network
483 * @result: where to put the Smack value
484 * 488 *
485 * This is a simple lookup in the label table. 489 * This is a simple lookup in the label table.
486 * 490 *
487 * This is an odd duck as far as smack handling goes in that 491 * Return the matching label from the label list or NULL.
488 * it sends back a copy of the smack label rather than a pointer
489 * to the master list. This is done because it is possible for
490 * a foreign host to send a smack label that is new to this
491 * machine and hence not on the list. That would not be an
492 * issue except that adding an entry to the master list can't
493 * be done at that point.
494 */ 492 */
495void smack_from_cipso(u32 level, char *cp, char *result) 493char *smack_from_cipso(u32 level, char *cp)
496{ 494{
497 struct smack_known *kp; 495 struct smack_known *kp;
498 char *final = NULL; 496 char *final = NULL;
@@ -509,12 +507,13 @@ void smack_from_cipso(u32 level, char *cp, char *result)
509 final = kp->smk_known; 507 final = kp->smk_known;
510 508
511 spin_unlock_bh(&kp->smk_cipsolock); 509 spin_unlock_bh(&kp->smk_cipsolock);
510
511 if (final != NULL)
512 break;
512 } 513 }
513 rcu_read_unlock(); 514 rcu_read_unlock();
514 if (final == NULL) 515
515 final = smack_known_huh.smk_known; 516 return final;
516 strncpy(result, final, SMK_MAXLEN);
517 return;
518} 517}
519 518
520/** 519/**
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/*
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index f4c28eeba1b1..76e520be1b5d 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -86,6 +86,16 @@ char *smack_onlycap;
86 */ 86 */
87 87
88LIST_HEAD(smk_netlbladdr_list); 88LIST_HEAD(smk_netlbladdr_list);
89
90/*
91 * Rule lists are maintained for each label.
92 * This master list is just for reading /smack/load.
93 */
94struct smack_master_list {
95 struct list_head list;
96 struct smack_rule *smk_rule;
97};
98
89LIST_HEAD(smack_rule_list); 99LIST_HEAD(smack_rule_list);
90 100
91static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; 101static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT;
@@ -93,7 +103,10 @@ static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT;
93const char *smack_cipso_option = SMACK_CIPSO_OPTION; 103const char *smack_cipso_option = SMACK_CIPSO_OPTION;
94 104
95 105
106#define SEQ_READ_FINISHED ((loff_t)-1)
107/*
96#define SEQ_READ_FINISHED 1 108#define SEQ_READ_FINISHED 1
109*/
97 110
98/* 111/*
99 * Values for parsing cipso rules 112 * Values for parsing cipso rules
@@ -160,9 +173,13 @@ static int smk_set_access(struct smack_rule *srp, struct list_head *rule_list,
160 173
161 mutex_lock(rule_lock); 174 mutex_lock(rule_lock);
162 175
176 /*
177 * Because the object label is less likely to match
178 * than the subject label check it first
179 */
163 list_for_each_entry_rcu(sp, rule_list, list) { 180 list_for_each_entry_rcu(sp, rule_list, list) {
164 if (sp->smk_subject == srp->smk_subject && 181 if (sp->smk_object == srp->smk_object &&
165 sp->smk_object == srp->smk_object) { 182 sp->smk_subject == srp->smk_subject) {
166 found = 1; 183 found = 1;
167 sp->smk_access = srp->smk_access; 184 sp->smk_access = srp->smk_access;
168 break; 185 break;
@@ -273,9 +290,12 @@ static ssize_t smk_write_load_list(struct file *file, const char __user *buf,
273 struct list_head *rule_list, 290 struct list_head *rule_list,
274 struct mutex *rule_lock) 291 struct mutex *rule_lock)
275{ 292{
293 struct smack_master_list *smlp;
294 struct smack_known *skp;
276 struct smack_rule *rule; 295 struct smack_rule *rule;
277 char *data; 296 char *data;
278 int rc = -EINVAL; 297 int rc = -EINVAL;
298 int load = 0;
279 299
280 /* 300 /*
281 * No partial writes. 301 * No partial writes.
@@ -313,13 +333,27 @@ static ssize_t smk_write_load_list(struct file *file, const char __user *buf,
313 if (smk_parse_rule(data, rule)) 333 if (smk_parse_rule(data, rule))
314 goto out_free_rule; 334 goto out_free_rule;
315 335
336 if (rule_list == NULL) {
337 load = 1;
338 skp = smk_find_entry(rule->smk_subject);
339 rule_list = &skp->smk_rules;
340 rule_lock = &skp->smk_rules_lock;
341 }
342
316 rc = count; 343 rc = count;
317 /* 344 /*
318 * smk_set_access returns true if there was already a rule 345 * smk_set_access returns true if there was already a rule
319 * for the subject/object pair, and false if it was new. 346 * for the subject/object pair, and false if it was new.
320 */ 347 */
321 if (!smk_set_access(rule, rule_list, rule_lock)) 348 if (!smk_set_access(rule, rule_list, rule_lock)) {
349 smlp = kzalloc(sizeof(*smlp), GFP_KERNEL);
350 if (smlp != NULL) {
351 smlp->smk_rule = rule;
352 list_add_rcu(&smlp->list, &smack_rule_list);
353 } else
354 rc = -ENOMEM;
322 goto out; 355 goto out;
356 }
323 357
324out_free_rule: 358out_free_rule:
325 kfree(rule); 359 kfree(rule);
@@ -335,11 +369,24 @@ out:
335 369
336static void *load_seq_start(struct seq_file *s, loff_t *pos) 370static void *load_seq_start(struct seq_file *s, loff_t *pos)
337{ 371{
338 if (*pos == SEQ_READ_FINISHED) 372 struct list_head *list;
373
374 /*
375 * This is 0 the first time through.
376 */
377 if (s->index == 0)
378 s->private = &smack_rule_list;
379
380 if (s->private == NULL)
339 return NULL; 381 return NULL;
340 if (list_empty(&smack_rule_list)) 382
383 list = s->private;
384 if (list_empty(list))
341 return NULL; 385 return NULL;
342 return smack_rule_list.next; 386
387 if (s->index == 0)
388 return list->next;
389 return list;
343} 390}
344 391
345static void *load_seq_next(struct seq_file *s, void *v, loff_t *pos) 392static void *load_seq_next(struct seq_file *s, void *v, loff_t *pos)
@@ -347,17 +394,19 @@ static void *load_seq_next(struct seq_file *s, void *v, loff_t *pos)
347 struct list_head *list = v; 394 struct list_head *list = v;
348 395
349 if (list_is_last(list, &smack_rule_list)) { 396 if (list_is_last(list, &smack_rule_list)) {
350 *pos = SEQ_READ_FINISHED; 397 s->private = NULL;
351 return NULL; 398 return NULL;
352 } 399 }
400 s->private = list->next;
353 return list->next; 401 return list->next;
354} 402}
355 403
356static int load_seq_show(struct seq_file *s, void *v) 404static int load_seq_show(struct seq_file *s, void *v)
357{ 405{
358 struct list_head *list = v; 406 struct list_head *list = v;
359 struct smack_rule *srp = 407 struct smack_master_list *smlp =
360 list_entry(list, struct smack_rule, list); 408 list_entry(list, struct smack_master_list, list);
409 struct smack_rule *srp = smlp->smk_rule;
361 410
362 seq_printf(s, "%s %s", (char *)srp->smk_subject, 411 seq_printf(s, "%s %s", (char *)srp->smk_subject,
363 (char *)srp->smk_object); 412 (char *)srp->smk_object);
@@ -426,8 +475,11 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
426 if (!capable(CAP_MAC_ADMIN)) 475 if (!capable(CAP_MAC_ADMIN))
427 return -EPERM; 476 return -EPERM;
428 477
478/*
429 return smk_write_load_list(file, buf, count, ppos, &smack_rule_list, 479 return smk_write_load_list(file, buf, count, ppos, &smack_rule_list,
430 &smack_list_lock); 480 &smack_list_lock);
481*/
482 return smk_write_load_list(file, buf, count, ppos, NULL, NULL);
431} 483}
432 484
433static const struct file_operations smk_load_ops = { 485static const struct file_operations smk_load_ops = {
@@ -1588,6 +1640,20 @@ static int __init init_smk_fs(void)
1588 smk_cipso_doi(); 1640 smk_cipso_doi();
1589 smk_unlbl_ambient(NULL); 1641 smk_unlbl_ambient(NULL);
1590 1642
1643 mutex_init(&smack_known_floor.smk_rules_lock);
1644 mutex_init(&smack_known_hat.smk_rules_lock);
1645 mutex_init(&smack_known_huh.smk_rules_lock);
1646 mutex_init(&smack_known_invalid.smk_rules_lock);
1647 mutex_init(&smack_known_star.smk_rules_lock);
1648 mutex_init(&smack_known_web.smk_rules_lock);
1649
1650 INIT_LIST_HEAD(&smack_known_floor.smk_rules);
1651 INIT_LIST_HEAD(&smack_known_hat.smk_rules);
1652 INIT_LIST_HEAD(&smack_known_huh.smk_rules);
1653 INIT_LIST_HEAD(&smack_known_invalid.smk_rules);
1654 INIT_LIST_HEAD(&smack_known_star.smk_rules);
1655 INIT_LIST_HEAD(&smack_known_web.smk_rules);
1656
1591 return err; 1657 return err;
1592} 1658}
1593 1659