Merge branch 'keys-trust' into keys-next
authorDavid Howells <dhowells@redhat.com>
Wed, 4 May 2016 16:20:20 +0000 (17:20 +0100)
committerDavid Howells <dhowells@redhat.com>
Wed, 4 May 2016 16:20:20 +0000 (17:20 +0100)
Here's a set of patches that changes how certificates/keys are determined
to be trusted.  That's currently a two-step process:

 (1) Up until recently, when an X.509 certificate was parsed - no matter
     the source - it was judged against the keys in .system_keyring,
     assuming those keys to be trusted if they have KEY_FLAG_TRUSTED set
     upon them.

     This has just been changed such that any key in the .ima_mok keyring,
     if configured, may also be used to judge the trustworthiness of a new
     certificate, whether or not the .ima_mok keyring is meant to be
     consulted for whatever process is being undertaken.

     If a certificate is determined to be trustworthy, KEY_FLAG_TRUSTED
     will be set upon a key it is loaded into (if it is loaded into one),
     no matter what the key is going to be loaded for.

 (2) If an X.509 certificate is loaded into a key, then that key - if
     KEY_FLAG_TRUSTED gets set upon it - can be linked into any keyring
     with KEY_FLAG_TRUSTED_ONLY set upon it.  This was meant to be the
     system keyring only, but has been extended to various IMA keyrings.
     A user can at will link any key marked KEY_FLAG_TRUSTED into any
     keyring marked KEY_FLAG_TRUSTED_ONLY if the relevant permissions masks
     permit it.

These patches change that:

 (1) Trust becomes a matter of consulting the ring of trusted keys supplied
     when the trust is evaluated only.

 (2) Every keyring can be supplied with its own manager function to
     restrict what may be added to that keyring.  This is called whenever a
     key is to be linked into the keyring to guard against a key being
     created in one keyring and then linked across.

     This function is supplied with the keyring and the key type and
     payload[*] of the key being linked in for use in its evaluation.  It
     is permitted to use other data also, such as the contents of other
     keyrings such as the system keyrings.

     [*] The type and payload are supplied instead of a key because as an
         optimisation this function may be called whilst creating a key and
         so may reject the proposed key between preparse and allocation.

 (3) A default manager function is provided that permits keys to be
     restricted to only asymmetric keys that are vouched for by the
     contents of the system keyring.

     A second manager function is provided that just rejects with EPERM.

 (4) A key allocation flag, KEY_ALLOC_BYPASS_RESTRICTION, is made available
     so that the kernel can initialise keyrings with keys that form the
     root of the trust relationship.

 (5) KEY_FLAG_TRUSTED and KEY_FLAG_TRUSTED_ONLY are removed, along with
     key_preparsed_payload::trusted.

This change also makes it possible in future for userspace to create a private
set of trusted keys and then to have it sealed by setting a manager function
where the private set is wholly independent of the kernel's trust
relationships.

Further changes in the set involve extracting certain IMA special keyrings
and making them generally global:

 (*) .system_keyring is renamed to .builtin_trusted_keys and remains read
     only.  It carries only keys built in to the kernel.  It may be where
     UEFI keys should be loaded - though that could better be the new
     secondary keyring (see below) or a separate UEFI keyring.

 (*) An optional secondary system keyring (called .secondary_trusted_keys)
     is added to replace the IMA MOK keyring.

     (*) Keys can be added to the secondary keyring by root if the keys can
         be vouched for by either ring of system keys.

 (*) Module signing and kexec only use .builtin_trusted_keys and do not use
     the new secondary keyring.

 (*) Config option SYSTEM_TRUSTED_KEYS now depends on ASYMMETRIC_KEY_TYPE as
     that's the only type currently permitted on the system keyrings.

 (*) A new config option, IMA_KEYRINGS_PERMIT_SIGNED_BY_BUILTIN_OR_SECONDARY,
     is provided to allow keys to be added to IMA keyrings, subject to the
     restriction that such keys are validly signed by a key already in the
     system keyrings.

     If this option is enabled, but secondary keyrings aren't, additions to
     the IMA keyrings will be restricted to signatures verifiable by keys in
     the builtin system keyring only.

Signed-off-by: David Howells <dhowells@redhat.com>
13 files changed:
Documentation/security/keys.txt
include/linux/lsm_hooks.h
include/uapi/linux/keyctl.h
security/integrity/Kconfig
security/keys/Kconfig
security/keys/Makefile
security/keys/big_key.c
security/keys/compat.c
security/keys/dh.c [new file with mode: 0644]
security/keys/internal.h
security/keys/keyctl.c
security/keys/user_defined.c
security/security.c

index a6a50b359025f76f51959a40c11a5bbe2e48f095..20d05719bceb92fa6c05648d5abe2e824be408de 100644 (file)
@@ -823,6 +823,36 @@ The keyctl syscall functions are:
      A process must have search permission on the key for this function to be
      successful.
 
+ (*) Compute a Diffie-Hellman shared secret or public key
+
+       long keyctl(KEYCTL_DH_COMPUTE, struct keyctl_dh_params *params,
+                  char *buffer, size_t buflen);
+
+     The params struct contains serial numbers for three keys:
+
+        - The prime, p, known to both parties
+        - The local private key
+        - The base integer, which is either a shared generator or the
+          remote public key
+
+     The value computed is:
+
+       result = base ^ private (mod prime)
+
+     If the base is the shared generator, the result is the local
+     public key.  If the base is the remote public key, the result is
+     the shared secret.
+
+     The buffer length must be at least the length of the prime, or zero.
+
+     If the buffer length is nonzero, the length of the result is
+     returned when it is successfully calculated and copied in to the
+     buffer. When the buffer length is zero, the minimum required
+     buffer length is returned.
+
+     This function will return error EOPNOTSUPP if the key type is not
+     supported, error ENOKEY if the key could not be found, or error
+     EACCES if the key is not readable by the caller.
 
 ===============
 KERNEL SERVICES
index cdee11cbcdf1487a7cd99d0f58a3c348e4b118d0..ae25378861774ea84dc1b99085a4cfc462cc2f84 100644 (file)
@@ -1804,7 +1804,6 @@ struct security_hook_heads {
        struct list_head tun_dev_attach_queue;
        struct list_head tun_dev_attach;
        struct list_head tun_dev_open;
-       struct list_head skb_owned_by;
 #endif /* CONFIG_SECURITY_NETWORK */
 #ifdef CONFIG_SECURITY_NETWORK_XFRM
        struct list_head xfrm_policy_alloc_security;
index 840cb990abe2e7147ec89c92ef143e86a35ce0f8..86eddd6241f36eb21897d65c6bb51f15bbb4ec58 100644 (file)
@@ -12,6 +12,8 @@
 #ifndef _LINUX_KEYCTL_H
 #define _LINUX_KEYCTL_H
 
+#include <linux/types.h>
+
 /* special process keyring shortcut IDs */
 #define KEY_SPEC_THREAD_KEYRING                -1      /* - key ID for thread-specific keyring */
 #define KEY_SPEC_PROCESS_KEYRING       -2      /* - key ID for process-specific keyring */
 #define KEYCTL_INSTANTIATE_IOV         20      /* instantiate a partially constructed key */
 #define KEYCTL_INVALIDATE              21      /* invalidate a key */
 #define KEYCTL_GET_PERSISTENT          22      /* get a user's persistent keyring */
+#define KEYCTL_DH_COMPUTE              23      /* Compute Diffie-Hellman values */
+
+/* keyctl structures */
+struct keyctl_dh_params {
+       __s32 private;
+       __s32 prime;
+       __s32 base;
+};
 
 #endif /*  _LINUX_KEYCTL_H */
index 979be65d22c4260aad2f7c2a9b3fc0b4247656a2..da9565891738d6c9836804c513595f5f6e238758 100644 (file)
@@ -35,7 +35,6 @@ config INTEGRITY_ASYMMETRIC_KEYS
        default n
         select ASYMMETRIC_KEY_TYPE
         select ASYMMETRIC_PUBLIC_KEY_SUBTYPE
-        select PUBLIC_KEY_ALGO_RSA
         select CRYPTO_RSA
         select X509_CERTIFICATE_PARSER
        help
index fe4d74e126a768f4c502cf3e55e5ab55f37e90d9..f826e87390233c1cfddb87e969642ab44219d84f 100644 (file)
@@ -41,6 +41,10 @@ config BIG_KEYS
        bool "Large payload keys"
        depends on KEYS
        depends on TMPFS
+       select CRYPTO
+       select CRYPTO_AES
+       select CRYPTO_ECB
+       select CRYPTO_RNG
        help
          This option provides support for holding large keys within the kernel
          (for example Kerberos ticket caches).  The data may be stored out to
@@ -81,3 +85,14 @@ config ENCRYPTED_KEYS
          Userspace only ever sees/stores encrypted blobs.
 
          If you are unsure as to whether this is required, answer N.
+
+config KEY_DH_OPERATIONS
+       bool "Diffie-Hellman operations on retained keys"
+       depends on KEYS
+       select MPILIB
+       help
+        This option provides support for calculating Diffie-Hellman
+        public keys and shared secrets using values stored as keys
+        in the kernel.
+
+        If you are unsure as to whether this is required, answer N.
index dfb3a7bededf548ac1eed24b094de858e7a07df6..1fd4a16e6dafb6779f770690319918ad4341b9c7 100644 (file)
@@ -19,6 +19,7 @@ obj-$(CONFIG_KEYS_COMPAT) += compat.o
 obj-$(CONFIG_PROC_FS) += proc.o
 obj-$(CONFIG_SYSCTL) += sysctl.o
 obj-$(CONFIG_PERSISTENT_KEYRINGS) += persistent.o
+obj-$(CONFIG_KEY_DH_OPERATIONS) += dh.o
 
 #
 # Key types
index c721e398893add4712d891a9dabeeee117048782..9e443fccad4cfde54deb9710feb4eee4bdadae17 100644 (file)
 #include <linux/file.h>
 #include <linux/shmem_fs.h>
 #include <linux/err.h>
+#include <linux/scatterlist.h>
 #include <keys/user-type.h>
 #include <keys/big_key-type.h>
+#include <crypto/rng.h>
 
 /*
  * Layout of key payload words.
@@ -27,6 +29,14 @@ enum {
        big_key_len,
 };
 
+/*
+ * Crypto operation with big_key data
+ */
+enum big_key_op {
+       BIG_KEY_ENC,
+       BIG_KEY_DEC,
+};
+
 /*
  * If the data is under this limit, there's no point creating a shm file to
  * hold it as the permanently resident metadata for the shmem fs will be at
@@ -34,6 +44,11 @@ enum {
  */
 #define BIG_KEY_FILE_THRESHOLD (sizeof(struct inode) + sizeof(struct dentry))
 
+/*
+ * Key size for big_key data encryption
+ */
+#define ENC_KEY_SIZE   16
+
 /*
  * big_key defined keys take an arbitrary string as the description and an
  * arbitrary blob of data as the payload
@@ -49,6 +64,54 @@ struct key_type key_type_big_key = {
        .read                   = big_key_read,
 };
 
+/*
+ * Crypto names for big_key data encryption
+ */
+static const char big_key_rng_name[] = "stdrng";
+static const char big_key_alg_name[] = "ecb(aes)";
+
+/*
+ * Crypto algorithms for big_key data encryption
+ */
+static struct crypto_rng *big_key_rng;
+static struct crypto_blkcipher *big_key_blkcipher;
+
+/*
+ * Generate random key to encrypt big_key data
+ */
+static inline int big_key_gen_enckey(u8 *key)
+{
+       return crypto_rng_get_bytes(big_key_rng, key, ENC_KEY_SIZE);
+}
+
+/*
+ * Encrypt/decrypt big_key data
+ */
+static int big_key_crypt(enum big_key_op op, u8 *data, size_t datalen, u8 *key)
+{
+       int ret = -EINVAL;
+       struct scatterlist sgio;
+       struct blkcipher_desc desc;
+
+       if (crypto_blkcipher_setkey(big_key_blkcipher, key, ENC_KEY_SIZE)) {
+               ret = -EAGAIN;
+               goto error;
+       }
+
+       desc.flags = 0;
+       desc.tfm = big_key_blkcipher;
+
+       sg_init_one(&sgio, data, datalen);
+
+       if (op == BIG_KEY_ENC)
+               ret = crypto_blkcipher_encrypt(&desc, &sgio, &sgio, datalen);
+       else
+               ret = crypto_blkcipher_decrypt(&desc, &sgio, &sgio, datalen);
+
+error:
+       return ret;
+}
+
 /*
  * Preparse a big key
  */
@@ -56,6 +119,8 @@ int big_key_preparse(struct key_preparsed_payload *prep)
 {
        struct path *path = (struct path *)&prep->payload.data[big_key_path];
        struct file *file;
+       u8 *enckey;
+       u8 *data = NULL;
        ssize_t written;
        size_t datalen = prep->datalen;
        int ret;
@@ -73,16 +138,43 @@ int big_key_preparse(struct key_preparsed_payload *prep)
                /* Create a shmem file to store the data in.  This will permit the data
                 * to be swapped out if needed.
                 *
-                * TODO: Encrypt the stored data with a temporary key.
+                * File content is stored encrypted with randomly generated key.
                 */
-               file = shmem_kernel_file_setup("", datalen, 0);
+               size_t enclen = ALIGN(datalen, crypto_blkcipher_blocksize(big_key_blkcipher));
+
+               /* prepare aligned data to encrypt */
+               data = kmalloc(enclen, GFP_KERNEL);
+               if (!data)
+                       return -ENOMEM;
+
+               memcpy(data, prep->data, datalen);
+               memset(data + datalen, 0x00, enclen - datalen);
+
+               /* generate random key */
+               enckey = kmalloc(ENC_KEY_SIZE, GFP_KERNEL);
+               if (!enckey) {
+                       ret = -ENOMEM;
+                       goto error;
+               }
+
+               ret = big_key_gen_enckey(enckey);
+               if (ret)
+                       goto err_enckey;
+
+               /* encrypt aligned data */
+               ret = big_key_crypt(BIG_KEY_ENC, data, enclen, enckey);
+               if (ret)
+                       goto err_enckey;
+
+               /* save aligned data to file */
+               file = shmem_kernel_file_setup("", enclen, 0);
                if (IS_ERR(file)) {
                        ret = PTR_ERR(file);
-                       goto error;
+                       goto err_enckey;
                }
 
-               written = kernel_write(file, prep->data, prep->datalen, 0);
-               if (written != datalen) {
+               written = kernel_write(file, data, enclen, 0);
+               if (written != enclen) {
                        ret = written;
                        if (written >= 0)
                                ret = -ENOMEM;
@@ -92,12 +184,15 @@ int big_key_preparse(struct key_preparsed_payload *prep)
                /* Pin the mount and dentry to the key so that we can open it again
                 * later
                 */
+               prep->payload.data[big_key_data] = enckey;
                *path = file->f_path;
                path_get(path);
                fput(file);
+               kfree(data);
        } else {
                /* Just store the data in a buffer */
                void *data = kmalloc(datalen, GFP_KERNEL);
+
                if (!data)
                        return -ENOMEM;
 
@@ -108,7 +203,10 @@ int big_key_preparse(struct key_preparsed_payload *prep)
 
 err_fput:
        fput(file);
+err_enckey:
+       kfree(enckey);
 error:
+       kfree(data);
        return ret;
 }
 
@@ -119,10 +217,10 @@ void big_key_free_preparse(struct key_preparsed_payload *prep)
 {
        if (prep->datalen > BIG_KEY_FILE_THRESHOLD) {
                struct path *path = (struct path *)&prep->payload.data[big_key_path];
+
                path_put(path);
-       } else {
-               kfree(prep->payload.data[big_key_data]);
        }
+       kfree(prep->payload.data[big_key_data]);
 }
 
 /*
@@ -147,15 +245,15 @@ void big_key_destroy(struct key *key)
 {
        size_t datalen = (size_t)key->payload.data[big_key_len];
 
-       if (datalen) {
+       if (datalen > BIG_KEY_FILE_THRESHOLD) {
                struct path *path = (struct path *)&key->payload.data[big_key_path];
+
                path_put(path);
                path->mnt = NULL;
                path->dentry = NULL;
-       } else {
-               kfree(key->payload.data[big_key_data]);
-               key->payload.data[big_key_data] = NULL;
        }
+       kfree(key->payload.data[big_key_data]);
+       key->payload.data[big_key_data] = NULL;
 }
 
 /*
@@ -188,17 +286,41 @@ long big_key_read(const struct key *key, char __user *buffer, size_t buflen)
        if (datalen > BIG_KEY_FILE_THRESHOLD) {
                struct path *path = (struct path *)&key->payload.data[big_key_path];
                struct file *file;
-               loff_t pos;
+               u8 *data;
+               u8 *enckey = (u8 *)key->payload.data[big_key_data];
+               size_t enclen = ALIGN(datalen, crypto_blkcipher_blocksize(big_key_blkcipher));
+
+               data = kmalloc(enclen, GFP_KERNEL);
+               if (!data)
+                       return -ENOMEM;
 
                file = dentry_open(path, O_RDONLY, current_cred());
-               if (IS_ERR(file))
-                       return PTR_ERR(file);
+               if (IS_ERR(file)) {
+                       ret = PTR_ERR(file);
+                       goto error;
+               }
 
-               pos = 0;
-               ret = vfs_read(file, buffer, datalen, &pos);
-               fput(file);
-               if (ret >= 0 && ret != datalen)
+               /* read file to kernel and decrypt */
+               ret = kernel_read(file, 0, data, enclen);
+               if (ret >= 0 && ret != enclen) {
                        ret = -EIO;
+                       goto err_fput;
+               }
+
+               ret = big_key_crypt(BIG_KEY_DEC, data, enclen, enckey);
+               if (ret)
+                       goto err_fput;
+
+               ret = datalen;
+
+               /* copy decrypted data to user */
+               if (copy_to_user(buffer, data, datalen) != 0)
+                       ret = -EFAULT;
+
+err_fput:
+               fput(file);
+error:
+               kfree(data);
        } else {
                ret = datalen;
                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)
        return ret;
 }
 
+/*
+ * Register key type
+ */
 static int __init big_key_init(void)
 {
        return register_key_type(&key_type_big_key);
 }
+
+/*
+ * Initialize big_key crypto and RNG algorithms
+ */
+static int __init big_key_crypto_init(void)
+{
+       int ret = -EINVAL;
+
+       /* init RNG */
+       big_key_rng = crypto_alloc_rng(big_key_rng_name, 0, 0);
+       if (IS_ERR(big_key_rng)) {
+               big_key_rng = NULL;
+               return -EFAULT;
+       }
+
+       /* seed RNG */
+       ret = crypto_rng_reset(big_key_rng, NULL, crypto_rng_seedsize(big_key_rng));
+       if (ret)
+               goto error;
+
+       /* init block cipher */
+       big_key_blkcipher = crypto_alloc_blkcipher(big_key_alg_name, 0, 0);
+       if (IS_ERR(big_key_blkcipher)) {
+               big_key_blkcipher = NULL;
+               ret = -EFAULT;
+               goto error;
+       }
+
+       return 0;
+
+error:
+       crypto_free_rng(big_key_rng);
+       big_key_rng = NULL;
+       return ret;
+}
+
 device_initcall(big_key_init);
+late_initcall(big_key_crypto_init);
index 25430a3aa7f7b9d6e6b4d10ae9bc72c8669c00fe..c8783b3b628ca6282bd59597eb1a7f685f1e48cc 100644 (file)
@@ -132,6 +132,10 @@ COMPAT_SYSCALL_DEFINE5(keyctl, u32, option,
        case KEYCTL_GET_PERSISTENT:
                return keyctl_get_persistent(arg2, arg3);
 
+       case KEYCTL_DH_COMPUTE:
+               return keyctl_dh_compute(compat_ptr(arg2), compat_ptr(arg3),
+                                        arg4);
+
        default:
                return -EOPNOTSUPP;
        }
diff --git a/security/keys/dh.c b/security/keys/dh.c
new file mode 100644 (file)
index 0000000..880505a
--- /dev/null
@@ -0,0 +1,160 @@
+/* Crypto operations using stored keys
+ *
+ * Copyright (c) 2016, Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/mpi.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <keys/user-type.h>
+#include "internal.h"
+
+/*
+ * Public key or shared secret generation function [RFC2631 sec 2.1.1]
+ *
+ * ya = g^xa mod p;
+ * or
+ * ZZ = yb^xa mod p;
+ *
+ * where xa is the local private key, ya is the local public key, g is
+ * the generator, p is the prime, yb is the remote public key, and ZZ
+ * is the shared secret.
+ *
+ * Both are the same calculation, so g or yb are the "base" and ya or
+ * ZZ are the "result".
+ */
+static int do_dh(MPI result, MPI base, MPI xa, MPI p)
+{
+       return mpi_powm(result, base, xa, p);
+}
+
+static ssize_t mpi_from_key(key_serial_t keyid, size_t maxlen, MPI *mpi)
+{
+       struct key *key;
+       key_ref_t key_ref;
+       long status;
+       ssize_t ret;
+
+       key_ref = lookup_user_key(keyid, 0, KEY_NEED_READ);
+       if (IS_ERR(key_ref)) {
+               ret = -ENOKEY;
+               goto error;
+       }
+
+       key = key_ref_to_ptr(key_ref);
+
+       ret = -EOPNOTSUPP;
+       if (key->type == &key_type_user) {
+               down_read(&key->sem);
+               status = key_validate(key);
+               if (status == 0) {
+                       const struct user_key_payload *payload;
+
+                       payload = user_key_payload(key);
+
+                       if (maxlen == 0) {
+                               *mpi = NULL;
+                               ret = payload->datalen;
+                       } else if (payload->datalen <= maxlen) {
+                               *mpi = mpi_read_raw_data(payload->data,
+                                                        payload->datalen);
+                               if (*mpi)
+                                       ret = payload->datalen;
+                       } else {
+                               ret = -EINVAL;
+                       }
+               }
+               up_read(&key->sem);
+       }
+
+       key_put(key);
+error:
+       return ret;
+}
+
+long keyctl_dh_compute(struct keyctl_dh_params __user *params,
+                      char __user *buffer, size_t buflen)
+{
+       long ret;
+       MPI base, private, prime, result;
+       unsigned nbytes;
+       struct keyctl_dh_params pcopy;
+       uint8_t *kbuf;
+       ssize_t keylen;
+       size_t resultlen;
+
+       if (!params || (!buffer && buflen)) {
+               ret = -EINVAL;
+               goto out;
+       }
+       if (copy_from_user(&pcopy, params, sizeof(pcopy)) != 0) {
+               ret = -EFAULT;
+               goto out;
+       }
+
+       keylen = mpi_from_key(pcopy.prime, buflen, &prime);
+       if (keylen < 0 || !prime) {
+               /* buflen == 0 may be used to query the required buffer size,
+                * which is the prime key length.
+                */
+               ret = keylen;
+               goto out;
+       }
+
+       /* The result is never longer than the prime */
+       resultlen = keylen;
+
+       keylen = mpi_from_key(pcopy.base, SIZE_MAX, &base);
+       if (keylen < 0 || !base) {
+               ret = keylen;
+               goto error1;
+       }
+
+       keylen = mpi_from_key(pcopy.private, SIZE_MAX, &private);
+       if (keylen < 0 || !private) {
+               ret = keylen;
+               goto error2;
+       }
+
+       result = mpi_alloc(0);
+       if (!result) {
+               ret = -ENOMEM;
+               goto error3;
+       }
+
+       kbuf = kmalloc(resultlen, GFP_KERNEL);
+       if (!kbuf) {
+               ret = -ENOMEM;
+               goto error4;
+       }
+
+       ret = do_dh(result, base, private, prime);
+       if (ret)
+               goto error5;
+
+       ret = mpi_read_buffer(result, kbuf, resultlen, &nbytes, NULL);
+       if (ret != 0)
+               goto error5;
+
+       ret = nbytes;
+       if (copy_to_user(buffer, kbuf, nbytes) != 0)
+               ret = -EFAULT;
+
+error5:
+       kfree(kbuf);
+error4:
+       mpi_free(result);
+error3:
+       mpi_free(private);
+error2:
+       mpi_free(base);
+error1:
+       mpi_free(prime);
+out:
+       return ret;
+}
index 5105c2c2da75b0e13dec1196be67c88f4d789e72..8ec7a528365d967b8c82a97ded54c20df2459ce6 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/sched.h>
 #include <linux/key-type.h>
 #include <linux/task_work.h>
+#include <linux/keyctl.h>
 
 struct iovec;
 
@@ -257,6 +258,17 @@ static inline long keyctl_get_persistent(uid_t uid, key_serial_t destring)
 }
 #endif
 
+#ifdef CONFIG_KEY_DH_OPERATIONS
+extern long keyctl_dh_compute(struct keyctl_dh_params __user *, char __user *,
+                             size_t);
+#else
+static inline long keyctl_dh_compute(struct keyctl_dh_params __user *params,
+                                    char __user *buffer, size_t buflen)
+{
+       return -EOPNOTSUPP;
+}
+#endif
+
 /*
  * Debugging key validation
  */
index ed73c6c1c326c02bf0f4f80923e4792f292ec2fd..3b135a0af34406a52dc8019f664fd855c5ad0068 100644 (file)
@@ -1686,6 +1686,11 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3,
        case KEYCTL_GET_PERSISTENT:
                return keyctl_get_persistent((uid_t)arg2, (key_serial_t)arg3);
 
+       case KEYCTL_DH_COMPUTE:
+               return keyctl_dh_compute((struct keyctl_dh_params __user *) arg2,
+                                        (char __user *) arg3,
+                                        (size_t) arg4);
+
        default:
                return -EOPNOTSUPP;
        }
index 8705d79b2c6f289736fde21fd38e6013a4e4ae3c..66b1840b4110b6ee876af85c8ba598a3054a43f8 100644 (file)
@@ -96,45 +96,25 @@ EXPORT_SYMBOL_GPL(user_free_preparse);
  */
 int user_update(struct key *key, struct key_preparsed_payload *prep)
 {
-       struct user_key_payload *upayload, *zap;
-       size_t datalen = prep->datalen;
+       struct user_key_payload *zap = NULL;
        int ret;
 
-       ret = -EINVAL;
-       if (datalen <= 0 || datalen > 32767 || !prep->data)
-               goto error;
-
-       /* construct a replacement payload */
-       ret = -ENOMEM;
-       upayload = kmalloc(sizeof(*upayload) + datalen, GFP_KERNEL);
-       if (!upayload)
-               goto error;
-
-       upayload->datalen = datalen;
-       memcpy(upayload->data, prep->data, datalen);
-
        /* check the quota and attach the new data */
-       zap = upayload;
-
-       ret = key_payload_reserve(key, datalen);
-
-       if (ret == 0) {
-               /* attach the new data, displacing the old */
-               if (!test_bit(KEY_FLAG_NEGATIVE, &key->flags))
-                       zap = key->payload.data[0];
-               else
-                       zap = NULL;
-               rcu_assign_keypointer(key, upayload);
-               key->expiry = 0;
-       }
+       ret = key_payload_reserve(key, prep->datalen);
+       if (ret < 0)
+               return ret;
+
+       /* attach the new data, displacing the old */
+       key->expiry = prep->expiry;
+       if (!test_bit(KEY_FLAG_NEGATIVE, &key->flags))
+               zap = rcu_dereference_key(key);
+       rcu_assign_keypointer(key, prep->payload.data[0]);
+       prep->payload.data[0] = NULL;
 
        if (zap)
                kfree_rcu(zap, rcu);
-
-error:
        return ret;
 }
-
 EXPORT_SYMBOL_GPL(user_update);
 
 /*
index 3644b0344d29f3a17ef4f94b1156c9dffff02e65..554c3fb7d4a53473b73753f885464388500b848a 100644 (file)
@@ -1848,7 +1848,6 @@ struct security_hook_heads security_hook_heads = {
        .tun_dev_attach =
                LIST_HEAD_INIT(security_hook_heads.tun_dev_attach),
        .tun_dev_open = LIST_HEAD_INIT(security_hook_heads.tun_dev_open),
-       .skb_owned_by = LIST_HEAD_INIT(security_hook_heads.skb_owned_by),
 #endif /* CONFIG_SECURITY_NETWORK */
 #ifdef CONFIG_SECURITY_NETWORK_XFRM
        .xfrm_policy_alloc_security =
This page took 0.202768 seconds and 5 git commands to generate.