diff options
Diffstat (limited to 'security')
-rw-r--r-- | security/dummy.c | 8 | ||||
-rw-r--r-- | security/keys/compat.c | 3 | ||||
-rw-r--r-- | security/keys/internal.h | 3 | ||||
-rw-r--r-- | security/keys/keyctl.c | 66 | ||||
-rw-r--r-- | security/security.c | 5 | ||||
-rw-r--r-- | security/selinux/hooks.c | 15 |
6 files changed, 99 insertions, 1 deletions
diff --git a/security/dummy.c b/security/dummy.c index 26ee06ef0e93..48cf30226e16 100644 --- a/security/dummy.c +++ b/security/dummy.c @@ -994,6 +994,13 @@ static inline int dummy_key_permission(key_ref_t key_ref, { return 0; } + +static int dummy_key_getsecurity(struct key *key, char **_buffer) +{ + *_buffer = NULL; + return 0; +} + #endif /* CONFIG_KEYS */ #ifdef CONFIG_AUDIT @@ -1210,6 +1217,7 @@ void security_fixup_ops (struct security_operations *ops) set_to_dummy_if_null(ops, key_alloc); set_to_dummy_if_null(ops, key_free); set_to_dummy_if_null(ops, key_permission); + set_to_dummy_if_null(ops, key_getsecurity); #endif /* CONFIG_KEYS */ #ifdef CONFIG_AUDIT set_to_dummy_if_null(ops, audit_rule_init); diff --git a/security/keys/compat.c b/security/keys/compat.c index e10ec995f275..c766c68a63bc 100644 --- a/security/keys/compat.c +++ b/security/keys/compat.c @@ -79,6 +79,9 @@ asmlinkage long compat_sys_keyctl(u32 option, case KEYCTL_ASSUME_AUTHORITY: return keyctl_assume_authority(arg2); + case KEYCTL_GET_SECURITY: + return keyctl_get_security(arg2, compat_ptr(arg3), arg4); + default: return -EOPNOTSUPP; } diff --git a/security/keys/internal.h b/security/keys/internal.h index 3cc04c2afe1c..6361d3736dbc 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h @@ -155,7 +155,8 @@ extern long keyctl_negate_key(key_serial_t, unsigned, key_serial_t); extern long keyctl_set_reqkey_keyring(int); extern long keyctl_set_timeout(key_serial_t, unsigned); extern long keyctl_assume_authority(key_serial_t); - +extern long keyctl_get_security(key_serial_t keyid, char __user *buffer, + size_t buflen); /* * debugging key validation diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 1698bf90ee84..56e963b700b9 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c @@ -20,6 +20,7 @@ #include <linux/string.h> #include <linux/err.h> #include <linux/vmalloc.h> +#include <linux/security.h> #include <asm/uaccess.h> #include "internal.h" @@ -1080,6 +1081,66 @@ error: } /* end keyctl_assume_authority() */ +/* + * get the security label of a key + * - the key must grant us view permission + * - if there's a buffer, we place up to buflen bytes of data into it + * - unless there's an error, we return the amount of information available, + * irrespective of how much we may have copied (including the terminal NUL) + * - implements keyctl(KEYCTL_GET_SECURITY) + */ +long keyctl_get_security(key_serial_t keyid, + char __user *buffer, + size_t buflen) +{ + struct key *key, *instkey; + key_ref_t key_ref; + char *context; + long ret; + + key_ref = lookup_user_key(NULL, keyid, 0, 1, KEY_VIEW); + if (IS_ERR(key_ref)) { + if (PTR_ERR(key_ref) != -EACCES) + return PTR_ERR(key_ref); + + /* viewing a key under construction is also permitted if we + * have the authorisation token handy */ + instkey = key_get_instantiation_authkey(keyid); + if (IS_ERR(instkey)) + return PTR_ERR(key_ref); + key_put(instkey); + + key_ref = lookup_user_key(NULL, keyid, 0, 1, 0); + if (IS_ERR(key_ref)) + return PTR_ERR(key_ref); + } + + key = key_ref_to_ptr(key_ref); + ret = security_key_getsecurity(key, &context); + if (ret == 0) { + /* if no information was returned, give userspace an empty + * string */ + ret = 1; + if (buffer && buflen > 0 && + copy_to_user(buffer, "", 1) != 0) + ret = -EFAULT; + } else if (ret > 0) { + /* return as much data as there's room for */ + if (buffer && buflen > 0) { + if (buflen > ret) + buflen = ret; + + if (copy_to_user(buffer, context, buflen) != 0) + ret = -EFAULT; + } + + kfree(context); + } + + key_ref_put(key_ref); + return ret; +} + /*****************************************************************************/ /* * the key control system call @@ -1160,6 +1221,11 @@ asmlinkage long sys_keyctl(int option, unsigned long arg2, unsigned long arg3, case KEYCTL_ASSUME_AUTHORITY: return keyctl_assume_authority((key_serial_t) arg2); + case KEYCTL_GET_SECURITY: + return keyctl_get_security((key_serial_t) arg2, + (char *) arg3, + (size_t) arg4); + default: return -EOPNOTSUPP; } diff --git a/security/security.c b/security/security.c index a809035441ab..8e64a29dc55d 100644 --- a/security/security.c +++ b/security/security.c @@ -1156,6 +1156,11 @@ int security_key_permission(key_ref_t key_ref, return security_ops->key_permission(key_ref, context, perm); } +int security_key_getsecurity(struct key *key, char **_buffer) +{ + return security_ops->key_getsecurity(key, _buffer); +} + #endif /* CONFIG_KEYS */ #ifdef CONFIG_AUDIT diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 047365ac9faa..838d1e5e63a1 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -5300,6 +5300,20 @@ static int selinux_key_permission(key_ref_t key_ref, SECCLASS_KEY, perm, NULL); } +static int selinux_key_getsecurity(struct key *key, char **_buffer) +{ + struct key_security_struct *ksec = key->security; + char *context = NULL; + unsigned len; + int rc; + + rc = security_sid_to_context(ksec->sid, &context, &len); + if (!rc) + rc = len; + *_buffer = context; + return rc; +} + #endif static struct security_operations selinux_ops = { @@ -5488,6 +5502,7 @@ static struct security_operations selinux_ops = { .key_alloc = selinux_key_alloc, .key_free = selinux_key_free, .key_permission = selinux_key_permission, + .key_getsecurity = selinux_key_getsecurity, #endif #ifdef CONFIG_AUDIT |