Re: [PATCH 04/15] libceph: introduce ceph_crypt() for in-place en/decryption

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, 12 Dec 2016, Ilya Dryomov wrote:
> Starting with 4.9, kernel stacks may be vmalloced and therefore not
> guaranteed to be physically contiguous; the new CONFIG_VMAP_STACK
> option is enabled by default on x86.  This makes it invalid to use
> on-stack buffers with the crypto scatterlist API, as sg_set_buf()
> expects a logical address and won't work with vmalloced addresses.
> 
> There isn't a different (e.g. kvec-based) crypto API we could switch
> net/ceph/crypto.c to and the current scatterlist.h API isn't getting
> updated to accommodate this use case.  Allocating a new header and
> padding for each operation is a non-starter, so do the en/decryption
> in-place on a single pre-assembled (header + data + padding) heap
> buffer.  This is explicitly supported by the crypto API:
> 
>     "... the caller may provide the same scatter/gather list for the
>      plaintext and cipher text. After the completion of the cipher
>      operation, the plaintext data is replaced with the ciphertext data
>      in case of an encryption and vice versa for a decryption."
> 
> Signed-off-by: Ilya Dryomov <idryomov@xxxxxxxxx>
> ---
>  net/ceph/crypto.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  net/ceph/crypto.h |  2 ++
>  2 files changed, 89 insertions(+)
> 
> diff --git a/net/ceph/crypto.c b/net/ceph/crypto.c
> index db2847ac5f12..32099c5c4c75 100644
> --- a/net/ceph/crypto.c
> +++ b/net/ceph/crypto.c
> @@ -526,6 +526,93 @@ int ceph_encrypt2(struct ceph_crypto_key *secret, void *dst, size_t *dst_len,
>  	}
>  }
>  
> +static int ceph_aes_crypt(const struct ceph_crypto_key *key, bool encrypt,
> +			  void *buf, int buf_len, int in_len, int *pout_len)
> +{
> +	struct crypto_skcipher *tfm = ceph_crypto_alloc_cipher();
> +	SKCIPHER_REQUEST_ON_STACK(req, tfm);
> +	struct sg_table sgt;
> +	struct scatterlist prealloc_sg;
> +	char iv[AES_BLOCK_SIZE];
> +	int pad_byte = AES_BLOCK_SIZE - (in_len & (AES_BLOCK_SIZE - 1));

nit: pad_bytes?

> +	int crypt_len = encrypt ? in_len + pad_byte : in_len;
> +	int ret;
> +
> +	if (IS_ERR(tfm))
> +		return PTR_ERR(tfm);
> +
> +	WARN_ON(crypt_len > buf_len);
> +	if (encrypt)
> +		memset(buf + in_len, pad_byte, pad_byte);
> +	ret = setup_sgtable(&sgt, &prealloc_sg, buf, crypt_len);
> +	if (ret)
> +		goto out_tfm;
> +
> +	crypto_skcipher_setkey((void *)tfm, key->key, key->len);
> +	memcpy(iv, aes_iv, AES_BLOCK_SIZE);
> +
> +	skcipher_request_set_tfm(req, tfm);
> +	skcipher_request_set_callback(req, 0, NULL, NULL);
> +	skcipher_request_set_crypt(req, sgt.sgl, sgt.sgl, crypt_len, iv);
> +
> +	/*
> +	print_hex_dump(KERN_ERR, "key: ", DUMP_PREFIX_NONE, 16, 1,
> +		       key->key, key->len, 1);
> +	print_hex_dump(KERN_ERR, " in: ", DUMP_PREFIX_NONE, 16, 1,
> +		       buf, crypt_len, 1);
> +	*/
> +	if (encrypt)
> +		ret = crypto_skcipher_encrypt(req);
> +	else
> +		ret = crypto_skcipher_decrypt(req);
> +	skcipher_request_zero(req);
> +	if (ret) {
> +		pr_err("%s %scrypt failed: %d\n", __func__,
> +		       encrypt ? "en" : "de", ret);
> +		goto out_sgt;
> +	}
> +	/*
> +	print_hex_dump(KERN_ERR, "out: ", DUMP_PREFIX_NONE, 16, 1,
> +		       buf, crypt_len, 1);
> +	*/
> +
> +	if (encrypt) {
> +		*pout_len = crypt_len;
> +	} else {
> +		pad_byte = *(char *)(buf + in_len - 1);
> +		if (pad_byte > 0 && pad_byte <= AES_BLOCK_SIZE &&
> +		    in_len >= pad_byte) {
> +			*pout_len = in_len - pad_byte;
> +		} else {
> +			pr_err("%s got bad padding %d on in_len %d\n",
> +			       __func__, pad_byte, in_len);
> +			ret = -EPERM;
> +			goto out_sgt;
> +		}
> +	}
> +
> +out_sgt:
> +	teardown_sgtable(&sgt);
> +out_tfm:
> +	crypto_free_skcipher(tfm);
> +	return ret;
> +}
> +
> +int ceph_crypt(const struct ceph_crypto_key *key, bool encrypt,
> +	       void *buf, int buf_len, int in_len, int *pout_len)
> +{
> +	switch (key->type) {
> +	case CEPH_CRYPTO_NONE:
> +		*pout_len = in_len;
> +		return 0;
> +	case CEPH_CRYPTO_AES:
> +		return ceph_aes_crypt(key, encrypt, buf, buf_len, in_len,
> +				      pout_len);
> +	default:
> +		return -ENOTSUPP;
> +	}
> +}
> +
>  static int ceph_key_preparse(struct key_preparsed_payload *prep)
>  {
>  	struct ceph_crypto_key *ckey;
> diff --git a/net/ceph/crypto.h b/net/ceph/crypto.h
> index 2e9cab09f37b..73da34e8c62e 100644
> --- a/net/ceph/crypto.h
> +++ b/net/ceph/crypto.h
> @@ -43,6 +43,8 @@ int ceph_encrypt2(struct ceph_crypto_key *secret,
>  		  void *dst, size_t *dst_len,
>  		  const void *src1, size_t src1_len,
>  		  const void *src2, size_t src2_len);
> +int ceph_crypt(const struct ceph_crypto_key *key, bool encrypt,
> +	       void *buf, int buf_len, int in_len, int *pout_len);
>  int ceph_crypto_init(void);
>  void ceph_crypto_shutdown(void);
>  
> -- 
> 2.4.3
> 
> --
> To unsubscribe from this list: send the line "unsubscribe ceph-devel" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
> 
--
To unsubscribe from this list: send the line "unsubscribe ceph-devel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [CEPH Users]     [Ceph Large]     [Information on CEPH]     [Linux BTRFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]
  Powered by Linux