| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * NET4: Implementation of BSD Unix domain sockets. |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Authors: Alan Cox, <alan@lxorguk.ukuu.org.uk> |
|---|
| 5 | | - * |
|---|
| 6 | | - * This program is free software; you can redistribute it and/or |
|---|
| 7 | | - * modify it under the terms of the GNU General Public License |
|---|
| 8 | | - * as published by the Free Software Foundation; either version |
|---|
| 9 | | - * 2 of the License, or (at your option) any later version. |
|---|
| 10 | 6 | * |
|---|
| 11 | 7 | * Fixes: |
|---|
| 12 | 8 | * Linus Torvalds : Assorted bug cures. |
|---|
| .. | .. |
|---|
| 48 | 44 | * Arnaldo C. Melo : Remove MOD_{INC,DEC}_USE_COUNT, |
|---|
| 49 | 45 | * the core infrastructure is doing that |
|---|
| 50 | 46 | * for all net proto families now (2.5.69+) |
|---|
| 51 | | - * |
|---|
| 52 | 47 | * |
|---|
| 53 | 48 | * Known differences from reference BSD that was tested: |
|---|
| 54 | 49 | * |
|---|
| .. | .. |
|---|
| 295 | 290 | |
|---|
| 296 | 291 | if (u->addr->len == len && |
|---|
| 297 | 292 | !memcmp(u->addr->name, sunname, len)) |
|---|
| 298 | | - goto found; |
|---|
| 293 | + return s; |
|---|
| 299 | 294 | } |
|---|
| 300 | | - s = NULL; |
|---|
| 301 | | -found: |
|---|
| 302 | | - return s; |
|---|
| 295 | + return NULL; |
|---|
| 303 | 296 | } |
|---|
| 304 | 297 | |
|---|
| 305 | 298 | static inline struct sock *unix_find_socket_byname(struct net *net, |
|---|
| .. | .. |
|---|
| 445 | 438 | * -ECONNREFUSED. Otherwise, if we haven't queued any skbs |
|---|
| 446 | 439 | * to other and its full, we will hang waiting for POLLOUT. |
|---|
| 447 | 440 | */ |
|---|
| 448 | | - if (unix_recvq_full(other) && !sock_flag(other, SOCK_DEAD)) |
|---|
| 441 | + if (unix_recvq_full_lockless(other) && !sock_flag(other, SOCK_DEAD)) |
|---|
| 449 | 442 | return 1; |
|---|
| 450 | 443 | |
|---|
| 451 | 444 | if (connected) |
|---|
| .. | .. |
|---|
| 643 | 636 | int err; |
|---|
| 644 | 637 | struct sock *sk = sock->sk; |
|---|
| 645 | 638 | struct unix_sock *u = unix_sk(sk); |
|---|
| 646 | | - struct pid *old_pid = NULL; |
|---|
| 647 | 639 | |
|---|
| 648 | 640 | err = -EOPNOTSUPP; |
|---|
| 649 | 641 | if (sock->type != SOCK_STREAM && sock->type != SOCK_SEQPACKET) |
|---|
| .. | .. |
|---|
| 664 | 656 | |
|---|
| 665 | 657 | out_unlock: |
|---|
| 666 | 658 | unix_state_unlock(sk); |
|---|
| 667 | | - put_pid(old_pid); |
|---|
| 668 | 659 | out: |
|---|
| 669 | 660 | return err; |
|---|
| 670 | 661 | } |
|---|
| .. | .. |
|---|
| 712 | 703 | return 0; |
|---|
| 713 | 704 | } |
|---|
| 714 | 705 | |
|---|
| 706 | +#ifdef CONFIG_PROC_FS |
|---|
| 707 | +static void unix_show_fdinfo(struct seq_file *m, struct socket *sock) |
|---|
| 708 | +{ |
|---|
| 709 | + struct sock *sk = sock->sk; |
|---|
| 710 | + struct unix_sock *u; |
|---|
| 711 | + |
|---|
| 712 | + if (sk) { |
|---|
| 713 | + u = unix_sk(sock->sk); |
|---|
| 714 | + seq_printf(m, "scm_fds: %u\n", |
|---|
| 715 | + atomic_read(&u->scm_stat.nr_fds)); |
|---|
| 716 | + } |
|---|
| 717 | +} |
|---|
| 718 | +#else |
|---|
| 719 | +#define unix_show_fdinfo NULL |
|---|
| 720 | +#endif |
|---|
| 715 | 721 | |
|---|
| 716 | 722 | static const struct proto_ops unix_stream_ops = { |
|---|
| 717 | 723 | .family = PF_UNIX, |
|---|
| .. | .. |
|---|
| 729 | 735 | #endif |
|---|
| 730 | 736 | .listen = unix_listen, |
|---|
| 731 | 737 | .shutdown = unix_shutdown, |
|---|
| 732 | | - .setsockopt = sock_no_setsockopt, |
|---|
| 733 | | - .getsockopt = sock_no_getsockopt, |
|---|
| 734 | 738 | .sendmsg = unix_stream_sendmsg, |
|---|
| 735 | 739 | .recvmsg = unix_stream_recvmsg, |
|---|
| 736 | 740 | .mmap = sock_no_mmap, |
|---|
| 737 | 741 | .sendpage = unix_stream_sendpage, |
|---|
| 738 | 742 | .splice_read = unix_stream_splice_read, |
|---|
| 739 | 743 | .set_peek_off = unix_set_peek_off, |
|---|
| 744 | + .show_fdinfo = unix_show_fdinfo, |
|---|
| 740 | 745 | }; |
|---|
| 741 | 746 | |
|---|
| 742 | 747 | static const struct proto_ops unix_dgram_ops = { |
|---|
| .. | .. |
|---|
| 755 | 760 | #endif |
|---|
| 756 | 761 | .listen = sock_no_listen, |
|---|
| 757 | 762 | .shutdown = unix_shutdown, |
|---|
| 758 | | - .setsockopt = sock_no_setsockopt, |
|---|
| 759 | | - .getsockopt = sock_no_getsockopt, |
|---|
| 760 | 763 | .sendmsg = unix_dgram_sendmsg, |
|---|
| 761 | 764 | .recvmsg = unix_dgram_recvmsg, |
|---|
| 762 | 765 | .mmap = sock_no_mmap, |
|---|
| 763 | 766 | .sendpage = sock_no_sendpage, |
|---|
| 764 | 767 | .set_peek_off = unix_set_peek_off, |
|---|
| 768 | + .show_fdinfo = unix_show_fdinfo, |
|---|
| 765 | 769 | }; |
|---|
| 766 | 770 | |
|---|
| 767 | 771 | static const struct proto_ops unix_seqpacket_ops = { |
|---|
| .. | .. |
|---|
| 780 | 784 | #endif |
|---|
| 781 | 785 | .listen = unix_listen, |
|---|
| 782 | 786 | .shutdown = unix_shutdown, |
|---|
| 783 | | - .setsockopt = sock_no_setsockopt, |
|---|
| 784 | | - .getsockopt = sock_no_getsockopt, |
|---|
| 785 | 787 | .sendmsg = unix_seqpacket_sendmsg, |
|---|
| 786 | 788 | .recvmsg = unix_seqpacket_recvmsg, |
|---|
| 787 | 789 | .mmap = sock_no_mmap, |
|---|
| 788 | 790 | .sendpage = sock_no_sendpage, |
|---|
| 789 | 791 | .set_peek_off = unix_set_peek_off, |
|---|
| 792 | + .show_fdinfo = unix_show_fdinfo, |
|---|
| 790 | 793 | }; |
|---|
| 791 | 794 | |
|---|
| 792 | 795 | static struct proto unix_proto = { |
|---|
| .. | .. |
|---|
| 824 | 827 | mutex_init(&u->bindlock); /* single task binding lock */ |
|---|
| 825 | 828 | init_waitqueue_head(&u->peer_wait); |
|---|
| 826 | 829 | init_waitqueue_func_entry(&u->peer_wake, unix_dgram_peer_wake_relay); |
|---|
| 830 | + memset(&u->scm_stat, 0, sizeof(struct scm_stat)); |
|---|
| 827 | 831 | unix_insert_socket(unix_sockets_unbound(sk), sk); |
|---|
| 828 | 832 | out: |
|---|
| 829 | 833 | if (sk == NULL) |
|---|
| .. | .. |
|---|
| 854 | 858 | */ |
|---|
| 855 | 859 | case SOCK_RAW: |
|---|
| 856 | 860 | sock->type = SOCK_DGRAM; |
|---|
| 857 | | - /* fall through */ |
|---|
| 861 | + fallthrough; |
|---|
| 858 | 862 | case SOCK_DGRAM: |
|---|
| 859 | 863 | sock->ops = &unix_dgram_ops; |
|---|
| 860 | 864 | break; |
|---|
| .. | .. |
|---|
| 895 | 899 | if (err) |
|---|
| 896 | 900 | return err; |
|---|
| 897 | 901 | |
|---|
| 898 | | - err = 0; |
|---|
| 899 | 902 | if (u->addr) |
|---|
| 900 | 903 | goto out; |
|---|
| 901 | 904 | |
|---|
| .. | .. |
|---|
| 1223 | 1226 | } |
|---|
| 1224 | 1227 | |
|---|
| 1225 | 1228 | static long unix_wait_for_peer(struct sock *other, long timeo) |
|---|
| 1229 | + __releases(&unix_sk(other)->lock) |
|---|
| 1226 | 1230 | { |
|---|
| 1227 | 1231 | struct unix_sock *u = unix_sk(other); |
|---|
| 1228 | 1232 | int sched; |
|---|
| .. | .. |
|---|
| 1655 | 1659 | unix_secdata_eq(scm, skb); |
|---|
| 1656 | 1660 | } |
|---|
| 1657 | 1661 | |
|---|
| 1662 | +static void scm_stat_add(struct sock *sk, struct sk_buff *skb) |
|---|
| 1663 | +{ |
|---|
| 1664 | + struct scm_fp_list *fp = UNIXCB(skb).fp; |
|---|
| 1665 | + struct unix_sock *u = unix_sk(sk); |
|---|
| 1666 | + |
|---|
| 1667 | + if (unlikely(fp && fp->count)) |
|---|
| 1668 | + atomic_add(fp->count, &u->scm_stat.nr_fds); |
|---|
| 1669 | +} |
|---|
| 1670 | + |
|---|
| 1671 | +static void scm_stat_del(struct sock *sk, struct sk_buff *skb) |
|---|
| 1672 | +{ |
|---|
| 1673 | + struct scm_fp_list *fp = UNIXCB(skb).fp; |
|---|
| 1674 | + struct unix_sock *u = unix_sk(sk); |
|---|
| 1675 | + |
|---|
| 1676 | + if (unlikely(fp && fp->count)) |
|---|
| 1677 | + atomic_sub(fp->count, &u->scm_stat.nr_fds); |
|---|
| 1678 | +} |
|---|
| 1679 | + |
|---|
| 1658 | 1680 | /* |
|---|
| 1659 | 1681 | * Send AF_UNIX data. |
|---|
| 1660 | 1682 | */ |
|---|
| .. | .. |
|---|
| 1841 | 1863 | if (sock_flag(other, SOCK_RCVTSTAMP)) |
|---|
| 1842 | 1864 | __net_timestamp(skb); |
|---|
| 1843 | 1865 | maybe_add_creds(skb, sock, other); |
|---|
| 1866 | + scm_stat_add(other, skb); |
|---|
| 1844 | 1867 | skb_queue_tail(&other->sk_receive_queue, skb); |
|---|
| 1845 | 1868 | unix_state_unlock(other); |
|---|
| 1846 | 1869 | other->sk_data_ready(other); |
|---|
| .. | .. |
|---|
| 1943 | 1966 | goto pipe_err_free; |
|---|
| 1944 | 1967 | |
|---|
| 1945 | 1968 | maybe_add_creds(skb, sock, other); |
|---|
| 1969 | + scm_stat_add(other, skb); |
|---|
| 1946 | 1970 | skb_queue_tail(&other->sk_receive_queue, skb); |
|---|
| 1947 | 1971 | unix_state_unlock(other); |
|---|
| 1948 | 1972 | other->sk_data_ready(other); |
|---|
| .. | .. |
|---|
| 2129 | 2153 | struct unix_sock *u = unix_sk(sk); |
|---|
| 2130 | 2154 | struct sk_buff *skb, *last; |
|---|
| 2131 | 2155 | long timeo; |
|---|
| 2156 | + int skip; |
|---|
| 2132 | 2157 | int err; |
|---|
| 2133 | | - int peeked, skip; |
|---|
| 2134 | 2158 | |
|---|
| 2135 | 2159 | err = -EOPNOTSUPP; |
|---|
| 2136 | 2160 | if (flags&MSG_OOB) |
|---|
| .. | .. |
|---|
| 2142 | 2166 | mutex_lock(&u->iolock); |
|---|
| 2143 | 2167 | |
|---|
| 2144 | 2168 | skip = sk_peek_offset(sk, flags); |
|---|
| 2145 | | - skb = __skb_try_recv_datagram(sk, flags, NULL, &peeked, &skip, |
|---|
| 2146 | | - &err, &last); |
|---|
| 2147 | | - if (skb) |
|---|
| 2169 | + skb = __skb_try_recv_datagram(sk, &sk->sk_receive_queue, flags, |
|---|
| 2170 | + &skip, &err, &last); |
|---|
| 2171 | + if (skb) { |
|---|
| 2172 | + if (!(flags & MSG_PEEK)) |
|---|
| 2173 | + scm_stat_del(sk, skb); |
|---|
| 2148 | 2174 | break; |
|---|
| 2175 | + } |
|---|
| 2149 | 2176 | |
|---|
| 2150 | 2177 | mutex_unlock(&u->iolock); |
|---|
| 2151 | 2178 | |
|---|
| 2152 | 2179 | if (err != -EAGAIN) |
|---|
| 2153 | 2180 | break; |
|---|
| 2154 | 2181 | } while (timeo && |
|---|
| 2155 | | - !__skb_wait_for_more_packets(sk, &err, &timeo, last)); |
|---|
| 2182 | + !__skb_wait_for_more_packets(sk, &sk->sk_receive_queue, |
|---|
| 2183 | + &err, &timeo, last)); |
|---|
| 2156 | 2184 | |
|---|
| 2157 | 2185 | if (!skb) { /* implies iolock unlocked */ |
|---|
| 2158 | 2186 | unix_state_lock(sk); |
|---|
| .. | .. |
|---|
| 2437 | 2465 | |
|---|
| 2438 | 2466 | sk_peek_offset_bwd(sk, chunk); |
|---|
| 2439 | 2467 | |
|---|
| 2440 | | - if (UNIXCB(skb).fp) |
|---|
| 2468 | + if (UNIXCB(skb).fp) { |
|---|
| 2469 | + scm_stat_del(sk, skb); |
|---|
| 2441 | 2470 | unix_detach_fds(&scm, skb); |
|---|
| 2471 | + } |
|---|
| 2442 | 2472 | |
|---|
| 2443 | 2473 | if (unix_skb_len(skb)) |
|---|
| 2444 | 2474 | break; |
|---|
| .. | .. |
|---|
| 2949 | 2979 | { |
|---|
| 2950 | 2980 | int rc = -1; |
|---|
| 2951 | 2981 | |
|---|
| 2952 | | - BUILD_BUG_ON(sizeof(struct unix_skb_parms) > FIELD_SIZEOF(struct sk_buff, cb)); |
|---|
| 2982 | + BUILD_BUG_ON(sizeof(struct unix_skb_parms) > sizeof_field(struct sk_buff, cb)); |
|---|
| 2953 | 2983 | |
|---|
| 2954 | 2984 | rc = proto_register(&unix_proto, 1); |
|---|
| 2955 | 2985 | if (rc != 0) { |
|---|
| .. | .. |
|---|
| 2978 | 3008 | module_exit(af_unix_exit); |
|---|
| 2979 | 3009 | |
|---|
| 2980 | 3010 | MODULE_LICENSE("GPL"); |
|---|
| 3011 | +MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); |
|---|
| 2981 | 3012 | MODULE_ALIAS_NETPROTO(PF_UNIX); |
|---|