diff options
Diffstat (limited to 'security/keys/keyctl.c')
-rw-r--r-- | security/keys/keyctl.c | 126 |
1 files changed, 112 insertions, 14 deletions
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index d9ca15c109cc..acc9c89e40a8 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c | |||
@@ -19,6 +19,8 @@ | |||
19 | #include <linux/capability.h> | 19 | #include <linux/capability.h> |
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> | ||
23 | #include <linux/security.h> | ||
22 | #include <asm/uaccess.h> | 24 | #include <asm/uaccess.h> |
23 | #include "internal.h" | 25 | #include "internal.h" |
24 | 26 | ||
@@ -62,9 +64,10 @@ asmlinkage long sys_add_key(const char __user *_type, | |||
62 | char type[32], *description; | 64 | char type[32], *description; |
63 | void *payload; | 65 | void *payload; |
64 | long ret; | 66 | long ret; |
67 | bool vm; | ||
65 | 68 | ||
66 | ret = -EINVAL; | 69 | ret = -EINVAL; |
67 | if (plen > 32767) | 70 | if (plen > 1024 * 1024 - 1) |
68 | goto error; | 71 | goto error; |
69 | 72 | ||
70 | /* draw all the data into kernel space */ | 73 | /* draw all the data into kernel space */ |
@@ -81,11 +84,18 @@ asmlinkage long sys_add_key(const char __user *_type, | |||
81 | /* pull the payload in if one was supplied */ | 84 | /* pull the payload in if one was supplied */ |
82 | payload = NULL; | 85 | payload = NULL; |
83 | 86 | ||
87 | vm = false; | ||
84 | if (_payload) { | 88 | if (_payload) { |
85 | ret = -ENOMEM; | 89 | ret = -ENOMEM; |
86 | payload = kmalloc(plen, GFP_KERNEL); | 90 | payload = kmalloc(plen, GFP_KERNEL); |
87 | if (!payload) | 91 | if (!payload) { |
88 | goto error2; | 92 | if (plen <= PAGE_SIZE) |
93 | goto error2; | ||
94 | vm = true; | ||
95 | payload = vmalloc(plen); | ||
96 | if (!payload) | ||
97 | goto error2; | ||
98 | } | ||
89 | 99 | ||
90 | ret = -EFAULT; | 100 | ret = -EFAULT; |
91 | if (copy_from_user(payload, _payload, plen) != 0) | 101 | if (copy_from_user(payload, _payload, plen) != 0) |
@@ -102,7 +112,8 @@ asmlinkage long sys_add_key(const char __user *_type, | |||
102 | /* create or update the requested key and add it to the target | 112 | /* create or update the requested key and add it to the target |
103 | * keyring */ | 113 | * keyring */ |
104 | key_ref = key_create_or_update(keyring_ref, type, description, | 114 | key_ref = key_create_or_update(keyring_ref, type, description, |
105 | payload, plen, KEY_ALLOC_IN_QUOTA); | 115 | payload, plen, KEY_PERM_UNDEF, |
116 | KEY_ALLOC_IN_QUOTA); | ||
106 | if (!IS_ERR(key_ref)) { | 117 | if (!IS_ERR(key_ref)) { |
107 | ret = key_ref_to_ptr(key_ref)->serial; | 118 | ret = key_ref_to_ptr(key_ref)->serial; |
108 | key_ref_put(key_ref); | 119 | key_ref_put(key_ref); |
@@ -113,7 +124,10 @@ asmlinkage long sys_add_key(const char __user *_type, | |||
113 | 124 | ||
114 | key_ref_put(keyring_ref); | 125 | key_ref_put(keyring_ref); |
115 | error3: | 126 | error3: |
116 | kfree(payload); | 127 | if (!vm) |
128 | kfree(payload); | ||
129 | else | ||
130 | vfree(payload); | ||
117 | error2: | 131 | error2: |
118 | kfree(description); | 132 | kfree(description); |
119 | error: | 133 | error: |
@@ -140,6 +154,7 @@ asmlinkage long sys_request_key(const char __user *_type, | |||
140 | struct key_type *ktype; | 154 | struct key_type *ktype; |
141 | struct key *key; | 155 | struct key *key; |
142 | key_ref_t dest_ref; | 156 | key_ref_t dest_ref; |
157 | size_t callout_len; | ||
143 | char type[32], *description, *callout_info; | 158 | char type[32], *description, *callout_info; |
144 | long ret; | 159 | long ret; |
145 | 160 | ||
@@ -157,12 +172,14 @@ asmlinkage long sys_request_key(const char __user *_type, | |||
157 | 172 | ||
158 | /* pull the callout info into kernel space */ | 173 | /* pull the callout info into kernel space */ |
159 | callout_info = NULL; | 174 | callout_info = NULL; |
175 | callout_len = 0; | ||
160 | if (_callout_info) { | 176 | if (_callout_info) { |
161 | callout_info = strndup_user(_callout_info, PAGE_SIZE); | 177 | callout_info = strndup_user(_callout_info, PAGE_SIZE); |
162 | if (IS_ERR(callout_info)) { | 178 | if (IS_ERR(callout_info)) { |
163 | ret = PTR_ERR(callout_info); | 179 | ret = PTR_ERR(callout_info); |
164 | goto error2; | 180 | goto error2; |
165 | } | 181 | } |
182 | callout_len = strlen(callout_info); | ||
166 | } | 183 | } |
167 | 184 | ||
168 | /* get the destination keyring if specified */ | 185 | /* get the destination keyring if specified */ |
@@ -183,8 +200,8 @@ asmlinkage long sys_request_key(const char __user *_type, | |||
183 | } | 200 | } |
184 | 201 | ||
185 | /* do the search */ | 202 | /* do the search */ |
186 | key = request_key_and_link(ktype, description, callout_info, NULL, | 203 | key = request_key_and_link(ktype, description, callout_info, |
187 | key_ref_to_ptr(dest_ref), | 204 | callout_len, NULL, key_ref_to_ptr(dest_ref), |
188 | KEY_ALLOC_IN_QUOTA); | 205 | KEY_ALLOC_IN_QUOTA); |
189 | if (IS_ERR(key)) { | 206 | if (IS_ERR(key)) { |
190 | ret = PTR_ERR(key); | 207 | ret = PTR_ERR(key); |
@@ -714,10 +731,16 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid) | |||
714 | 731 | ||
715 | /* transfer the quota burden to the new user */ | 732 | /* transfer the quota burden to the new user */ |
716 | if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { | 733 | if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { |
734 | unsigned maxkeys = (uid == 0) ? | ||
735 | key_quota_root_maxkeys : key_quota_maxkeys; | ||
736 | unsigned maxbytes = (uid == 0) ? | ||
737 | key_quota_root_maxbytes : key_quota_maxbytes; | ||
738 | |||
717 | spin_lock(&newowner->lock); | 739 | spin_lock(&newowner->lock); |
718 | if (newowner->qnkeys + 1 >= KEYQUOTA_MAX_KEYS || | 740 | if (newowner->qnkeys + 1 >= maxkeys || |
719 | newowner->qnbytes + key->quotalen >= | 741 | newowner->qnbytes + key->quotalen >= maxbytes || |
720 | KEYQUOTA_MAX_BYTES) | 742 | newowner->qnbytes + key->quotalen < |
743 | newowner->qnbytes) | ||
721 | goto quota_overrun; | 744 | goto quota_overrun; |
722 | 745 | ||
723 | newowner->qnkeys++; | 746 | newowner->qnkeys++; |
@@ -821,9 +844,10 @@ long keyctl_instantiate_key(key_serial_t id, | |||
821 | key_ref_t keyring_ref; | 844 | key_ref_t keyring_ref; |
822 | void *payload; | 845 | void *payload; |
823 | long ret; | 846 | long ret; |
847 | bool vm = false; | ||
824 | 848 | ||
825 | ret = -EINVAL; | 849 | ret = -EINVAL; |
826 | if (plen > 32767) | 850 | if (plen > 1024 * 1024 - 1) |
827 | goto error; | 851 | goto error; |
828 | 852 | ||
829 | /* the appropriate instantiation authorisation key must have been | 853 | /* the appropriate instantiation authorisation key must have been |
@@ -843,8 +867,14 @@ long keyctl_instantiate_key(key_serial_t id, | |||
843 | if (_payload) { | 867 | if (_payload) { |
844 | ret = -ENOMEM; | 868 | ret = -ENOMEM; |
845 | payload = kmalloc(plen, GFP_KERNEL); | 869 | payload = kmalloc(plen, GFP_KERNEL); |
846 | if (!payload) | 870 | if (!payload) { |
847 | goto error; | 871 | if (plen <= PAGE_SIZE) |
872 | goto error; | ||
873 | vm = true; | ||
874 | payload = vmalloc(plen); | ||
875 | if (!payload) | ||
876 | goto error; | ||
877 | } | ||
848 | 878 | ||
849 | ret = -EFAULT; | 879 | ret = -EFAULT; |
850 | if (copy_from_user(payload, _payload, plen) != 0) | 880 | if (copy_from_user(payload, _payload, plen) != 0) |
@@ -877,7 +907,10 @@ long keyctl_instantiate_key(key_serial_t id, | |||
877 | } | 907 | } |
878 | 908 | ||
879 | error2: | 909 | error2: |
880 | kfree(payload); | 910 | if (!vm) |
911 | kfree(payload); | ||
912 | else | ||
913 | vfree(payload); | ||
881 | error: | 914 | error: |
882 | return ret; | 915 | return ret; |
883 | 916 | ||
@@ -1055,6 +1088,66 @@ error: | |||
1055 | 1088 | ||
1056 | } /* end keyctl_assume_authority() */ | 1089 | } /* end keyctl_assume_authority() */ |
1057 | 1090 | ||
1091 | /* | ||
1092 | * get the security label of a key | ||
1093 | * - the key must grant us view permission | ||
1094 | * - if there's a buffer, we place up to buflen bytes of data into it | ||
1095 | * - unless there's an error, we return the amount of information available, | ||
1096 | * irrespective of how much we may have copied (including the terminal NUL) | ||
1097 | * - implements keyctl(KEYCTL_GET_SECURITY) | ||
1098 | */ | ||
1099 | long keyctl_get_security(key_serial_t keyid, | ||
1100 | char __user *buffer, | ||
1101 | size_t buflen) | ||
1102 | { | ||
1103 | struct key *key, *instkey; | ||
1104 | key_ref_t key_ref; | ||
1105 | char *context; | ||
1106 | long ret; | ||
1107 | |||
1108 | key_ref = lookup_user_key(NULL, keyid, 0, 1, KEY_VIEW); | ||
1109 | if (IS_ERR(key_ref)) { | ||
1110 | if (PTR_ERR(key_ref) != -EACCES) | ||
1111 | return PTR_ERR(key_ref); | ||
1112 | |||
1113 | /* viewing a key under construction is also permitted if we | ||
1114 | * have the authorisation token handy */ | ||
1115 | instkey = key_get_instantiation_authkey(keyid); | ||
1116 | if (IS_ERR(instkey)) | ||
1117 | return PTR_ERR(key_ref); | ||
1118 | key_put(instkey); | ||
1119 | |||
1120 | key_ref = lookup_user_key(NULL, keyid, 0, 1, 0); | ||
1121 | if (IS_ERR(key_ref)) | ||
1122 | return PTR_ERR(key_ref); | ||
1123 | } | ||
1124 | |||
1125 | key = key_ref_to_ptr(key_ref); | ||
1126 | ret = security_key_getsecurity(key, &context); | ||
1127 | if (ret == 0) { | ||
1128 | /* if no information was returned, give userspace an empty | ||
1129 | * string */ | ||
1130 | ret = 1; | ||
1131 | if (buffer && buflen > 0 && | ||
1132 | copy_to_user(buffer, "", 1) != 0) | ||
1133 | ret = -EFAULT; | ||
1134 | } else if (ret > 0) { | ||
1135 | /* return as much data as there's room for */ | ||
1136 | if (buffer && buflen > 0) { | ||
1137 | if (buflen > ret) | ||
1138 | buflen = ret; | ||
1139 | |||
1140 | if (copy_to_user(buffer, context, buflen) != 0) | ||
1141 | ret = -EFAULT; | ||
1142 | } | ||
1143 | |||
1144 | kfree(context); | ||
1145 | } | ||
1146 | |||
1147 | key_ref_put(key_ref); | ||
1148 | return ret; | ||
1149 | } | ||
1150 | |||
1058 | /*****************************************************************************/ | 1151 | /*****************************************************************************/ |
1059 | /* | 1152 | /* |
1060 | * the key control system call | 1153 | * the key control system call |
@@ -1135,6 +1228,11 @@ asmlinkage long sys_keyctl(int option, unsigned long arg2, unsigned long arg3, | |||
1135 | case KEYCTL_ASSUME_AUTHORITY: | 1228 | case KEYCTL_ASSUME_AUTHORITY: |
1136 | return keyctl_assume_authority((key_serial_t) arg2); | 1229 | return keyctl_assume_authority((key_serial_t) arg2); |
1137 | 1230 | ||
1231 | case KEYCTL_GET_SECURITY: | ||
1232 | return keyctl_get_security((key_serial_t) arg2, | ||
1233 | (char *) arg3, | ||
1234 | (size_t) arg4); | ||
1235 | |||
1138 | default: | 1236 | default: |
1139 | return -EOPNOTSUPP; | 1237 | return -EOPNOTSUPP; |
1140 | } | 1238 | } |