aboutsummaryrefslogtreecommitdiffstats
path: root/security/selinux/ss/services.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/selinux/ss/services.c')
-rw-r--r--security/selinux/ss/services.c245
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/** 666static 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 */
668int 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
711static 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 */
723int 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
728int 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
733static 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); 824out:
819out_unlock:
820 POLICY_RDUNLOCK;
821 context_destroy(&context);
822 kfree(scontext2); 825 kfree(scontext2);
826 return rc;
827}
828
829static 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);
823out: 868out:
869 POLICY_RDUNLOCK;
824 return rc; 870 return rc;
825} 871}
826 872
@@ -838,7 +884,7 @@ out:
838int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid) 884int 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
915int 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
868static int compute_sid_handle_invalid_context( 922static 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;
1322out: 1406out:
1323 return rc; 1407 return rc;
1324bad: 1408bad:
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;