diff options
author | James Morris <jmorris@redhat.com> | 2005-07-28 04:07:37 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-07-28 11:39:02 -0400 |
commit | f5c1d5b2aaf9a98f15a6dcdfbba1f494d0aaae52 (patch) | |
tree | e896d0b6b9f561c9d124fa81efd261518ccbddf4 | |
parent | e1699f508ab5098de4b258268fa8913db38d9d35 (diff) |
[PATCH] SELinux: default labeling of MLS field
Implement kernel labeling of the MLS (multilevel security) field of
security contexts for files which have no existing MLS field. This is to
enable upgrades of a system from non-MLS to MLS without performing a full
filesystem relabel including all of the mountpoints, which would be quite
painful for users.
With this patch, with MLS enabled, if a file has no MLS field, the kernel
internally adds an MLS field to the in-core inode (but not to the on-disk
file). This MLS field added is the default for the superblock, allowing
per-mountpoint control over the values via fixed policy or mount options.
This patch has been tested by enabling MLS without relabeling its
filesystem, and seems to be working correctly.
Signed-off-by: James Morris <jmorris@redhat.com>
Signed-off-by: Stephen Smalley <sds@epoch.ncsc.mil>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | security/selinux/hooks.c | 3 | ||||
-rw-r--r-- | security/selinux/include/security.h | 2 | ||||
-rw-r--r-- | security/selinux/ss/mls.c | 71 | ||||
-rw-r--r-- | security/selinux/ss/mls.h | 4 | ||||
-rw-r--r-- | security/selinux/ss/services.c | 55 |
5 files changed, 97 insertions, 38 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 6be273851144..10fd51c9056d 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -826,7 +826,8 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent | |||
826 | sid = sbsec->def_sid; | 826 | sid = sbsec->def_sid; |
827 | rc = 0; | 827 | rc = 0; |
828 | } else { | 828 | } else { |
829 | rc = security_context_to_sid(context, rc, &sid); | 829 | rc = security_context_to_sid_default(context, rc, &sid, |
830 | sbsec->def_sid); | ||
830 | if (rc) { | 831 | if (rc) { |
831 | printk(KERN_WARNING "%s: context_to_sid(%s) " | 832 | printk(KERN_WARNING "%s: context_to_sid(%s) " |
832 | "returned %d for dev=%s ino=%ld\n", | 833 | "returned %d for dev=%s ino=%ld\n", |
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index fa187c9a351d..71c0a19c9753 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h | |||
@@ -65,6 +65,8 @@ int security_sid_to_context(u32 sid, char **scontext, | |||
65 | int security_context_to_sid(char *scontext, u32 scontext_len, | 65 | int security_context_to_sid(char *scontext, u32 scontext_len, |
66 | u32 *out_sid); | 66 | u32 *out_sid); |
67 | 67 | ||
68 | int security_context_to_sid_default(char *scontext, u32 scontext_len, u32 *out_sid, u32 def_sid); | ||
69 | |||
68 | int security_get_user_sids(u32 callsid, char *username, | 70 | int security_get_user_sids(u32 callsid, char *username, |
69 | u32 **sids, u32 *nel); | 71 | u32 **sids, u32 *nel); |
70 | 72 | ||
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c index 756036bcc243..d4c32c39ccc9 100644 --- a/security/selinux/ss/mls.c +++ b/security/selinux/ss/mls.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | #include <linux/string.h> | 16 | #include <linux/string.h> |
17 | #include <linux/errno.h> | 17 | #include <linux/errno.h> |
18 | #include "sidtab.h" | ||
18 | #include "mls.h" | 19 | #include "mls.h" |
19 | #include "policydb.h" | 20 | #include "policydb.h" |
20 | #include "services.h" | 21 | #include "services.h" |
@@ -208,6 +209,26 @@ int mls_context_isvalid(struct policydb *p, struct context *c) | |||
208 | } | 209 | } |
209 | 210 | ||
210 | /* | 211 | /* |
212 | * Copies the MLS range from `src' into `dst'. | ||
213 | */ | ||
214 | static inline int mls_copy_context(struct context *dst, | ||
215 | struct context *src) | ||
216 | { | ||
217 | int l, rc = 0; | ||
218 | |||
219 | /* Copy the MLS range from the source context */ | ||
220 | for (l = 0; l < 2; l++) { | ||
221 | dst->range.level[l].sens = src->range.level[l].sens; | ||
222 | rc = ebitmap_cpy(&dst->range.level[l].cat, | ||
223 | &src->range.level[l].cat); | ||
224 | if (rc) | ||
225 | break; | ||
226 | } | ||
227 | |||
228 | return rc; | ||
229 | } | ||
230 | |||
231 | /* | ||
211 | * Set the MLS fields in the security context structure | 232 | * Set the MLS fields in the security context structure |
212 | * `context' based on the string representation in | 233 | * `context' based on the string representation in |
213 | * the string `*scontext'. Update `*scontext' to | 234 | * the string `*scontext'. Update `*scontext' to |
@@ -216,10 +237,20 @@ int mls_context_isvalid(struct policydb *p, struct context *c) | |||
216 | * | 237 | * |
217 | * This function modifies the string in place, inserting | 238 | * This function modifies the string in place, inserting |
218 | * NULL characters to terminate the MLS fields. | 239 | * NULL characters to terminate the MLS fields. |
240 | * | ||
241 | * If a def_sid is provided and no MLS field is present, | ||
242 | * copy the MLS field of the associated default context. | ||
243 | * Used for upgraded to MLS systems where objects may lack | ||
244 | * MLS fields. | ||
245 | * | ||
246 | * Policy read-lock must be held for sidtab lookup. | ||
247 | * | ||
219 | */ | 248 | */ |
220 | int mls_context_to_sid(char oldc, | 249 | int mls_context_to_sid(char oldc, |
221 | char **scontext, | 250 | char **scontext, |
222 | struct context *context) | 251 | struct context *context, |
252 | struct sidtab *s, | ||
253 | u32 def_sid) | ||
223 | { | 254 | { |
224 | 255 | ||
225 | char delim; | 256 | char delim; |
@@ -231,9 +262,23 @@ int mls_context_to_sid(char oldc, | |||
231 | if (!selinux_mls_enabled) | 262 | if (!selinux_mls_enabled) |
232 | return 0; | 263 | return 0; |
233 | 264 | ||
234 | /* No MLS component to the security context. */ | 265 | /* |
235 | if (!oldc) | 266 | * No MLS component to the security context, try and map to |
267 | * default if provided. | ||
268 | */ | ||
269 | if (!oldc) { | ||
270 | struct context *defcon; | ||
271 | |||
272 | if (def_sid == SECSID_NULL) | ||
273 | goto out; | ||
274 | |||
275 | defcon = sidtab_search(s, def_sid); | ||
276 | if (!defcon) | ||
277 | goto out; | ||
278 | |||
279 | rc = mls_copy_context(context, defcon); | ||
236 | goto out; | 280 | goto out; |
281 | } | ||
237 | 282 | ||
238 | /* Extract low sensitivity. */ | 283 | /* Extract low sensitivity. */ |
239 | scontextp = p = *scontext; | 284 | scontextp = p = *scontext; |
@@ -334,26 +379,6 @@ out: | |||
334 | } | 379 | } |
335 | 380 | ||
336 | /* | 381 | /* |
337 | * Copies the MLS range from `src' into `dst'. | ||
338 | */ | ||
339 | static inline int mls_copy_context(struct context *dst, | ||
340 | struct context *src) | ||
341 | { | ||
342 | int l, rc = 0; | ||
343 | |||
344 | /* Copy the MLS range from the source context */ | ||
345 | for (l = 0; l < 2; l++) { | ||
346 | dst->range.level[l].sens = src->range.level[l].sens; | ||
347 | rc = ebitmap_cpy(&dst->range.level[l].cat, | ||
348 | &src->range.level[l].cat); | ||
349 | if (rc) | ||
350 | break; | ||
351 | } | ||
352 | |||
353 | return rc; | ||
354 | } | ||
355 | |||
356 | /* | ||
357 | * Copies the effective MLS range from `src' into `dst'. | 382 | * Copies the effective MLS range from `src' into `dst'. |
358 | */ | 383 | */ |
359 | static inline int mls_scopy_context(struct context *dst, | 384 | static inline int mls_scopy_context(struct context *dst, |
diff --git a/security/selinux/ss/mls.h b/security/selinux/ss/mls.h index 0d37beaa85e2..03de697c8058 100644 --- a/security/selinux/ss/mls.h +++ b/security/selinux/ss/mls.h | |||
@@ -23,7 +23,9 @@ int mls_context_isvalid(struct policydb *p, struct context *c); | |||
23 | 23 | ||
24 | int mls_context_to_sid(char oldc, | 24 | int mls_context_to_sid(char oldc, |
25 | char **scontext, | 25 | char **scontext, |
26 | struct context *context); | 26 | struct context *context, |
27 | struct sidtab *s, | ||
28 | u32 def_sid); | ||
27 | 29 | ||
28 | int mls_convert_context(struct policydb *oldp, | 30 | int mls_convert_context(struct policydb *oldp, |
29 | struct policydb *newp, | 31 | struct policydb *newp, |
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 922bb45054aa..014120474e69 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
@@ -601,18 +601,7 @@ out: | |||
601 | 601 | ||
602 | } | 602 | } |
603 | 603 | ||
604 | /** | 604 | static int security_context_to_sid_core(char *scontext, u32 scontext_len, u32 *sid, u32 def_sid) |
605 | * security_context_to_sid - Obtain a SID for a given security context. | ||
606 | * @scontext: security context | ||
607 | * @scontext_len: length in bytes | ||
608 | * @sid: security identifier, SID | ||
609 | * | ||
610 | * Obtains a SID associated with the security context that | ||
611 | * has the string representation specified by @scontext. | ||
612 | * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient | ||
613 | * memory is available, or 0 on success. | ||
614 | */ | ||
615 | int security_context_to_sid(char *scontext, u32 scontext_len, u32 *sid) | ||
616 | { | 605 | { |
617 | char *scontext2; | 606 | char *scontext2; |
618 | struct context context; | 607 | struct context context; |
@@ -703,7 +692,7 @@ int security_context_to_sid(char *scontext, u32 scontext_len, u32 *sid) | |||
703 | 692 | ||
704 | context.type = typdatum->value; | 693 | context.type = typdatum->value; |
705 | 694 | ||
706 | rc = mls_context_to_sid(oldc, &p, &context); | 695 | rc = mls_context_to_sid(oldc, &p, &context, &sidtab, def_sid); |
707 | if (rc) | 696 | if (rc) |
708 | goto out_unlock; | 697 | goto out_unlock; |
709 | 698 | ||
@@ -727,6 +716,46 @@ out: | |||
727 | return rc; | 716 | return rc; |
728 | } | 717 | } |
729 | 718 | ||
719 | /** | ||
720 | * security_context_to_sid - Obtain a SID for a given security context. | ||
721 | * @scontext: security context | ||
722 | * @scontext_len: length in bytes | ||
723 | * @sid: security identifier, SID | ||
724 | * | ||
725 | * Obtains a SID associated with the security context that | ||
726 | * has the string representation specified by @scontext. | ||
727 | * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient | ||
728 | * memory is available, or 0 on success. | ||
729 | */ | ||
730 | int security_context_to_sid(char *scontext, u32 scontext_len, u32 *sid) | ||
731 | { | ||
732 | return security_context_to_sid_core(scontext, scontext_len, | ||
733 | sid, SECSID_NULL); | ||
734 | } | ||
735 | |||
736 | /** | ||
737 | * security_context_to_sid_default - Obtain a SID for a given security context, | ||
738 | * falling back to specified default if needed. | ||
739 | * | ||
740 | * @scontext: security context | ||
741 | * @scontext_len: length in bytes | ||
742 | * @sid: security identifier, SID | ||
743 | * @def_sid: default SID to assign on errror | ||
744 | * | ||
745 | * Obtains a SID associated with the security context that | ||
746 | * has the string representation specified by @scontext. | ||
747 | * The default SID is passed to the MLS layer to be used to allow | ||
748 | * kernel labeling of the MLS field if the MLS field is not present | ||
749 | * (for upgrading to MLS without full relabel). | ||
750 | * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient | ||
751 | * memory is available, or 0 on success. | ||
752 | */ | ||
753 | int security_context_to_sid_default(char *scontext, u32 scontext_len, u32 *sid, u32 def_sid) | ||
754 | { | ||
755 | return security_context_to_sid_core(scontext, scontext_len, | ||
756 | sid, def_sid); | ||
757 | } | ||
758 | |||
730 | static int compute_sid_handle_invalid_context( | 759 | static int compute_sid_handle_invalid_context( |
731 | struct context *scontext, | 760 | struct context *scontext, |
732 | struct context *tcontext, | 761 | struct context *tcontext, |