aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2016-04-12 15:09:34 -0400
committerDavid Howells <dhowells@redhat.com>2016-04-12 15:09:34 -0400
commit6e007f3186e398ec4e3b6d4f1c22740d9dc2715e (patch)
tree3e5cc20804b646256525cd9c2de7a9681d7e4996
parent3c9d6296b7aee536a96ea2b53a15d23511738c1c (diff)
parentddbb41148724367394d0880c516bfaeed127b52e (diff)
Merge branch 'keys-misc' into keys-next
Miscellaneous keyrings changes. Signed-off-by: David Howells <dhowells@redhat.com>
-rw-r--r--Documentation/security/keys.txt30
-rw-r--r--include/uapi/linux/keyctl.h10
-rw-r--r--security/integrity/Kconfig1
-rw-r--r--security/keys/Kconfig15
-rw-r--r--security/keys/Makefile1
-rw-r--r--security/keys/big_key.c198
-rw-r--r--security/keys/compat.c4
-rw-r--r--security/keys/dh.c160
-rw-r--r--security/keys/internal.h12
-rw-r--r--security/keys/keyctl.c5
-rw-r--r--security/keys/user_defined.c42
11 files changed, 428 insertions, 50 deletions
diff --git a/Documentation/security/keys.txt b/Documentation/security/keys.txt
index 8c183873b2b7..a2f70cf6763a 100644
--- a/Documentation/security/keys.txt
+++ b/Documentation/security/keys.txt
@@ -823,6 +823,36 @@ The keyctl syscall functions are:
823 A process must have search permission on the key for this function to be 823 A process must have search permission on the key for this function to be
824 successful. 824 successful.
825 825
826 (*) Compute a Diffie-Hellman shared secret or public key
827
828 long keyctl(KEYCTL_DH_COMPUTE, struct keyctl_dh_params *params,
829 char *buffer, size_t buflen);
830
831 The params struct contains serial numbers for three keys:
832
833 - The prime, p, known to both parties
834 - The local private key
835 - The base integer, which is either a shared generator or the
836 remote public key
837
838 The value computed is:
839
840 result = base ^ private (mod prime)
841
842 If the base is the shared generator, the result is the local
843 public key. If the base is the remote public key, the result is
844 the shared secret.
845
846 The buffer length must be at least the length of the prime, or zero.
847
848 If the buffer length is nonzero, the length of the result is
849 returned when it is successfully calculated and copied in to the
850 buffer. When the buffer length is zero, the minimum required
851 buffer length is returned.
852
853 This function will return error EOPNOTSUPP if the key type is not
854 supported, error ENOKEY if the key could not be found, or error
855 EACCES if the key is not readable by the caller.
826 856
827=============== 857===============
828KERNEL SERVICES 858KERNEL SERVICES
diff --git a/include/uapi/linux/keyctl.h b/include/uapi/linux/keyctl.h
index 840cb990abe2..86eddd6241f3 100644
--- a/include/uapi/linux/keyctl.h
+++ b/include/uapi/linux/keyctl.h
@@ -12,6 +12,8 @@
12#ifndef _LINUX_KEYCTL_H 12#ifndef _LINUX_KEYCTL_H
13#define _LINUX_KEYCTL_H 13#define _LINUX_KEYCTL_H
14 14
15#include <linux/types.h>
16
15/* special process keyring shortcut IDs */ 17/* special process keyring shortcut IDs */
16#define KEY_SPEC_THREAD_KEYRING -1 /* - key ID for thread-specific keyring */ 18#define KEY_SPEC_THREAD_KEYRING -1 /* - key ID for thread-specific keyring */
17#define KEY_SPEC_PROCESS_KEYRING -2 /* - key ID for process-specific keyring */ 19#define KEY_SPEC_PROCESS_KEYRING -2 /* - key ID for process-specific keyring */
@@ -57,5 +59,13 @@
57#define KEYCTL_INSTANTIATE_IOV 20 /* instantiate a partially constructed key */ 59#define KEYCTL_INSTANTIATE_IOV 20 /* instantiate a partially constructed key */
58#define KEYCTL_INVALIDATE 21 /* invalidate a key */ 60#define KEYCTL_INVALIDATE 21 /* invalidate a key */
59#define KEYCTL_GET_PERSISTENT 22 /* get a user's persistent keyring */ 61#define KEYCTL_GET_PERSISTENT 22 /* get a user's persistent keyring */
62#define KEYCTL_DH_COMPUTE 23 /* Compute Diffie-Hellman values */
63
64/* keyctl structures */
65struct keyctl_dh_params {
66 __s32 private;
67 __s32 prime;
68 __s32 base;
69};
60 70
61#endif /* _LINUX_KEYCTL_H */ 71#endif /* _LINUX_KEYCTL_H */
diff --git a/security/integrity/Kconfig b/security/integrity/Kconfig
index 979be65d22c4..da9565891738 100644
--- a/security/integrity/Kconfig
+++ b/security/integrity/Kconfig
@@ -35,7 +35,6 @@ config INTEGRITY_ASYMMETRIC_KEYS
35 default n 35 default n
36 select ASYMMETRIC_KEY_TYPE 36 select ASYMMETRIC_KEY_TYPE
37 select ASYMMETRIC_PUBLIC_KEY_SUBTYPE 37 select ASYMMETRIC_PUBLIC_KEY_SUBTYPE
38 select PUBLIC_KEY_ALGO_RSA
39 select CRYPTO_RSA 38 select CRYPTO_RSA
40 select X509_CERTIFICATE_PARSER 39 select X509_CERTIFICATE_PARSER
41 help 40 help
diff --git a/security/keys/Kconfig b/security/keys/Kconfig
index fe4d74e126a7..f826e8739023 100644
--- a/security/keys/Kconfig
+++ b/security/keys/Kconfig
@@ -41,6 +41,10 @@ config BIG_KEYS
41 bool "Large payload keys" 41 bool "Large payload keys"
42 depends on KEYS 42 depends on KEYS
43 depends on TMPFS 43 depends on TMPFS
44 select CRYPTO
45 select CRYPTO_AES
46 select CRYPTO_ECB
47 select CRYPTO_RNG
44 help 48 help
45 This option provides support for holding large keys within the kernel 49 This option provides support for holding large keys within the kernel
46 (for example Kerberos ticket caches). The data may be stored out to 50 (for example Kerberos ticket caches). The data may be stored out to
@@ -81,3 +85,14 @@ config ENCRYPTED_KEYS
81 Userspace only ever sees/stores encrypted blobs. 85 Userspace only ever sees/stores encrypted blobs.
82 86
83 If you are unsure as to whether this is required, answer N. 87 If you are unsure as to whether this is required, answer N.
88
89config KEY_DH_OPERATIONS
90 bool "Diffie-Hellman operations on retained keys"
91 depends on KEYS
92 select MPILIB
93 help
94 This option provides support for calculating Diffie-Hellman
95 public keys and shared secrets using values stored as keys
96 in the kernel.
97
98 If you are unsure as to whether this is required, answer N.
diff --git a/security/keys/Makefile b/security/keys/Makefile
index dfb3a7bededf..1fd4a16e6daf 100644
--- a/security/keys/Makefile
+++ b/security/keys/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_KEYS_COMPAT) += compat.o
19obj-$(CONFIG_PROC_FS) += proc.o 19obj-$(CONFIG_PROC_FS) += proc.o
20obj-$(CONFIG_SYSCTL) += sysctl.o 20obj-$(CONFIG_SYSCTL) += sysctl.o
21obj-$(CONFIG_PERSISTENT_KEYRINGS) += persistent.o 21obj-$(CONFIG_PERSISTENT_KEYRINGS) += persistent.o
22obj-$(CONFIG_KEY_DH_OPERATIONS) += dh.o
22 23
23# 24#
24# Key types 25# Key types
diff --git a/security/keys/big_key.c b/security/keys/big_key.c
index c721e398893a..9e443fccad4c 100644
--- a/security/keys/big_key.c
+++ b/security/keys/big_key.c
@@ -14,8 +14,10 @@
14#include <linux/file.h> 14#include <linux/file.h>
15#include <linux/shmem_fs.h> 15#include <linux/shmem_fs.h>
16#include <linux/err.h> 16#include <linux/err.h>
17#include <linux/scatterlist.h>
17#include <keys/user-type.h> 18#include <keys/user-type.h>
18#include <keys/big_key-type.h> 19#include <keys/big_key-type.h>
20#include <crypto/rng.h>
19 21
20/* 22/*
21 * Layout of key payload words. 23 * Layout of key payload words.
@@ -28,6 +30,14 @@ enum {
28}; 30};
29 31
30/* 32/*
33 * Crypto operation with big_key data
34 */
35enum big_key_op {
36 BIG_KEY_ENC,
37 BIG_KEY_DEC,
38};
39
40/*
31 * If the data is under this limit, there's no point creating a shm file to 41 * If the data is under this limit, there's no point creating a shm file to
32 * hold it as the permanently resident metadata for the shmem fs will be at 42 * hold it as the permanently resident metadata for the shmem fs will be at
33 * least as large as the data. 43 * least as large as the data.
@@ -35,6 +45,11 @@ enum {
35#define BIG_KEY_FILE_THRESHOLD (sizeof(struct inode) + sizeof(struct dentry)) 45#define BIG_KEY_FILE_THRESHOLD (sizeof(struct inode) + sizeof(struct dentry))
36 46
37/* 47/*
48 * Key size for big_key data encryption
49 */
50#define ENC_KEY_SIZE 16
51
52/*
38 * big_key defined keys take an arbitrary string as the description and an 53 * big_key defined keys take an arbitrary string as the description and an
39 * arbitrary blob of data as the payload 54 * arbitrary blob of data as the payload
40 */ 55 */
@@ -50,12 +65,62 @@ struct key_type key_type_big_key = {
50}; 65};
51 66
52/* 67/*
68 * Crypto names for big_key data encryption
69 */
70static const char big_key_rng_name[] = "stdrng";
71static const char big_key_alg_name[] = "ecb(aes)";
72
73/*
74 * Crypto algorithms for big_key data encryption
75 */
76static struct crypto_rng *big_key_rng;
77static struct crypto_blkcipher *big_key_blkcipher;
78
79/*
80 * Generate random key to encrypt big_key data
81 */
82static inline int big_key_gen_enckey(u8 *key)
83{
84 return crypto_rng_get_bytes(big_key_rng, key, ENC_KEY_SIZE);
85}
86
87/*
88 * Encrypt/decrypt big_key data
89 */
90static int big_key_crypt(enum big_key_op op, u8 *data, size_t datalen, u8 *key)
91{
92 int ret = -EINVAL;
93 struct scatterlist sgio;
94 struct blkcipher_desc desc;
95
96 if (crypto_blkcipher_setkey(big_key_blkcipher, key, ENC_KEY_SIZE)) {
97 ret = -EAGAIN;
98 goto error;
99 }
100
101 desc.flags = 0;
102 desc.tfm = big_key_blkcipher;
103
104 sg_init_one(&sgio, data, datalen);
105
106 if (op == BIG_KEY_ENC)
107 ret = crypto_blkcipher_encrypt(&desc, &sgio, &sgio, datalen);
108 else
109 ret = crypto_blkcipher_decrypt(&desc, &sgio, &sgio, datalen);
110
111error:
112 return ret;
113}
114
115/*
53 * Preparse a big key 116 * Preparse a big key
54 */ 117 */
55int big_key_preparse(struct key_preparsed_payload *prep) 118int big_key_preparse(struct key_preparsed_payload *prep)
56{ 119{
57 struct path *path = (struct path *)&prep->payload.data[big_key_path]; 120 struct path *path = (struct path *)&prep->payload.data[big_key_path];
58 struct file *file; 121 struct file *file;
122 u8 *enckey;
123 u8 *data = NULL;
59 ssize_t written; 124 ssize_t written;
60 size_t datalen = prep->datalen; 125 size_t datalen = prep->datalen;
61 int ret; 126 int ret;
@@ -73,16 +138,43 @@ int big_key_preparse(struct key_preparsed_payload *prep)
73 /* Create a shmem file to store the data in. This will permit the data 138 /* Create a shmem file to store the data in. This will permit the data
74 * to be swapped out if needed. 139 * to be swapped out if needed.
75 * 140 *
76 * TODO: Encrypt the stored data with a temporary key. 141 * File content is stored encrypted with randomly generated key.
77 */ 142 */
78 file = shmem_kernel_file_setup("", datalen, 0); 143 size_t enclen = ALIGN(datalen, crypto_blkcipher_blocksize(big_key_blkcipher));
144
145 /* prepare aligned data to encrypt */
146 data = kmalloc(enclen, GFP_KERNEL);
147 if (!data)
148 return -ENOMEM;
149
150 memcpy(data, prep->data, datalen);
151 memset(data + datalen, 0x00, enclen - datalen);
152
153 /* generate random key */
154 enckey = kmalloc(ENC_KEY_SIZE, GFP_KERNEL);
155 if (!enckey) {
156 ret = -ENOMEM;
157 goto error;
158 }
159
160 ret = big_key_gen_enckey(enckey);
161 if (ret)
162 goto err_enckey;
163
164 /* encrypt aligned data */
165 ret = big_key_crypt(BIG_KEY_ENC, data, enclen, enckey);
166 if (ret)
167 goto err_enckey;
168
169 /* save aligned data to file */
170 file = shmem_kernel_file_setup("", enclen, 0);
79 if (IS_ERR(file)) { 171 if (IS_ERR(file)) {
80 ret = PTR_ERR(file); 172 ret = PTR_ERR(file);
81 goto error; 173 goto err_enckey;
82 } 174 }
83 175
84 written = kernel_write(file, prep->data, prep->datalen, 0); 176 written = kernel_write(file, data, enclen, 0);
85 if (written != datalen) { 177 if (written != enclen) {
86 ret = written; 178 ret = written;
87 if (written >= 0) 179 if (written >= 0)
88 ret = -ENOMEM; 180 ret = -ENOMEM;
@@ -92,12 +184,15 @@ int big_key_preparse(struct key_preparsed_payload *prep)
92 /* Pin the mount and dentry to the key so that we can open it again 184 /* Pin the mount and dentry to the key so that we can open it again
93 * later 185 * later
94 */ 186 */
187 prep->payload.data[big_key_data] = enckey;
95 *path = file->f_path; 188 *path = file->f_path;
96 path_get(path); 189 path_get(path);
97 fput(file); 190 fput(file);
191 kfree(data);
98 } else { 192 } else {
99 /* Just store the data in a buffer */ 193 /* Just store the data in a buffer */
100 void *data = kmalloc(datalen, GFP_KERNEL); 194 void *data = kmalloc(datalen, GFP_KERNEL);
195
101 if (!data) 196 if (!data)
102 return -ENOMEM; 197 return -ENOMEM;
103 198
@@ -108,7 +203,10 @@ int big_key_preparse(struct key_preparsed_payload *prep)
108 203
109err_fput: 204err_fput:
110 fput(file); 205 fput(file);
206err_enckey:
207 kfree(enckey);
111error: 208error:
209 kfree(data);
112 return ret; 210 return ret;
113} 211}
114 212
@@ -119,10 +217,10 @@ void big_key_free_preparse(struct key_preparsed_payload *prep)
119{ 217{
120 if (prep->datalen > BIG_KEY_FILE_THRESHOLD) { 218 if (prep->datalen > BIG_KEY_FILE_THRESHOLD) {
121 struct path *path = (struct path *)&prep->payload.data[big_key_path]; 219 struct path *path = (struct path *)&prep->payload.data[big_key_path];
220
122 path_put(path); 221 path_put(path);
123 } else {
124 kfree(prep->payload.data[big_key_data]);
125 } 222 }
223 kfree(prep->payload.data[big_key_data]);
126} 224}
127 225
128/* 226/*
@@ -147,15 +245,15 @@ void big_key_destroy(struct key *key)
147{ 245{
148 size_t datalen = (size_t)key->payload.data[big_key_len]; 246 size_t datalen = (size_t)key->payload.data[big_key_len];
149 247
150 if (datalen) { 248 if (datalen > BIG_KEY_FILE_THRESHOLD) {
151 struct path *path = (struct path *)&key->payload.data[big_key_path]; 249 struct path *path = (struct path *)&key->payload.data[big_key_path];
250
152 path_put(path); 251 path_put(path);
153 path->mnt = NULL; 252 path->mnt = NULL;
154 path->dentry = NULL; 253 path->dentry = NULL;
155 } else {
156 kfree(key->payload.data[big_key_data]);
157 key->payload.data[big_key_data] = NULL;
158 } 254 }
255 kfree(key->payload.data[big_key_data]);
256 key->payload.data[big_key_data] = NULL;
159} 257}
160 258
161/* 259/*
@@ -188,17 +286,41 @@ long big_key_read(const struct key *key, char __user *buffer, size_t buflen)
188 if (datalen > BIG_KEY_FILE_THRESHOLD) { 286 if (datalen > BIG_KEY_FILE_THRESHOLD) {
189 struct path *path = (struct path *)&key->payload.data[big_key_path]; 287 struct path *path = (struct path *)&key->payload.data[big_key_path];
190 struct file *file; 288 struct file *file;
191 loff_t pos; 289 u8 *data;
290 u8 *enckey = (u8 *)key->payload.data[big_key_data];
291 size_t enclen = ALIGN(datalen, crypto_blkcipher_blocksize(big_key_blkcipher));
292
293 data = kmalloc(enclen, GFP_KERNEL);
294 if (!data)
295 return -ENOMEM;
192 296
193 file = dentry_open(path, O_RDONLY, current_cred()); 297 file = dentry_open(path, O_RDONLY, current_cred());
194 if (IS_ERR(file)) 298 if (IS_ERR(file)) {
195 return PTR_ERR(file); 299 ret = PTR_ERR(file);
300 goto error;
301 }
196 302
197 pos = 0; 303 /* read file to kernel and decrypt */
198 ret = vfs_read(file, buffer, datalen, &pos); 304 ret = kernel_read(file, 0, data, enclen);
199 fput(file); 305 if (ret >= 0 && ret != enclen) {
200 if (ret >= 0 && ret != datalen)
201 ret = -EIO; 306 ret = -EIO;
307 goto err_fput;
308 }
309
310 ret = big_key_crypt(BIG_KEY_DEC, data, enclen, enckey);
311 if (ret)
312 goto err_fput;
313
314 ret = datalen;
315
316 /* copy decrypted data to user */
317 if (copy_to_user(buffer, data, datalen) != 0)
318 ret = -EFAULT;
319
320err_fput:
321 fput(file);
322error:
323 kfree(data);
202 } else { 324 } else {
203 ret = datalen; 325 ret = datalen;
204 if (copy_to_user(buffer, key->payload.data[big_key_data], 326 if (copy_to_user(buffer, key->payload.data[big_key_data],
@@ -209,8 +331,48 @@ long big_key_read(const struct key *key, char __user *buffer, size_t buflen)
209 return ret; 331 return ret;
210} 332}
211 333
334/*
335 * Register key type
336 */
212static int __init big_key_init(void) 337static int __init big_key_init(void)
213{ 338{
214 return register_key_type(&key_type_big_key); 339 return register_key_type(&key_type_big_key);
215} 340}
341
342/*
343 * Initialize big_key crypto and RNG algorithms
344 */
345static int __init big_key_crypto_init(void)
346{
347 int ret = -EINVAL;
348
349 /* init RNG */
350 big_key_rng = crypto_alloc_rng(big_key_rng_name, 0, 0);
351 if (IS_ERR(big_key_rng)) {
352 big_key_rng = NULL;
353 return -EFAULT;
354 }
355
356 /* seed RNG */
357 ret = crypto_rng_reset(big_key_rng, NULL, crypto_rng_seedsize(big_key_rng));
358 if (ret)
359 goto error;
360
361 /* init block cipher */
362 big_key_blkcipher = crypto_alloc_blkcipher(big_key_alg_name, 0, 0);
363 if (IS_ERR(big_key_blkcipher)) {
364 big_key_blkcipher = NULL;
365 ret = -EFAULT;
366 goto error;
367 }
368
369 return 0;
370
371error:
372 crypto_free_rng(big_key_rng);
373 big_key_rng = NULL;
374 return ret;
375}
376
216device_initcall(big_key_init); 377device_initcall(big_key_init);
378late_initcall(big_key_crypto_init);
diff --git a/security/keys/compat.c b/security/keys/compat.c
index 25430a3aa7f7..c8783b3b628c 100644
--- a/security/keys/compat.c
+++ b/security/keys/compat.c
@@ -132,6 +132,10 @@ COMPAT_SYSCALL_DEFINE5(keyctl, u32, option,
132 case KEYCTL_GET_PERSISTENT: 132 case KEYCTL_GET_PERSISTENT:
133 return keyctl_get_persistent(arg2, arg3); 133 return keyctl_get_persistent(arg2, arg3);
134 134
135 case KEYCTL_DH_COMPUTE:
136 return keyctl_dh_compute(compat_ptr(arg2), compat_ptr(arg3),
137 arg4);
138
135 default: 139 default:
136 return -EOPNOTSUPP; 140 return -EOPNOTSUPP;
137 } 141 }
diff --git a/security/keys/dh.c b/security/keys/dh.c
new file mode 100644
index 000000000000..880505a4b9f1
--- /dev/null
+++ b/security/keys/dh.c
@@ -0,0 +1,160 @@
1/* Crypto operations using stored keys
2 *
3 * Copyright (c) 2016, Intel Corporation
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version
8 * 2 of the License, or (at your option) any later version.
9 */
10
11#include <linux/mpi.h>
12#include <linux/slab.h>
13#include <linux/uaccess.h>
14#include <keys/user-type.h>
15#include "internal.h"
16
17/*
18 * Public key or shared secret generation function [RFC2631 sec 2.1.1]
19 *
20 * ya = g^xa mod p;
21 * or
22 * ZZ = yb^xa mod p;
23 *
24 * where xa is the local private key, ya is the local public key, g is
25 * the generator, p is the prime, yb is the remote public key, and ZZ
26 * is the shared secret.
27 *
28 * Both are the same calculation, so g or yb are the "base" and ya or
29 * ZZ are the "result".
30 */
31static int do_dh(MPI result, MPI base, MPI xa, MPI p)
32{
33 return mpi_powm(result, base, xa, p);
34}
35
36static ssize_t mpi_from_key(key_serial_t keyid, size_t maxlen, MPI *mpi)
37{
38 struct key *key;
39 key_ref_t key_ref;
40 long status;
41 ssize_t ret;
42
43 key_ref = lookup_user_key(keyid, 0, KEY_NEED_READ);
44 if (IS_ERR(key_ref)) {
45 ret = -ENOKEY;
46 goto error;
47 }
48
49 key = key_ref_to_ptr(key_ref);
50
51 ret = -EOPNOTSUPP;
52 if (key->type == &key_type_user) {
53 down_read(&key->sem);
54 status = key_validate(key);
55 if (status == 0) {
56 const struct user_key_payload *payload;
57
58 payload = user_key_payload(key);
59
60 if (maxlen == 0) {
61 *mpi = NULL;
62 ret = payload->datalen;
63 } else if (payload->datalen <= maxlen) {
64 *mpi = mpi_read_raw_data(payload->data,
65 payload->datalen);
66 if (*mpi)
67 ret = payload->datalen;
68 } else {
69 ret = -EINVAL;
70 }
71 }
72 up_read(&key->sem);
73 }
74
75 key_put(key);
76error:
77 return ret;
78}
79
80long keyctl_dh_compute(struct keyctl_dh_params __user *params,
81 char __user *buffer, size_t buflen)
82{
83 long ret;
84 MPI base, private, prime, result;
85 unsigned nbytes;
86 struct keyctl_dh_params pcopy;
87 uint8_t *kbuf;
88 ssize_t keylen;
89 size_t resultlen;
90
91 if (!params || (!buffer && buflen)) {
92 ret = -EINVAL;
93 goto out;
94 }
95 if (copy_from_user(&pcopy, params, sizeof(pcopy)) != 0) {
96 ret = -EFAULT;
97 goto out;
98 }
99
100 keylen = mpi_from_key(pcopy.prime, buflen, &prime);
101 if (keylen < 0 || !prime) {
102 /* buflen == 0 may be used to query the required buffer size,
103 * which is the prime key length.
104 */
105 ret = keylen;
106 goto out;
107 }
108
109 /* The result is never longer than the prime */
110 resultlen = keylen;
111
112 keylen = mpi_from_key(pcopy.base, SIZE_MAX, &base);
113 if (keylen < 0 || !base) {
114 ret = keylen;
115 goto error1;
116 }
117
118 keylen = mpi_from_key(pcopy.private, SIZE_MAX, &private);
119 if (keylen < 0 || !private) {
120 ret = keylen;
121 goto error2;
122 }
123
124 result = mpi_alloc(0);
125 if (!result) {
126 ret = -ENOMEM;
127 goto error3;
128 }
129
130 kbuf = kmalloc(resultlen, GFP_KERNEL);
131 if (!kbuf) {
132 ret = -ENOMEM;
133 goto error4;
134 }
135
136 ret = do_dh(result, base, private, prime);
137 if (ret)
138 goto error5;
139
140 ret = mpi_read_buffer(result, kbuf, resultlen, &nbytes, NULL);
141 if (ret != 0)
142 goto error5;
143
144 ret = nbytes;
145 if (copy_to_user(buffer, kbuf, nbytes) != 0)
146 ret = -EFAULT;
147
148error5:
149 kfree(kbuf);
150error4:
151 mpi_free(result);
152error3:
153 mpi_free(private);
154error2:
155 mpi_free(base);
156error1:
157 mpi_free(prime);
158out:
159 return ret;
160}
diff --git a/security/keys/internal.h b/security/keys/internal.h
index 5105c2c2da75..8ec7a528365d 100644
--- a/security/keys/internal.h
+++ b/security/keys/internal.h
@@ -15,6 +15,7 @@
15#include <linux/sched.h> 15#include <linux/sched.h>
16#include <linux/key-type.h> 16#include <linux/key-type.h>
17#include <linux/task_work.h> 17#include <linux/task_work.h>
18#include <linux/keyctl.h>
18 19
19struct iovec; 20struct iovec;
20 21
@@ -257,6 +258,17 @@ static inline long keyctl_get_persistent(uid_t uid, key_serial_t destring)
257} 258}
258#endif 259#endif
259 260
261#ifdef CONFIG_KEY_DH_OPERATIONS
262extern long keyctl_dh_compute(struct keyctl_dh_params __user *, char __user *,
263 size_t);
264#else
265static inline long keyctl_dh_compute(struct keyctl_dh_params __user *params,
266 char __user *buffer, size_t buflen)
267{
268 return -EOPNOTSUPP;
269}
270#endif
271
260/* 272/*
261 * Debugging key validation 273 * Debugging key validation
262 */ 274 */
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index ed73c6c1c326..3b135a0af344 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -1686,6 +1686,11 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3,
1686 case KEYCTL_GET_PERSISTENT: 1686 case KEYCTL_GET_PERSISTENT:
1687 return keyctl_get_persistent((uid_t)arg2, (key_serial_t)arg3); 1687 return keyctl_get_persistent((uid_t)arg2, (key_serial_t)arg3);
1688 1688
1689 case KEYCTL_DH_COMPUTE:
1690 return keyctl_dh_compute((struct keyctl_dh_params __user *) arg2,
1691 (char __user *) arg3,
1692 (size_t) arg4);
1693
1689 default: 1694 default:
1690 return -EOPNOTSUPP; 1695 return -EOPNOTSUPP;
1691 } 1696 }
diff --git a/security/keys/user_defined.c b/security/keys/user_defined.c
index 8705d79b2c6f..66b1840b4110 100644
--- a/security/keys/user_defined.c
+++ b/security/keys/user_defined.c
@@ -96,45 +96,25 @@ EXPORT_SYMBOL_GPL(user_free_preparse);
96 */ 96 */
97int user_update(struct key *key, struct key_preparsed_payload *prep) 97int user_update(struct key *key, struct key_preparsed_payload *prep)
98{ 98{
99 struct user_key_payload *upayload, *zap; 99 struct user_key_payload *zap = NULL;
100 size_t datalen = prep->datalen;
101 int ret; 100 int ret;
102 101
103 ret = -EINVAL;
104 if (datalen <= 0 || datalen > 32767 || !prep->data)
105 goto error;
106
107 /* construct a replacement payload */
108 ret = -ENOMEM;
109 upayload = kmalloc(sizeof(*upayload) + datalen, GFP_KERNEL);
110 if (!upayload)
111 goto error;
112
113 upayload->datalen = datalen;
114 memcpy(upayload->data, prep->data, datalen);
115
116 /* check the quota and attach the new data */ 102 /* check the quota and attach the new data */
117 zap = upayload; 103 ret = key_payload_reserve(key, prep->datalen);
118 104 if (ret < 0)
119 ret = key_payload_reserve(key, datalen); 105 return ret;
120 106
121 if (ret == 0) { 107 /* attach the new data, displacing the old */
122 /* attach the new data, displacing the old */ 108 key->expiry = prep->expiry;
123 if (!test_bit(KEY_FLAG_NEGATIVE, &key->flags)) 109 if (!test_bit(KEY_FLAG_NEGATIVE, &key->flags))
124 zap = key->payload.data[0]; 110 zap = rcu_dereference_key(key);
125 else 111 rcu_assign_keypointer(key, prep->payload.data[0]);
126 zap = NULL; 112 prep->payload.data[0] = NULL;
127 rcu_assign_keypointer(key, upayload);
128 key->expiry = 0;
129 }
130 113
131 if (zap) 114 if (zap)
132 kfree_rcu(zap, rcu); 115 kfree_rcu(zap, rcu);
133
134error:
135 return ret; 116 return ret;
136} 117}
137
138EXPORT_SYMBOL_GPL(user_update); 118EXPORT_SYMBOL_GPL(user_update);
139 119
140/* 120/*