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        struct sock *sk = sock->sk;
 131        struct alg_sock *ask = alg_sk(sk);
 132        struct sockaddr_alg *sa = (void *)uaddr;
 133        const struct af_alg_type *type;
 134        void *private;
 135
 136        if (sock->state == SS_CONNECTED)
 137                return -EINVAL;
 138
 139        if (addr_len != sizeof(*sa))
 140                return -EINVAL;
 141
 142        sa->salg_type[sizeof(sa->salg_type) - 1] = 0;
 143        sa->salg_name[sizeof(sa->salg_name) - 1] = 0;
 144
 145        type = alg_get_type(sa->salg_type);
 146        if (IS_ERR(type) && PTR_ERR(type) == -ENOENT) {
 147                request_module("algif-%s", sa->salg_type);
 148                type = alg_get_type(sa->salg_type);
 149        }
 150
 151        if (IS_ERR(type))
 152                return PTR_ERR(type);
 153
 154        private = type->bind(sa->salg_name, sa->salg_feat, sa->salg_mask);
 155        if (IS_ERR(private)) {
 156                module_put(type->owner);
 157                return PTR_ERR(private);
 158        }
 159
 160        lock_sock(sk);
 161
 162        swap(ask->type, type);
 163        swap(ask->private, private);
 164
 165        release_sock(sk);
 166
 167        alg_do_release(type, private);
 168
 169        return 0;
 170}
 171
 172static int alg_setkey(struct sock *sk, char __user *ukey,
 173                      unsigned int keylen)
 174{
 175        struct alg_sock *ask = alg_sk(sk);
 176        const struct af_alg_type *type = ask->type;
 177        u8 *key;
 178        int err;
 179
 180        key = sock_kmalloc(sk, keylen, GFP_KERNEL);
 181        if (!key)
 182                return -ENOMEM;
 183
 184        err = -EFAULT;
 185        if (copy_from_user(key, ukey, keylen))
 186                goto out;
 187
 188        err = type->setkey(ask->private, key, keylen);
 189
 190out:
 191        sock_kfree_s(sk, key, keylen);
 192
 193        return err;
 194}
 195
 196static int alg_setsockopt(struct socket *sock, int level, int optname,
 197                          char __user *optval, unsigned int optlen)
 198{
 199        struct sock *sk = sock->sk;
 200        struct alg_sock *ask = alg_sk(sk);
 201        const struct af_alg_type *type;
 202        int err = -ENOPROTOOPT;
 203
 204        lock_sock(sk);
 205        type = ask->type;
 206
 207        if (level != SOL_ALG || !type)
 208                goto unlock;
 209
 210        switch (optname) {
 211        case ALG_SET_KEY:
 212                if (sock->state == SS_CONNECTED)
 213                        goto unlock;
 214                if (!type->setkey)
 215                        goto unlock;
 216
 217                err = alg_setkey(sk, optval, optlen);
 218        }
 219
 220unlock:
 221        release_sock(sk);
 222
 223        return err;
 224}
 225
 226int af_alg_accept(struct sock *sk, struct socket *newsock)
 227{
 228        struct alg_sock *ask = alg_sk(sk);
 229        const struct af_alg_type *type;
 230        struct sock *sk2;
 231        int err;
 232
 233        lock_sock(sk);
 234        type = ask->type;
 235
 236        err = -EINVAL;
 237        if (!type)
 238                goto unlock;
 239
 240        sk2 = sk_alloc(sock_net(sk), PF_ALG, GFP_KERNEL, &alg_proto);
 241        err = -ENOMEM;
 242        if (!sk2)
 243                goto unlock;
 244
 245        sock_init_data(newsock, sk2);
 246        sock_graft(sk2, newsock);
 247        security_sk_clone(sk, sk2);
 248
 249        err = type->accept(ask->private, sk2);
 250        if (err) {
 251                sk_free(sk2);
 252                goto unlock;
 253        }
 254
 255        sk2->sk_family = PF_ALG;
 256
 257        sock_hold(sk);
 258        alg_sk(sk2)->parent = sk;
 259        alg_sk(sk2)->type = type;
 260
 261        newsock->ops = type->ops;
 262        newsock->state = SS_CONNECTED;
 263
 264        err = 0;
 265
 266unlock:
 267        release_sock(sk);
 268
 269        return err;
 270}
 271EXPORT_SYMBOL_GPL(af_alg_accept);
 272
 273static int alg_accept(struct socket *sock, struct socket *newsock, int flags)
 274{
 275        return af_alg_accept(sock->sk, newsock);
 276}
 277
 278static const struct proto_ops alg_proto_ops = {
 279        .family         =       PF_ALG,
 280        .owner          =       THIS_MODULE,
 281
 282        .connect        =       sock_no_connect,
 283        .socketpair     =       sock_no_socketpair,
 284        .getname        =       sock_no_getname,
 285        .ioctl          =       sock_no_ioctl,
 286        .listen         =       sock_no_listen,
 287        .shutdown       =       sock_no_shutdown,
 288        .getsockopt     =       sock_no_getsockopt,
 289        .mmap           =       sock_no_mmap,
 290        .sendpage       =       sock_no_sendpage,
 291        .sendmsg        =       sock_no_sendmsg,
 292        .recvmsg        =       sock_no_recvmsg,
 293        .poll           =       sock_no_poll,
 294
 295        .bind           =       alg_bind,
 296        .release        =       af_alg_release,
 297        .setsockopt     =       alg_setsockopt,
 298        .accept         =       alg_accept,
 299};
 300
 301static void alg_sock_destruct(struct sock *sk)
 302{
 303        struct alg_sock *ask = alg_sk(sk);
 304
 305        alg_do_release(ask->type, ask->private);
 306}
 307
 308static int alg_create(struct net *net, struct socket *sock, int protocol,
 309                      int kern)
 310{
 311        struct sock *sk;
 312        int err;
 313
 314        if (sock->type != SOCK_SEQPACKET)
 315                return -ESOCKTNOSUPPORT;
 316        if (protocol != 0)
 317                return -EPROTONOSUPPORT;
 318
 319        err = -ENOMEM;
 320        sk = sk_alloc(net, PF_ALG, GFP_KERNEL, &alg_proto);
 321        if (!sk)
 322                goto out;
 323
 324        sock->ops = &alg_proto_ops;
 325        sock_init_data(sock, sk);
 326
 327        sk->sk_family = PF_ALG;
 328        sk->sk_destruct = alg_sock_destruct;
 329
 330        return 0;
 331out:
 332        return err;
 333}
 334
 335static const struct net_proto_family alg_family = {
 336        .family =       PF_ALG,
 337        .create =       alg_create,
 338        .owner  =       THIS_MODULE,
 339};
 340
 341int af_alg_make_sg(struct af_alg_sgl *sgl, void __user *addr, int len,
 342                   int write)
 343{
 344        unsigned long from = (unsigned long)addr;
 345        unsigned long npages;
 346        unsigned off;
 347        int err;
 348        int i;
 349
 350        err = -EFAULT;
 351        if (!access_ok(write ? VERIFY_READ : VERIFY_WRITE, addr, len))
 352                goto out;
 353
 354        off = from & ~PAGE_MASK;
 355        npages = (off + len + PAGE_SIZE - 1) >> PAGE_SHIFT;
 356        if (npages > ALG_MAX_PAGES)
 357                npages = ALG_MAX_PAGES;
 358
 359        err = get_user_pages_fast(from, npages, write, sgl->pages);
 360        if (err < 0)
 361                goto out;
 362
 363        npages = err;
 364        err = -EINVAL;
 365        if (WARN_ON(npages == 0))
 366                goto out;
 367
 368        err = 0;
 369
 370        sg_init_table(sgl->sg, npages);
 371
 372        for (i = 0; i < npages; i++) {
 373                int plen = min_t(int, len, PAGE_SIZE - off);
 374
 375                sg_set_page(sgl->sg + i, sgl->pages[i], plen, off);
 376
 377                off = 0;
 378                len -= plen;
 379                err += plen;
 380        }
 381
 382out:
 383        return err;
 384}
 385EXPORT_SYMBOL_GPL(af_alg_make_sg);
 386
 387void af_alg_free_sg(struct af_alg_sgl *sgl)
 388{
 389        int i;
 390
 391        i = 0;
 392        do {
 393                put_page(sgl->pages[i]);
 394        } while (!sg_is_last(sgl->sg + (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 (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
 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                default:
 425                        return -EINVAL;
 426                }
 427        }
 428
 429        return 0;
 430}
 431EXPORT_SYMBOL_GPL(af_alg_cmsg_send);
 432
 433int af_alg_wait_for_completion(int err, struct af_alg_completion *completion)
 434{
 435        switch (err) {
 436        case -EINPROGRESS:
 437        case -EBUSY:
 438                wait_for_completion(&completion->completion);
 439                reinit_completion(&completion->completion);
 440                err = completion->err;
 441                break;
 442        };
 443
 444        return err;
 445}
 446EXPORT_SYMBOL_GPL(af_alg_wait_for_completion);
 447
 448void af_alg_complete(struct crypto_async_request *req, int err)
 449{
 450        struct af_alg_completion *completion = req->data;
 451
 452        completion->err = err;
 453        complete(&completion->completion);
 454}
 455EXPORT_SYMBOL_GPL(af_alg_complete);
 456
 457static int __init af_alg_init(void)
 458{
 459        int err = proto_register(&alg_proto, 0);
 460
 461        if (err)
 462                goto out;
 463
 464        err = sock_register(&alg_family);
 465        if (err != 0)
 466                goto out_unregister_proto;
 467
 468out:
 469        return err;
 470
 471out_unregister_proto:
 472        proto_unregister(&alg_proto);
 473        goto out;
 474}
 475
 476static void __exit af_alg_exit(void)
 477{
 478        sock_unregister(PF_ALG);
 479        proto_unregister(&alg_proto);
 480}
 481
 482module_init(af_alg_init);
 483module_exit(af_alg_exit);
 484MODULE_LICENSE("GPL");
 485MODULE_ALIAS_NETPROTO(AF_ALG);
 486