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        if (type->ops_nokey)
  80                type->ops_nokey->owner = THIS_MODULE;
  81        node->type = type;
  82        list_add(&node->list, &alg_types);
  83        err = 0;
  84
  85unlock:
  86        up_write(&alg_types_sem);
  87
  88        return err;
  89}
  90EXPORT_SYMBOL_GPL(af_alg_register_type);
  91
  92int af_alg_unregister_type(const struct af_alg_type *type)
  93{
  94        struct alg_type_list *node;
  95        int err = -ENOENT;
  96
  97        down_write(&alg_types_sem);
  98        list_for_each_entry(node, &alg_types, list) {
  99                if (strcmp(node->type->name, type->name))
 100                        continue;
 101
 102                list_del(&node->list);
 103                kfree(node);
 104                err = 0;
 105                break;
 106        }
 107        up_write(&alg_types_sem);
 108
 109        return err;
 110}
 111EXPORT_SYMBOL_GPL(af_alg_unregister_type);
 112
 113static void alg_do_release(const struct af_alg_type *type, void *private)
 114{
 115        if (!type)
 116                return;
 117
 118        type->release(private);
 119        module_put(type->owner);
 120}
 121
 122int af_alg_release(struct socket *sock)
 123{
 124        if (sock->sk)
 125                sock_put(sock->sk);
 126        return 0;
 127}
 128EXPORT_SYMBOL_GPL(af_alg_release);
 129
 130void af_alg_release_parent(struct sock *sk)
 131{
 132        struct alg_sock *ask = alg_sk(sk);
 133        unsigned int nokey = ask->nokey_refcnt;
 134        bool last = nokey && !ask->refcnt;
 135
 136        sk = ask->parent;
 137        ask = alg_sk(sk);
 138
 139        lock_sock(sk);
 140        ask->nokey_refcnt -= nokey;
 141        if (!last)
 142                last = !--ask->refcnt;
 143        release_sock(sk);
 144
 145        if (last)
 146                sock_put(sk);
 147}
 148EXPORT_SYMBOL_GPL(af_alg_release_parent);
 149
 150static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 151{
 152        const u32 forbidden = CRYPTO_ALG_INTERNAL;
 153        struct sock *sk = sock->sk;
 154        struct alg_sock *ask = alg_sk(sk);
 155        struct sockaddr_alg *sa = (void *)uaddr;
 156        const struct af_alg_type *type;
 157        void *private;
 158        int err;
 159
 160        if (sock->state == SS_CONNECTED)
 161                return -EINVAL;
 162
 163        if (addr_len < sizeof(*sa))
 164                return -EINVAL;
 165
 166        sa->salg_type[sizeof(sa->salg_type) - 1] = 0;
 167        sa->salg_name[sizeof(sa->salg_name) + addr_len - sizeof(*sa) - 1] = 0;
 168
 169        type = alg_get_type(sa->salg_type);
 170        if (IS_ERR(type) && PTR_ERR(type) == -ENOENT) {
 171                request_module("algif-%s", sa->salg_type);
 172                type = alg_get_type(sa->salg_type);
 173        }
 174
 175        if (IS_ERR(type))
 176                return PTR_ERR(type);
 177
 178        private = type->bind(sa->salg_name,
 179                             sa->salg_feat & ~forbidden,
 180                             sa->salg_mask & ~forbidden);
 181        if (IS_ERR(private)) {
 182                module_put(type->owner);
 183                return PTR_ERR(private);
 184        }
 185
 186        err = -EBUSY;
 187        lock_sock(sk);
 188        if (ask->refcnt | ask->nokey_refcnt)
 189                goto unlock;
 190
 191        swap(ask->type, type);
 192        swap(ask->private, private);
 193
 194        err = 0;
 195
 196unlock:
 197        release_sock(sk);
 198
 199        alg_do_release(type, private);
 200
 201        return err;
 202}
 203
 204static int alg_setkey(struct sock *sk, char __user *ukey,
 205                      unsigned int keylen)
 206{
 207        struct alg_sock *ask = alg_sk(sk);
 208        const struct af_alg_type *type = ask->type;
 209        u8 *key;
 210        int err;
 211
 212        key = sock_kmalloc(sk, keylen, GFP_KERNEL);
 213        if (!key)
 214                return -ENOMEM;
 215
 216        err = -EFAULT;
 217        if (copy_from_user(key, ukey, keylen))
 218                goto out;
 219
 220        err = type->setkey(ask->private, key, keylen);
 221
 222out:
 223        sock_kzfree_s(sk, key, keylen);
 224
 225        return err;
 226}
 227
 228static int alg_setsockopt(struct socket *sock, int level, int optname,
 229                          char __user *optval, unsigned int optlen)
 230{
 231        struct sock *sk = sock->sk;
 232        struct alg_sock *ask = alg_sk(sk);
 233        const struct af_alg_type *type;
 234        int err = -EBUSY;
 235
 236        lock_sock(sk);
 237        if (ask->refcnt)
 238                goto unlock;
 239
 240        type = ask->type;
 241
 242        err = -ENOPROTOOPT;
 243        if (level != SOL_ALG || !type)
 244                goto unlock;
 245
 246        switch (optname) {
 247        case ALG_SET_KEY:
 248                if (sock->state == SS_CONNECTED)
 249                        goto unlock;
 250                if (!type->setkey)
 251                        goto unlock;
 252
 253                err = alg_setkey(sk, optval, optlen);
 254                break;
 255        case ALG_SET_AEAD_AUTHSIZE:
 256                if (sock->state == SS_CONNECTED)
 257                        goto unlock;
 258                if (!type->setauthsize)
 259                        goto unlock;
 260                err = type->setauthsize(ask->private, optlen);
 261        }
 262
 263unlock:
 264        release_sock(sk);
 265
 266        return err;
 267}
 268
 269int af_alg_accept(struct sock *sk, struct socket *newsock, bool kern)
 270{
 271        struct alg_sock *ask = alg_sk(sk);
 272        const struct af_alg_type *type;
 273        struct sock *sk2;
 274        unsigned int nokey;
 275        int err;
 276
 277        lock_sock(sk);
 278        type = ask->type;
 279
 280        err = -EINVAL;
 281        if (!type)
 282                goto unlock;
 283
 284        sk2 = sk_alloc(sock_net(sk), PF_ALG, GFP_KERNEL, &alg_proto, kern);
 285        err = -ENOMEM;
 286        if (!sk2)
 287                goto unlock;
 288
 289        sock_init_data(newsock, sk2);
 290        security_sock_graft(sk2, newsock);
 291        security_sk_clone(sk, sk2);
 292
 293        err = type->accept(ask->private, sk2);
 294
 295        nokey = err == -ENOKEY;
 296        if (nokey && type->accept_nokey)
 297                err = type->accept_nokey(ask->private, sk2);
 298
 299        if (err)
 300                goto unlock;
 301
 302        sk2->sk_family = PF_ALG;
 303
 304        if (nokey || !ask->refcnt++)
 305                sock_hold(sk);
 306        ask->nokey_refcnt += nokey;
 307        alg_sk(sk2)->parent = sk;
 308        alg_sk(sk2)->type = type;
 309        alg_sk(sk2)->nokey_refcnt = nokey;
 310
 311        newsock->ops = type->ops;
 312        newsock->state = SS_CONNECTED;
 313
 314        if (nokey)
 315                newsock->ops = type->ops_nokey;
 316
 317        err = 0;
 318
 319unlock:
 320        release_sock(sk);
 321
 322        return err;
 323}
 324EXPORT_SYMBOL_GPL(af_alg_accept);
 325
 326static int alg_accept(struct socket *sock, struct socket *newsock, int flags,
 327                      bool kern)
 328{
 329        return af_alg_accept(sock->sk, newsock, kern);
 330}
 331
 332static const struct proto_ops alg_proto_ops = {
 333        .family         =       PF_ALG,
 334        .owner          =       THIS_MODULE,
 335
 336        .connect        =       sock_no_connect,
 337        .socketpair     =       sock_no_socketpair,
 338        .getname        =       sock_no_getname,
 339        .ioctl          =       sock_no_ioctl,
 340        .listen         =       sock_no_listen,
 341        .shutdown       =       sock_no_shutdown,
 342        .getsockopt     =       sock_no_getsockopt,
 343        .mmap           =       sock_no_mmap,
 344        .sendpage       =       sock_no_sendpage,
 345        .sendmsg        =       sock_no_sendmsg,
 346        .recvmsg        =       sock_no_recvmsg,
 347        .poll           =       sock_no_poll,
 348
 349        .bind           =       alg_bind,
 350        .release        =       af_alg_release,
 351        .setsockopt     =       alg_setsockopt,
 352        .accept         =       alg_accept,
 353};
 354
 355static void alg_sock_destruct(struct sock *sk)
 356{
 357        struct alg_sock *ask = alg_sk(sk);
 358
 359        alg_do_release(ask->type, ask->private);
 360}
 361
 362static int alg_create(struct net *net, struct socket *sock, int protocol,
 363                      int kern)
 364{
 365        struct sock *sk;
 366        int err;
 367
 368        if (sock->type != SOCK_SEQPACKET)
 369                return -ESOCKTNOSUPPORT;
 370        if (protocol != 0)
 371                return -EPROTONOSUPPORT;
 372
 373        err = -ENOMEM;
 374        sk = sk_alloc(net, PF_ALG, GFP_KERNEL, &alg_proto, kern);
 375        if (!sk)
 376                goto out;
 377
 378        sock->ops = &alg_proto_ops;
 379        sock_init_data(sock, sk);
 380
 381        sk->sk_family = PF_ALG;
 382        sk->sk_destruct = alg_sock_destruct;
 383
 384        return 0;
 385out:
 386        return err;
 387}
 388
 389static const struct net_proto_family alg_family = {
 390        .family =       PF_ALG,
 391        .create =       alg_create,
 392        .owner  =       THIS_MODULE,
 393};
 394
 395int af_alg_make_sg(struct af_alg_sgl *sgl, struct iov_iter *iter, int len)
 396{
 397        size_t off;
 398        ssize_t n;
 399        int npages, i;
 400
 401        n = iov_iter_get_pages(iter, sgl->pages, len, ALG_MAX_PAGES, &off);
 402        if (n < 0)
 403                return n;
 404
 405        npages = (off + n + PAGE_SIZE - 1) >> PAGE_SHIFT;
 406        if (WARN_ON(npages == 0))
 407                return -EINVAL;
 408        /* Add one extra for linking */
 409        sg_init_table(sgl->sg, npages + 1);
 410
 411        for (i = 0, len = n; i < npages; i++) {
 412                int plen = min_t(int, len, PAGE_SIZE - off);
 413
 414                sg_set_page(sgl->sg + i, sgl->pages[i], plen, off);
 415
 416                off = 0;
 417                len -= plen;
 418        }
 419        sg_mark_end(sgl->sg + npages - 1);
 420        sgl->npages = npages;
 421
 422        return n;
 423}
 424EXPORT_SYMBOL_GPL(af_alg_make_sg);
 425
 426void af_alg_link_sg(struct af_alg_sgl *sgl_prev, struct af_alg_sgl *sgl_new)
 427{
 428        sg_unmark_end(sgl_prev->sg + sgl_prev->npages - 1);
 429        sg_chain(sgl_prev->sg, sgl_prev->npages + 1, sgl_new->sg);
 430}
 431EXPORT_SYMBOL_GPL(af_alg_link_sg);
 432
 433void af_alg_free_sg(struct af_alg_sgl *sgl)
 434{
 435        int i;
 436
 437        for (i = 0; i < sgl->npages; i++)
 438                put_page(sgl->pages[i]);
 439}
 440EXPORT_SYMBOL_GPL(af_alg_free_sg);
 441
 442int af_alg_cmsg_send(struct msghdr *msg, struct af_alg_control *con)
 443{
 444        struct cmsghdr *cmsg;
 445
 446        for_each_cmsghdr(cmsg, msg) {
 447                if (!CMSG_OK(msg, cmsg))
 448                        return -EINVAL;
 449                if (cmsg->cmsg_level != SOL_ALG)
 450                        continue;
 451
 452                switch (cmsg->cmsg_type) {
 453                case ALG_SET_IV:
 454                        if (cmsg->cmsg_len < CMSG_LEN(sizeof(*con->iv)))
 455                                return -EINVAL;
 456                        con->iv = (void *)CMSG_DATA(cmsg);
 457                        if (cmsg->cmsg_len < CMSG_LEN(con->iv->ivlen +
 458                                                      sizeof(*con->iv)))
 459                                return -EINVAL;
 460                        break;
 461
 462                case ALG_SET_OP:
 463                        if (cmsg->cmsg_len < CMSG_LEN(sizeof(u32)))
 464                                return -EINVAL;
 465                        con->op = *(u32 *)CMSG_DATA(cmsg);
 466                        break;
 467
 468                case ALG_SET_AEAD_ASSOCLEN:
 469                        if (cmsg->cmsg_len < CMSG_LEN(sizeof(u32)))
 470                                return -EINVAL;
 471                        con->aead_assoclen = *(u32 *)CMSG_DATA(cmsg);
 472                        break;
 473
 474                default:
 475                        return -EINVAL;
 476                }
 477        }
 478
 479        return 0;
 480}
 481EXPORT_SYMBOL_GPL(af_alg_cmsg_send);
 482
 483int af_alg_wait_for_completion(int err, struct af_alg_completion *completion)
 484{
 485        switch (err) {
 486        case -EINPROGRESS:
 487        case -EBUSY:
 488                wait_for_completion(&completion->completion);
 489                reinit_completion(&completion->completion);
 490                err = completion->err;
 491                break;
 492        };
 493
 494        return err;
 495}
 496EXPORT_SYMBOL_GPL(af_alg_wait_for_completion);
 497
 498void af_alg_complete(struct crypto_async_request *req, int err)
 499{
 500        struct af_alg_completion *completion = req->data;
 501
 502        if (err == -EINPROGRESS)
 503                return;
 504
 505        completion->err = err;
 506        complete(&completion->completion);
 507}
 508EXPORT_SYMBOL_GPL(af_alg_complete);
 509
 510static int __init af_alg_init(void)
 511{
 512        int err = proto_register(&alg_proto, 0);
 513
 514        if (err)
 515                goto out;
 516
 517        err = sock_register(&alg_family);
 518        if (err != 0)
 519                goto out_unregister_proto;
 520
 521out:
 522        return err;
 523
 524out_unregister_proto:
 525        proto_unregister(&alg_proto);
 526        goto out;
 527}
 528
 529static void __exit af_alg_exit(void)
 530{
 531        sock_unregister(PF_ALG);
 532        proto_unregister(&alg_proto);
 533}
 534
 535module_init(af_alg_init);
 536module_exit(af_alg_exit);
 537MODULE_LICENSE("GPL");
 538MODULE_ALIAS_NETPROTO(AF_ALG);
 539