From f5c1d5b2aaf9a98f15a6dcdfbba1f494d0aaae52 Mon Sep 17 00:00:00 2001 From: James Morris Date: Thu, 28 Jul 2005 01:07:37 -0700 Subject: [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 Signed-off-by: Stephen Smalley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- security/selinux/hooks.c | 3 +- security/selinux/include/security.h | 2 ++ security/selinux/ss/mls.c | 71 +++++++++++++++++++++++++------------ security/selinux/ss/mls.h | 4 ++- security/selinux/ss/services.c | 55 +++++++++++++++++++++------- 5 files changed, 97 insertions(+), 38 deletions(-) (limited to 'security') diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 6be2738..10fd51c 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 sid = sbsec->def_sid; rc = 0; } else { - rc = security_context_to_sid(context, rc, &sid); + rc = security_context_to_sid_default(context, rc, &sid, + sbsec->def_sid); if (rc) { printk(KERN_WARNING "%s: context_to_sid(%s) " "returned %d for dev=%s ino=%ld\n", diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index fa187c9a..71c0a19 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, int security_context_to_sid(char *scontext, u32 scontext_len, u32 *out_sid); +int security_context_to_sid_default(char *scontext, u32 scontext_len, u32 *out_sid, u32 def_sid); + int security_get_user_sids(u32 callsid, char *username, u32 **sids, u32 *nel); diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c index 756036b..d4c32c3 100644 --- a/security/selinux/ss/mls.c +++ b/security/selinux/ss/mls.c @@ -15,6 +15,7 @@ #include #include #include +#include "sidtab.h" #include "mls.h" #include "policydb.h" #include "services.h" @@ -208,6 +209,26 @@ int mls_context_isvalid(struct policydb *p, struct context *c) } /* + * Copies the MLS range from `src' into `dst'. + */ +static inline int mls_copy_context(struct context *dst, + struct context *src) +{ + int l, rc = 0; + + /* Copy the MLS range from the source context */ + for (l = 0; l < 2; l++) { + dst->range.level[l].sens = src->range.level[l].sens; + rc = ebitmap_cpy(&dst->range.level[l].cat, + &src->range.level[l].cat); + if (rc) + break; + } + + return rc; +} + +/* * Set the MLS fields in the security context structure * `context' based on the string representation in * the string `*scontext'. Update `*scontext' to @@ -216,10 +237,20 @@ int mls_context_isvalid(struct policydb *p, struct context *c) * * This function modifies the string in place, inserting * NULL characters to terminate the MLS fields. + * + * If a def_sid is provided and no MLS field is present, + * copy the MLS field of the associated default context. + * Used for upgraded to MLS systems where objects may lack + * MLS fields. + * + * Policy read-lock must be held for sidtab lookup. + * */ int mls_context_to_sid(char oldc, char **scontext, - struct context *context) + struct context *context, + struct sidtab *s, + u32 def_sid) { char delim; @@ -231,9 +262,23 @@ int mls_context_to_sid(char oldc, if (!selinux_mls_enabled) return 0; - /* No MLS component to the security context. */ - if (!oldc) + /* + * No MLS component to the security context, try and map to + * default if provided. + */ + if (!oldc) { + struct context *defcon; + + if (def_sid == SECSID_NULL) + goto out; + + defcon = sidtab_search(s, def_sid); + if (!defcon) + goto out; + + rc = mls_copy_context(context, defcon); goto out; + } /* Extract low sensitivity. */ scontextp = p = *scontext; @@ -334,26 +379,6 @@ out: } /* - * Copies the MLS range from `src' into `dst'. - */ -static inline int mls_copy_context(struct context *dst, - struct context *src) -{ - int l, rc = 0; - - /* Copy the MLS range from the source context */ - for (l = 0; l < 2; l++) { - dst->range.level[l].sens = src->range.level[l].sens; - rc = ebitmap_cpy(&dst->range.level[l].cat, - &src->range.level[l].cat); - if (rc) - break; - } - - return rc; -} - -/* * Copies the effective MLS range from `src' into `dst'. */ static inline int mls_scopy_context(struct context *dst, diff --git a/security/selinux/ss/mls.h b/security/selinux/ss/mls.h index 0d37bea..03de697 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); int mls_context_to_sid(char oldc, char **scontext, - struct context *context); + struct context *context, + struct sidtab *s, + u32 def_sid); int mls_convert_context(struct policydb *oldp, struct policydb *newp, diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 922bb45..0141204 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -601,18 +601,7 @@ out: } -/** - * security_context_to_sid - Obtain a SID for a given security context. - * @scontext: security context - * @scontext_len: length in bytes - * @sid: security identifier, SID - * - * Obtains a SID associated with the security context that - * has the string representation specified by @scontext. - * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient - * memory is available, or 0 on success. - */ -int security_context_to_sid(char *scontext, u32 scontext_len, u32 *sid) +static int security_context_to_sid_core(char *scontext, u32 scontext_len, u32 *sid, u32 def_sid) { char *scontext2; struct context context; @@ -703,7 +692,7 @@ int security_context_to_sid(char *scontext, u32 scontext_len, u32 *sid) context.type = typdatum->value; - rc = mls_context_to_sid(oldc, &p, &context); + rc = mls_context_to_sid(oldc, &p, &context, &sidtab, def_sid); if (rc) goto out_unlock; @@ -727,6 +716,46 @@ out: return rc; } +/** + * security_context_to_sid - Obtain a SID for a given security context. + * @scontext: security context + * @scontext_len: length in bytes + * @sid: security identifier, SID + * + * Obtains a SID associated with the security context that + * has the string representation specified by @scontext. + * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient + * memory is available, or 0 on success. + */ +int security_context_to_sid(char *scontext, u32 scontext_len, u32 *sid) +{ + return security_context_to_sid_core(scontext, scontext_len, + sid, SECSID_NULL); +} + +/** + * security_context_to_sid_default - Obtain a SID for a given security context, + * falling back to specified default if needed. + * + * @scontext: security context + * @scontext_len: length in bytes + * @sid: security identifier, SID + * @def_sid: default SID to assign on errror + * + * Obtains a SID associated with the security context that + * has the string representation specified by @scontext. + * The default SID is passed to the MLS layer to be used to allow + * kernel labeling of the MLS field if the MLS field is not present + * (for upgrading to MLS without full relabel). + * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient + * memory is available, or 0 on success. + */ +int security_context_to_sid_default(char *scontext, u32 scontext_len, u32 *sid, u32 def_sid) +{ + return security_context_to_sid_core(scontext, scontext_len, + sid, def_sid); +} + static int compute_sid_handle_invalid_context( struct context *scontext, struct context *tcontext, -- cgit v1.1 From 911656f8a630e36b22c7e2bba3317dec9174209c Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Thu, 28 Jul 2005 21:16:21 -0700 Subject: [PATCH] selinux: Fix address length checks in connect hook This patch fixes the address length checks in the selinux_socket_connect hook to be no more restrictive than the underlying ipv4 and ipv6 code; otherwise, this hook can reject valid connect calls. This patch is in response to a bug report where an application was calling connect on an INET6 socket with an address that didn't include the optional scope id and failing due to these checks. Signed-off-by: Stephen Smalley Signed-off-by: James Morris Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- security/selinux/hooks.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'security') diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 10fd51c..2253f38 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -3126,12 +3126,12 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, if (sk->sk_family == PF_INET) { addr4 = (struct sockaddr_in *)address; - if (addrlen != sizeof(struct sockaddr_in)) + if (addrlen < sizeof(struct sockaddr_in)) return -EINVAL; snum = ntohs(addr4->sin_port); } else { addr6 = (struct sockaddr_in6 *)address; - if (addrlen != sizeof(struct sockaddr_in6)) + if (addrlen < SIN6_LEN_RFC2133) return -EINVAL; snum = ntohs(addr6->sin6_port); } -- cgit v1.1 From 1260f801b4e4ba7be200886b4a53d730de05ca19 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 4 Aug 2005 11:50:01 +0100 Subject: [PATCH] Keys: Fix key management syscall interface bugs This fixes five bugs in the key management syscall interface: (1) add_key() returns 0 rather than EINVAL if the key type is "". Checking the key type isn't "" should be left to lookup_user_key(). (2) request_key() returns ENOKEY rather than EPERM if the key type begins with a ".". lookup_user_key() can't do this because internal key types begin with a ".". (3) Key revocation always returns 0, even if it fails. (4) Key read can return EAGAIN rather than EACCES under some circumstances. A key is permitted to by read by a process if it doesn't grant read access, but it does grant search access and it is in the process's keyrings. That search returns EAGAIN if it fails, and this needs translating to EACCES. (5) request_key() never adds the new key to the destination keyring if one is supplied. The wrong macro was being used to test for an error condition: PTR_ERR() will always return true, whether or not there's an error; this should've been IS_ERR(). Signed-Off-By: David Howells Signed-Off-By: Linus Torvalds --- security/keys/keyctl.c | 11 +++++++---- security/keys/request_key.c | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'security') diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index fea2628..a6516a6 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c @@ -49,9 +49,6 @@ asmlinkage long sys_add_key(const char __user *_type, goto error; type[31] = '\0'; - if (!type[0]) - goto error; - ret = -EPERM; if (type[0] == '.') goto error; @@ -144,6 +141,10 @@ asmlinkage long sys_request_key(const char __user *_type, goto error; type[31] = '\0'; + ret = -EPERM; + if (type[0] == '.') + goto error; + /* pull the description into kernel space */ ret = -EFAULT; dlen = strnlen_user(_description, PAGE_SIZE - 1); @@ -362,7 +363,7 @@ long keyctl_revoke_key(key_serial_t id) key_put(key); error: - return 0; + return ret; } /* end keyctl_revoke_key() */ @@ -685,6 +686,8 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen) goto can_read_key2; ret = PTR_ERR(skey); + if (ret == -EAGAIN) + ret = -EACCES; goto error2; } diff --git a/security/keys/request_key.c b/security/keys/request_key.c index dfcd983..90c1506 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c @@ -405,7 +405,7 @@ struct key *request_key_and_link(struct key_type *type, key_user_put(user); /* link the new key into the appropriate keyring */ - if (!PTR_ERR(key)) + if (!IS_ERR(key)) request_key_link(key, dest_keyring); } -- cgit v1.1 From bcf945d36fa0598f41ac4ad46a9dc43135460263 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 4 Aug 2005 13:07:06 -0700 Subject: [PATCH] Error during attempt to join key management session can leave semaphore pinned The attached patch prevents an error during the key session joining operation from hanging future joins in the D state [CAN-2005-2098]. The problem is that the error handling path for the KEYCTL_JOIN_SESSION_KEYRING operation has one error path that doesn't release the session management semaphore. Further attempts to get the semaphore will then sleep for ever in the D state. This can happen in four situations, all involving an attempt to allocate a new session keyring: (1) ENOMEM. (2) The users key quota being reached. (3) A keyring name that is an empty string. (4) A keyring name that is too long. Any user may attempt this operation, and so any user can cause the problem to occur. Signed-Off-By: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- security/keys/process_keys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'security') diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index 9b0369c..c089f78 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c @@ -678,7 +678,7 @@ long join_session_keyring(const char *name) keyring = keyring_alloc(name, tsk->uid, tsk->gid, 0, NULL); if (IS_ERR(keyring)) { ret = PTR_ERR(keyring); - goto error; + goto error2; } } else if (IS_ERR(keyring)) { -- cgit v1.1 From 94efe72f762e2c147d8146d637d5ece5614c8d94 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 4 Aug 2005 13:07:07 -0700 Subject: [PATCH] Destruction of failed keyring oopses The attached patch makes sure that a keyring that failed to instantiate properly is destroyed without oopsing [CAN-2005-2099]. The problem occurs in three stages: (1) The key allocator initialises the type-specific data to all zeroes. In the case of a keyring, this will become a link in the keyring name list when the keyring is instantiated. (2) If a user (any user) attempts to add a keyring with anything other than an empty payload, the keyring instantiation function will fail with an error and won't add the keyring to the name list. (3) The keyring's destructor then sees that the keyring has a description (name) and tries to remove the keyring from the name list, which oopses because the link pointers are both zero. This bug permits any user to take down a box trivially. Signed-Off-By: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- security/keys/keyring.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'security') diff --git a/security/keys/keyring.c b/security/keys/keyring.c index a1f6bac..9c208c7 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c @@ -201,7 +201,11 @@ static void keyring_destroy(struct key *keyring) if (keyring->description) { write_lock(&keyring_name_lock); - list_del(&keyring->type_data.link); + + if (keyring->type_data.link.next != NULL && + !list_empty(&keyring->type_data.link)) + list_del(&keyring->type_data.link); + write_unlock(&keyring_name_lock); } -- cgit v1.1