diff options
| author | Etienne Basset <etienne.basset@numericable.fr> | 2009-03-24 15:53:24 -0400 |
|---|---|---|
| committer | James Morris <jmorris@namei.org> | 2009-03-25 18:17:04 -0400 |
| commit | 7198e2eeb44b3fe7cc97f997824002da47a9c644 (patch) | |
| tree | 4989ad0f9727ac4b861189217760517aa8beea43 /security | |
| parent | 703a3cd72817e99201cef84a8a7aecc60b2b3581 (diff) | |
smack: convert smack to standard linux lists
the following patch (on top of 2.6.29) converts Smack lists to standard linux lists
Please review and consider for inclusion in 2.6.30-rc
regards,
Etienne
Signed-off-by: Etienne Basset <etienne.basset@numericable.fr>
Acked-by: Casey Schaufler <casey@schaufler-ca.com>
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; |
