diff options
Diffstat (limited to 'security/selinux/ss/services.c')
-rw-r--r-- | security/selinux/ss/services.c | 245 |
1 files changed, 173 insertions, 72 deletions
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index dcc2e1c4fd83..b86ac9da6cf3 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
@@ -616,6 +616,14 @@ static int context_struct_to_string(struct context *context, char **scontext, u3 | |||
616 | *scontext = NULL; | 616 | *scontext = NULL; |
617 | *scontext_len = 0; | 617 | *scontext_len = 0; |
618 | 618 | ||
619 | if (context->len) { | ||
620 | *scontext_len = context->len; | ||
621 | *scontext = kstrdup(context->str, GFP_ATOMIC); | ||
622 | if (!(*scontext)) | ||
623 | return -ENOMEM; | ||
624 | return 0; | ||
625 | } | ||
626 | |||
619 | /* Compute the size of the context. */ | 627 | /* Compute the size of the context. */ |
620 | *scontext_len += strlen(policydb.p_user_val_to_name[context->user - 1]) + 1; | 628 | *scontext_len += strlen(policydb.p_user_val_to_name[context->user - 1]) + 1; |
621 | *scontext_len += strlen(policydb.p_role_val_to_name[context->role - 1]) + 1; | 629 | *scontext_len += strlen(policydb.p_role_val_to_name[context->role - 1]) + 1; |
@@ -655,17 +663,8 @@ const char *security_get_initial_sid_context(u32 sid) | |||
655 | return initial_sid_to_string[sid]; | 663 | return initial_sid_to_string[sid]; |
656 | } | 664 | } |
657 | 665 | ||
658 | /** | 666 | static int security_sid_to_context_core(u32 sid, char **scontext, |
659 | * security_sid_to_context - Obtain a context for a given SID. | 667 | u32 *scontext_len, int force) |
660 | * @sid: security identifier, SID | ||
661 | * @scontext: security context | ||
662 | * @scontext_len: length in bytes | ||
663 | * | ||
664 | * Write the string representation of the context associated with @sid | ||
665 | * into a dynamically allocated string of the correct size. Set @scontext | ||
666 | * to point to this string and set @scontext_len to the length of the string. | ||
667 | */ | ||
668 | int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len) | ||
669 | { | 668 | { |
670 | struct context *context; | 669 | struct context *context; |
671 | int rc = 0; | 670 | int rc = 0; |
@@ -693,7 +692,10 @@ int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len) | |||
693 | goto out; | 692 | goto out; |
694 | } | 693 | } |
695 | POLICY_RDLOCK; | 694 | POLICY_RDLOCK; |
696 | context = sidtab_search(&sidtab, sid); | 695 | if (force) |
696 | context = sidtab_search_force(&sidtab, sid); | ||
697 | else | ||
698 | context = sidtab_search(&sidtab, sid); | ||
697 | if (!context) { | 699 | if (!context) { |
698 | printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", | 700 | printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", |
699 | __func__, sid); | 701 | __func__, sid); |
@@ -708,36 +710,44 @@ out: | |||
708 | 710 | ||
709 | } | 711 | } |
710 | 712 | ||
711 | static int security_context_to_sid_core(const char *scontext, u32 scontext_len, | 713 | /** |
712 | u32 *sid, u32 def_sid, gfp_t gfp_flags) | 714 | * security_sid_to_context - Obtain a context for a given SID. |
715 | * @sid: security identifier, SID | ||
716 | * @scontext: security context | ||
717 | * @scontext_len: length in bytes | ||
718 | * | ||
719 | * Write the string representation of the context associated with @sid | ||
720 | * into a dynamically allocated string of the correct size. Set @scontext | ||
721 | * to point to this string and set @scontext_len to the length of the string. | ||
722 | */ | ||
723 | int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len) | ||
713 | { | 724 | { |
714 | char *scontext2; | 725 | return security_sid_to_context_core(sid, scontext, scontext_len, 0); |
715 | struct context context; | 726 | } |
727 | |||
728 | int security_sid_to_context_force(u32 sid, char **scontext, u32 *scontext_len) | ||
729 | { | ||
730 | return security_sid_to_context_core(sid, scontext, scontext_len, 1); | ||
731 | } | ||
732 | |||
733 | static int string_to_context_struct(struct policydb *pol, | ||
734 | struct sidtab *sidtabp, | ||
735 | const char *scontext, | ||
736 | u32 scontext_len, | ||
737 | struct context *ctx, | ||
738 | u32 def_sid, | ||
739 | gfp_t gfp_flags) | ||
740 | { | ||
741 | char *scontext2 = NULL; | ||
716 | struct role_datum *role; | 742 | struct role_datum *role; |
717 | struct type_datum *typdatum; | 743 | struct type_datum *typdatum; |
718 | struct user_datum *usrdatum; | 744 | struct user_datum *usrdatum; |
719 | char *scontextp, *p, oldc; | 745 | char *scontextp, *p, oldc; |
720 | int rc = 0; | 746 | int rc = 0; |
721 | 747 | ||
722 | if (!ss_initialized) { | 748 | context_init(ctx); |
723 | int i; | ||
724 | 749 | ||
725 | for (i = 1; i < SECINITSID_NUM; i++) { | 750 | /* Copy the string so that we can modify the copy as we parse it. */ |
726 | if (!strcmp(initial_sid_to_string[i], scontext)) { | ||
727 | *sid = i; | ||
728 | goto out; | ||
729 | } | ||
730 | } | ||
731 | *sid = SECINITSID_KERNEL; | ||
732 | goto out; | ||
733 | } | ||
734 | *sid = SECSID_NULL; | ||
735 | |||
736 | /* Copy the string so that we can modify the copy as we parse it. | ||
737 | The string should already by null terminated, but we append a | ||
738 | null suffix to the copy to avoid problems with the existing | ||
739 | attr package, which doesn't view the null terminator as part | ||
740 | of the attribute value. */ | ||
741 | scontext2 = kmalloc(scontext_len+1, gfp_flags); | 751 | scontext2 = kmalloc(scontext_len+1, gfp_flags); |
742 | if (!scontext2) { | 752 | if (!scontext2) { |
743 | rc = -ENOMEM; | 753 | rc = -ENOMEM; |
@@ -746,11 +756,6 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len, | |||
746 | memcpy(scontext2, scontext, scontext_len); | 756 | memcpy(scontext2, scontext, scontext_len); |
747 | scontext2[scontext_len] = 0; | 757 | scontext2[scontext_len] = 0; |
748 | 758 | ||
749 | context_init(&context); | ||
750 | *sid = SECSID_NULL; | ||
751 | |||
752 | POLICY_RDLOCK; | ||
753 | |||
754 | /* Parse the security context. */ | 759 | /* Parse the security context. */ |
755 | 760 | ||
756 | rc = -EINVAL; | 761 | rc = -EINVAL; |
@@ -762,15 +767,15 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len, | |||
762 | p++; | 767 | p++; |
763 | 768 | ||
764 | if (*p == 0) | 769 | if (*p == 0) |
765 | goto out_unlock; | 770 | goto out; |
766 | 771 | ||
767 | *p++ = 0; | 772 | *p++ = 0; |
768 | 773 | ||
769 | usrdatum = hashtab_search(policydb.p_users.table, scontextp); | 774 | usrdatum = hashtab_search(pol->p_users.table, scontextp); |
770 | if (!usrdatum) | 775 | if (!usrdatum) |
771 | goto out_unlock; | 776 | goto out; |
772 | 777 | ||
773 | context.user = usrdatum->value; | 778 | ctx->user = usrdatum->value; |
774 | 779 | ||
775 | /* Extract role. */ | 780 | /* Extract role. */ |
776 | scontextp = p; | 781 | scontextp = p; |
@@ -778,14 +783,14 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len, | |||
778 | p++; | 783 | p++; |
779 | 784 | ||
780 | if (*p == 0) | 785 | if (*p == 0) |
781 | goto out_unlock; | 786 | goto out; |
782 | 787 | ||
783 | *p++ = 0; | 788 | *p++ = 0; |
784 | 789 | ||
785 | role = hashtab_search(policydb.p_roles.table, scontextp); | 790 | role = hashtab_search(pol->p_roles.table, scontextp); |
786 | if (!role) | 791 | if (!role) |
787 | goto out_unlock; | 792 | goto out; |
788 | context.role = role->value; | 793 | ctx->role = role->value; |
789 | 794 | ||
790 | /* Extract type. */ | 795 | /* Extract type. */ |
791 | scontextp = p; | 796 | scontextp = p; |
@@ -794,33 +799,74 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len, | |||
794 | oldc = *p; | 799 | oldc = *p; |
795 | *p++ = 0; | 800 | *p++ = 0; |
796 | 801 | ||
797 | typdatum = hashtab_search(policydb.p_types.table, scontextp); | 802 | typdatum = hashtab_search(pol->p_types.table, scontextp); |
798 | if (!typdatum) | 803 | if (!typdatum) |
799 | goto out_unlock; | 804 | goto out; |
800 | 805 | ||
801 | context.type = typdatum->value; | 806 | ctx->type = typdatum->value; |
802 | 807 | ||
803 | rc = mls_context_to_sid(oldc, &p, &context, &sidtab, def_sid); | 808 | rc = mls_context_to_sid(pol, oldc, &p, ctx, sidtabp, def_sid); |
804 | if (rc) | 809 | if (rc) |
805 | goto out_unlock; | 810 | goto out; |
806 | 811 | ||
807 | if ((p - scontext2) < scontext_len) { | 812 | if ((p - scontext2) < scontext_len) { |
808 | rc = -EINVAL; | 813 | rc = -EINVAL; |
809 | goto out_unlock; | 814 | goto out; |
810 | } | 815 | } |
811 | 816 | ||
812 | /* Check the validity of the new context. */ | 817 | /* Check the validity of the new context. */ |
813 | if (!policydb_context_isvalid(&policydb, &context)) { | 818 | if (!policydb_context_isvalid(pol, ctx)) { |
814 | rc = -EINVAL; | 819 | rc = -EINVAL; |
815 | goto out_unlock; | 820 | context_destroy(ctx); |
821 | goto out; | ||
816 | } | 822 | } |
817 | /* Obtain the new sid. */ | 823 | rc = 0; |
818 | rc = sidtab_context_to_sid(&sidtab, &context, sid); | 824 | out: |
819 | out_unlock: | ||
820 | POLICY_RDUNLOCK; | ||
821 | context_destroy(&context); | ||
822 | kfree(scontext2); | 825 | kfree(scontext2); |
826 | return rc; | ||
827 | } | ||
828 | |||
829 | static int security_context_to_sid_core(const char *scontext, u32 scontext_len, | ||
830 | u32 *sid, u32 def_sid, gfp_t gfp_flags, | ||
831 | int force) | ||
832 | { | ||
833 | struct context context; | ||
834 | int rc = 0; | ||
835 | |||
836 | if (!ss_initialized) { | ||
837 | int i; | ||
838 | |||
839 | for (i = 1; i < SECINITSID_NUM; i++) { | ||
840 | if (!strcmp(initial_sid_to_string[i], scontext)) { | ||
841 | *sid = i; | ||
842 | goto out; | ||
843 | } | ||
844 | } | ||
845 | *sid = SECINITSID_KERNEL; | ||
846 | goto out; | ||
847 | } | ||
848 | *sid = SECSID_NULL; | ||
849 | |||
850 | POLICY_RDLOCK; | ||
851 | rc = string_to_context_struct(&policydb, &sidtab, | ||
852 | scontext, scontext_len, | ||
853 | &context, def_sid, gfp_flags); | ||
854 | if (rc == -EINVAL && force) { | ||
855 | context.str = kmalloc(scontext_len+1, gfp_flags); | ||
856 | if (!context.str) { | ||
857 | rc = -ENOMEM; | ||
858 | goto out; | ||
859 | } | ||
860 | memcpy(context.str, scontext, scontext_len); | ||
861 | context.str[scontext_len] = 0; | ||
862 | context.len = scontext_len; | ||
863 | } else if (rc) | ||
864 | goto out; | ||
865 | rc = sidtab_context_to_sid(&sidtab, &context, sid); | ||
866 | if (rc) | ||
867 | context_destroy(&context); | ||
823 | out: | 868 | out: |
869 | POLICY_RDUNLOCK; | ||
824 | return rc; | 870 | return rc; |
825 | } | 871 | } |
826 | 872 | ||
@@ -838,7 +884,7 @@ out: | |||
838 | int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid) | 884 | int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid) |
839 | { | 885 | { |
840 | return security_context_to_sid_core(scontext, scontext_len, | 886 | return security_context_to_sid_core(scontext, scontext_len, |
841 | sid, SECSID_NULL, GFP_KERNEL); | 887 | sid, SECSID_NULL, GFP_KERNEL, 0); |
842 | } | 888 | } |
843 | 889 | ||
844 | /** | 890 | /** |
@@ -855,6 +901,7 @@ int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid) | |||
855 | * The default SID is passed to the MLS layer to be used to allow | 901 | * The default SID is passed to the MLS layer to be used to allow |
856 | * kernel labeling of the MLS field if the MLS field is not present | 902 | * kernel labeling of the MLS field if the MLS field is not present |
857 | * (for upgrading to MLS without full relabel). | 903 | * (for upgrading to MLS without full relabel). |
904 | * Implicitly forces adding of the context even if it cannot be mapped yet. | ||
858 | * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient | 905 | * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient |
859 | * memory is available, or 0 on success. | 906 | * memory is available, or 0 on success. |
860 | */ | 907 | */ |
@@ -862,7 +909,14 @@ int security_context_to_sid_default(const char *scontext, u32 scontext_len, | |||
862 | u32 *sid, u32 def_sid, gfp_t gfp_flags) | 909 | u32 *sid, u32 def_sid, gfp_t gfp_flags) |
863 | { | 910 | { |
864 | return security_context_to_sid_core(scontext, scontext_len, | 911 | return security_context_to_sid_core(scontext, scontext_len, |
865 | sid, def_sid, gfp_flags); | 912 | sid, def_sid, gfp_flags, 1); |
913 | } | ||
914 | |||
915 | int security_context_to_sid_force(const char *scontext, u32 scontext_len, | ||
916 | u32 *sid) | ||
917 | { | ||
918 | return security_context_to_sid_core(scontext, scontext_len, | ||
919 | sid, SECSID_NULL, GFP_KERNEL, 1); | ||
866 | } | 920 | } |
867 | 921 | ||
868 | static int compute_sid_handle_invalid_context( | 922 | static int compute_sid_handle_invalid_context( |
@@ -1246,9 +1300,12 @@ static inline int convert_context_handle_invalid_context(struct context *context | |||
1246 | char *s; | 1300 | char *s; |
1247 | u32 len; | 1301 | u32 len; |
1248 | 1302 | ||
1249 | context_struct_to_string(context, &s, &len); | 1303 | if (!context_struct_to_string(context, &s, &len)) { |
1250 | printk(KERN_ERR "SELinux: context %s is invalid\n", s); | 1304 | printk(KERN_WARNING |
1251 | kfree(s); | 1305 | "SELinux: Context %s would be invalid if enforcing\n", |
1306 | s); | ||
1307 | kfree(s); | ||
1308 | } | ||
1252 | } | 1309 | } |
1253 | return rc; | 1310 | return rc; |
1254 | } | 1311 | } |
@@ -1280,6 +1337,32 @@ static int convert_context(u32 key, | |||
1280 | 1337 | ||
1281 | args = p; | 1338 | args = p; |
1282 | 1339 | ||
1340 | if (c->str) { | ||
1341 | struct context ctx; | ||
1342 | rc = string_to_context_struct(args->newp, NULL, c->str, | ||
1343 | c->len, &ctx, SECSID_NULL, | ||
1344 | GFP_KERNEL); | ||
1345 | if (!rc) { | ||
1346 | printk(KERN_INFO | ||
1347 | "SELinux: Context %s became valid (mapped).\n", | ||
1348 | c->str); | ||
1349 | /* Replace string with mapped representation. */ | ||
1350 | kfree(c->str); | ||
1351 | memcpy(c, &ctx, sizeof(*c)); | ||
1352 | goto out; | ||
1353 | } else if (rc == -EINVAL) { | ||
1354 | /* Retain string representation for later mapping. */ | ||
1355 | rc = 0; | ||
1356 | goto out; | ||
1357 | } else { | ||
1358 | /* Other error condition, e.g. ENOMEM. */ | ||
1359 | printk(KERN_ERR | ||
1360 | "SELinux: Unable to map context %s, rc = %d.\n", | ||
1361 | c->str, -rc); | ||
1362 | goto out; | ||
1363 | } | ||
1364 | } | ||
1365 | |||
1283 | rc = context_cpy(&oldc, c); | 1366 | rc = context_cpy(&oldc, c); |
1284 | if (rc) | 1367 | if (rc) |
1285 | goto out; | 1368 | goto out; |
@@ -1319,13 +1402,21 @@ static int convert_context(u32 key, | |||
1319 | } | 1402 | } |
1320 | 1403 | ||
1321 | context_destroy(&oldc); | 1404 | context_destroy(&oldc); |
1405 | rc = 0; | ||
1322 | out: | 1406 | out: |
1323 | return rc; | 1407 | return rc; |
1324 | bad: | 1408 | bad: |
1325 | context_struct_to_string(&oldc, &s, &len); | 1409 | /* Map old representation to string and save it. */ |
1410 | if (context_struct_to_string(&oldc, &s, &len)) | ||
1411 | return -ENOMEM; | ||
1326 | context_destroy(&oldc); | 1412 | context_destroy(&oldc); |
1327 | printk(KERN_ERR "SELinux: invalidating context %s\n", s); | 1413 | context_destroy(c); |
1328 | kfree(s); | 1414 | c->str = s; |
1415 | c->len = len; | ||
1416 | printk(KERN_INFO | ||
1417 | "SELinux: Context %s became invalid (unmapped).\n", | ||
1418 | c->str); | ||
1419 | rc = 0; | ||
1329 | goto out; | 1420 | goto out; |
1330 | } | 1421 | } |
1331 | 1422 | ||
@@ -1406,7 +1497,11 @@ int security_load_policy(void *data, size_t len) | |||
1406 | return -EINVAL; | 1497 | return -EINVAL; |
1407 | } | 1498 | } |
1408 | 1499 | ||
1409 | sidtab_init(&newsidtab); | 1500 | if (sidtab_init(&newsidtab)) { |
1501 | LOAD_UNLOCK; | ||
1502 | policydb_destroy(&newpolicydb); | ||
1503 | return -ENOMEM; | ||
1504 | } | ||
1410 | 1505 | ||
1411 | /* Verify that the kernel defined classes are correct. */ | 1506 | /* Verify that the kernel defined classes are correct. */ |
1412 | if (validate_classes(&newpolicydb)) { | 1507 | if (validate_classes(&newpolicydb)) { |
@@ -1429,11 +1524,15 @@ int security_load_policy(void *data, size_t len) | |||
1429 | goto err; | 1524 | goto err; |
1430 | } | 1525 | } |
1431 | 1526 | ||
1432 | /* Convert the internal representations of contexts | 1527 | /* |
1433 | in the new SID table and remove invalid SIDs. */ | 1528 | * Convert the internal representations of contexts |
1529 | * in the new SID table. | ||
1530 | */ | ||
1434 | args.oldp = &policydb; | 1531 | args.oldp = &policydb; |
1435 | args.newp = &newpolicydb; | 1532 | args.newp = &newpolicydb; |
1436 | sidtab_map_remove_on_error(&newsidtab, convert_context, &args); | 1533 | rc = sidtab_map(&newsidtab, convert_context, &args); |
1534 | if (rc) | ||
1535 | goto err; | ||
1437 | 1536 | ||
1438 | /* Save the old policydb and SID table to free later. */ | 1537 | /* Save the old policydb and SID table to free later. */ |
1439 | memcpy(&oldpolicydb, &policydb, sizeof policydb); | 1538 | memcpy(&oldpolicydb, &policydb, sizeof policydb); |
@@ -1673,6 +1772,8 @@ int security_get_user_sids(u32 fromsid, | |||
1673 | 1772 | ||
1674 | POLICY_RDLOCK; | 1773 | POLICY_RDLOCK; |
1675 | 1774 | ||
1775 | context_init(&usercon); | ||
1776 | |||
1676 | fromcon = sidtab_search(&sidtab, fromsid); | 1777 | fromcon = sidtab_search(&sidtab, fromsid); |
1677 | if (!fromcon) { | 1778 | if (!fromcon) { |
1678 | rc = -EINVAL; | 1779 | rc = -EINVAL; |