diff options
Diffstat (limited to 'security/keys')
| -rw-r--r-- | security/keys/big_key.c | 110 | ||||
| -rw-r--r-- | security/keys/keyring.c | 7 | ||||
| -rw-r--r-- | security/keys/trusted.c | 35 | 
3 files changed, 104 insertions, 48 deletions
| diff --git a/security/keys/big_key.c b/security/keys/big_key.c index 929e14978c42..fa728f662a6f 100644 --- a/security/keys/big_key.c +++ b/security/keys/big_key.c @@ -22,6 +22,13 @@  #include <keys/big_key-type.h>  #include <crypto/aead.h> +struct big_key_buf { +	unsigned int		nr_pages; +	void			*virt; +	struct scatterlist	*sg; +	struct page		*pages[]; +}; +  /*   * Layout of key payload words.   */ @@ -91,10 +98,9 @@ static DEFINE_MUTEX(big_key_aead_lock);  /*   * Encrypt/decrypt big_key data   */ -static int big_key_crypt(enum big_key_op op, u8 *data, size_t datalen, u8 *key) +static int big_key_crypt(enum big_key_op op, struct big_key_buf *buf, size_t datalen, u8 *key)  {  	int ret; -	struct scatterlist sgio;  	struct aead_request *aead_req;  	/* We always use a zero nonce. The reason we can get away with this is  	 * because we're using a different randomly generated key for every @@ -109,8 +115,7 @@ static int big_key_crypt(enum big_key_op op, u8 *data, size_t datalen, u8 *key)  		return -ENOMEM;  	memset(zero_nonce, 0, sizeof(zero_nonce)); -	sg_init_one(&sgio, data, datalen + (op == BIG_KEY_ENC ? ENC_AUTHTAG_SIZE : 0)); -	aead_request_set_crypt(aead_req, &sgio, &sgio, datalen, zero_nonce); +	aead_request_set_crypt(aead_req, buf->sg, buf->sg, datalen, zero_nonce);  	aead_request_set_callback(aead_req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL);  	aead_request_set_ad(aead_req, 0); @@ -130,21 +135,81 @@ error:  }  /* + * Free up the buffer. + */ +static void big_key_free_buffer(struct big_key_buf *buf) +{ +	unsigned int i; + +	if (buf->virt) { +		memset(buf->virt, 0, buf->nr_pages * PAGE_SIZE); +		vunmap(buf->virt); +	} + +	for (i = 0; i < buf->nr_pages; i++) +		if (buf->pages[i]) +			__free_page(buf->pages[i]); + +	kfree(buf); +} + +/* + * Allocate a buffer consisting of a set of pages with a virtual mapping + * applied over them. + */ +static void *big_key_alloc_buffer(size_t len) +{ +	struct big_key_buf *buf; +	unsigned int npg = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; +	unsigned int i, l; + +	buf = kzalloc(sizeof(struct big_key_buf) + +		      sizeof(struct page) * npg + +		      sizeof(struct scatterlist) * npg, +		      GFP_KERNEL); +	if (!buf) +		return NULL; + +	buf->nr_pages = npg; +	buf->sg = (void *)(buf->pages + npg); +	sg_init_table(buf->sg, npg); + +	for (i = 0; i < buf->nr_pages; i++) { +		buf->pages[i] = alloc_page(GFP_KERNEL); +		if (!buf->pages[i]) +			goto nomem; + +		l = min_t(size_t, len, PAGE_SIZE); +		sg_set_page(&buf->sg[i], buf->pages[i], l, 0); +		len -= l; +	} + +	buf->virt = vmap(buf->pages, buf->nr_pages, VM_MAP, PAGE_KERNEL); +	if (!buf->virt) +		goto nomem; + +	return buf; + +nomem: +	big_key_free_buffer(buf); +	return NULL; +} + +/*   * Preparse a big key   */  int big_key_preparse(struct key_preparsed_payload *prep)  { +	struct big_key_buf *buf;  	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; +	size_t datalen = prep->datalen, enclen = datalen + ENC_AUTHTAG_SIZE;  	int ret; -	ret = -EINVAL;  	if (datalen <= 0 || datalen > 1024 * 1024 || !prep->data) -		goto error; +		return -EINVAL;  	/* Set an arbitrary quota */  	prep->quotalen = 16; @@ -157,13 +222,12 @@ int big_key_preparse(struct key_preparsed_payload *prep)  		 *  		 * File content is stored encrypted with randomly generated key.  		 */ -		size_t enclen = datalen + ENC_AUTHTAG_SIZE;  		loff_t pos = 0; -		data = kmalloc(enclen, GFP_KERNEL); -		if (!data) +		buf = big_key_alloc_buffer(enclen); +		if (!buf)  			return -ENOMEM; -		memcpy(data, prep->data, datalen); +		memcpy(buf->virt, prep->data, datalen);  		/* generate random key */  		enckey = kmalloc(ENC_KEY_SIZE, GFP_KERNEL); @@ -176,7 +240,7 @@ int big_key_preparse(struct key_preparsed_payload *prep)  			goto err_enckey;  		/* encrypt aligned data */ -		ret = big_key_crypt(BIG_KEY_ENC, data, datalen, enckey); +		ret = big_key_crypt(BIG_KEY_ENC, buf, datalen, enckey);  		if (ret)  			goto err_enckey; @@ -187,7 +251,7 @@ int big_key_preparse(struct key_preparsed_payload *prep)  			goto err_enckey;  		} -		written = kernel_write(file, data, enclen, &pos); +		written = kernel_write(file, buf->virt, enclen, &pos);  		if (written != enclen) {  			ret = written;  			if (written >= 0) @@ -202,7 +266,7 @@ int big_key_preparse(struct key_preparsed_payload *prep)  		*path = file->f_path;  		path_get(path);  		fput(file); -		kzfree(data); +		big_key_free_buffer(buf);  	} else {  		/* Just store the data in a buffer */  		void *data = kmalloc(datalen, GFP_KERNEL); @@ -220,7 +284,7 @@ err_fput:  err_enckey:  	kzfree(enckey);  error: -	kzfree(data); +	big_key_free_buffer(buf);  	return ret;  } @@ -298,15 +362,15 @@ long big_key_read(const struct key *key, char __user *buffer, size_t buflen)  		return datalen;  	if (datalen > BIG_KEY_FILE_THRESHOLD) { +		struct big_key_buf *buf;  		struct path *path = (struct path *)&key->payload.data[big_key_path];  		struct file *file; -		u8 *data;  		u8 *enckey = (u8 *)key->payload.data[big_key_data];  		size_t enclen = datalen + ENC_AUTHTAG_SIZE;  		loff_t pos = 0; -		data = kmalloc(enclen, GFP_KERNEL); -		if (!data) +		buf = big_key_alloc_buffer(enclen); +		if (!buf)  			return -ENOMEM;  		file = dentry_open(path, O_RDONLY, current_cred()); @@ -316,26 +380,26 @@ long big_key_read(const struct key *key, char __user *buffer, size_t buflen)  		}  		/* read file to kernel and decrypt */ -		ret = kernel_read(file, data, enclen, &pos); +		ret = kernel_read(file, buf->virt, enclen, &pos);  		if (ret >= 0 && ret != enclen) {  			ret = -EIO;  			goto err_fput;  		} -		ret = big_key_crypt(BIG_KEY_DEC, data, enclen, enckey); +		ret = big_key_crypt(BIG_KEY_DEC, buf, enclen, enckey);  		if (ret)  			goto err_fput;  		ret = datalen;  		/* copy decrypted data to user */ -		if (copy_to_user(buffer, data, datalen) != 0) +		if (copy_to_user(buffer, buf->virt, datalen) != 0)  			ret = -EFAULT;  err_fput:  		fput(file);  error: -		kzfree(data); +		big_key_free_buffer(buf);  	} else {  		ret = datalen;  		if (copy_to_user(buffer, key->payload.data[big_key_data], diff --git a/security/keys/keyring.c b/security/keys/keyring.c index d0bccebbd3b5..41bcf57e96f2 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c @@ -713,7 +713,6 @@ descend_to_keyring:  		 * doesn't contain any keyring pointers.  		 */  		shortcut = assoc_array_ptr_to_shortcut(ptr); -		smp_read_barrier_depends();  		if ((shortcut->index_key[0] & ASSOC_ARRAY_FAN_MASK) != 0)  			goto not_this_keyring; @@ -723,8 +722,6 @@ descend_to_keyring:  	}  	node = assoc_array_ptr_to_node(ptr); -	smp_read_barrier_depends(); -  	ptr = node->slots[0];  	if (!assoc_array_ptr_is_meta(ptr))  		goto begin_node; @@ -736,7 +733,6 @@ descend_to_node:  	kdebug("descend");  	if (assoc_array_ptr_is_shortcut(ptr)) {  		shortcut = assoc_array_ptr_to_shortcut(ptr); -		smp_read_barrier_depends();  		ptr = READ_ONCE(shortcut->next_node);  		BUG_ON(!assoc_array_ptr_is_node(ptr));  	} @@ -744,7 +740,6 @@ descend_to_node:  begin_node:  	kdebug("begin_node"); -	smp_read_barrier_depends();  	slot = 0;  ascend_to_node:  	/* Go through the slots in a node */ @@ -792,14 +787,12 @@ ascend_to_node:  	if (ptr && assoc_array_ptr_is_shortcut(ptr)) {  		shortcut = assoc_array_ptr_to_shortcut(ptr); -		smp_read_barrier_depends();  		ptr = READ_ONCE(shortcut->back_pointer);  		slot = shortcut->parent_slot;  	}  	if (!ptr)  		goto not_this_keyring;  	node = assoc_array_ptr_to_node(ptr); -	smp_read_barrier_depends();  	slot++;  	/* If we've ascended to the root (zero backpointer), we must have just diff --git a/security/keys/trusted.c b/security/keys/trusted.c index 98aa89ff7bfd..423776682025 100644 --- a/security/keys/trusted.c +++ b/security/keys/trusted.c @@ -355,13 +355,12 @@ out:   * For key specific tpm requests, we will generate and send our   * own TPM command packets using the drivers send function.   */ -static int trusted_tpm_send(const u32 chip_num, unsigned char *cmd, -			    size_t buflen) +static int trusted_tpm_send(unsigned char *cmd, size_t buflen)  {  	int rc;  	dump_tpm_buf(cmd); -	rc = tpm_send(chip_num, cmd, buflen); +	rc = tpm_send(NULL, cmd, buflen);  	dump_tpm_buf(cmd);  	if (rc > 0)  		/* Can't return positive return codes values to keyctl */ @@ -382,10 +381,10 @@ static int pcrlock(const int pcrnum)  	if (!capable(CAP_SYS_ADMIN))  		return -EPERM; -	ret = tpm_get_random(TPM_ANY_NUM, hash, SHA1_DIGEST_SIZE); +	ret = tpm_get_random(NULL, hash, SHA1_DIGEST_SIZE);  	if (ret != SHA1_DIGEST_SIZE)  		return ret; -	return tpm_pcr_extend(TPM_ANY_NUM, pcrnum, hash) ? -EINVAL : 0; +	return tpm_pcr_extend(NULL, pcrnum, hash) ? -EINVAL : 0;  }  /* @@ -398,7 +397,7 @@ static int osap(struct tpm_buf *tb, struct osapsess *s,  	unsigned char ononce[TPM_NONCE_SIZE];  	int ret; -	ret = tpm_get_random(TPM_ANY_NUM, ononce, TPM_NONCE_SIZE); +	ret = tpm_get_random(NULL, ononce, TPM_NONCE_SIZE);  	if (ret != TPM_NONCE_SIZE)  		return ret; @@ -410,7 +409,7 @@ static int osap(struct tpm_buf *tb, struct osapsess *s,  	store32(tb, handle);  	storebytes(tb, ononce, TPM_NONCE_SIZE); -	ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE); +	ret = trusted_tpm_send(tb->data, MAX_BUF_SIZE);  	if (ret < 0)  		return ret; @@ -434,7 +433,7 @@ static int oiap(struct tpm_buf *tb, uint32_t *handle, unsigned char *nonce)  	store16(tb, TPM_TAG_RQU_COMMAND);  	store32(tb, TPM_OIAP_SIZE);  	store32(tb, TPM_ORD_OIAP); -	ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE); +	ret = trusted_tpm_send(tb->data, MAX_BUF_SIZE);  	if (ret < 0)  		return ret; @@ -493,7 +492,7 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype,  	if (ret < 0)  		goto out; -	ret = tpm_get_random(TPM_ANY_NUM, td->nonceodd, TPM_NONCE_SIZE); +	ret = tpm_get_random(NULL, td->nonceodd, TPM_NONCE_SIZE);  	if (ret != TPM_NONCE_SIZE)  		goto out;  	ordinal = htonl(TPM_ORD_SEAL); @@ -542,7 +541,7 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype,  	store8(tb, cont);  	storebytes(tb, td->pubauth, SHA1_DIGEST_SIZE); -	ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE); +	ret = trusted_tpm_send(tb->data, MAX_BUF_SIZE);  	if (ret < 0)  		goto out; @@ -603,7 +602,7 @@ static int tpm_unseal(struct tpm_buf *tb,  	ordinal = htonl(TPM_ORD_UNSEAL);  	keyhndl = htonl(SRKHANDLE); -	ret = tpm_get_random(TPM_ANY_NUM, nonceodd, TPM_NONCE_SIZE); +	ret = tpm_get_random(NULL, nonceodd, TPM_NONCE_SIZE);  	if (ret != TPM_NONCE_SIZE) {  		pr_info("trusted_key: tpm_get_random failed (%d)\n", ret);  		return ret; @@ -635,7 +634,7 @@ static int tpm_unseal(struct tpm_buf *tb,  	store8(tb, cont);  	storebytes(tb, authdata2, SHA1_DIGEST_SIZE); -	ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE); +	ret = trusted_tpm_send(tb->data, MAX_BUF_SIZE);  	if (ret < 0) {  		pr_info("trusted_key: authhmac failed (%d)\n", ret);  		return ret; @@ -748,7 +747,7 @@ static int getoptions(char *c, struct trusted_key_payload *pay,  	int i;  	int tpm2; -	tpm2 = tpm_is_tpm2(TPM_ANY_NUM); +	tpm2 = tpm_is_tpm2(NULL);  	if (tpm2 < 0)  		return tpm2; @@ -917,7 +916,7 @@ static struct trusted_key_options *trusted_options_alloc(void)  	struct trusted_key_options *options;  	int tpm2; -	tpm2 = tpm_is_tpm2(TPM_ANY_NUM); +	tpm2 = tpm_is_tpm2(NULL);  	if (tpm2 < 0)  		return NULL; @@ -967,7 +966,7 @@ static int trusted_instantiate(struct key *key,  	size_t key_len;  	int tpm2; -	tpm2 = tpm_is_tpm2(TPM_ANY_NUM); +	tpm2 = tpm_is_tpm2(NULL);  	if (tpm2 < 0)  		return tpm2; @@ -1008,7 +1007,7 @@ static int trusted_instantiate(struct key *key,  	switch (key_cmd) {  	case Opt_load:  		if (tpm2) -			ret = tpm_unseal_trusted(TPM_ANY_NUM, payload, options); +			ret = tpm_unseal_trusted(NULL, payload, options);  		else  			ret = key_unseal(payload, options);  		dump_payload(payload); @@ -1018,13 +1017,13 @@ static int trusted_instantiate(struct key *key,  		break;  	case Opt_new:  		key_len = payload->key_len; -		ret = tpm_get_random(TPM_ANY_NUM, payload->key, key_len); +		ret = tpm_get_random(NULL, payload->key, key_len);  		if (ret != key_len) {  			pr_info("trusted_key: key_create failed (%d)\n", ret);  			goto out;  		}  		if (tpm2) -			ret = tpm_seal_trusted(TPM_ANY_NUM, payload, options); +			ret = tpm_seal_trusted(NULL, payload, options);  		else  			ret = key_seal(payload, options);  		if (ret < 0) |