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 24struct 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 37struct algif_hash_tfm { 38 struct crypto_ahash *hash; 39 bool has_key; 40}; 41 42static int hash_sendmsg(struct socket *sock, struct msghdr *msg, 43 size_t ignored) 44{ 45 int limit = ALG_MAX_PAGES * PAGE_SIZE; 46 struct sock *sk = sock->sk; 47 struct alg_sock *ask = alg_sk(sk); 48 struct hash_ctx *ctx = ask->private; 49 long copied = 0; 50 int err; 51 52 if (limit > sk->sk_sndbuf) 53 limit = sk->sk_sndbuf; 54 55 lock_sock(sk); 56 if (!ctx->more) { 57 err = af_alg_wait_for_completion(crypto_ahash_init(&ctx->req), 58 &ctx->completion); 59 if (err) 60 goto unlock; 61 } 62 63 ctx->more = 0; 64 65 while (msg_data_left(msg)) { 66 int len = msg_data_left(msg); 67 68 if (len > limit) 69 len = limit; 70 71 len = af_alg_make_sg(&ctx->sgl, &msg->msg_iter, len); 72 if (len < 0) { 73 err = copied ? 0 : len; 74 goto unlock; 75 } 76 77 ahash_request_set_crypt(&ctx->req, ctx->sgl.sg, NULL, len); 78 79 err = af_alg_wait_for_completion(crypto_ahash_update(&ctx->req), 80 &ctx->completion); 81 af_alg_free_sg(&ctx->sgl); 82 if (err) 83 goto unlock; 84 85 copied += len; 86 iov_iter_advance(&msg->msg_iter, len); 87 } 88 89 err = 0; 90 91 ctx->more = msg->msg_flags & MSG_MORE; 92 if (!ctx->more) { 93 ahash_request_set_crypt(&ctx->req, NULL, ctx->result, 0); 94 err = af_alg_wait_for_completion(crypto_ahash_final(&ctx->req), 95 &ctx->completion); 96 } 97 98unlock: 99 release_sock(sk); 100 101 return err ?: copied; 102} 103 104static ssize_t hash_sendpage(struct socket *sock, struct page *page, 105 int offset, size_t size, int flags) 106{ 107 struct sock *sk = sock->sk; 108 struct alg_sock *ask = alg_sk(sk); 109 struct hash_ctx *ctx = ask->private; 110 int err; 111 112 if (flags & MSG_SENDPAGE_NOTLAST) 113 flags |= MSG_MORE; 114 115 lock_sock(sk); 116 sg_init_table(ctx->sgl.sg, 1); 117 sg_set_page(ctx->sgl.sg, page, size, offset); 118 119 ahash_request_set_crypt(&ctx->req, ctx->sgl.sg, ctx->result, size); 120 121 if (!(flags & MSG_MORE)) { 122 if (ctx->more) 123 err = crypto_ahash_finup(&ctx->req); 124 else 125 err = crypto_ahash_digest(&ctx->req); 126 } else { 127 if (!ctx->more) { 128 err = crypto_ahash_init(&ctx->req); 129 err = af_alg_wait_for_completion(err, &ctx->completion); 130 if (err) 131 goto unlock; 132 } 133 134 err = crypto_ahash_update(&ctx->req); 135 } 136 137 err = af_alg_wait_for_completion(err, &ctx->completion); 138 if (err) 139 goto unlock; 140 141 ctx->more = flags & MSG_MORE; 142 143unlock: 144 release_sock(sk); 145 146 return err ?: size; 147} 148 149static int hash_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, 150 int flags) 151{ 152 struct sock *sk = sock->sk; 153 struct alg_sock *ask = alg_sk(sk); 154 struct hash_ctx *ctx = ask->private; 155 unsigned ds = crypto_ahash_digestsize(crypto_ahash_reqtfm(&ctx->req)); 156 int err; 157 158 if (len > ds) 159 len = ds; 160 else if (len < ds) 161 msg->msg_flags |= MSG_TRUNC; 162 163 lock_sock(sk); 164 if (ctx->more) { 165 ctx->more = 0; 166 ahash_request_set_crypt(&ctx->req, NULL, ctx->result, 0); 167 err = af_alg_wait_for_completion(crypto_ahash_final(&ctx->req), 168 &ctx->completion); 169 if (err) 170 goto unlock; 171 } 172 173 err = memcpy_to_msg(msg, ctx->result, len); 174 175unlock: 176 release_sock(sk); 177 178 return err ?: len; 179} 180 181static int hash_accept(struct socket *sock, struct socket *newsock, int flags) 182{ 183 struct sock *sk = sock->sk; 184 struct alg_sock *ask = alg_sk(sk); 185 struct hash_ctx *ctx = ask->private; 186 struct ahash_request *req = &ctx->req; 187 char state[crypto_ahash_statesize(crypto_ahash_reqtfm(req))]; 188 struct sock *sk2; 189 struct alg_sock *ask2; 190 struct hash_ctx *ctx2; 191 int err; 192 193 err = crypto_ahash_export(req, state); 194 if (err) 195 return err; 196 197 err = af_alg_accept(ask->parent, newsock); 198 if (err) 199 return err; 200 201 sk2 = newsock->sk; 202 ask2 = alg_sk(sk2); 203 ctx2 = ask2->private; 204 ctx2->more = 1; 205 206 err = crypto_ahash_import(&ctx2->req, state); 207 if (err) { 208 sock_orphan(sk2); 209 sock_put(sk2); 210 } 211 212 return err; 213} 214 215static struct proto_ops algif_hash_ops = { 216 .family = PF_ALG, 217 218 .connect = sock_no_connect, 219 .socketpair = sock_no_socketpair, 220 .getname = sock_no_getname, 221 .ioctl = sock_no_ioctl, 222 .listen = sock_no_listen, 223 .shutdown = sock_no_shutdown, 224 .getsockopt = sock_no_getsockopt, 225 .mmap = sock_no_mmap, 226 .bind = sock_no_bind, 227 .setsockopt = sock_no_setsockopt, 228 .poll = sock_no_poll, 229 230 .release = af_alg_release, 231 .sendmsg = hash_sendmsg, 232 .sendpage = hash_sendpage, 233 .recvmsg = hash_recvmsg, 234 .accept = hash_accept, 235}; 236 237static int hash_check_key(struct socket *sock) 238{ 239 int err = 0; 240 struct sock *psk; 241 struct alg_sock *pask; 242 struct algif_hash_tfm *tfm; 243 struct sock *sk = sock->sk; 244 struct alg_sock *ask = alg_sk(sk); 245 246 lock_sock(sk); 247 if (ask->refcnt) 248 goto unlock_child; 249 250 psk = ask->parent; 251 pask = alg_sk(ask->parent); 252 tfm = pask->private; 253 254 err = -ENOKEY; 255 lock_sock_nested(psk, SINGLE_DEPTH_NESTING); 256 if (!tfm->has_key) 257 goto unlock; 258 259 if (!pask->refcnt++) 260 sock_hold(psk); 261 262 ask->refcnt = 1; 263 sock_put(psk); 264 265 err = 0; 266 267unlock: 268 release_sock(psk); 269unlock_child: 270 release_sock(sk); 271 272 return err; 273} 274 275static int hash_sendmsg_nokey(struct socket *sock, struct msghdr *msg, 276 size_t size) 277{ 278 int err; 279 280 err = hash_check_key(sock); 281 if (err) 282 return err; 283 284 return hash_sendmsg(sock, msg, size); 285} 286 287static ssize_t hash_sendpage_nokey(struct socket *sock, struct page *page, 288 int offset, size_t size, int flags) 289{ 290 int err; 291 292 err = hash_check_key(sock); 293 if (err) 294 return err; 295 296 return hash_sendpage(sock, page, offset, size, flags); 297} 298 299static int hash_recvmsg_nokey(struct socket *sock, struct msghdr *msg, 300 size_t ignored, int flags) 301{ 302 int err; 303 304 err = hash_check_key(sock); 305 if (err) 306 return err; 307 308 return hash_recvmsg(sock, msg, ignored, flags); 309} 310 311static int hash_accept_nokey(struct socket *sock, struct socket *newsock, 312 int flags) 313{ 314 int err; 315 316 err = hash_check_key(sock); 317 if (err) 318 return err; 319 320 return hash_accept(sock, newsock, flags); 321} 322 323static struct proto_ops algif_hash_ops_nokey = { 324 .family = PF_ALG, 325 326 .connect = sock_no_connect, 327 .socketpair = sock_no_socketpair, 328 .getname = sock_no_getname, 329 .ioctl = sock_no_ioctl, 330 .listen = sock_no_listen, 331 .shutdown = sock_no_shutdown, 332 .getsockopt = sock_no_getsockopt, 333 .mmap = sock_no_mmap, 334 .bind = sock_no_bind, 335 .setsockopt = sock_no_setsockopt, 336 .poll = sock_no_poll, 337 338 .release = af_alg_release, 339 .sendmsg = hash_sendmsg_nokey, 340 .sendpage = hash_sendpage_nokey, 341 .recvmsg = hash_recvmsg_nokey, 342 .accept = hash_accept_nokey, 343}; 344 345static void *hash_bind(const char *name, u32 type, u32 mask) 346{ 347 struct algif_hash_tfm *tfm; 348 struct crypto_ahash *hash; 349 350 tfm = kzalloc(sizeof(*tfm), GFP_KERNEL); 351 if (!tfm) 352 return ERR_PTR(-ENOMEM); 353 354 hash = crypto_alloc_ahash(name, type, mask); 355 if (IS_ERR(hash)) { 356 kfree(tfm); 357 return ERR_CAST(hash); 358 } 359 360 tfm->hash = hash; 361 362 return tfm; 363} 364 365static void hash_release(void *private) 366{ 367 struct algif_hash_tfm *tfm = private; 368 369 crypto_free_ahash(tfm->hash); 370 kfree(tfm); 371} 372 373static int hash_setkey(void *private, const u8 *key, unsigned int keylen) 374{ 375 struct algif_hash_tfm *tfm = private; 376 int err; 377 378 err = crypto_ahash_setkey(tfm->hash, key, keylen); 379 tfm->has_key = !err; 380 381 return err; 382} 383 384static void hash_sock_destruct(struct sock *sk) 385{ 386 struct alg_sock *ask = alg_sk(sk); 387 struct hash_ctx *ctx = ask->private; 388 389 sock_kzfree_s(sk, ctx->result, 390 crypto_ahash_digestsize(crypto_ahash_reqtfm(&ctx->req))); 391 sock_kfree_s(sk, ctx, ctx->len); 392 af_alg_release_parent(sk); 393} 394 395static int hash_accept_parent_nokey(void *private, struct sock *sk) 396{ 397 struct hash_ctx *ctx; 398 struct alg_sock *ask = alg_sk(sk); 399 struct algif_hash_tfm *tfm = private; 400 struct crypto_ahash *hash = tfm->hash; 401 unsigned len = sizeof(*ctx) + crypto_ahash_reqsize(hash); 402 unsigned ds = crypto_ahash_digestsize(hash); 403 404 ctx = sock_kmalloc(sk, len, GFP_KERNEL); 405 if (!ctx) 406 return -ENOMEM; 407 408 ctx->result = sock_kmalloc(sk, ds, GFP_KERNEL); 409 if (!ctx->result) { 410 sock_kfree_s(sk, ctx, len); 411 return -ENOMEM; 412 } 413 414 memset(ctx->result, 0, ds); 415 416 ctx->len = len; 417 ctx->more = 0; 418 af_alg_init_completion(&ctx->completion); 419 420 ask->private = ctx; 421 422 ahash_request_set_tfm(&ctx->req, hash); 423 ahash_request_set_callback(&ctx->req, CRYPTO_TFM_REQ_MAY_BACKLOG, 424 af_alg_complete, &ctx->completion); 425 426 sk->sk_destruct = hash_sock_destruct; 427 428 return 0; 429} 430 431static int hash_accept_parent(void *private, struct sock *sk) 432{ 433 struct algif_hash_tfm *tfm = private; 434 435 if (!tfm->has_key && crypto_ahash_has_setkey(tfm->hash)) 436 return -ENOKEY; 437 438 return hash_accept_parent_nokey(private, sk); 439} 440 441static const struct af_alg_type algif_type_hash = { 442 .bind = hash_bind, 443 .release = hash_release, 444 .setkey = hash_setkey, 445 .accept = hash_accept_parent, 446 .accept_nokey = hash_accept_parent_nokey, 447 .ops = &algif_hash_ops, 448 .ops_nokey = &algif_hash_ops_nokey, 449 .name = "hash", 450 .owner = THIS_MODULE 451}; 452 453static int __init algif_hash_init(void) 454{ 455 return af_alg_register_type(&algif_type_hash); 456} 457 458static void __exit algif_hash_exit(void) 459{ 460 int err = af_alg_unregister_type(&algif_type_hash); 461 BUG_ON(err); 462} 463 464module_init(algif_hash_init); 465module_exit(algif_hash_exit); 466MODULE_LICENSE("GPL"); 467