.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * NET An implementation of the SOCKET network access protocol. |
---|
3 | 4 | * |
---|
.. | .. |
---|
45 | 46 | * Tigran Aivazian : Made listen(2) backlog sanity checks |
---|
46 | 47 | * protocol-independent |
---|
47 | 48 | * |
---|
48 | | - * |
---|
49 | | - * This program is free software; you can redistribute it and/or |
---|
50 | | - * modify it under the terms of the GNU General Public License |
---|
51 | | - * as published by the Free Software Foundation; either version |
---|
52 | | - * 2 of the License, or (at your option) any later version. |
---|
53 | | - * |
---|
54 | | - * |
---|
55 | 49 | * This module is effectively the top level interface to the BSD socket |
---|
56 | 50 | * paradigm. |
---|
57 | 51 | * |
---|
.. | .. |
---|
79 | 73 | #include <linux/module.h> |
---|
80 | 74 | #include <linux/highmem.h> |
---|
81 | 75 | #include <linux/mount.h> |
---|
| 76 | +#include <linux/pseudo_fs.h> |
---|
82 | 77 | #include <linux/security.h> |
---|
83 | 78 | #include <linux/syscalls.h> |
---|
84 | 79 | #include <linux/compat.h> |
---|
.. | .. |
---|
90 | 85 | #include <linux/slab.h> |
---|
91 | 86 | #include <linux/xattr.h> |
---|
92 | 87 | #include <linux/nospec.h> |
---|
| 88 | +#include <linux/indirect_call_wrapper.h> |
---|
93 | 89 | |
---|
94 | 90 | #include <linux/uaccess.h> |
---|
95 | 91 | #include <asm/unistd.h> |
---|
.. | .. |
---|
104 | 100 | #include <linux/if_tun.h> |
---|
105 | 101 | #include <linux/ipv6_route.h> |
---|
106 | 102 | #include <linux/route.h> |
---|
| 103 | +#include <linux/termios.h> |
---|
107 | 104 | #include <linux/sockios.h> |
---|
108 | 105 | #include <net/busy_poll.h> |
---|
109 | 106 | #include <linux/errqueue.h> |
---|
.. | .. |
---|
132 | 129 | struct pipe_inode_info *pipe, size_t len, |
---|
133 | 130 | unsigned int flags); |
---|
134 | 131 | |
---|
| 132 | +#ifdef CONFIG_PROC_FS |
---|
| 133 | +static void sock_show_fdinfo(struct seq_file *m, struct file *f) |
---|
| 134 | +{ |
---|
| 135 | + struct socket *sock = f->private_data; |
---|
| 136 | + |
---|
| 137 | + if (sock->ops->show_fdinfo) |
---|
| 138 | + sock->ops->show_fdinfo(m, sock); |
---|
| 139 | +} |
---|
| 140 | +#else |
---|
| 141 | +#define sock_show_fdinfo NULL |
---|
| 142 | +#endif |
---|
| 143 | + |
---|
135 | 144 | /* |
---|
136 | 145 | * Socket files have a set of 'special' operations as well as the generic file ones. These don't appear |
---|
137 | 146 | * in the operation structures but are done directly via the socketcall() multiplexor. |
---|
.. | .. |
---|
153 | 162 | .sendpage = sock_sendpage, |
---|
154 | 163 | .splice_write = generic_splice_sendpage, |
---|
155 | 164 | .splice_read = sock_splice_read, |
---|
| 165 | + .show_fdinfo = sock_show_fdinfo, |
---|
156 | 166 | }; |
---|
157 | 167 | |
---|
158 | 168 | /* |
---|
.. | .. |
---|
239 | 249 | static struct inode *sock_alloc_inode(struct super_block *sb) |
---|
240 | 250 | { |
---|
241 | 251 | struct socket_alloc *ei; |
---|
242 | | - struct socket_wq *wq; |
---|
243 | 252 | |
---|
244 | 253 | ei = kmem_cache_alloc(sock_inode_cachep, GFP_KERNEL); |
---|
245 | 254 | if (!ei) |
---|
246 | 255 | return NULL; |
---|
247 | | - wq = kmalloc(sizeof(*wq), GFP_KERNEL); |
---|
248 | | - if (!wq) { |
---|
249 | | - kmem_cache_free(sock_inode_cachep, ei); |
---|
250 | | - return NULL; |
---|
251 | | - } |
---|
252 | | - init_waitqueue_head(&wq->wait); |
---|
253 | | - wq->fasync_list = NULL; |
---|
254 | | - wq->flags = 0; |
---|
255 | | - ei->socket.wq = wq; |
---|
| 256 | + init_waitqueue_head(&ei->socket.wq.wait); |
---|
| 257 | + ei->socket.wq.fasync_list = NULL; |
---|
| 258 | + ei->socket.wq.flags = 0; |
---|
256 | 259 | |
---|
257 | 260 | ei->socket.state = SS_UNCONNECTED; |
---|
258 | 261 | ei->socket.flags = 0; |
---|
.. | .. |
---|
263 | 266 | return &ei->vfs_inode; |
---|
264 | 267 | } |
---|
265 | 268 | |
---|
266 | | -static void sock_destroy_inode(struct inode *inode) |
---|
| 269 | +static void sock_free_inode(struct inode *inode) |
---|
267 | 270 | { |
---|
268 | 271 | struct socket_alloc *ei; |
---|
269 | 272 | |
---|
270 | 273 | ei = container_of(inode, struct socket_alloc, vfs_inode); |
---|
271 | | - kfree_rcu(ei->socket.wq, rcu); |
---|
272 | 274 | kmem_cache_free(sock_inode_cachep, ei); |
---|
273 | 275 | } |
---|
274 | 276 | |
---|
.. | .. |
---|
293 | 295 | |
---|
294 | 296 | static const struct super_operations sockfs_ops = { |
---|
295 | 297 | .alloc_inode = sock_alloc_inode, |
---|
296 | | - .destroy_inode = sock_destroy_inode, |
---|
| 298 | + .free_inode = sock_free_inode, |
---|
297 | 299 | .statfs = simple_statfs, |
---|
298 | 300 | }; |
---|
299 | 301 | |
---|
.. | .. |
---|
312 | 314 | |
---|
313 | 315 | static int sockfs_xattr_get(const struct xattr_handler *handler, |
---|
314 | 316 | struct dentry *dentry, struct inode *inode, |
---|
315 | | - const char *suffix, void *value, size_t size) |
---|
| 317 | + const char *suffix, void *value, size_t size, |
---|
| 318 | + int flags) |
---|
316 | 319 | { |
---|
317 | 320 | if (value) { |
---|
318 | 321 | if (dentry->d_name.len + 1 > size) |
---|
.. | .. |
---|
351 | 354 | NULL |
---|
352 | 355 | }; |
---|
353 | 356 | |
---|
354 | | -static struct dentry *sockfs_mount(struct file_system_type *fs_type, |
---|
355 | | - int flags, const char *dev_name, void *data) |
---|
| 357 | +static int sockfs_init_fs_context(struct fs_context *fc) |
---|
356 | 358 | { |
---|
357 | | - return mount_pseudo_xattr(fs_type, "socket:", &sockfs_ops, |
---|
358 | | - sockfs_xattr_handlers, |
---|
359 | | - &sockfs_dentry_operations, SOCKFS_MAGIC); |
---|
| 359 | + struct pseudo_fs_context *ctx = init_pseudo(fc, SOCKFS_MAGIC); |
---|
| 360 | + if (!ctx) |
---|
| 361 | + return -ENOMEM; |
---|
| 362 | + ctx->ops = &sockfs_ops; |
---|
| 363 | + ctx->dops = &sockfs_dentry_operations; |
---|
| 364 | + ctx->xattr = sockfs_xattr_handlers; |
---|
| 365 | + return 0; |
---|
360 | 366 | } |
---|
361 | 367 | |
---|
362 | 368 | static struct vfsmount *sock_mnt __read_mostly; |
---|
363 | 369 | |
---|
364 | 370 | static struct file_system_type sock_fs_type = { |
---|
365 | 371 | .name = "sockfs", |
---|
366 | | - .mount = sockfs_mount, |
---|
| 372 | + .init_fs_context = sockfs_init_fs_context, |
---|
367 | 373 | .kill_sb = kill_anon_super, |
---|
368 | 374 | }; |
---|
369 | 375 | |
---|
.. | .. |
---|
413 | 419 | |
---|
414 | 420 | sock->file = file; |
---|
415 | 421 | file->private_data = sock; |
---|
| 422 | + stream_open(SOCK_INODE(sock), file); |
---|
416 | 423 | return file; |
---|
417 | 424 | } |
---|
418 | 425 | EXPORT_SYMBOL(sock_alloc_file); |
---|
.. | .. |
---|
427 | 434 | } |
---|
428 | 435 | |
---|
429 | 436 | newfile = sock_alloc_file(sock, flags, NULL); |
---|
430 | | - if (likely(!IS_ERR(newfile))) { |
---|
| 437 | + if (!IS_ERR(newfile)) { |
---|
431 | 438 | fd_install(fd, newfile); |
---|
432 | 439 | return fd; |
---|
433 | 440 | } |
---|
.. | .. |
---|
580 | 587 | } |
---|
581 | 588 | EXPORT_SYMBOL(sock_alloc); |
---|
582 | 589 | |
---|
583 | | -/** |
---|
584 | | - * sock_release - close a socket |
---|
585 | | - * @sock: socket to close |
---|
586 | | - * |
---|
587 | | - * The socket is released from the protocol stack if it has a release |
---|
588 | | - * callback, and the inode is then released if the socket is bound to |
---|
589 | | - * an inode not a file. |
---|
590 | | - */ |
---|
591 | | - |
---|
592 | 590 | static void __sock_release(struct socket *sock, struct inode *inode) |
---|
593 | 591 | { |
---|
594 | 592 | if (sock->ops) { |
---|
.. | .. |
---|
604 | 602 | module_put(owner); |
---|
605 | 603 | } |
---|
606 | 604 | |
---|
607 | | - if (sock->wq->fasync_list) |
---|
| 605 | + if (sock->wq.fasync_list) |
---|
608 | 606 | pr_err("%s: fasync list not empty!\n", __func__); |
---|
609 | 607 | |
---|
610 | 608 | if (!sock->file) { |
---|
.. | .. |
---|
614 | 612 | sock->file = NULL; |
---|
615 | 613 | } |
---|
616 | 614 | |
---|
| 615 | +/** |
---|
| 616 | + * sock_release - close a socket |
---|
| 617 | + * @sock: socket to close |
---|
| 618 | + * |
---|
| 619 | + * The socket is released from the protocol stack if it has a release |
---|
| 620 | + * callback, and the inode is then released if the socket is bound to |
---|
| 621 | + * an inode not a file. |
---|
| 622 | + */ |
---|
617 | 623 | void sock_release(struct socket *sock) |
---|
618 | 624 | { |
---|
619 | 625 | __sock_release(sock, NULL); |
---|
.. | .. |
---|
637 | 643 | } |
---|
638 | 644 | EXPORT_SYMBOL(__sock_tx_timestamp); |
---|
639 | 645 | |
---|
| 646 | +INDIRECT_CALLABLE_DECLARE(int inet_sendmsg(struct socket *, struct msghdr *, |
---|
| 647 | + size_t)); |
---|
| 648 | +INDIRECT_CALLABLE_DECLARE(int inet6_sendmsg(struct socket *, struct msghdr *, |
---|
| 649 | + size_t)); |
---|
| 650 | +static inline int sock_sendmsg_nosec(struct socket *sock, struct msghdr *msg) |
---|
| 651 | +{ |
---|
| 652 | + int ret = INDIRECT_CALL_INET(sock->ops->sendmsg, inet6_sendmsg, |
---|
| 653 | + inet_sendmsg, sock, msg, |
---|
| 654 | + msg_data_left(msg)); |
---|
| 655 | + BUG_ON(ret == -EIOCBQUEUED); |
---|
| 656 | + return ret; |
---|
| 657 | +} |
---|
| 658 | + |
---|
| 659 | +static int __sock_sendmsg(struct socket *sock, struct msghdr *msg) |
---|
| 660 | +{ |
---|
| 661 | + int err = security_socket_sendmsg(sock, msg, |
---|
| 662 | + msg_data_left(msg)); |
---|
| 663 | + |
---|
| 664 | + return err ?: sock_sendmsg_nosec(sock, msg); |
---|
| 665 | +} |
---|
| 666 | + |
---|
640 | 667 | /** |
---|
641 | 668 | * sock_sendmsg - send a message through @sock |
---|
642 | 669 | * @sock: socket |
---|
.. | .. |
---|
645 | 672 | * Sends @msg through @sock, passing through LSM. |
---|
646 | 673 | * Returns the number of bytes sent, or an error code. |
---|
647 | 674 | */ |
---|
648 | | - |
---|
649 | | -static inline int sock_sendmsg_nosec(struct socket *sock, struct msghdr *msg) |
---|
650 | | -{ |
---|
651 | | - int ret = sock->ops->sendmsg(sock, msg, msg_data_left(msg)); |
---|
652 | | - BUG_ON(ret == -EIOCBQUEUED); |
---|
653 | | - return ret; |
---|
654 | | -} |
---|
655 | | - |
---|
656 | 675 | int sock_sendmsg(struct socket *sock, struct msghdr *msg) |
---|
657 | 676 | { |
---|
658 | | - int err = security_socket_sendmsg(sock, msg, |
---|
659 | | - msg_data_left(msg)); |
---|
| 677 | + struct sockaddr_storage *save_addr = (struct sockaddr_storage *)msg->msg_name; |
---|
| 678 | + struct sockaddr_storage address; |
---|
| 679 | + int ret; |
---|
660 | 680 | |
---|
661 | | - return err ?: sock_sendmsg_nosec(sock, msg); |
---|
| 681 | + if (msg->msg_name) { |
---|
| 682 | + memcpy(&address, msg->msg_name, msg->msg_namelen); |
---|
| 683 | + msg->msg_name = &address; |
---|
| 684 | + } |
---|
| 685 | + |
---|
| 686 | + ret = __sock_sendmsg(sock, msg); |
---|
| 687 | + msg->msg_name = save_addr; |
---|
| 688 | + |
---|
| 689 | + return ret; |
---|
662 | 690 | } |
---|
663 | 691 | EXPORT_SYMBOL(sock_sendmsg); |
---|
664 | 692 | |
---|
.. | .. |
---|
677 | 705 | int kernel_sendmsg(struct socket *sock, struct msghdr *msg, |
---|
678 | 706 | struct kvec *vec, size_t num, size_t size) |
---|
679 | 707 | { |
---|
680 | | - iov_iter_kvec(&msg->msg_iter, WRITE | ITER_KVEC, vec, num, size); |
---|
| 708 | + iov_iter_kvec(&msg->msg_iter, WRITE, vec, num, size); |
---|
681 | 709 | return sock_sendmsg(sock, msg); |
---|
682 | 710 | } |
---|
683 | 711 | EXPORT_SYMBOL(kernel_sendmsg); |
---|
.. | .. |
---|
703 | 731 | if (!sock->ops->sendmsg_locked) |
---|
704 | 732 | return sock_no_sendmsg_locked(sk, msg, size); |
---|
705 | 733 | |
---|
706 | | - iov_iter_kvec(&msg->msg_iter, WRITE | ITER_KVEC, vec, num, size); |
---|
| 734 | + iov_iter_kvec(&msg->msg_iter, WRITE, vec, num, size); |
---|
707 | 735 | |
---|
708 | 736 | return sock->ops->sendmsg_locked(sk, msg, msg_data_left(msg)); |
---|
709 | 737 | } |
---|
.. | .. |
---|
724 | 752 | * before the software timestamp is received, a hardware TX timestamp may be |
---|
725 | 753 | * returned only if there is no software TX timestamp. Ignore false software |
---|
726 | 754 | * timestamps, which may be made in the __sock_recv_timestamp() call when the |
---|
727 | | - * option SO_TIMESTAMP(NS) is enabled on the socket, even when the skb has a |
---|
| 755 | + * option SO_TIMESTAMP_OLD(NS) is enabled on the socket, even when the skb has a |
---|
728 | 756 | * hardware timestamp. |
---|
729 | 757 | */ |
---|
730 | 758 | static bool skb_is_swtx_tstamp(const struct sk_buff *skb, int false_tstamp) |
---|
.. | .. |
---|
760 | 788 | struct sk_buff *skb) |
---|
761 | 789 | { |
---|
762 | 790 | int need_software_tstamp = sock_flag(sk, SOCK_RCVTSTAMP); |
---|
763 | | - struct scm_timestamping tss; |
---|
| 791 | + int new_tstamp = sock_flag(sk, SOCK_TSTAMP_NEW); |
---|
| 792 | + struct scm_timestamping_internal tss; |
---|
| 793 | + |
---|
764 | 794 | int empty = 1, false_tstamp = 0; |
---|
765 | 795 | struct skb_shared_hwtstamps *shhwtstamps = |
---|
766 | 796 | skb_hwtstamps(skb); |
---|
.. | .. |
---|
774 | 804 | |
---|
775 | 805 | if (need_software_tstamp) { |
---|
776 | 806 | if (!sock_flag(sk, SOCK_RCVTSTAMPNS)) { |
---|
777 | | - struct timeval tv; |
---|
778 | | - skb_get_timestamp(skb, &tv); |
---|
779 | | - put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMP, |
---|
780 | | - sizeof(tv), &tv); |
---|
| 807 | + if (new_tstamp) { |
---|
| 808 | + struct __kernel_sock_timeval tv; |
---|
| 809 | + |
---|
| 810 | + skb_get_new_timestamp(skb, &tv); |
---|
| 811 | + put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMP_NEW, |
---|
| 812 | + sizeof(tv), &tv); |
---|
| 813 | + } else { |
---|
| 814 | + struct __kernel_old_timeval tv; |
---|
| 815 | + |
---|
| 816 | + skb_get_timestamp(skb, &tv); |
---|
| 817 | + put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMP_OLD, |
---|
| 818 | + sizeof(tv), &tv); |
---|
| 819 | + } |
---|
781 | 820 | } else { |
---|
782 | | - struct timespec ts; |
---|
783 | | - skb_get_timestampns(skb, &ts); |
---|
784 | | - put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMPNS, |
---|
785 | | - sizeof(ts), &ts); |
---|
| 821 | + if (new_tstamp) { |
---|
| 822 | + struct __kernel_timespec ts; |
---|
| 823 | + |
---|
| 824 | + skb_get_new_timestampns(skb, &ts); |
---|
| 825 | + put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMPNS_NEW, |
---|
| 826 | + sizeof(ts), &ts); |
---|
| 827 | + } else { |
---|
| 828 | + struct __kernel_old_timespec ts; |
---|
| 829 | + |
---|
| 830 | + skb_get_timestampns(skb, &ts); |
---|
| 831 | + put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMPNS_OLD, |
---|
| 832 | + sizeof(ts), &ts); |
---|
| 833 | + } |
---|
786 | 834 | } |
---|
787 | 835 | } |
---|
788 | 836 | |
---|
789 | 837 | memset(&tss, 0, sizeof(tss)); |
---|
790 | 838 | if ((sk->sk_tsflags & SOF_TIMESTAMPING_SOFTWARE) && |
---|
791 | | - ktime_to_timespec_cond(skb->tstamp, tss.ts + 0)) |
---|
| 839 | + ktime_to_timespec64_cond(skb->tstamp, tss.ts + 0)) |
---|
792 | 840 | empty = 0; |
---|
793 | 841 | if (shhwtstamps && |
---|
794 | 842 | (sk->sk_tsflags & SOF_TIMESTAMPING_RAW_HARDWARE) && |
---|
795 | 843 | !skb_is_swtx_tstamp(skb, false_tstamp) && |
---|
796 | | - ktime_to_timespec_cond(shhwtstamps->hwtstamp, tss.ts + 2)) { |
---|
| 844 | + ktime_to_timespec64_cond(shhwtstamps->hwtstamp, tss.ts + 2)) { |
---|
797 | 845 | empty = 0; |
---|
798 | 846 | if ((sk->sk_tsflags & SOF_TIMESTAMPING_OPT_PKTINFO) && |
---|
799 | 847 | !skb_is_err_queue(skb)) |
---|
800 | 848 | put_ts_pktinfo(msg, skb); |
---|
801 | 849 | } |
---|
802 | 850 | if (!empty) { |
---|
803 | | - put_cmsg(msg, SOL_SOCKET, |
---|
804 | | - SCM_TIMESTAMPING, sizeof(tss), &tss); |
---|
| 851 | + if (sock_flag(sk, SOCK_TSTAMP_NEW)) |
---|
| 852 | + put_cmsg_scm_timestamping64(msg, &tss); |
---|
| 853 | + else |
---|
| 854 | + put_cmsg_scm_timestamping(msg, &tss); |
---|
805 | 855 | |
---|
806 | 856 | if (skb_is_err_queue(skb) && skb->len && |
---|
807 | 857 | SKB_EXT_ERR(skb)->opt_stats) |
---|
.. | .. |
---|
843 | 893 | } |
---|
844 | 894 | EXPORT_SYMBOL_GPL(__sock_recv_ts_and_drops); |
---|
845 | 895 | |
---|
| 896 | +INDIRECT_CALLABLE_DECLARE(int inet_recvmsg(struct socket *, struct msghdr *, |
---|
| 897 | + size_t, int)); |
---|
| 898 | +INDIRECT_CALLABLE_DECLARE(int inet6_recvmsg(struct socket *, struct msghdr *, |
---|
| 899 | + size_t, int)); |
---|
| 900 | +static inline int sock_recvmsg_nosec(struct socket *sock, struct msghdr *msg, |
---|
| 901 | + int flags) |
---|
| 902 | +{ |
---|
| 903 | + return INDIRECT_CALL_INET(sock->ops->recvmsg, inet6_recvmsg, |
---|
| 904 | + inet_recvmsg, sock, msg, msg_data_left(msg), |
---|
| 905 | + flags); |
---|
| 906 | +} |
---|
| 907 | + |
---|
846 | 908 | /** |
---|
847 | 909 | * sock_recvmsg - receive a message from @sock |
---|
848 | 910 | * @sock: socket |
---|
.. | .. |
---|
852 | 914 | * Receives @msg from @sock, passing through LSM. Returns the total number |
---|
853 | 915 | * of bytes received, or an error. |
---|
854 | 916 | */ |
---|
855 | | - |
---|
856 | | -static inline int sock_recvmsg_nosec(struct socket *sock, struct msghdr *msg, |
---|
857 | | - int flags) |
---|
858 | | -{ |
---|
859 | | - return sock->ops->recvmsg(sock, msg, msg_data_left(msg), flags); |
---|
860 | | -} |
---|
861 | | - |
---|
862 | 917 | int sock_recvmsg(struct socket *sock, struct msghdr *msg, int flags) |
---|
863 | 918 | { |
---|
864 | 919 | int err = security_socket_recvmsg(sock, msg, msg_data_left(msg), flags); |
---|
.. | .. |
---|
886 | 941 | int kernel_recvmsg(struct socket *sock, struct msghdr *msg, |
---|
887 | 942 | struct kvec *vec, size_t num, size_t size, int flags) |
---|
888 | 943 | { |
---|
889 | | - mm_segment_t oldfs = get_fs(); |
---|
890 | | - int result; |
---|
891 | | - |
---|
892 | | - iov_iter_kvec(&msg->msg_iter, READ | ITER_KVEC, vec, num, size); |
---|
893 | | - set_fs(KERNEL_DS); |
---|
894 | | - result = sock_recvmsg(sock, msg, flags); |
---|
895 | | - set_fs(oldfs); |
---|
896 | | - return result; |
---|
| 944 | + msg->msg_control_is_user = false; |
---|
| 945 | + iov_iter_kvec(&msg->msg_iter, READ, vec, num, size); |
---|
| 946 | + return sock_recvmsg(sock, msg, flags); |
---|
897 | 947 | } |
---|
898 | 948 | EXPORT_SYMBOL(kernel_recvmsg); |
---|
899 | 949 | |
---|
.. | .. |
---|
919 | 969 | struct socket *sock = file->private_data; |
---|
920 | 970 | |
---|
921 | 971 | if (unlikely(!sock->ops->splice_read)) |
---|
922 | | - return -EINVAL; |
---|
| 972 | + return generic_file_splice_read(file, ppos, pipe, len, flags); |
---|
923 | 973 | |
---|
924 | 974 | return sock->ops->splice_read(sock, ppos, pipe, len, flags); |
---|
925 | 975 | } |
---|
.. | .. |
---|
963 | 1013 | if (sock->type == SOCK_SEQPACKET) |
---|
964 | 1014 | msg.msg_flags |= MSG_EOR; |
---|
965 | 1015 | |
---|
966 | | - res = sock_sendmsg(sock, &msg); |
---|
| 1016 | + res = __sock_sendmsg(sock, &msg); |
---|
967 | 1017 | *from = msg.msg_iter; |
---|
968 | 1018 | return res; |
---|
969 | 1019 | } |
---|
.. | .. |
---|
1131 | 1181 | |
---|
1132 | 1182 | err = open_related_ns(&net->ns, get_net_ns); |
---|
1133 | 1183 | break; |
---|
| 1184 | + case SIOCGSTAMP_OLD: |
---|
| 1185 | + case SIOCGSTAMPNS_OLD: |
---|
| 1186 | + if (!sock->ops->gettstamp) { |
---|
| 1187 | + err = -ENOIOCTLCMD; |
---|
| 1188 | + break; |
---|
| 1189 | + } |
---|
| 1190 | + err = sock->ops->gettstamp(sock, argp, |
---|
| 1191 | + cmd == SIOCGSTAMP_OLD, |
---|
| 1192 | + !IS_ENABLED(CONFIG_64BIT)); |
---|
| 1193 | + break; |
---|
| 1194 | + case SIOCGSTAMP_NEW: |
---|
| 1195 | + case SIOCGSTAMPNS_NEW: |
---|
| 1196 | + if (!sock->ops->gettstamp) { |
---|
| 1197 | + err = -ENOIOCTLCMD; |
---|
| 1198 | + break; |
---|
| 1199 | + } |
---|
| 1200 | + err = sock->ops->gettstamp(sock, argp, |
---|
| 1201 | + cmd == SIOCGSTAMP_NEW, |
---|
| 1202 | + false); |
---|
| 1203 | + break; |
---|
1134 | 1204 | default: |
---|
1135 | 1205 | err = sock_do_ioctl(net, sock, cmd, arg); |
---|
1136 | 1206 | break; |
---|
.. | .. |
---|
1230 | 1300 | { |
---|
1231 | 1301 | struct socket *sock = filp->private_data; |
---|
1232 | 1302 | struct sock *sk = sock->sk; |
---|
1233 | | - struct socket_wq *wq; |
---|
| 1303 | + struct socket_wq *wq = &sock->wq; |
---|
1234 | 1304 | |
---|
1235 | 1305 | if (sk == NULL) |
---|
1236 | 1306 | return -EINVAL; |
---|
1237 | 1307 | |
---|
1238 | 1308 | lock_sock(sk); |
---|
1239 | | - wq = sock->wq; |
---|
1240 | 1309 | fasync_helper(fd, filp, on, &wq->fasync_list); |
---|
1241 | 1310 | |
---|
1242 | 1311 | if (!wq->fasync_list) |
---|
.. | .. |
---|
1263 | 1332 | case SOCK_WAKE_SPACE: |
---|
1264 | 1333 | if (!test_and_clear_bit(SOCKWQ_ASYNC_NOSPACE, &wq->flags)) |
---|
1265 | 1334 | break; |
---|
1266 | | - /* fall through */ |
---|
| 1335 | + fallthrough; |
---|
1267 | 1336 | case SOCK_WAKE_IO: |
---|
1268 | 1337 | call_kill: |
---|
1269 | 1338 | kill_fasync(&wq->fasync_list, SIGIO, band); |
---|
.. | .. |
---|
1586 | 1655 | sock = sockfd_lookup_light(fd, &err, &fput_needed); |
---|
1587 | 1656 | if (sock) { |
---|
1588 | 1657 | err = move_addr_to_kernel(umyaddr, addrlen, &address); |
---|
1589 | | - if (err >= 0) { |
---|
| 1658 | + if (!err) { |
---|
1590 | 1659 | err = security_socket_bind(sock, |
---|
1591 | 1660 | (struct sockaddr *)&address, |
---|
1592 | 1661 | addrlen); |
---|
.. | .. |
---|
1619 | 1688 | |
---|
1620 | 1689 | sock = sockfd_lookup_light(fd, &err, &fput_needed); |
---|
1621 | 1690 | if (sock) { |
---|
1622 | | - somaxconn = sock_net(sock->sk)->core.sysctl_somaxconn; |
---|
| 1691 | + somaxconn = READ_ONCE(sock_net(sock->sk)->core.sysctl_somaxconn); |
---|
1623 | 1692 | if ((unsigned int)backlog > somaxconn) |
---|
1624 | 1693 | backlog = somaxconn; |
---|
1625 | 1694 | |
---|
.. | .. |
---|
1637 | 1706 | return __sys_listen(fd, backlog); |
---|
1638 | 1707 | } |
---|
1639 | 1708 | |
---|
1640 | | -/* |
---|
1641 | | - * For accept, we attempt to create a new socket, set up the link |
---|
1642 | | - * with the client, wake up the client, then return the new |
---|
1643 | | - * connected fd. We collect the address of the connector in kernel |
---|
1644 | | - * space and move it to user at the very end. This is unclean because |
---|
1645 | | - * we open the socket then return an error. |
---|
1646 | | - * |
---|
1647 | | - * 1003.1g adds the ability to recvmsg() to query connection pending |
---|
1648 | | - * status to recvmsg. We need to add that support in a way thats |
---|
1649 | | - * clean when we restructure accept also. |
---|
1650 | | - */ |
---|
1651 | | - |
---|
1652 | | -int __sys_accept4(int fd, struct sockaddr __user *upeer_sockaddr, |
---|
1653 | | - int __user *upeer_addrlen, int flags) |
---|
| 1709 | +struct file *do_accept(struct file *file, unsigned file_flags, |
---|
| 1710 | + struct sockaddr __user *upeer_sockaddr, |
---|
| 1711 | + int __user *upeer_addrlen, int flags) |
---|
1654 | 1712 | { |
---|
1655 | 1713 | struct socket *sock, *newsock; |
---|
1656 | 1714 | struct file *newfile; |
---|
1657 | | - int err, len, newfd, fput_needed; |
---|
| 1715 | + int err, len; |
---|
1658 | 1716 | struct sockaddr_storage address; |
---|
1659 | 1717 | |
---|
1660 | | - if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK)) |
---|
1661 | | - return -EINVAL; |
---|
1662 | | - |
---|
1663 | | - if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK)) |
---|
1664 | | - flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK; |
---|
1665 | | - |
---|
1666 | | - sock = sockfd_lookup_light(fd, &err, &fput_needed); |
---|
| 1718 | + sock = sock_from_file(file, &err); |
---|
1667 | 1719 | if (!sock) |
---|
1668 | | - goto out; |
---|
| 1720 | + return ERR_PTR(err); |
---|
1669 | 1721 | |
---|
1670 | | - err = -ENFILE; |
---|
1671 | 1722 | newsock = sock_alloc(); |
---|
1672 | 1723 | if (!newsock) |
---|
1673 | | - goto out_put; |
---|
| 1724 | + return ERR_PTR(-ENFILE); |
---|
1674 | 1725 | |
---|
1675 | 1726 | newsock->type = sock->type; |
---|
1676 | 1727 | newsock->ops = sock->ops; |
---|
.. | .. |
---|
1681 | 1732 | */ |
---|
1682 | 1733 | __module_get(newsock->ops->owner); |
---|
1683 | 1734 | |
---|
1684 | | - newfd = get_unused_fd_flags(flags); |
---|
1685 | | - if (unlikely(newfd < 0)) { |
---|
1686 | | - err = newfd; |
---|
1687 | | - sock_release(newsock); |
---|
1688 | | - goto out_put; |
---|
1689 | | - } |
---|
1690 | 1735 | newfile = sock_alloc_file(newsock, flags, sock->sk->sk_prot_creator->name); |
---|
1691 | | - if (IS_ERR(newfile)) { |
---|
1692 | | - err = PTR_ERR(newfile); |
---|
1693 | | - put_unused_fd(newfd); |
---|
1694 | | - goto out_put; |
---|
1695 | | - } |
---|
| 1736 | + if (IS_ERR(newfile)) |
---|
| 1737 | + return newfile; |
---|
1696 | 1738 | |
---|
1697 | 1739 | err = security_socket_accept(sock, newsock); |
---|
1698 | 1740 | if (err) |
---|
1699 | 1741 | goto out_fd; |
---|
1700 | 1742 | |
---|
1701 | | - err = sock->ops->accept(sock, newsock, sock->file->f_flags, false); |
---|
| 1743 | + err = sock->ops->accept(sock, newsock, sock->file->f_flags | file_flags, |
---|
| 1744 | + false); |
---|
1702 | 1745 | if (err < 0) |
---|
1703 | 1746 | goto out_fd; |
---|
1704 | 1747 | |
---|
.. | .. |
---|
1716 | 1759 | } |
---|
1717 | 1760 | |
---|
1718 | 1761 | /* File flags are not inherited via accept() unlike another OSes. */ |
---|
1719 | | - |
---|
1720 | | - fd_install(newfd, newfile); |
---|
1721 | | - err = newfd; |
---|
1722 | | - |
---|
1723 | | -out_put: |
---|
1724 | | - fput_light(sock->file, fput_needed); |
---|
1725 | | -out: |
---|
1726 | | - return err; |
---|
| 1762 | + return newfile; |
---|
1727 | 1763 | out_fd: |
---|
1728 | 1764 | fput(newfile); |
---|
1729 | | - put_unused_fd(newfd); |
---|
1730 | | - goto out_put; |
---|
| 1765 | + return ERR_PTR(err); |
---|
| 1766 | +} |
---|
| 1767 | + |
---|
| 1768 | +int __sys_accept4_file(struct file *file, unsigned file_flags, |
---|
| 1769 | + struct sockaddr __user *upeer_sockaddr, |
---|
| 1770 | + int __user *upeer_addrlen, int flags, |
---|
| 1771 | + unsigned long nofile) |
---|
| 1772 | +{ |
---|
| 1773 | + struct file *newfile; |
---|
| 1774 | + int newfd; |
---|
| 1775 | + |
---|
| 1776 | + if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK)) |
---|
| 1777 | + return -EINVAL; |
---|
| 1778 | + |
---|
| 1779 | + if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK)) |
---|
| 1780 | + flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK; |
---|
| 1781 | + |
---|
| 1782 | + newfd = __get_unused_fd_flags(flags, nofile); |
---|
| 1783 | + if (unlikely(newfd < 0)) |
---|
| 1784 | + return newfd; |
---|
| 1785 | + |
---|
| 1786 | + newfile = do_accept(file, file_flags, upeer_sockaddr, upeer_addrlen, |
---|
| 1787 | + flags); |
---|
| 1788 | + if (IS_ERR(newfile)) { |
---|
| 1789 | + put_unused_fd(newfd); |
---|
| 1790 | + return PTR_ERR(newfile); |
---|
| 1791 | + } |
---|
| 1792 | + fd_install(newfd, newfile); |
---|
| 1793 | + return newfd; |
---|
| 1794 | +} |
---|
| 1795 | + |
---|
| 1796 | +/* |
---|
| 1797 | + * For accept, we attempt to create a new socket, set up the link |
---|
| 1798 | + * with the client, wake up the client, then return the new |
---|
| 1799 | + * connected fd. We collect the address of the connector in kernel |
---|
| 1800 | + * space and move it to user at the very end. This is unclean because |
---|
| 1801 | + * we open the socket then return an error. |
---|
| 1802 | + * |
---|
| 1803 | + * 1003.1g adds the ability to recvmsg() to query connection pending |
---|
| 1804 | + * status to recvmsg. We need to add that support in a way thats |
---|
| 1805 | + * clean when we restructure accept also. |
---|
| 1806 | + */ |
---|
| 1807 | + |
---|
| 1808 | +int __sys_accept4(int fd, struct sockaddr __user *upeer_sockaddr, |
---|
| 1809 | + int __user *upeer_addrlen, int flags) |
---|
| 1810 | +{ |
---|
| 1811 | + int ret = -EBADF; |
---|
| 1812 | + struct fd f; |
---|
| 1813 | + |
---|
| 1814 | + f = fdget(fd); |
---|
| 1815 | + if (f.file) { |
---|
| 1816 | + ret = __sys_accept4_file(f.file, 0, upeer_sockaddr, |
---|
| 1817 | + upeer_addrlen, flags, |
---|
| 1818 | + rlimit(RLIMIT_NOFILE)); |
---|
| 1819 | + fdput(f); |
---|
| 1820 | + } |
---|
| 1821 | + |
---|
| 1822 | + return ret; |
---|
1731 | 1823 | } |
---|
1732 | 1824 | |
---|
1733 | 1825 | SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr, |
---|
.. | .. |
---|
1754 | 1846 | * include the -EINPROGRESS status for such sockets. |
---|
1755 | 1847 | */ |
---|
1756 | 1848 | |
---|
1757 | | -int __sys_connect(int fd, struct sockaddr __user *uservaddr, int addrlen) |
---|
| 1849 | +int __sys_connect_file(struct file *file, struct sockaddr_storage *address, |
---|
| 1850 | + int addrlen, int file_flags) |
---|
1758 | 1851 | { |
---|
1759 | 1852 | struct socket *sock; |
---|
1760 | | - struct sockaddr_storage address; |
---|
1761 | | - int err, fput_needed; |
---|
| 1853 | + int err; |
---|
1762 | 1854 | |
---|
1763 | | - sock = sockfd_lookup_light(fd, &err, &fput_needed); |
---|
| 1855 | + sock = sock_from_file(file, &err); |
---|
1764 | 1856 | if (!sock) |
---|
1765 | 1857 | goto out; |
---|
1766 | | - err = move_addr_to_kernel(uservaddr, addrlen, &address); |
---|
1767 | | - if (err < 0) |
---|
1768 | | - goto out_put; |
---|
1769 | 1858 | |
---|
1770 | 1859 | err = |
---|
1771 | | - security_socket_connect(sock, (struct sockaddr *)&address, addrlen); |
---|
| 1860 | + security_socket_connect(sock, (struct sockaddr *)address, addrlen); |
---|
1772 | 1861 | if (err) |
---|
1773 | | - goto out_put; |
---|
| 1862 | + goto out; |
---|
1774 | 1863 | |
---|
1775 | | - err = sock->ops->connect(sock, (struct sockaddr *)&address, addrlen, |
---|
1776 | | - sock->file->f_flags); |
---|
1777 | | -out_put: |
---|
1778 | | - fput_light(sock->file, fput_needed); |
---|
| 1864 | + err = sock->ops->connect(sock, (struct sockaddr *)address, addrlen, |
---|
| 1865 | + sock->file->f_flags | file_flags); |
---|
1779 | 1866 | out: |
---|
1780 | 1867 | return err; |
---|
| 1868 | +} |
---|
| 1869 | + |
---|
| 1870 | +int __sys_connect(int fd, struct sockaddr __user *uservaddr, int addrlen) |
---|
| 1871 | +{ |
---|
| 1872 | + int ret = -EBADF; |
---|
| 1873 | + struct fd f; |
---|
| 1874 | + |
---|
| 1875 | + f = fdget(fd); |
---|
| 1876 | + if (f.file) { |
---|
| 1877 | + struct sockaddr_storage address; |
---|
| 1878 | + |
---|
| 1879 | + ret = move_addr_to_kernel(uservaddr, addrlen, &address); |
---|
| 1880 | + if (!ret) |
---|
| 1881 | + ret = __sys_connect_file(f.file, &address, addrlen, 0); |
---|
| 1882 | + fdput(f); |
---|
| 1883 | + } |
---|
| 1884 | + |
---|
| 1885 | + return ret; |
---|
1781 | 1886 | } |
---|
1782 | 1887 | |
---|
1783 | 1888 | SYSCALL_DEFINE3(connect, int, fd, struct sockaddr __user *, uservaddr, |
---|
.. | .. |
---|
1896 | 2001 | if (sock->file->f_flags & O_NONBLOCK) |
---|
1897 | 2002 | flags |= MSG_DONTWAIT; |
---|
1898 | 2003 | msg.msg_flags = flags; |
---|
1899 | | - err = sock_sendmsg(sock, &msg); |
---|
| 2004 | + err = __sock_sendmsg(sock, &msg); |
---|
1900 | 2005 | |
---|
1901 | 2006 | out_put: |
---|
1902 | 2007 | fput_light(sock->file, fput_needed); |
---|
.. | .. |
---|
1984 | 2089 | return __sys_recvfrom(fd, ubuf, size, flags, NULL, NULL); |
---|
1985 | 2090 | } |
---|
1986 | 2091 | |
---|
| 2092 | +static bool sock_use_custom_sol_socket(const struct socket *sock) |
---|
| 2093 | +{ |
---|
| 2094 | + const struct sock *sk = sock->sk; |
---|
| 2095 | + |
---|
| 2096 | + /* Use sock->ops->setsockopt() for MPTCP */ |
---|
| 2097 | + return IS_ENABLED(CONFIG_MPTCP) && |
---|
| 2098 | + sk->sk_protocol == IPPROTO_MPTCP && |
---|
| 2099 | + sk->sk_type == SOCK_STREAM && |
---|
| 2100 | + (sk->sk_family == AF_INET || sk->sk_family == AF_INET6); |
---|
| 2101 | +} |
---|
| 2102 | + |
---|
1987 | 2103 | /* |
---|
1988 | 2104 | * Set a socket option. Because we don't know the option lengths we have |
---|
1989 | 2105 | * to pass the user mode parameter for the protocols to sort out. |
---|
1990 | 2106 | */ |
---|
1991 | | - |
---|
1992 | | -static int __sys_setsockopt(int fd, int level, int optname, |
---|
1993 | | - char __user *optval, int optlen) |
---|
| 2107 | +int __sys_setsockopt(int fd, int level, int optname, char __user *user_optval, |
---|
| 2108 | + int optlen) |
---|
1994 | 2109 | { |
---|
| 2110 | + sockptr_t optval = USER_SOCKPTR(user_optval); |
---|
| 2111 | + char *kernel_optval = NULL; |
---|
1995 | 2112 | int err, fput_needed; |
---|
1996 | 2113 | struct socket *sock; |
---|
1997 | 2114 | |
---|
.. | .. |
---|
1999 | 2116 | return -EINVAL; |
---|
2000 | 2117 | |
---|
2001 | 2118 | sock = sockfd_lookup_light(fd, &err, &fput_needed); |
---|
2002 | | - if (sock != NULL) { |
---|
2003 | | - err = security_socket_setsockopt(sock, level, optname); |
---|
2004 | | - if (err) |
---|
2005 | | - goto out_put; |
---|
| 2119 | + if (!sock) |
---|
| 2120 | + return err; |
---|
2006 | 2121 | |
---|
2007 | | - if (level == SOL_SOCKET) |
---|
2008 | | - err = |
---|
2009 | | - sock_setsockopt(sock, level, optname, optval, |
---|
2010 | | - optlen); |
---|
2011 | | - else |
---|
2012 | | - err = |
---|
2013 | | - sock->ops->setsockopt(sock, level, optname, optval, |
---|
2014 | | - optlen); |
---|
2015 | | -out_put: |
---|
2016 | | - fput_light(sock->file, fput_needed); |
---|
| 2122 | + err = security_socket_setsockopt(sock, level, optname); |
---|
| 2123 | + if (err) |
---|
| 2124 | + goto out_put; |
---|
| 2125 | + |
---|
| 2126 | + if (!in_compat_syscall()) |
---|
| 2127 | + err = BPF_CGROUP_RUN_PROG_SETSOCKOPT(sock->sk, &level, &optname, |
---|
| 2128 | + user_optval, &optlen, |
---|
| 2129 | + &kernel_optval); |
---|
| 2130 | + if (err < 0) |
---|
| 2131 | + goto out_put; |
---|
| 2132 | + if (err > 0) { |
---|
| 2133 | + err = 0; |
---|
| 2134 | + goto out_put; |
---|
2017 | 2135 | } |
---|
| 2136 | + |
---|
| 2137 | + if (kernel_optval) |
---|
| 2138 | + optval = KERNEL_SOCKPTR(kernel_optval); |
---|
| 2139 | + if (level == SOL_SOCKET && !sock_use_custom_sol_socket(sock)) |
---|
| 2140 | + err = sock_setsockopt(sock, level, optname, optval, optlen); |
---|
| 2141 | + else if (unlikely(!sock->ops->setsockopt)) |
---|
| 2142 | + err = -EOPNOTSUPP; |
---|
| 2143 | + else |
---|
| 2144 | + err = sock->ops->setsockopt(sock, level, optname, optval, |
---|
| 2145 | + optlen); |
---|
| 2146 | + kfree(kernel_optval); |
---|
| 2147 | +out_put: |
---|
| 2148 | + fput_light(sock->file, fput_needed); |
---|
2018 | 2149 | return err; |
---|
2019 | 2150 | } |
---|
2020 | 2151 | |
---|
.. | .. |
---|
2028 | 2159 | * Get a socket option. Because we don't know the option lengths we have |
---|
2029 | 2160 | * to pass a user mode parameter for the protocols to sort out. |
---|
2030 | 2161 | */ |
---|
2031 | | - |
---|
2032 | | -static int __sys_getsockopt(int fd, int level, int optname, |
---|
2033 | | - char __user *optval, int __user *optlen) |
---|
| 2162 | +int __sys_getsockopt(int fd, int level, int optname, char __user *optval, |
---|
| 2163 | + int __user *optlen) |
---|
2034 | 2164 | { |
---|
2035 | 2165 | int err, fput_needed; |
---|
2036 | 2166 | struct socket *sock; |
---|
| 2167 | + int max_optlen; |
---|
2037 | 2168 | |
---|
2038 | 2169 | sock = sockfd_lookup_light(fd, &err, &fput_needed); |
---|
2039 | | - if (sock != NULL) { |
---|
2040 | | - err = security_socket_getsockopt(sock, level, optname); |
---|
2041 | | - if (err) |
---|
2042 | | - goto out_put; |
---|
| 2170 | + if (!sock) |
---|
| 2171 | + return err; |
---|
2043 | 2172 | |
---|
2044 | | - if (level == SOL_SOCKET) |
---|
2045 | | - err = |
---|
2046 | | - sock_getsockopt(sock, level, optname, optval, |
---|
| 2173 | + err = security_socket_getsockopt(sock, level, optname); |
---|
| 2174 | + if (err) |
---|
| 2175 | + goto out_put; |
---|
| 2176 | + |
---|
| 2177 | + if (!in_compat_syscall()) |
---|
| 2178 | + max_optlen = BPF_CGROUP_GETSOCKOPT_MAX_OPTLEN(optlen); |
---|
| 2179 | + |
---|
| 2180 | + if (level == SOL_SOCKET) |
---|
| 2181 | + err = sock_getsockopt(sock, level, optname, optval, optlen); |
---|
| 2182 | + else if (unlikely(!sock->ops->getsockopt)) |
---|
| 2183 | + err = -EOPNOTSUPP; |
---|
| 2184 | + else |
---|
| 2185 | + err = sock->ops->getsockopt(sock, level, optname, optval, |
---|
2047 | 2186 | optlen); |
---|
2048 | | - else |
---|
2049 | | - err = |
---|
2050 | | - sock->ops->getsockopt(sock, level, optname, optval, |
---|
2051 | | - optlen); |
---|
| 2187 | + |
---|
| 2188 | + if (!in_compat_syscall()) |
---|
| 2189 | + err = BPF_CGROUP_RUN_PROG_GETSOCKOPT(sock->sk, level, optname, |
---|
| 2190 | + optval, optlen, max_optlen, |
---|
| 2191 | + err); |
---|
2052 | 2192 | out_put: |
---|
2053 | | - fput_light(sock->file, fput_needed); |
---|
2054 | | - } |
---|
| 2193 | + fput_light(sock->file, fput_needed); |
---|
2055 | 2194 | return err; |
---|
2056 | 2195 | } |
---|
2057 | 2196 | |
---|
.. | .. |
---|
2065 | 2204 | * Shutdown a socket. |
---|
2066 | 2205 | */ |
---|
2067 | 2206 | |
---|
| 2207 | +int __sys_shutdown_sock(struct socket *sock, int how) |
---|
| 2208 | +{ |
---|
| 2209 | + int err; |
---|
| 2210 | + |
---|
| 2211 | + err = security_socket_shutdown(sock, how); |
---|
| 2212 | + if (!err) |
---|
| 2213 | + err = sock->ops->shutdown(sock, how); |
---|
| 2214 | + |
---|
| 2215 | + return err; |
---|
| 2216 | +} |
---|
| 2217 | + |
---|
2068 | 2218 | int __sys_shutdown(int fd, int how) |
---|
2069 | 2219 | { |
---|
2070 | 2220 | int err, fput_needed; |
---|
.. | .. |
---|
2072 | 2222 | |
---|
2073 | 2223 | sock = sockfd_lookup_light(fd, &err, &fput_needed); |
---|
2074 | 2224 | if (sock != NULL) { |
---|
2075 | | - err = security_socket_shutdown(sock, how); |
---|
2076 | | - if (!err) |
---|
2077 | | - err = sock->ops->shutdown(sock, how); |
---|
| 2225 | + err = __sys_shutdown_sock(sock, how); |
---|
2078 | 2226 | fput_light(sock->file, fput_needed); |
---|
2079 | 2227 | } |
---|
2080 | 2228 | return err; |
---|
.. | .. |
---|
2097 | 2245 | unsigned int name_len; |
---|
2098 | 2246 | }; |
---|
2099 | 2247 | |
---|
2100 | | -static int copy_msghdr_from_user(struct msghdr *kmsg, |
---|
2101 | | - struct user_msghdr __user *umsg, |
---|
2102 | | - struct sockaddr __user **save_addr, |
---|
2103 | | - struct iovec **iov) |
---|
| 2248 | +int __copy_msghdr_from_user(struct msghdr *kmsg, |
---|
| 2249 | + struct user_msghdr __user *umsg, |
---|
| 2250 | + struct sockaddr __user **save_addr, |
---|
| 2251 | + struct iovec __user **uiov, size_t *nsegs) |
---|
2104 | 2252 | { |
---|
2105 | 2253 | struct user_msghdr msg; |
---|
2106 | 2254 | ssize_t err; |
---|
.. | .. |
---|
2108 | 2256 | if (copy_from_user(&msg, umsg, sizeof(*umsg))) |
---|
2109 | 2257 | return -EFAULT; |
---|
2110 | 2258 | |
---|
2111 | | - kmsg->msg_control = (void __force *)msg.msg_control; |
---|
| 2259 | + kmsg->msg_control_is_user = true; |
---|
| 2260 | + kmsg->msg_control_user = msg.msg_control; |
---|
2112 | 2261 | kmsg->msg_controllen = msg.msg_controllen; |
---|
2113 | 2262 | kmsg->msg_flags = msg.msg_flags; |
---|
2114 | 2263 | |
---|
.. | .. |
---|
2142 | 2291 | return -EMSGSIZE; |
---|
2143 | 2292 | |
---|
2144 | 2293 | kmsg->msg_iocb = NULL; |
---|
2145 | | - |
---|
2146 | | - return import_iovec(save_addr ? READ : WRITE, |
---|
2147 | | - msg.msg_iov, msg.msg_iovlen, |
---|
2148 | | - UIO_FASTIOV, iov, &kmsg->msg_iter); |
---|
| 2294 | + *uiov = msg.msg_iov; |
---|
| 2295 | + *nsegs = msg.msg_iovlen; |
---|
| 2296 | + return 0; |
---|
2149 | 2297 | } |
---|
2150 | 2298 | |
---|
2151 | | -static int ___sys_sendmsg(struct socket *sock, struct user_msghdr __user *msg, |
---|
2152 | | - struct msghdr *msg_sys, unsigned int flags, |
---|
2153 | | - struct used_address *used_address, |
---|
2154 | | - unsigned int allowed_msghdr_flags) |
---|
| 2299 | +static int copy_msghdr_from_user(struct msghdr *kmsg, |
---|
| 2300 | + struct user_msghdr __user *umsg, |
---|
| 2301 | + struct sockaddr __user **save_addr, |
---|
| 2302 | + struct iovec **iov) |
---|
2155 | 2303 | { |
---|
2156 | | - struct compat_msghdr __user *msg_compat = |
---|
2157 | | - (struct compat_msghdr __user *)msg; |
---|
2158 | | - struct sockaddr_storage address; |
---|
2159 | | - struct iovec iovstack[UIO_FASTIOV], *iov = iovstack; |
---|
| 2304 | + struct user_msghdr msg; |
---|
| 2305 | + ssize_t err; |
---|
| 2306 | + |
---|
| 2307 | + err = __copy_msghdr_from_user(kmsg, umsg, save_addr, &msg.msg_iov, |
---|
| 2308 | + &msg.msg_iovlen); |
---|
| 2309 | + if (err) |
---|
| 2310 | + return err; |
---|
| 2311 | + |
---|
| 2312 | + err = import_iovec(save_addr ? READ : WRITE, |
---|
| 2313 | + msg.msg_iov, msg.msg_iovlen, |
---|
| 2314 | + UIO_FASTIOV, iov, &kmsg->msg_iter); |
---|
| 2315 | + return err < 0 ? err : 0; |
---|
| 2316 | +} |
---|
| 2317 | + |
---|
| 2318 | +static int ____sys_sendmsg(struct socket *sock, struct msghdr *msg_sys, |
---|
| 2319 | + unsigned int flags, struct used_address *used_address, |
---|
| 2320 | + unsigned int allowed_msghdr_flags) |
---|
| 2321 | +{ |
---|
2160 | 2322 | unsigned char ctl[sizeof(struct cmsghdr) + 20] |
---|
2161 | 2323 | __aligned(sizeof(__kernel_size_t)); |
---|
2162 | 2324 | /* 20 is size of ipv6_pktinfo */ |
---|
.. | .. |
---|
2164 | 2326 | int ctl_len; |
---|
2165 | 2327 | ssize_t err; |
---|
2166 | 2328 | |
---|
2167 | | - msg_sys->msg_name = &address; |
---|
2168 | | - |
---|
2169 | | - if (MSG_CMSG_COMPAT & flags) |
---|
2170 | | - err = get_compat_msghdr(msg_sys, msg_compat, NULL, &iov); |
---|
2171 | | - else |
---|
2172 | | - err = copy_msghdr_from_user(msg_sys, msg, NULL, &iov); |
---|
2173 | | - if (err < 0) |
---|
2174 | | - return err; |
---|
2175 | | - |
---|
2176 | 2329 | err = -ENOBUFS; |
---|
2177 | 2330 | |
---|
2178 | 2331 | if (msg_sys->msg_controllen > INT_MAX) |
---|
2179 | | - goto out_freeiov; |
---|
| 2332 | + goto out; |
---|
2180 | 2333 | flags |= (msg_sys->msg_flags & allowed_msghdr_flags); |
---|
2181 | 2334 | ctl_len = msg_sys->msg_controllen; |
---|
2182 | 2335 | if ((MSG_CMSG_COMPAT & flags) && ctl_len) { |
---|
.. | .. |
---|
2184 | 2337 | cmsghdr_from_user_compat_to_kern(msg_sys, sock->sk, ctl, |
---|
2185 | 2338 | sizeof(ctl)); |
---|
2186 | 2339 | if (err) |
---|
2187 | | - goto out_freeiov; |
---|
| 2340 | + goto out; |
---|
2188 | 2341 | ctl_buf = msg_sys->msg_control; |
---|
2189 | 2342 | ctl_len = msg_sys->msg_controllen; |
---|
2190 | 2343 | } else if (ctl_len) { |
---|
.. | .. |
---|
2193 | 2346 | if (ctl_len > sizeof(ctl)) { |
---|
2194 | 2347 | ctl_buf = sock_kmalloc(sock->sk, ctl_len, GFP_KERNEL); |
---|
2195 | 2348 | if (ctl_buf == NULL) |
---|
2196 | | - goto out_freeiov; |
---|
| 2349 | + goto out; |
---|
2197 | 2350 | } |
---|
2198 | 2351 | err = -EFAULT; |
---|
2199 | | - /* |
---|
2200 | | - * Careful! Before this, msg_sys->msg_control contains a user pointer. |
---|
2201 | | - * Afterwards, it will be a kernel pointer. Thus the compiler-assisted |
---|
2202 | | - * checking falls down on this. |
---|
2203 | | - */ |
---|
2204 | | - if (copy_from_user(ctl_buf, |
---|
2205 | | - (void __user __force *)msg_sys->msg_control, |
---|
2206 | | - ctl_len)) |
---|
| 2352 | + if (copy_from_user(ctl_buf, msg_sys->msg_control_user, ctl_len)) |
---|
2207 | 2353 | goto out_freectl; |
---|
2208 | 2354 | msg_sys->msg_control = ctl_buf; |
---|
| 2355 | + msg_sys->msg_control_is_user = false; |
---|
2209 | 2356 | } |
---|
2210 | 2357 | msg_sys->msg_flags = flags; |
---|
2211 | 2358 | |
---|
.. | .. |
---|
2224 | 2371 | err = sock_sendmsg_nosec(sock, msg_sys); |
---|
2225 | 2372 | goto out_freectl; |
---|
2226 | 2373 | } |
---|
2227 | | - err = sock_sendmsg(sock, msg_sys); |
---|
| 2374 | + err = __sock_sendmsg(sock, msg_sys); |
---|
2228 | 2375 | /* |
---|
2229 | 2376 | * If this is sendmmsg() and sending to current destination address was |
---|
2230 | 2377 | * successful, remember it. |
---|
.. | .. |
---|
2239 | 2386 | out_freectl: |
---|
2240 | 2387 | if (ctl_buf != ctl) |
---|
2241 | 2388 | sock_kfree_s(sock->sk, ctl_buf, ctl_len); |
---|
2242 | | -out_freeiov: |
---|
| 2389 | +out: |
---|
| 2390 | + return err; |
---|
| 2391 | +} |
---|
| 2392 | + |
---|
| 2393 | +int sendmsg_copy_msghdr(struct msghdr *msg, |
---|
| 2394 | + struct user_msghdr __user *umsg, unsigned flags, |
---|
| 2395 | + struct iovec **iov) |
---|
| 2396 | +{ |
---|
| 2397 | + int err; |
---|
| 2398 | + |
---|
| 2399 | + if (flags & MSG_CMSG_COMPAT) { |
---|
| 2400 | + struct compat_msghdr __user *msg_compat; |
---|
| 2401 | + |
---|
| 2402 | + msg_compat = (struct compat_msghdr __user *) umsg; |
---|
| 2403 | + err = get_compat_msghdr(msg, msg_compat, NULL, iov); |
---|
| 2404 | + } else { |
---|
| 2405 | + err = copy_msghdr_from_user(msg, umsg, NULL, iov); |
---|
| 2406 | + } |
---|
| 2407 | + if (err < 0) |
---|
| 2408 | + return err; |
---|
| 2409 | + |
---|
| 2410 | + return 0; |
---|
| 2411 | +} |
---|
| 2412 | + |
---|
| 2413 | +static int ___sys_sendmsg(struct socket *sock, struct user_msghdr __user *msg, |
---|
| 2414 | + struct msghdr *msg_sys, unsigned int flags, |
---|
| 2415 | + struct used_address *used_address, |
---|
| 2416 | + unsigned int allowed_msghdr_flags) |
---|
| 2417 | +{ |
---|
| 2418 | + struct sockaddr_storage address; |
---|
| 2419 | + struct iovec iovstack[UIO_FASTIOV], *iov = iovstack; |
---|
| 2420 | + ssize_t err; |
---|
| 2421 | + |
---|
| 2422 | + msg_sys->msg_name = &address; |
---|
| 2423 | + |
---|
| 2424 | + err = sendmsg_copy_msghdr(msg_sys, msg, flags, &iov); |
---|
| 2425 | + if (err < 0) |
---|
| 2426 | + return err; |
---|
| 2427 | + |
---|
| 2428 | + err = ____sys_sendmsg(sock, msg_sys, flags, used_address, |
---|
| 2429 | + allowed_msghdr_flags); |
---|
2243 | 2430 | kfree(iov); |
---|
2244 | 2431 | return err; |
---|
2245 | 2432 | } |
---|
.. | .. |
---|
2247 | 2434 | /* |
---|
2248 | 2435 | * BSD sendmsg interface |
---|
2249 | 2436 | */ |
---|
| 2437 | +long __sys_sendmsg_sock(struct socket *sock, struct msghdr *msg, |
---|
| 2438 | + unsigned int flags) |
---|
| 2439 | +{ |
---|
| 2440 | + return ____sys_sendmsg(sock, msg, flags, NULL, 0); |
---|
| 2441 | +} |
---|
2250 | 2442 | |
---|
2251 | 2443 | long __sys_sendmsg(int fd, struct user_msghdr __user *msg, unsigned int flags, |
---|
2252 | 2444 | bool forbid_cmsg_compat) |
---|
.. | .. |
---|
2351 | 2543 | return __sys_sendmmsg(fd, mmsg, vlen, flags, true); |
---|
2352 | 2544 | } |
---|
2353 | 2545 | |
---|
2354 | | -static int ___sys_recvmsg(struct socket *sock, struct user_msghdr __user *msg, |
---|
2355 | | - struct msghdr *msg_sys, unsigned int flags, int nosec) |
---|
| 2546 | +int recvmsg_copy_msghdr(struct msghdr *msg, |
---|
| 2547 | + struct user_msghdr __user *umsg, unsigned flags, |
---|
| 2548 | + struct sockaddr __user **uaddr, |
---|
| 2549 | + struct iovec **iov) |
---|
| 2550 | +{ |
---|
| 2551 | + ssize_t err; |
---|
| 2552 | + |
---|
| 2553 | + if (MSG_CMSG_COMPAT & flags) { |
---|
| 2554 | + struct compat_msghdr __user *msg_compat; |
---|
| 2555 | + |
---|
| 2556 | + msg_compat = (struct compat_msghdr __user *) umsg; |
---|
| 2557 | + err = get_compat_msghdr(msg, msg_compat, uaddr, iov); |
---|
| 2558 | + } else { |
---|
| 2559 | + err = copy_msghdr_from_user(msg, umsg, uaddr, iov); |
---|
| 2560 | + } |
---|
| 2561 | + if (err < 0) |
---|
| 2562 | + return err; |
---|
| 2563 | + |
---|
| 2564 | + return 0; |
---|
| 2565 | +} |
---|
| 2566 | + |
---|
| 2567 | +static int ____sys_recvmsg(struct socket *sock, struct msghdr *msg_sys, |
---|
| 2568 | + struct user_msghdr __user *msg, |
---|
| 2569 | + struct sockaddr __user *uaddr, |
---|
| 2570 | + unsigned int flags, int nosec) |
---|
2356 | 2571 | { |
---|
2357 | 2572 | struct compat_msghdr __user *msg_compat = |
---|
2358 | | - (struct compat_msghdr __user *)msg; |
---|
2359 | | - struct iovec iovstack[UIO_FASTIOV]; |
---|
2360 | | - struct iovec *iov = iovstack; |
---|
| 2573 | + (struct compat_msghdr __user *) msg; |
---|
| 2574 | + int __user *uaddr_len = COMPAT_NAMELEN(msg); |
---|
| 2575 | + struct sockaddr_storage addr; |
---|
2361 | 2576 | unsigned long cmsg_ptr; |
---|
2362 | 2577 | int len; |
---|
2363 | 2578 | ssize_t err; |
---|
2364 | 2579 | |
---|
2365 | | - /* kernel mode address */ |
---|
2366 | | - struct sockaddr_storage addr; |
---|
2367 | | - |
---|
2368 | | - /* user mode address pointers */ |
---|
2369 | | - struct sockaddr __user *uaddr; |
---|
2370 | | - int __user *uaddr_len = COMPAT_NAMELEN(msg); |
---|
2371 | | - |
---|
2372 | 2580 | msg_sys->msg_name = &addr; |
---|
2373 | | - |
---|
2374 | | - if (MSG_CMSG_COMPAT & flags) |
---|
2375 | | - err = get_compat_msghdr(msg_sys, msg_compat, &uaddr, &iov); |
---|
2376 | | - else |
---|
2377 | | - err = copy_msghdr_from_user(msg_sys, msg, &uaddr, &iov); |
---|
2378 | | - if (err < 0) |
---|
2379 | | - return err; |
---|
2380 | | - |
---|
2381 | 2581 | cmsg_ptr = (unsigned long)msg_sys->msg_control; |
---|
2382 | 2582 | msg_sys->msg_flags = flags & (MSG_CMSG_CLOEXEC|MSG_CMSG_COMPAT); |
---|
2383 | 2583 | |
---|
.. | .. |
---|
2386 | 2586 | |
---|
2387 | 2587 | if (sock->file->f_flags & O_NONBLOCK) |
---|
2388 | 2588 | flags |= MSG_DONTWAIT; |
---|
2389 | | - err = (nosec ? sock_recvmsg_nosec : sock_recvmsg)(sock, msg_sys, flags); |
---|
| 2589 | + |
---|
| 2590 | + if (unlikely(nosec)) |
---|
| 2591 | + err = sock_recvmsg_nosec(sock, msg_sys, flags); |
---|
| 2592 | + else |
---|
| 2593 | + err = sock_recvmsg(sock, msg_sys, flags); |
---|
| 2594 | + |
---|
2390 | 2595 | if (err < 0) |
---|
2391 | | - goto out_freeiov; |
---|
| 2596 | + goto out; |
---|
2392 | 2597 | len = err; |
---|
2393 | 2598 | |
---|
2394 | 2599 | if (uaddr != NULL) { |
---|
.. | .. |
---|
2396 | 2601 | msg_sys->msg_namelen, uaddr, |
---|
2397 | 2602 | uaddr_len); |
---|
2398 | 2603 | if (err < 0) |
---|
2399 | | - goto out_freeiov; |
---|
| 2604 | + goto out; |
---|
2400 | 2605 | } |
---|
2401 | 2606 | err = __put_user((msg_sys->msg_flags & ~MSG_CMSG_COMPAT), |
---|
2402 | 2607 | COMPAT_FLAGS(msg)); |
---|
2403 | 2608 | if (err) |
---|
2404 | | - goto out_freeiov; |
---|
| 2609 | + goto out; |
---|
2405 | 2610 | if (MSG_CMSG_COMPAT & flags) |
---|
2406 | 2611 | err = __put_user((unsigned long)msg_sys->msg_control - cmsg_ptr, |
---|
2407 | 2612 | &msg_compat->msg_controllen); |
---|
.. | .. |
---|
2409 | 2614 | err = __put_user((unsigned long)msg_sys->msg_control - cmsg_ptr, |
---|
2410 | 2615 | &msg->msg_controllen); |
---|
2411 | 2616 | if (err) |
---|
2412 | | - goto out_freeiov; |
---|
| 2617 | + goto out; |
---|
2413 | 2618 | err = len; |
---|
| 2619 | +out: |
---|
| 2620 | + return err; |
---|
| 2621 | +} |
---|
2414 | 2622 | |
---|
2415 | | -out_freeiov: |
---|
| 2623 | +static int ___sys_recvmsg(struct socket *sock, struct user_msghdr __user *msg, |
---|
| 2624 | + struct msghdr *msg_sys, unsigned int flags, int nosec) |
---|
| 2625 | +{ |
---|
| 2626 | + struct iovec iovstack[UIO_FASTIOV], *iov = iovstack; |
---|
| 2627 | + /* user mode address pointers */ |
---|
| 2628 | + struct sockaddr __user *uaddr; |
---|
| 2629 | + ssize_t err; |
---|
| 2630 | + |
---|
| 2631 | + err = recvmsg_copy_msghdr(msg_sys, msg, flags, &uaddr, &iov); |
---|
| 2632 | + if (err < 0) |
---|
| 2633 | + return err; |
---|
| 2634 | + |
---|
| 2635 | + err = ____sys_recvmsg(sock, msg_sys, msg, uaddr, flags, nosec); |
---|
2416 | 2636 | kfree(iov); |
---|
2417 | 2637 | return err; |
---|
2418 | 2638 | } |
---|
.. | .. |
---|
2420 | 2640 | /* |
---|
2421 | 2641 | * BSD recvmsg interface |
---|
2422 | 2642 | */ |
---|
| 2643 | + |
---|
| 2644 | +long __sys_recvmsg_sock(struct socket *sock, struct msghdr *msg, |
---|
| 2645 | + struct user_msghdr __user *umsg, |
---|
| 2646 | + struct sockaddr __user *uaddr, unsigned int flags) |
---|
| 2647 | +{ |
---|
| 2648 | + return ____sys_recvmsg(sock, msg, umsg, uaddr, flags, 0); |
---|
| 2649 | +} |
---|
2423 | 2650 | |
---|
2424 | 2651 | long __sys_recvmsg(int fd, struct user_msghdr __user *msg, unsigned int flags, |
---|
2425 | 2652 | bool forbid_cmsg_compat) |
---|
.. | .. |
---|
2452 | 2679 | * Linux recvmmsg interface |
---|
2453 | 2680 | */ |
---|
2454 | 2681 | |
---|
2455 | | -int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, |
---|
2456 | | - unsigned int flags, struct timespec *timeout) |
---|
| 2682 | +static int do_recvmmsg(int fd, struct mmsghdr __user *mmsg, |
---|
| 2683 | + unsigned int vlen, unsigned int flags, |
---|
| 2684 | + struct timespec64 *timeout) |
---|
2457 | 2685 | { |
---|
2458 | 2686 | int fput_needed, err, datagrams; |
---|
2459 | 2687 | struct socket *sock; |
---|
.. | .. |
---|
2518 | 2746 | |
---|
2519 | 2747 | if (timeout) { |
---|
2520 | 2748 | ktime_get_ts64(&timeout64); |
---|
2521 | | - *timeout = timespec64_to_timespec( |
---|
2522 | | - timespec64_sub(end_time, timeout64)); |
---|
| 2749 | + *timeout = timespec64_sub(end_time, timeout64); |
---|
2523 | 2750 | if (timeout->tv_sec < 0) { |
---|
2524 | 2751 | timeout->tv_sec = timeout->tv_nsec = 0; |
---|
2525 | 2752 | break; |
---|
.. | .. |
---|
2555 | 2782 | * error to return on the next call or if the |
---|
2556 | 2783 | * app asks about it using getsockopt(SO_ERROR). |
---|
2557 | 2784 | */ |
---|
2558 | | - sock->sk->sk_err = -err; |
---|
| 2785 | + WRITE_ONCE(sock->sk->sk_err, -err); |
---|
2559 | 2786 | } |
---|
2560 | 2787 | out_put: |
---|
2561 | 2788 | fput_light(sock->file, fput_needed); |
---|
.. | .. |
---|
2563 | 2790 | return datagrams; |
---|
2564 | 2791 | } |
---|
2565 | 2792 | |
---|
2566 | | -static int do_sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, |
---|
2567 | | - unsigned int vlen, unsigned int flags, |
---|
2568 | | - struct timespec __user *timeout) |
---|
| 2793 | +int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, |
---|
| 2794 | + unsigned int vlen, unsigned int flags, |
---|
| 2795 | + struct __kernel_timespec __user *timeout, |
---|
| 2796 | + struct old_timespec32 __user *timeout32) |
---|
2569 | 2797 | { |
---|
2570 | 2798 | int datagrams; |
---|
2571 | | - struct timespec timeout_sys; |
---|
| 2799 | + struct timespec64 timeout_sys; |
---|
2572 | 2800 | |
---|
2573 | | - if (flags & MSG_CMSG_COMPAT) |
---|
2574 | | - return -EINVAL; |
---|
2575 | | - |
---|
2576 | | - if (!timeout) |
---|
2577 | | - return __sys_recvmmsg(fd, mmsg, vlen, flags, NULL); |
---|
2578 | | - |
---|
2579 | | - if (copy_from_user(&timeout_sys, timeout, sizeof(timeout_sys))) |
---|
| 2801 | + if (timeout && get_timespec64(&timeout_sys, timeout)) |
---|
2580 | 2802 | return -EFAULT; |
---|
2581 | 2803 | |
---|
2582 | | - datagrams = __sys_recvmmsg(fd, mmsg, vlen, flags, &timeout_sys); |
---|
| 2804 | + if (timeout32 && get_old_timespec32(&timeout_sys, timeout32)) |
---|
| 2805 | + return -EFAULT; |
---|
2583 | 2806 | |
---|
2584 | | - if (datagrams > 0 && |
---|
2585 | | - copy_to_user(timeout, &timeout_sys, sizeof(timeout_sys))) |
---|
| 2807 | + if (!timeout && !timeout32) |
---|
| 2808 | + return do_recvmmsg(fd, mmsg, vlen, flags, NULL); |
---|
| 2809 | + |
---|
| 2810 | + datagrams = do_recvmmsg(fd, mmsg, vlen, flags, &timeout_sys); |
---|
| 2811 | + |
---|
| 2812 | + if (datagrams <= 0) |
---|
| 2813 | + return datagrams; |
---|
| 2814 | + |
---|
| 2815 | + if (timeout && put_timespec64(&timeout_sys, timeout)) |
---|
| 2816 | + datagrams = -EFAULT; |
---|
| 2817 | + |
---|
| 2818 | + if (timeout32 && put_old_timespec32(&timeout_sys, timeout32)) |
---|
2586 | 2819 | datagrams = -EFAULT; |
---|
2587 | 2820 | |
---|
2588 | 2821 | return datagrams; |
---|
.. | .. |
---|
2590 | 2823 | |
---|
2591 | 2824 | SYSCALL_DEFINE5(recvmmsg, int, fd, struct mmsghdr __user *, mmsg, |
---|
2592 | 2825 | unsigned int, vlen, unsigned int, flags, |
---|
2593 | | - struct timespec __user *, timeout) |
---|
| 2826 | + struct __kernel_timespec __user *, timeout) |
---|
2594 | 2827 | { |
---|
2595 | | - return do_sys_recvmmsg(fd, mmsg, vlen, flags, timeout); |
---|
| 2828 | + if (flags & MSG_CMSG_COMPAT) |
---|
| 2829 | + return -EINVAL; |
---|
| 2830 | + |
---|
| 2831 | + return __sys_recvmmsg(fd, mmsg, vlen, flags, timeout, NULL); |
---|
2596 | 2832 | } |
---|
| 2833 | + |
---|
| 2834 | +#ifdef CONFIG_COMPAT_32BIT_TIME |
---|
| 2835 | +SYSCALL_DEFINE5(recvmmsg_time32, int, fd, struct mmsghdr __user *, mmsg, |
---|
| 2836 | + unsigned int, vlen, unsigned int, flags, |
---|
| 2837 | + struct old_timespec32 __user *, timeout) |
---|
| 2838 | +{ |
---|
| 2839 | + if (flags & MSG_CMSG_COMPAT) |
---|
| 2840 | + return -EINVAL; |
---|
| 2841 | + |
---|
| 2842 | + return __sys_recvmmsg(fd, mmsg, vlen, flags, NULL, timeout); |
---|
| 2843 | +} |
---|
| 2844 | +#endif |
---|
2597 | 2845 | |
---|
2598 | 2846 | #ifdef __ARCH_WANT_SYS_SOCKETCALL |
---|
2599 | 2847 | /* Argument list sizes for sys_socketcall */ |
---|
.. | .. |
---|
2713 | 2961 | a[2], true); |
---|
2714 | 2962 | break; |
---|
2715 | 2963 | case SYS_RECVMMSG: |
---|
2716 | | - err = do_sys_recvmmsg(a0, (struct mmsghdr __user *)a1, a[2], |
---|
2717 | | - a[3], (struct timespec __user *)a[4]); |
---|
| 2964 | + if (IS_ENABLED(CONFIG_64BIT)) |
---|
| 2965 | + err = __sys_recvmmsg(a0, (struct mmsghdr __user *)a1, |
---|
| 2966 | + a[2], a[3], |
---|
| 2967 | + (struct __kernel_timespec __user *)a[4], |
---|
| 2968 | + NULL); |
---|
| 2969 | + else |
---|
| 2970 | + err = __sys_recvmmsg(a0, (struct mmsghdr __user *)a1, |
---|
| 2971 | + a[2], a[3], NULL, |
---|
| 2972 | + (struct old_timespec32 __user *)a[4]); |
---|
2718 | 2973 | break; |
---|
2719 | 2974 | case SYS_ACCEPT4: |
---|
2720 | 2975 | err = __sys_accept4(a0, (struct sockaddr __user *)a1, |
---|
.. | .. |
---|
2817 | 3072 | |
---|
2818 | 3073 | err = register_filesystem(&sock_fs_type); |
---|
2819 | 3074 | if (err) |
---|
2820 | | - goto out_fs; |
---|
| 3075 | + goto out; |
---|
2821 | 3076 | sock_mnt = kern_mount(&sock_fs_type); |
---|
2822 | 3077 | if (IS_ERR(sock_mnt)) { |
---|
2823 | 3078 | err = PTR_ERR(sock_mnt); |
---|
.. | .. |
---|
2840 | 3095 | |
---|
2841 | 3096 | out_mount: |
---|
2842 | 3097 | unregister_filesystem(&sock_fs_type); |
---|
2843 | | -out_fs: |
---|
2844 | 3098 | goto out; |
---|
2845 | 3099 | } |
---|
2846 | 3100 | |
---|
.. | .. |
---|
2855 | 3109 | #endif /* CONFIG_PROC_FS */ |
---|
2856 | 3110 | |
---|
2857 | 3111 | #ifdef CONFIG_COMPAT |
---|
2858 | | -static int do_siocgstamp(struct net *net, struct socket *sock, |
---|
2859 | | - unsigned int cmd, void __user *up) |
---|
2860 | | -{ |
---|
2861 | | - mm_segment_t old_fs = get_fs(); |
---|
2862 | | - struct timeval ktv; |
---|
2863 | | - int err; |
---|
2864 | | - |
---|
2865 | | - set_fs(KERNEL_DS); |
---|
2866 | | - err = sock_do_ioctl(net, sock, cmd, (unsigned long)&ktv); |
---|
2867 | | - set_fs(old_fs); |
---|
2868 | | - if (!err) |
---|
2869 | | - err = compat_put_timeval(&ktv, up); |
---|
2870 | | - |
---|
2871 | | - return err; |
---|
2872 | | -} |
---|
2873 | | - |
---|
2874 | | -static int do_siocgstampns(struct net *net, struct socket *sock, |
---|
2875 | | - unsigned int cmd, void __user *up) |
---|
2876 | | -{ |
---|
2877 | | - mm_segment_t old_fs = get_fs(); |
---|
2878 | | - struct timespec kts; |
---|
2879 | | - int err; |
---|
2880 | | - |
---|
2881 | | - set_fs(KERNEL_DS); |
---|
2882 | | - err = sock_do_ioctl(net, sock, cmd, (unsigned long)&kts); |
---|
2883 | | - set_fs(old_fs); |
---|
2884 | | - if (!err) |
---|
2885 | | - err = compat_put_timespec(&kts, up); |
---|
2886 | | - |
---|
2887 | | - return err; |
---|
2888 | | -} |
---|
2889 | | - |
---|
2890 | 3112 | static int compat_dev_ifconf(struct net *net, struct compat_ifconf __user *uifc32) |
---|
2891 | 3113 | { |
---|
2892 | 3114 | struct compat_ifconf ifc32; |
---|
.. | .. |
---|
2908 | 3130 | ifc32.ifc_len = ifc.ifc_len; |
---|
2909 | 3131 | if (copy_to_user(uifc32, &ifc32, sizeof(struct compat_ifconf))) |
---|
2910 | 3132 | return -EFAULT; |
---|
2911 | | - |
---|
2912 | | - return 0; |
---|
2913 | | -} |
---|
2914 | | - |
---|
2915 | | -static int ethtool_ioctl(struct net *net, struct compat_ifreq __user *ifr32) |
---|
2916 | | -{ |
---|
2917 | | - struct compat_ethtool_rxnfc __user *compat_rxnfc; |
---|
2918 | | - bool convert_in = false, convert_out = false; |
---|
2919 | | - size_t buf_size = 0; |
---|
2920 | | - struct ethtool_rxnfc __user *rxnfc = NULL; |
---|
2921 | | - struct ifreq ifr; |
---|
2922 | | - u32 rule_cnt = 0, actual_rule_cnt; |
---|
2923 | | - u32 ethcmd; |
---|
2924 | | - u32 data; |
---|
2925 | | - int ret; |
---|
2926 | | - |
---|
2927 | | - if (get_user(data, &ifr32->ifr_ifru.ifru_data)) |
---|
2928 | | - return -EFAULT; |
---|
2929 | | - |
---|
2930 | | - compat_rxnfc = compat_ptr(data); |
---|
2931 | | - |
---|
2932 | | - if (get_user(ethcmd, &compat_rxnfc->cmd)) |
---|
2933 | | - return -EFAULT; |
---|
2934 | | - |
---|
2935 | | - /* Most ethtool structures are defined without padding. |
---|
2936 | | - * Unfortunately struct ethtool_rxnfc is an exception. |
---|
2937 | | - */ |
---|
2938 | | - switch (ethcmd) { |
---|
2939 | | - default: |
---|
2940 | | - break; |
---|
2941 | | - case ETHTOOL_GRXCLSRLALL: |
---|
2942 | | - /* Buffer size is variable */ |
---|
2943 | | - if (get_user(rule_cnt, &compat_rxnfc->rule_cnt)) |
---|
2944 | | - return -EFAULT; |
---|
2945 | | - if (rule_cnt > KMALLOC_MAX_SIZE / sizeof(u32)) |
---|
2946 | | - return -ENOMEM; |
---|
2947 | | - buf_size += rule_cnt * sizeof(u32); |
---|
2948 | | - /* fall through */ |
---|
2949 | | - case ETHTOOL_GRXRINGS: |
---|
2950 | | - case ETHTOOL_GRXCLSRLCNT: |
---|
2951 | | - case ETHTOOL_GRXCLSRULE: |
---|
2952 | | - case ETHTOOL_SRXCLSRLINS: |
---|
2953 | | - convert_out = true; |
---|
2954 | | - /* fall through */ |
---|
2955 | | - case ETHTOOL_SRXCLSRLDEL: |
---|
2956 | | - buf_size += sizeof(struct ethtool_rxnfc); |
---|
2957 | | - convert_in = true; |
---|
2958 | | - rxnfc = compat_alloc_user_space(buf_size); |
---|
2959 | | - break; |
---|
2960 | | - } |
---|
2961 | | - |
---|
2962 | | - if (copy_from_user(&ifr.ifr_name, &ifr32->ifr_name, IFNAMSIZ)) |
---|
2963 | | - return -EFAULT; |
---|
2964 | | - |
---|
2965 | | - ifr.ifr_data = convert_in ? rxnfc : (void __user *)compat_rxnfc; |
---|
2966 | | - |
---|
2967 | | - if (convert_in) { |
---|
2968 | | - /* We expect there to be holes between fs.m_ext and |
---|
2969 | | - * fs.ring_cookie and at the end of fs, but nowhere else. |
---|
2970 | | - */ |
---|
2971 | | - BUILD_BUG_ON(offsetof(struct compat_ethtool_rxnfc, fs.m_ext) + |
---|
2972 | | - sizeof(compat_rxnfc->fs.m_ext) != |
---|
2973 | | - offsetof(struct ethtool_rxnfc, fs.m_ext) + |
---|
2974 | | - sizeof(rxnfc->fs.m_ext)); |
---|
2975 | | - BUILD_BUG_ON( |
---|
2976 | | - offsetof(struct compat_ethtool_rxnfc, fs.location) - |
---|
2977 | | - offsetof(struct compat_ethtool_rxnfc, fs.ring_cookie) != |
---|
2978 | | - offsetof(struct ethtool_rxnfc, fs.location) - |
---|
2979 | | - offsetof(struct ethtool_rxnfc, fs.ring_cookie)); |
---|
2980 | | - |
---|
2981 | | - if (copy_in_user(rxnfc, compat_rxnfc, |
---|
2982 | | - (void __user *)(&rxnfc->fs.m_ext + 1) - |
---|
2983 | | - (void __user *)rxnfc) || |
---|
2984 | | - copy_in_user(&rxnfc->fs.ring_cookie, |
---|
2985 | | - &compat_rxnfc->fs.ring_cookie, |
---|
2986 | | - (void __user *)(&rxnfc->fs.location + 1) - |
---|
2987 | | - (void __user *)&rxnfc->fs.ring_cookie)) |
---|
2988 | | - return -EFAULT; |
---|
2989 | | - if (ethcmd == ETHTOOL_GRXCLSRLALL) { |
---|
2990 | | - if (put_user(rule_cnt, &rxnfc->rule_cnt)) |
---|
2991 | | - return -EFAULT; |
---|
2992 | | - } else if (copy_in_user(&rxnfc->rule_cnt, |
---|
2993 | | - &compat_rxnfc->rule_cnt, |
---|
2994 | | - sizeof(rxnfc->rule_cnt))) |
---|
2995 | | - return -EFAULT; |
---|
2996 | | - } |
---|
2997 | | - |
---|
2998 | | - ret = dev_ioctl(net, SIOCETHTOOL, &ifr, NULL); |
---|
2999 | | - if (ret) |
---|
3000 | | - return ret; |
---|
3001 | | - |
---|
3002 | | - if (convert_out) { |
---|
3003 | | - if (copy_in_user(compat_rxnfc, rxnfc, |
---|
3004 | | - (const void __user *)(&rxnfc->fs.m_ext + 1) - |
---|
3005 | | - (const void __user *)rxnfc) || |
---|
3006 | | - copy_in_user(&compat_rxnfc->fs.ring_cookie, |
---|
3007 | | - &rxnfc->fs.ring_cookie, |
---|
3008 | | - (const void __user *)(&rxnfc->fs.location + 1) - |
---|
3009 | | - (const void __user *)&rxnfc->fs.ring_cookie) || |
---|
3010 | | - copy_in_user(&compat_rxnfc->rule_cnt, &rxnfc->rule_cnt, |
---|
3011 | | - sizeof(rxnfc->rule_cnt))) |
---|
3012 | | - return -EFAULT; |
---|
3013 | | - |
---|
3014 | | - if (ethcmd == ETHTOOL_GRXCLSRLALL) { |
---|
3015 | | - /* As an optimisation, we only copy the actual |
---|
3016 | | - * number of rules that the underlying |
---|
3017 | | - * function returned. Since Mallory might |
---|
3018 | | - * change the rule count in user memory, we |
---|
3019 | | - * check that it is less than the rule count |
---|
3020 | | - * originally given (as the user buffer size), |
---|
3021 | | - * which has been range-checked. |
---|
3022 | | - */ |
---|
3023 | | - if (get_user(actual_rule_cnt, &rxnfc->rule_cnt)) |
---|
3024 | | - return -EFAULT; |
---|
3025 | | - if (actual_rule_cnt < rule_cnt) |
---|
3026 | | - rule_cnt = actual_rule_cnt; |
---|
3027 | | - if (copy_in_user(&compat_rxnfc->rule_locs[0], |
---|
3028 | | - &rxnfc->rule_locs[0], |
---|
3029 | | - rule_cnt * sizeof(u32))) |
---|
3030 | | - return -EFAULT; |
---|
3031 | | - } |
---|
3032 | | - } |
---|
3033 | 3133 | |
---|
3034 | 3134 | return 0; |
---|
3035 | 3135 | } |
---|
.. | .. |
---|
3159 | 3259 | return err; |
---|
3160 | 3260 | } |
---|
3161 | 3261 | |
---|
3162 | | -struct rtentry32 { |
---|
3163 | | - u32 rt_pad1; |
---|
3164 | | - struct sockaddr rt_dst; /* target address */ |
---|
3165 | | - struct sockaddr rt_gateway; /* gateway addr (RTF_GATEWAY) */ |
---|
3166 | | - struct sockaddr rt_genmask; /* target network mask (IP) */ |
---|
3167 | | - unsigned short rt_flags; |
---|
3168 | | - short rt_pad2; |
---|
3169 | | - u32 rt_pad3; |
---|
3170 | | - unsigned char rt_tos; |
---|
3171 | | - unsigned char rt_class; |
---|
3172 | | - short rt_pad4; |
---|
3173 | | - short rt_metric; /* +1 for binary compatibility! */ |
---|
3174 | | - /* char * */ u32 rt_dev; /* forcing the device at add */ |
---|
3175 | | - u32 rt_mtu; /* per route MTU/Window */ |
---|
3176 | | - u32 rt_window; /* Window clamping */ |
---|
3177 | | - unsigned short rt_irtt; /* Initial RTT */ |
---|
3178 | | -}; |
---|
3179 | | - |
---|
3180 | | -struct in6_rtmsg32 { |
---|
3181 | | - struct in6_addr rtmsg_dst; |
---|
3182 | | - struct in6_addr rtmsg_src; |
---|
3183 | | - struct in6_addr rtmsg_gateway; |
---|
3184 | | - u32 rtmsg_type; |
---|
3185 | | - u16 rtmsg_dst_len; |
---|
3186 | | - u16 rtmsg_src_len; |
---|
3187 | | - u32 rtmsg_metric; |
---|
3188 | | - u32 rtmsg_info; |
---|
3189 | | - u32 rtmsg_flags; |
---|
3190 | | - s32 rtmsg_ifindex; |
---|
3191 | | -}; |
---|
3192 | | - |
---|
3193 | | -static int routing_ioctl(struct net *net, struct socket *sock, |
---|
3194 | | - unsigned int cmd, void __user *argp) |
---|
3195 | | -{ |
---|
3196 | | - int ret; |
---|
3197 | | - void *r = NULL; |
---|
3198 | | - struct in6_rtmsg r6; |
---|
3199 | | - struct rtentry r4; |
---|
3200 | | - char devname[16]; |
---|
3201 | | - u32 rtdev; |
---|
3202 | | - mm_segment_t old_fs = get_fs(); |
---|
3203 | | - |
---|
3204 | | - if (sock && sock->sk && sock->sk->sk_family == AF_INET6) { /* ipv6 */ |
---|
3205 | | - struct in6_rtmsg32 __user *ur6 = argp; |
---|
3206 | | - ret = copy_from_user(&r6.rtmsg_dst, &(ur6->rtmsg_dst), |
---|
3207 | | - 3 * sizeof(struct in6_addr)); |
---|
3208 | | - ret |= get_user(r6.rtmsg_type, &(ur6->rtmsg_type)); |
---|
3209 | | - ret |= get_user(r6.rtmsg_dst_len, &(ur6->rtmsg_dst_len)); |
---|
3210 | | - ret |= get_user(r6.rtmsg_src_len, &(ur6->rtmsg_src_len)); |
---|
3211 | | - ret |= get_user(r6.rtmsg_metric, &(ur6->rtmsg_metric)); |
---|
3212 | | - ret |= get_user(r6.rtmsg_info, &(ur6->rtmsg_info)); |
---|
3213 | | - ret |= get_user(r6.rtmsg_flags, &(ur6->rtmsg_flags)); |
---|
3214 | | - ret |= get_user(r6.rtmsg_ifindex, &(ur6->rtmsg_ifindex)); |
---|
3215 | | - |
---|
3216 | | - r = (void *) &r6; |
---|
3217 | | - } else { /* ipv4 */ |
---|
3218 | | - struct rtentry32 __user *ur4 = argp; |
---|
3219 | | - ret = copy_from_user(&r4.rt_dst, &(ur4->rt_dst), |
---|
3220 | | - 3 * sizeof(struct sockaddr)); |
---|
3221 | | - ret |= get_user(r4.rt_flags, &(ur4->rt_flags)); |
---|
3222 | | - ret |= get_user(r4.rt_metric, &(ur4->rt_metric)); |
---|
3223 | | - ret |= get_user(r4.rt_mtu, &(ur4->rt_mtu)); |
---|
3224 | | - ret |= get_user(r4.rt_window, &(ur4->rt_window)); |
---|
3225 | | - ret |= get_user(r4.rt_irtt, &(ur4->rt_irtt)); |
---|
3226 | | - ret |= get_user(rtdev, &(ur4->rt_dev)); |
---|
3227 | | - if (rtdev) { |
---|
3228 | | - ret |= copy_from_user(devname, compat_ptr(rtdev), 15); |
---|
3229 | | - r4.rt_dev = (char __user __force *)devname; |
---|
3230 | | - devname[15] = 0; |
---|
3231 | | - } else |
---|
3232 | | - r4.rt_dev = NULL; |
---|
3233 | | - |
---|
3234 | | - r = (void *) &r4; |
---|
3235 | | - } |
---|
3236 | | - |
---|
3237 | | - if (ret) { |
---|
3238 | | - ret = -EFAULT; |
---|
3239 | | - goto out; |
---|
3240 | | - } |
---|
3241 | | - |
---|
3242 | | - set_fs(KERNEL_DS); |
---|
3243 | | - ret = sock_do_ioctl(net, sock, cmd, (unsigned long) r); |
---|
3244 | | - set_fs(old_fs); |
---|
3245 | | - |
---|
3246 | | -out: |
---|
3247 | | - return ret; |
---|
3248 | | -} |
---|
3249 | | - |
---|
3250 | 3262 | /* Since old style bridge ioctl's endup using SIOCDEVPRIVATE |
---|
3251 | 3263 | * for some operations; this forces use of the newer bridge-utils that |
---|
3252 | 3264 | * use compatible ioctls |
---|
.. | .. |
---|
3278 | 3290 | return old_bridge_ioctl(argp); |
---|
3279 | 3291 | case SIOCGIFCONF: |
---|
3280 | 3292 | return compat_dev_ifconf(net, argp); |
---|
3281 | | - case SIOCETHTOOL: |
---|
3282 | | - return ethtool_ioctl(net, argp); |
---|
3283 | 3293 | case SIOCWANDEV: |
---|
3284 | 3294 | return compat_siocwandev(net, argp); |
---|
3285 | 3295 | case SIOCGIFMAP: |
---|
3286 | 3296 | case SIOCSIFMAP: |
---|
3287 | 3297 | return compat_sioc_ifmap(net, cmd, argp); |
---|
3288 | | - case SIOCADDRT: |
---|
3289 | | - case SIOCDELRT: |
---|
3290 | | - return routing_ioctl(net, sock, cmd, argp); |
---|
3291 | | - case SIOCGSTAMP: |
---|
3292 | | - return do_siocgstamp(net, sock, cmd, argp); |
---|
3293 | | - case SIOCGSTAMPNS: |
---|
3294 | | - return do_siocgstampns(net, sock, cmd, argp); |
---|
| 3298 | + case SIOCGSTAMP_OLD: |
---|
| 3299 | + case SIOCGSTAMPNS_OLD: |
---|
| 3300 | + if (!sock->ops->gettstamp) |
---|
| 3301 | + return -ENOIOCTLCMD; |
---|
| 3302 | + return sock->ops->gettstamp(sock, argp, cmd == SIOCGSTAMP_OLD, |
---|
| 3303 | + !COMPAT_USE_64BIT_TIME); |
---|
| 3304 | + |
---|
| 3305 | + case SIOCETHTOOL: |
---|
3295 | 3306 | case SIOCBONDSLAVEINFOQUERY: |
---|
3296 | 3307 | case SIOCBONDINFOQUERY: |
---|
3297 | 3308 | case SIOCSHWTSTAMP: |
---|
.. | .. |
---|
3309 | 3320 | case SIOCADDDLCI: |
---|
3310 | 3321 | case SIOCDELDLCI: |
---|
3311 | 3322 | case SIOCGSKNS: |
---|
| 3323 | + case SIOCGSTAMP_NEW: |
---|
| 3324 | + case SIOCGSTAMPNS_NEW: |
---|
3312 | 3325 | return sock_ioctl(file, cmd, arg); |
---|
3313 | 3326 | |
---|
3314 | 3327 | case SIOCGIFFLAGS: |
---|
.. | .. |
---|
3354 | 3367 | case SIOCSARP: |
---|
3355 | 3368 | case SIOCGARP: |
---|
3356 | 3369 | case SIOCDARP: |
---|
| 3370 | + case SIOCOUTQ: |
---|
3357 | 3371 | case SIOCOUTQNSD: |
---|
3358 | 3372 | case SIOCATMARK: |
---|
3359 | 3373 | return sock_do_ioctl(net, sock, cmd, arg); |
---|
.. | .. |
---|
3468 | 3482 | int kernel_connect(struct socket *sock, struct sockaddr *addr, int addrlen, |
---|
3469 | 3483 | int flags) |
---|
3470 | 3484 | { |
---|
3471 | | - return sock->ops->connect(sock, addr, addrlen, flags); |
---|
| 3485 | + struct sockaddr_storage address; |
---|
| 3486 | + |
---|
| 3487 | + memcpy(&address, addr, addrlen); |
---|
| 3488 | + |
---|
| 3489 | + return sock->ops->connect(sock, (struct sockaddr *)&address, addrlen, flags); |
---|
3472 | 3490 | } |
---|
3473 | 3491 | EXPORT_SYMBOL(kernel_connect); |
---|
3474 | 3492 | |
---|
.. | .. |
---|
3488 | 3506 | EXPORT_SYMBOL(kernel_getsockname); |
---|
3489 | 3507 | |
---|
3490 | 3508 | /** |
---|
3491 | | - * kernel_peername - get the address which the socket is connected (kernel space) |
---|
| 3509 | + * kernel_getpeername - get the address which the socket is connected (kernel space) |
---|
3492 | 3510 | * @sock: socket |
---|
3493 | 3511 | * @addr: address holder |
---|
3494 | 3512 | * |
---|
.. | .. |
---|
3501 | 3519 | return sock->ops->getname(sock, addr, 1); |
---|
3502 | 3520 | } |
---|
3503 | 3521 | EXPORT_SYMBOL(kernel_getpeername); |
---|
3504 | | - |
---|
3505 | | -/** |
---|
3506 | | - * kernel_getsockopt - get a socket option (kernel space) |
---|
3507 | | - * @sock: socket |
---|
3508 | | - * @level: API level (SOL_SOCKET, ...) |
---|
3509 | | - * @optname: option tag |
---|
3510 | | - * @optval: option value |
---|
3511 | | - * @optlen: option length |
---|
3512 | | - * |
---|
3513 | | - * Assigns the option length to @optlen. |
---|
3514 | | - * Returns 0 or an error. |
---|
3515 | | - */ |
---|
3516 | | - |
---|
3517 | | -int kernel_getsockopt(struct socket *sock, int level, int optname, |
---|
3518 | | - char *optval, int *optlen) |
---|
3519 | | -{ |
---|
3520 | | - mm_segment_t oldfs = get_fs(); |
---|
3521 | | - char __user *uoptval; |
---|
3522 | | - int __user *uoptlen; |
---|
3523 | | - int err; |
---|
3524 | | - |
---|
3525 | | - uoptval = (char __user __force *) optval; |
---|
3526 | | - uoptlen = (int __user __force *) optlen; |
---|
3527 | | - |
---|
3528 | | - set_fs(KERNEL_DS); |
---|
3529 | | - if (level == SOL_SOCKET) |
---|
3530 | | - err = sock_getsockopt(sock, level, optname, uoptval, uoptlen); |
---|
3531 | | - else |
---|
3532 | | - err = sock->ops->getsockopt(sock, level, optname, uoptval, |
---|
3533 | | - uoptlen); |
---|
3534 | | - set_fs(oldfs); |
---|
3535 | | - return err; |
---|
3536 | | -} |
---|
3537 | | -EXPORT_SYMBOL(kernel_getsockopt); |
---|
3538 | | - |
---|
3539 | | -/** |
---|
3540 | | - * kernel_setsockopt - set a socket option (kernel space) |
---|
3541 | | - * @sock: socket |
---|
3542 | | - * @level: API level (SOL_SOCKET, ...) |
---|
3543 | | - * @optname: option tag |
---|
3544 | | - * @optval: option value |
---|
3545 | | - * @optlen: option length |
---|
3546 | | - * |
---|
3547 | | - * Returns 0 or an error. |
---|
3548 | | - */ |
---|
3549 | | - |
---|
3550 | | -int kernel_setsockopt(struct socket *sock, int level, int optname, |
---|
3551 | | - char *optval, unsigned int optlen) |
---|
3552 | | -{ |
---|
3553 | | - mm_segment_t oldfs = get_fs(); |
---|
3554 | | - char __user *uoptval; |
---|
3555 | | - int err; |
---|
3556 | | - |
---|
3557 | | - uoptval = (char __user __force *) optval; |
---|
3558 | | - |
---|
3559 | | - set_fs(KERNEL_DS); |
---|
3560 | | - if (level == SOL_SOCKET) |
---|
3561 | | - err = sock_setsockopt(sock, level, optname, uoptval, optlen); |
---|
3562 | | - else |
---|
3563 | | - err = sock->ops->setsockopt(sock, level, optname, uoptval, |
---|
3564 | | - optlen); |
---|
3565 | | - set_fs(oldfs); |
---|
3566 | | - return err; |
---|
3567 | | -} |
---|
3568 | | -EXPORT_SYMBOL(kernel_setsockopt); |
---|
3569 | 3522 | |
---|
3570 | 3523 | /** |
---|
3571 | 3524 | * kernel_sendpage - send a &page through a socket (kernel space) |
---|
.. | .. |
---|
3581 | 3534 | int kernel_sendpage(struct socket *sock, struct page *page, int offset, |
---|
3582 | 3535 | size_t size, int flags) |
---|
3583 | 3536 | { |
---|
3584 | | - if (sock->ops->sendpage) |
---|
| 3537 | + if (sock->ops->sendpage) { |
---|
| 3538 | + /* Warn in case the improper page to zero-copy send */ |
---|
| 3539 | + WARN_ONCE(!sendpage_ok(page), "improper page for zero-copy send"); |
---|
3585 | 3540 | return sock->ops->sendpage(sock, page, offset, size, flags); |
---|
3586 | | - |
---|
| 3541 | + } |
---|
3587 | 3542 | return sock_no_sendpage(sock, page, offset, size, flags); |
---|
3588 | 3543 | } |
---|
3589 | 3544 | EXPORT_SYMBOL(kernel_sendpage); |
---|
.. | .. |
---|
3614 | 3569 | EXPORT_SYMBOL(kernel_sendpage_locked); |
---|
3615 | 3570 | |
---|
3616 | 3571 | /** |
---|
3617 | | - * kernel_shutdown - shut down part of a full-duplex connection (kernel space) |
---|
| 3572 | + * kernel_sock_shutdown - shut down part of a full-duplex connection (kernel space) |
---|
3618 | 3573 | * @sock: socket |
---|
3619 | 3574 | * @how: connection part |
---|
3620 | 3575 | * |
---|