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