aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Rothwell <sfr@canb.auug.org.au>2017-05-30 12:25:10 +1000
committerStephen Rothwell <sfr@canb.auug.org.au>2017-05-30 12:25:10 +1000
commit52e553a8cc67f5448bd44d9fe5fae3ef1660cdf2 (patch)
treecaae5556f5dd44859e8ecde8f942ac4092d54b01
parent644406fd7dd7fa0b7c894b0fd5093b85de7bc0e3 (diff)
parente36484b5ac315f477c9c4075a78753fa4c0e0cf1 (diff)
Merge remote-tracking branch 'keys/keys-next'
-rw-r--r--crypto/asymmetric_keys/verify_pefile.c4
-rw-r--r--include/linux/key.h1
-rw-r--r--include/linux/mpi.h2
-rw-r--r--include/uapi/linux/keyctl.h4
-rw-r--r--lib/mpi/mpicoder.c10
-rw-r--r--security/keys/dh.c34
-rw-r--r--security/keys/encrypted-keys/encrypted.c31
-rw-r--r--security/keys/gc.c4
-rw-r--r--security/keys/keyctl.c4
-rw-r--r--security/keys/trusted.c50
-rw-r--r--security/keys/user_defined.c16
11 files changed, 79 insertions, 81 deletions
diff --git a/crypto/asymmetric_keys/verify_pefile.c b/crypto/asymmetric_keys/verify_pefile.c
index 672a94c2c3ff..d178650fd524 100644
--- a/crypto/asymmetric_keys/verify_pefile.c
+++ b/crypto/asymmetric_keys/verify_pefile.c
@@ -381,7 +381,7 @@ static int pefile_digest_pe(const void *pebuf, unsigned int pelen,
}
error:
- kfree(desc);
+ kzfree(desc);
error_no_desc:
crypto_free_shash(tfm);
kleave(" = %d", ret);
@@ -450,6 +450,6 @@ int verify_pefile_signature(const void *pebuf, unsigned pelen,
ret = pefile_digest_pe(pebuf, pelen, &ctx);
error:
- kfree(ctx.digest);
+ kzfree(ctx.digest);
return ret;
}
diff --git a/include/linux/key.h b/include/linux/key.h
index 24dfe6c1f8cb..044114185120 100644
--- a/include/linux/key.h
+++ b/include/linux/key.h
@@ -173,7 +173,6 @@ struct key {
#ifdef KEY_DEBUGGING
unsigned magic;
#define KEY_DEBUG_MAGIC 0x18273645u
-#define KEY_DEBUG_MAGIC_X 0xf8e9dacbu
#endif
unsigned long flags; /* status flags (change with bitops) */
diff --git a/include/linux/mpi.h b/include/linux/mpi.h
index 1cc5ffb769af..1f679b632277 100644
--- a/include/linux/mpi.h
+++ b/include/linux/mpi.h
@@ -78,7 +78,7 @@ int mpi_fromstr(MPI val, const char *str);
u32 mpi_get_keyid(MPI a, u32 *keyid);
void *mpi_get_buffer(MPI a, unsigned *nbytes, int *sign);
int mpi_read_buffer(MPI a, uint8_t *buf, unsigned buf_len, unsigned *nbytes,
- int *sign);
+ int *sign, bool skip_lzeros);
void *mpi_get_secure_buffer(MPI a, unsigned *nbytes, int *sign);
int mpi_write_to_sgl(MPI a, struct scatterlist *sg, unsigned nbytes,
int *sign);
diff --git a/include/uapi/linux/keyctl.h b/include/uapi/linux/keyctl.h
index 201c6644b237..ef16df06642a 100644
--- a/include/uapi/linux/keyctl.h
+++ b/include/uapi/linux/keyctl.h
@@ -70,8 +70,8 @@ struct keyctl_dh_params {
};
struct keyctl_kdf_params {
- char *hashname;
- char *otherinfo;
+ char __user *hashname;
+ char __user *otherinfo;
__u32 otherinfolen;
__u32 __spare[8];
};
diff --git a/lib/mpi/mpicoder.c b/lib/mpi/mpicoder.c
index 5a0f75a3bf01..659d787fb2fd 100644
--- a/lib/mpi/mpicoder.c
+++ b/lib/mpi/mpicoder.c
@@ -137,11 +137,12 @@ static int count_lzeros(MPI a)
* the data to-be-written on -EOVERFLOW in case buf_len was too
* small.
* @sign: if not NULL, it will be set to the sign of a.
+ * @skip_lzeros:Skip the leading zeros of the MPI before writing to buffer.
*
* Return: 0 on success or error code in case of error
*/
int mpi_read_buffer(MPI a, uint8_t *buf, unsigned buf_len, unsigned *nbytes,
- int *sign)
+ int *sign, bool skip_lzeros)
{
uint8_t *p;
#if BYTES_PER_MPI_LIMB == 4
@@ -152,7 +153,7 @@ int mpi_read_buffer(MPI a, uint8_t *buf, unsigned buf_len, unsigned *nbytes,
#error please implement for this limb size.
#endif
unsigned int n = mpi_get_size(a);
- int i, lzeros;
+ int i, lzeros = 0;
if (!buf || !nbytes)
return -EINVAL;
@@ -160,7 +161,8 @@ int mpi_read_buffer(MPI a, uint8_t *buf, unsigned buf_len, unsigned *nbytes,
if (sign)
*sign = a->sign;
- lzeros = count_lzeros(a);
+ if (skip_lzeros)
+ lzeros = count_lzeros(a);
if (buf_len < n - lzeros) {
*nbytes = n - lzeros;
@@ -219,7 +221,7 @@ void *mpi_get_buffer(MPI a, unsigned *nbytes, int *sign)
if (!buf)
return NULL;
- ret = mpi_read_buffer(a, buf, n, nbytes, sign);
+ ret = mpi_read_buffer(a, buf, n, nbytes, sign, true);
if (ret) {
kfree(buf);
diff --git a/security/keys/dh.c b/security/keys/dh.c
index e603bd912e4c..9b6e6b3ecccb 100644
--- a/security/keys/dh.c
+++ b/security/keys/dh.c
@@ -89,6 +89,7 @@ static int kdf_alloc(struct kdf_sdesc **sdesc_ret, char *hashname)
struct crypto_shash *tfm;
struct kdf_sdesc *sdesc;
int size;
+ int err;
/* allocate synchronous hash */
tfm = crypto_alloc_shash(hashname, 0, 0);
@@ -97,16 +98,25 @@ static int kdf_alloc(struct kdf_sdesc **sdesc_ret, char *hashname)
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);
sdesc = kmalloc(size, GFP_KERNEL);
if (!sdesc)
- return -ENOMEM;
+ goto out_free_tfm;
sdesc->shash.tfm = tfm;
sdesc->shash.flags = 0x0;
*sdesc_ret = sdesc;
return 0;
+
+out_free_tfm:
+ crypto_free_shash(tfm);
+ return err;
}
static void kdf_dealloc(struct kdf_sdesc *sdesc)
@@ -120,14 +130,6 @@ static void kdf_dealloc(struct kdf_sdesc *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
* as well as SP800-56A section 5.8.1 (Single-step KDF).
@@ -144,16 +146,14 @@ static int kdf_ctr(struct kdf_sdesc *sdesc, const u8 *src, unsigned int slen,
unsigned int h = crypto_shash_digestsize(desc->tfm);
int err = 0;
u8 *dst_orig = dst;
- u32 i = 1;
- u8 iteration[sizeof(u32)];
+ __be32 counter = cpu_to_be32(1);
while (dlen) {
err = crypto_shash_init(desc);
if (err)
goto err;
- crypto_kw_cpu_to_be32(i, iteration);
- err = crypto_shash_update(desc, iteration, sizeof(u32));
+ err = crypto_shash_update(desc, (u8 *)&counter, sizeof(__be32));
if (err)
goto err;
@@ -179,7 +179,7 @@ static int kdf_ctr(struct kdf_sdesc *sdesc, const u8 *src, unsigned int slen,
dlen -= h;
dst += h;
- i++;
+ counter = cpu_to_be32(be32_to_cpu(counter) + 1);
}
}
@@ -296,7 +296,7 @@ long __keyctl_dh_compute(struct keyctl_dh_params __user *params,
}
/* allocate space for DH shared secret and SP800-56A otherinfo */
- kbuf = kmalloc(kdfcopy ? (resultlen + kdfcopy->otherinfolen) : resultlen,
+ kbuf = kzalloc(kdfcopy ? (resultlen + kdfcopy->otherinfolen) : resultlen,
GFP_KERNEL);
if (!kbuf) {
ret = -ENOMEM;
@@ -307,7 +307,7 @@ long __keyctl_dh_compute(struct keyctl_dh_params __user *params,
* Concatenate SP800-56A otherinfo past DH shared secret -- the
* input to the KDF is (DH shared secret || otherinfo)
*/
- if (kdfcopy && kdfcopy->otherinfo &&
+ if (kdfcopy &&
copy_from_user(kbuf + resultlen, kdfcopy->otherinfo,
kdfcopy->otherinfolen) != 0) {
ret = -EFAULT;
@@ -318,7 +318,7 @@ long __keyctl_dh_compute(struct keyctl_dh_params __user *params,
if (ret)
goto error5;
- ret = mpi_read_buffer(result, kbuf, resultlen, &nbytes, NULL);
+ ret = mpi_read_buffer(result, kbuf, resultlen, &nbytes, NULL, false);
if (ret != 0)
goto error5;
diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c
index 72ecbd0d1e37..f2f920fa703a 100644
--- a/security/keys/encrypted-keys/encrypted.c
+++ b/security/keys/encrypted-keys/encrypted.c
@@ -397,7 +397,7 @@ static int get_derived_key(u8 *derived_key, enum derived_key_type key_type,
memcpy(derived_buf + strlen(derived_buf) + 1, master_key,
master_keylen);
ret = calc_hash(derived_key, derived_buf, derived_buf_len);
- kfree(derived_buf);
+ kzfree(derived_buf);
return ret;
}
@@ -533,6 +533,7 @@ static int datablob_hmac_append(struct encrypted_key_payload *epayload,
if (!ret)
dump_hmac(NULL, digest, HASH_SIZE);
out:
+ memzero_explicit(derived_key, sizeof(derived_key));
return ret;
}
@@ -571,6 +572,7 @@ static int datablob_hmac_verify(struct encrypted_key_payload *epayload,
dump_hmac("calc", digest, HASH_SIZE);
}
out:
+ memzero_explicit(derived_key, sizeof(derived_key));
return ret;
}
@@ -722,6 +724,7 @@ static int encrypted_key_decrypt(struct encrypted_key_payload *epayload,
out:
up_read(&mkey->sem);
key_put(mkey);
+ memzero_explicit(derived_key, sizeof(derived_key));
return ret;
}
@@ -828,13 +831,13 @@ static int encrypted_instantiate(struct key *key,
ret = encrypted_init(epayload, key->description, format, master_desc,
decrypted_datalen, hex_encoded_iv);
if (ret < 0) {
- kfree(epayload);
+ kzfree(epayload);
goto out;
}
rcu_assign_keypointer(key, epayload);
out:
- kfree(datablob);
+ kzfree(datablob);
return ret;
}
@@ -843,8 +846,7 @@ static void encrypted_rcu_free(struct rcu_head *rcu)
struct encrypted_key_payload *epayload;
epayload = container_of(rcu, struct encrypted_key_payload, rcu);
- memset(epayload->decrypted_data, 0, epayload->decrypted_datalen);
- kfree(epayload);
+ kzfree(epayload);
}
/*
@@ -902,7 +904,7 @@ static int encrypted_update(struct key *key, struct key_preparsed_payload *prep)
rcu_assign_keypointer(key, new_epayload);
call_rcu(&epayload->rcu, encrypted_rcu_free);
out:
- kfree(buf);
+ kzfree(buf);
return ret;
}
@@ -960,33 +962,26 @@ static long encrypted_read(const struct key *key, char __user *buffer,
up_read(&mkey->sem);
key_put(mkey);
+ memzero_explicit(derived_key, sizeof(derived_key));
if (copy_to_user(buffer, ascii_buf, asciiblob_len) != 0)
ret = -EFAULT;
- kfree(ascii_buf);
+ kzfree(ascii_buf);
return asciiblob_len;
out:
up_read(&mkey->sem);
key_put(mkey);
+ memzero_explicit(derived_key, sizeof(derived_key));
return ret;
}
/*
- * encrypted_destroy - before freeing the key, clear the decrypted data
- *
- * Before freeing the key, clear the memory containing the decrypted
- * key data.
+ * encrypted_destroy - clear and free the key's payload
*/
static void encrypted_destroy(struct key *key)
{
- struct encrypted_key_payload *epayload = key->payload.data[0];
-
- if (!epayload)
- return;
-
- memzero_explicit(epayload->decrypted_data, epayload->decrypted_datalen);
- kfree(key->payload.data[0]);
+ kzfree(key->payload.data[0]);
}
struct key_type key_type_encrypted = {
diff --git a/security/keys/gc.c b/security/keys/gc.c
index 595becc6d0d2..87cb260e4890 100644
--- a/security/keys/gc.c
+++ b/security/keys/gc.c
@@ -158,9 +158,7 @@ static noinline void key_gc_unused_keys(struct list_head *keys)
kfree(key->description);
-#ifdef KEY_DEBUGGING
- key->magic = KEY_DEBUG_MAGIC_X;
-#endif
+ memzero_explicit(key, sizeof(*key));
kmem_cache_free(key_jar, key);
}
}
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index 447a7d5cee0f..dd0da25211b0 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -132,6 +132,7 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type,
key_ref_put(keyring_ref);
error3:
+ memzero_explicit(payload, plen);
kvfree(payload);
error2:
kfree(description);
@@ -347,7 +348,7 @@ long keyctl_update_key(key_serial_t id,
key_ref_put(key_ref);
error2:
- kfree(payload);
+ kzfree(payload);
error:
return ret;
}
@@ -1093,6 +1094,7 @@ long keyctl_instantiate_key_common(key_serial_t id,
keyctl_change_reqkey_auth(NULL);
error2:
+ memzero_explicit(payload, plen);
kvfree(payload);
error:
return ret;
diff --git a/security/keys/trusted.c b/security/keys/trusted.c
index 3811e75d280f..ddfaebf60fc8 100644
--- a/security/keys/trusted.c
+++ b/security/keys/trusted.c
@@ -70,7 +70,7 @@ static int TSS_sha1(const unsigned char *data, unsigned int datalen,
}
ret = crypto_shash_digest(&sdesc->shash, data, datalen, digest);
- kfree(sdesc);
+ kzfree(sdesc);
return ret;
}
@@ -114,7 +114,7 @@ static int TSS_rawhmac(unsigned char *digest, const unsigned char *key,
if (!ret)
ret = crypto_shash_final(&sdesc->shash, digest);
out:
- kfree(sdesc);
+ kzfree(sdesc);
return ret;
}
@@ -165,7 +165,7 @@ static int TSS_authhmac(unsigned char *digest, const unsigned char *key,
paramdigest, TPM_NONCE_SIZE, h1,
TPM_NONCE_SIZE, h2, 1, &c, 0, 0);
out:
- kfree(sdesc);
+ kzfree(sdesc);
return ret;
}
@@ -246,7 +246,7 @@ static int TSS_checkhmac1(unsigned char *buffer,
if (memcmp(testhmac, authdata, SHA1_DIGEST_SIZE))
ret = -EINVAL;
out:
- kfree(sdesc);
+ kzfree(sdesc);
return ret;
}
@@ -347,7 +347,7 @@ static int TSS_checkhmac2(unsigned char *buffer,
if (memcmp(testhmac2, authdata2, SHA1_DIGEST_SIZE))
ret = -EINVAL;
out:
- kfree(sdesc);
+ kzfree(sdesc);
return ret;
}
@@ -564,7 +564,7 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype,
*bloblen = storedsize;
}
out:
- kfree(td);
+ kzfree(td);
return ret;
}
@@ -678,7 +678,7 @@ static int key_seal(struct trusted_key_payload *p,
if (ret < 0)
pr_info("trusted_key: srkseal failed (%d)\n", ret);
- kfree(tb);
+ kzfree(tb);
return ret;
}
@@ -703,7 +703,7 @@ static int key_unseal(struct trusted_key_payload *p,
/* pull migratable flag out of sealed key */
p->migratable = p->key[--p->key_len];
- kfree(tb);
+ kzfree(tb);
return ret;
}
@@ -1037,12 +1037,12 @@ static int trusted_instantiate(struct key *key,
if (!ret && options->pcrlock)
ret = pcrlock(options->pcrlock);
out:
- kfree(datablob);
- kfree(options);
+ kzfree(datablob);
+ kzfree(options);
if (!ret)
rcu_assign_keypointer(key, payload);
else
- kfree(payload);
+ kzfree(payload);
return ret;
}
@@ -1051,8 +1051,7 @@ static void trusted_rcu_free(struct rcu_head *rcu)
struct trusted_key_payload *p;
p = container_of(rcu, struct trusted_key_payload, rcu);
- memset(p->key, 0, p->key_len);
- kfree(p);
+ kzfree(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);
if (ret != Opt_update) {
ret = -EINVAL;
- kfree(new_p);
+ kzfree(new_p);
goto out;
}
if (!new_o->keyhandle) {
ret = -EINVAL;
- kfree(new_p);
+ kzfree(new_p);
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);
if (ret < 0) {
pr_info("trusted_key: key_seal failed (%d)\n", ret);
- kfree(new_p);
+ kzfree(new_p);
goto out;
}
if (new_o->pcrlock) {
ret = pcrlock(new_o->pcrlock);
if (ret < 0) {
pr_info("trusted_key: pcrlock failed (%d)\n", ret);
- kfree(new_p);
+ kzfree(new_p);
goto out;
}
}
rcu_assign_keypointer(key, new_p);
call_rcu(&p->rcu, trusted_rcu_free);
out:
- kfree(datablob);
- kfree(new_o);
+ kzfree(datablob);
+ kzfree(new_o);
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++)
bufp = hex_byte_pack(bufp, p->blob[i]);
if ((copy_to_user(buffer, ascii_buf, 2 * p->blob_len)) != 0) {
- kfree(ascii_buf);
+ kzfree(ascii_buf);
return -EFAULT;
}
- kfree(ascii_buf);
+ kzfree(ascii_buf);
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)
{
- struct trusted_key_payload *p = key->payload.data[0];
-
- if (!p)
- return;
- memset(p->key, 0, p->key_len);
- kfree(key->payload.data[0]);
+ kzfree(key->payload.data[0]);
}
struct key_type key_type_trusted = {
diff --git a/security/keys/user_defined.c b/security/keys/user_defined.c
index 26605134f17a..3d8c68eba516 100644
--- a/security/keys/user_defined.c
+++ b/security/keys/user_defined.c
@@ -86,10 +86,18 @@ EXPORT_SYMBOL_GPL(user_preparse);
*/
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);
+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
* - 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;
if (zap)
- kfree_rcu(zap, rcu);
+ call_rcu(&zap->rcu, user_free_payload_rcu);
return ret;
}
EXPORT_SYMBOL_GPL(user_update);
@@ -130,7 +138,7 @@ void user_revoke(struct key *key)
if (upayload) {
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];
- kfree(upayload);
+ kzfree(upayload);
}
EXPORT_SYMBOL_GPL(user_destroy);