diff options
-rw-r--r-- | Documentation/keys.txt | 21 | ||||
-rw-r--r-- | include/linux/keyctl.h | 1 | ||||
-rw-r--r-- | include/linux/security.h | 20 | ||||
-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 |
9 files changed, 140 insertions, 2 deletions
diff --git a/Documentation/keys.txt b/Documentation/keys.txt index b82d38de8b89..be424b02437d 100644 --- a/Documentation/keys.txt +++ b/Documentation/keys.txt | |||
@@ -711,6 +711,27 @@ The keyctl syscall functions are: | |||
711 | The assumed authoritative key is inherited across fork and exec. | 711 | The assumed authoritative key is inherited across fork and exec. |
712 | 712 | ||
713 | 713 | ||
714 | (*) Get the LSM security context attached to a key. | ||
715 | |||
716 | long keyctl(KEYCTL_GET_SECURITY, key_serial_t key, char *buffer, | ||
717 | size_t buflen) | ||
718 | |||
719 | This function returns a string that represents the LSM security context | ||
720 | attached to a key in the buffer provided. | ||
721 | |||
722 | Unless there's an error, it always returns the amount of data it could | ||
723 | produce, even if that's too big for the buffer, but it won't copy more | ||
724 | than requested to userspace. If the buffer pointer is NULL then no copy | ||
725 | will take place. | ||
726 | |||
727 | A NUL character is included at the end of the string if the buffer is | ||
728 | sufficiently big. This is included in the returned count. If no LSM is | ||
729 | in force then an empty string will be returned. | ||
730 | |||
731 | A process must have view permission on the key for this function to be | ||
732 | successful. | ||
733 | |||
734 | |||
714 | =============== | 735 | =============== |
715 | KERNEL SERVICES | 736 | KERNEL SERVICES |
716 | =============== | 737 | =============== |
diff --git a/include/linux/keyctl.h b/include/linux/keyctl.h index 3365945640c9..656ee6b77a4a 100644 --- a/include/linux/keyctl.h +++ b/include/linux/keyctl.h | |||
@@ -49,5 +49,6 @@ | |||
49 | #define KEYCTL_SET_REQKEY_KEYRING 14 /* set default request-key keyring */ | 49 | #define KEYCTL_SET_REQKEY_KEYRING 14 /* set default request-key keyring */ |
50 | #define KEYCTL_SET_TIMEOUT 15 /* set key timeout */ | 50 | #define KEYCTL_SET_TIMEOUT 15 /* set key timeout */ |
51 | #define KEYCTL_ASSUME_AUTHORITY 16 /* assume request_key() authorisation */ | 51 | #define KEYCTL_ASSUME_AUTHORITY 16 /* assume request_key() authorisation */ |
52 | #define KEYCTL_GET_SECURITY 17 /* get key security label */ | ||
52 | 53 | ||
53 | #endif /* _LINUX_KEYCTL_H */ | 54 | #endif /* _LINUX_KEYCTL_H */ |
diff --git a/include/linux/security.h b/include/linux/security.h index 3ebcdd00b17d..adb09d893ae0 100644 --- a/include/linux/security.h +++ b/include/linux/security.h | |||
@@ -1009,6 +1009,17 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) | |||
1009 | * @perm describes the combination of permissions required of this key. | 1009 | * @perm describes the combination of permissions required of this key. |
1010 | * Return 1 if permission granted, 0 if permission denied and -ve it the | 1010 | * Return 1 if permission granted, 0 if permission denied and -ve it the |
1011 | * normal permissions model should be effected. | 1011 | * normal permissions model should be effected. |
1012 | * @key_getsecurity: | ||
1013 | * Get a textual representation of the security context attached to a key | ||
1014 | * for the purposes of honouring KEYCTL_GETSECURITY. This function | ||
1015 | * allocates the storage for the NUL-terminated string and the caller | ||
1016 | * should free it. | ||
1017 | * @key points to the key to be queried. | ||
1018 | * @_buffer points to a pointer that should be set to point to the | ||
1019 | * resulting string (if no label or an error occurs). | ||
1020 | * Return the length of the string (including terminating NUL) or -ve if | ||
1021 | * an error. | ||
1022 | * May also return 0 (and a NULL buffer pointer) if there is no label. | ||
1012 | * | 1023 | * |
1013 | * Security hooks affecting all System V IPC operations. | 1024 | * Security hooks affecting all System V IPC operations. |
1014 | * | 1025 | * |
@@ -1538,7 +1549,7 @@ struct security_operations { | |||
1538 | int (*key_permission) (key_ref_t key_ref, | 1549 | int (*key_permission) (key_ref_t key_ref, |
1539 | struct task_struct *context, | 1550 | struct task_struct *context, |
1540 | key_perm_t perm); | 1551 | key_perm_t perm); |
1541 | 1552 | int (*key_getsecurity)(struct key *key, char **_buffer); | |
1542 | #endif /* CONFIG_KEYS */ | 1553 | #endif /* CONFIG_KEYS */ |
1543 | 1554 | ||
1544 | #ifdef CONFIG_AUDIT | 1555 | #ifdef CONFIG_AUDIT |
@@ -2732,6 +2743,7 @@ int security_key_alloc(struct key *key, struct task_struct *tsk, unsigned long f | |||
2732 | void security_key_free(struct key *key); | 2743 | void security_key_free(struct key *key); |
2733 | int security_key_permission(key_ref_t key_ref, | 2744 | int security_key_permission(key_ref_t key_ref, |
2734 | struct task_struct *context, key_perm_t perm); | 2745 | struct task_struct *context, key_perm_t perm); |
2746 | int security_key_getsecurity(struct key *key, char **_buffer); | ||
2735 | 2747 | ||
2736 | #else | 2748 | #else |
2737 | 2749 | ||
@@ -2753,6 +2765,12 @@ static inline int security_key_permission(key_ref_t key_ref, | |||
2753 | return 0; | 2765 | return 0; |
2754 | } | 2766 | } |
2755 | 2767 | ||
2768 | static inline int security_key_getsecurity(struct key *key, char **_buffer) | ||
2769 | { | ||
2770 | *_buffer = NULL; | ||
2771 | return 0; | ||
2772 | } | ||
2773 | |||
2756 | #endif | 2774 | #endif |
2757 | #endif /* CONFIG_KEYS */ | 2775 | #endif /* CONFIG_KEYS */ |
2758 | 2776 | ||
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, | |||
994 | { | 994 | { |
995 | return 0; | 995 | return 0; |
996 | } | 996 | } |
997 | |||
998 | static int dummy_key_getsecurity(struct key *key, char **_buffer) | ||
999 | { | ||
1000 | *_buffer = NULL; | ||
1001 | return 0; | ||
1002 | } | ||
1003 | |||
997 | #endif /* CONFIG_KEYS */ | 1004 | #endif /* CONFIG_KEYS */ |
998 | 1005 | ||
999 | #ifdef CONFIG_AUDIT | 1006 | #ifdef CONFIG_AUDIT |
@@ -1210,6 +1217,7 @@ void security_fixup_ops (struct security_operations *ops) | |||
1210 | set_to_dummy_if_null(ops, key_alloc); | 1217 | set_to_dummy_if_null(ops, key_alloc); |
1211 | set_to_dummy_if_null(ops, key_free); | 1218 | set_to_dummy_if_null(ops, key_free); |
1212 | set_to_dummy_if_null(ops, key_permission); | 1219 | set_to_dummy_if_null(ops, key_permission); |
1220 | set_to_dummy_if_null(ops, key_getsecurity); | ||
1213 | #endif /* CONFIG_KEYS */ | 1221 | #endif /* CONFIG_KEYS */ |
1214 | #ifdef CONFIG_AUDIT | 1222 | #ifdef CONFIG_AUDIT |
1215 | set_to_dummy_if_null(ops, audit_rule_init); | 1223 | 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, | |||
79 | case KEYCTL_ASSUME_AUTHORITY: | 79 | case KEYCTL_ASSUME_AUTHORITY: |
80 | return keyctl_assume_authority(arg2); | 80 | return keyctl_assume_authority(arg2); |
81 | 81 | ||
82 | case KEYCTL_GET_SECURITY: | ||
83 | return keyctl_get_security(arg2, compat_ptr(arg3), arg4); | ||
84 | |||
82 | default: | 85 | default: |
83 | return -EOPNOTSUPP; | 86 | return -EOPNOTSUPP; |
84 | } | 87 | } |
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); | |||
155 | extern long keyctl_set_reqkey_keyring(int); | 155 | extern long keyctl_set_reqkey_keyring(int); |
156 | extern long keyctl_set_timeout(key_serial_t, unsigned); | 156 | extern long keyctl_set_timeout(key_serial_t, unsigned); |
157 | extern long keyctl_assume_authority(key_serial_t); | 157 | extern long keyctl_assume_authority(key_serial_t); |
158 | 158 | extern long keyctl_get_security(key_serial_t keyid, char __user *buffer, | |
159 | size_t buflen); | ||
159 | 160 | ||
160 | /* | 161 | /* |
161 | * debugging key validation | 162 | * 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 @@ | |||
20 | #include <linux/string.h> | 20 | #include <linux/string.h> |
21 | #include <linux/err.h> | 21 | #include <linux/err.h> |
22 | #include <linux/vmalloc.h> | 22 | #include <linux/vmalloc.h> |
23 | #include <linux/security.h> | ||
23 | #include <asm/uaccess.h> | 24 | #include <asm/uaccess.h> |
24 | #include "internal.h" | 25 | #include "internal.h" |
25 | 26 | ||
@@ -1080,6 +1081,66 @@ error: | |||
1080 | 1081 | ||
1081 | } /* end keyctl_assume_authority() */ | 1082 | } /* end keyctl_assume_authority() */ |
1082 | 1083 | ||
1084 | /* | ||
1085 | * get the security label of a key | ||
1086 | * - the key must grant us view permission | ||
1087 | * - if there's a buffer, we place up to buflen bytes of data into it | ||
1088 | * - unless there's an error, we return the amount of information available, | ||
1089 | * irrespective of how much we may have copied (including the terminal NUL) | ||
1090 | * - implements keyctl(KEYCTL_GET_SECURITY) | ||
1091 | */ | ||
1092 | long keyctl_get_security(key_serial_t keyid, | ||
1093 | char __user *buffer, | ||
1094 | size_t buflen) | ||
1095 | { | ||
1096 | struct key *key, *instkey; | ||
1097 | key_ref_t key_ref; | ||
1098 | char *context; | ||
1099 | long ret; | ||
1100 | |||
1101 | key_ref = lookup_user_key(NULL, keyid, 0, 1, KEY_VIEW); | ||
1102 | if (IS_ERR(key_ref)) { | ||
1103 | if (PTR_ERR(key_ref) != -EACCES) | ||
1104 | return PTR_ERR(key_ref); | ||
1105 | |||
1106 | /* viewing a key under construction is also permitted if we | ||
1107 | * have the authorisation token handy */ | ||
1108 | instkey = key_get_instantiation_authkey(keyid); | ||
1109 | if (IS_ERR(instkey)) | ||
1110 | return PTR_ERR(key_ref); | ||
1111 | key_put(instkey); | ||
1112 | |||
1113 | key_ref = lookup_user_key(NULL, keyid, 0, 1, 0); | ||
1114 | if (IS_ERR(key_ref)) | ||
1115 | return PTR_ERR(key_ref); | ||
1116 | } | ||
1117 | |||
1118 | key = key_ref_to_ptr(key_ref); | ||
1119 | ret = security_key_getsecurity(key, &context); | ||
1120 | if (ret == 0) { | ||
1121 | /* if no information was returned, give userspace an empty | ||
1122 | * string */ | ||
1123 | ret = 1; | ||
1124 | if (buffer && buflen > 0 && | ||
1125 | copy_to_user(buffer, "", 1) != 0) | ||
1126 | ret = -EFAULT; | ||
1127 | } else if (ret > 0) { | ||
1128 | /* return as much data as there's room for */ | ||
1129 | if (buffer && buflen > 0) { | ||
1130 | if (buflen > ret) | ||
1131 | buflen = ret; | ||
1132 | |||
1133 | if (copy_to_user(buffer, context, buflen) != 0) | ||
1134 | ret = -EFAULT; | ||
1135 | } | ||
1136 | |||
1137 | kfree(context); | ||
1138 | } | ||
1139 | |||
1140 | key_ref_put(key_ref); | ||
1141 | return ret; | ||
1142 | } | ||
1143 | |||
1083 | /*****************************************************************************/ | 1144 | /*****************************************************************************/ |
1084 | /* | 1145 | /* |
1085 | * the key control system call | 1146 | * the key control system call |
@@ -1160,6 +1221,11 @@ asmlinkage long sys_keyctl(int option, unsigned long arg2, unsigned long arg3, | |||
1160 | case KEYCTL_ASSUME_AUTHORITY: | 1221 | case KEYCTL_ASSUME_AUTHORITY: |
1161 | return keyctl_assume_authority((key_serial_t) arg2); | 1222 | return keyctl_assume_authority((key_serial_t) arg2); |
1162 | 1223 | ||
1224 | case KEYCTL_GET_SECURITY: | ||
1225 | return keyctl_get_security((key_serial_t) arg2, | ||
1226 | (char *) arg3, | ||
1227 | (size_t) arg4); | ||
1228 | |||
1163 | default: | 1229 | default: |
1164 | return -EOPNOTSUPP; | 1230 | return -EOPNOTSUPP; |
1165 | } | 1231 | } |
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, | |||
1156 | return security_ops->key_permission(key_ref, context, perm); | 1156 | return security_ops->key_permission(key_ref, context, perm); |
1157 | } | 1157 | } |
1158 | 1158 | ||
1159 | int security_key_getsecurity(struct key *key, char **_buffer) | ||
1160 | { | ||
1161 | return security_ops->key_getsecurity(key, _buffer); | ||
1162 | } | ||
1163 | |||
1159 | #endif /* CONFIG_KEYS */ | 1164 | #endif /* CONFIG_KEYS */ |
1160 | 1165 | ||
1161 | #ifdef CONFIG_AUDIT | 1166 | #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, | |||
5300 | SECCLASS_KEY, perm, NULL); | 5300 | SECCLASS_KEY, perm, NULL); |
5301 | } | 5301 | } |
5302 | 5302 | ||
5303 | static int selinux_key_getsecurity(struct key *key, char **_buffer) | ||
5304 | { | ||
5305 | struct key_security_struct *ksec = key->security; | ||
5306 | char *context = NULL; | ||
5307 | unsigned len; | ||
5308 | int rc; | ||
5309 | |||
5310 | rc = security_sid_to_context(ksec->sid, &context, &len); | ||
5311 | if (!rc) | ||
5312 | rc = len; | ||
5313 | *_buffer = context; | ||
5314 | return rc; | ||
5315 | } | ||
5316 | |||
5303 | #endif | 5317 | #endif |
5304 | 5318 | ||
5305 | static struct security_operations selinux_ops = { | 5319 | static struct security_operations selinux_ops = { |
@@ -5488,6 +5502,7 @@ static struct security_operations selinux_ops = { | |||
5488 | .key_alloc = selinux_key_alloc, | 5502 | .key_alloc = selinux_key_alloc, |
5489 | .key_free = selinux_key_free, | 5503 | .key_free = selinux_key_free, |
5490 | .key_permission = selinux_key_permission, | 5504 | .key_permission = selinux_key_permission, |
5505 | .key_getsecurity = selinux_key_getsecurity, | ||
5491 | #endif | 5506 | #endif |
5492 | 5507 | ||
5493 | #ifdef CONFIG_AUDIT | 5508 | #ifdef CONFIG_AUDIT |