Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull key subsystem fixes from James Morris: "Here are a bunch of fixes for Linux keyrings, including: - Fix up the refcount handling now that key structs use the refcount_t type and the refcount_t ops don't allow a 0->1 transition. - Fix a potential NULL deref after error in x509_cert_parse(). - Don't put data for the crypto algorithms to use on the stack. - Fix the handling of a null payload being passed to add_key(). - Fix incorrect cleanup an uninitialised key_preparsed_payload in key_update(). - Explicit sanitisation of potentially secure data before freeing. - Fixes for the Diffie-Helman code" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (23 commits) KEYS: fix refcount_inc() on zero KEYS: Convert KEYCTL_DH_COMPUTE to use the crypto KPP API crypto : asymmetric_keys : verify_pefile:zero memory content before freeing KEYS: DH: add __user annotations to keyctl_kdf_params KEYS: DH: ensure the KDF counter is properly aligned KEYS: DH: don't feed uninitialized "otherinfo" into KDF KEYS: DH: forbid using digest_null as the KDF hash KEYS: sanitize key structs before freeing KEYS: trusted: sanitize all key material KEYS: encrypted: sanitize all key material KEYS: user_defined: sanitize key payloads KEYS: sanitize add_key() and keyctl() key payloads KEYS: fix freeing uninitialized memory in key_update() KEYS: fix dereferencing NULL payload with nonzero length KEYS: encrypted: use constant-time HMAC comparison KEYS: encrypted: fix race causing incorrect HMAC calculations KEYS: encrypted: fix buffer overread in valid_master_desc() KEYS: encrypted: avoid encrypting/decrypting stack buffers KEYS: put keyring if install_session_keyring_to_cred() fails KEYS: Delete an error message for a failed memory allocation in get_derived_key() ...
This commit is contained in:
commit
32627645e9
|
@ -1084,10 +1084,6 @@ config SYSVIPC_COMPAT
|
||||||
def_bool y
|
def_bool y
|
||||||
depends on COMPAT && SYSVIPC
|
depends on COMPAT && SYSVIPC
|
||||||
|
|
||||||
config KEYS_COMPAT
|
|
||||||
def_bool y
|
|
||||||
depends on COMPAT && KEYS
|
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
||||||
menu "Power management options"
|
menu "Power management options"
|
||||||
|
|
|
@ -1199,11 +1199,6 @@ source "arch/powerpc/Kconfig.debug"
|
||||||
|
|
||||||
source "security/Kconfig"
|
source "security/Kconfig"
|
||||||
|
|
||||||
config KEYS_COMPAT
|
|
||||||
bool
|
|
||||||
depends on COMPAT && KEYS
|
|
||||||
default y
|
|
||||||
|
|
||||||
source "crypto/Kconfig"
|
source "crypto/Kconfig"
|
||||||
|
|
||||||
config PPC_LIB_RHEAP
|
config PPC_LIB_RHEAP
|
||||||
|
|
|
@ -363,9 +363,6 @@ config COMPAT
|
||||||
config SYSVIPC_COMPAT
|
config SYSVIPC_COMPAT
|
||||||
def_bool y if COMPAT && SYSVIPC
|
def_bool y if COMPAT && SYSVIPC
|
||||||
|
|
||||||
config KEYS_COMPAT
|
|
||||||
def_bool y if COMPAT && KEYS
|
|
||||||
|
|
||||||
config SMP
|
config SMP
|
||||||
def_bool y
|
def_bool y
|
||||||
prompt "Symmetric multi-processing support"
|
prompt "Symmetric multi-processing support"
|
||||||
|
|
|
@ -577,9 +577,6 @@ config SYSVIPC_COMPAT
|
||||||
depends on COMPAT && SYSVIPC
|
depends on COMPAT && SYSVIPC
|
||||||
default y
|
default y
|
||||||
|
|
||||||
config KEYS_COMPAT
|
|
||||||
def_bool y if COMPAT && KEYS
|
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
||||||
source "net/Kconfig"
|
source "net/Kconfig"
|
||||||
|
|
|
@ -2776,10 +2776,6 @@ config COMPAT_FOR_U64_ALIGNMENT
|
||||||
config SYSVIPC_COMPAT
|
config SYSVIPC_COMPAT
|
||||||
def_bool y
|
def_bool y
|
||||||
depends on SYSVIPC
|
depends on SYSVIPC
|
||||||
|
|
||||||
config KEYS_COMPAT
|
|
||||||
def_bool y
|
|
||||||
depends on KEYS
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
|
@ -381,7 +381,7 @@ static int pefile_digest_pe(const void *pebuf, unsigned int pelen,
|
||||||
}
|
}
|
||||||
|
|
||||||
error:
|
error:
|
||||||
kfree(desc);
|
kzfree(desc);
|
||||||
error_no_desc:
|
error_no_desc:
|
||||||
crypto_free_shash(tfm);
|
crypto_free_shash(tfm);
|
||||||
kleave(" = %d", ret);
|
kleave(" = %d", ret);
|
||||||
|
@ -450,6 +450,6 @@ int verify_pefile_signature(const void *pebuf, unsigned pelen,
|
||||||
ret = pefile_digest_pe(pebuf, pelen, &ctx);
|
ret = pefile_digest_pe(pebuf, pelen, &ctx);
|
||||||
|
|
||||||
error:
|
error:
|
||||||
kfree(ctx.digest);
|
kzfree(ctx.digest);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,6 +102,7 @@ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = -ENOMEM;
|
||||||
cert->pub->key = kmemdup(ctx->key, ctx->key_size, GFP_KERNEL);
|
cert->pub->key = kmemdup(ctx->key, ctx->key_size, GFP_KERNEL);
|
||||||
if (!cert->pub->key)
|
if (!cert->pub->key)
|
||||||
goto error_decode;
|
goto error_decode;
|
||||||
|
|
|
@ -173,7 +173,6 @@ struct key {
|
||||||
#ifdef KEY_DEBUGGING
|
#ifdef KEY_DEBUGGING
|
||||||
unsigned magic;
|
unsigned magic;
|
||||||
#define KEY_DEBUG_MAGIC 0x18273645u
|
#define KEY_DEBUG_MAGIC 0x18273645u
|
||||||
#define KEY_DEBUG_MAGIC_X 0xf8e9dacbu
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
unsigned long flags; /* status flags (change with bitops) */
|
unsigned long flags; /* status flags (change with bitops) */
|
||||||
|
|
|
@ -70,8 +70,8 @@ struct keyctl_dh_params {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct keyctl_kdf_params {
|
struct keyctl_kdf_params {
|
||||||
char *hashname;
|
char __user *hashname;
|
||||||
char *otherinfo;
|
char __user *otherinfo;
|
||||||
__u32 otherinfolen;
|
__u32 otherinfolen;
|
||||||
__u32 __spare[8];
|
__u32 __spare[8];
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,6 +20,10 @@ config KEYS
|
||||||
|
|
||||||
If you are unsure as to whether this is required, answer N.
|
If you are unsure as to whether this is required, answer N.
|
||||||
|
|
||||||
|
config KEYS_COMPAT
|
||||||
|
def_bool y
|
||||||
|
depends on COMPAT && KEYS
|
||||||
|
|
||||||
config PERSISTENT_KEYRINGS
|
config PERSISTENT_KEYRINGS
|
||||||
bool "Enable register of persistent per-UID keyrings"
|
bool "Enable register of persistent per-UID keyrings"
|
||||||
depends on KEYS
|
depends on KEYS
|
||||||
|
@ -89,9 +93,9 @@ config ENCRYPTED_KEYS
|
||||||
config KEY_DH_OPERATIONS
|
config KEY_DH_OPERATIONS
|
||||||
bool "Diffie-Hellman operations on retained keys"
|
bool "Diffie-Hellman operations on retained keys"
|
||||||
depends on KEYS
|
depends on KEYS
|
||||||
select MPILIB
|
|
||||||
select CRYPTO
|
select CRYPTO
|
||||||
select CRYPTO_HASH
|
select CRYPTO_HASH
|
||||||
|
select CRYPTO_DH
|
||||||
help
|
help
|
||||||
This option provides support for calculating Diffie-Hellman
|
This option provides support for calculating Diffie-Hellman
|
||||||
public keys and shared secrets using values stored as keys
|
public keys and shared secrets using values stored as keys
|
||||||
|
|
|
@ -8,34 +8,17 @@
|
||||||
* 2 of the License, or (at your option) any later version.
|
* 2 of the License, or (at your option) any later version.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/mpi.h>
|
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
|
#include <linux/scatterlist.h>
|
||||||
#include <linux/crypto.h>
|
#include <linux/crypto.h>
|
||||||
#include <crypto/hash.h>
|
#include <crypto/hash.h>
|
||||||
|
#include <crypto/kpp.h>
|
||||||
|
#include <crypto/dh.h>
|
||||||
#include <keys/user-type.h>
|
#include <keys/user-type.h>
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
/*
|
static ssize_t dh_data_from_key(key_serial_t keyid, void **data)
|
||||||
* 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;
|
struct key *key;
|
||||||
key_ref_t key_ref;
|
key_ref_t key_ref;
|
||||||
|
@ -56,19 +39,17 @@ static ssize_t mpi_from_key(key_serial_t keyid, size_t maxlen, MPI *mpi)
|
||||||
status = key_validate(key);
|
status = key_validate(key);
|
||||||
if (status == 0) {
|
if (status == 0) {
|
||||||
const struct user_key_payload *payload;
|
const struct user_key_payload *payload;
|
||||||
|
uint8_t *duplicate;
|
||||||
|
|
||||||
payload = user_key_payload_locked(key);
|
payload = user_key_payload_locked(key);
|
||||||
|
|
||||||
if (maxlen == 0) {
|
duplicate = kmemdup(payload->data, payload->datalen,
|
||||||
*mpi = NULL;
|
GFP_KERNEL);
|
||||||
|
if (duplicate) {
|
||||||
|
*data = duplicate;
|
||||||
ret = payload->datalen;
|
ret = payload->datalen;
|
||||||
} else if (payload->datalen <= maxlen) {
|
|
||||||
*mpi = mpi_read_raw_data(payload->data,
|
|
||||||
payload->datalen);
|
|
||||||
if (*mpi)
|
|
||||||
ret = payload->datalen;
|
|
||||||
} else {
|
} else {
|
||||||
ret = -EINVAL;
|
ret = -ENOMEM;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
up_read(&key->sem);
|
up_read(&key->sem);
|
||||||
|
@ -79,6 +60,29 @@ error:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void dh_free_data(struct dh *dh)
|
||||||
|
{
|
||||||
|
kzfree(dh->key);
|
||||||
|
kzfree(dh->p);
|
||||||
|
kzfree(dh->g);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct dh_completion {
|
||||||
|
struct completion completion;
|
||||||
|
int err;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void dh_crypto_done(struct crypto_async_request *req, int err)
|
||||||
|
{
|
||||||
|
struct dh_completion *compl = req->data;
|
||||||
|
|
||||||
|
if (err == -EINPROGRESS)
|
||||||
|
return;
|
||||||
|
|
||||||
|
compl->err = err;
|
||||||
|
complete(&compl->completion);
|
||||||
|
}
|
||||||
|
|
||||||
struct kdf_sdesc {
|
struct kdf_sdesc {
|
||||||
struct shash_desc shash;
|
struct shash_desc shash;
|
||||||
char ctx[];
|
char ctx[];
|
||||||
|
@ -89,6 +93,7 @@ static int kdf_alloc(struct kdf_sdesc **sdesc_ret, char *hashname)
|
||||||
struct crypto_shash *tfm;
|
struct crypto_shash *tfm;
|
||||||
struct kdf_sdesc *sdesc;
|
struct kdf_sdesc *sdesc;
|
||||||
int size;
|
int size;
|
||||||
|
int err;
|
||||||
|
|
||||||
/* allocate synchronous hash */
|
/* allocate synchronous hash */
|
||||||
tfm = crypto_alloc_shash(hashname, 0, 0);
|
tfm = crypto_alloc_shash(hashname, 0, 0);
|
||||||
|
@ -97,16 +102,25 @@ static int kdf_alloc(struct kdf_sdesc **sdesc_ret, char *hashname)
|
||||||
return PTR_ERR(tfm);
|
return PTR_ERR(tfm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = -EINVAL;
|
||||||
|
if (crypto_shash_digestsize(tfm) == 0)
|
||||||
|
goto out_free_tfm;
|
||||||
|
|
||||||
|
err = -ENOMEM;
|
||||||
size = sizeof(struct shash_desc) + crypto_shash_descsize(tfm);
|
size = sizeof(struct shash_desc) + crypto_shash_descsize(tfm);
|
||||||
sdesc = kmalloc(size, GFP_KERNEL);
|
sdesc = kmalloc(size, GFP_KERNEL);
|
||||||
if (!sdesc)
|
if (!sdesc)
|
||||||
return -ENOMEM;
|
goto out_free_tfm;
|
||||||
sdesc->shash.tfm = tfm;
|
sdesc->shash.tfm = tfm;
|
||||||
sdesc->shash.flags = 0x0;
|
sdesc->shash.flags = 0x0;
|
||||||
|
|
||||||
*sdesc_ret = sdesc;
|
*sdesc_ret = sdesc;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
out_free_tfm:
|
||||||
|
crypto_free_shash(tfm);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void kdf_dealloc(struct kdf_sdesc *sdesc)
|
static void kdf_dealloc(struct kdf_sdesc *sdesc)
|
||||||
|
@ -120,14 +134,6 @@ static void kdf_dealloc(struct kdf_sdesc *sdesc)
|
||||||
kzfree(sdesc);
|
kzfree(sdesc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* convert 32 bit integer into its string representation */
|
|
||||||
static inline void crypto_kw_cpu_to_be32(u32 val, u8 *buf)
|
|
||||||
{
|
|
||||||
__be32 *a = (__be32 *)buf;
|
|
||||||
|
|
||||||
*a = cpu_to_be32(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Implementation of the KDF in counter mode according to SP800-108 section 5.1
|
* Implementation of the KDF in counter mode according to SP800-108 section 5.1
|
||||||
* as well as SP800-56A section 5.8.1 (Single-step KDF).
|
* as well as SP800-56A section 5.8.1 (Single-step KDF).
|
||||||
|
@ -138,25 +144,39 @@ static inline void crypto_kw_cpu_to_be32(u32 val, u8 *buf)
|
||||||
* 5.8.1.2).
|
* 5.8.1.2).
|
||||||
*/
|
*/
|
||||||
static int kdf_ctr(struct kdf_sdesc *sdesc, const u8 *src, unsigned int slen,
|
static int kdf_ctr(struct kdf_sdesc *sdesc, const u8 *src, unsigned int slen,
|
||||||
u8 *dst, unsigned int dlen)
|
u8 *dst, unsigned int dlen, unsigned int zlen)
|
||||||
{
|
{
|
||||||
struct shash_desc *desc = &sdesc->shash;
|
struct shash_desc *desc = &sdesc->shash;
|
||||||
unsigned int h = crypto_shash_digestsize(desc->tfm);
|
unsigned int h = crypto_shash_digestsize(desc->tfm);
|
||||||
int err = 0;
|
int err = 0;
|
||||||
u8 *dst_orig = dst;
|
u8 *dst_orig = dst;
|
||||||
u32 i = 1;
|
__be32 counter = cpu_to_be32(1);
|
||||||
u8 iteration[sizeof(u32)];
|
|
||||||
|
|
||||||
while (dlen) {
|
while (dlen) {
|
||||||
err = crypto_shash_init(desc);
|
err = crypto_shash_init(desc);
|
||||||
if (err)
|
if (err)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
crypto_kw_cpu_to_be32(i, iteration);
|
err = crypto_shash_update(desc, (u8 *)&counter, sizeof(__be32));
|
||||||
err = crypto_shash_update(desc, iteration, sizeof(u32));
|
|
||||||
if (err)
|
if (err)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
|
if (zlen && h) {
|
||||||
|
u8 tmpbuffer[h];
|
||||||
|
size_t chunk = min_t(size_t, zlen, h);
|
||||||
|
memset(tmpbuffer, 0, chunk);
|
||||||
|
|
||||||
|
do {
|
||||||
|
err = crypto_shash_update(desc, tmpbuffer,
|
||||||
|
chunk);
|
||||||
|
if (err)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
zlen -= chunk;
|
||||||
|
chunk = min_t(size_t, zlen, h);
|
||||||
|
} while (zlen);
|
||||||
|
}
|
||||||
|
|
||||||
if (src && slen) {
|
if (src && slen) {
|
||||||
err = crypto_shash_update(desc, src, slen);
|
err = crypto_shash_update(desc, src, slen);
|
||||||
if (err)
|
if (err)
|
||||||
|
@ -179,7 +199,7 @@ static int kdf_ctr(struct kdf_sdesc *sdesc, const u8 *src, unsigned int slen,
|
||||||
|
|
||||||
dlen -= h;
|
dlen -= h;
|
||||||
dst += h;
|
dst += h;
|
||||||
i++;
|
counter = cpu_to_be32(be32_to_cpu(counter) + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,7 +212,7 @@ err:
|
||||||
|
|
||||||
static int keyctl_dh_compute_kdf(struct kdf_sdesc *sdesc,
|
static int keyctl_dh_compute_kdf(struct kdf_sdesc *sdesc,
|
||||||
char __user *buffer, size_t buflen,
|
char __user *buffer, size_t buflen,
|
||||||
uint8_t *kbuf, size_t kbuflen)
|
uint8_t *kbuf, size_t kbuflen, size_t lzero)
|
||||||
{
|
{
|
||||||
uint8_t *outbuf = NULL;
|
uint8_t *outbuf = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -203,7 +223,7 @@ static int keyctl_dh_compute_kdf(struct kdf_sdesc *sdesc,
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = kdf_ctr(sdesc, kbuf, kbuflen, outbuf, buflen);
|
ret = kdf_ctr(sdesc, kbuf, kbuflen, outbuf, buflen, lzero);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
|
@ -221,21 +241,26 @@ long __keyctl_dh_compute(struct keyctl_dh_params __user *params,
|
||||||
struct keyctl_kdf_params *kdfcopy)
|
struct keyctl_kdf_params *kdfcopy)
|
||||||
{
|
{
|
||||||
long ret;
|
long ret;
|
||||||
MPI base, private, prime, result;
|
ssize_t dlen;
|
||||||
unsigned nbytes;
|
int secretlen;
|
||||||
|
int outlen;
|
||||||
struct keyctl_dh_params pcopy;
|
struct keyctl_dh_params pcopy;
|
||||||
uint8_t *kbuf;
|
struct dh dh_inputs;
|
||||||
ssize_t keylen;
|
struct scatterlist outsg;
|
||||||
size_t resultlen;
|
struct dh_completion compl;
|
||||||
|
struct crypto_kpp *tfm;
|
||||||
|
struct kpp_request *req;
|
||||||
|
uint8_t *secret;
|
||||||
|
uint8_t *outbuf;
|
||||||
struct kdf_sdesc *sdesc = NULL;
|
struct kdf_sdesc *sdesc = NULL;
|
||||||
|
|
||||||
if (!params || (!buffer && buflen)) {
|
if (!params || (!buffer && buflen)) {
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto out;
|
goto out1;
|
||||||
}
|
}
|
||||||
if (copy_from_user(&pcopy, params, sizeof(pcopy)) != 0) {
|
if (copy_from_user(&pcopy, params, sizeof(pcopy)) != 0) {
|
||||||
ret = -EFAULT;
|
ret = -EFAULT;
|
||||||
goto out;
|
goto out1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kdfcopy) {
|
if (kdfcopy) {
|
||||||
|
@ -244,104 +269,147 @@ long __keyctl_dh_compute(struct keyctl_dh_params __user *params,
|
||||||
if (buflen > KEYCTL_KDF_MAX_OUTPUT_LEN ||
|
if (buflen > KEYCTL_KDF_MAX_OUTPUT_LEN ||
|
||||||
kdfcopy->otherinfolen > KEYCTL_KDF_MAX_OI_LEN) {
|
kdfcopy->otherinfolen > KEYCTL_KDF_MAX_OI_LEN) {
|
||||||
ret = -EMSGSIZE;
|
ret = -EMSGSIZE;
|
||||||
goto out;
|
goto out1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get KDF name string */
|
/* get KDF name string */
|
||||||
hashname = strndup_user(kdfcopy->hashname, CRYPTO_MAX_ALG_NAME);
|
hashname = strndup_user(kdfcopy->hashname, CRYPTO_MAX_ALG_NAME);
|
||||||
if (IS_ERR(hashname)) {
|
if (IS_ERR(hashname)) {
|
||||||
ret = PTR_ERR(hashname);
|
ret = PTR_ERR(hashname);
|
||||||
goto out;
|
goto out1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* allocate KDF from the kernel crypto API */
|
/* allocate KDF from the kernel crypto API */
|
||||||
ret = kdf_alloc(&sdesc, hashname);
|
ret = kdf_alloc(&sdesc, hashname);
|
||||||
kfree(hashname);
|
kfree(hashname);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
memset(&dh_inputs, 0, sizeof(dh_inputs));
|
||||||
* If the caller requests postprocessing with a KDF, allow an
|
|
||||||
* arbitrary output buffer size since the KDF ensures proper truncation.
|
dlen = dh_data_from_key(pcopy.prime, &dh_inputs.p);
|
||||||
*/
|
if (dlen < 0) {
|
||||||
keylen = mpi_from_key(pcopy.prime, kdfcopy ? SIZE_MAX : buflen, &prime);
|
ret = dlen;
|
||||||
if (keylen < 0 || !prime) {
|
goto out1;
|
||||||
/* buflen == 0 may be used to query the required buffer size,
|
|
||||||
* which is the prime key length.
|
|
||||||
*/
|
|
||||||
ret = keylen;
|
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
dh_inputs.p_size = dlen;
|
||||||
|
|
||||||
/* The result is never longer than the prime */
|
dlen = dh_data_from_key(pcopy.base, &dh_inputs.g);
|
||||||
resultlen = keylen;
|
if (dlen < 0) {
|
||||||
|
ret = dlen;
|
||||||
keylen = mpi_from_key(pcopy.base, SIZE_MAX, &base);
|
goto out2;
|
||||||
if (keylen < 0 || !base) {
|
|
||||||
ret = keylen;
|
|
||||||
goto error1;
|
|
||||||
}
|
}
|
||||||
|
dh_inputs.g_size = dlen;
|
||||||
|
|
||||||
keylen = mpi_from_key(pcopy.private, SIZE_MAX, &private);
|
dlen = dh_data_from_key(pcopy.private, &dh_inputs.key);
|
||||||
if (keylen < 0 || !private) {
|
if (dlen < 0) {
|
||||||
ret = keylen;
|
ret = dlen;
|
||||||
goto error2;
|
goto out2;
|
||||||
}
|
}
|
||||||
|
dh_inputs.key_size = dlen;
|
||||||
|
|
||||||
result = mpi_alloc(0);
|
secretlen = crypto_dh_key_len(&dh_inputs);
|
||||||
if (!result) {
|
secret = kmalloc(secretlen, GFP_KERNEL);
|
||||||
|
if (!secret) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto error3;
|
goto out2;
|
||||||
}
|
}
|
||||||
|
ret = crypto_dh_encode_key(secret, secretlen, &dh_inputs);
|
||||||
/* allocate space for DH shared secret and SP800-56A otherinfo */
|
|
||||||
kbuf = kmalloc(kdfcopy ? (resultlen + kdfcopy->otherinfolen) : resultlen,
|
|
||||||
GFP_KERNEL);
|
|
||||||
if (!kbuf) {
|
|
||||||
ret = -ENOMEM;
|
|
||||||
goto error4;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Concatenate SP800-56A otherinfo past DH shared secret -- the
|
|
||||||
* input to the KDF is (DH shared secret || otherinfo)
|
|
||||||
*/
|
|
||||||
if (kdfcopy && kdfcopy->otherinfo &&
|
|
||||||
copy_from_user(kbuf + resultlen, kdfcopy->otherinfo,
|
|
||||||
kdfcopy->otherinfolen) != 0) {
|
|
||||||
ret = -EFAULT;
|
|
||||||
goto error5;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = do_dh(result, base, private, prime);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
goto error5;
|
goto out3;
|
||||||
|
|
||||||
ret = mpi_read_buffer(result, kbuf, resultlen, &nbytes, NULL);
|
tfm = crypto_alloc_kpp("dh", CRYPTO_ALG_TYPE_KPP, 0);
|
||||||
if (ret != 0)
|
if (IS_ERR(tfm)) {
|
||||||
goto error5;
|
ret = PTR_ERR(tfm);
|
||||||
|
goto out3;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = crypto_kpp_set_secret(tfm, secret, secretlen);
|
||||||
|
if (ret)
|
||||||
|
goto out4;
|
||||||
|
|
||||||
|
outlen = crypto_kpp_maxsize(tfm);
|
||||||
|
|
||||||
|
if (!kdfcopy) {
|
||||||
|
/*
|
||||||
|
* When not using a KDF, buflen 0 is used to read the
|
||||||
|
* required buffer length
|
||||||
|
*/
|
||||||
|
if (buflen == 0) {
|
||||||
|
ret = outlen;
|
||||||
|
goto out4;
|
||||||
|
} else if (outlen > buflen) {
|
||||||
|
ret = -EOVERFLOW;
|
||||||
|
goto out4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
outbuf = kzalloc(kdfcopy ? (outlen + kdfcopy->otherinfolen) : outlen,
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!outbuf) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto out4;
|
||||||
|
}
|
||||||
|
|
||||||
|
sg_init_one(&outsg, outbuf, outlen);
|
||||||
|
|
||||||
|
req = kpp_request_alloc(tfm, GFP_KERNEL);
|
||||||
|
if (!req) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto out5;
|
||||||
|
}
|
||||||
|
|
||||||
|
kpp_request_set_input(req, NULL, 0);
|
||||||
|
kpp_request_set_output(req, &outsg, outlen);
|
||||||
|
init_completion(&compl.completion);
|
||||||
|
kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG |
|
||||||
|
CRYPTO_TFM_REQ_MAY_SLEEP,
|
||||||
|
dh_crypto_done, &compl);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For DH, generate_public_key and generate_shared_secret are
|
||||||
|
* the same calculation
|
||||||
|
*/
|
||||||
|
ret = crypto_kpp_generate_public_key(req);
|
||||||
|
if (ret == -EINPROGRESS) {
|
||||||
|
wait_for_completion(&compl.completion);
|
||||||
|
ret = compl.err;
|
||||||
|
if (ret)
|
||||||
|
goto out6;
|
||||||
|
}
|
||||||
|
|
||||||
if (kdfcopy) {
|
if (kdfcopy) {
|
||||||
ret = keyctl_dh_compute_kdf(sdesc, buffer, buflen, kbuf,
|
/*
|
||||||
resultlen + kdfcopy->otherinfolen);
|
* Concatenate SP800-56A otherinfo past DH shared secret -- the
|
||||||
} else {
|
* input to the KDF is (DH shared secret || otherinfo)
|
||||||
ret = nbytes;
|
*/
|
||||||
if (copy_to_user(buffer, kbuf, nbytes) != 0)
|
if (copy_from_user(outbuf + req->dst_len, kdfcopy->otherinfo,
|
||||||
|
kdfcopy->otherinfolen) != 0) {
|
||||||
ret = -EFAULT;
|
ret = -EFAULT;
|
||||||
|
goto out6;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = keyctl_dh_compute_kdf(sdesc, buffer, buflen, outbuf,
|
||||||
|
req->dst_len + kdfcopy->otherinfolen,
|
||||||
|
outlen - req->dst_len);
|
||||||
|
} else if (copy_to_user(buffer, outbuf, req->dst_len) == 0) {
|
||||||
|
ret = req->dst_len;
|
||||||
|
} else {
|
||||||
|
ret = -EFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
error5:
|
out6:
|
||||||
kzfree(kbuf);
|
kpp_request_free(req);
|
||||||
error4:
|
out5:
|
||||||
mpi_free(result);
|
kzfree(outbuf);
|
||||||
error3:
|
out4:
|
||||||
mpi_free(private);
|
crypto_free_kpp(tfm);
|
||||||
error2:
|
out3:
|
||||||
mpi_free(base);
|
kzfree(secret);
|
||||||
error1:
|
out2:
|
||||||
mpi_free(prime);
|
dh_free_data(&dh_inputs);
|
||||||
out:
|
out1:
|
||||||
kdf_dealloc(sdesc);
|
kdf_dealloc(sdesc);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include <linux/scatterlist.h>
|
#include <linux/scatterlist.h>
|
||||||
#include <linux/ctype.h>
|
#include <linux/ctype.h>
|
||||||
#include <crypto/aes.h>
|
#include <crypto/aes.h>
|
||||||
|
#include <crypto/algapi.h>
|
||||||
#include <crypto/hash.h>
|
#include <crypto/hash.h>
|
||||||
#include <crypto/sha.h>
|
#include <crypto/sha.h>
|
||||||
#include <crypto/skcipher.h>
|
#include <crypto/skcipher.h>
|
||||||
|
@ -54,13 +55,7 @@ static int blksize;
|
||||||
#define MAX_DATA_SIZE 4096
|
#define MAX_DATA_SIZE 4096
|
||||||
#define MIN_DATA_SIZE 20
|
#define MIN_DATA_SIZE 20
|
||||||
|
|
||||||
struct sdesc {
|
static struct crypto_shash *hash_tfm;
|
||||||
struct shash_desc shash;
|
|
||||||
char ctx[];
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct crypto_shash *hashalg;
|
|
||||||
static struct crypto_shash *hmacalg;
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
Opt_err = -1, Opt_new, Opt_load, Opt_update
|
Opt_err = -1, Opt_new, Opt_load, Opt_update
|
||||||
|
@ -141,23 +136,22 @@ static int valid_ecryptfs_desc(const char *ecryptfs_desc)
|
||||||
*/
|
*/
|
||||||
static int valid_master_desc(const char *new_desc, const char *orig_desc)
|
static int valid_master_desc(const char *new_desc, const char *orig_desc)
|
||||||
{
|
{
|
||||||
if (!memcmp(new_desc, KEY_TRUSTED_PREFIX, KEY_TRUSTED_PREFIX_LEN)) {
|
int prefix_len;
|
||||||
if (strlen(new_desc) == KEY_TRUSTED_PREFIX_LEN)
|
|
||||||
goto out;
|
if (!strncmp(new_desc, KEY_TRUSTED_PREFIX, KEY_TRUSTED_PREFIX_LEN))
|
||||||
if (orig_desc)
|
prefix_len = KEY_TRUSTED_PREFIX_LEN;
|
||||||
if (memcmp(new_desc, orig_desc, KEY_TRUSTED_PREFIX_LEN))
|
else if (!strncmp(new_desc, KEY_USER_PREFIX, KEY_USER_PREFIX_LEN))
|
||||||
goto out;
|
prefix_len = KEY_USER_PREFIX_LEN;
|
||||||
} else if (!memcmp(new_desc, KEY_USER_PREFIX, KEY_USER_PREFIX_LEN)) {
|
else
|
||||||
if (strlen(new_desc) == KEY_USER_PREFIX_LEN)
|
return -EINVAL;
|
||||||
goto out;
|
|
||||||
if (orig_desc)
|
if (!new_desc[prefix_len])
|
||||||
if (memcmp(new_desc, orig_desc, KEY_USER_PREFIX_LEN))
|
return -EINVAL;
|
||||||
goto out;
|
|
||||||
} else
|
if (orig_desc && strncmp(new_desc, orig_desc, prefix_len))
|
||||||
goto out;
|
return -EINVAL;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
out:
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -321,53 +315,38 @@ error:
|
||||||
return ukey;
|
return ukey;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct sdesc *alloc_sdesc(struct crypto_shash *alg)
|
static int calc_hash(struct crypto_shash *tfm, u8 *digest,
|
||||||
|
const u8 *buf, unsigned int buflen)
|
||||||
{
|
{
|
||||||
struct sdesc *sdesc;
|
SHASH_DESC_ON_STACK(desc, tfm);
|
||||||
int size;
|
int err;
|
||||||
|
|
||||||
size = sizeof(struct shash_desc) + crypto_shash_descsize(alg);
|
desc->tfm = tfm;
|
||||||
sdesc = kmalloc(size, GFP_KERNEL);
|
desc->flags = 0;
|
||||||
if (!sdesc)
|
|
||||||
return ERR_PTR(-ENOMEM);
|
err = crypto_shash_digest(desc, buf, buflen, digest);
|
||||||
sdesc->shash.tfm = alg;
|
shash_desc_zero(desc);
|
||||||
sdesc->shash.flags = 0x0;
|
return err;
|
||||||
return sdesc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int calc_hmac(u8 *digest, const u8 *key, unsigned int keylen,
|
static int calc_hmac(u8 *digest, const u8 *key, unsigned int keylen,
|
||||||
const u8 *buf, unsigned int buflen)
|
const u8 *buf, unsigned int buflen)
|
||||||
{
|
{
|
||||||
struct sdesc *sdesc;
|
struct crypto_shash *tfm;
|
||||||
int ret;
|
int err;
|
||||||
|
|
||||||
sdesc = alloc_sdesc(hmacalg);
|
tfm = crypto_alloc_shash(hmac_alg, 0, CRYPTO_ALG_ASYNC);
|
||||||
if (IS_ERR(sdesc)) {
|
if (IS_ERR(tfm)) {
|
||||||
pr_info("encrypted_key: can't alloc %s\n", hmac_alg);
|
pr_err("encrypted_key: can't alloc %s transform: %ld\n",
|
||||||
return PTR_ERR(sdesc);
|
hmac_alg, PTR_ERR(tfm));
|
||||||
|
return PTR_ERR(tfm);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = crypto_shash_setkey(hmacalg, key, keylen);
|
err = crypto_shash_setkey(tfm, key, keylen);
|
||||||
if (!ret)
|
if (!err)
|
||||||
ret = crypto_shash_digest(&sdesc->shash, buf, buflen, digest);
|
err = calc_hash(tfm, digest, buf, buflen);
|
||||||
kfree(sdesc);
|
crypto_free_shash(tfm);
|
||||||
return ret;
|
return err;
|
||||||
}
|
|
||||||
|
|
||||||
static int calc_hash(u8 *digest, const u8 *buf, unsigned int buflen)
|
|
||||||
{
|
|
||||||
struct sdesc *sdesc;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
sdesc = alloc_sdesc(hashalg);
|
|
||||||
if (IS_ERR(sdesc)) {
|
|
||||||
pr_info("encrypted_key: can't alloc %s\n", hash_alg);
|
|
||||||
return PTR_ERR(sdesc);
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = crypto_shash_digest(&sdesc->shash, buf, buflen, digest);
|
|
||||||
kfree(sdesc);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum derived_key_type { ENC_KEY, AUTH_KEY };
|
enum derived_key_type { ENC_KEY, AUTH_KEY };
|
||||||
|
@ -385,10 +364,9 @@ static int get_derived_key(u8 *derived_key, enum derived_key_type key_type,
|
||||||
derived_buf_len = HASH_SIZE;
|
derived_buf_len = HASH_SIZE;
|
||||||
|
|
||||||
derived_buf = kzalloc(derived_buf_len, GFP_KERNEL);
|
derived_buf = kzalloc(derived_buf_len, GFP_KERNEL);
|
||||||
if (!derived_buf) {
|
if (!derived_buf)
|
||||||
pr_err("encrypted_key: out of memory\n");
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
|
||||||
if (key_type)
|
if (key_type)
|
||||||
strcpy(derived_buf, "AUTH_KEY");
|
strcpy(derived_buf, "AUTH_KEY");
|
||||||
else
|
else
|
||||||
|
@ -396,8 +374,8 @@ static int get_derived_key(u8 *derived_key, enum derived_key_type key_type,
|
||||||
|
|
||||||
memcpy(derived_buf + strlen(derived_buf) + 1, master_key,
|
memcpy(derived_buf + strlen(derived_buf) + 1, master_key,
|
||||||
master_keylen);
|
master_keylen);
|
||||||
ret = calc_hash(derived_key, derived_buf, derived_buf_len);
|
ret = calc_hash(hash_tfm, derived_key, derived_buf, derived_buf_len);
|
||||||
kfree(derived_buf);
|
kzfree(derived_buf);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -480,12 +458,9 @@ static int derived_key_encrypt(struct encrypted_key_payload *epayload,
|
||||||
struct skcipher_request *req;
|
struct skcipher_request *req;
|
||||||
unsigned int encrypted_datalen;
|
unsigned int encrypted_datalen;
|
||||||
u8 iv[AES_BLOCK_SIZE];
|
u8 iv[AES_BLOCK_SIZE];
|
||||||
unsigned int padlen;
|
|
||||||
char pad[16];
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
encrypted_datalen = roundup(epayload->decrypted_datalen, blksize);
|
encrypted_datalen = roundup(epayload->decrypted_datalen, blksize);
|
||||||
padlen = encrypted_datalen - epayload->decrypted_datalen;
|
|
||||||
|
|
||||||
req = init_skcipher_req(derived_key, derived_keylen);
|
req = init_skcipher_req(derived_key, derived_keylen);
|
||||||
ret = PTR_ERR(req);
|
ret = PTR_ERR(req);
|
||||||
|
@ -493,11 +468,10 @@ static int derived_key_encrypt(struct encrypted_key_payload *epayload,
|
||||||
goto out;
|
goto out;
|
||||||
dump_decrypted_data(epayload);
|
dump_decrypted_data(epayload);
|
||||||
|
|
||||||
memset(pad, 0, sizeof pad);
|
|
||||||
sg_init_table(sg_in, 2);
|
sg_init_table(sg_in, 2);
|
||||||
sg_set_buf(&sg_in[0], epayload->decrypted_data,
|
sg_set_buf(&sg_in[0], epayload->decrypted_data,
|
||||||
epayload->decrypted_datalen);
|
epayload->decrypted_datalen);
|
||||||
sg_set_buf(&sg_in[1], pad, padlen);
|
sg_set_page(&sg_in[1], ZERO_PAGE(0), AES_BLOCK_SIZE, 0);
|
||||||
|
|
||||||
sg_init_table(sg_out, 1);
|
sg_init_table(sg_out, 1);
|
||||||
sg_set_buf(sg_out, epayload->encrypted_data, encrypted_datalen);
|
sg_set_buf(sg_out, epayload->encrypted_data, encrypted_datalen);
|
||||||
|
@ -533,6 +507,7 @@ static int datablob_hmac_append(struct encrypted_key_payload *epayload,
|
||||||
if (!ret)
|
if (!ret)
|
||||||
dump_hmac(NULL, digest, HASH_SIZE);
|
dump_hmac(NULL, digest, HASH_SIZE);
|
||||||
out:
|
out:
|
||||||
|
memzero_explicit(derived_key, sizeof(derived_key));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -561,8 +536,8 @@ static int datablob_hmac_verify(struct encrypted_key_payload *epayload,
|
||||||
ret = calc_hmac(digest, derived_key, sizeof derived_key, p, len);
|
ret = calc_hmac(digest, derived_key, sizeof derived_key, p, len);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out;
|
goto out;
|
||||||
ret = memcmp(digest, epayload->format + epayload->datablob_len,
|
ret = crypto_memneq(digest, epayload->format + epayload->datablob_len,
|
||||||
sizeof digest);
|
sizeof(digest));
|
||||||
if (ret) {
|
if (ret) {
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
dump_hmac("datablob",
|
dump_hmac("datablob",
|
||||||
|
@ -571,6 +546,7 @@ static int datablob_hmac_verify(struct encrypted_key_payload *epayload,
|
||||||
dump_hmac("calc", digest, HASH_SIZE);
|
dump_hmac("calc", digest, HASH_SIZE);
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
|
memzero_explicit(derived_key, sizeof(derived_key));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -584,9 +560,14 @@ static int derived_key_decrypt(struct encrypted_key_payload *epayload,
|
||||||
struct skcipher_request *req;
|
struct skcipher_request *req;
|
||||||
unsigned int encrypted_datalen;
|
unsigned int encrypted_datalen;
|
||||||
u8 iv[AES_BLOCK_SIZE];
|
u8 iv[AES_BLOCK_SIZE];
|
||||||
char pad[16];
|
u8 *pad;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
/* Throwaway buffer to hold the unused zero padding at the end */
|
||||||
|
pad = kmalloc(AES_BLOCK_SIZE, GFP_KERNEL);
|
||||||
|
if (!pad)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
encrypted_datalen = roundup(epayload->decrypted_datalen, blksize);
|
encrypted_datalen = roundup(epayload->decrypted_datalen, blksize);
|
||||||
req = init_skcipher_req(derived_key, derived_keylen);
|
req = init_skcipher_req(derived_key, derived_keylen);
|
||||||
ret = PTR_ERR(req);
|
ret = PTR_ERR(req);
|
||||||
|
@ -594,13 +575,12 @@ static int derived_key_decrypt(struct encrypted_key_payload *epayload,
|
||||||
goto out;
|
goto out;
|
||||||
dump_encrypted_data(epayload, encrypted_datalen);
|
dump_encrypted_data(epayload, encrypted_datalen);
|
||||||
|
|
||||||
memset(pad, 0, sizeof pad);
|
|
||||||
sg_init_table(sg_in, 1);
|
sg_init_table(sg_in, 1);
|
||||||
sg_init_table(sg_out, 2);
|
sg_init_table(sg_out, 2);
|
||||||
sg_set_buf(sg_in, epayload->encrypted_data, encrypted_datalen);
|
sg_set_buf(sg_in, epayload->encrypted_data, encrypted_datalen);
|
||||||
sg_set_buf(&sg_out[0], epayload->decrypted_data,
|
sg_set_buf(&sg_out[0], epayload->decrypted_data,
|
||||||
epayload->decrypted_datalen);
|
epayload->decrypted_datalen);
|
||||||
sg_set_buf(&sg_out[1], pad, sizeof pad);
|
sg_set_buf(&sg_out[1], pad, AES_BLOCK_SIZE);
|
||||||
|
|
||||||
memcpy(iv, epayload->iv, sizeof(iv));
|
memcpy(iv, epayload->iv, sizeof(iv));
|
||||||
skcipher_request_set_crypt(req, sg_in, sg_out, encrypted_datalen, iv);
|
skcipher_request_set_crypt(req, sg_in, sg_out, encrypted_datalen, iv);
|
||||||
|
@ -612,6 +592,7 @@ static int derived_key_decrypt(struct encrypted_key_payload *epayload,
|
||||||
goto out;
|
goto out;
|
||||||
dump_decrypted_data(epayload);
|
dump_decrypted_data(epayload);
|
||||||
out:
|
out:
|
||||||
|
kfree(pad);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -722,6 +703,7 @@ static int encrypted_key_decrypt(struct encrypted_key_payload *epayload,
|
||||||
out:
|
out:
|
||||||
up_read(&mkey->sem);
|
up_read(&mkey->sem);
|
||||||
key_put(mkey);
|
key_put(mkey);
|
||||||
|
memzero_explicit(derived_key, sizeof(derived_key));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -828,13 +810,13 @@ static int encrypted_instantiate(struct key *key,
|
||||||
ret = encrypted_init(epayload, key->description, format, master_desc,
|
ret = encrypted_init(epayload, key->description, format, master_desc,
|
||||||
decrypted_datalen, hex_encoded_iv);
|
decrypted_datalen, hex_encoded_iv);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
kfree(epayload);
|
kzfree(epayload);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
rcu_assign_keypointer(key, epayload);
|
rcu_assign_keypointer(key, epayload);
|
||||||
out:
|
out:
|
||||||
kfree(datablob);
|
kzfree(datablob);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -843,8 +825,7 @@ static void encrypted_rcu_free(struct rcu_head *rcu)
|
||||||
struct encrypted_key_payload *epayload;
|
struct encrypted_key_payload *epayload;
|
||||||
|
|
||||||
epayload = container_of(rcu, struct encrypted_key_payload, rcu);
|
epayload = container_of(rcu, struct encrypted_key_payload, rcu);
|
||||||
memset(epayload->decrypted_data, 0, epayload->decrypted_datalen);
|
kzfree(epayload);
|
||||||
kfree(epayload);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -902,7 +883,7 @@ static int encrypted_update(struct key *key, struct key_preparsed_payload *prep)
|
||||||
rcu_assign_keypointer(key, new_epayload);
|
rcu_assign_keypointer(key, new_epayload);
|
||||||
call_rcu(&epayload->rcu, encrypted_rcu_free);
|
call_rcu(&epayload->rcu, encrypted_rcu_free);
|
||||||
out:
|
out:
|
||||||
kfree(buf);
|
kzfree(buf);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -960,33 +941,26 @@ static long encrypted_read(const struct key *key, char __user *buffer,
|
||||||
|
|
||||||
up_read(&mkey->sem);
|
up_read(&mkey->sem);
|
||||||
key_put(mkey);
|
key_put(mkey);
|
||||||
|
memzero_explicit(derived_key, sizeof(derived_key));
|
||||||
|
|
||||||
if (copy_to_user(buffer, ascii_buf, asciiblob_len) != 0)
|
if (copy_to_user(buffer, ascii_buf, asciiblob_len) != 0)
|
||||||
ret = -EFAULT;
|
ret = -EFAULT;
|
||||||
kfree(ascii_buf);
|
kzfree(ascii_buf);
|
||||||
|
|
||||||
return asciiblob_len;
|
return asciiblob_len;
|
||||||
out:
|
out:
|
||||||
up_read(&mkey->sem);
|
up_read(&mkey->sem);
|
||||||
key_put(mkey);
|
key_put(mkey);
|
||||||
|
memzero_explicit(derived_key, sizeof(derived_key));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* encrypted_destroy - before freeing the key, clear the decrypted data
|
* encrypted_destroy - clear and free the key's payload
|
||||||
*
|
|
||||||
* Before freeing the key, clear the memory containing the decrypted
|
|
||||||
* key data.
|
|
||||||
*/
|
*/
|
||||||
static void encrypted_destroy(struct key *key)
|
static void encrypted_destroy(struct key *key)
|
||||||
{
|
{
|
||||||
struct encrypted_key_payload *epayload = key->payload.data[0];
|
kzfree(key->payload.data[0]);
|
||||||
|
|
||||||
if (!epayload)
|
|
||||||
return;
|
|
||||||
|
|
||||||
memzero_explicit(epayload->decrypted_data, epayload->decrypted_datalen);
|
|
||||||
kfree(key->payload.data[0]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct key_type key_type_encrypted = {
|
struct key_type key_type_encrypted = {
|
||||||
|
@ -999,47 +973,17 @@ struct key_type key_type_encrypted = {
|
||||||
};
|
};
|
||||||
EXPORT_SYMBOL_GPL(key_type_encrypted);
|
EXPORT_SYMBOL_GPL(key_type_encrypted);
|
||||||
|
|
||||||
static void encrypted_shash_release(void)
|
|
||||||
{
|
|
||||||
if (hashalg)
|
|
||||||
crypto_free_shash(hashalg);
|
|
||||||
if (hmacalg)
|
|
||||||
crypto_free_shash(hmacalg);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __init encrypted_shash_alloc(void)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
hmacalg = crypto_alloc_shash(hmac_alg, 0, CRYPTO_ALG_ASYNC);
|
|
||||||
if (IS_ERR(hmacalg)) {
|
|
||||||
pr_info("encrypted_key: could not allocate crypto %s\n",
|
|
||||||
hmac_alg);
|
|
||||||
return PTR_ERR(hmacalg);
|
|
||||||
}
|
|
||||||
|
|
||||||
hashalg = crypto_alloc_shash(hash_alg, 0, CRYPTO_ALG_ASYNC);
|
|
||||||
if (IS_ERR(hashalg)) {
|
|
||||||
pr_info("encrypted_key: could not allocate crypto %s\n",
|
|
||||||
hash_alg);
|
|
||||||
ret = PTR_ERR(hashalg);
|
|
||||||
goto hashalg_fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
hashalg_fail:
|
|
||||||
crypto_free_shash(hmacalg);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __init init_encrypted(void)
|
static int __init init_encrypted(void)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = encrypted_shash_alloc();
|
hash_tfm = crypto_alloc_shash(hash_alg, 0, CRYPTO_ALG_ASYNC);
|
||||||
if (ret < 0)
|
if (IS_ERR(hash_tfm)) {
|
||||||
return ret;
|
pr_err("encrypted_key: can't allocate %s transform: %ld\n",
|
||||||
|
hash_alg, PTR_ERR(hash_tfm));
|
||||||
|
return PTR_ERR(hash_tfm);
|
||||||
|
}
|
||||||
|
|
||||||
ret = aes_get_sizes();
|
ret = aes_get_sizes();
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -1048,14 +992,14 @@ static int __init init_encrypted(void)
|
||||||
goto out;
|
goto out;
|
||||||
return 0;
|
return 0;
|
||||||
out:
|
out:
|
||||||
encrypted_shash_release();
|
crypto_free_shash(hash_tfm);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __exit cleanup_encrypted(void)
|
static void __exit cleanup_encrypted(void)
|
||||||
{
|
{
|
||||||
encrypted_shash_release();
|
crypto_free_shash(hash_tfm);
|
||||||
unregister_key_type(&key_type_encrypted);
|
unregister_key_type(&key_type_encrypted);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -158,9 +158,7 @@ static noinline void key_gc_unused_keys(struct list_head *keys)
|
||||||
|
|
||||||
kfree(key->description);
|
kfree(key->description);
|
||||||
|
|
||||||
#ifdef KEY_DEBUGGING
|
memzero_explicit(key, sizeof(*key));
|
||||||
key->magic = KEY_DEBUG_MAGIC_X;
|
|
||||||
#endif
|
|
||||||
kmem_cache_free(key_jar, key);
|
kmem_cache_free(key_jar, key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -660,14 +660,11 @@ not_found:
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
found:
|
found:
|
||||||
/* pretend it doesn't exist if it is awaiting deletion */
|
/* A key is allowed to be looked up only if someone still owns a
|
||||||
if (refcount_read(&key->usage) == 0)
|
* reference to it - otherwise it's awaiting the gc.
|
||||||
goto not_found;
|
|
||||||
|
|
||||||
/* this races with key_put(), but that doesn't matter since key_put()
|
|
||||||
* doesn't actually change the key
|
|
||||||
*/
|
*/
|
||||||
__key_get(key);
|
if (!refcount_inc_not_zero(&key->usage))
|
||||||
|
goto not_found;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
spin_unlock(&key_serial_lock);
|
spin_unlock(&key_serial_lock);
|
||||||
|
@ -966,12 +963,11 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen)
|
||||||
/* the key must be writable */
|
/* the key must be writable */
|
||||||
ret = key_permission(key_ref, KEY_NEED_WRITE);
|
ret = key_permission(key_ref, KEY_NEED_WRITE);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto error;
|
return ret;
|
||||||
|
|
||||||
/* attempt to update it if supported */
|
/* attempt to update it if supported */
|
||||||
ret = -EOPNOTSUPP;
|
|
||||||
if (!key->type->update)
|
if (!key->type->update)
|
||||||
goto error;
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
memset(&prep, 0, sizeof(prep));
|
memset(&prep, 0, sizeof(prep));
|
||||||
prep.data = payload;
|
prep.data = payload;
|
||||||
|
|
|
@ -99,7 +99,7 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type,
|
||||||
/* pull the payload in if one was supplied */
|
/* pull the payload in if one was supplied */
|
||||||
payload = NULL;
|
payload = NULL;
|
||||||
|
|
||||||
if (_payload) {
|
if (plen) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
payload = kvmalloc(plen, GFP_KERNEL);
|
payload = kvmalloc(plen, GFP_KERNEL);
|
||||||
if (!payload)
|
if (!payload)
|
||||||
|
@ -132,7 +132,10 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type,
|
||||||
|
|
||||||
key_ref_put(keyring_ref);
|
key_ref_put(keyring_ref);
|
||||||
error3:
|
error3:
|
||||||
kvfree(payload);
|
if (payload) {
|
||||||
|
memzero_explicit(payload, plen);
|
||||||
|
kvfree(payload);
|
||||||
|
}
|
||||||
error2:
|
error2:
|
||||||
kfree(description);
|
kfree(description);
|
||||||
error:
|
error:
|
||||||
|
@ -324,7 +327,7 @@ long keyctl_update_key(key_serial_t id,
|
||||||
|
|
||||||
/* pull the payload in if one was supplied */
|
/* pull the payload in if one was supplied */
|
||||||
payload = NULL;
|
payload = NULL;
|
||||||
if (_payload) {
|
if (plen) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
payload = kmalloc(plen, GFP_KERNEL);
|
payload = kmalloc(plen, GFP_KERNEL);
|
||||||
if (!payload)
|
if (!payload)
|
||||||
|
@ -347,7 +350,7 @@ long keyctl_update_key(key_serial_t id,
|
||||||
|
|
||||||
key_ref_put(key_ref);
|
key_ref_put(key_ref);
|
||||||
error2:
|
error2:
|
||||||
kfree(payload);
|
kzfree(payload);
|
||||||
error:
|
error:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -1093,7 +1096,10 @@ long keyctl_instantiate_key_common(key_serial_t id,
|
||||||
keyctl_change_reqkey_auth(NULL);
|
keyctl_change_reqkey_auth(NULL);
|
||||||
|
|
||||||
error2:
|
error2:
|
||||||
kvfree(payload);
|
if (payload) {
|
||||||
|
memzero_explicit(payload, plen);
|
||||||
|
kvfree(payload);
|
||||||
|
}
|
||||||
error:
|
error:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -706,7 +706,7 @@ descend_to_keyring:
|
||||||
* Non-keyrings avoid the leftmost branch of the root entirely (root
|
* Non-keyrings avoid the leftmost branch of the root entirely (root
|
||||||
* slots 1-15).
|
* slots 1-15).
|
||||||
*/
|
*/
|
||||||
ptr = ACCESS_ONCE(keyring->keys.root);
|
ptr = READ_ONCE(keyring->keys.root);
|
||||||
if (!ptr)
|
if (!ptr)
|
||||||
goto not_this_keyring;
|
goto not_this_keyring;
|
||||||
|
|
||||||
|
@ -720,7 +720,7 @@ descend_to_keyring:
|
||||||
if ((shortcut->index_key[0] & ASSOC_ARRAY_FAN_MASK) != 0)
|
if ((shortcut->index_key[0] & ASSOC_ARRAY_FAN_MASK) != 0)
|
||||||
goto not_this_keyring;
|
goto not_this_keyring;
|
||||||
|
|
||||||
ptr = ACCESS_ONCE(shortcut->next_node);
|
ptr = READ_ONCE(shortcut->next_node);
|
||||||
node = assoc_array_ptr_to_node(ptr);
|
node = assoc_array_ptr_to_node(ptr);
|
||||||
goto begin_node;
|
goto begin_node;
|
||||||
}
|
}
|
||||||
|
@ -740,7 +740,7 @@ descend_to_node:
|
||||||
if (assoc_array_ptr_is_shortcut(ptr)) {
|
if (assoc_array_ptr_is_shortcut(ptr)) {
|
||||||
shortcut = assoc_array_ptr_to_shortcut(ptr);
|
shortcut = assoc_array_ptr_to_shortcut(ptr);
|
||||||
smp_read_barrier_depends();
|
smp_read_barrier_depends();
|
||||||
ptr = ACCESS_ONCE(shortcut->next_node);
|
ptr = READ_ONCE(shortcut->next_node);
|
||||||
BUG_ON(!assoc_array_ptr_is_node(ptr));
|
BUG_ON(!assoc_array_ptr_is_node(ptr));
|
||||||
}
|
}
|
||||||
node = assoc_array_ptr_to_node(ptr);
|
node = assoc_array_ptr_to_node(ptr);
|
||||||
|
@ -752,7 +752,7 @@ begin_node:
|
||||||
ascend_to_node:
|
ascend_to_node:
|
||||||
/* Go through the slots in a node */
|
/* Go through the slots in a node */
|
||||||
for (; slot < ASSOC_ARRAY_FAN_OUT; slot++) {
|
for (; slot < ASSOC_ARRAY_FAN_OUT; slot++) {
|
||||||
ptr = ACCESS_ONCE(node->slots[slot]);
|
ptr = READ_ONCE(node->slots[slot]);
|
||||||
|
|
||||||
if (assoc_array_ptr_is_meta(ptr) && node->back_pointer)
|
if (assoc_array_ptr_is_meta(ptr) && node->back_pointer)
|
||||||
goto descend_to_node;
|
goto descend_to_node;
|
||||||
|
@ -790,13 +790,13 @@ ascend_to_node:
|
||||||
/* We've dealt with all the slots in the current node, so now we need
|
/* We've dealt with all the slots in the current node, so now we need
|
||||||
* to ascend to the parent and continue processing there.
|
* to ascend to the parent and continue processing there.
|
||||||
*/
|
*/
|
||||||
ptr = ACCESS_ONCE(node->back_pointer);
|
ptr = READ_ONCE(node->back_pointer);
|
||||||
slot = node->parent_slot;
|
slot = node->parent_slot;
|
||||||
|
|
||||||
if (ptr && assoc_array_ptr_is_shortcut(ptr)) {
|
if (ptr && assoc_array_ptr_is_shortcut(ptr)) {
|
||||||
shortcut = assoc_array_ptr_to_shortcut(ptr);
|
shortcut = assoc_array_ptr_to_shortcut(ptr);
|
||||||
smp_read_barrier_depends();
|
smp_read_barrier_depends();
|
||||||
ptr = ACCESS_ONCE(shortcut->back_pointer);
|
ptr = READ_ONCE(shortcut->back_pointer);
|
||||||
slot = shortcut->parent_slot;
|
slot = shortcut->parent_slot;
|
||||||
}
|
}
|
||||||
if (!ptr)
|
if (!ptr)
|
||||||
|
|
|
@ -809,15 +809,14 @@ long join_session_keyring(const char *name)
|
||||||
ret = PTR_ERR(keyring);
|
ret = PTR_ERR(keyring);
|
||||||
goto error2;
|
goto error2;
|
||||||
} else if (keyring == new->session_keyring) {
|
} else if (keyring == new->session_keyring) {
|
||||||
key_put(keyring);
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
goto error2;
|
goto error3;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* we've got a keyring - now to install it */
|
/* we've got a keyring - now to install it */
|
||||||
ret = install_session_keyring_to_cred(new, keyring);
|
ret = install_session_keyring_to_cred(new, keyring);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto error2;
|
goto error3;
|
||||||
|
|
||||||
commit_creds(new);
|
commit_creds(new);
|
||||||
mutex_unlock(&key_session_mutex);
|
mutex_unlock(&key_session_mutex);
|
||||||
|
@ -827,6 +826,8 @@ long join_session_keyring(const char *name)
|
||||||
okay:
|
okay:
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
error3:
|
||||||
|
key_put(keyring);
|
||||||
error2:
|
error2:
|
||||||
mutex_unlock(&key_session_mutex);
|
mutex_unlock(&key_session_mutex);
|
||||||
error:
|
error:
|
||||||
|
|
|
@ -70,7 +70,7 @@ static int TSS_sha1(const unsigned char *data, unsigned int datalen,
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = crypto_shash_digest(&sdesc->shash, data, datalen, digest);
|
ret = crypto_shash_digest(&sdesc->shash, data, datalen, digest);
|
||||||
kfree(sdesc);
|
kzfree(sdesc);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,7 +114,7 @@ static int TSS_rawhmac(unsigned char *digest, const unsigned char *key,
|
||||||
if (!ret)
|
if (!ret)
|
||||||
ret = crypto_shash_final(&sdesc->shash, digest);
|
ret = crypto_shash_final(&sdesc->shash, digest);
|
||||||
out:
|
out:
|
||||||
kfree(sdesc);
|
kzfree(sdesc);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,7 +165,7 @@ static int TSS_authhmac(unsigned char *digest, const unsigned char *key,
|
||||||
paramdigest, TPM_NONCE_SIZE, h1,
|
paramdigest, TPM_NONCE_SIZE, h1,
|
||||||
TPM_NONCE_SIZE, h2, 1, &c, 0, 0);
|
TPM_NONCE_SIZE, h2, 1, &c, 0, 0);
|
||||||
out:
|
out:
|
||||||
kfree(sdesc);
|
kzfree(sdesc);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,7 +246,7 @@ static int TSS_checkhmac1(unsigned char *buffer,
|
||||||
if (memcmp(testhmac, authdata, SHA1_DIGEST_SIZE))
|
if (memcmp(testhmac, authdata, SHA1_DIGEST_SIZE))
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
out:
|
out:
|
||||||
kfree(sdesc);
|
kzfree(sdesc);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -347,7 +347,7 @@ static int TSS_checkhmac2(unsigned char *buffer,
|
||||||
if (memcmp(testhmac2, authdata2, SHA1_DIGEST_SIZE))
|
if (memcmp(testhmac2, authdata2, SHA1_DIGEST_SIZE))
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
out:
|
out:
|
||||||
kfree(sdesc);
|
kzfree(sdesc);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -564,7 +564,7 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype,
|
||||||
*bloblen = storedsize;
|
*bloblen = storedsize;
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
kfree(td);
|
kzfree(td);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -678,7 +678,7 @@ static int key_seal(struct trusted_key_payload *p,
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
pr_info("trusted_key: srkseal failed (%d)\n", ret);
|
pr_info("trusted_key: srkseal failed (%d)\n", ret);
|
||||||
|
|
||||||
kfree(tb);
|
kzfree(tb);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -703,7 +703,7 @@ static int key_unseal(struct trusted_key_payload *p,
|
||||||
/* pull migratable flag out of sealed key */
|
/* pull migratable flag out of sealed key */
|
||||||
p->migratable = p->key[--p->key_len];
|
p->migratable = p->key[--p->key_len];
|
||||||
|
|
||||||
kfree(tb);
|
kzfree(tb);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1037,12 +1037,12 @@ static int trusted_instantiate(struct key *key,
|
||||||
if (!ret && options->pcrlock)
|
if (!ret && options->pcrlock)
|
||||||
ret = pcrlock(options->pcrlock);
|
ret = pcrlock(options->pcrlock);
|
||||||
out:
|
out:
|
||||||
kfree(datablob);
|
kzfree(datablob);
|
||||||
kfree(options);
|
kzfree(options);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
rcu_assign_keypointer(key, payload);
|
rcu_assign_keypointer(key, payload);
|
||||||
else
|
else
|
||||||
kfree(payload);
|
kzfree(payload);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1051,8 +1051,7 @@ static void trusted_rcu_free(struct rcu_head *rcu)
|
||||||
struct trusted_key_payload *p;
|
struct trusted_key_payload *p;
|
||||||
|
|
||||||
p = container_of(rcu, struct trusted_key_payload, rcu);
|
p = container_of(rcu, struct trusted_key_payload, rcu);
|
||||||
memset(p->key, 0, p->key_len);
|
kzfree(p);
|
||||||
kfree(p);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1094,13 +1093,13 @@ static int trusted_update(struct key *key, struct key_preparsed_payload *prep)
|
||||||
ret = datablob_parse(datablob, new_p, new_o);
|
ret = datablob_parse(datablob, new_p, new_o);
|
||||||
if (ret != Opt_update) {
|
if (ret != Opt_update) {
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
kfree(new_p);
|
kzfree(new_p);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!new_o->keyhandle) {
|
if (!new_o->keyhandle) {
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
kfree(new_p);
|
kzfree(new_p);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1114,22 +1113,22 @@ static int trusted_update(struct key *key, struct key_preparsed_payload *prep)
|
||||||
ret = key_seal(new_p, new_o);
|
ret = key_seal(new_p, new_o);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
pr_info("trusted_key: key_seal failed (%d)\n", ret);
|
pr_info("trusted_key: key_seal failed (%d)\n", ret);
|
||||||
kfree(new_p);
|
kzfree(new_p);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (new_o->pcrlock) {
|
if (new_o->pcrlock) {
|
||||||
ret = pcrlock(new_o->pcrlock);
|
ret = pcrlock(new_o->pcrlock);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
pr_info("trusted_key: pcrlock failed (%d)\n", ret);
|
pr_info("trusted_key: pcrlock failed (%d)\n", ret);
|
||||||
kfree(new_p);
|
kzfree(new_p);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rcu_assign_keypointer(key, new_p);
|
rcu_assign_keypointer(key, new_p);
|
||||||
call_rcu(&p->rcu, trusted_rcu_free);
|
call_rcu(&p->rcu, trusted_rcu_free);
|
||||||
out:
|
out:
|
||||||
kfree(datablob);
|
kzfree(datablob);
|
||||||
kfree(new_o);
|
kzfree(new_o);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1158,24 +1157,19 @@ static long trusted_read(const struct key *key, char __user *buffer,
|
||||||
for (i = 0; i < p->blob_len; i++)
|
for (i = 0; i < p->blob_len; i++)
|
||||||
bufp = hex_byte_pack(bufp, p->blob[i]);
|
bufp = hex_byte_pack(bufp, p->blob[i]);
|
||||||
if ((copy_to_user(buffer, ascii_buf, 2 * p->blob_len)) != 0) {
|
if ((copy_to_user(buffer, ascii_buf, 2 * p->blob_len)) != 0) {
|
||||||
kfree(ascii_buf);
|
kzfree(ascii_buf);
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
kfree(ascii_buf);
|
kzfree(ascii_buf);
|
||||||
return 2 * p->blob_len;
|
return 2 * p->blob_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* trusted_destroy - before freeing the key, clear the decrypted data
|
* trusted_destroy - clear and free the key's payload
|
||||||
*/
|
*/
|
||||||
static void trusted_destroy(struct key *key)
|
static void trusted_destroy(struct key *key)
|
||||||
{
|
{
|
||||||
struct trusted_key_payload *p = key->payload.data[0];
|
kzfree(key->payload.data[0]);
|
||||||
|
|
||||||
if (!p)
|
|
||||||
return;
|
|
||||||
memset(p->key, 0, p->key_len);
|
|
||||||
kfree(key->payload.data[0]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct key_type key_type_trusted = {
|
struct key_type key_type_trusted = {
|
||||||
|
|
|
@ -86,10 +86,18 @@ EXPORT_SYMBOL_GPL(user_preparse);
|
||||||
*/
|
*/
|
||||||
void user_free_preparse(struct key_preparsed_payload *prep)
|
void user_free_preparse(struct key_preparsed_payload *prep)
|
||||||
{
|
{
|
||||||
kfree(prep->payload.data[0]);
|
kzfree(prep->payload.data[0]);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(user_free_preparse);
|
EXPORT_SYMBOL_GPL(user_free_preparse);
|
||||||
|
|
||||||
|
static void user_free_payload_rcu(struct rcu_head *head)
|
||||||
|
{
|
||||||
|
struct user_key_payload *payload;
|
||||||
|
|
||||||
|
payload = container_of(head, struct user_key_payload, rcu);
|
||||||
|
kzfree(payload);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* update a user defined key
|
* update a user defined key
|
||||||
* - the key's semaphore is write-locked
|
* - the key's semaphore is write-locked
|
||||||
|
@ -112,7 +120,7 @@ int user_update(struct key *key, struct key_preparsed_payload *prep)
|
||||||
prep->payload.data[0] = NULL;
|
prep->payload.data[0] = NULL;
|
||||||
|
|
||||||
if (zap)
|
if (zap)
|
||||||
kfree_rcu(zap, rcu);
|
call_rcu(&zap->rcu, user_free_payload_rcu);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(user_update);
|
EXPORT_SYMBOL_GPL(user_update);
|
||||||
|
@ -130,7 +138,7 @@ void user_revoke(struct key *key)
|
||||||
|
|
||||||
if (upayload) {
|
if (upayload) {
|
||||||
rcu_assign_keypointer(key, NULL);
|
rcu_assign_keypointer(key, NULL);
|
||||||
kfree_rcu(upayload, rcu);
|
call_rcu(&upayload->rcu, user_free_payload_rcu);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,7 +151,7 @@ void user_destroy(struct key *key)
|
||||||
{
|
{
|
||||||
struct user_key_payload *upayload = key->payload.data[0];
|
struct user_key_payload *upayload = key->payload.data[0];
|
||||||
|
|
||||||
kfree(upayload);
|
kzfree(upayload);
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT_SYMBOL_GPL(user_destroy);
|
EXPORT_SYMBOL_GPL(user_destroy);
|
||||||
|
|
Loading…
Reference in New Issue