.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * af_alg: User-space algorithm interface |
---|
3 | 4 | * |
---|
4 | 5 | * This file provides the user-space API for algorithms. |
---|
5 | 6 | * |
---|
6 | 7 | * 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 | 8 | */ |
---|
14 | 9 | |
---|
15 | 10 | #include <linux/atomic.h> |
---|
.. | .. |
---|
21 | 16 | #include <linux/module.h> |
---|
22 | 17 | #include <linux/net.h> |
---|
23 | 18 | #include <linux/rwsem.h> |
---|
| 19 | +#include <linux/sched.h> |
---|
24 | 20 | #include <linux/sched/signal.h> |
---|
25 | 21 | #include <linux/security.h> |
---|
26 | 22 | |
---|
.. | .. |
---|
174 | 170 | sa->salg_name[addr_len - sizeof(*sa) - 1] = 0; |
---|
175 | 171 | |
---|
176 | 172 | type = alg_get_type(sa->salg_type); |
---|
177 | | - if (IS_ERR(type) && PTR_ERR(type) == -ENOENT) { |
---|
| 173 | + if (PTR_ERR(type) == -ENOENT) { |
---|
178 | 174 | request_module("algif-%s", sa->salg_type); |
---|
179 | 175 | type = alg_get_type(sa->salg_type); |
---|
180 | 176 | } |
---|
.. | .. |
---|
206 | 202 | return err; |
---|
207 | 203 | } |
---|
208 | 204 | |
---|
209 | | -static int alg_setkey(struct sock *sk, char __user *ukey, |
---|
210 | | - unsigned int keylen) |
---|
| 205 | +static int alg_setkey(struct sock *sk, sockptr_t ukey, unsigned int keylen) |
---|
211 | 206 | { |
---|
212 | 207 | struct alg_sock *ask = alg_sk(sk); |
---|
213 | 208 | const struct af_alg_type *type = ask->type; |
---|
.. | .. |
---|
219 | 214 | return -ENOMEM; |
---|
220 | 215 | |
---|
221 | 216 | err = -EFAULT; |
---|
222 | | - if (copy_from_user(key, ukey, keylen)) |
---|
| 217 | + if (copy_from_sockptr(key, ukey, keylen)) |
---|
223 | 218 | goto out; |
---|
224 | 219 | |
---|
225 | 220 | err = type->setkey(ask->private, key, keylen); |
---|
.. | .. |
---|
231 | 226 | } |
---|
232 | 227 | |
---|
233 | 228 | static int alg_setsockopt(struct socket *sock, int level, int optname, |
---|
234 | | - char __user *optval, unsigned int optlen) |
---|
| 229 | + sockptr_t optval, unsigned int optlen) |
---|
235 | 230 | { |
---|
236 | 231 | struct sock *sk = sock->sk; |
---|
237 | 232 | struct alg_sock *ask = alg_sk(sk); |
---|
.. | .. |
---|
263 | 258 | if (!type->setauthsize) |
---|
264 | 259 | goto unlock; |
---|
265 | 260 | err = type->setauthsize(ask->private, optlen); |
---|
| 261 | + break; |
---|
| 262 | + case ALG_SET_DRBG_ENTROPY: |
---|
| 263 | + if (sock->state == SS_CONNECTED) |
---|
| 264 | + goto unlock; |
---|
| 265 | + if (!type->setentropy) |
---|
| 266 | + goto unlock; |
---|
| 267 | + |
---|
| 268 | + err = type->setentropy(ask->private, optval, optlen); |
---|
266 | 269 | } |
---|
267 | 270 | |
---|
268 | 271 | unlock: |
---|
.. | .. |
---|
295 | 298 | security_sock_graft(sk2, newsock); |
---|
296 | 299 | security_sk_clone(sk, sk2); |
---|
297 | 300 | |
---|
| 301 | + /* |
---|
| 302 | + * newsock->ops assigned here to allow type->accept call to override |
---|
| 303 | + * them when required. |
---|
| 304 | + */ |
---|
| 305 | + newsock->ops = type->ops; |
---|
298 | 306 | err = type->accept(ask->private, sk2); |
---|
299 | 307 | |
---|
300 | 308 | nokey = err == -ENOKEY; |
---|
.. | .. |
---|
303 | 311 | |
---|
304 | 312 | if (err) |
---|
305 | 313 | goto unlock; |
---|
306 | | - |
---|
307 | | - sk2->sk_family = PF_ALG; |
---|
308 | 314 | |
---|
309 | 315 | if (atomic_inc_return_relaxed(&ask->refcnt) == 1) |
---|
310 | 316 | sock_hold(sk); |
---|
.. | .. |
---|
315 | 321 | alg_sk(sk2)->parent = sk; |
---|
316 | 322 | alg_sk(sk2)->type = type; |
---|
317 | 323 | |
---|
318 | | - newsock->ops = type->ops; |
---|
319 | 324 | newsock->state = SS_CONNECTED; |
---|
320 | 325 | |
---|
321 | 326 | if (nokey) |
---|
.. | .. |
---|
346 | 351 | .ioctl = sock_no_ioctl, |
---|
347 | 352 | .listen = sock_no_listen, |
---|
348 | 353 | .shutdown = sock_no_shutdown, |
---|
349 | | - .getsockopt = sock_no_getsockopt, |
---|
350 | 354 | .mmap = sock_no_mmap, |
---|
351 | 355 | .sendpage = sock_no_sendpage, |
---|
352 | 356 | .sendmsg = sock_no_sendmsg, |
---|
.. | .. |
---|
384 | 388 | sock->ops = &alg_proto_ops; |
---|
385 | 389 | sock_init_data(sock, sk); |
---|
386 | 390 | |
---|
387 | | - sk->sk_family = PF_ALG; |
---|
388 | 391 | sk->sk_destruct = alg_sock_destruct; |
---|
389 | 392 | |
---|
390 | 393 | return 0; |
---|
.. | .. |
---|
429 | 432 | } |
---|
430 | 433 | EXPORT_SYMBOL_GPL(af_alg_make_sg); |
---|
431 | 434 | |
---|
432 | | -void af_alg_link_sg(struct af_alg_sgl *sgl_prev, struct af_alg_sgl *sgl_new) |
---|
| 435 | +static void af_alg_link_sg(struct af_alg_sgl *sgl_prev, |
---|
| 436 | + struct af_alg_sgl *sgl_new) |
---|
433 | 437 | { |
---|
434 | 438 | sg_unmark_end(sgl_prev->sg + sgl_prev->npages - 1); |
---|
435 | 439 | sg_chain(sgl_prev->sg, sgl_prev->npages + 1, sgl_new->sg); |
---|
436 | 440 | } |
---|
437 | | -EXPORT_SYMBOL_GPL(af_alg_link_sg); |
---|
438 | 441 | |
---|
439 | 442 | void af_alg_free_sg(struct af_alg_sgl *sgl) |
---|
440 | 443 | { |
---|
.. | .. |
---|
445 | 448 | } |
---|
446 | 449 | EXPORT_SYMBOL_GPL(af_alg_free_sg); |
---|
447 | 450 | |
---|
448 | | -int af_alg_cmsg_send(struct msghdr *msg, struct af_alg_control *con) |
---|
| 451 | +static int af_alg_cmsg_send(struct msghdr *msg, struct af_alg_control *con) |
---|
449 | 452 | { |
---|
450 | 453 | struct cmsghdr *cmsg; |
---|
451 | 454 | |
---|
.. | .. |
---|
484 | 487 | |
---|
485 | 488 | return 0; |
---|
486 | 489 | } |
---|
487 | | -EXPORT_SYMBOL_GPL(af_alg_cmsg_send); |
---|
488 | 490 | |
---|
489 | 491 | /** |
---|
490 | 492 | * af_alg_alloc_tsgl - allocate the TX SGL |
---|
.. | .. |
---|
492 | 494 | * @sk socket of connection to user space |
---|
493 | 495 | * @return: 0 upon success, < 0 upon error |
---|
494 | 496 | */ |
---|
495 | | -int af_alg_alloc_tsgl(struct sock *sk) |
---|
| 497 | +static int af_alg_alloc_tsgl(struct sock *sk) |
---|
496 | 498 | { |
---|
497 | 499 | struct alg_sock *ask = alg_sk(sk); |
---|
498 | 500 | struct af_alg_ctx *ctx = ask->private; |
---|
.. | .. |
---|
521 | 523 | |
---|
522 | 524 | return 0; |
---|
523 | 525 | } |
---|
524 | | -EXPORT_SYMBOL_GPL(af_alg_alloc_tsgl); |
---|
525 | 526 | |
---|
526 | 527 | /** |
---|
527 | 528 | * aead_count_tsgl - Count number of TX SG entries |
---|
.. | .. |
---|
536 | 537 | */ |
---|
537 | 538 | unsigned int af_alg_count_tsgl(struct sock *sk, size_t bytes, size_t offset) |
---|
538 | 539 | { |
---|
539 | | - struct alg_sock *ask = alg_sk(sk); |
---|
540 | | - struct af_alg_ctx *ctx = ask->private; |
---|
541 | | - struct af_alg_tsgl *sgl, *tmp; |
---|
| 540 | + const struct alg_sock *ask = alg_sk(sk); |
---|
| 541 | + const struct af_alg_ctx *ctx = ask->private; |
---|
| 542 | + const struct af_alg_tsgl *sgl; |
---|
542 | 543 | unsigned int i; |
---|
543 | 544 | unsigned int sgl_count = 0; |
---|
544 | 545 | |
---|
545 | 546 | if (!bytes) |
---|
546 | 547 | return 0; |
---|
547 | 548 | |
---|
548 | | - list_for_each_entry_safe(sgl, tmp, &ctx->tsgl_list, list) { |
---|
549 | | - struct scatterlist *sg = sgl->sg; |
---|
| 549 | + list_for_each_entry(sgl, &ctx->tsgl_list, list) { |
---|
| 550 | + const struct scatterlist *sg = sgl->sg; |
---|
550 | 551 | |
---|
551 | 552 | for (i = 0; i < sgl->cur; i++) { |
---|
552 | 553 | size_t bytes_count; |
---|
.. | .. |
---|
644 | 645 | } |
---|
645 | 646 | |
---|
646 | 647 | list_del(&sgl->list); |
---|
647 | | - sock_kfree_s(sk, sgl, sizeof(*sgl) + sizeof(sgl->sg[0]) * |
---|
648 | | - (MAX_SGL_ENTS + 1)); |
---|
| 648 | + sock_kfree_s(sk, sgl, struct_size(sgl, sg, MAX_SGL_ENTS + 1)); |
---|
649 | 649 | } |
---|
650 | 650 | |
---|
651 | 651 | if (!ctx->used) |
---|
652 | 652 | ctx->merge = 0; |
---|
| 653 | + ctx->init = ctx->more; |
---|
653 | 654 | } |
---|
654 | 655 | EXPORT_SYMBOL_GPL(af_alg_pull_tsgl); |
---|
655 | 656 | |
---|
.. | .. |
---|
658 | 659 | * |
---|
659 | 660 | * @areq Request holding the TX and RX SGL |
---|
660 | 661 | */ |
---|
661 | | -void af_alg_free_areq_sgls(struct af_alg_async_req *areq) |
---|
| 662 | +static void af_alg_free_areq_sgls(struct af_alg_async_req *areq) |
---|
662 | 663 | { |
---|
663 | 664 | struct sock *sk = areq->sk; |
---|
664 | 665 | struct alg_sock *ask = alg_sk(sk); |
---|
.. | .. |
---|
687 | 688 | sock_kfree_s(sk, tsgl, areq->tsgl_entries * sizeof(*tsgl)); |
---|
688 | 689 | } |
---|
689 | 690 | } |
---|
690 | | -EXPORT_SYMBOL_GPL(af_alg_free_areq_sgls); |
---|
691 | 691 | |
---|
692 | 692 | /** |
---|
693 | 693 | * af_alg_wait_for_wmem - wait for availability of writable memory |
---|
.. | .. |
---|
696 | 696 | * @flags If MSG_DONTWAIT is set, then only report if function would sleep |
---|
697 | 697 | * @return 0 when writable memory is available, < 0 upon error |
---|
698 | 698 | */ |
---|
699 | | -int af_alg_wait_for_wmem(struct sock *sk, unsigned int flags) |
---|
| 699 | +static int af_alg_wait_for_wmem(struct sock *sk, unsigned int flags) |
---|
700 | 700 | { |
---|
701 | 701 | DEFINE_WAIT_FUNC(wait, woken_wake_function); |
---|
702 | 702 | int err = -ERESTARTSYS; |
---|
.. | .. |
---|
721 | 721 | |
---|
722 | 722 | return err; |
---|
723 | 723 | } |
---|
724 | | -EXPORT_SYMBOL_GPL(af_alg_wait_for_wmem); |
---|
725 | 724 | |
---|
726 | 725 | /** |
---|
727 | 726 | * af_alg_wmem_wakeup - wakeup caller when writable memory is available |
---|
.. | .. |
---|
751 | 750 | * |
---|
752 | 751 | * @sk socket of connection to user space |
---|
753 | 752 | * @flags If MSG_DONTWAIT is set, then only report if function would sleep |
---|
| 753 | + * @min Set to minimum request size if partial requests are allowed. |
---|
754 | 754 | * @return 0 when writable memory is available, < 0 upon error |
---|
755 | 755 | */ |
---|
756 | | -int af_alg_wait_for_data(struct sock *sk, unsigned flags) |
---|
| 756 | +int af_alg_wait_for_data(struct sock *sk, unsigned flags, unsigned min) |
---|
757 | 757 | { |
---|
758 | 758 | DEFINE_WAIT_FUNC(wait, woken_wake_function); |
---|
759 | 759 | struct alg_sock *ask = alg_sk(sk); |
---|
.. | .. |
---|
771 | 771 | if (signal_pending(current)) |
---|
772 | 772 | break; |
---|
773 | 773 | timeout = MAX_SCHEDULE_TIMEOUT; |
---|
774 | | - if (sk_wait_event(sk, &timeout, (ctx->used || !ctx->more), |
---|
| 774 | + if (sk_wait_event(sk, &timeout, |
---|
| 775 | + ctx->init && (!ctx->more || |
---|
| 776 | + (min && ctx->used >= min)), |
---|
775 | 777 | &wait)) { |
---|
776 | 778 | err = 0; |
---|
777 | 779 | break; |
---|
.. | .. |
---|
790 | 792 | * |
---|
791 | 793 | * @sk socket of connection to user space |
---|
792 | 794 | */ |
---|
793 | | - |
---|
794 | | -void af_alg_data_wakeup(struct sock *sk) |
---|
| 795 | +static void af_alg_data_wakeup(struct sock *sk) |
---|
795 | 796 | { |
---|
796 | 797 | struct alg_sock *ask = alg_sk(sk); |
---|
797 | 798 | struct af_alg_ctx *ctx = ask->private; |
---|
.. | .. |
---|
809 | 810 | sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT); |
---|
810 | 811 | rcu_read_unlock(); |
---|
811 | 812 | } |
---|
812 | | -EXPORT_SYMBOL_GPL(af_alg_data_wakeup); |
---|
813 | 813 | |
---|
814 | 814 | /** |
---|
815 | 815 | * af_alg_sendmsg - implementation of sendmsg system call handler |
---|
.. | .. |
---|
836 | 836 | struct af_alg_tsgl *sgl; |
---|
837 | 837 | struct af_alg_control con = {}; |
---|
838 | 838 | long copied = 0; |
---|
839 | | - bool enc = 0; |
---|
840 | | - bool init = 0; |
---|
| 839 | + bool enc = false; |
---|
| 840 | + bool init = false; |
---|
841 | 841 | int err = 0; |
---|
842 | 842 | |
---|
843 | 843 | if (msg->msg_controllen) { |
---|
.. | .. |
---|
845 | 845 | if (err) |
---|
846 | 846 | return err; |
---|
847 | 847 | |
---|
848 | | - init = 1; |
---|
| 848 | + init = true; |
---|
849 | 849 | switch (con.op) { |
---|
850 | 850 | case ALG_OP_ENCRYPT: |
---|
851 | | - enc = 1; |
---|
| 851 | + enc = true; |
---|
852 | 852 | break; |
---|
853 | 853 | case ALG_OP_DECRYPT: |
---|
854 | | - enc = 0; |
---|
| 854 | + enc = false; |
---|
855 | 855 | break; |
---|
856 | 856 | default: |
---|
857 | 857 | return -EINVAL; |
---|
.. | .. |
---|
862 | 862 | } |
---|
863 | 863 | |
---|
864 | 864 | lock_sock(sk); |
---|
865 | | - if (!ctx->more && ctx->used) { |
---|
866 | | - err = -EINVAL; |
---|
867 | | - goto unlock; |
---|
| 865 | + if (ctx->init && !ctx->more) { |
---|
| 866 | + if (ctx->used) { |
---|
| 867 | + err = -EINVAL; |
---|
| 868 | + goto unlock; |
---|
| 869 | + } |
---|
| 870 | + |
---|
| 871 | + pr_info_once( |
---|
| 872 | + "%s sent an empty control message without MSG_MORE.\n", |
---|
| 873 | + current->comm); |
---|
868 | 874 | } |
---|
| 875 | + ctx->init = true; |
---|
869 | 876 | |
---|
870 | 877 | if (init) { |
---|
871 | 878 | ctx->enc = enc; |
---|