aboutsummaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorStephen Smalley <sds@tycho.nsa.gov>2008-05-07 13:03:20 -0400
committerJames Morris <jmorris@namei.org>2008-07-14 01:01:34 -0400
commit12b29f34558b9b45a2c6eabd4f3c6be939a3980f (patch)
tree9b7921724226cd81901070026572bf05014dc41c /security
parentbce7f793daec3e65ec5c5705d2457b81fe7b5725 (diff)
selinux: support deferred mapping of contexts
Introduce SELinux support for deferred mapping of security contexts in the SID table upon policy reload, and use this support for inode security contexts when the context is not yet valid under the current policy. Only processes with CAP_MAC_ADMIN + mac_admin permission in policy can set undefined security contexts on inodes. Inodes with such undefined contexts are treated as having the unlabeled context until the context becomes valid upon a policy reload that defines the context. Context invalidation upon policy reload also uses this support to save the context information in the SID table and later recover it upon a subsequent policy reload that defines the context again. This support is to enable package managers and similar programs to set down file contexts unknown to the system policy at the time the file is created in order to better support placing loadable policy modules in packages and to support build systems that need to create images of different distro releases with different policies w/o requiring all of the contexts to be defined or legal in the build host policy. With this patch applied, the following sequence is possible, although in practice it is recommended that this permission only be allowed to specific program domains such as the package manager. # rmdir baz # rm bar # touch bar # chcon -t foo_exec_t bar # foo_exec_t is not yet defined chcon: failed to change context of `bar' to `system_u:object_r:foo_exec_t': Invalid argument # mkdir -Z system_u:object_r:foo_exec_t baz mkdir: failed to set default file creation context to `system_u:object_r:foo_exec_t': Invalid argument # cat setundefined.te policy_module(setundefined, 1.0) require { type unconfined_t; type unlabeled_t; } files_type(unlabeled_t) allow unconfined_t self:capability2 mac_admin; # make -f /usr/share/selinux/devel/Makefile setundefined.pp # semodule -i setundefined.pp # chcon -t foo_exec_t bar # foo_exec_t is not yet defined # mkdir -Z system_u:object_r:foo_exec_t baz # ls -Zd bar baz -rw-r--r-- root root system_u:object_r:unlabeled_t bar drwxr-xr-x root root system_u:object_r:unlabeled_t baz # cat foo.te policy_module(foo, 1.0) type foo_exec_t; files_type(foo_exec_t) # make -f /usr/share/selinux/devel/Makefile foo.pp # semodule -i foo.pp # defines foo_exec_t # ls -Zd bar baz -rw-r--r-- root root user_u:object_r:foo_exec_t bar drwxr-xr-x root root system_u:object_r:foo_exec_t baz # semodule -r foo # ls -Zd bar baz -rw-r--r-- root root system_u:object_r:unlabeled_t bar drwxr-xr-x root root system_u:object_r:unlabeled_t baz # semodule -i foo.pp # ls -Zd bar baz -rw-r--r-- root root user_u:object_r:foo_exec_t bar drwxr-xr-x root root system_u:object_r:foo_exec_t baz # semodule -r setundefined foo # chcon -t foo_exec_t bar # no longer defined and not allowed chcon: failed to change context of `bar' to `system_u:object_r:foo_exec_t': Invalid argument # rmdir baz # mkdir -Z system_u:object_r:foo_exec_t baz mkdir: failed to set default file creation context to `system_u:object_r:foo_exec_t': Invalid argument 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/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);