linux/crypto/algif_skcipher.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * algif_skcipher: User-space interface for skcipher algorithms
   4 *
   5 * This file provides the user-space API for symmetric key ciphers.
   6 *
   7 * Copyright (c) 2010 Herbert Xu <herbert@gondor.apana.org.au>
   8 *
   9 * The following concept of the memory management is used:
  10 *
  11 * The kernel maintains two SGLs, the TX SGL and the RX SGL. The TX SGL is
  12 * filled by user space with the data submitted via sendpage/sendmsg. Filling
  13 * up the TX SGL does not cause a crypto operation -- the data will only be
  14 * tracked by the kernel. Upon receipt of one recvmsg call, the caller must
  15 * provide a buffer which is tracked with the RX SGL.
  16 *
  17 * During the processing of the recvmsg operation, the cipher request is
  18 * allocated and prepared. As part of the recvmsg operation, the processed
  19 * TX buffers are extracted from the TX SGL into a separate SGL.
  20 *
  21 * After the completion of the crypto operation, the RX SGL and the cipher
  22 * request is released. The extracted TX SGL parts are released together with
  23 * the RX SGL release.
  24 */
  25
  26#include <crypto/scatterwalk.h>
  27#include <crypto/skcipher.h>
  28#include <crypto/if_alg.h>
  29#include <linux/init.h>
  30#include <linux/list.h>
  31#include <linux/kernel.h>
  32#include <linux/mm.h>
  33#include <linux/module.h>
  34#include <linux/net.h>
  35#include <net/sock.h>
  36
  37static int skcipher_sendmsg(struct socket *sock, struct msghdr *msg,
  38                            size_t size)
  39{
  40        struct sock *sk = sock->sk;
  41        struct alg_sock *ask = alg_sk(sk);
  42        struct sock *psk = ask->parent;
  43        struct alg_sock *pask = alg_sk(psk);
  44        struct crypto_skcipher *tfm = pask->private;
  45        unsigned ivsize = crypto_skcipher_ivsize(tfm);
  46
  47        return af_alg_sendmsg(sock, msg, size, ivsize);
  48}
  49
  50static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg,
  51                             size_t ignored, int flags)
  52{
  53        struct sock *sk = sock->sk;
  54        struct alg_sock *ask = alg_sk(sk);
  55        struct sock *psk = ask->parent;
  56        struct alg_sock *pask = alg_sk(psk);
  57        struct af_alg_ctx *ctx = ask->private;
  58        struct crypto_skcipher *tfm = pask->private;
  59        unsigned int bs = crypto_skcipher_chunksize(tfm);
  60        struct af_alg_async_req *areq;
  61        int err = 0;
  62        size_t len = 0;
  63
  64        if (!ctx->init || (ctx->more && ctx->used < bs)) {
  65                err = af_alg_wait_for_data(sk, flags, bs);
  66                if (err)
  67                        return err;
  68        }
  69
  70        /* Allocate cipher request for current operation. */
  71        areq = af_alg_alloc_areq(sk, sizeof(struct af_alg_async_req) +
  72                                     crypto_skcipher_reqsize(tfm));
  73        if (IS_ERR(areq))
  74                return PTR_ERR(areq);
  75
  76        /* convert iovecs of output buffers into RX SGL */
  77        err = af_alg_get_rsgl(sk, msg, flags, areq, ctx->used, &len);
  78        if (err)
  79                goto free;
  80
  81        /*
  82         * If more buffers are to be expected to be processed, process only
  83         * full block size buffers.
  84         */
  85        if (ctx->more || len < ctx->used)
  86                len -= len % bs;
  87
  88        /*
  89         * Create a per request TX SGL for this request which tracks the
  90         * SG entries from the global TX SGL.
  91         */
  92        areq->tsgl_entries = af_alg_count_tsgl(sk, len, 0);
  93        if (!areq->tsgl_entries)
  94                areq->tsgl_entries = 1;
  95        areq->tsgl = sock_kmalloc(sk, array_size(sizeof(*areq->tsgl),
  96                                                 areq->tsgl_entries),
  97                                  GFP_KERNEL);
  98        if (!areq->tsgl) {
  99                err = -ENOMEM;
 100                goto free;
 101        }
 102        sg_init_table(areq->tsgl, areq->tsgl_entries);
 103        af_alg_pull_tsgl(sk, len, areq->tsgl, 0);
 104
 105        /* Initialize the crypto operation */
 106        skcipher_request_set_tfm(&areq->cra_u.skcipher_req, tfm);
 107        skcipher_request_set_crypt(&areq->cra_u.skcipher_req, areq->tsgl,
 108                                   areq->first_rsgl.sgl.sg, len, ctx->iv);
 109
 110        if (msg->msg_iocb && !is_sync_kiocb(msg->msg_iocb)) {
 111                /* AIO operation */
 112                sock_hold(sk);
 113                areq->iocb = msg->msg_iocb;
 114
 115                /* Remember output size that will be generated. */
 116                areq->outlen = len;
 117
 118                skcipher_request_set_callback(&areq->cra_u.skcipher_req,
 119                                              CRYPTO_TFM_REQ_MAY_SLEEP,
 120                                              af_alg_async_cb, areq);
 121                err = ctx->enc ?
 122                        crypto_skcipher_encrypt(&areq->cra_u.skcipher_req) :
 123                        crypto_skcipher_decrypt(&areq->cra_u.skcipher_req);
 124
 125                /* AIO operation in progress */
 126                if (err == -EINPROGRESS)
 127                        return -EIOCBQUEUED;
 128
 129                sock_put(sk);
 130        } else {
 131                /* Synchronous operation */
 132                skcipher_request_set_callback(&areq->cra_u.skcipher_req,
 133                                              CRYPTO_TFM_REQ_MAY_SLEEP |
 134                                              CRYPTO_TFM_REQ_MAY_BACKLOG,
 135                                              crypto_req_done, &ctx->wait);
 136                err = crypto_wait_req(ctx->enc ?
 137                        crypto_skcipher_encrypt(&areq->cra_u.skcipher_req) :
 138                        crypto_skcipher_decrypt(&areq->cra_u.skcipher_req),
 139                                                 &ctx->wait);
 140        }
 141
 142
 143free:
 144        af_alg_free_resources(areq);
 145
 146        return err ? err : len;
 147}
 148
 149static int skcipher_recvmsg(struct socket *sock, struct msghdr *msg,
 150                            size_t ignored, int flags)
 151{
 152        struct sock *sk = sock->sk;
 153        int ret = 0;
 154
 155        lock_sock(sk);
 156        while (msg_data_left(msg)) {
 157                int err = _skcipher_recvmsg(sock, msg, ignored, flags);
 158
 159                /*
 160                 * This error covers -EIOCBQUEUED which implies that we can
 161                 * only handle one AIO request. If the caller wants to have
 162                 * multiple AIO requests in parallel, he must make multiple
 163                 * separate AIO calls.
 164                 *
 165                 * Also return the error if no data has been processed so far.
 166                 */
 167                if (err <= 0) {
 168                        if (err == -EIOCBQUEUED || !ret)
 169                                ret = err;
 170                        goto out;
 171                }
 172
 173                ret += err;
 174        }
 175
 176out:
 177        af_alg_wmem_wakeup(sk);
 178        release_sock(sk);
 179        return ret;
 180}
 181
 182static struct proto_ops algif_skcipher_ops = {
 183        .family         =       PF_ALG,
 184
 185        .connect        =       sock_no_connect,
 186        .socketpair     =       sock_no_socketpair,
 187        .getname        =       sock_no_getname,
 188        .ioctl          =       sock_no_ioctl,
 189        .listen         =       sock_no_listen,
 190        .shutdown       =       sock_no_shutdown,
 191        .mmap           =       sock_no_mmap,
 192        .bind           =       sock_no_bind,
 193        .accept         =       sock_no_accept,
 194
 195        .release        =       af_alg_release,
 196        .sendmsg        =       skcipher_sendmsg,
 197        .sendpage       =       af_alg_sendpage,
 198        .recvmsg        =       skcipher_recvmsg,
 199        .poll           =       af_alg_poll,
 200};
 201
 202static int skcipher_check_key(struct socket *sock)
 203{
 204        int err = 0;
 205        struct sock *psk;
 206        struct alg_sock *pask;
 207        struct crypto_skcipher *tfm;
 208        struct sock *sk = sock->sk;
 209        struct alg_sock *ask = alg_sk(sk);
 210
 211        lock_sock(sk);
 212        if (!atomic_read(&ask->nokey_refcnt))
 213                goto unlock_child;
 214
 215        psk = ask->parent;
 216        pask = alg_sk(ask->parent);
 217        tfm = pask->private;
 218
 219        err = -ENOKEY;
 220        lock_sock_nested(psk, SINGLE_DEPTH_NESTING);
 221        if (crypto_skcipher_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
 222                goto unlock;
 223
 224        atomic_dec(&pask->nokey_refcnt);
 225        atomic_set(&ask->nokey_refcnt, 0);
 226
 227        err = 0;
 228
 229unlock:
 230        release_sock(psk);
 231unlock_child:
 232        release_sock(sk);
 233
 234        return err;
 235}
 236
 237static int skcipher_sendmsg_nokey(struct socket *sock, struct msghdr *msg,
 238                                  size_t size)
 239{
 240        int err;
 241
 242        err = skcipher_check_key(sock);
 243        if (err)
 244                return err;
 245
 246        return skcipher_sendmsg(sock, msg, size);
 247}
 248
 249static ssize_t skcipher_sendpage_nokey(struct socket *sock, struct page *page,
 250                                       int offset, size_t size, int flags)
 251{
 252        int err;
 253
 254        err = skcipher_check_key(sock);
 255        if (err)
 256                return err;
 257
 258        return af_alg_sendpage(sock, page, offset, size, flags);
 259}
 260
 261static int skcipher_recvmsg_nokey(struct socket *sock, struct msghdr *msg,
 262                                  size_t ignored, int flags)
 263{
 264        int err;
 265
 266        err = skcipher_check_key(sock);
 267        if (err)
 268                return err;
 269
 270        return skcipher_recvmsg(sock, msg, ignored, flags);
 271}
 272
 273static struct proto_ops algif_skcipher_ops_nokey = {
 274        .family         =       PF_ALG,
 275
 276        .connect        =       sock_no_connect,
 277        .socketpair     =       sock_no_socketpair,
 278        .getname        =       sock_no_getname,
 279        .ioctl          =       sock_no_ioctl,
 280        .listen         =       sock_no_listen,
 281        .shutdown       =       sock_no_shutdown,
 282        .mmap           =       sock_no_mmap,
 283        .bind           =       sock_no_bind,
 284        .accept         =       sock_no_accept,
 285
 286        .release        =       af_alg_release,
 287        .sendmsg        =       skcipher_sendmsg_nokey,
 288        .sendpage       =       skcipher_sendpage_nokey,
 289        .recvmsg        =       skcipher_recvmsg_nokey,
 290        .poll           =       af_alg_poll,
 291};
 292
 293static void *skcipher_bind(const char *name, u32 type, u32 mask)
 294{
 295        return crypto_alloc_skcipher(name, type, mask);
 296}
 297
 298static void skcipher_release(void *private)
 299{
 300        crypto_free_skcipher(private);
 301}
 302
 303static int skcipher_setkey(void *private, const u8 *key, unsigned int keylen)
 304{
 305        return crypto_skcipher_setkey(private, key, keylen);
 306}
 307
 308static void skcipher_sock_destruct(struct sock *sk)
 309{
 310        struct alg_sock *ask = alg_sk(sk);
 311        struct af_alg_ctx *ctx = ask->private;
 312        struct sock *psk = ask->parent;
 313        struct alg_sock *pask = alg_sk(psk);
 314        struct crypto_skcipher *tfm = pask->private;
 315
 316        af_alg_pull_tsgl(sk, ctx->used, NULL, 0);
 317        sock_kzfree_s(sk, ctx->iv, crypto_skcipher_ivsize(tfm));
 318        sock_kfree_s(sk, ctx, ctx->len);
 319        af_alg_release_parent(sk);
 320}
 321
 322static int skcipher_accept_parent_nokey(void *private, struct sock *sk)
 323{
 324        struct af_alg_ctx *ctx;
 325        struct alg_sock *ask = alg_sk(sk);
 326        struct crypto_skcipher *tfm = private;
 327        unsigned int len = sizeof(*ctx);
 328
 329        ctx = sock_kmalloc(sk, len, GFP_KERNEL);
 330        if (!ctx)
 331                return -ENOMEM;
 332        memset(ctx, 0, len);
 333
 334        ctx->iv = sock_kmalloc(sk, crypto_skcipher_ivsize(tfm),
 335                               GFP_KERNEL);
 336        if (!ctx->iv) {
 337                sock_kfree_s(sk, ctx, len);
 338                return -ENOMEM;
 339        }
 340        memset(ctx->iv, 0, crypto_skcipher_ivsize(tfm));
 341
 342        INIT_LIST_HEAD(&ctx->tsgl_list);
 343        ctx->len = len;
 344        crypto_init_wait(&ctx->wait);
 345
 346        ask->private = ctx;
 347
 348        sk->sk_destruct = skcipher_sock_destruct;
 349
 350        return 0;
 351}
 352
 353static int skcipher_accept_parent(void *private, struct sock *sk)
 354{
 355        struct crypto_skcipher *tfm = private;
 356
 357        if (crypto_skcipher_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
 358                return -ENOKEY;
 359
 360        return skcipher_accept_parent_nokey(private, sk);
 361}
 362
 363static const struct af_alg_type algif_type_skcipher = {
 364        .bind           =       skcipher_bind,
 365        .release        =       skcipher_release,
 366        .setkey         =       skcipher_setkey,
 367        .accept         =       skcipher_accept_parent,
 368        .accept_nokey   =       skcipher_accept_parent_nokey,
 369        .ops            =       &algif_skcipher_ops,
 370        .ops_nokey      =       &algif_skcipher_ops_nokey,
 371        .name           =       "skcipher",
 372        .owner          =       THIS_MODULE
 373};
 374
 375static int __init algif_skcipher_init(void)
 376{
 377        return af_alg_register_type(&algif_type_skcipher);
 378}
 379
 380static void __exit algif_skcipher_exit(void)
 381{
 382        int err = af_alg_unregister_type(&algif_type_skcipher);
 383        BUG_ON(err);
 384}
 385
 386module_init(algif_skcipher_init);
 387module_exit(algif_skcipher_exit);
 388MODULE_LICENSE("GPL");
 389
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.