aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--security/selinux/hooks.c20
-rw-r--r--security/selinux/include/security.h5
-rw-r--r--security/selinux/ss/context.h27
-rw-r--r--security/selinux/ss/mls.c11
-rw-r--r--security/selinux/ss/mls.h3
-rw-r--r--security/selinux/ss/services.c245
-rw-r--r--security/selinux/ss/sidtab.c58
-rw-r--r--security/selinux/ss/sidtab.h7
8 files changed, 248 insertions, 128 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 1c864c0efe2b..59c6e98f7bea 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2495,7 +2495,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
2495 } 2495 }
2496 2496
2497 if (value && len) { 2497 if (value && len) {
2498 rc = security_sid_to_context(newsid, &context, &clen); 2498 rc = security_sid_to_context_force(newsid, &context, &clen);
2499 if (rc) { 2499 if (rc) {
2500 kfree(namep); 2500 kfree(namep);
2501 return rc; 2501 return rc;
@@ -2669,6 +2669,11 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
2669 return rc; 2669 return rc;
2670 2670
2671 rc = security_context_to_sid(value, size, &newsid); 2671 rc = security_context_to_sid(value, size, &newsid);
2672 if (rc == -EINVAL) {
2673 if (!capable(CAP_MAC_ADMIN))
2674 return rc;
2675 rc = security_context_to_sid_force(value, size, &newsid);
2676 }
2672 if (rc) 2677 if (rc)
2673 return rc; 2678 return rc;
2674 2679
@@ -2703,10 +2708,11 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
2703 return; 2708 return;
2704 } 2709 }
2705 2710
2706 rc = security_context_to_sid(value, size, &newsid); 2711 rc = security_context_to_sid_force(value, size, &newsid);
2707 if (rc) { 2712 if (rc) {
2708 printk(KERN_WARNING "%s: unable to obtain SID for context " 2713 printk(KERN_ERR "SELinux: unable to map context to SID"
2709 "%s, rc=%d\n", __func__, (char *)value, -rc); 2714 "for (%s, %lu), rc=%d\n",
2715 inode->i_sb->s_id, inode->i_ino, -rc);
2710 return; 2716 return;
2711 } 2717 }
2712 2718
@@ -5153,6 +5159,12 @@ static int selinux_setprocattr(struct task_struct *p,
5153 size--; 5159 size--;
5154 } 5160 }
5155 error = security_context_to_sid(value, size, &sid); 5161 error = security_context_to_sid(value, size, &sid);
5162 if (error == -EINVAL && !strcmp(name, "fscreate")) {
5163 if (!capable(CAP_MAC_ADMIN))
5164 return error;
5165 error = security_context_to_sid_force(value, size,
5166 &sid);
5167 }
5156 if (error) 5168 if (error)
5157 return error; 5169 return error;
5158 } 5170 }
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index ad30ac4273d6..7c543003d653 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -93,12 +93,17 @@ int security_change_sid(u32 ssid, u32 tsid,
93int security_sid_to_context(u32 sid, char **scontext, 93int security_sid_to_context(u32 sid, char **scontext,
94 u32 *scontext_len); 94 u32 *scontext_len);
95 95
96int security_sid_to_context_force(u32 sid, char **scontext, u32 *scontext_len);
97
96int security_context_to_sid(const char *scontext, u32 scontext_len, 98int security_context_to_sid(const char *scontext, u32 scontext_len,
97 u32 *out_sid); 99 u32 *out_sid);
98 100
99int security_context_to_sid_default(const char *scontext, u32 scontext_len, 101int security_context_to_sid_default(const char *scontext, u32 scontext_len,
100 u32 *out_sid, u32 def_sid, gfp_t gfp_flags); 102 u32 *out_sid, u32 def_sid, gfp_t gfp_flags);
101 103
104int security_context_to_sid_force(const char *scontext, u32 scontext_len,
105 u32 *sid);
106
102int security_get_user_sids(u32 callsid, char *username, 107int security_get_user_sids(u32 callsid, char *username,
103 u32 **sids, u32 *nel); 108 u32 **sids, u32 *nel);
104 109
diff --git a/security/selinux/ss/context.h b/security/selinux/ss/context.h
index b9a6f7fc62fc..658c2bd17da8 100644
--- a/security/selinux/ss/context.h
+++ b/security/selinux/ss/context.h
@@ -28,6 +28,8 @@ struct context {
28 u32 role; 28 u32 role;
29 u32 type; 29 u32 type;
30 struct mls_range range; 30 struct mls_range range;
31 char *str; /* string representation if context cannot be mapped. */
32 u32 len; /* length of string in bytes */
31}; 33};
32 34
33static inline void mls_context_init(struct context *c) 35static inline void mls_context_init(struct context *c)
@@ -106,20 +108,43 @@ static inline void context_init(struct context *c)
106 108
107static inline int context_cpy(struct context *dst, struct context *src) 109static inline int context_cpy(struct context *dst, struct context *src)
108{ 110{
111 int rc;
112
109 dst->user = src->user; 113 dst->user = src->user;
110 dst->role = src->role; 114 dst->role = src->role;
111 dst->type = src->type; 115 dst->type = src->type;
112 return mls_context_cpy(dst, src); 116 if (src->str) {
117 dst->str = kstrdup(src->str, GFP_ATOMIC);
118 if (!dst->str)
119 return -ENOMEM;
120 dst->len = src->len;
121 } else {
122 dst->str = NULL;
123 dst->len = 0;
124 }
125 rc = mls_context_cpy(dst, src);
126 if (rc) {
127 kfree(dst->str);
128 return rc;
129 }
130 return 0;
113} 131}
114 132
115static inline void context_destroy(struct context *c) 133static inline void context_destroy(struct context *c)
116{ 134{
117 c->user = c->role = c->type = 0; 135 c->user = c->role = c->type = 0;
136 kfree(c->str);
137 c->str = NULL;
138 c->len = 0;
118 mls_context_destroy(c); 139 mls_context_destroy(c);
119} 140}
120 141
121static inline int context_cmp(struct context *c1, struct context *c2) 142static inline int context_cmp(struct context *c1, struct context *c2)
122{ 143{
144 if (c1->len && c2->len)
145 return (c1->len == c2->len && !strcmp(c1->str, c2->str));
146 if (c1->len || c2->len)
147 return 0;
123 return ((c1->user == c2->user) && 148 return ((c1->user == c2->user) &&
124 (c1->role == c2->role) && 149 (c1->role == c2->role) &&
125 (c1->type == c2->type) && 150 (c1->type == c2->type) &&
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
index 8b1706b7b3cc..a6ca0587e634 100644
--- a/security/selinux/ss/mls.c
+++ b/security/selinux/ss/mls.c
@@ -239,7 +239,8 @@ int mls_context_isvalid(struct policydb *p, struct context *c)
239 * Policy read-lock must be held for sidtab lookup. 239 * Policy read-lock must be held for sidtab lookup.
240 * 240 *
241 */ 241 */
242int mls_context_to_sid(char oldc, 242int mls_context_to_sid(struct policydb *pol,
243 char oldc,
243 char **scontext, 244 char **scontext,
244 struct context *context, 245 struct context *context,
245 struct sidtab *s, 246 struct sidtab *s,
@@ -286,7 +287,7 @@ int mls_context_to_sid(char oldc,
286 *p++ = 0; 287 *p++ = 0;
287 288
288 for (l = 0; l < 2; l++) { 289 for (l = 0; l < 2; l++) {
289 levdatum = hashtab_search(policydb.p_levels.table, scontextp); 290 levdatum = hashtab_search(pol->p_levels.table, scontextp);
290 if (!levdatum) { 291 if (!levdatum) {
291 rc = -EINVAL; 292 rc = -EINVAL;
292 goto out; 293 goto out;
@@ -311,7 +312,7 @@ int mls_context_to_sid(char oldc,
311 *rngptr++ = 0; 312 *rngptr++ = 0;
312 } 313 }
313 314
314 catdatum = hashtab_search(policydb.p_cats.table, 315 catdatum = hashtab_search(pol->p_cats.table,
315 scontextp); 316 scontextp);
316 if (!catdatum) { 317 if (!catdatum) {
317 rc = -EINVAL; 318 rc = -EINVAL;
@@ -327,7 +328,7 @@ int mls_context_to_sid(char oldc,
327 if (rngptr) { 328 if (rngptr) {
328 int i; 329 int i;
329 330
330 rngdatum = hashtab_search(policydb.p_cats.table, rngptr); 331 rngdatum = hashtab_search(pol->p_cats.table, rngptr);
331 if (!rngdatum) { 332 if (!rngdatum) {
332 rc = -EINVAL; 333 rc = -EINVAL;
333 goto out; 334 goto out;
@@ -395,7 +396,7 @@ int mls_from_string(char *str, struct context *context, gfp_t gfp_mask)
395 if (!tmpstr) { 396 if (!tmpstr) {
396 rc = -ENOMEM; 397 rc = -ENOMEM;
397 } else { 398 } else {
398 rc = mls_context_to_sid(':', &tmpstr, context, 399 rc = mls_context_to_sid(&policydb, ':', &tmpstr, context,
399 NULL, SECSID_NULL); 400 NULL, SECSID_NULL);
400 kfree(freestr); 401 kfree(freestr);
401 } 402 }
diff --git a/security/selinux/ss/mls.h b/security/selinux/ss/mls.h
index 0fdf6257ef64..1276715aaa8b 100644
--- a/security/selinux/ss/mls.h
+++ b/security/selinux/ss/mls.h
@@ -30,7 +30,8 @@ int mls_context_isvalid(struct policydb *p, struct context *c);
30int mls_range_isvalid(struct policydb *p, struct mls_range *r); 30int mls_range_isvalid(struct policydb *p, struct mls_range *r);
31int mls_level_isvalid(struct policydb *p, struct mls_level *l); 31int mls_level_isvalid(struct policydb *p, struct mls_level *l);
32 32
33int mls_context_to_sid(char oldc, 33int mls_context_to_sid(struct policydb *p,
34 char oldc,
34 char **scontext, 35 char **scontext,
35 struct context *context, 36 struct context *context,
36 struct sidtab *s, 37 struct sidtab *s,
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;
diff --git a/security/selinux/ss/sidtab.c b/security/selinux/ss/sidtab.c
index 4a516ff4bcde..ba3541640491 100644
--- a/security/selinux/ss/sidtab.c
+++ b/security/selinux/ss/sidtab.c
@@ -86,7 +86,7 @@ out:
86 return rc; 86 return rc;
87} 87}
88 88
89struct context *sidtab_search(struct sidtab *s, u32 sid) 89static struct context *sidtab_search_core(struct sidtab *s, u32 sid, int force)
90{ 90{
91 int hvalue; 91 int hvalue;
92 struct sidtab_node *cur; 92 struct sidtab_node *cur;
@@ -99,7 +99,10 @@ struct context *sidtab_search(struct sidtab *s, u32 sid)
99 while (cur != NULL && sid > cur->sid) 99 while (cur != NULL && sid > cur->sid)
100 cur = cur->next; 100 cur = cur->next;
101 101
102 if (cur == NULL || sid != cur->sid) { 102 if (force && cur && sid == cur->sid && cur->context.len)
103 return &cur->context;
104
105 if (cur == NULL || sid != cur->sid || cur->context.len) {
103 /* Remap invalid SIDs to the unlabeled SID. */ 106 /* Remap invalid SIDs to the unlabeled SID. */
104 sid = SECINITSID_UNLABELED; 107 sid = SECINITSID_UNLABELED;
105 hvalue = SIDTAB_HASH(sid); 108 hvalue = SIDTAB_HASH(sid);
@@ -113,6 +116,16 @@ struct context *sidtab_search(struct sidtab *s, u32 sid)
113 return &cur->context; 116 return &cur->context;
114} 117}
115 118
119struct context *sidtab_search(struct sidtab *s, u32 sid)
120{
121 return sidtab_search_core(s, sid, 0);
122}
123
124struct context *sidtab_search_force(struct sidtab *s, u32 sid)
125{
126 return sidtab_search_core(s, sid, 1);
127}
128
116int sidtab_map(struct sidtab *s, 129int sidtab_map(struct sidtab *s,
117 int (*apply) (u32 sid, 130 int (*apply) (u32 sid,
118 struct context *context, 131 struct context *context,
@@ -138,43 +151,6 @@ out:
138 return rc; 151 return rc;
139} 152}
140 153
141void sidtab_map_remove_on_error(struct sidtab *s,
142 int (*apply) (u32 sid,
143 struct context *context,
144 void *args),
145 void *args)
146{
147 int i, ret;
148 struct sidtab_node *last, *cur, *temp;
149
150 if (!s)
151 return;
152
153 for (i = 0; i < SIDTAB_SIZE; i++) {
154 last = NULL;
155 cur = s->htable[i];
156 while (cur != NULL) {
157 ret = apply(cur->sid, &cur->context, args);
158 if (ret) {
159 if (last)
160 last->next = cur->next;
161 else
162 s->htable[i] = cur->next;
163 temp = cur;
164 cur = cur->next;
165 context_destroy(&temp->context);
166 kfree(temp);
167 s->nel--;
168 } else {
169 last = cur;
170 cur = cur->next;
171 }
172 }
173 }
174
175 return;
176}
177
178static inline u32 sidtab_search_context(struct sidtab *s, 154static inline u32 sidtab_search_context(struct sidtab *s,
179 struct context *context) 155 struct context *context)
180{ 156{
@@ -215,6 +191,10 @@ int sidtab_context_to_sid(struct sidtab *s,
215 goto unlock_out; 191 goto unlock_out;
216 } 192 }
217 sid = s->next_sid++; 193 sid = s->next_sid++;
194 if (context->len)
195 printk(KERN_INFO
196 "SELinux: Context %s is not valid (left unmapped).\n",
197 context->str);
218 ret = sidtab_insert(s, sid, context); 198 ret = sidtab_insert(s, sid, context);
219 if (ret) 199 if (ret)
220 s->next_sid--; 200 s->next_sid--;
diff --git a/security/selinux/ss/sidtab.h b/security/selinux/ss/sidtab.h
index 2fe9dfa3eb3a..64ea5b1cdea4 100644
--- a/security/selinux/ss/sidtab.h
+++ b/security/selinux/ss/sidtab.h
@@ -32,6 +32,7 @@ struct sidtab {
32int sidtab_init(struct sidtab *s); 32int sidtab_init(struct sidtab *s);
33int sidtab_insert(struct sidtab *s, u32 sid, struct context *context); 33int sidtab_insert(struct sidtab *s, u32 sid, struct context *context);
34struct context *sidtab_search(struct sidtab *s, u32 sid); 34struct context *sidtab_search(struct sidtab *s, u32 sid);
35struct context *sidtab_search_force(struct sidtab *s, u32 sid);
35 36
36int sidtab_map(struct sidtab *s, 37int sidtab_map(struct sidtab *s,
37 int (*apply) (u32 sid, 38 int (*apply) (u32 sid,
@@ -39,12 +40,6 @@ int sidtab_map(struct sidtab *s,
39 void *args), 40 void *args),
40 void *args); 41 void *args);
41 42
42void sidtab_map_remove_on_error(struct sidtab *s,
43 int (*apply) (u32 sid,
44 struct context *context,
45 void *args),
46 void *args);
47
48int sidtab_context_to_sid(struct sidtab *s, 43int sidtab_context_to_sid(struct sidtab *s,
49 struct context *context, 44 struct context *context,
50 u32 *sid); 45 u32 *sid);