diff options
Diffstat (limited to 'security/selinux')
-rw-r--r-- | security/selinux/hooks.c | 20 | ||||
-rw-r--r-- | security/selinux/include/security.h | 5 | ||||
-rw-r--r-- | security/selinux/ss/context.h | 27 | ||||
-rw-r--r-- | security/selinux/ss/mls.c | 11 | ||||
-rw-r--r-- | security/selinux/ss/mls.h | 3 | ||||
-rw-r--r-- | security/selinux/ss/services.c | 245 | ||||
-rw-r--r-- | security/selinux/ss/sidtab.c | 58 | ||||
-rw-r--r-- | security/selinux/ss/sidtab.h | 7 |
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, | |||
93 | int security_sid_to_context(u32 sid, char **scontext, | 93 | int security_sid_to_context(u32 sid, char **scontext, |
94 | u32 *scontext_len); | 94 | u32 *scontext_len); |
95 | 95 | ||
96 | int security_sid_to_context_force(u32 sid, char **scontext, u32 *scontext_len); | ||
97 | |||
96 | int security_context_to_sid(const char *scontext, u32 scontext_len, | 98 | int security_context_to_sid(const char *scontext, u32 scontext_len, |
97 | u32 *out_sid); | 99 | u32 *out_sid); |
98 | 100 | ||
99 | int security_context_to_sid_default(const char *scontext, u32 scontext_len, | 101 | int 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 | ||
104 | int security_context_to_sid_force(const char *scontext, u32 scontext_len, | ||
105 | u32 *sid); | ||
106 | |||
102 | int security_get_user_sids(u32 callsid, char *username, | 107 | int 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 | ||
33 | static inline void mls_context_init(struct context *c) | 35 | static inline void mls_context_init(struct context *c) |
@@ -106,20 +108,43 @@ static inline void context_init(struct context *c) | |||
106 | 108 | ||
107 | static inline int context_cpy(struct context *dst, struct context *src) | 109 | static 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 | ||
115 | static inline void context_destroy(struct context *c) | 133 | static 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 | ||
121 | static inline int context_cmp(struct context *c1, struct context *c2) | 142 | static 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 | */ |
242 | int mls_context_to_sid(char oldc, | 242 | int 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); | |||
30 | int mls_range_isvalid(struct policydb *p, struct mls_range *r); | 30 | int mls_range_isvalid(struct policydb *p, struct mls_range *r); |
31 | int mls_level_isvalid(struct policydb *p, struct mls_level *l); | 31 | int mls_level_isvalid(struct policydb *p, struct mls_level *l); |
32 | 32 | ||
33 | int mls_context_to_sid(char oldc, | 33 | int 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 | /** | 666 | static 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 | */ | ||
668 | int 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 | ||
711 | static 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 | */ | ||
723 | int 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 | |||
728 | int 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 | |||
733 | static 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); | 824 | out: |
819 | out_unlock: | ||
820 | POLICY_RDUNLOCK; | ||
821 | context_destroy(&context); | ||
822 | kfree(scontext2); | 825 | kfree(scontext2); |
826 | return rc; | ||
827 | } | ||
828 | |||
829 | static 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); | ||
823 | out: | 868 | out: |
869 | POLICY_RDUNLOCK; | ||
824 | return rc; | 870 | return rc; |
825 | } | 871 | } |
826 | 872 | ||
@@ -838,7 +884,7 @@ out: | |||
838 | int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid) | 884 | int 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 | |||
915 | int 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 | ||
868 | static int compute_sid_handle_invalid_context( | 922 | static 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; | ||
1322 | out: | 1406 | out: |
1323 | return rc; | 1407 | return rc; |
1324 | bad: | 1408 | bad: |
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 | ||
89 | struct context *sidtab_search(struct sidtab *s, u32 sid) | 89 | static 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 | ||
119 | struct context *sidtab_search(struct sidtab *s, u32 sid) | ||
120 | { | ||
121 | return sidtab_search_core(s, sid, 0); | ||
122 | } | ||
123 | |||
124 | struct context *sidtab_search_force(struct sidtab *s, u32 sid) | ||
125 | { | ||
126 | return sidtab_search_core(s, sid, 1); | ||
127 | } | ||
128 | |||
116 | int sidtab_map(struct sidtab *s, | 129 | int 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 | ||
141 | void 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 | |||
178 | static inline u32 sidtab_search_context(struct sidtab *s, | 154 | static 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 { | |||
32 | int sidtab_init(struct sidtab *s); | 32 | int sidtab_init(struct sidtab *s); |
33 | int sidtab_insert(struct sidtab *s, u32 sid, struct context *context); | 33 | int sidtab_insert(struct sidtab *s, u32 sid, struct context *context); |
34 | struct context *sidtab_search(struct sidtab *s, u32 sid); | 34 | struct context *sidtab_search(struct sidtab *s, u32 sid); |
35 | struct context *sidtab_search_force(struct sidtab *s, u32 sid); | ||
35 | 36 | ||
36 | int sidtab_map(struct sidtab *s, | 37 | int 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 | ||
42 | void sidtab_map_remove_on_error(struct sidtab *s, | ||
43 | int (*apply) (u32 sid, | ||
44 | struct context *context, | ||
45 | void *args), | ||
46 | void *args); | ||
47 | |||
48 | int sidtab_context_to_sid(struct sidtab *s, | 43 | int sidtab_context_to_sid(struct sidtab *s, |
49 | struct context *context, | 44 | struct context *context, |
50 | u32 *sid); | 45 | u32 *sid); |