The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/crypto/algif_hash.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * algif_hash: User-space interface for hash algorithms
    3  *
    4  * This file provides the user-space API for hash 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 <crypto/hash.h>
   16 #include <crypto/if_alg.h>
   17 #include <linux/init.h>
   18 #include <linux/kernel.h>
   19 #include <linux/mm.h>
   20 #include <linux/module.h>
   21 #include <linux/net.h>
   22 #include <net/sock.h>
   23 
   24 struct hash_ctx {
   25         struct af_alg_sgl sgl;
   26 
   27         u8 *result;
   28 
   29         struct af_alg_completion completion;
   30 
   31         unsigned int len;
   32         bool more;
   33 
   34         struct ahash_request req;
   35 };
   36 
   37 static int hash_sendmsg(struct kiocb *unused, struct socket *sock,
   38                         struct msghdr *msg, size_t ignored)
   39 {
   40         int limit = ALG_MAX_PAGES * PAGE_SIZE;
   41         struct sock *sk = sock->sk;
   42         struct alg_sock *ask = alg_sk(sk);
   43         struct hash_ctx *ctx = ask->private;
   44         unsigned long iovlen;
   45         struct iovec *iov;
   46         long copied = 0;
   47         int err;
   48 
   49         if (limit > sk->sk_sndbuf)
   50                 limit = sk->sk_sndbuf;
   51 
   52         lock_sock(sk);
   53         if (!ctx->more) {
   54                 err = crypto_ahash_init(&ctx->req);
   55                 if (err)
   56                         goto unlock;
   57         }
   58 
   59         ctx->more = 0;
   60 
   61         for (iov = msg->msg_iov, iovlen = msg->msg_iovlen; iovlen > 0;
   62              iovlen--, iov++) {
   63                 unsigned long seglen = iov->iov_len;
   64                 char __user *from = iov->iov_base;
   65 
   66                 while (seglen) {
   67                         int len = min_t(unsigned long, seglen, limit);
   68                         int newlen;
   69 
   70                         newlen = af_alg_make_sg(&ctx->sgl, from, len, 0);
   71                         if (newlen < 0) {
   72                                 err = copied ? 0 : newlen;
   73                                 goto unlock;
   74                         }
   75 
   76                         ahash_request_set_crypt(&ctx->req, ctx->sgl.sg, NULL,
   77                                                 newlen);
   78 
   79                         err = af_alg_wait_for_completion(
   80                                 crypto_ahash_update(&ctx->req),
   81                                 &ctx->completion);
   82 
   83                         af_alg_free_sg(&ctx->sgl);
   84 
   85                         if (err)
   86                                 goto unlock;
   87 
   88                         seglen -= newlen;
   89                         from += newlen;
   90                         copied += newlen;
   91                 }
   92         }
   93 
   94         err = 0;
   95 
   96         ctx->more = msg->msg_flags & MSG_MORE;
   97         if (!ctx->more) {
   98                 ahash_request_set_crypt(&ctx->req, NULL, ctx->result, 0);
   99                 err = af_alg_wait_for_completion(crypto_ahash_final(&ctx->req),
  100                                                  &ctx->completion);
  101         }
  102 
  103 unlock:
  104         release_sock(sk);
  105 
  106         return err ?: copied;
  107 }
  108 
  109 static ssize_t hash_sendpage(struct socket *sock, struct page *page,
  110                              int offset, size_t size, int flags)
  111 {
  112         struct sock *sk = sock->sk;
  113         struct alg_sock *ask = alg_sk(sk);
  114         struct hash_ctx *ctx = ask->private;
  115         int err;
  116 
  117         lock_sock(sk);
  118         sg_init_table(ctx->sgl.sg, 1);
  119         sg_set_page(ctx->sgl.sg, page, size, offset);
  120 
  121         ahash_request_set_crypt(&ctx->req, ctx->sgl.sg, ctx->result, size);
  122 
  123         if (!(flags & MSG_MORE)) {
  124                 if (ctx->more)
  125                         err = crypto_ahash_finup(&ctx->req);
  126                 else
  127                         err = crypto_ahash_digest(&ctx->req);
  128         } else {
  129                 if (!ctx->more) {
  130                         err = crypto_ahash_init(&ctx->req);
  131                         if (err)
  132                                 goto unlock;
  133                 }
  134 
  135                 err = crypto_ahash_update(&ctx->req);
  136         }
  137 
  138         err = af_alg_wait_for_completion(err, &ctx->completion);
  139         if (err)
  140                 goto unlock;
  141 
  142         ctx->more = flags & MSG_MORE;
  143 
  144 unlock:
  145         release_sock(sk);
  146 
  147         return err ?: size;
  148 }
  149 
  150 static int hash_recvmsg(struct kiocb *unused, struct socket *sock,
  151                         struct msghdr *msg, size_t len, int flags)
  152 {
  153         struct sock *sk = sock->sk;
  154         struct alg_sock *ask = alg_sk(sk);
  155         struct hash_ctx *ctx = ask->private;
  156         unsigned ds = crypto_ahash_digestsize(crypto_ahash_reqtfm(&ctx->req));
  157         int err;
  158 
  159         if (len > ds)
  160                 len = ds;
  161         else if (len < ds)
  162                 msg->msg_flags |= MSG_TRUNC;
  163 
  164         lock_sock(sk);
  165         if (ctx->more) {
  166                 ctx->more = 0;
  167                 ahash_request_set_crypt(&ctx->req, NULL, ctx->result, 0);
  168                 err = af_alg_wait_for_completion(crypto_ahash_final(&ctx->req),
  169                                                  &ctx->completion);
  170                 if (err)
  171                         goto unlock;
  172         }
  173 
  174         err = memcpy_toiovec(msg->msg_iov, ctx->result, len);
  175 
  176 unlock:
  177         release_sock(sk);
  178 
  179         return err ?: len;
  180 }
  181 
  182 static int hash_accept(struct socket *sock, struct socket *newsock, int flags)
  183 {
  184         struct sock *sk = sock->sk;
  185         struct alg_sock *ask = alg_sk(sk);
  186         struct hash_ctx *ctx = ask->private;
  187         struct ahash_request *req = &ctx->req;
  188         char state[crypto_ahash_statesize(crypto_ahash_reqtfm(req))];
  189         struct sock *sk2;
  190         struct alg_sock *ask2;
  191         struct hash_ctx *ctx2;
  192         int err;
  193 
  194         err = crypto_ahash_export(req, state);
  195         if (err)
  196                 return err;
  197 
  198         err = af_alg_accept(ask->parent, newsock);
  199         if (err)
  200                 return err;
  201 
  202         sk2 = newsock->sk;
  203         ask2 = alg_sk(sk2);
  204         ctx2 = ask2->private;
  205         ctx2->more = 1;
  206 
  207         err = crypto_ahash_import(&ctx2->req, state);
  208         if (err) {
  209                 sock_orphan(sk2);
  210                 sock_put(sk2);
  211         }
  212 
  213         return err;
  214 }
  215 
  216 static struct proto_ops algif_hash_ops = {
  217         .family         =       PF_ALG,
  218 
  219         .connect        =       sock_no_connect,
  220         .socketpair     =       sock_no_socketpair,
  221         .getname        =       sock_no_getname,
  222         .ioctl          =       sock_no_ioctl,
  223         .listen         =       sock_no_listen,
  224         .shutdown       =       sock_no_shutdown,
  225         .getsockopt     =       sock_no_getsockopt,
  226         .mmap           =       sock_no_mmap,
  227         .bind           =       sock_no_bind,
  228         .setsockopt     =       sock_no_setsockopt,
  229         .poll           =       sock_no_poll,
  230 
  231         .release        =       af_alg_release,
  232         .sendmsg        =       hash_sendmsg,
  233         .sendpage       =       hash_sendpage,
  234         .recvmsg        =       hash_recvmsg,
  235         .accept         =       hash_accept,
  236 };
  237 
  238 static void *hash_bind(const char *name, u32 type, u32 mask)
  239 {
  240         return crypto_alloc_ahash(name, type, mask);
  241 }
  242 
  243 static void hash_release(void *private)
  244 {
  245         crypto_free_ahash(private);
  246 }
  247 
  248 static int hash_setkey(void *private, const u8 *key, unsigned int keylen)
  249 {
  250         return crypto_ahash_setkey(private, key, keylen);
  251 }
  252 
  253 static void hash_sock_destruct(struct sock *sk)
  254 {
  255         struct alg_sock *ask = alg_sk(sk);
  256         struct hash_ctx *ctx = ask->private;
  257 
  258         sock_kfree_s(sk, ctx->result,
  259                      crypto_ahash_digestsize(crypto_ahash_reqtfm(&ctx->req)));
  260         sock_kfree_s(sk, ctx, ctx->len);
  261         af_alg_release_parent(sk);
  262 }
  263 
  264 static int hash_accept_parent(void *private, struct sock *sk)
  265 {
  266         struct hash_ctx *ctx;
  267         struct alg_sock *ask = alg_sk(sk);
  268         unsigned len = sizeof(*ctx) + crypto_ahash_reqsize(private);
  269         unsigned ds = crypto_ahash_digestsize(private);
  270 
  271         ctx = sock_kmalloc(sk, len, GFP_KERNEL);
  272         if (!ctx)
  273                 return -ENOMEM;
  274 
  275         ctx->result = sock_kmalloc(sk, ds, GFP_KERNEL);
  276         if (!ctx->result) {
  277                 sock_kfree_s(sk, ctx, len);
  278                 return -ENOMEM;
  279         }
  280 
  281         memset(ctx->result, 0, ds);
  282 
  283         ctx->len = len;
  284         ctx->more = 0;
  285         af_alg_init_completion(&ctx->completion);
  286 
  287         ask->private = ctx;
  288 
  289         ahash_request_set_tfm(&ctx->req, private);
  290         ahash_request_set_callback(&ctx->req, CRYPTO_TFM_REQ_MAY_BACKLOG,
  291                                    af_alg_complete, &ctx->completion);
  292 
  293         sk->sk_destruct = hash_sock_destruct;
  294 
  295         return 0;
  296 }
  297 
  298 static const struct af_alg_type algif_type_hash = {
  299         .bind           =       hash_bind,
  300         .release        =       hash_release,
  301         .setkey         =       hash_setkey,
  302         .accept         =       hash_accept_parent,
  303         .ops            =       &algif_hash_ops,
  304         .name           =       "hash",
  305         .owner          =       THIS_MODULE
  306 };
  307 
  308 static int __init algif_hash_init(void)
  309 {
  310         return af_alg_register_type(&algif_type_hash);
  311 }
  312 
  313 static void __exit algif_hash_exit(void)
  314 {
  315         int err = af_alg_unregister_type(&algif_type_hash);
  316         BUG_ON(err);
  317 }
  318 
  319 module_init(algif_hash_init);
  320 module_exit(algif_hash_exit);
  321 MODULE_LICENSE("GPL");

Cache object: 87cb918175771601bf9e8f9f50c4ad15


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.