On 14 April 2017 at 00:04, Abed Kamaluddin <[email protected]> wrote:
> crypto: algif_compression - User-space interface for compression
>
> This patch adds af_alg plugin for compression algorithms of type scomp/acomp
> registered to the kernel crypto layer.
>
> The user needs to set operation (compression/decompression) as a control
> message to sendmsg, identical to selecting the cipher operation type in case
> of
> ciphers. Once a sendmsg call occurs, no further writes can be made to the
> socket until all previous data has been processed and read. Therefore the
> interface only supports one request at a time.
>
> The interface is completely synchronous; all operations are carried out in
> recvmsg and will complete prior to the system call returning.
>
> The sendmsg and recvmsg interface supports directly reading/writing to
> user-space without additional copying, i.e., the kernel crypto interface will
> receive the user-space address as its input/output SG list. The scomp
> interface
> or crypto drivers may copy the data as required.
>
> Signed-off-by: Abed Kamaluddin <[email protected]>
> Signed-off-by: Mahipal Challa <[email protected]>
>
> ---
> crypto/Kconfig | 11 ++
> crypto/Makefile | 1 +
> crypto/algif_compression.c | 272
> ++++++++++++++++++++++++++++++++++++++++++++
> include/uapi/linux/if_alg.h | 2 +
> 4 files changed, 286 insertions(+)
>
> diff --git a/crypto/Kconfig b/crypto/Kconfig
> index f37e9cc..13b03ba 100644
> --- a/crypto/Kconfig
> +++ b/crypto/Kconfig
> @@ -1741,6 +1741,17 @@ config CRYPTO_USER_API_AEAD
> This option enables the user-spaces interface for AEAD
> cipher algorithms.
>
> +config CRYPTO_USER_API_COMPRESSION
> + tristate "User-space interface for compression algorithms"
> + depends on NET
> + select CRYPTO_ACOMP
> + select CRYPTO_USER_API
> + help
> + This option enables the user-space interface for compression
> + algorithms. Enable this option for access to compression algorithms
> + of type scomp/acomp exported by the kernel crypto layer through
> + AF_ALG interface.
> +
> config CRYPTO_HASH_INFO
> bool
>
> diff --git a/crypto/Makefile b/crypto/Makefile
> index 8a44057..1469e06 100644
> --- a/crypto/Makefile
> +++ b/crypto/Makefile
> @@ -134,6 +134,7 @@ obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o
> obj-$(CONFIG_CRYPTO_GHASH) += ghash-generic.o
> obj-$(CONFIG_CRYPTO_USER_API) += af_alg.o
> obj-$(CONFIG_CRYPTO_USER_API_HASH) += algif_hash.o
> +obj-$(CONFIG_CRYPTO_USER_API_COMPRESSION) += algif_compression.o
> obj-$(CONFIG_CRYPTO_USER_API_SKCIPHER) += algif_skcipher.o
> obj-$(CONFIG_CRYPTO_USER_API_RNG) += algif_rng.o
> obj-$(CONFIG_CRYPTO_USER_API_AEAD) += algif_aead.o
> diff --git a/crypto/algif_compression.c b/crypto/algif_compression.c
> new file mode 100644
> index 0000000..0ba6d1e
> --- /dev/null
> +++ b/crypto/algif_compression.c
> @@ -0,0 +1,272 @@
> +/*
> + * algif_compression: User-space interface for COMPRESSION algorithms
> + *
> + * This file provides user-space API support for compression algorithms
> + * registered through the kernel crypto layer.
> + *
> + * Copyright (C) 2017 Cavium, Inc.
> + *
> + * Original Authors: Abed Kamaluddin <[email protected]>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the Free
> + * Software Foundation; either version 2 of the License, or (at your option)
> + * any later version.
> + */
> +
> +#include <crypto/acompress.h>
> +#include <crypto/if_alg.h>
> +#include <linux/crypto.h>
> +#include <linux/init.h>
> +#include <linux/kernel.h>
> +#include <linux/mm.h>
> +#include <linux/module.h>
> +#include <linux/net.h>
> +#include <net/sock.h>
> +#include <linux/scatterlist.h>
> +
> +/* scomp scratch is currently 128KB */
> +#define COMP_BUFFER_SIZE 65535
> +
> +struct comp_ctx {
> + struct af_alg_sgl tsgl;
> + struct af_alg_sgl rsgl;
> + struct af_alg_completion completion;
> + unsigned int clen;
> + unsigned int slen;
> + unsigned int dlen;
> + bool comp;
> + bool used;
> + struct acomp_req *acomp_req;
> +};
Is it necessary to have 3 len fields viz clen, slen, dlen? Please add
a comment indicating their purpose.
> +struct comp_tfm {
> + struct crypto_acomp *acomp;
> +};
> +
> +static int comp_sendmsg(struct socket *sock, struct msghdr *msg,
> + size_t ignored)
> +{
> + struct sock *sk = sock->sk;
> + struct alg_sock *ask = alg_sk(sk);
> + struct comp_ctx *ctx = ask->private;
> + struct af_alg_control con = {};
> + int limit = COMP_BUFFER_SIZE;
> + int len;
> + int err = -EINVAL;
> +
> + if (msg->msg_controllen) {
> + err = af_alg_cmsg_send(msg, &con);
> + if (err)
> + return err;
> +
> + switch (con.op) {
> + case ALG_OP_COMPRESS:
> + ctx->comp = 1;
> + break;
> +
> + case ALG_OP_DECOMPRESS:
> + ctx->comp = 0;
> + break;
> +
> + default:
> + return -EINVAL;
> + }
> + }
> +
> + lock_sock(sk);
> +
> + /* One request at a time supported, data submitted for comp/decomp
> will
> + * be processed at subsequent recvmsg
> + */
> + if (ctx->used) {
> + err = -EAGAIN;
> + goto unlock;
> + }
> +
> + len = msg_data_left(msg);
> +
> + if (len > limit)
> + len = limit;
> +
> + len = af_alg_make_sg(&ctx->tsgl, &msg->msg_iter, len);
> +
> + if (len < 0) {
> + err = len;
> + goto unlock;
> + }
> +
> + ctx->slen = len;
> + ctx->used = 1;
> +
> +unlock:
> + release_sock(sk);
> +
> + return err ?: len;
> +}
> +
> +static int comp_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
> + int flags)
> +{
> + struct sock *sk = sock->sk;
> + struct alg_sock *ask = alg_sk(sk);
> + struct comp_ctx *ctx = ask->private;
> + int rlen = ctx->dlen;
> + int err;
> +
> + if (len > rlen)
> + len = rlen;
> +
> + lock_sock(sk);
> +
> + if (!ctx->used) {
> + err = -EAGAIN;
> + goto unlock;
> + }
> +
> + len = af_alg_make_sg(&ctx->rsgl, &msg->msg_iter, len);
> + if (len < 0) {
> + err = len;
> + goto unlock;
> + }
> +
> + acomp_request_set_params(ctx->acomp_req, ctx->tsgl.sg, ctx->rsgl.sg,
> + ctx->slen, len);
> +
> + /* Synchronous completion of comp/decomp requests */
> + err = af_alg_wait_for_completion(
> + ctx->comp ?
> + crypto_acomp_compress(ctx->acomp_req) :
> + crypto_acomp_decompress(ctx->acomp_req),
> + &ctx->completion);
> +
> + /* Add acomp req wrapper for dlen */
> + len = (ctx->acomp_req)->dlen;
> +
> + af_alg_free_sg(&ctx->tsgl);
> + af_alg_free_sg(&ctx->rsgl);
> +
> +unlock:
> + ctx->used = 0;
> + release_sock(sk);
> +
> + return err ?: len;
> +}
> +
> +static struct proto_ops algif_comp_ops = {
> + .family = PF_ALG,
> +
> + .connect = sock_no_connect,
> + .socketpair = sock_no_socketpair,
> + .getname = sock_no_getname,
> + .ioctl = sock_no_ioctl,
> + .listen = sock_no_listen,
> + .shutdown = sock_no_shutdown,
> + .getsockopt = sock_no_getsockopt,
> + .mmap = sock_no_mmap,
> + .bind = sock_no_bind,
> + .setsockopt = sock_no_setsockopt,
> + .poll = sock_no_poll,
> +
> + .release = af_alg_release,
> + .sendmsg = comp_sendmsg,
> + .recvmsg = comp_recvmsg,
> + .sendpage = sock_no_sendpage,
> + .accept = sock_no_accept,
> +};
> +
> +static void *comp_bind(const char *name, u32 type, u32 mask)
> +{
> + struct comp_tfm *tfm;
> + struct crypto_acomp *acomp;
> +
> + tfm = kzalloc(sizeof(*tfm), GFP_KERNEL);
> + if (!tfm)
> + return ERR_PTR(-ENOMEM);
> +
> + acomp = crypto_alloc_acomp(name, type, mask);
> + if (IS_ERR_OR_NULL(acomp)) {
> + kfree(tfm);
> + return ERR_PTR(-ENOMEM);
> + }
> + tfm->acomp = acomp;
> +
> + return tfm;
> +}
> +
> +static void comp_release(void *private)
> +{
> + struct comp_tfm *tfm = private;
> +
> + crypto_free_acomp(tfm->acomp);
> + kfree(tfm);
> +}
> +
> +static void comp_sock_destruct(struct sock *sk)
> +{
> + struct alg_sock *ask = alg_sk(sk);
> + struct comp_ctx *ctx = ask->private;
> +
> + acomp_request_free(ctx->acomp_req);
> + sock_kfree_s(sk, ctx, ctx->clen);
> + af_alg_release_parent(sk);
> +}
> +
> +static int comp_accept_parent(void *private, struct sock *sk)
> +{
> + struct comp_ctx *ctx;
> + struct alg_sock *ask = alg_sk(sk);
> + struct comp_tfm *tfm = private;
> + struct crypto_acomp *acomp = tfm->acomp;
> + unsigned int len = sizeof(*ctx);
> +
> + ctx = sock_kmalloc(sk, len, GFP_KERNEL);
> + if (!ctx)
> + return -ENOMEM;
> +
> + ctx->used = 0;
> + ctx->clen = len;
> + ctx->dlen = COMP_BUFFER_SIZE;
> + ctx->slen = COMP_BUFFER_SIZE;
> +
> + af_alg_init_completion(&ctx->completion);
> +
> + ctx->acomp_req = acomp_request_alloc(acomp);
> + if (!ctx->acomp_req) {
> + sock_kfree_s(sk, ctx, ctx->clen);
> + return -ENOMEM;
> + }
> +
> + acomp_request_set_callback(ctx->acomp_req, CRYPTO_TFM_REQ_MAY_BACKLOG,
> + af_alg_complete, &ctx->completion);
> +
> + ask->private = ctx;
> + sk->sk_destruct = comp_sock_destruct;
> +
> + return 0;
> +}
> +
> +static const struct af_alg_type algif_type_comp = {
> + .bind = comp_bind,
> + .release = comp_release,
> + .accept = comp_accept_parent,
> + .ops = &algif_comp_ops,
> + .name = "compression",
> + .owner = THIS_MODULE
> +};
> +
> +static int __init algif_comp_init(void)
> +{
> + return af_alg_register_type(&algif_type_comp);
> +}
> +
> +static void __exit algif_comp_exit(void)
> +{
> + int err = af_alg_unregister_type(&algif_type_comp);
> +
> + BUG_ON(err);
> +}
> +
> +module_init(algif_comp_init);
> +module_exit(algif_comp_exit);
> +MODULE_LICENSE("GPL");
> diff --git a/include/uapi/linux/if_alg.h b/include/uapi/linux/if_alg.h
> index f2acd2f..5cca9eb 100644
> --- a/include/uapi/linux/if_alg.h
> +++ b/include/uapi/linux/if_alg.h
> @@ -38,5 +38,7 @@ struct af_alg_iv {
> /* Operations */
> #define ALG_OP_DECRYPT 0
> #define ALG_OP_ENCRYPT 1
> +#define ALG_OP_DECOMPRESS 0
> +#define ALG_OP_COMPRESS 1
>
> #endif /* _LINUX_IF_ALG_H */
> --
> 2.7.4
>
Regards,
PrasannaKumar