diff options
Diffstat (limited to 'security')
-rw-r--r-- | security/smack/smack.h | 28 | ||||
-rw-r--r-- | security/smack/smack_access.c | 63 | ||||
-rw-r--r-- | security/smack/smack_lsm.c | 19 | ||||
-rw-r--r-- | security/smack/smackfs.c | 180 |
4 files changed, 168 insertions, 122 deletions
diff --git a/security/smack/smack.h b/security/smack/smack.h index b79582e4fbfd..64164f8fde70 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h | |||
@@ -18,6 +18,8 @@ | |||
18 | #include <linux/security.h> | 18 | #include <linux/security.h> |
19 | #include <linux/in.h> | 19 | #include <linux/in.h> |
20 | #include <net/netlabel.h> | 20 | #include <net/netlabel.h> |
21 | #include <linux/list.h> | ||
22 | #include <linux/rculist.h> | ||
21 | 23 | ||
22 | /* | 24 | /* |
23 | * Why 23? CIPSO is constrained to 30, so a 32 byte buffer is | 25 | * Why 23? CIPSO is constrained to 30, so a 32 byte buffer is |
@@ -59,17 +61,10 @@ struct inode_smack { | |||
59 | * A label access rule. | 61 | * A label access rule. |
60 | */ | 62 | */ |
61 | struct smack_rule { | 63 | struct smack_rule { |
62 | char *smk_subject; | 64 | struct list_head list; |
63 | char *smk_object; | 65 | char *smk_subject; |
64 | int smk_access; | 66 | char *smk_object; |
65 | }; | 67 | int smk_access; |
66 | |||
67 | /* | ||
68 | * An entry in the table of permitted label accesses. | ||
69 | */ | ||
70 | struct smk_list_entry { | ||
71 | struct smk_list_entry *smk_next; | ||
72 | struct smack_rule smk_rule; | ||
73 | }; | 68 | }; |
74 | 69 | ||
75 | /* | 70 | /* |
@@ -85,7 +80,7 @@ struct smack_cipso { | |||
85 | * An entry in the table identifying hosts. | 80 | * An entry in the table identifying hosts. |
86 | */ | 81 | */ |
87 | struct smk_netlbladdr { | 82 | struct smk_netlbladdr { |
88 | struct smk_netlbladdr *smk_next; | 83 | struct list_head list; |
89 | struct sockaddr_in smk_host; /* network address */ | 84 | struct sockaddr_in smk_host; /* network address */ |
90 | struct in_addr smk_mask; /* network mask */ | 85 | struct in_addr smk_mask; /* network mask */ |
91 | char *smk_label; /* label */ | 86 | char *smk_label; /* label */ |
@@ -113,7 +108,7 @@ struct smk_netlbladdr { | |||
113 | * the cipso direct mapping in used internally. | 108 | * the cipso direct mapping in used internally. |
114 | */ | 109 | */ |
115 | struct smack_known { | 110 | struct smack_known { |
116 | struct smack_known *smk_next; | 111 | struct list_head list; |
117 | char smk_known[SMK_LABELLEN]; | 112 | char smk_known[SMK_LABELLEN]; |
118 | u32 smk_secid; | 113 | u32 smk_secid; |
119 | struct smack_cipso *smk_cipso; | 114 | struct smack_cipso *smk_cipso; |
@@ -206,7 +201,6 @@ extern int smack_cipso_direct; | |||
206 | extern char *smack_net_ambient; | 201 | extern char *smack_net_ambient; |
207 | extern char *smack_onlycap; | 202 | extern char *smack_onlycap; |
208 | 203 | ||
209 | extern struct smack_known *smack_known; | ||
210 | extern struct smack_known smack_known_floor; | 204 | extern struct smack_known smack_known_floor; |
211 | extern struct smack_known smack_known_hat; | 205 | extern struct smack_known smack_known_hat; |
212 | extern struct smack_known smack_known_huh; | 206 | extern struct smack_known smack_known_huh; |
@@ -214,8 +208,10 @@ extern struct smack_known smack_known_invalid; | |||
214 | extern struct smack_known smack_known_star; | 208 | extern struct smack_known smack_known_star; |
215 | extern struct smack_known smack_known_web; | 209 | extern struct smack_known smack_known_web; |
216 | 210 | ||
217 | extern struct smk_list_entry *smack_list; | 211 | extern struct list_head smack_known_list; |
218 | extern struct smk_netlbladdr *smack_netlbladdrs; | 212 | extern struct list_head smack_rule_list; |
213 | extern struct list_head smk_netlbladdr_list; | ||
214 | |||
219 | extern struct security_operations smack_ops; | 215 | extern struct security_operations smack_ops; |
220 | 216 | ||
221 | /* | 217 | /* |
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c index cfa19ca125e3..58564195bb09 100644 --- a/security/smack/smack_access.c +++ b/security/smack/smack_access.c | |||
@@ -16,48 +16,42 @@ | |||
16 | #include "smack.h" | 16 | #include "smack.h" |
17 | 17 | ||
18 | struct smack_known smack_known_huh = { | 18 | struct smack_known smack_known_huh = { |
19 | .smk_next = NULL, | ||
20 | .smk_known = "?", | 19 | .smk_known = "?", |
21 | .smk_secid = 2, | 20 | .smk_secid = 2, |
22 | .smk_cipso = NULL, | 21 | .smk_cipso = NULL, |
23 | }; | 22 | }; |
24 | 23 | ||
25 | struct smack_known smack_known_hat = { | 24 | struct smack_known smack_known_hat = { |
26 | .smk_next = &smack_known_huh, | ||
27 | .smk_known = "^", | 25 | .smk_known = "^", |
28 | .smk_secid = 3, | 26 | .smk_secid = 3, |
29 | .smk_cipso = NULL, | 27 | .smk_cipso = NULL, |
30 | }; | 28 | }; |
31 | 29 | ||
32 | struct smack_known smack_known_star = { | 30 | struct smack_known smack_known_star = { |
33 | .smk_next = &smack_known_hat, | ||
34 | .smk_known = "*", | 31 | .smk_known = "*", |
35 | .smk_secid = 4, | 32 | .smk_secid = 4, |
36 | .smk_cipso = NULL, | 33 | .smk_cipso = NULL, |
37 | }; | 34 | }; |
38 | 35 | ||
39 | struct smack_known smack_known_floor = { | 36 | struct smack_known smack_known_floor = { |
40 | .smk_next = &smack_known_star, | ||
41 | .smk_known = "_", | 37 | .smk_known = "_", |
42 | .smk_secid = 5, | 38 | .smk_secid = 5, |
43 | .smk_cipso = NULL, | 39 | .smk_cipso = NULL, |
44 | }; | 40 | }; |
45 | 41 | ||
46 | struct smack_known smack_known_invalid = { | 42 | struct smack_known smack_known_invalid = { |
47 | .smk_next = &smack_known_floor, | ||
48 | .smk_known = "", | 43 | .smk_known = "", |
49 | .smk_secid = 6, | 44 | .smk_secid = 6, |
50 | .smk_cipso = NULL, | 45 | .smk_cipso = NULL, |
51 | }; | 46 | }; |
52 | 47 | ||
53 | struct smack_known smack_known_web = { | 48 | struct smack_known smack_known_web = { |
54 | .smk_next = &smack_known_invalid, | ||
55 | .smk_known = "@", | 49 | .smk_known = "@", |
56 | .smk_secid = 7, | 50 | .smk_secid = 7, |
57 | .smk_cipso = NULL, | 51 | .smk_cipso = NULL, |
58 | }; | 52 | }; |
59 | 53 | ||
60 | struct smack_known *smack_known = &smack_known_web; | 54 | LIST_HEAD(smack_known_list); |
61 | 55 | ||
62 | /* | 56 | /* |
63 | * The initial value needs to be bigger than any of the | 57 | * The initial value needs to be bigger than any of the |
@@ -87,7 +81,6 @@ static u32 smack_next_secid = 10; | |||
87 | int smk_access(char *subject_label, char *object_label, int request) | 81 | int smk_access(char *subject_label, char *object_label, int request) |
88 | { | 82 | { |
89 | u32 may = MAY_NOT; | 83 | u32 may = MAY_NOT; |
90 | struct smk_list_entry *sp; | ||
91 | struct smack_rule *srp; | 84 | struct smack_rule *srp; |
92 | 85 | ||
93 | /* | 86 | /* |
@@ -139,9 +132,8 @@ int smk_access(char *subject_label, char *object_label, int request) | |||
139 | * access (e.g. read is included in readwrite) it's | 132 | * access (e.g. read is included in readwrite) it's |
140 | * good. | 133 | * good. |
141 | */ | 134 | */ |
142 | for (sp = smack_list; sp != NULL; sp = sp->smk_next) { | 135 | rcu_read_lock(); |
143 | srp = &sp->smk_rule; | 136 | list_for_each_entry_rcu(srp, &smack_rule_list, list) { |
144 | |||
145 | if (srp->smk_subject == subject_label || | 137 | if (srp->smk_subject == subject_label || |
146 | strcmp(srp->smk_subject, subject_label) == 0) { | 138 | strcmp(srp->smk_subject, subject_label) == 0) { |
147 | if (srp->smk_object == object_label || | 139 | if (srp->smk_object == object_label || |
@@ -151,6 +143,7 @@ int smk_access(char *subject_label, char *object_label, int request) | |||
151 | } | 143 | } |
152 | } | 144 | } |
153 | } | 145 | } |
146 | rcu_read_unlock(); | ||
154 | /* | 147 | /* |
155 | * This is a bit map operation. | 148 | * This is a bit map operation. |
156 | */ | 149 | */ |
@@ -228,14 +221,17 @@ struct smack_known *smk_import_entry(const char *string, int len) | |||
228 | 221 | ||
229 | mutex_lock(&smack_known_lock); | 222 | mutex_lock(&smack_known_lock); |
230 | 223 | ||
231 | for (skp = smack_known; skp != NULL; skp = skp->smk_next) | 224 | found = 0; |
232 | if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0) | 225 | list_for_each_entry_rcu(skp, &smack_known_list, list) { |
226 | if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0) { | ||
227 | found = 1; | ||
233 | break; | 228 | break; |
229 | } | ||
230 | } | ||
234 | 231 | ||
235 | if (skp == NULL) { | 232 | if (found == 0) { |
236 | skp = kzalloc(sizeof(struct smack_known), GFP_KERNEL); | 233 | skp = kzalloc(sizeof(struct smack_known), GFP_KERNEL); |
237 | if (skp != NULL) { | 234 | if (skp != NULL) { |
238 | skp->smk_next = smack_known; | ||
239 | strncpy(skp->smk_known, smack, SMK_MAXLEN); | 235 | strncpy(skp->smk_known, smack, SMK_MAXLEN); |
240 | skp->smk_secid = smack_next_secid++; | 236 | skp->smk_secid = smack_next_secid++; |
241 | skp->smk_cipso = NULL; | 237 | skp->smk_cipso = NULL; |
@@ -244,8 +240,7 @@ struct smack_known *smk_import_entry(const char *string, int len) | |||
244 | * Make sure that the entry is actually | 240 | * Make sure that the entry is actually |
245 | * filled before putting it on the list. | 241 | * filled before putting it on the list. |
246 | */ | 242 | */ |
247 | smp_mb(); | 243 | list_add_rcu(&skp->list, &smack_known_list); |
248 | smack_known = skp; | ||
249 | } | 244 | } |
250 | } | 245 | } |
251 | 246 | ||
@@ -283,14 +278,19 @@ char *smack_from_secid(const u32 secid) | |||
283 | { | 278 | { |
284 | struct smack_known *skp; | 279 | struct smack_known *skp; |
285 | 280 | ||
286 | for (skp = smack_known; skp != NULL; skp = skp->smk_next) | 281 | rcu_read_lock(); |
287 | if (skp->smk_secid == secid) | 282 | list_for_each_entry_rcu(skp, &smack_known_list, list) { |
283 | if (skp->smk_secid == secid) { | ||
284 | rcu_read_unlock(); | ||
288 | return skp->smk_known; | 285 | return skp->smk_known; |
286 | } | ||
287 | } | ||
289 | 288 | ||
290 | /* | 289 | /* |
291 | * If we got this far someone asked for the translation | 290 | * If we got this far someone asked for the translation |
292 | * of a secid that is not on the list. | 291 | * of a secid that is not on the list. |
293 | */ | 292 | */ |
293 | rcu_read_unlock(); | ||
294 | return smack_known_invalid.smk_known; | 294 | return smack_known_invalid.smk_known; |
295 | } | 295 | } |
296 | 296 | ||
@@ -305,9 +305,14 @@ u32 smack_to_secid(const char *smack) | |||
305 | { | 305 | { |
306 | struct smack_known *skp; | 306 | struct smack_known *skp; |
307 | 307 | ||
308 | for (skp = smack_known; skp != NULL; skp = skp->smk_next) | 308 | rcu_read_lock(); |
309 | if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0) | 309 | list_for_each_entry_rcu(skp, &smack_known_list, list) { |
310 | if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0) { | ||
311 | rcu_read_unlock(); | ||
310 | return skp->smk_secid; | 312 | return skp->smk_secid; |
313 | } | ||
314 | } | ||
315 | rcu_read_unlock(); | ||
311 | return 0; | 316 | return 0; |
312 | } | 317 | } |
313 | 318 | ||
@@ -332,7 +337,8 @@ void smack_from_cipso(u32 level, char *cp, char *result) | |||
332 | struct smack_known *kp; | 337 | struct smack_known *kp; |
333 | char *final = NULL; | 338 | char *final = NULL; |
334 | 339 | ||
335 | for (kp = smack_known; final == NULL && kp != NULL; kp = kp->smk_next) { | 340 | rcu_read_lock(); |
341 | list_for_each_entry(kp, &smack_known_list, list) { | ||
336 | if (kp->smk_cipso == NULL) | 342 | if (kp->smk_cipso == NULL) |
337 | continue; | 343 | continue; |
338 | 344 | ||
@@ -344,6 +350,7 @@ void smack_from_cipso(u32 level, char *cp, char *result) | |||
344 | 350 | ||
345 | spin_unlock_bh(&kp->smk_cipsolock); | 351 | spin_unlock_bh(&kp->smk_cipsolock); |
346 | } | 352 | } |
353 | rcu_read_unlock(); | ||
347 | if (final == NULL) | 354 | if (final == NULL) |
348 | final = smack_known_huh.smk_known; | 355 | final = smack_known_huh.smk_known; |
349 | strncpy(result, final, SMK_MAXLEN); | 356 | strncpy(result, final, SMK_MAXLEN); |
@@ -360,13 +367,19 @@ void smack_from_cipso(u32 level, char *cp, char *result) | |||
360 | int smack_to_cipso(const char *smack, struct smack_cipso *cp) | 367 | int smack_to_cipso(const char *smack, struct smack_cipso *cp) |
361 | { | 368 | { |
362 | struct smack_known *kp; | 369 | struct smack_known *kp; |
370 | int found = 0; | ||
363 | 371 | ||
364 | for (kp = smack_known; kp != NULL; kp = kp->smk_next) | 372 | rcu_read_lock(); |
373 | list_for_each_entry_rcu(kp, &smack_known_list, list) { | ||
365 | if (kp->smk_known == smack || | 374 | if (kp->smk_known == smack || |
366 | strcmp(kp->smk_known, smack) == 0) | 375 | strcmp(kp->smk_known, smack) == 0) { |
376 | found = 1; | ||
367 | break; | 377 | break; |
378 | } | ||
379 | } | ||
380 | rcu_read_unlock(); | ||
368 | 381 | ||
369 | if (kp == NULL || kp->smk_cipso == NULL) | 382 | if (found == 0 || kp->smk_cipso == NULL) |
370 | return -ENOENT; | 383 | return -ENOENT; |
371 | 384 | ||
372 | memcpy(cp, kp->smk_cipso, sizeof(struct smack_cipso)); | 385 | memcpy(cp, kp->smk_cipso, sizeof(struct smack_cipso)); |
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 84b62b5e9e2c..fd20d15f5b9a 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c | |||
@@ -1508,7 +1508,8 @@ static char *smack_host_label(struct sockaddr_in *sip) | |||
1508 | if (siap->s_addr == 0) | 1508 | if (siap->s_addr == 0) |
1509 | return NULL; | 1509 | return NULL; |
1510 | 1510 | ||
1511 | for (snp = smack_netlbladdrs; snp != NULL; snp = snp->smk_next) { | 1511 | rcu_read_lock(); |
1512 | list_for_each_entry_rcu(snp, &smk_netlbladdr_list, list) { | ||
1512 | /* | 1513 | /* |
1513 | * we break after finding the first match because | 1514 | * we break after finding the first match because |
1514 | * the list is sorted from longest to shortest mask | 1515 | * the list is sorted from longest to shortest mask |
@@ -1516,10 +1517,11 @@ static char *smack_host_label(struct sockaddr_in *sip) | |||
1516 | */ | 1517 | */ |
1517 | if ((&snp->smk_host.sin_addr)->s_addr == | 1518 | if ((&snp->smk_host.sin_addr)->s_addr == |
1518 | (siap->s_addr & (&snp->smk_mask)->s_addr)) { | 1519 | (siap->s_addr & (&snp->smk_mask)->s_addr)) { |
1520 | rcu_read_unlock(); | ||
1519 | return snp->smk_label; | 1521 | return snp->smk_label; |
1520 | } | 1522 | } |
1521 | } | 1523 | } |
1522 | 1524 | rcu_read_unlock(); | |
1523 | return NULL; | 1525 | return NULL; |
1524 | } | 1526 | } |
1525 | 1527 | ||
@@ -2930,6 +2932,17 @@ struct security_operations smack_ops = { | |||
2930 | .release_secctx = smack_release_secctx, | 2932 | .release_secctx = smack_release_secctx, |
2931 | }; | 2933 | }; |
2932 | 2934 | ||
2935 | |||
2936 | static __init void init_smack_know_list(void) | ||
2937 | { | ||
2938 | list_add(&smack_known_huh.list, &smack_known_list); | ||
2939 | list_add(&smack_known_hat.list, &smack_known_list); | ||
2940 | list_add(&smack_known_star.list, &smack_known_list); | ||
2941 | list_add(&smack_known_floor.list, &smack_known_list); | ||
2942 | list_add(&smack_known_invalid.list, &smack_known_list); | ||
2943 | list_add(&smack_known_web.list, &smack_known_list); | ||
2944 | } | ||
2945 | |||
2933 | /** | 2946 | /** |
2934 | * smack_init - initialize the smack system | 2947 | * smack_init - initialize the smack system |
2935 | * | 2948 | * |
@@ -2950,6 +2963,8 @@ static __init int smack_init(void) | |||
2950 | cred = (struct cred *) current->cred; | 2963 | cred = (struct cred *) current->cred; |
2951 | cred->security = &smack_known_floor.smk_known; | 2964 | cred->security = &smack_known_floor.smk_known; |
2952 | 2965 | ||
2966 | /* initilize the smack_know_list */ | ||
2967 | init_smack_know_list(); | ||
2953 | /* | 2968 | /* |
2954 | * Initialize locks | 2969 | * Initialize locks |
2955 | */ | 2970 | */ |
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index a1b57e4dba3e..856c8a287523 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c | |||
@@ -80,10 +80,11 @@ char *smack_onlycap; | |||
80 | * Packets are sent there unlabeled, but only from tasks that | 80 | * Packets are sent there unlabeled, but only from tasks that |
81 | * can write to the specified label. | 81 | * can write to the specified label. |
82 | */ | 82 | */ |
83 | struct smk_netlbladdr *smack_netlbladdrs; | 83 | |
84 | LIST_HEAD(smk_netlbladdr_list); | ||
85 | LIST_HEAD(smack_rule_list); | ||
84 | 86 | ||
85 | static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; | 87 | static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; |
86 | struct smk_list_entry *smack_list; | ||
87 | 88 | ||
88 | #define SEQ_READ_FINISHED 1 | 89 | #define SEQ_READ_FINISHED 1 |
89 | 90 | ||
@@ -134,24 +135,27 @@ static void *load_seq_start(struct seq_file *s, loff_t *pos) | |||
134 | { | 135 | { |
135 | if (*pos == SEQ_READ_FINISHED) | 136 | if (*pos == SEQ_READ_FINISHED) |
136 | return NULL; | 137 | return NULL; |
137 | 138 | if (list_empty(&smack_rule_list)) | |
138 | return smack_list; | 139 | return NULL; |
140 | return smack_rule_list.next; | ||
139 | } | 141 | } |
140 | 142 | ||
141 | static void *load_seq_next(struct seq_file *s, void *v, loff_t *pos) | 143 | static void *load_seq_next(struct seq_file *s, void *v, loff_t *pos) |
142 | { | 144 | { |
143 | struct smk_list_entry *skp = ((struct smk_list_entry *) v)->smk_next; | 145 | struct list_head *list = v; |
144 | 146 | ||
145 | if (skp == NULL) | 147 | if (list_is_last(list, &smack_rule_list)) { |
146 | *pos = SEQ_READ_FINISHED; | 148 | *pos = SEQ_READ_FINISHED; |
147 | 149 | return NULL; | |
148 | return skp; | 150 | } |
151 | return list->next; | ||
149 | } | 152 | } |
150 | 153 | ||
151 | static int load_seq_show(struct seq_file *s, void *v) | 154 | static int load_seq_show(struct seq_file *s, void *v) |
152 | { | 155 | { |
153 | struct smk_list_entry *slp = (struct smk_list_entry *) v; | 156 | struct list_head *list = v; |
154 | struct smack_rule *srp = &slp->smk_rule; | 157 | struct smack_rule *srp = |
158 | list_entry(list, struct smack_rule, list); | ||
155 | 159 | ||
156 | seq_printf(s, "%s %s", (char *)srp->smk_subject, | 160 | seq_printf(s, "%s %s", (char *)srp->smk_subject, |
157 | (char *)srp->smk_object); | 161 | (char *)srp->smk_object); |
@@ -212,32 +216,23 @@ static int smk_open_load(struct inode *inode, struct file *file) | |||
212 | */ | 216 | */ |
213 | static int smk_set_access(struct smack_rule *srp) | 217 | static int smk_set_access(struct smack_rule *srp) |
214 | { | 218 | { |
215 | struct smk_list_entry *sp; | 219 | struct smack_rule *sp; |
216 | struct smk_list_entry *newp; | ||
217 | int ret = 0; | 220 | int ret = 0; |
218 | 221 | int found; | |
219 | mutex_lock(&smack_list_lock); | 222 | mutex_lock(&smack_list_lock); |
220 | 223 | ||
221 | for (sp = smack_list; sp != NULL; sp = sp->smk_next) | 224 | found = 0; |
222 | if (sp->smk_rule.smk_subject == srp->smk_subject && | 225 | list_for_each_entry_rcu(sp, &smack_rule_list, list) { |
223 | sp->smk_rule.smk_object == srp->smk_object) { | 226 | if (sp->smk_subject == srp->smk_subject && |
224 | sp->smk_rule.smk_access = srp->smk_access; | 227 | sp->smk_object == srp->smk_object) { |
228 | found = 1; | ||
229 | sp->smk_access = srp->smk_access; | ||
225 | break; | 230 | break; |
226 | } | 231 | } |
227 | |||
228 | if (sp == NULL) { | ||
229 | newp = kzalloc(sizeof(struct smk_list_entry), GFP_KERNEL); | ||
230 | if (newp == NULL) { | ||
231 | ret = -ENOMEM; | ||
232 | goto out; | ||
233 | } | ||
234 | |||
235 | newp->smk_rule = *srp; | ||
236 | newp->smk_next = smack_list; | ||
237 | smack_list = newp; | ||
238 | } | 232 | } |
233 | if (found == 0) | ||
234 | list_add_rcu(&srp->list, &smack_rule_list); | ||
239 | 235 | ||
240 | out: | ||
241 | mutex_unlock(&smack_list_lock); | 236 | mutex_unlock(&smack_list_lock); |
242 | 237 | ||
243 | return ret; | 238 | return ret; |
@@ -261,7 +256,7 @@ out: | |||
261 | static ssize_t smk_write_load(struct file *file, const char __user *buf, | 256 | static ssize_t smk_write_load(struct file *file, const char __user *buf, |
262 | size_t count, loff_t *ppos) | 257 | size_t count, loff_t *ppos) |
263 | { | 258 | { |
264 | struct smack_rule rule; | 259 | struct smack_rule *rule; |
265 | char *data; | 260 | char *data; |
266 | int rc = -EINVAL; | 261 | int rc = -EINVAL; |
267 | 262 | ||
@@ -272,9 +267,8 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf, | |||
272 | */ | 267 | */ |
273 | if (!capable(CAP_MAC_ADMIN)) | 268 | if (!capable(CAP_MAC_ADMIN)) |
274 | return -EPERM; | 269 | return -EPERM; |
275 | if (*ppos != 0) | 270 | |
276 | return -EINVAL; | 271 | if (*ppos != 0 || count != SMK_LOADLEN) |
277 | if (count != SMK_LOADLEN) | ||
278 | return -EINVAL; | 272 | return -EINVAL; |
279 | 273 | ||
280 | data = kzalloc(count, GFP_KERNEL); | 274 | data = kzalloc(count, GFP_KERNEL); |
@@ -286,25 +280,31 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf, | |||
286 | goto out; | 280 | goto out; |
287 | } | 281 | } |
288 | 282 | ||
289 | rule.smk_subject = smk_import(data, 0); | 283 | rule = kzalloc(sizeof(*rule), GFP_KERNEL); |
290 | if (rule.smk_subject == NULL) | 284 | if (rule == NULL) { |
285 | rc = -ENOMEM; | ||
291 | goto out; | 286 | goto out; |
287 | } | ||
292 | 288 | ||
293 | rule.smk_object = smk_import(data + SMK_LABELLEN, 0); | 289 | rule->smk_subject = smk_import(data, 0); |
294 | if (rule.smk_object == NULL) | 290 | if (rule->smk_subject == NULL) |
295 | goto out; | 291 | goto out_free_rule; |
296 | 292 | ||
297 | rule.smk_access = 0; | 293 | rule->smk_object = smk_import(data + SMK_LABELLEN, 0); |
294 | if (rule->smk_object == NULL) | ||
295 | goto out_free_rule; | ||
296 | |||
297 | rule->smk_access = 0; | ||
298 | 298 | ||
299 | switch (data[SMK_LABELLEN + SMK_LABELLEN]) { | 299 | switch (data[SMK_LABELLEN + SMK_LABELLEN]) { |
300 | case '-': | 300 | case '-': |
301 | break; | 301 | break; |
302 | case 'r': | 302 | case 'r': |
303 | case 'R': | 303 | case 'R': |
304 | rule.smk_access |= MAY_READ; | 304 | rule->smk_access |= MAY_READ; |
305 | break; | 305 | break; |
306 | default: | 306 | default: |
307 | goto out; | 307 | goto out_free_rule; |
308 | } | 308 | } |
309 | 309 | ||
310 | switch (data[SMK_LABELLEN + SMK_LABELLEN + 1]) { | 310 | switch (data[SMK_LABELLEN + SMK_LABELLEN + 1]) { |
@@ -312,10 +312,10 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf, | |||
312 | break; | 312 | break; |
313 | case 'w': | 313 | case 'w': |
314 | case 'W': | 314 | case 'W': |
315 | rule.smk_access |= MAY_WRITE; | 315 | rule->smk_access |= MAY_WRITE; |
316 | break; | 316 | break; |
317 | default: | 317 | default: |
318 | goto out; | 318 | goto out_free_rule; |
319 | } | 319 | } |
320 | 320 | ||
321 | switch (data[SMK_LABELLEN + SMK_LABELLEN + 2]) { | 321 | switch (data[SMK_LABELLEN + SMK_LABELLEN + 2]) { |
@@ -323,10 +323,10 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf, | |||
323 | break; | 323 | break; |
324 | case 'x': | 324 | case 'x': |
325 | case 'X': | 325 | case 'X': |
326 | rule.smk_access |= MAY_EXEC; | 326 | rule->smk_access |= MAY_EXEC; |
327 | break; | 327 | break; |
328 | default: | 328 | default: |
329 | goto out; | 329 | goto out_free_rule; |
330 | } | 330 | } |
331 | 331 | ||
332 | switch (data[SMK_LABELLEN + SMK_LABELLEN + 3]) { | 332 | switch (data[SMK_LABELLEN + SMK_LABELLEN + 3]) { |
@@ -334,17 +334,20 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf, | |||
334 | break; | 334 | break; |
335 | case 'a': | 335 | case 'a': |
336 | case 'A': | 336 | case 'A': |
337 | rule.smk_access |= MAY_APPEND; | 337 | rule->smk_access |= MAY_APPEND; |
338 | break; | 338 | break; |
339 | default: | 339 | default: |
340 | goto out; | 340 | goto out_free_rule; |
341 | } | 341 | } |
342 | 342 | ||
343 | rc = smk_set_access(&rule); | 343 | rc = smk_set_access(rule); |
344 | 344 | ||
345 | if (!rc) | 345 | if (!rc) |
346 | rc = count; | 346 | rc = count; |
347 | goto out; | ||
347 | 348 | ||
349 | out_free_rule: | ||
350 | kfree(rule); | ||
348 | out: | 351 | out: |
349 | kfree(data); | 352 | kfree(data); |
350 | return rc; | 353 | return rc; |
@@ -433,24 +436,26 @@ static void *cipso_seq_start(struct seq_file *s, loff_t *pos) | |||
433 | { | 436 | { |
434 | if (*pos == SEQ_READ_FINISHED) | 437 | if (*pos == SEQ_READ_FINISHED) |
435 | return NULL; | 438 | return NULL; |
439 | if (list_empty(&smack_known_list)) | ||
440 | return NULL; | ||
436 | 441 | ||
437 | return smack_known; | 442 | return smack_known_list.next; |
438 | } | 443 | } |
439 | 444 | ||
440 | static void *cipso_seq_next(struct seq_file *s, void *v, loff_t *pos) | 445 | static void *cipso_seq_next(struct seq_file *s, void *v, loff_t *pos) |
441 | { | 446 | { |
442 | struct smack_known *skp = ((struct smack_known *) v)->smk_next; | 447 | struct list_head *list = v; |
443 | 448 | ||
444 | /* | 449 | /* |
445 | * Omit labels with no associated cipso value | 450 | * labels with no associated cipso value wont be printed |
451 | * in cipso_seq_show | ||
446 | */ | 452 | */ |
447 | while (skp != NULL && !skp->smk_cipso) | 453 | if (list_is_last(list, &smack_known_list)) { |
448 | skp = skp->smk_next; | ||
449 | |||
450 | if (skp == NULL) | ||
451 | *pos = SEQ_READ_FINISHED; | 454 | *pos = SEQ_READ_FINISHED; |
455 | return NULL; | ||
456 | } | ||
452 | 457 | ||
453 | return skp; | 458 | return list->next; |
454 | } | 459 | } |
455 | 460 | ||
456 | /* | 461 | /* |
@@ -459,7 +464,9 @@ static void *cipso_seq_next(struct seq_file *s, void *v, loff_t *pos) | |||
459 | */ | 464 | */ |
460 | static int cipso_seq_show(struct seq_file *s, void *v) | 465 | static int cipso_seq_show(struct seq_file *s, void *v) |
461 | { | 466 | { |
462 | struct smack_known *skp = (struct smack_known *) v; | 467 | struct list_head *list = v; |
468 | struct smack_known *skp = | ||
469 | list_entry(list, struct smack_known, list); | ||
463 | struct smack_cipso *scp = skp->smk_cipso; | 470 | struct smack_cipso *scp = skp->smk_cipso; |
464 | char *cbp; | 471 | char *cbp; |
465 | char sep = '/'; | 472 | char sep = '/'; |
@@ -638,18 +645,21 @@ static void *netlbladdr_seq_start(struct seq_file *s, loff_t *pos) | |||
638 | { | 645 | { |
639 | if (*pos == SEQ_READ_FINISHED) | 646 | if (*pos == SEQ_READ_FINISHED) |
640 | return NULL; | 647 | return NULL; |
641 | 648 | if (list_empty(&smk_netlbladdr_list)) | |
642 | return smack_netlbladdrs; | 649 | return NULL; |
650 | return smk_netlbladdr_list.next; | ||
643 | } | 651 | } |
644 | 652 | ||
645 | static void *netlbladdr_seq_next(struct seq_file *s, void *v, loff_t *pos) | 653 | static void *netlbladdr_seq_next(struct seq_file *s, void *v, loff_t *pos) |
646 | { | 654 | { |
647 | struct smk_netlbladdr *skp = ((struct smk_netlbladdr *) v)->smk_next; | 655 | struct list_head *list = v; |
648 | 656 | ||
649 | if (skp == NULL) | 657 | if (list_is_last(list, &smk_netlbladdr_list)) { |
650 | *pos = SEQ_READ_FINISHED; | 658 | *pos = SEQ_READ_FINISHED; |
659 | return NULL; | ||
660 | } | ||
651 | 661 | ||
652 | return skp; | 662 | return list->next; |
653 | } | 663 | } |
654 | #define BEBITS (sizeof(__be32) * 8) | 664 | #define BEBITS (sizeof(__be32) * 8) |
655 | 665 | ||
@@ -658,7 +668,9 @@ static void *netlbladdr_seq_next(struct seq_file *s, void *v, loff_t *pos) | |||
658 | */ | 668 | */ |
659 | static int netlbladdr_seq_show(struct seq_file *s, void *v) | 669 | static int netlbladdr_seq_show(struct seq_file *s, void *v) |
660 | { | 670 | { |
661 | struct smk_netlbladdr *skp = (struct smk_netlbladdr *) v; | 671 | struct list_head *list = v; |
672 | struct smk_netlbladdr *skp = | ||
673 | list_entry(list, struct smk_netlbladdr, list); | ||
662 | unsigned char *hp = (char *) &skp->smk_host.sin_addr.s_addr; | 674 | unsigned char *hp = (char *) &skp->smk_host.sin_addr.s_addr; |
663 | int maskn; | 675 | int maskn; |
664 | u32 temp_mask = be32_to_cpu(skp->smk_mask.s_addr); | 676 | u32 temp_mask = be32_to_cpu(skp->smk_mask.s_addr); |
@@ -702,30 +714,36 @@ static int smk_open_netlbladdr(struct inode *inode, struct file *file) | |||
702 | * | 714 | * |
703 | * This helper insert netlabel in the smack_netlbladdrs list | 715 | * This helper insert netlabel in the smack_netlbladdrs list |
704 | * sorted by netmask length (longest to smallest) | 716 | * sorted by netmask length (longest to smallest) |
717 | * locked by &smk_netlbladdr_lock in smk_write_netlbladdr | ||
718 | * | ||
705 | */ | 719 | */ |
706 | static void smk_netlbladdr_insert(struct smk_netlbladdr *new) | 720 | static void smk_netlbladdr_insert(struct smk_netlbladdr *new) |
707 | { | 721 | { |
708 | struct smk_netlbladdr *m; | 722 | struct smk_netlbladdr *m, *m_next; |
709 | 723 | ||
710 | if (smack_netlbladdrs == NULL) { | 724 | if (list_empty(&smk_netlbladdr_list)) { |
711 | smack_netlbladdrs = new; | 725 | list_add_rcu(&new->list, &smk_netlbladdr_list); |
712 | return; | 726 | return; |
713 | } | 727 | } |
714 | 728 | ||
729 | m = list_entry(rcu_dereference(smk_netlbladdr_list.next), | ||
730 | struct smk_netlbladdr, list); | ||
731 | |||
715 | /* the comparison '>' is a bit hacky, but works */ | 732 | /* the comparison '>' is a bit hacky, but works */ |
716 | if (new->smk_mask.s_addr > smack_netlbladdrs->smk_mask.s_addr) { | 733 | if (new->smk_mask.s_addr > m->smk_mask.s_addr) { |
717 | new->smk_next = smack_netlbladdrs; | 734 | list_add_rcu(&new->list, &smk_netlbladdr_list); |
718 | smack_netlbladdrs = new; | ||
719 | return; | 735 | return; |
720 | } | 736 | } |
721 | for (m = smack_netlbladdrs; m != NULL; m = m->smk_next) { | 737 | |
722 | if (m->smk_next == NULL) { | 738 | list_for_each_entry_rcu(m, &smk_netlbladdr_list, list) { |
723 | m->smk_next = new; | 739 | if (list_is_last(&m->list, &smk_netlbladdr_list)) { |
740 | list_add_rcu(&new->list, &m->list); | ||
724 | return; | 741 | return; |
725 | } | 742 | } |
726 | if (new->smk_mask.s_addr > m->smk_next->smk_mask.s_addr) { | 743 | m_next = list_entry(rcu_dereference(m->list.next), |
727 | new->smk_next = m->smk_next; | 744 | struct smk_netlbladdr, list); |
728 | m->smk_next = new; | 745 | if (new->smk_mask.s_addr > m_next->smk_mask.s_addr) { |
746 | list_add_rcu(&new->list, &m->list); | ||
729 | return; | 747 | return; |
730 | } | 748 | } |
731 | } | 749 | } |
@@ -755,6 +773,7 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, | |||
755 | struct netlbl_audit audit_info; | 773 | struct netlbl_audit audit_info; |
756 | struct in_addr mask; | 774 | struct in_addr mask; |
757 | unsigned int m; | 775 | unsigned int m; |
776 | int found; | ||
758 | u32 mask_bits = (1<<31); | 777 | u32 mask_bits = (1<<31); |
759 | __be32 nsa; | 778 | __be32 nsa; |
760 | u32 temp_mask; | 779 | u32 temp_mask; |
@@ -808,14 +827,17 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, | |||
808 | 827 | ||
809 | nsa = newname.sin_addr.s_addr; | 828 | nsa = newname.sin_addr.s_addr; |
810 | /* try to find if the prefix is already in the list */ | 829 | /* try to find if the prefix is already in the list */ |
811 | for (skp = smack_netlbladdrs; skp != NULL; skp = skp->smk_next) | 830 | found = 0; |
831 | list_for_each_entry_rcu(skp, &smk_netlbladdr_list, list) { | ||
812 | if (skp->smk_host.sin_addr.s_addr == nsa && | 832 | if (skp->smk_host.sin_addr.s_addr == nsa && |
813 | skp->smk_mask.s_addr == mask.s_addr) | 833 | skp->smk_mask.s_addr == mask.s_addr) { |
834 | found = 1; | ||
814 | break; | 835 | break; |
815 | 836 | } | |
837 | } | ||
816 | smk_netlabel_audit_set(&audit_info); | 838 | smk_netlabel_audit_set(&audit_info); |
817 | 839 | ||
818 | if (skp == NULL) { | 840 | if (found == 0) { |
819 | skp = kzalloc(sizeof(*skp), GFP_KERNEL); | 841 | skp = kzalloc(sizeof(*skp), GFP_KERNEL); |
820 | if (skp == NULL) | 842 | if (skp == NULL) |
821 | rc = -ENOMEM; | 843 | rc = -ENOMEM; |