linux/crypto/af_alg.c
<<
>>
Prefs
   1/*
   2 * af_alg: User-space algorithm interface
   3 *
   4 * This file provides the user-space API for algorithms.
   5 *
   6 * Copyright (c) 2010 Herbert Xu <herbert@gondor.apana.org.au>
   7 *
   8 * This program is free software; you can redistribute it and/or modify it
   9 * under the terms of the GNU General Public License as published by the Free
  10 * Software Foundation; either version 2 of the License, or (at your option)
  11 * any later version.
  12 *
  13 */
  14
  15#include <linux/atomic.h>
  16#include <crypto/if_alg.h>
  17#include <linux/crypto.h>
  18#include <linux/init.h>
  19#include <linux/kernel.h>
  20#include <linux/list.h>
  21#include <linux/module.h>
  22#include <linux/net.h>
  23#include <linux/rwsem.h>
  24#include <linux/security.h>
  25
  26struct alg_type_list {
  27        const struct af_alg_type *type;
  28        struct list_head list;
  29};
  30
  31static atomic_long_t alg_memory_allocated;
  32
  33static struct proto alg_proto = {
  34        .name                   = "ALG",
  35        .owner                  = THIS_MODULE,
  36        .memory_allocated       = &alg_memory_allocated,
  37        .obj_size               = sizeof(struct alg_sock),
  38};
  39
  40static LIST_HEAD(alg_types);
  41static DECLARE_RWSEM(alg_types_sem);
  42
  43static const struct af_alg_type *alg_get_type(const char *name)
  44{
  45        const struct af_alg_type *type = ERR_PTR(-ENOENT);
  46        struct alg_type_list *node;
  47
  48        down_read(&alg_types_sem);
  49        list_for_each_entry(node, &alg_types, list) {
  50                if (strcmp(node->type->name, name))
  51                        continue;
  52
  53                if (try_module_get(node->type->owner))
  54                        type = node->type;
  55                break;
  56        }
  57        up_read(&alg_types_sem);
  58
  59        return type;
  60}
  61
  62int af_alg_register_type(const struct af_alg_type *type)
  63{
  64        struct alg_type_list *node;
  65        int err = -EEXIST;
  66
  67        down_write(&alg_types_sem);
  68        list_for_each_entry(node, &alg_types, list) {
  69                if (!strcmp(node->type->name, type->name))
  70                        goto unlock;
  71        }
  72
  73        node = kmalloc(sizeof(*node), GFP_KERNEL);
  74        err = -ENOMEM;
  75        if (!node)
  76                goto unlock;
  77
  78        type->ops->owner = THIS_MODULE;
  79        node->type = type;
  80        list_add(&node->list, &alg_types);
  81        err = 0;
  82
  83unlock:
  84        up_write(&alg_types_sem);
  85
  86        return err;
  87}
  88EXPORT_SYMBOL_GPL(af_alg_register_type);
  89
  90int af_alg_unregister_type(const struct af_alg_type *type)
  91{
  92        struct alg_type_list *node;
  93        int err = -ENOENT;
  94
  95        down_write(&alg_types_sem);
  96        list_for_each_entry(node, &alg_types, list) {
  97                if (strcmp(node->type->name, type->name))
  98                        continue;
  99
 100                list_del(&node->list);
 101                kfree(node);
 102                err = 0;
 103                break;
 104        }
 105        up_write(&alg_types_sem);
 106
 107        return err;
 108}
 109EXPORT_SYMBOL_GPL(af_alg_unregister_type);
 110
 111static void alg_do_release(const struct af_alg_type *type, void *private)
 112{
 113        if (!type)
 114                return;
 115
 116        type->release(private);
 117        module_put(type->owner);
 118}
 119
 120int af_alg_release(struct socket *sock)
 121{
 122        if (sock->sk)
 123                sock_put(sock->sk);
 124        return 0;
 125}
 126EXPORT_SYMBOL_GPL(af_alg_release);
 127
 128static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 129{
 130        const u32 forbidden = CRYPTO_ALG_INTERNAL;
 131        struct sock *sk = sock->sk;
 132        struct alg_sock *ask = alg_sk(sk);
 133        struct sockaddr_alg *sa = (void *)uaddr;
 134        const struct af_alg_type *type;
 135        void *private;
 136
 137        if (sock->state == SS_CONNECTED)
 138                return -EINVAL;
 139
 140        if (addr_len != sizeof(*sa))
 141                return -EINVAL;
 142
 143        sa->salg_type[sizeof(sa->salg_type) - 1] = 0;
 144        sa->salg_name[sizeof(sa->salg_name) - 1] = 0;
 145
 146        type = alg_get_type(sa->salg_type);
 147        if (IS_ERR(type) && PTR_ERR(type) == -ENOENT) {
 148                request_module("algif-%s", sa->salg_type);
 149                type = alg_get_type(sa->salg_type);
 150        }
 151
 152        if (IS_ERR(type))
 153                return PTR_ERR(type);
 154
 155        private = type->bind(sa->salg_name,
 156                             sa->salg_feat & ~forbidden,
 157                             sa->salg_mask & ~forbidden);
 158        if (IS_ERR(private)) {
 159                module_put(type->owner);
 160                return PTR_ERR(private);
 161        }
 162
 163        lock_sock(sk);
 164
 165        swap(ask->type, type);
 166        swap(ask->private, private);
 167
 168        release_sock(sk);
 169
 170        alg_do_release(type, private);
 171
 172        return 0;
 173}
 174
 175static int alg_setkey(struct sock *sk, char __user *ukey,
 176                      unsigned int keylen)
 177{
 178        struct alg_sock *ask = alg_sk(sk);
 179        const struct af_alg_type *type = ask->type;
 180        u8 *key;
 181        int err;
 182
 183        key = sock_kmalloc(sk, keylen, GFP_KERNEL);
 184        if (!key)
 185                return -ENOMEM;
 186
 187        err = -EFAULT;
 188        if (copy_from_user(key, ukey, keylen))
 189                goto out;
 190
 191        err = type->setkey(ask->private, key, keylen);
 192
 193out:
 194        sock_kzfree_s(sk, key, keylen);
 195
 196        return err;
 197}
 198
 199static int alg_setsockopt(struct socket *sock, int level, int optname,
 200                          char __user *optval, unsigned int optlen)
 201{
 202        struct sock *sk = sock->sk;
 203        struct alg_sock *ask = alg_sk(sk);
 204        const struct af_alg_type *type;
 205        int err = -ENOPROTOOPT;
 206
 207        lock_sock(sk);
 208        type = ask->type;
 209
 210        if (level != SOL_ALG || !type)
 211                goto unlock;
 212
 213        switch (optname) {
 214        case ALG_SET_KEY:
 215                if (sock->state == SS_CONNECTED)
 216                        goto unlock;
 217                if (!type->setkey)
 218                        goto unlock;
 219
 220                err = alg_setkey(sk, optval, optlen);
 221                break;
 222        case ALG_SET_AEAD_AUTHSIZE:
 223                if (sock->state == SS_CONNECTED)
 224                        goto unlock;
 225                if (!type->setauthsize)
 226                        goto unlock;
 227                err = type->setauthsize(ask->private, optlen);
 228        }
 229
 230unlock:
 231        release_sock(sk);
 232
 233        return err;
 234}
 235
 236int af_alg_accept(struct sock *sk, struct socket *newsock)
 237{
 238        struct alg_sock *ask = alg_sk(sk);
 239        const struct af_alg_type *type;
 240        struct sock *sk2;
 241        int err;
 242
 243        lock_sock(sk);
 244        type = ask->type;
 245
 246        err = -EINVAL;
 247        if (!type)
 248                goto unlock;
 249
 250        sk2 = sk_alloc(sock_net(sk), PF_ALG, GFP_KERNEL, &alg_proto, 0);
 251        err = -ENOMEM;
 252        if (!sk2)
 253                goto unlock;
 254
 255        sock_init_data(newsock, sk2);
 256        sock_graft(sk2, newsock);
 257        security_sk_clone(sk, sk2);
 258
 259        err = type->accept(ask->private, sk2);
 260        if (err) {
 261                sk_free(sk2);
 262                goto unlock;
 263        }
 264
 265        sk2->sk_family = PF_ALG;
 266
 267        sock_hold(sk);
 268        alg_sk(sk2)->parent = sk;
 269        alg_sk(sk2)->type = type;
 270
 271        newsock->ops = type->ops;
 272        newsock->state = SS_CONNECTED;
 273
 274        err = 0;
 275
 276unlock:
 277        release_sock(sk);
 278
 279        return err;
 280}
 281EXPORT_SYMBOL_GPL(af_alg_accept);
 282
 283static int alg_accept(struct socket *sock, struct socket *newsock, int flags)
 284{
 285        return af_alg_accept(sock->sk, newsock);
 286}
 287
 288static const struct proto_ops alg_proto_ops = {
 289        .family         =       PF_ALG,
 290        .owner          =       THIS_MODULE,
 291
 292        .connect        =       sock_no_connect,
 293        .socketpair     =       sock_no_socketpair,
 294        .getname        =       sock_no_getname,
 295        .ioctl          =       sock_no_ioctl,
 296        .listen         =       sock_no_listen,
 297        .shutdown       =       sock_no_shutdown,
 298        .getsockopt     =       sock_no_getsockopt,
 299        .mmap           =       sock_no_mmap,
 300        .sendpage       =       sock_no_sendpage,
 301        .sendmsg        =       sock_no_sendmsg,
 302        .recvmsg        =       sock_no_recvmsg,
 303        .poll           =       sock_no_poll,
 304
 305        .bind           =       alg_bind,
 306        .release        =       af_alg_release,
 307        .setsockopt     =       alg_setsockopt,
 308        .accept         =       alg_accept,
 309};
 310
 311static void alg_sock_destruct(struct sock *sk)
 312{
 313        struct alg_sock *ask = alg_sk(sk);
 314
 315        alg_do_release(ask->type, ask->private);
 316}
 317
 318static int alg_create(struct net *net, struct socket *sock, int protocol,
 319                      int kern)
 320{
 321        struct sock *sk;
 322        int err;
 323
 324        if (sock->type != SOCK_SEQPACKET)
 325                return -ESOCKTNOSUPPORT;
 326        if (protocol != 0)
 327                return -EPROTONOSUPPORT;
 328
 329        err = -ENOMEM;
 330        sk = sk_alloc(net, PF_ALG, GFP_KERNEL, &alg_proto, kern);
 331        if (!sk)
 332                goto out;
 333
 334        sock->ops = &alg_proto_ops;
 335        sock_init_data(sock, sk);
 336
 337        sk->sk_family = PF_ALG;
 338        sk->sk_destruct = alg_sock_destruct;
 339
 340        return 0;
 341out:
 342        return err;
 343}
 344
 345static const struct net_proto_family alg_family = {
 346        .family =       PF_ALG,
 347        .create =       alg_create,
 348        .owner  =       THIS_MODULE,
 349};
 350
 351int af_alg_make_sg(struct af_alg_sgl *sgl, struct iov_iter *iter, int len)
 352{
 353        size_t off;
 354        ssize_t n;
 355        int npages, i;
 356
 357        n = iov_iter_get_pages(iter, sgl->pages, len, ALG_MAX_PAGES, &off);
 358        if (n < 0)
 359                return n;
 360
 361        npages = (off + n + PAGE_SIZE - 1) >> PAGE_SHIFT;
 362        if (WARN_ON(npages == 0))
 363                return -EINVAL;
 364        /* Add one extra for linking */
 365        sg_init_table(sgl->sg, npages + 1);
 366
 367        for (i = 0, len = n; i < npages; i++) {
 368                int plen = min_t(int, len, PAGE_SIZE - off);
 369
 370                sg_set_page(sgl->sg + i, sgl->pages[i], plen, off);
 371
 372                off = 0;
 373                len -= plen;
 374        }
 375        sg_mark_end(sgl->sg + npages - 1);
 376        sgl->npages = npages;
 377
 378        return n;
 379}
 380EXPORT_SYMBOL_GPL(af_alg_make_sg);
 381
 382void af_alg_link_sg(struct af_alg_sgl *sgl_prev, struct af_alg_sgl *sgl_new)
 383{
 384        sg_unmark_end(sgl_prev->sg + sgl_prev->npages - 1);
 385        sg_chain(sgl_prev->sg, sgl_prev->npages + 1, sgl_new->sg);
 386}
 387EXPORT_SYMBOL_GPL(af_alg_link_sg);
 388
 389void af_alg_free_sg(struct af_alg_sgl *sgl)
 390{
 391        int i;
 392
 393        for (i = 0; i < sgl->npages; i++)
 394                put_page(sgl->pages[i]);
 395}
 396EXPORT_SYMBOL_GPL(af_alg_free_sg);
 397
 398int af_alg_cmsg_send(struct msghdr *msg, struct af_alg_control *con)
 399{
 400        struct cmsghdr *cmsg;
 401
 402        for_each_cmsghdr(cmsg, msg) {
 403                if (!CMSG_OK(msg, cmsg))
 404                        return -EINVAL;
 405                if (cmsg->cmsg_level != SOL_ALG)
 406                        continue;
 407
 408                switch (cmsg->cmsg_type) {
 409                case ALG_SET_IV:
 410                        if (cmsg->cmsg_len < CMSG_LEN(sizeof(*con->iv)))
 411                                return -EINVAL;
 412                        con->iv = (void *)CMSG_DATA(cmsg);
 413                        if (cmsg->cmsg_len < CMSG_LEN(con->iv->ivlen +
 414                                                      sizeof(*con->iv)))
 415                                return -EINVAL;
 416                        break;
 417
 418                case ALG_SET_OP:
 419                        if (cmsg->cmsg_len < CMSG_LEN(sizeof(u32)))
 420                                return -EINVAL;
 421                        con->op = *(u32 *)CMSG_DATA(cmsg);
 422                        break;
 423
 424                case ALG_SET_AEAD_ASSOCLEN:
 425                        if (cmsg->cmsg_len < CMSG_LEN(sizeof(u32)))
 426                                return -EINVAL;
 427                        con->aead_assoclen = *(u32 *)CMSG_DATA(cmsg);
 428                        break;
 429
 430                default:
 431                        return -EINVAL;
 432                }
 433        }
 434
 435        return 0;
 436}
 437EXPORT_SYMBOL_GPL(af_alg_cmsg_send);
 438
 439int af_alg_wait_for_completion(int err, struct af_alg_completion *completion)
 440{
 441        switch (err) {
 442        case -EINPROGRESS:
 443        case -EBUSY:
 444                wait_for_completion(&completion->completion);
 445                reinit_completion(&completion->completion);
 446                err = completion->err;
 447                break;
 448        };
 449
 450        return err;
 451}
 452EXPORT_SYMBOL_GPL(af_alg_wait_for_completion);
 453
 454void af_alg_complete(struct crypto_async_request *req, int err)
 455{
 456        struct af_alg_completion *completion = req->data;
 457
 458        if (err == -EINPROGRESS)
 459                return;
 460
 461        completion->err = err;
 462        complete(&completion->completion);
 463}
 464EXPORT_SYMBOL_GPL(af_alg_complete);
 465
 466static int __init af_alg_init(void)
 467{
 468        int err = proto_register(&alg_proto, 0);
 469
 470        if (err)
 471                goto out;
 472
 473        err = sock_register(&alg_family);
 474        if (err != 0)
 475                goto out_unregister_proto;
 476
 477out:
 478        return err;
 479
 480out_unregister_proto:
 481        proto_unregister(&alg_proto);
 482        goto out;
 483}
 484
 485static void __exit af_alg_exit(void)
 486{
 487        sock_unregister(PF_ALG);
 488        proto_unregister(&alg_proto);
 489}
 490
 491module_init(af_alg_init);
 492module_exit(af_alg_exit);
 493MODULE_LICENSE("GPL");
 494MODULE_ALIAS_NETPROTO(AF_ALG);
 495