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 /security | |
| 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>
Diffstat (limited to 'security')
| -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", |
