diff options
author | James Morris <james.l.morris@oracle.com> | 2015-06-03 05:10:29 -0400 |
---|---|---|
committer | James Morris <james.l.morris@oracle.com> | 2015-06-03 05:10:29 -0400 |
commit | e6e29a4eae335059d2cc44ac543de7556ff7ac09 (patch) | |
tree | e09595fa1c5e5ac6c9eb1f92c86df1d0cfc62a9d | |
parent | 8d94eb9b5cff350ba170848c862ca0006d33d496 (diff) | |
parent | c0d77c884461fc0dec0411e49797dc3f3651c31b (diff) |
Merge branch 'smack-for-4.2-stacked' of https://github.com/cschaufler/smack-next into next
-rw-r--r-- | Documentation/security/Smack.txt | 6 | ||||
-rw-r--r-- | security/smack/smack.h | 25 | ||||
-rw-r--r-- | security/smack/smack_access.c | 68 | ||||
-rw-r--r-- | security/smack/smack_lsm.c | 96 | ||||
-rw-r--r-- | security/smack/smackfs.c | 311 |
5 files changed, 317 insertions, 189 deletions
diff --git a/Documentation/security/Smack.txt b/Documentation/security/Smack.txt index abc82f85215b..de5e1aeca7fb 100644 --- a/Documentation/security/Smack.txt +++ b/Documentation/security/Smack.txt | |||
@@ -206,11 +206,11 @@ netlabel | |||
206 | label. The format accepted on write is: | 206 | label. The format accepted on write is: |
207 | "%d.%d.%d.%d label" or "%d.%d.%d.%d/%d label". | 207 | "%d.%d.%d.%d label" or "%d.%d.%d.%d/%d label". |
208 | onlycap | 208 | onlycap |
209 | This contains the label processes must have for CAP_MAC_ADMIN | 209 | This contains labels processes must have for CAP_MAC_ADMIN |
210 | and CAP_MAC_OVERRIDE to be effective. If this file is empty | 210 | and CAP_MAC_OVERRIDE to be effective. If this file is empty |
211 | these capabilities are effective at for processes with any | 211 | these capabilities are effective at for processes with any |
212 | label. The value is set by writing the desired label to the | 212 | label. The values are set by writing the desired labels, separated |
213 | file or cleared by writing "-" to the file. | 213 | by spaces, to the file or cleared by writing "-" to the file. |
214 | ptrace | 214 | ptrace |
215 | This is used to define the current ptrace policy | 215 | This is used to define the current ptrace policy |
216 | 0 - default: this is the policy that relies on Smack access rules. | 216 | 0 - default: this is the policy that relies on Smack access rules. |
diff --git a/security/smack/smack.h b/security/smack/smack.h index b8c1a869d85e..244e035e5a99 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h | |||
@@ -138,6 +138,11 @@ struct smk_port_label { | |||
138 | struct smack_known *smk_out; /* outgoing label */ | 138 | struct smack_known *smk_out; /* outgoing label */ |
139 | }; | 139 | }; |
140 | 140 | ||
141 | struct smack_onlycap { | ||
142 | struct list_head list; | ||
143 | struct smack_known *smk_label; | ||
144 | }; | ||
145 | |||
141 | /* | 146 | /* |
142 | * Mount options | 147 | * Mount options |
143 | */ | 148 | */ |
@@ -249,6 +254,7 @@ int smk_netlbl_mls(int, char *, struct netlbl_lsm_secattr *, int); | |||
249 | struct smack_known *smk_import_entry(const char *, int); | 254 | struct smack_known *smk_import_entry(const char *, int); |
250 | void smk_insert_entry(struct smack_known *skp); | 255 | void smk_insert_entry(struct smack_known *skp); |
251 | struct smack_known *smk_find_entry(const char *); | 256 | struct smack_known *smk_find_entry(const char *); |
257 | int smack_privileged(int cap); | ||
252 | 258 | ||
253 | /* | 259 | /* |
254 | * Shared data. | 260 | * Shared data. |
@@ -257,7 +263,6 @@ extern int smack_enabled; | |||
257 | extern int smack_cipso_direct; | 263 | extern int smack_cipso_direct; |
258 | extern int smack_cipso_mapped; | 264 | extern int smack_cipso_mapped; |
259 | extern struct smack_known *smack_net_ambient; | 265 | extern struct smack_known *smack_net_ambient; |
260 | extern struct smack_known *smack_onlycap; | ||
261 | extern struct smack_known *smack_syslog_label; | 266 | extern struct smack_known *smack_syslog_label; |
262 | #ifdef CONFIG_SECURITY_SMACK_BRINGUP | 267 | #ifdef CONFIG_SECURITY_SMACK_BRINGUP |
263 | extern struct smack_known *smack_unconfined; | 268 | extern struct smack_known *smack_unconfined; |
@@ -276,6 +281,9 @@ extern struct mutex smack_known_lock; | |||
276 | extern struct list_head smack_known_list; | 281 | extern struct list_head smack_known_list; |
277 | extern struct list_head smk_netlbladdr_list; | 282 | extern struct list_head smk_netlbladdr_list; |
278 | 283 | ||
284 | extern struct mutex smack_onlycap_lock; | ||
285 | extern struct list_head smack_onlycap_list; | ||
286 | |||
279 | #define SMACK_HASH_SLOTS 16 | 287 | #define SMACK_HASH_SLOTS 16 |
280 | extern struct hlist_head smack_known_hash[SMACK_HASH_SLOTS]; | 288 | extern struct hlist_head smack_known_hash[SMACK_HASH_SLOTS]; |
281 | 289 | ||
@@ -332,21 +340,6 @@ static inline struct smack_known *smk_of_current(void) | |||
332 | } | 340 | } |
333 | 341 | ||
334 | /* | 342 | /* |
335 | * Is the task privileged and allowed to be privileged | ||
336 | * by the onlycap rule. | ||
337 | */ | ||
338 | static inline int smack_privileged(int cap) | ||
339 | { | ||
340 | struct smack_known *skp = smk_of_current(); | ||
341 | |||
342 | if (!capable(cap)) | ||
343 | return 0; | ||
344 | if (smack_onlycap == NULL || smack_onlycap == skp) | ||
345 | return 1; | ||
346 | return 0; | ||
347 | } | ||
348 | |||
349 | /* | ||
350 | * logging functions | 343 | * logging functions |
351 | */ | 344 | */ |
352 | #define SMACK_AUDIT_DENIED 0x1 | 345 | #define SMACK_AUDIT_DENIED 0x1 |
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c index 0f410fc56e33..00f6b38bffbd 100644 --- a/security/smack/smack_access.c +++ b/security/smack/smack_access.c | |||
@@ -425,7 +425,7 @@ void smk_insert_entry(struct smack_known *skp) | |||
425 | * @string: a text string that might be a Smack label | 425 | * @string: a text string that might be a Smack label |
426 | * | 426 | * |
427 | * Returns a pointer to the entry in the label list that | 427 | * Returns a pointer to the entry in the label list that |
428 | * matches the passed string. | 428 | * matches the passed string or NULL if not found. |
429 | */ | 429 | */ |
430 | struct smack_known *smk_find_entry(const char *string) | 430 | struct smack_known *smk_find_entry(const char *string) |
431 | { | 431 | { |
@@ -448,7 +448,7 @@ struct smack_known *smk_find_entry(const char *string) | |||
448 | * @string: a text string that might contain a Smack label | 448 | * @string: a text string that might contain a Smack label |
449 | * @len: the maximum size, or zero if it is NULL terminated. | 449 | * @len: the maximum size, or zero if it is NULL terminated. |
450 | * | 450 | * |
451 | * Returns a pointer to the clean label, or NULL | 451 | * Returns a pointer to the clean label or an error code. |
452 | */ | 452 | */ |
453 | char *smk_parse_smack(const char *string, int len) | 453 | char *smk_parse_smack(const char *string, int len) |
454 | { | 454 | { |
@@ -464,7 +464,7 @@ char *smk_parse_smack(const char *string, int len) | |||
464 | * including /smack/cipso and /smack/cipso2 | 464 | * including /smack/cipso and /smack/cipso2 |
465 | */ | 465 | */ |
466 | if (string[0] == '-') | 466 | if (string[0] == '-') |
467 | return NULL; | 467 | return ERR_PTR(-EINVAL); |
468 | 468 | ||
469 | for (i = 0; i < len; i++) | 469 | for (i = 0; i < len; i++) |
470 | if (string[i] > '~' || string[i] <= ' ' || string[i] == '/' || | 470 | if (string[i] > '~' || string[i] <= ' ' || string[i] == '/' || |
@@ -472,11 +472,13 @@ char *smk_parse_smack(const char *string, int len) | |||
472 | break; | 472 | break; |
473 | 473 | ||
474 | if (i == 0 || i >= SMK_LONGLABEL) | 474 | if (i == 0 || i >= SMK_LONGLABEL) |
475 | return NULL; | 475 | return ERR_PTR(-EINVAL); |
476 | 476 | ||
477 | smack = kzalloc(i + 1, GFP_KERNEL); | 477 | smack = kzalloc(i + 1, GFP_KERNEL); |
478 | if (smack != NULL) | 478 | if (smack == NULL) |
479 | strncpy(smack, string, i); | 479 | return ERR_PTR(-ENOMEM); |
480 | |||
481 | strncpy(smack, string, i); | ||
480 | 482 | ||
481 | return smack; | 483 | return smack; |
482 | } | 484 | } |
@@ -523,7 +525,8 @@ int smk_netlbl_mls(int level, char *catset, struct netlbl_lsm_secattr *sap, | |||
523 | * @len: the maximum size, or zero if it is NULL terminated. | 525 | * @len: the maximum size, or zero if it is NULL terminated. |
524 | * | 526 | * |
525 | * Returns a pointer to the entry in the label list that | 527 | * Returns a pointer to the entry in the label list that |
526 | * matches the passed string, adding it if necessary. | 528 | * matches the passed string, adding it if necessary, |
529 | * or an error code. | ||
527 | */ | 530 | */ |
528 | struct smack_known *smk_import_entry(const char *string, int len) | 531 | struct smack_known *smk_import_entry(const char *string, int len) |
529 | { | 532 | { |
@@ -533,8 +536,8 @@ struct smack_known *smk_import_entry(const char *string, int len) | |||
533 | int rc; | 536 | int rc; |
534 | 537 | ||
535 | smack = smk_parse_smack(string, len); | 538 | smack = smk_parse_smack(string, len); |
536 | if (smack == NULL) | 539 | if (IS_ERR(smack)) |
537 | return NULL; | 540 | return ERR_CAST(smack); |
538 | 541 | ||
539 | mutex_lock(&smack_known_lock); | 542 | mutex_lock(&smack_known_lock); |
540 | 543 | ||
@@ -543,8 +546,10 @@ struct smack_known *smk_import_entry(const char *string, int len) | |||
543 | goto freeout; | 546 | goto freeout; |
544 | 547 | ||
545 | skp = kzalloc(sizeof(*skp), GFP_KERNEL); | 548 | skp = kzalloc(sizeof(*skp), GFP_KERNEL); |
546 | if (skp == NULL) | 549 | if (skp == NULL) { |
550 | skp = ERR_PTR(-ENOMEM); | ||
547 | goto freeout; | 551 | goto freeout; |
552 | } | ||
548 | 553 | ||
549 | skp->smk_known = smack; | 554 | skp->smk_known = smack; |
550 | skp->smk_secid = smack_next_secid++; | 555 | skp->smk_secid = smack_next_secid++; |
@@ -577,7 +582,7 @@ struct smack_known *smk_import_entry(const char *string, int len) | |||
577 | * smk_netlbl_mls failed. | 582 | * smk_netlbl_mls failed. |
578 | */ | 583 | */ |
579 | kfree(skp); | 584 | kfree(skp); |
580 | skp = NULL; | 585 | skp = ERR_PTR(rc); |
581 | freeout: | 586 | freeout: |
582 | kfree(smack); | 587 | kfree(smack); |
583 | unlockout: | 588 | unlockout: |
@@ -612,3 +617,44 @@ struct smack_known *smack_from_secid(const u32 secid) | |||
612 | rcu_read_unlock(); | 617 | rcu_read_unlock(); |
613 | return &smack_known_invalid; | 618 | return &smack_known_invalid; |
614 | } | 619 | } |
620 | |||
621 | /* | ||
622 | * Unless a process is running with one of these labels | ||
623 | * even having CAP_MAC_OVERRIDE isn't enough to grant | ||
624 | * privilege to violate MAC policy. If no labels are | ||
625 | * designated (the empty list case) capabilities apply to | ||
626 | * everyone. | ||
627 | */ | ||
628 | LIST_HEAD(smack_onlycap_list); | ||
629 | DEFINE_MUTEX(smack_onlycap_lock); | ||
630 | |||
631 | /* | ||
632 | * Is the task privileged and allowed to be privileged | ||
633 | * by the onlycap rule. | ||
634 | * | ||
635 | * Returns 1 if the task is allowed to be privileged, 0 if it's not. | ||
636 | */ | ||
637 | int smack_privileged(int cap) | ||
638 | { | ||
639 | struct smack_known *skp = smk_of_current(); | ||
640 | struct smack_onlycap *sop; | ||
641 | |||
642 | if (!capable(cap)) | ||
643 | return 0; | ||
644 | |||
645 | rcu_read_lock(); | ||
646 | if (list_empty(&smack_onlycap_list)) { | ||
647 | rcu_read_unlock(); | ||
648 | return 1; | ||
649 | } | ||
650 | |||
651 | list_for_each_entry_rcu(sop, &smack_onlycap_list, list) { | ||
652 | if (sop->smk_label == skp) { | ||
653 | rcu_read_unlock(); | ||
654 | return 1; | ||
655 | } | ||
656 | } | ||
657 | rcu_read_unlock(); | ||
658 | |||
659 | return 0; | ||
660 | } | ||
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 5eae42c8d0d5..a143328f75eb 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c | |||
@@ -245,8 +245,8 @@ static int smk_bu_credfile(const struct cred *cred, struct file *file, | |||
245 | * @ip: a pointer to the inode | 245 | * @ip: a pointer to the inode |
246 | * @dp: a pointer to the dentry | 246 | * @dp: a pointer to the dentry |
247 | * | 247 | * |
248 | * Returns a pointer to the master list entry for the Smack label | 248 | * Returns a pointer to the master list entry for the Smack label, |
249 | * or NULL if there was no label to fetch. | 249 | * NULL if there was no label to fetch, or an error code. |
250 | */ | 250 | */ |
251 | static struct smack_known *smk_fetch(const char *name, struct inode *ip, | 251 | static struct smack_known *smk_fetch(const char *name, struct inode *ip, |
252 | struct dentry *dp) | 252 | struct dentry *dp) |
@@ -256,14 +256,18 @@ static struct smack_known *smk_fetch(const char *name, struct inode *ip, | |||
256 | struct smack_known *skp = NULL; | 256 | struct smack_known *skp = NULL; |
257 | 257 | ||
258 | if (ip->i_op->getxattr == NULL) | 258 | if (ip->i_op->getxattr == NULL) |
259 | return NULL; | 259 | return ERR_PTR(-EOPNOTSUPP); |
260 | 260 | ||
261 | buffer = kzalloc(SMK_LONGLABEL, GFP_KERNEL); | 261 | buffer = kzalloc(SMK_LONGLABEL, GFP_KERNEL); |
262 | if (buffer == NULL) | 262 | if (buffer == NULL) |
263 | return NULL; | 263 | return ERR_PTR(-ENOMEM); |
264 | 264 | ||
265 | rc = ip->i_op->getxattr(dp, name, buffer, SMK_LONGLABEL); | 265 | rc = ip->i_op->getxattr(dp, name, buffer, SMK_LONGLABEL); |
266 | if (rc > 0) | 266 | if (rc < 0) |
267 | skp = ERR_PTR(rc); | ||
268 | else if (rc == 0) | ||
269 | skp = NULL; | ||
270 | else | ||
267 | skp = smk_import_entry(buffer, rc); | 271 | skp = smk_import_entry(buffer, rc); |
268 | 272 | ||
269 | kfree(buffer); | 273 | kfree(buffer); |
@@ -605,40 +609,44 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data) | |||
605 | if (strncmp(op, SMK_FSHAT, strlen(SMK_FSHAT)) == 0) { | 609 | if (strncmp(op, SMK_FSHAT, strlen(SMK_FSHAT)) == 0) { |
606 | op += strlen(SMK_FSHAT); | 610 | op += strlen(SMK_FSHAT); |
607 | skp = smk_import_entry(op, 0); | 611 | skp = smk_import_entry(op, 0); |
608 | if (skp != NULL) { | 612 | if (IS_ERR(skp)) |
609 | sp->smk_hat = skp; | 613 | return PTR_ERR(skp); |
610 | specified = 1; | 614 | sp->smk_hat = skp; |
611 | } | 615 | specified = 1; |
616 | |||
612 | } else if (strncmp(op, SMK_FSFLOOR, strlen(SMK_FSFLOOR)) == 0) { | 617 | } else if (strncmp(op, SMK_FSFLOOR, strlen(SMK_FSFLOOR)) == 0) { |
613 | op += strlen(SMK_FSFLOOR); | 618 | op += strlen(SMK_FSFLOOR); |
614 | skp = smk_import_entry(op, 0); | 619 | skp = smk_import_entry(op, 0); |
615 | if (skp != NULL) { | 620 | if (IS_ERR(skp)) |
616 | sp->smk_floor = skp; | 621 | return PTR_ERR(skp); |
617 | specified = 1; | 622 | sp->smk_floor = skp; |
618 | } | 623 | specified = 1; |
624 | |||
619 | } else if (strncmp(op, SMK_FSDEFAULT, | 625 | } else if (strncmp(op, SMK_FSDEFAULT, |
620 | strlen(SMK_FSDEFAULT)) == 0) { | 626 | strlen(SMK_FSDEFAULT)) == 0) { |
621 | op += strlen(SMK_FSDEFAULT); | 627 | op += strlen(SMK_FSDEFAULT); |
622 | skp = smk_import_entry(op, 0); | 628 | skp = smk_import_entry(op, 0); |
623 | if (skp != NULL) { | 629 | if (IS_ERR(skp)) |
624 | sp->smk_default = skp; | 630 | return PTR_ERR(skp); |
625 | specified = 1; | 631 | sp->smk_default = skp; |
626 | } | 632 | specified = 1; |
633 | |||
627 | } else if (strncmp(op, SMK_FSROOT, strlen(SMK_FSROOT)) == 0) { | 634 | } else if (strncmp(op, SMK_FSROOT, strlen(SMK_FSROOT)) == 0) { |
628 | op += strlen(SMK_FSROOT); | 635 | op += strlen(SMK_FSROOT); |
629 | skp = smk_import_entry(op, 0); | 636 | skp = smk_import_entry(op, 0); |
630 | if (skp != NULL) { | 637 | if (IS_ERR(skp)) |
631 | sp->smk_root = skp; | 638 | return PTR_ERR(skp); |
632 | specified = 1; | 639 | sp->smk_root = skp; |
633 | } | 640 | specified = 1; |
641 | |||
634 | } else if (strncmp(op, SMK_FSTRANS, strlen(SMK_FSTRANS)) == 0) { | 642 | } else if (strncmp(op, SMK_FSTRANS, strlen(SMK_FSTRANS)) == 0) { |
635 | op += strlen(SMK_FSTRANS); | 643 | op += strlen(SMK_FSTRANS); |
636 | skp = smk_import_entry(op, 0); | 644 | skp = smk_import_entry(op, 0); |
637 | if (skp != NULL) { | 645 | if (IS_ERR(skp)) |
638 | sp->smk_root = skp; | 646 | return PTR_ERR(skp); |
639 | transmute = 1; | 647 | sp->smk_root = skp; |
640 | specified = 1; | 648 | transmute = 1; |
641 | } | 649 | specified = 1; |
642 | } | 650 | } |
643 | } | 651 | } |
644 | 652 | ||
@@ -1118,7 +1126,9 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name, | |||
1118 | 1126 | ||
1119 | if (rc == 0 && check_import) { | 1127 | if (rc == 0 && check_import) { |
1120 | skp = size ? smk_import_entry(value, size) : NULL; | 1128 | skp = size ? smk_import_entry(value, size) : NULL; |
1121 | if (skp == NULL || (check_star && | 1129 | if (IS_ERR(skp)) |
1130 | rc = PTR_ERR(skp); | ||
1131 | else if (skp == NULL || (check_star && | ||
1122 | (skp == &smack_known_star || skp == &smack_known_web))) | 1132 | (skp == &smack_known_star || skp == &smack_known_web))) |
1123 | rc = -EINVAL; | 1133 | rc = -EINVAL; |
1124 | } | 1134 | } |
@@ -1158,19 +1168,19 @@ static void smack_inode_post_setxattr(struct dentry *dentry, const char *name, | |||
1158 | 1168 | ||
1159 | if (strcmp(name, XATTR_NAME_SMACK) == 0) { | 1169 | if (strcmp(name, XATTR_NAME_SMACK) == 0) { |
1160 | skp = smk_import_entry(value, size); | 1170 | skp = smk_import_entry(value, size); |
1161 | if (skp != NULL) | 1171 | if (!IS_ERR(skp)) |
1162 | isp->smk_inode = skp; | 1172 | isp->smk_inode = skp; |
1163 | else | 1173 | else |
1164 | isp->smk_inode = &smack_known_invalid; | 1174 | isp->smk_inode = &smack_known_invalid; |
1165 | } else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0) { | 1175 | } else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0) { |
1166 | skp = smk_import_entry(value, size); | 1176 | skp = smk_import_entry(value, size); |
1167 | if (skp != NULL) | 1177 | if (!IS_ERR(skp)) |
1168 | isp->smk_task = skp; | 1178 | isp->smk_task = skp; |
1169 | else | 1179 | else |
1170 | isp->smk_task = &smack_known_invalid; | 1180 | isp->smk_task = &smack_known_invalid; |
1171 | } else if (strcmp(name, XATTR_NAME_SMACKMMAP) == 0) { | 1181 | } else if (strcmp(name, XATTR_NAME_SMACKMMAP) == 0) { |
1172 | skp = smk_import_entry(value, size); | 1182 | skp = smk_import_entry(value, size); |
1173 | if (skp != NULL) | 1183 | if (!IS_ERR(skp)) |
1174 | isp->smk_mmap = skp; | 1184 | isp->smk_mmap = skp; |
1175 | else | 1185 | else |
1176 | isp->smk_mmap = &smack_known_invalid; | 1186 | isp->smk_mmap = &smack_known_invalid; |
@@ -1658,6 +1668,9 @@ static int smack_file_receive(struct file *file) | |||
1658 | struct smk_audit_info ad; | 1668 | struct smk_audit_info ad; |
1659 | struct inode *inode = file_inode(file); | 1669 | struct inode *inode = file_inode(file); |
1660 | 1670 | ||
1671 | if (unlikely(IS_PRIVATE(inode))) | ||
1672 | return 0; | ||
1673 | |||
1661 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); | 1674 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); |
1662 | smk_ad_setfield_u_fs_path(&ad, file->f_path); | 1675 | smk_ad_setfield_u_fs_path(&ad, file->f_path); |
1663 | /* | 1676 | /* |
@@ -2400,8 +2413,8 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name, | |||
2400 | return -EINVAL; | 2413 | return -EINVAL; |
2401 | 2414 | ||
2402 | skp = smk_import_entry(value, size); | 2415 | skp = smk_import_entry(value, size); |
2403 | if (skp == NULL) | 2416 | if (IS_ERR(skp)) |
2404 | return -EINVAL; | 2417 | return PTR_ERR(skp); |
2405 | 2418 | ||
2406 | if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) { | 2419 | if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) { |
2407 | nsp->smk_inode = skp; | 2420 | nsp->smk_inode = skp; |
@@ -3174,7 +3187,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) | |||
3174 | */ | 3187 | */ |
3175 | dp = dget(opt_dentry); | 3188 | dp = dget(opt_dentry); |
3176 | skp = smk_fetch(XATTR_NAME_SMACK, inode, dp); | 3189 | skp = smk_fetch(XATTR_NAME_SMACK, inode, dp); |
3177 | if (skp != NULL) | 3190 | if (!IS_ERR_OR_NULL(skp)) |
3178 | final = skp; | 3191 | final = skp; |
3179 | 3192 | ||
3180 | /* | 3193 | /* |
@@ -3211,11 +3224,14 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) | |||
3211 | * Don't let the exec or mmap label be "*" or "@". | 3224 | * Don't let the exec or mmap label be "*" or "@". |
3212 | */ | 3225 | */ |
3213 | skp = smk_fetch(XATTR_NAME_SMACKEXEC, inode, dp); | 3226 | skp = smk_fetch(XATTR_NAME_SMACKEXEC, inode, dp); |
3214 | if (skp == &smack_known_star || skp == &smack_known_web) | 3227 | if (IS_ERR(skp) || skp == &smack_known_star || |
3228 | skp == &smack_known_web) | ||
3215 | skp = NULL; | 3229 | skp = NULL; |
3216 | isp->smk_task = skp; | 3230 | isp->smk_task = skp; |
3231 | |||
3217 | skp = smk_fetch(XATTR_NAME_SMACKMMAP, inode, dp); | 3232 | skp = smk_fetch(XATTR_NAME_SMACKMMAP, inode, dp); |
3218 | if (skp == &smack_known_star || skp == &smack_known_web) | 3233 | if (IS_ERR(skp) || skp == &smack_known_star || |
3234 | skp == &smack_known_web) | ||
3219 | skp = NULL; | 3235 | skp = NULL; |
3220 | isp->smk_mmap = skp; | 3236 | isp->smk_mmap = skp; |
3221 | 3237 | ||
@@ -3299,8 +3315,8 @@ static int smack_setprocattr(struct task_struct *p, char *name, | |||
3299 | return -EINVAL; | 3315 | return -EINVAL; |
3300 | 3316 | ||
3301 | skp = smk_import_entry(value, size); | 3317 | skp = smk_import_entry(value, size); |
3302 | if (skp == NULL) | 3318 | if (IS_ERR(skp)) |
3303 | return -EINVAL; | 3319 | return PTR_ERR(skp); |
3304 | 3320 | ||
3305 | /* | 3321 | /* |
3306 | * No process is ever allowed the web ("@") label. | 3322 | * No process is ever allowed the web ("@") label. |
@@ -4075,8 +4091,10 @@ static int smack_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule) | |||
4075 | return -EINVAL; | 4091 | return -EINVAL; |
4076 | 4092 | ||
4077 | skp = smk_import_entry(rulestr, 0); | 4093 | skp = smk_import_entry(rulestr, 0); |
4078 | if (skp) | 4094 | if (IS_ERR(skp)) |
4079 | *rule = skp->smk_known; | 4095 | return PTR_ERR(skp); |
4096 | |||
4097 | *rule = skp->smk_known; | ||
4080 | 4098 | ||
4081 | return 0; | 4099 | return 0; |
4082 | } | 4100 | } |
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index 4aa12c8d3c63..f1c22a891b1a 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c | |||
@@ -87,16 +87,6 @@ int smack_cipso_direct = SMACK_CIPSO_DIRECT_DEFAULT; | |||
87 | */ | 87 | */ |
88 | int smack_cipso_mapped = SMACK_CIPSO_MAPPED_DEFAULT; | 88 | int smack_cipso_mapped = SMACK_CIPSO_MAPPED_DEFAULT; |
89 | 89 | ||
90 | /* | ||
91 | * Unless a process is running with this label even | ||
92 | * having CAP_MAC_OVERRIDE isn't enough to grant | ||
93 | * privilege to violate MAC policy. If no label is | ||
94 | * designated (the NULL case) capabilities apply to | ||
95 | * everyone. It is expected that the hat (^) label | ||
96 | * will be used if any label is used. | ||
97 | */ | ||
98 | struct smack_known *smack_onlycap; | ||
99 | |||
100 | #ifdef CONFIG_SECURITY_SMACK_BRINGUP | 90 | #ifdef CONFIG_SECURITY_SMACK_BRINGUP |
101 | /* | 91 | /* |
102 | * Allow one label to be unconfined. This is for | 92 | * Allow one label to be unconfined. This is for |
@@ -338,8 +328,7 @@ static int smk_perm_from_str(const char *string) | |||
338 | * @import: if non-zero, import labels | 328 | * @import: if non-zero, import labels |
339 | * @len: label length limit | 329 | * @len: label length limit |
340 | * | 330 | * |
341 | * Returns 0 on success, -EINVAL on failure and -ENOENT when either subject | 331 | * Returns 0 on success, appropriate error code on failure. |
342 | * or object is missing. | ||
343 | */ | 332 | */ |
344 | static int smk_fill_rule(const char *subject, const char *object, | 333 | static int smk_fill_rule(const char *subject, const char *object, |
345 | const char *access1, const char *access2, | 334 | const char *access1, const char *access2, |
@@ -351,16 +340,16 @@ static int smk_fill_rule(const char *subject, const char *object, | |||
351 | 340 | ||
352 | if (import) { | 341 | if (import) { |
353 | rule->smk_subject = smk_import_entry(subject, len); | 342 | rule->smk_subject = smk_import_entry(subject, len); |
354 | if (rule->smk_subject == NULL) | 343 | if (IS_ERR(rule->smk_subject)) |
355 | return -EINVAL; | 344 | return PTR_ERR(rule->smk_subject); |
356 | 345 | ||
357 | rule->smk_object = smk_import_entry(object, len); | 346 | rule->smk_object = smk_import_entry(object, len); |
358 | if (rule->smk_object == NULL) | 347 | if (IS_ERR(rule->smk_object)) |
359 | return -EINVAL; | 348 | return PTR_ERR(rule->smk_object); |
360 | } else { | 349 | } else { |
361 | cp = smk_parse_smack(subject, len); | 350 | cp = smk_parse_smack(subject, len); |
362 | if (cp == NULL) | 351 | if (IS_ERR(cp)) |
363 | return -EINVAL; | 352 | return PTR_ERR(cp); |
364 | skp = smk_find_entry(cp); | 353 | skp = smk_find_entry(cp); |
365 | kfree(cp); | 354 | kfree(cp); |
366 | if (skp == NULL) | 355 | if (skp == NULL) |
@@ -368,8 +357,8 @@ static int smk_fill_rule(const char *subject, const char *object, | |||
368 | rule->smk_subject = skp; | 357 | rule->smk_subject = skp; |
369 | 358 | ||
370 | cp = smk_parse_smack(object, len); | 359 | cp = smk_parse_smack(object, len); |
371 | if (cp == NULL) | 360 | if (IS_ERR(cp)) |
372 | return -EINVAL; | 361 | return PTR_ERR(cp); |
373 | skp = smk_find_entry(cp); | 362 | skp = smk_find_entry(cp); |
374 | kfree(cp); | 363 | kfree(cp); |
375 | if (skp == NULL) | 364 | if (skp == NULL) |
@@ -412,7 +401,7 @@ static int smk_parse_rule(const char *data, struct smack_parsed_rule *rule, | |||
412 | * @import: if non-zero, import labels | 401 | * @import: if non-zero, import labels |
413 | * @tokens: numer of substrings expected in data | 402 | * @tokens: numer of substrings expected in data |
414 | * | 403 | * |
415 | * Returns number of processed bytes on success, -1 on failure. | 404 | * Returns number of processed bytes on success, -ERRNO on failure. |
416 | */ | 405 | */ |
417 | static ssize_t smk_parse_long_rule(char *data, struct smack_parsed_rule *rule, | 406 | static ssize_t smk_parse_long_rule(char *data, struct smack_parsed_rule *rule, |
418 | int import, int tokens) | 407 | int import, int tokens) |
@@ -431,7 +420,7 @@ static ssize_t smk_parse_long_rule(char *data, struct smack_parsed_rule *rule, | |||
431 | 420 | ||
432 | if (data[cnt] == '\0') | 421 | if (data[cnt] == '\0') |
433 | /* Unexpected end of data */ | 422 | /* Unexpected end of data */ |
434 | return -1; | 423 | return -EINVAL; |
435 | 424 | ||
436 | tok[i] = data + cnt; | 425 | tok[i] = data + cnt; |
437 | 426 | ||
@@ -529,14 +518,14 @@ static ssize_t smk_write_rules_list(struct file *file, const char __user *buf, | |||
529 | while (cnt < count) { | 518 | while (cnt < count) { |
530 | if (format == SMK_FIXED24_FMT) { | 519 | if (format == SMK_FIXED24_FMT) { |
531 | rc = smk_parse_rule(data, &rule, 1); | 520 | rc = smk_parse_rule(data, &rule, 1); |
532 | if (rc != 0) { | 521 | if (rc < 0) |
533 | rc = -EINVAL; | ||
534 | goto out; | 522 | goto out; |
535 | } | ||
536 | cnt = count; | 523 | cnt = count; |
537 | } else { | 524 | } else { |
538 | rc = smk_parse_long_rule(data + cnt, &rule, 1, tokens); | 525 | rc = smk_parse_long_rule(data + cnt, &rule, 1, tokens); |
539 | if (rc <= 0) { | 526 | if (rc < 0) |
527 | goto out; | ||
528 | if (rc == 0) { | ||
540 | rc = -EINVAL; | 529 | rc = -EINVAL; |
541 | goto out; | 530 | goto out; |
542 | } | 531 | } |
@@ -567,23 +556,17 @@ static void *smk_seq_start(struct seq_file *s, loff_t *pos, | |||
567 | struct list_head *head) | 556 | struct list_head *head) |
568 | { | 557 | { |
569 | struct list_head *list; | 558 | struct list_head *list; |
559 | int i = *pos; | ||
560 | |||
561 | rcu_read_lock(); | ||
562 | for (list = rcu_dereference(list_next_rcu(head)); | ||
563 | list != head; | ||
564 | list = rcu_dereference(list_next_rcu(list))) { | ||
565 | if (i-- == 0) | ||
566 | return list; | ||
567 | } | ||
570 | 568 | ||
571 | /* | 569 | return NULL; |
572 | * This is 0 the first time through. | ||
573 | */ | ||
574 | if (s->index == 0) | ||
575 | s->private = head; | ||
576 | |||
577 | if (s->private == NULL) | ||
578 | return NULL; | ||
579 | |||
580 | list = s->private; | ||
581 | if (list_empty(list)) | ||
582 | return NULL; | ||
583 | |||
584 | if (s->index == 0) | ||
585 | return list->next; | ||
586 | return list; | ||
587 | } | 570 | } |
588 | 571 | ||
589 | static void *smk_seq_next(struct seq_file *s, void *v, loff_t *pos, | 572 | static void *smk_seq_next(struct seq_file *s, void *v, loff_t *pos, |
@@ -591,17 +574,15 @@ static void *smk_seq_next(struct seq_file *s, void *v, loff_t *pos, | |||
591 | { | 574 | { |
592 | struct list_head *list = v; | 575 | struct list_head *list = v; |
593 | 576 | ||
594 | if (list_is_last(list, head)) { | 577 | ++*pos; |
595 | s->private = NULL; | 578 | list = rcu_dereference(list_next_rcu(list)); |
596 | return NULL; | 579 | |
597 | } | 580 | return (list == head) ? NULL : list; |
598 | s->private = list->next; | ||
599 | return list->next; | ||
600 | } | 581 | } |
601 | 582 | ||
602 | static void smk_seq_stop(struct seq_file *s, void *v) | 583 | static void smk_seq_stop(struct seq_file *s, void *v) |
603 | { | 584 | { |
604 | /* No-op */ | 585 | rcu_read_unlock(); |
605 | } | 586 | } |
606 | 587 | ||
607 | static void smk_rule_show(struct seq_file *s, struct smack_rule *srp, int max) | 588 | static void smk_rule_show(struct seq_file *s, struct smack_rule *srp, int max) |
@@ -661,7 +642,7 @@ static int load_seq_show(struct seq_file *s, void *v) | |||
661 | { | 642 | { |
662 | struct list_head *list = v; | 643 | struct list_head *list = v; |
663 | struct smack_master_list *smlp = | 644 | struct smack_master_list *smlp = |
664 | list_entry(list, struct smack_master_list, list); | 645 | list_entry_rcu(list, struct smack_master_list, list); |
665 | 646 | ||
666 | smk_rule_show(s, smlp->smk_rule, SMK_LABELLEN); | 647 | smk_rule_show(s, smlp->smk_rule, SMK_LABELLEN); |
667 | 648 | ||
@@ -809,7 +790,7 @@ static int cipso_seq_show(struct seq_file *s, void *v) | |||
809 | { | 790 | { |
810 | struct list_head *list = v; | 791 | struct list_head *list = v; |
811 | struct smack_known *skp = | 792 | struct smack_known *skp = |
812 | list_entry(list, struct smack_known, list); | 793 | list_entry_rcu(list, struct smack_known, list); |
813 | struct netlbl_lsm_catmap *cmp = skp->smk_netlabel.attr.mls.cat; | 794 | struct netlbl_lsm_catmap *cmp = skp->smk_netlabel.attr.mls.cat; |
814 | char sep = '/'; | 795 | char sep = '/'; |
815 | int i; | 796 | int i; |
@@ -915,8 +896,10 @@ static ssize_t smk_set_cipso(struct file *file, const char __user *buf, | |||
915 | mutex_lock(&smack_cipso_lock); | 896 | mutex_lock(&smack_cipso_lock); |
916 | 897 | ||
917 | skp = smk_import_entry(rule, 0); | 898 | skp = smk_import_entry(rule, 0); |
918 | if (skp == NULL) | 899 | if (IS_ERR(skp)) { |
900 | rc = PTR_ERR(skp); | ||
919 | goto out; | 901 | goto out; |
902 | } | ||
920 | 903 | ||
921 | if (format == SMK_FIXED24_FMT) | 904 | if (format == SMK_FIXED24_FMT) |
922 | rule += SMK_LABELLEN; | 905 | rule += SMK_LABELLEN; |
@@ -998,7 +981,7 @@ static int cipso2_seq_show(struct seq_file *s, void *v) | |||
998 | { | 981 | { |
999 | struct list_head *list = v; | 982 | struct list_head *list = v; |
1000 | struct smack_known *skp = | 983 | struct smack_known *skp = |
1001 | list_entry(list, struct smack_known, list); | 984 | list_entry_rcu(list, struct smack_known, list); |
1002 | struct netlbl_lsm_catmap *cmp = skp->smk_netlabel.attr.mls.cat; | 985 | struct netlbl_lsm_catmap *cmp = skp->smk_netlabel.attr.mls.cat; |
1003 | char sep = '/'; | 986 | char sep = '/'; |
1004 | int i; | 987 | int i; |
@@ -1082,7 +1065,7 @@ static int netlbladdr_seq_show(struct seq_file *s, void *v) | |||
1082 | { | 1065 | { |
1083 | struct list_head *list = v; | 1066 | struct list_head *list = v; |
1084 | struct smk_netlbladdr *skp = | 1067 | struct smk_netlbladdr *skp = |
1085 | list_entry(list, struct smk_netlbladdr, list); | 1068 | list_entry_rcu(list, struct smk_netlbladdr, list); |
1086 | unsigned char *hp = (char *) &skp->smk_host.sin_addr.s_addr; | 1069 | unsigned char *hp = (char *) &skp->smk_host.sin_addr.s_addr; |
1087 | int maskn; | 1070 | int maskn; |
1088 | u32 temp_mask = be32_to_cpu(skp->smk_mask.s_addr); | 1071 | u32 temp_mask = be32_to_cpu(skp->smk_mask.s_addr); |
@@ -1237,8 +1220,8 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, | |||
1237 | */ | 1220 | */ |
1238 | if (smack[0] != '-') { | 1221 | if (smack[0] != '-') { |
1239 | skp = smk_import_entry(smack, 0); | 1222 | skp = smk_import_entry(smack, 0); |
1240 | if (skp == NULL) { | 1223 | if (IS_ERR(skp)) { |
1241 | rc = -EINVAL; | 1224 | rc = PTR_ERR(skp); |
1242 | goto free_out; | 1225 | goto free_out; |
1243 | } | 1226 | } |
1244 | } else { | 1227 | } else { |
@@ -1619,8 +1602,8 @@ static ssize_t smk_write_ambient(struct file *file, const char __user *buf, | |||
1619 | } | 1602 | } |
1620 | 1603 | ||
1621 | skp = smk_import_entry(data, count); | 1604 | skp = smk_import_entry(data, count); |
1622 | if (skp == NULL) { | 1605 | if (IS_ERR(skp)) { |
1623 | rc = -EINVAL; | 1606 | rc = PTR_ERR(skp); |
1624 | goto out; | 1607 | goto out; |
1625 | } | 1608 | } |
1626 | 1609 | ||
@@ -1643,34 +1626,79 @@ static const struct file_operations smk_ambient_ops = { | |||
1643 | .llseek = default_llseek, | 1626 | .llseek = default_llseek, |
1644 | }; | 1627 | }; |
1645 | 1628 | ||
1646 | /** | 1629 | /* |
1647 | * smk_read_onlycap - read() for smackfs/onlycap | 1630 | * Seq_file operations for /smack/onlycap |
1648 | * @filp: file pointer, not actually used | ||
1649 | * @buf: where to put the result | ||
1650 | * @cn: maximum to send along | ||
1651 | * @ppos: where to start | ||
1652 | * | ||
1653 | * Returns number of bytes read or error code, as appropriate | ||
1654 | */ | 1631 | */ |
1655 | static ssize_t smk_read_onlycap(struct file *filp, char __user *buf, | 1632 | static void *onlycap_seq_start(struct seq_file *s, loff_t *pos) |
1656 | size_t cn, loff_t *ppos) | ||
1657 | { | 1633 | { |
1658 | char *smack = ""; | 1634 | return smk_seq_start(s, pos, &smack_onlycap_list); |
1659 | ssize_t rc = -EINVAL; | 1635 | } |
1660 | int asize; | ||
1661 | 1636 | ||
1662 | if (*ppos != 0) | 1637 | static void *onlycap_seq_next(struct seq_file *s, void *v, loff_t *pos) |
1663 | return 0; | 1638 | { |
1639 | return smk_seq_next(s, v, pos, &smack_onlycap_list); | ||
1640 | } | ||
1664 | 1641 | ||
1665 | if (smack_onlycap != NULL) | 1642 | static int onlycap_seq_show(struct seq_file *s, void *v) |
1666 | smack = smack_onlycap->smk_known; | 1643 | { |
1644 | struct list_head *list = v; | ||
1645 | struct smack_onlycap *sop = | ||
1646 | list_entry_rcu(list, struct smack_onlycap, list); | ||
1667 | 1647 | ||
1668 | asize = strlen(smack) + 1; | 1648 | seq_puts(s, sop->smk_label->smk_known); |
1649 | seq_putc(s, ' '); | ||
1669 | 1650 | ||
1670 | if (cn >= asize) | 1651 | return 0; |
1671 | rc = simple_read_from_buffer(buf, cn, ppos, smack, asize); | 1652 | } |
1672 | 1653 | ||
1673 | return rc; | 1654 | static const struct seq_operations onlycap_seq_ops = { |
1655 | .start = onlycap_seq_start, | ||
1656 | .next = onlycap_seq_next, | ||
1657 | .show = onlycap_seq_show, | ||
1658 | .stop = smk_seq_stop, | ||
1659 | }; | ||
1660 | |||
1661 | static int smk_open_onlycap(struct inode *inode, struct file *file) | ||
1662 | { | ||
1663 | return seq_open(file, &onlycap_seq_ops); | ||
1664 | } | ||
1665 | |||
1666 | /** | ||
1667 | * smk_list_swap_rcu - swap public list with a private one in RCU-safe way | ||
1668 | * The caller must hold appropriate mutex to prevent concurrent modifications | ||
1669 | * to the public list. | ||
1670 | * Private list is assumed to be not accessible to other threads yet. | ||
1671 | * | ||
1672 | * @public: public list | ||
1673 | * @private: private list | ||
1674 | */ | ||
1675 | static void smk_list_swap_rcu(struct list_head *public, | ||
1676 | struct list_head *private) | ||
1677 | { | ||
1678 | struct list_head *first, *last; | ||
1679 | |||
1680 | if (list_empty(public)) { | ||
1681 | list_splice_init_rcu(private, public, synchronize_rcu); | ||
1682 | } else { | ||
1683 | /* Remember public list before replacing it */ | ||
1684 | first = public->next; | ||
1685 | last = public->prev; | ||
1686 | |||
1687 | /* Publish private list in place of public in RCU-safe way */ | ||
1688 | private->prev->next = public; | ||
1689 | private->next->prev = public; | ||
1690 | rcu_assign_pointer(public->next, private->next); | ||
1691 | public->prev = private->prev; | ||
1692 | |||
1693 | synchronize_rcu(); | ||
1694 | |||
1695 | /* When all readers are done with the old public list, | ||
1696 | * attach it in place of private */ | ||
1697 | private->next = first; | ||
1698 | private->prev = last; | ||
1699 | first->prev = private; | ||
1700 | last->next = private; | ||
1701 | } | ||
1674 | } | 1702 | } |
1675 | 1703 | ||
1676 | /** | 1704 | /** |
@@ -1686,47 +1714,79 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf, | |||
1686 | size_t count, loff_t *ppos) | 1714 | size_t count, loff_t *ppos) |
1687 | { | 1715 | { |
1688 | char *data; | 1716 | char *data; |
1689 | struct smack_known *skp = smk_of_task(current->cred->security); | 1717 | char *data_parse; |
1718 | char *tok; | ||
1719 | struct smack_known *skp; | ||
1720 | struct smack_onlycap *sop; | ||
1721 | struct smack_onlycap *sop2; | ||
1722 | LIST_HEAD(list_tmp); | ||
1690 | int rc = count; | 1723 | int rc = count; |
1691 | 1724 | ||
1692 | if (!smack_privileged(CAP_MAC_ADMIN)) | 1725 | if (!smack_privileged(CAP_MAC_ADMIN)) |
1693 | return -EPERM; | 1726 | return -EPERM; |
1694 | 1727 | ||
1695 | /* | ||
1696 | * This can be done using smk_access() but is done | ||
1697 | * explicitly for clarity. The smk_access() implementation | ||
1698 | * would use smk_access(smack_onlycap, MAY_WRITE) | ||
1699 | */ | ||
1700 | if (smack_onlycap != NULL && smack_onlycap != skp) | ||
1701 | return -EPERM; | ||
1702 | |||
1703 | data = kzalloc(count + 1, GFP_KERNEL); | 1728 | data = kzalloc(count + 1, GFP_KERNEL); |
1704 | if (data == NULL) | 1729 | if (data == NULL) |
1705 | return -ENOMEM; | 1730 | return -ENOMEM; |
1706 | 1731 | ||
1732 | if (copy_from_user(data, buf, count) != 0) { | ||
1733 | kfree(data); | ||
1734 | return -EFAULT; | ||
1735 | } | ||
1736 | |||
1737 | data_parse = data; | ||
1738 | while ((tok = strsep(&data_parse, " ")) != NULL) { | ||
1739 | if (!*tok) | ||
1740 | continue; | ||
1741 | |||
1742 | skp = smk_import_entry(tok, 0); | ||
1743 | if (IS_ERR(skp)) { | ||
1744 | rc = PTR_ERR(skp); | ||
1745 | break; | ||
1746 | } | ||
1747 | |||
1748 | sop = kzalloc(sizeof(*sop), GFP_KERNEL); | ||
1749 | if (sop == NULL) { | ||
1750 | rc = -ENOMEM; | ||
1751 | break; | ||
1752 | } | ||
1753 | |||
1754 | sop->smk_label = skp; | ||
1755 | list_add_rcu(&sop->list, &list_tmp); | ||
1756 | } | ||
1757 | kfree(data); | ||
1758 | |||
1707 | /* | 1759 | /* |
1708 | * Should the null string be passed in unset the onlycap value. | 1760 | * Clear the smack_onlycap on invalid label errors. This means |
1709 | * This seems like something to be careful with as usually | 1761 | * that we can pass a null string to unset the onlycap value. |
1710 | * smk_import only expects to return NULL for errors. It | ||
1711 | * is usually the case that a nullstring or "\n" would be | ||
1712 | * bad to pass to smk_import but in fact this is useful here. | ||
1713 | * | 1762 | * |
1714 | * smk_import will also reject a label beginning with '-', | 1763 | * Importing will also reject a label beginning with '-', |
1715 | * so "-usecapabilities" will also work. | 1764 | * so "-usecapabilities" will also work. |
1765 | * | ||
1766 | * But do so only on invalid label, not on system errors. | ||
1767 | * The invalid label must be first to count as clearing attempt. | ||
1716 | */ | 1768 | */ |
1717 | if (copy_from_user(data, buf, count) != 0) | 1769 | if (rc == -EINVAL && list_empty(&list_tmp)) |
1718 | rc = -EFAULT; | 1770 | rc = count; |
1719 | else | 1771 | |
1720 | smack_onlycap = smk_import_entry(data, count); | 1772 | if (rc >= 0) { |
1773 | mutex_lock(&smack_onlycap_lock); | ||
1774 | smk_list_swap_rcu(&smack_onlycap_list, &list_tmp); | ||
1775 | mutex_unlock(&smack_onlycap_lock); | ||
1776 | } | ||
1777 | |||
1778 | list_for_each_entry_safe(sop, sop2, &list_tmp, list) | ||
1779 | kfree(sop); | ||
1721 | 1780 | ||
1722 | kfree(data); | ||
1723 | return rc; | 1781 | return rc; |
1724 | } | 1782 | } |
1725 | 1783 | ||
1726 | static const struct file_operations smk_onlycap_ops = { | 1784 | static const struct file_operations smk_onlycap_ops = { |
1727 | .read = smk_read_onlycap, | 1785 | .open = smk_open_onlycap, |
1786 | .read = seq_read, | ||
1728 | .write = smk_write_onlycap, | 1787 | .write = smk_write_onlycap, |
1729 | .llseek = default_llseek, | 1788 | .llseek = seq_lseek, |
1789 | .release = seq_release, | ||
1730 | }; | 1790 | }; |
1731 | 1791 | ||
1732 | #ifdef CONFIG_SECURITY_SMACK_BRINGUP | 1792 | #ifdef CONFIG_SECURITY_SMACK_BRINGUP |
@@ -1773,6 +1833,7 @@ static ssize_t smk_write_unconfined(struct file *file, const char __user *buf, | |||
1773 | size_t count, loff_t *ppos) | 1833 | size_t count, loff_t *ppos) |
1774 | { | 1834 | { |
1775 | char *data; | 1835 | char *data; |
1836 | struct smack_known *skp; | ||
1776 | int rc = count; | 1837 | int rc = count; |
1777 | 1838 | ||
1778 | if (!smack_privileged(CAP_MAC_ADMIN)) | 1839 | if (!smack_privileged(CAP_MAC_ADMIN)) |
@@ -1782,21 +1843,31 @@ static ssize_t smk_write_unconfined(struct file *file, const char __user *buf, | |||
1782 | if (data == NULL) | 1843 | if (data == NULL) |
1783 | return -ENOMEM; | 1844 | return -ENOMEM; |
1784 | 1845 | ||
1846 | if (copy_from_user(data, buf, count) != 0) { | ||
1847 | rc = -EFAULT; | ||
1848 | goto freeout; | ||
1849 | } | ||
1850 | |||
1785 | /* | 1851 | /* |
1786 | * Should the null string be passed in unset the unconfined value. | 1852 | * Clear the smack_unconfined on invalid label errors. This means |
1787 | * This seems like something to be careful with as usually | 1853 | * that we can pass a null string to unset the unconfined value. |
1788 | * smk_import only expects to return NULL for errors. It | ||
1789 | * is usually the case that a nullstring or "\n" would be | ||
1790 | * bad to pass to smk_import but in fact this is useful here. | ||
1791 | * | 1854 | * |
1792 | * smk_import will also reject a label beginning with '-', | 1855 | * Importing will also reject a label beginning with '-', |
1793 | * so "-confine" will also work. | 1856 | * so "-confine" will also work. |
1857 | * | ||
1858 | * But do so only on invalid label, not on system errors. | ||
1794 | */ | 1859 | */ |
1795 | if (copy_from_user(data, buf, count) != 0) | 1860 | skp = smk_import_entry(data, count); |
1796 | rc = -EFAULT; | 1861 | if (PTR_ERR(skp) == -EINVAL) |
1797 | else | 1862 | skp = NULL; |
1798 | smack_unconfined = smk_import_entry(data, count); | 1863 | else if (IS_ERR(skp)) { |
1864 | rc = PTR_ERR(skp); | ||
1865 | goto freeout; | ||
1866 | } | ||
1867 | |||
1868 | smack_unconfined = skp; | ||
1799 | 1869 | ||
1870 | freeout: | ||
1800 | kfree(data); | 1871 | kfree(data); |
1801 | return rc; | 1872 | return rc; |
1802 | } | 1873 | } |
@@ -1895,7 +1966,7 @@ static int load_self_seq_show(struct seq_file *s, void *v) | |||
1895 | { | 1966 | { |
1896 | struct list_head *list = v; | 1967 | struct list_head *list = v; |
1897 | struct smack_rule *srp = | 1968 | struct smack_rule *srp = |
1898 | list_entry(list, struct smack_rule, list); | 1969 | list_entry_rcu(list, struct smack_rule, list); |
1899 | 1970 | ||
1900 | smk_rule_show(s, srp, SMK_LABELLEN); | 1971 | smk_rule_show(s, srp, SMK_LABELLEN); |
1901 | 1972 | ||
@@ -1980,7 +2051,7 @@ static ssize_t smk_user_access(struct file *file, const char __user *buf, | |||
1980 | res = smk_access(rule.smk_subject, rule.smk_object, | 2051 | res = smk_access(rule.smk_subject, rule.smk_object, |
1981 | rule.smk_access1, NULL); | 2052 | rule.smk_access1, NULL); |
1982 | else if (res != -ENOENT) | 2053 | else if (res != -ENOENT) |
1983 | return -EINVAL; | 2054 | return res; |
1984 | 2055 | ||
1985 | /* | 2056 | /* |
1986 | * smk_access() can return a value > 0 in the "bringup" case. | 2057 | * smk_access() can return a value > 0 in the "bringup" case. |
@@ -2024,7 +2095,7 @@ static int load2_seq_show(struct seq_file *s, void *v) | |||
2024 | { | 2095 | { |
2025 | struct list_head *list = v; | 2096 | struct list_head *list = v; |
2026 | struct smack_master_list *smlp = | 2097 | struct smack_master_list *smlp = |
2027 | list_entry(list, struct smack_master_list, list); | 2098 | list_entry_rcu(list, struct smack_master_list, list); |
2028 | 2099 | ||
2029 | smk_rule_show(s, smlp->smk_rule, SMK_LONGLABEL); | 2100 | smk_rule_show(s, smlp->smk_rule, SMK_LONGLABEL); |
2030 | 2101 | ||
@@ -2101,7 +2172,7 @@ static int load_self2_seq_show(struct seq_file *s, void *v) | |||
2101 | { | 2172 | { |
2102 | struct list_head *list = v; | 2173 | struct list_head *list = v; |
2103 | struct smack_rule *srp = | 2174 | struct smack_rule *srp = |
2104 | list_entry(list, struct smack_rule, list); | 2175 | list_entry_rcu(list, struct smack_rule, list); |
2105 | 2176 | ||
2106 | smk_rule_show(s, srp, SMK_LONGLABEL); | 2177 | smk_rule_show(s, srp, SMK_LONGLABEL); |
2107 | 2178 | ||
@@ -2209,8 +2280,8 @@ static ssize_t smk_write_revoke_subj(struct file *file, const char __user *buf, | |||
2209 | } | 2280 | } |
2210 | 2281 | ||
2211 | cp = smk_parse_smack(data, count); | 2282 | cp = smk_parse_smack(data, count); |
2212 | if (cp == NULL) { | 2283 | if (IS_ERR(cp)) { |
2213 | rc = -EINVAL; | 2284 | rc = PTR_ERR(cp); |
2214 | goto free_out; | 2285 | goto free_out; |
2215 | } | 2286 | } |
2216 | 2287 | ||
@@ -2341,10 +2412,10 @@ static ssize_t smk_write_syslog(struct file *file, const char __user *buf, | |||
2341 | rc = -EFAULT; | 2412 | rc = -EFAULT; |
2342 | else { | 2413 | else { |
2343 | skp = smk_import_entry(data, count); | 2414 | skp = smk_import_entry(data, count); |
2344 | if (skp == NULL) | 2415 | if (IS_ERR(skp)) |
2345 | rc = -EINVAL; | 2416 | rc = PTR_ERR(skp); |
2346 | else | 2417 | else |
2347 | smack_syslog_label = smk_import_entry(data, count); | 2418 | smack_syslog_label = skp; |
2348 | } | 2419 | } |
2349 | 2420 | ||
2350 | kfree(data); | 2421 | kfree(data); |