diff options
author | Stephen Smalley <sds@tycho.nsa.gov> | 2008-05-14 10:33:55 -0400 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2008-07-14 01:01:35 -0400 |
commit | 9a59daa03df72526d234b91dd3e32ded5aebd3ef (patch) | |
tree | 9ba6797d509a5657be7f47f55e630f06a489174d | |
parent | 12b29f34558b9b45a2c6eabd4f3c6be939a3980f (diff) |
SELinux: fix sleeping allocation in security_context_to_sid
Fix a sleeping function called from invalid context bug by moving allocation
to the callers prior to taking the policy rdlock.
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>
-rw-r--r-- | security/selinux/ss/services.c | 70 |
1 files changed, 40 insertions, 30 deletions
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index b86ac9da6cf3..2d5e5a3a8aa9 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
@@ -730,15 +730,16 @@ int security_sid_to_context_force(u32 sid, char **scontext, u32 *scontext_len) | |||
730 | return security_sid_to_context_core(sid, scontext, scontext_len, 1); | 730 | return security_sid_to_context_core(sid, scontext, scontext_len, 1); |
731 | } | 731 | } |
732 | 732 | ||
733 | /* | ||
734 | * Caveat: Mutates scontext. | ||
735 | */ | ||
733 | static int string_to_context_struct(struct policydb *pol, | 736 | static int string_to_context_struct(struct policydb *pol, |
734 | struct sidtab *sidtabp, | 737 | struct sidtab *sidtabp, |
735 | const char *scontext, | 738 | char *scontext, |
736 | u32 scontext_len, | 739 | u32 scontext_len, |
737 | struct context *ctx, | 740 | struct context *ctx, |
738 | u32 def_sid, | 741 | u32 def_sid) |
739 | gfp_t gfp_flags) | ||
740 | { | 742 | { |
741 | char *scontext2 = NULL; | ||
742 | struct role_datum *role; | 743 | struct role_datum *role; |
743 | struct type_datum *typdatum; | 744 | struct type_datum *typdatum; |
744 | struct user_datum *usrdatum; | 745 | struct user_datum *usrdatum; |
@@ -747,19 +748,10 @@ static int string_to_context_struct(struct policydb *pol, | |||
747 | 748 | ||
748 | context_init(ctx); | 749 | context_init(ctx); |
749 | 750 | ||
750 | /* Copy the string so that we can modify the copy as we parse it. */ | ||
751 | scontext2 = kmalloc(scontext_len+1, gfp_flags); | ||
752 | if (!scontext2) { | ||
753 | rc = -ENOMEM; | ||
754 | goto out; | ||
755 | } | ||
756 | memcpy(scontext2, scontext, scontext_len); | ||
757 | scontext2[scontext_len] = 0; | ||
758 | |||
759 | /* Parse the security context. */ | 751 | /* Parse the security context. */ |
760 | 752 | ||
761 | rc = -EINVAL; | 753 | rc = -EINVAL; |
762 | scontextp = (char *) scontext2; | 754 | scontextp = (char *) scontext; |
763 | 755 | ||
764 | /* Extract the user. */ | 756 | /* Extract the user. */ |
765 | p = scontextp; | 757 | p = scontextp; |
@@ -809,7 +801,7 @@ static int string_to_context_struct(struct policydb *pol, | |||
809 | if (rc) | 801 | if (rc) |
810 | goto out; | 802 | goto out; |
811 | 803 | ||
812 | if ((p - scontext2) < scontext_len) { | 804 | if ((p - scontext) < scontext_len) { |
813 | rc = -EINVAL; | 805 | rc = -EINVAL; |
814 | goto out; | 806 | goto out; |
815 | } | 807 | } |
@@ -822,7 +814,6 @@ static int string_to_context_struct(struct policydb *pol, | |||
822 | } | 814 | } |
823 | rc = 0; | 815 | rc = 0; |
824 | out: | 816 | out: |
825 | kfree(scontext2); | ||
826 | return rc; | 817 | return rc; |
827 | } | 818 | } |
828 | 819 | ||
@@ -830,6 +821,7 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len, | |||
830 | u32 *sid, u32 def_sid, gfp_t gfp_flags, | 821 | u32 *sid, u32 def_sid, gfp_t gfp_flags, |
831 | int force) | 822 | int force) |
832 | { | 823 | { |
824 | char *scontext2, *str = NULL; | ||
833 | struct context context; | 825 | struct context context; |
834 | int rc = 0; | 826 | int rc = 0; |
835 | 827 | ||
@@ -839,27 +831,38 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len, | |||
839 | for (i = 1; i < SECINITSID_NUM; i++) { | 831 | for (i = 1; i < SECINITSID_NUM; i++) { |
840 | if (!strcmp(initial_sid_to_string[i], scontext)) { | 832 | if (!strcmp(initial_sid_to_string[i], scontext)) { |
841 | *sid = i; | 833 | *sid = i; |
842 | goto out; | 834 | return 0; |
843 | } | 835 | } |
844 | } | 836 | } |
845 | *sid = SECINITSID_KERNEL; | 837 | *sid = SECINITSID_KERNEL; |
846 | goto out; | 838 | return 0; |
847 | } | 839 | } |
848 | *sid = SECSID_NULL; | 840 | *sid = SECSID_NULL; |
849 | 841 | ||
842 | /* Copy the string so that we can modify the copy as we parse it. */ | ||
843 | scontext2 = kmalloc(scontext_len+1, gfp_flags); | ||
844 | if (!scontext2) | ||
845 | return -ENOMEM; | ||
846 | memcpy(scontext2, scontext, scontext_len); | ||
847 | scontext2[scontext_len] = 0; | ||
848 | |||
849 | if (force) { | ||
850 | /* Save another copy for storing in uninterpreted form */ | ||
851 | str = kstrdup(scontext2, gfp_flags); | ||
852 | if (!str) { | ||
853 | kfree(scontext2); | ||
854 | return -ENOMEM; | ||
855 | } | ||
856 | } | ||
857 | |||
850 | POLICY_RDLOCK; | 858 | POLICY_RDLOCK; |
851 | rc = string_to_context_struct(&policydb, &sidtab, | 859 | rc = string_to_context_struct(&policydb, &sidtab, |
852 | scontext, scontext_len, | 860 | scontext2, scontext_len, |
853 | &context, def_sid, gfp_flags); | 861 | &context, def_sid); |
854 | if (rc == -EINVAL && force) { | 862 | if (rc == -EINVAL && force) { |
855 | context.str = kmalloc(scontext_len+1, gfp_flags); | 863 | context.str = str; |
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; | 864 | context.len = scontext_len; |
865 | str = NULL; | ||
863 | } else if (rc) | 866 | } else if (rc) |
864 | goto out; | 867 | goto out; |
865 | rc = sidtab_context_to_sid(&sidtab, &context, sid); | 868 | rc = sidtab_context_to_sid(&sidtab, &context, sid); |
@@ -867,6 +870,8 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len, | |||
867 | context_destroy(&context); | 870 | context_destroy(&context); |
868 | out: | 871 | out: |
869 | POLICY_RDUNLOCK; | 872 | POLICY_RDUNLOCK; |
873 | kfree(scontext2); | ||
874 | kfree(str); | ||
870 | return rc; | 875 | return rc; |
871 | } | 876 | } |
872 | 877 | ||
@@ -1339,9 +1344,14 @@ static int convert_context(u32 key, | |||
1339 | 1344 | ||
1340 | if (c->str) { | 1345 | if (c->str) { |
1341 | struct context ctx; | 1346 | struct context ctx; |
1342 | rc = string_to_context_struct(args->newp, NULL, c->str, | 1347 | s = kstrdup(c->str, GFP_KERNEL); |
1343 | c->len, &ctx, SECSID_NULL, | 1348 | if (!s) { |
1344 | GFP_KERNEL); | 1349 | rc = -ENOMEM; |
1350 | goto out; | ||
1351 | } | ||
1352 | rc = string_to_context_struct(args->newp, NULL, s, | ||
1353 | c->len, &ctx, SECSID_NULL); | ||
1354 | kfree(s); | ||
1345 | if (!rc) { | 1355 | if (!rc) { |
1346 | printk(KERN_INFO | 1356 | printk(KERN_INFO |
1347 | "SELinux: Context %s became valid (mapped).\n", | 1357 | "SELinux: Context %s became valid (mapped).\n", |