18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * NET4: Implementation of BSD Unix domain sockets. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Authors: Alan Cox, <alan@lxorguk.ukuu.org.uk> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Fixes: 88c2ecf20Sopenharmony_ci * Linus Torvalds : Assorted bug cures. 98c2ecf20Sopenharmony_ci * Niibe Yutaka : async I/O support. 108c2ecf20Sopenharmony_ci * Carsten Paeth : PF_UNIX check, address fixes. 118c2ecf20Sopenharmony_ci * Alan Cox : Limit size of allocated blocks. 128c2ecf20Sopenharmony_ci * Alan Cox : Fixed the stupid socketpair bug. 138c2ecf20Sopenharmony_ci * Alan Cox : BSD compatibility fine tuning. 148c2ecf20Sopenharmony_ci * Alan Cox : Fixed a bug in connect when interrupted. 158c2ecf20Sopenharmony_ci * Alan Cox : Sorted out a proper draft version of 168c2ecf20Sopenharmony_ci * file descriptor passing hacked up from 178c2ecf20Sopenharmony_ci * Mike Shaver's work. 188c2ecf20Sopenharmony_ci * Marty Leisner : Fixes to fd passing 198c2ecf20Sopenharmony_ci * Nick Nevin : recvmsg bugfix. 208c2ecf20Sopenharmony_ci * Alan Cox : Started proper garbage collector 218c2ecf20Sopenharmony_ci * Heiko EiBfeldt : Missing verify_area check 228c2ecf20Sopenharmony_ci * Alan Cox : Started POSIXisms 238c2ecf20Sopenharmony_ci * Andreas Schwab : Replace inode by dentry for proper 248c2ecf20Sopenharmony_ci * reference counting 258c2ecf20Sopenharmony_ci * Kirk Petersen : Made this a module 268c2ecf20Sopenharmony_ci * Christoph Rohland : Elegant non-blocking accept/connect algorithm. 278c2ecf20Sopenharmony_ci * Lots of bug fixes. 288c2ecf20Sopenharmony_ci * Alexey Kuznetosv : Repaired (I hope) bugs introduces 298c2ecf20Sopenharmony_ci * by above two patches. 308c2ecf20Sopenharmony_ci * Andrea Arcangeli : If possible we block in connect(2) 318c2ecf20Sopenharmony_ci * if the max backlog of the listen socket 328c2ecf20Sopenharmony_ci * is been reached. This won't break 338c2ecf20Sopenharmony_ci * old apps and it will avoid huge amount 348c2ecf20Sopenharmony_ci * of socks hashed (this for unix_gc() 358c2ecf20Sopenharmony_ci * performances reasons). 368c2ecf20Sopenharmony_ci * Security fix that limits the max 378c2ecf20Sopenharmony_ci * number of socks to 2*max_files and 388c2ecf20Sopenharmony_ci * the number of skb queueable in the 398c2ecf20Sopenharmony_ci * dgram receiver. 408c2ecf20Sopenharmony_ci * Artur Skawina : Hash function optimizations 418c2ecf20Sopenharmony_ci * Alexey Kuznetsov : Full scale SMP. Lot of bugs are introduced 8) 428c2ecf20Sopenharmony_ci * Malcolm Beattie : Set peercred for socketpair 438c2ecf20Sopenharmony_ci * Michal Ostrowski : Module initialization cleanup. 448c2ecf20Sopenharmony_ci * Arnaldo C. Melo : Remove MOD_{INC,DEC}_USE_COUNT, 458c2ecf20Sopenharmony_ci * the core infrastructure is doing that 468c2ecf20Sopenharmony_ci * for all net proto families now (2.5.69+) 478c2ecf20Sopenharmony_ci * 488c2ecf20Sopenharmony_ci * Known differences from reference BSD that was tested: 498c2ecf20Sopenharmony_ci * 508c2ecf20Sopenharmony_ci * [TO FIX] 518c2ecf20Sopenharmony_ci * ECONNREFUSED is not returned from one end of a connected() socket to the 528c2ecf20Sopenharmony_ci * other the moment one end closes. 538c2ecf20Sopenharmony_ci * fstat() doesn't return st_dev=0, and give the blksize as high water mark 548c2ecf20Sopenharmony_ci * and a fake inode identifier (nor the BSD first socket fstat twice bug). 558c2ecf20Sopenharmony_ci * [NOT TO FIX] 568c2ecf20Sopenharmony_ci * accept() returns a path name even if the connecting socket has closed 578c2ecf20Sopenharmony_ci * in the meantime (BSD loses the path and gives up). 588c2ecf20Sopenharmony_ci * accept() returns 0 length path for an unbound connector. BSD returns 16 598c2ecf20Sopenharmony_ci * and a null first byte in the path (but not for gethost/peername - BSD bug ??) 608c2ecf20Sopenharmony_ci * socketpair(...SOCK_RAW..) doesn't panic the kernel. 618c2ecf20Sopenharmony_ci * BSD af_unix apparently has connect forgetting to block properly. 628c2ecf20Sopenharmony_ci * (need to check this with the POSIX spec in detail) 638c2ecf20Sopenharmony_ci * 648c2ecf20Sopenharmony_ci * Differences from 2.0.0-11-... (ANK) 658c2ecf20Sopenharmony_ci * Bug fixes and improvements. 668c2ecf20Sopenharmony_ci * - client shutdown killed server socket. 678c2ecf20Sopenharmony_ci * - removed all useless cli/sti pairs. 688c2ecf20Sopenharmony_ci * 698c2ecf20Sopenharmony_ci * Semantic changes/extensions. 708c2ecf20Sopenharmony_ci * - generic control message passing. 718c2ecf20Sopenharmony_ci * - SCM_CREDENTIALS control message. 728c2ecf20Sopenharmony_ci * - "Abstract" (not FS based) socket bindings. 738c2ecf20Sopenharmony_ci * Abstract names are sequences of bytes (not zero terminated) 748c2ecf20Sopenharmony_ci * started by 0, so that this name space does not intersect 758c2ecf20Sopenharmony_ci * with BSD names. 768c2ecf20Sopenharmony_ci */ 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci#include <linux/module.h> 818c2ecf20Sopenharmony_ci#include <linux/kernel.h> 828c2ecf20Sopenharmony_ci#include <linux/signal.h> 838c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 848c2ecf20Sopenharmony_ci#include <linux/errno.h> 858c2ecf20Sopenharmony_ci#include <linux/string.h> 868c2ecf20Sopenharmony_ci#include <linux/stat.h> 878c2ecf20Sopenharmony_ci#include <linux/dcache.h> 888c2ecf20Sopenharmony_ci#include <linux/namei.h> 898c2ecf20Sopenharmony_ci#include <linux/socket.h> 908c2ecf20Sopenharmony_ci#include <linux/un.h> 918c2ecf20Sopenharmony_ci#include <linux/fcntl.h> 928c2ecf20Sopenharmony_ci#include <linux/termios.h> 938c2ecf20Sopenharmony_ci#include <linux/sockios.h> 948c2ecf20Sopenharmony_ci#include <linux/net.h> 958c2ecf20Sopenharmony_ci#include <linux/in.h> 968c2ecf20Sopenharmony_ci#include <linux/fs.h> 978c2ecf20Sopenharmony_ci#include <linux/slab.h> 988c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 998c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 1008c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 1018c2ecf20Sopenharmony_ci#include <net/net_namespace.h> 1028c2ecf20Sopenharmony_ci#include <net/sock.h> 1038c2ecf20Sopenharmony_ci#include <net/tcp_states.h> 1048c2ecf20Sopenharmony_ci#include <net/af_unix.h> 1058c2ecf20Sopenharmony_ci#include <linux/proc_fs.h> 1068c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 1078c2ecf20Sopenharmony_ci#include <net/scm.h> 1088c2ecf20Sopenharmony_ci#include <linux/init.h> 1098c2ecf20Sopenharmony_ci#include <linux/poll.h> 1108c2ecf20Sopenharmony_ci#include <linux/rtnetlink.h> 1118c2ecf20Sopenharmony_ci#include <linux/mount.h> 1128c2ecf20Sopenharmony_ci#include <net/checksum.h> 1138c2ecf20Sopenharmony_ci#include <linux/security.h> 1148c2ecf20Sopenharmony_ci#include <linux/freezer.h> 1158c2ecf20Sopenharmony_ci#include <linux/file.h> 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci#include "scm.h" 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_cistruct hlist_head unix_socket_table[2 * UNIX_HASH_SIZE]; 1208c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(unix_socket_table); 1218c2ecf20Sopenharmony_ciDEFINE_SPINLOCK(unix_table_lock); 1228c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(unix_table_lock); 1238c2ecf20Sopenharmony_cistatic atomic_long_t unix_nr_socks; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic struct hlist_head *unix_sockets_unbound(void *addr) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci unsigned long hash = (unsigned long)addr; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci hash ^= hash >> 16; 1318c2ecf20Sopenharmony_ci hash ^= hash >> 8; 1328c2ecf20Sopenharmony_ci hash %= UNIX_HASH_SIZE; 1338c2ecf20Sopenharmony_ci return &unix_socket_table[UNIX_HASH_SIZE + hash]; 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci#define UNIX_ABSTRACT(sk) (unix_sk(sk)->addr->hash < UNIX_HASH_SIZE) 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci#ifdef CONFIG_SECURITY_NETWORK 1398c2ecf20Sopenharmony_cistatic void unix_get_secdata(struct scm_cookie *scm, struct sk_buff *skb) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci UNIXCB(skb).secid = scm->secid; 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistatic inline void unix_set_secdata(struct scm_cookie *scm, struct sk_buff *skb) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci scm->secid = UNIXCB(skb).secid; 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic inline bool unix_secdata_eq(struct scm_cookie *scm, struct sk_buff *skb) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci return (scm->secid == UNIXCB(skb).secid); 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_ci#else 1548c2ecf20Sopenharmony_cistatic inline void unix_get_secdata(struct scm_cookie *scm, struct sk_buff *skb) 1558c2ecf20Sopenharmony_ci{ } 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistatic inline void unix_set_secdata(struct scm_cookie *scm, struct sk_buff *skb) 1588c2ecf20Sopenharmony_ci{ } 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic inline bool unix_secdata_eq(struct scm_cookie *scm, struct sk_buff *skb) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci return true; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci#endif /* CONFIG_SECURITY_NETWORK */ 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci/* 1678c2ecf20Sopenharmony_ci * SMP locking strategy: 1688c2ecf20Sopenharmony_ci * hash table is protected with spinlock unix_table_lock 1698c2ecf20Sopenharmony_ci * each socket state is protected by separate spin lock. 1708c2ecf20Sopenharmony_ci */ 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_cistatic inline unsigned int unix_hash_fold(__wsum n) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci unsigned int hash = (__force unsigned int)csum_fold(n); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci hash ^= hash>>8; 1778c2ecf20Sopenharmony_ci return hash&(UNIX_HASH_SIZE-1); 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci#define unix_peer(sk) (unix_sk(sk)->peer) 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_cistatic inline int unix_our_peer(struct sock *sk, struct sock *osk) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci return unix_peer(osk) == sk; 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_cistatic inline int unix_may_send(struct sock *sk, struct sock *osk) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci return unix_peer(osk) == NULL || unix_our_peer(sk, osk); 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_cistatic inline int unix_recvq_full(const struct sock *sk) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci return skb_queue_len(&sk->sk_receive_queue) > sk->sk_max_ack_backlog; 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_cistatic inline int unix_recvq_full_lockless(const struct sock *sk) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci return skb_queue_len_lockless(&sk->sk_receive_queue) > 2008c2ecf20Sopenharmony_ci READ_ONCE(sk->sk_max_ack_backlog); 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_cistruct sock *unix_peer_get(struct sock *s) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci struct sock *peer; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci unix_state_lock(s); 2088c2ecf20Sopenharmony_ci peer = unix_peer(s); 2098c2ecf20Sopenharmony_ci if (peer) 2108c2ecf20Sopenharmony_ci sock_hold(peer); 2118c2ecf20Sopenharmony_ci unix_state_unlock(s); 2128c2ecf20Sopenharmony_ci return peer; 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(unix_peer_get); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic inline void unix_release_addr(struct unix_address *addr) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci if (refcount_dec_and_test(&addr->refcnt)) 2198c2ecf20Sopenharmony_ci kfree(addr); 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci/* 2238c2ecf20Sopenharmony_ci * Check unix socket name: 2248c2ecf20Sopenharmony_ci * - should be not zero length. 2258c2ecf20Sopenharmony_ci * - if started by not zero, should be NULL terminated (FS object) 2268c2ecf20Sopenharmony_ci * - if started by zero, it is abstract name. 2278c2ecf20Sopenharmony_ci */ 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_cistatic int unix_mkname(struct sockaddr_un *sunaddr, int len, unsigned int *hashp) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci *hashp = 0; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci if (len <= sizeof(short) || len > sizeof(*sunaddr)) 2348c2ecf20Sopenharmony_ci return -EINVAL; 2358c2ecf20Sopenharmony_ci if (!sunaddr || sunaddr->sun_family != AF_UNIX) 2368c2ecf20Sopenharmony_ci return -EINVAL; 2378c2ecf20Sopenharmony_ci if (sunaddr->sun_path[0]) { 2388c2ecf20Sopenharmony_ci /* 2398c2ecf20Sopenharmony_ci * This may look like an off by one error but it is a bit more 2408c2ecf20Sopenharmony_ci * subtle. 108 is the longest valid AF_UNIX path for a binding. 2418c2ecf20Sopenharmony_ci * sun_path[108] doesn't as such exist. However in kernel space 2428c2ecf20Sopenharmony_ci * we are guaranteed that it is a valid memory location in our 2438c2ecf20Sopenharmony_ci * kernel address buffer. 2448c2ecf20Sopenharmony_ci */ 2458c2ecf20Sopenharmony_ci ((char *)sunaddr)[len] = 0; 2468c2ecf20Sopenharmony_ci len = strlen(sunaddr->sun_path)+1+sizeof(short); 2478c2ecf20Sopenharmony_ci return len; 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci *hashp = unix_hash_fold(csum_partial(sunaddr, len, 0)); 2518c2ecf20Sopenharmony_ci return len; 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cistatic void __unix_remove_socket(struct sock *sk) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci sk_del_node_init(sk); 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cistatic void __unix_insert_socket(struct hlist_head *list, struct sock *sk) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci WARN_ON(!sk_unhashed(sk)); 2628c2ecf20Sopenharmony_ci sk_add_node(sk, list); 2638c2ecf20Sopenharmony_ci} 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_cistatic inline void unix_remove_socket(struct sock *sk) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci spin_lock(&unix_table_lock); 2688c2ecf20Sopenharmony_ci __unix_remove_socket(sk); 2698c2ecf20Sopenharmony_ci spin_unlock(&unix_table_lock); 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_cistatic inline void unix_insert_socket(struct hlist_head *list, struct sock *sk) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci spin_lock(&unix_table_lock); 2758c2ecf20Sopenharmony_ci __unix_insert_socket(list, sk); 2768c2ecf20Sopenharmony_ci spin_unlock(&unix_table_lock); 2778c2ecf20Sopenharmony_ci} 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_cistatic struct sock *__unix_find_socket_byname(struct net *net, 2808c2ecf20Sopenharmony_ci struct sockaddr_un *sunname, 2818c2ecf20Sopenharmony_ci int len, int type, unsigned int hash) 2828c2ecf20Sopenharmony_ci{ 2838c2ecf20Sopenharmony_ci struct sock *s; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci sk_for_each(s, &unix_socket_table[hash ^ type]) { 2868c2ecf20Sopenharmony_ci struct unix_sock *u = unix_sk(s); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci if (!net_eq(sock_net(s), net)) 2898c2ecf20Sopenharmony_ci continue; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci if (u->addr->len == len && 2928c2ecf20Sopenharmony_ci !memcmp(u->addr->name, sunname, len)) 2938c2ecf20Sopenharmony_ci return s; 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci return NULL; 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_cistatic inline struct sock *unix_find_socket_byname(struct net *net, 2998c2ecf20Sopenharmony_ci struct sockaddr_un *sunname, 3008c2ecf20Sopenharmony_ci int len, int type, 3018c2ecf20Sopenharmony_ci unsigned int hash) 3028c2ecf20Sopenharmony_ci{ 3038c2ecf20Sopenharmony_ci struct sock *s; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci spin_lock(&unix_table_lock); 3068c2ecf20Sopenharmony_ci s = __unix_find_socket_byname(net, sunname, len, type, hash); 3078c2ecf20Sopenharmony_ci if (s) 3088c2ecf20Sopenharmony_ci sock_hold(s); 3098c2ecf20Sopenharmony_ci spin_unlock(&unix_table_lock); 3108c2ecf20Sopenharmony_ci return s; 3118c2ecf20Sopenharmony_ci} 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_cistatic struct sock *unix_find_socket_byinode(struct inode *i) 3148c2ecf20Sopenharmony_ci{ 3158c2ecf20Sopenharmony_ci struct sock *s; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci spin_lock(&unix_table_lock); 3188c2ecf20Sopenharmony_ci sk_for_each(s, 3198c2ecf20Sopenharmony_ci &unix_socket_table[i->i_ino & (UNIX_HASH_SIZE - 1)]) { 3208c2ecf20Sopenharmony_ci struct dentry *dentry = unix_sk(s)->path.dentry; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci if (dentry && d_backing_inode(dentry) == i) { 3238c2ecf20Sopenharmony_ci sock_hold(s); 3248c2ecf20Sopenharmony_ci goto found; 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci } 3278c2ecf20Sopenharmony_ci s = NULL; 3288c2ecf20Sopenharmony_cifound: 3298c2ecf20Sopenharmony_ci spin_unlock(&unix_table_lock); 3308c2ecf20Sopenharmony_ci return s; 3318c2ecf20Sopenharmony_ci} 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci/* Support code for asymmetrically connected dgram sockets 3348c2ecf20Sopenharmony_ci * 3358c2ecf20Sopenharmony_ci * If a datagram socket is connected to a socket not itself connected 3368c2ecf20Sopenharmony_ci * to the first socket (eg, /dev/log), clients may only enqueue more 3378c2ecf20Sopenharmony_ci * messages if the present receive queue of the server socket is not 3388c2ecf20Sopenharmony_ci * "too large". This means there's a second writeability condition 3398c2ecf20Sopenharmony_ci * poll and sendmsg need to test. The dgram recv code will do a wake 3408c2ecf20Sopenharmony_ci * up on the peer_wait wait queue of a socket upon reception of a 3418c2ecf20Sopenharmony_ci * datagram which needs to be propagated to sleeping would-be writers 3428c2ecf20Sopenharmony_ci * since these might not have sent anything so far. This can't be 3438c2ecf20Sopenharmony_ci * accomplished via poll_wait because the lifetime of the server 3448c2ecf20Sopenharmony_ci * socket might be less than that of its clients if these break their 3458c2ecf20Sopenharmony_ci * association with it or if the server socket is closed while clients 3468c2ecf20Sopenharmony_ci * are still connected to it and there's no way to inform "a polling 3478c2ecf20Sopenharmony_ci * implementation" that it should let go of a certain wait queue 3488c2ecf20Sopenharmony_ci * 3498c2ecf20Sopenharmony_ci * In order to propagate a wake up, a wait_queue_entry_t of the client 3508c2ecf20Sopenharmony_ci * socket is enqueued on the peer_wait queue of the server socket 3518c2ecf20Sopenharmony_ci * whose wake function does a wake_up on the ordinary client socket 3528c2ecf20Sopenharmony_ci * wait queue. This connection is established whenever a write (or 3538c2ecf20Sopenharmony_ci * poll for write) hit the flow control condition and broken when the 3548c2ecf20Sopenharmony_ci * association to the server socket is dissolved or after a wake up 3558c2ecf20Sopenharmony_ci * was relayed. 3568c2ecf20Sopenharmony_ci */ 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_cistatic int unix_dgram_peer_wake_relay(wait_queue_entry_t *q, unsigned mode, int flags, 3598c2ecf20Sopenharmony_ci void *key) 3608c2ecf20Sopenharmony_ci{ 3618c2ecf20Sopenharmony_ci struct unix_sock *u; 3628c2ecf20Sopenharmony_ci wait_queue_head_t *u_sleep; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci u = container_of(q, struct unix_sock, peer_wake); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci __remove_wait_queue(&unix_sk(u->peer_wake.private)->peer_wait, 3678c2ecf20Sopenharmony_ci q); 3688c2ecf20Sopenharmony_ci u->peer_wake.private = NULL; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci /* relaying can only happen while the wq still exists */ 3718c2ecf20Sopenharmony_ci u_sleep = sk_sleep(&u->sk); 3728c2ecf20Sopenharmony_ci if (u_sleep) 3738c2ecf20Sopenharmony_ci wake_up_interruptible_poll(u_sleep, key_to_poll(key)); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci return 0; 3768c2ecf20Sopenharmony_ci} 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_cistatic int unix_dgram_peer_wake_connect(struct sock *sk, struct sock *other) 3798c2ecf20Sopenharmony_ci{ 3808c2ecf20Sopenharmony_ci struct unix_sock *u, *u_other; 3818c2ecf20Sopenharmony_ci int rc; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci u = unix_sk(sk); 3848c2ecf20Sopenharmony_ci u_other = unix_sk(other); 3858c2ecf20Sopenharmony_ci rc = 0; 3868c2ecf20Sopenharmony_ci spin_lock(&u_other->peer_wait.lock); 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci if (!u->peer_wake.private) { 3898c2ecf20Sopenharmony_ci u->peer_wake.private = other; 3908c2ecf20Sopenharmony_ci __add_wait_queue(&u_other->peer_wait, &u->peer_wake); 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci rc = 1; 3938c2ecf20Sopenharmony_ci } 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci spin_unlock(&u_other->peer_wait.lock); 3968c2ecf20Sopenharmony_ci return rc; 3978c2ecf20Sopenharmony_ci} 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_cistatic void unix_dgram_peer_wake_disconnect(struct sock *sk, 4008c2ecf20Sopenharmony_ci struct sock *other) 4018c2ecf20Sopenharmony_ci{ 4028c2ecf20Sopenharmony_ci struct unix_sock *u, *u_other; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci u = unix_sk(sk); 4058c2ecf20Sopenharmony_ci u_other = unix_sk(other); 4068c2ecf20Sopenharmony_ci spin_lock(&u_other->peer_wait.lock); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci if (u->peer_wake.private == other) { 4098c2ecf20Sopenharmony_ci __remove_wait_queue(&u_other->peer_wait, &u->peer_wake); 4108c2ecf20Sopenharmony_ci u->peer_wake.private = NULL; 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci spin_unlock(&u_other->peer_wait.lock); 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_cistatic void unix_dgram_peer_wake_disconnect_wakeup(struct sock *sk, 4178c2ecf20Sopenharmony_ci struct sock *other) 4188c2ecf20Sopenharmony_ci{ 4198c2ecf20Sopenharmony_ci unix_dgram_peer_wake_disconnect(sk, other); 4208c2ecf20Sopenharmony_ci wake_up_interruptible_poll(sk_sleep(sk), 4218c2ecf20Sopenharmony_ci EPOLLOUT | 4228c2ecf20Sopenharmony_ci EPOLLWRNORM | 4238c2ecf20Sopenharmony_ci EPOLLWRBAND); 4248c2ecf20Sopenharmony_ci} 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci/* preconditions: 4278c2ecf20Sopenharmony_ci * - unix_peer(sk) == other 4288c2ecf20Sopenharmony_ci * - association is stable 4298c2ecf20Sopenharmony_ci */ 4308c2ecf20Sopenharmony_cistatic int unix_dgram_peer_wake_me(struct sock *sk, struct sock *other) 4318c2ecf20Sopenharmony_ci{ 4328c2ecf20Sopenharmony_ci int connected; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci connected = unix_dgram_peer_wake_connect(sk, other); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci /* If other is SOCK_DEAD, we want to make sure we signal 4378c2ecf20Sopenharmony_ci * POLLOUT, such that a subsequent write() can get a 4388c2ecf20Sopenharmony_ci * -ECONNREFUSED. Otherwise, if we haven't queued any skbs 4398c2ecf20Sopenharmony_ci * to other and its full, we will hang waiting for POLLOUT. 4408c2ecf20Sopenharmony_ci */ 4418c2ecf20Sopenharmony_ci if (unix_recvq_full_lockless(other) && !sock_flag(other, SOCK_DEAD)) 4428c2ecf20Sopenharmony_ci return 1; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci if (connected) 4458c2ecf20Sopenharmony_ci unix_dgram_peer_wake_disconnect(sk, other); 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci return 0; 4488c2ecf20Sopenharmony_ci} 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_cistatic int unix_writable(const struct sock *sk) 4518c2ecf20Sopenharmony_ci{ 4528c2ecf20Sopenharmony_ci return sk->sk_state != TCP_LISTEN && 4538c2ecf20Sopenharmony_ci (refcount_read(&sk->sk_wmem_alloc) << 2) <= sk->sk_sndbuf; 4548c2ecf20Sopenharmony_ci} 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_cistatic void unix_write_space(struct sock *sk) 4578c2ecf20Sopenharmony_ci{ 4588c2ecf20Sopenharmony_ci struct socket_wq *wq; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci rcu_read_lock(); 4618c2ecf20Sopenharmony_ci if (unix_writable(sk)) { 4628c2ecf20Sopenharmony_ci wq = rcu_dereference(sk->sk_wq); 4638c2ecf20Sopenharmony_ci if (skwq_has_sleeper(wq)) 4648c2ecf20Sopenharmony_ci wake_up_interruptible_sync_poll(&wq->wait, 4658c2ecf20Sopenharmony_ci EPOLLOUT | EPOLLWRNORM | EPOLLWRBAND); 4668c2ecf20Sopenharmony_ci sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT); 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci rcu_read_unlock(); 4698c2ecf20Sopenharmony_ci} 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci/* When dgram socket disconnects (or changes its peer), we clear its receive 4728c2ecf20Sopenharmony_ci * queue of packets arrived from previous peer. First, it allows to do 4738c2ecf20Sopenharmony_ci * flow control based only on wmem_alloc; second, sk connected to peer 4748c2ecf20Sopenharmony_ci * may receive messages only from that peer. */ 4758c2ecf20Sopenharmony_cistatic void unix_dgram_disconnected(struct sock *sk, struct sock *other) 4768c2ecf20Sopenharmony_ci{ 4778c2ecf20Sopenharmony_ci if (!skb_queue_empty(&sk->sk_receive_queue)) { 4788c2ecf20Sopenharmony_ci skb_queue_purge(&sk->sk_receive_queue); 4798c2ecf20Sopenharmony_ci wake_up_interruptible_all(&unix_sk(sk)->peer_wait); 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci /* If one link of bidirectional dgram pipe is disconnected, 4828c2ecf20Sopenharmony_ci * we signal error. Messages are lost. Do not make this, 4838c2ecf20Sopenharmony_ci * when peer was not connected to us. 4848c2ecf20Sopenharmony_ci */ 4858c2ecf20Sopenharmony_ci if (!sock_flag(other, SOCK_DEAD) && unix_peer(other) == sk) { 4868c2ecf20Sopenharmony_ci other->sk_err = ECONNRESET; 4878c2ecf20Sopenharmony_ci other->sk_error_report(other); 4888c2ecf20Sopenharmony_ci } 4898c2ecf20Sopenharmony_ci } 4908c2ecf20Sopenharmony_ci} 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_cistatic void unix_sock_destructor(struct sock *sk) 4938c2ecf20Sopenharmony_ci{ 4948c2ecf20Sopenharmony_ci struct unix_sock *u = unix_sk(sk); 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci skb_queue_purge(&sk->sk_receive_queue); 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci WARN_ON(refcount_read(&sk->sk_wmem_alloc)); 4998c2ecf20Sopenharmony_ci WARN_ON(!sk_unhashed(sk)); 5008c2ecf20Sopenharmony_ci WARN_ON(sk->sk_socket); 5018c2ecf20Sopenharmony_ci if (!sock_flag(sk, SOCK_DEAD)) { 5028c2ecf20Sopenharmony_ci pr_info("Attempt to release alive unix socket: %p\n", sk); 5038c2ecf20Sopenharmony_ci return; 5048c2ecf20Sopenharmony_ci } 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci if (u->addr) 5078c2ecf20Sopenharmony_ci unix_release_addr(u->addr); 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci atomic_long_dec(&unix_nr_socks); 5108c2ecf20Sopenharmony_ci local_bh_disable(); 5118c2ecf20Sopenharmony_ci sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); 5128c2ecf20Sopenharmony_ci local_bh_enable(); 5138c2ecf20Sopenharmony_ci#ifdef UNIX_REFCNT_DEBUG 5148c2ecf20Sopenharmony_ci pr_debug("UNIX %p is destroyed, %ld are still alive.\n", sk, 5158c2ecf20Sopenharmony_ci atomic_long_read(&unix_nr_socks)); 5168c2ecf20Sopenharmony_ci#endif 5178c2ecf20Sopenharmony_ci} 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_cistatic void unix_release_sock(struct sock *sk, int embrion) 5208c2ecf20Sopenharmony_ci{ 5218c2ecf20Sopenharmony_ci struct unix_sock *u = unix_sk(sk); 5228c2ecf20Sopenharmony_ci struct path path; 5238c2ecf20Sopenharmony_ci struct sock *skpair; 5248c2ecf20Sopenharmony_ci struct sk_buff *skb; 5258c2ecf20Sopenharmony_ci int state; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci unix_remove_socket(sk); 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci /* Clear state */ 5308c2ecf20Sopenharmony_ci unix_state_lock(sk); 5318c2ecf20Sopenharmony_ci sock_orphan(sk); 5328c2ecf20Sopenharmony_ci WRITE_ONCE(sk->sk_shutdown, SHUTDOWN_MASK); 5338c2ecf20Sopenharmony_ci path = u->path; 5348c2ecf20Sopenharmony_ci u->path.dentry = NULL; 5358c2ecf20Sopenharmony_ci u->path.mnt = NULL; 5368c2ecf20Sopenharmony_ci state = sk->sk_state; 5378c2ecf20Sopenharmony_ci sk->sk_state = TCP_CLOSE; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci skpair = unix_peer(sk); 5408c2ecf20Sopenharmony_ci unix_peer(sk) = NULL; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci unix_state_unlock(sk); 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci wake_up_interruptible_all(&u->peer_wait); 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci if (skpair != NULL) { 5478c2ecf20Sopenharmony_ci if (sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_SEQPACKET) { 5488c2ecf20Sopenharmony_ci unix_state_lock(skpair); 5498c2ecf20Sopenharmony_ci /* No more writes */ 5508c2ecf20Sopenharmony_ci WRITE_ONCE(skpair->sk_shutdown, SHUTDOWN_MASK); 5518c2ecf20Sopenharmony_ci if (!skb_queue_empty(&sk->sk_receive_queue) || embrion) 5528c2ecf20Sopenharmony_ci skpair->sk_err = ECONNRESET; 5538c2ecf20Sopenharmony_ci unix_state_unlock(skpair); 5548c2ecf20Sopenharmony_ci skpair->sk_state_change(skpair); 5558c2ecf20Sopenharmony_ci sk_wake_async(skpair, SOCK_WAKE_WAITD, POLL_HUP); 5568c2ecf20Sopenharmony_ci } 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci unix_dgram_peer_wake_disconnect(sk, skpair); 5598c2ecf20Sopenharmony_ci sock_put(skpair); /* It may now die */ 5608c2ecf20Sopenharmony_ci } 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci /* Try to flush out this socket. Throw out buffers at least */ 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { 5658c2ecf20Sopenharmony_ci if (state == TCP_LISTEN) 5668c2ecf20Sopenharmony_ci unix_release_sock(skb->sk, 1); 5678c2ecf20Sopenharmony_ci /* passed fds are erased in the kfree_skb hook */ 5688c2ecf20Sopenharmony_ci UNIXCB(skb).consumed = skb->len; 5698c2ecf20Sopenharmony_ci kfree_skb(skb); 5708c2ecf20Sopenharmony_ci } 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci if (path.dentry) 5738c2ecf20Sopenharmony_ci path_put(&path); 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci sock_put(sk); 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci /* ---- Socket is dead now and most probably destroyed ---- */ 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci /* 5808c2ecf20Sopenharmony_ci * Fixme: BSD difference: In BSD all sockets connected to us get 5818c2ecf20Sopenharmony_ci * ECONNRESET and we die on the spot. In Linux we behave 5828c2ecf20Sopenharmony_ci * like files and pipes do and wait for the last 5838c2ecf20Sopenharmony_ci * dereference. 5848c2ecf20Sopenharmony_ci * 5858c2ecf20Sopenharmony_ci * Can't we simply set sock->err? 5868c2ecf20Sopenharmony_ci * 5878c2ecf20Sopenharmony_ci * What the above comment does talk about? --ANK(980817) 5888c2ecf20Sopenharmony_ci */ 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci if (READ_ONCE(unix_tot_inflight)) 5918c2ecf20Sopenharmony_ci unix_gc(); /* Garbage collect fds */ 5928c2ecf20Sopenharmony_ci} 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_cistatic void init_peercred(struct sock *sk) 5958c2ecf20Sopenharmony_ci{ 5968c2ecf20Sopenharmony_ci const struct cred *old_cred; 5978c2ecf20Sopenharmony_ci struct pid *old_pid; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci spin_lock(&sk->sk_peer_lock); 6008c2ecf20Sopenharmony_ci old_pid = sk->sk_peer_pid; 6018c2ecf20Sopenharmony_ci old_cred = sk->sk_peer_cred; 6028c2ecf20Sopenharmony_ci sk->sk_peer_pid = get_pid(task_tgid(current)); 6038c2ecf20Sopenharmony_ci sk->sk_peer_cred = get_current_cred(); 6048c2ecf20Sopenharmony_ci spin_unlock(&sk->sk_peer_lock); 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci put_pid(old_pid); 6078c2ecf20Sopenharmony_ci put_cred(old_cred); 6088c2ecf20Sopenharmony_ci} 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_cistatic void copy_peercred(struct sock *sk, struct sock *peersk) 6118c2ecf20Sopenharmony_ci{ 6128c2ecf20Sopenharmony_ci const struct cred *old_cred; 6138c2ecf20Sopenharmony_ci struct pid *old_pid; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci if (sk < peersk) { 6168c2ecf20Sopenharmony_ci spin_lock(&sk->sk_peer_lock); 6178c2ecf20Sopenharmony_ci spin_lock_nested(&peersk->sk_peer_lock, SINGLE_DEPTH_NESTING); 6188c2ecf20Sopenharmony_ci } else { 6198c2ecf20Sopenharmony_ci spin_lock(&peersk->sk_peer_lock); 6208c2ecf20Sopenharmony_ci spin_lock_nested(&sk->sk_peer_lock, SINGLE_DEPTH_NESTING); 6218c2ecf20Sopenharmony_ci } 6228c2ecf20Sopenharmony_ci old_pid = sk->sk_peer_pid; 6238c2ecf20Sopenharmony_ci old_cred = sk->sk_peer_cred; 6248c2ecf20Sopenharmony_ci sk->sk_peer_pid = get_pid(peersk->sk_peer_pid); 6258c2ecf20Sopenharmony_ci sk->sk_peer_cred = get_cred(peersk->sk_peer_cred); 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci spin_unlock(&sk->sk_peer_lock); 6288c2ecf20Sopenharmony_ci spin_unlock(&peersk->sk_peer_lock); 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci put_pid(old_pid); 6318c2ecf20Sopenharmony_ci put_cred(old_cred); 6328c2ecf20Sopenharmony_ci} 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_cistatic int unix_listen(struct socket *sock, int backlog) 6358c2ecf20Sopenharmony_ci{ 6368c2ecf20Sopenharmony_ci int err; 6378c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 6388c2ecf20Sopenharmony_ci struct unix_sock *u = unix_sk(sk); 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 6418c2ecf20Sopenharmony_ci if (sock->type != SOCK_STREAM && sock->type != SOCK_SEQPACKET) 6428c2ecf20Sopenharmony_ci goto out; /* Only stream/seqpacket sockets accept */ 6438c2ecf20Sopenharmony_ci err = -EINVAL; 6448c2ecf20Sopenharmony_ci if (!u->addr) 6458c2ecf20Sopenharmony_ci goto out; /* No listens on an unbound socket */ 6468c2ecf20Sopenharmony_ci unix_state_lock(sk); 6478c2ecf20Sopenharmony_ci if (sk->sk_state != TCP_CLOSE && sk->sk_state != TCP_LISTEN) 6488c2ecf20Sopenharmony_ci goto out_unlock; 6498c2ecf20Sopenharmony_ci if (backlog > sk->sk_max_ack_backlog) 6508c2ecf20Sopenharmony_ci wake_up_interruptible_all(&u->peer_wait); 6518c2ecf20Sopenharmony_ci sk->sk_max_ack_backlog = backlog; 6528c2ecf20Sopenharmony_ci sk->sk_state = TCP_LISTEN; 6538c2ecf20Sopenharmony_ci /* set credentials so connect can copy them */ 6548c2ecf20Sopenharmony_ci init_peercred(sk); 6558c2ecf20Sopenharmony_ci err = 0; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ciout_unlock: 6588c2ecf20Sopenharmony_ci unix_state_unlock(sk); 6598c2ecf20Sopenharmony_ciout: 6608c2ecf20Sopenharmony_ci return err; 6618c2ecf20Sopenharmony_ci} 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_cistatic int unix_release(struct socket *); 6648c2ecf20Sopenharmony_cistatic int unix_bind(struct socket *, struct sockaddr *, int); 6658c2ecf20Sopenharmony_cistatic int unix_stream_connect(struct socket *, struct sockaddr *, 6668c2ecf20Sopenharmony_ci int addr_len, int flags); 6678c2ecf20Sopenharmony_cistatic int unix_socketpair(struct socket *, struct socket *); 6688c2ecf20Sopenharmony_cistatic int unix_accept(struct socket *, struct socket *, int, bool); 6698c2ecf20Sopenharmony_cistatic int unix_getname(struct socket *, struct sockaddr *, int); 6708c2ecf20Sopenharmony_cistatic __poll_t unix_poll(struct file *, struct socket *, poll_table *); 6718c2ecf20Sopenharmony_cistatic __poll_t unix_dgram_poll(struct file *, struct socket *, 6728c2ecf20Sopenharmony_ci poll_table *); 6738c2ecf20Sopenharmony_cistatic int unix_ioctl(struct socket *, unsigned int, unsigned long); 6748c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 6758c2ecf20Sopenharmony_cistatic int unix_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg); 6768c2ecf20Sopenharmony_ci#endif 6778c2ecf20Sopenharmony_cistatic int unix_shutdown(struct socket *, int); 6788c2ecf20Sopenharmony_cistatic int unix_stream_sendmsg(struct socket *, struct msghdr *, size_t); 6798c2ecf20Sopenharmony_cistatic int unix_stream_recvmsg(struct socket *, struct msghdr *, size_t, int); 6808c2ecf20Sopenharmony_cistatic ssize_t unix_stream_sendpage(struct socket *, struct page *, int offset, 6818c2ecf20Sopenharmony_ci size_t size, int flags); 6828c2ecf20Sopenharmony_cistatic ssize_t unix_stream_splice_read(struct socket *, loff_t *ppos, 6838c2ecf20Sopenharmony_ci struct pipe_inode_info *, size_t size, 6848c2ecf20Sopenharmony_ci unsigned int flags); 6858c2ecf20Sopenharmony_cistatic int unix_dgram_sendmsg(struct socket *, struct msghdr *, size_t); 6868c2ecf20Sopenharmony_cistatic int unix_dgram_recvmsg(struct socket *, struct msghdr *, size_t, int); 6878c2ecf20Sopenharmony_cistatic int unix_dgram_connect(struct socket *, struct sockaddr *, 6888c2ecf20Sopenharmony_ci int, int); 6898c2ecf20Sopenharmony_cistatic int unix_seqpacket_sendmsg(struct socket *, struct msghdr *, size_t); 6908c2ecf20Sopenharmony_cistatic int unix_seqpacket_recvmsg(struct socket *, struct msghdr *, size_t, 6918c2ecf20Sopenharmony_ci int); 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_cistatic int unix_set_peek_off(struct sock *sk, int val) 6948c2ecf20Sopenharmony_ci{ 6958c2ecf20Sopenharmony_ci struct unix_sock *u = unix_sk(sk); 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&u->iolock)) 6988c2ecf20Sopenharmony_ci return -EINTR; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci WRITE_ONCE(sk->sk_peek_off, val); 7018c2ecf20Sopenharmony_ci mutex_unlock(&u->iolock); 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci return 0; 7048c2ecf20Sopenharmony_ci} 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_FS 7078c2ecf20Sopenharmony_cistatic void unix_show_fdinfo(struct seq_file *m, struct socket *sock) 7088c2ecf20Sopenharmony_ci{ 7098c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 7108c2ecf20Sopenharmony_ci struct unix_sock *u; 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci if (sk) { 7138c2ecf20Sopenharmony_ci u = unix_sk(sock->sk); 7148c2ecf20Sopenharmony_ci seq_printf(m, "scm_fds: %u\n", 7158c2ecf20Sopenharmony_ci atomic_read(&u->scm_stat.nr_fds)); 7168c2ecf20Sopenharmony_ci } 7178c2ecf20Sopenharmony_ci} 7188c2ecf20Sopenharmony_ci#else 7198c2ecf20Sopenharmony_ci#define unix_show_fdinfo NULL 7208c2ecf20Sopenharmony_ci#endif 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_cistatic const struct proto_ops unix_stream_ops = { 7238c2ecf20Sopenharmony_ci .family = PF_UNIX, 7248c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 7258c2ecf20Sopenharmony_ci .release = unix_release, 7268c2ecf20Sopenharmony_ci .bind = unix_bind, 7278c2ecf20Sopenharmony_ci .connect = unix_stream_connect, 7288c2ecf20Sopenharmony_ci .socketpair = unix_socketpair, 7298c2ecf20Sopenharmony_ci .accept = unix_accept, 7308c2ecf20Sopenharmony_ci .getname = unix_getname, 7318c2ecf20Sopenharmony_ci .poll = unix_poll, 7328c2ecf20Sopenharmony_ci .ioctl = unix_ioctl, 7338c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 7348c2ecf20Sopenharmony_ci .compat_ioctl = unix_compat_ioctl, 7358c2ecf20Sopenharmony_ci#endif 7368c2ecf20Sopenharmony_ci .listen = unix_listen, 7378c2ecf20Sopenharmony_ci .shutdown = unix_shutdown, 7388c2ecf20Sopenharmony_ci .sendmsg = unix_stream_sendmsg, 7398c2ecf20Sopenharmony_ci .recvmsg = unix_stream_recvmsg, 7408c2ecf20Sopenharmony_ci .mmap = sock_no_mmap, 7418c2ecf20Sopenharmony_ci .sendpage = unix_stream_sendpage, 7428c2ecf20Sopenharmony_ci .splice_read = unix_stream_splice_read, 7438c2ecf20Sopenharmony_ci .set_peek_off = unix_set_peek_off, 7448c2ecf20Sopenharmony_ci .show_fdinfo = unix_show_fdinfo, 7458c2ecf20Sopenharmony_ci}; 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_cistatic const struct proto_ops unix_dgram_ops = { 7488c2ecf20Sopenharmony_ci .family = PF_UNIX, 7498c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 7508c2ecf20Sopenharmony_ci .release = unix_release, 7518c2ecf20Sopenharmony_ci .bind = unix_bind, 7528c2ecf20Sopenharmony_ci .connect = unix_dgram_connect, 7538c2ecf20Sopenharmony_ci .socketpair = unix_socketpair, 7548c2ecf20Sopenharmony_ci .accept = sock_no_accept, 7558c2ecf20Sopenharmony_ci .getname = unix_getname, 7568c2ecf20Sopenharmony_ci .poll = unix_dgram_poll, 7578c2ecf20Sopenharmony_ci .ioctl = unix_ioctl, 7588c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 7598c2ecf20Sopenharmony_ci .compat_ioctl = unix_compat_ioctl, 7608c2ecf20Sopenharmony_ci#endif 7618c2ecf20Sopenharmony_ci .listen = sock_no_listen, 7628c2ecf20Sopenharmony_ci .shutdown = unix_shutdown, 7638c2ecf20Sopenharmony_ci .sendmsg = unix_dgram_sendmsg, 7648c2ecf20Sopenharmony_ci .recvmsg = unix_dgram_recvmsg, 7658c2ecf20Sopenharmony_ci .mmap = sock_no_mmap, 7668c2ecf20Sopenharmony_ci .sendpage = sock_no_sendpage, 7678c2ecf20Sopenharmony_ci .set_peek_off = unix_set_peek_off, 7688c2ecf20Sopenharmony_ci .show_fdinfo = unix_show_fdinfo, 7698c2ecf20Sopenharmony_ci}; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_cistatic const struct proto_ops unix_seqpacket_ops = { 7728c2ecf20Sopenharmony_ci .family = PF_UNIX, 7738c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 7748c2ecf20Sopenharmony_ci .release = unix_release, 7758c2ecf20Sopenharmony_ci .bind = unix_bind, 7768c2ecf20Sopenharmony_ci .connect = unix_stream_connect, 7778c2ecf20Sopenharmony_ci .socketpair = unix_socketpair, 7788c2ecf20Sopenharmony_ci .accept = unix_accept, 7798c2ecf20Sopenharmony_ci .getname = unix_getname, 7808c2ecf20Sopenharmony_ci .poll = unix_dgram_poll, 7818c2ecf20Sopenharmony_ci .ioctl = unix_ioctl, 7828c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 7838c2ecf20Sopenharmony_ci .compat_ioctl = unix_compat_ioctl, 7848c2ecf20Sopenharmony_ci#endif 7858c2ecf20Sopenharmony_ci .listen = unix_listen, 7868c2ecf20Sopenharmony_ci .shutdown = unix_shutdown, 7878c2ecf20Sopenharmony_ci .sendmsg = unix_seqpacket_sendmsg, 7888c2ecf20Sopenharmony_ci .recvmsg = unix_seqpacket_recvmsg, 7898c2ecf20Sopenharmony_ci .mmap = sock_no_mmap, 7908c2ecf20Sopenharmony_ci .sendpage = sock_no_sendpage, 7918c2ecf20Sopenharmony_ci .set_peek_off = unix_set_peek_off, 7928c2ecf20Sopenharmony_ci .show_fdinfo = unix_show_fdinfo, 7938c2ecf20Sopenharmony_ci}; 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_cistatic struct proto unix_proto = { 7968c2ecf20Sopenharmony_ci .name = "UNIX", 7978c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 7988c2ecf20Sopenharmony_ci .obj_size = sizeof(struct unix_sock), 7998c2ecf20Sopenharmony_ci}; 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_cistatic struct sock *unix_create1(struct net *net, struct socket *sock, int kern) 8028c2ecf20Sopenharmony_ci{ 8038c2ecf20Sopenharmony_ci struct sock *sk = NULL; 8048c2ecf20Sopenharmony_ci struct unix_sock *u; 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci atomic_long_inc(&unix_nr_socks); 8078c2ecf20Sopenharmony_ci if (atomic_long_read(&unix_nr_socks) > 2 * get_max_files()) 8088c2ecf20Sopenharmony_ci goto out; 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci sk = sk_alloc(net, PF_UNIX, GFP_KERNEL, &unix_proto, kern); 8118c2ecf20Sopenharmony_ci if (!sk) 8128c2ecf20Sopenharmony_ci goto out; 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci sock_init_data(sock, sk); 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci sk->sk_allocation = GFP_KERNEL_ACCOUNT; 8178c2ecf20Sopenharmony_ci sk->sk_write_space = unix_write_space; 8188c2ecf20Sopenharmony_ci sk->sk_max_ack_backlog = net->unx.sysctl_max_dgram_qlen; 8198c2ecf20Sopenharmony_ci sk->sk_destruct = unix_sock_destructor; 8208c2ecf20Sopenharmony_ci u = unix_sk(sk); 8218c2ecf20Sopenharmony_ci u->path.dentry = NULL; 8228c2ecf20Sopenharmony_ci u->path.mnt = NULL; 8238c2ecf20Sopenharmony_ci spin_lock_init(&u->lock); 8248c2ecf20Sopenharmony_ci atomic_long_set(&u->inflight, 0); 8258c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&u->link); 8268c2ecf20Sopenharmony_ci mutex_init(&u->iolock); /* single task reading lock */ 8278c2ecf20Sopenharmony_ci mutex_init(&u->bindlock); /* single task binding lock */ 8288c2ecf20Sopenharmony_ci init_waitqueue_head(&u->peer_wait); 8298c2ecf20Sopenharmony_ci init_waitqueue_func_entry(&u->peer_wake, unix_dgram_peer_wake_relay); 8308c2ecf20Sopenharmony_ci memset(&u->scm_stat, 0, sizeof(struct scm_stat)); 8318c2ecf20Sopenharmony_ci unix_insert_socket(unix_sockets_unbound(sk), sk); 8328c2ecf20Sopenharmony_ciout: 8338c2ecf20Sopenharmony_ci if (sk == NULL) 8348c2ecf20Sopenharmony_ci atomic_long_dec(&unix_nr_socks); 8358c2ecf20Sopenharmony_ci else { 8368c2ecf20Sopenharmony_ci local_bh_disable(); 8378c2ecf20Sopenharmony_ci sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); 8388c2ecf20Sopenharmony_ci local_bh_enable(); 8398c2ecf20Sopenharmony_ci } 8408c2ecf20Sopenharmony_ci return sk; 8418c2ecf20Sopenharmony_ci} 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_cistatic int unix_create(struct net *net, struct socket *sock, int protocol, 8448c2ecf20Sopenharmony_ci int kern) 8458c2ecf20Sopenharmony_ci{ 8468c2ecf20Sopenharmony_ci if (protocol && protocol != PF_UNIX) 8478c2ecf20Sopenharmony_ci return -EPROTONOSUPPORT; 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci sock->state = SS_UNCONNECTED; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci switch (sock->type) { 8528c2ecf20Sopenharmony_ci case SOCK_STREAM: 8538c2ecf20Sopenharmony_ci sock->ops = &unix_stream_ops; 8548c2ecf20Sopenharmony_ci break; 8558c2ecf20Sopenharmony_ci /* 8568c2ecf20Sopenharmony_ci * Believe it or not BSD has AF_UNIX, SOCK_RAW though 8578c2ecf20Sopenharmony_ci * nothing uses it. 8588c2ecf20Sopenharmony_ci */ 8598c2ecf20Sopenharmony_ci case SOCK_RAW: 8608c2ecf20Sopenharmony_ci sock->type = SOCK_DGRAM; 8618c2ecf20Sopenharmony_ci fallthrough; 8628c2ecf20Sopenharmony_ci case SOCK_DGRAM: 8638c2ecf20Sopenharmony_ci sock->ops = &unix_dgram_ops; 8648c2ecf20Sopenharmony_ci break; 8658c2ecf20Sopenharmony_ci case SOCK_SEQPACKET: 8668c2ecf20Sopenharmony_ci sock->ops = &unix_seqpacket_ops; 8678c2ecf20Sopenharmony_ci break; 8688c2ecf20Sopenharmony_ci default: 8698c2ecf20Sopenharmony_ci return -ESOCKTNOSUPPORT; 8708c2ecf20Sopenharmony_ci } 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci return unix_create1(net, sock, kern) ? 0 : -ENOMEM; 8738c2ecf20Sopenharmony_ci} 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_cistatic int unix_release(struct socket *sock) 8768c2ecf20Sopenharmony_ci{ 8778c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci if (!sk) 8808c2ecf20Sopenharmony_ci return 0; 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci unix_release_sock(sk, 0); 8838c2ecf20Sopenharmony_ci sock->sk = NULL; 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci return 0; 8868c2ecf20Sopenharmony_ci} 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_cistatic int unix_autobind(struct socket *sock) 8898c2ecf20Sopenharmony_ci{ 8908c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 8918c2ecf20Sopenharmony_ci struct net *net = sock_net(sk); 8928c2ecf20Sopenharmony_ci struct unix_sock *u = unix_sk(sk); 8938c2ecf20Sopenharmony_ci static u32 ordernum = 1; 8948c2ecf20Sopenharmony_ci struct unix_address *addr; 8958c2ecf20Sopenharmony_ci int err; 8968c2ecf20Sopenharmony_ci unsigned int retries = 0; 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci err = mutex_lock_interruptible(&u->bindlock); 8998c2ecf20Sopenharmony_ci if (err) 9008c2ecf20Sopenharmony_ci return err; 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci if (u->addr) 9038c2ecf20Sopenharmony_ci goto out; 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci err = -ENOMEM; 9068c2ecf20Sopenharmony_ci addr = kzalloc(sizeof(*addr) + sizeof(short) + 16, GFP_KERNEL); 9078c2ecf20Sopenharmony_ci if (!addr) 9088c2ecf20Sopenharmony_ci goto out; 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci addr->name->sun_family = AF_UNIX; 9118c2ecf20Sopenharmony_ci refcount_set(&addr->refcnt, 1); 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ciretry: 9148c2ecf20Sopenharmony_ci addr->len = sprintf(addr->name->sun_path+1, "%05x", ordernum) + 1 + sizeof(short); 9158c2ecf20Sopenharmony_ci addr->hash = unix_hash_fold(csum_partial(addr->name, addr->len, 0)); 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci spin_lock(&unix_table_lock); 9188c2ecf20Sopenharmony_ci ordernum = (ordernum+1)&0xFFFFF; 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci if (__unix_find_socket_byname(net, addr->name, addr->len, sock->type, 9218c2ecf20Sopenharmony_ci addr->hash)) { 9228c2ecf20Sopenharmony_ci spin_unlock(&unix_table_lock); 9238c2ecf20Sopenharmony_ci /* 9248c2ecf20Sopenharmony_ci * __unix_find_socket_byname() may take long time if many names 9258c2ecf20Sopenharmony_ci * are already in use. 9268c2ecf20Sopenharmony_ci */ 9278c2ecf20Sopenharmony_ci cond_resched(); 9288c2ecf20Sopenharmony_ci /* Give up if all names seems to be in use. */ 9298c2ecf20Sopenharmony_ci if (retries++ == 0xFFFFF) { 9308c2ecf20Sopenharmony_ci err = -ENOSPC; 9318c2ecf20Sopenharmony_ci kfree(addr); 9328c2ecf20Sopenharmony_ci goto out; 9338c2ecf20Sopenharmony_ci } 9348c2ecf20Sopenharmony_ci goto retry; 9358c2ecf20Sopenharmony_ci } 9368c2ecf20Sopenharmony_ci addr->hash ^= sk->sk_type; 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci __unix_remove_socket(sk); 9398c2ecf20Sopenharmony_ci smp_store_release(&u->addr, addr); 9408c2ecf20Sopenharmony_ci __unix_insert_socket(&unix_socket_table[addr->hash], sk); 9418c2ecf20Sopenharmony_ci spin_unlock(&unix_table_lock); 9428c2ecf20Sopenharmony_ci err = 0; 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ciout: mutex_unlock(&u->bindlock); 9458c2ecf20Sopenharmony_ci return err; 9468c2ecf20Sopenharmony_ci} 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_cistatic struct sock *unix_find_other(struct net *net, 9498c2ecf20Sopenharmony_ci struct sockaddr_un *sunname, int len, 9508c2ecf20Sopenharmony_ci int type, unsigned int hash, int *error) 9518c2ecf20Sopenharmony_ci{ 9528c2ecf20Sopenharmony_ci struct sock *u; 9538c2ecf20Sopenharmony_ci struct path path; 9548c2ecf20Sopenharmony_ci int err = 0; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci if (sunname->sun_path[0]) { 9578c2ecf20Sopenharmony_ci struct inode *inode; 9588c2ecf20Sopenharmony_ci err = kern_path(sunname->sun_path, LOOKUP_FOLLOW, &path); 9598c2ecf20Sopenharmony_ci if (err) 9608c2ecf20Sopenharmony_ci goto fail; 9618c2ecf20Sopenharmony_ci inode = d_backing_inode(path.dentry); 9628c2ecf20Sopenharmony_ci err = inode_permission(inode, MAY_WRITE); 9638c2ecf20Sopenharmony_ci if (err) 9648c2ecf20Sopenharmony_ci goto put_fail; 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci err = -ECONNREFUSED; 9678c2ecf20Sopenharmony_ci if (!S_ISSOCK(inode->i_mode)) 9688c2ecf20Sopenharmony_ci goto put_fail; 9698c2ecf20Sopenharmony_ci u = unix_find_socket_byinode(inode); 9708c2ecf20Sopenharmony_ci if (!u) 9718c2ecf20Sopenharmony_ci goto put_fail; 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci if (u->sk_type == type) 9748c2ecf20Sopenharmony_ci touch_atime(&path); 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci path_put(&path); 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci err = -EPROTOTYPE; 9798c2ecf20Sopenharmony_ci if (u->sk_type != type) { 9808c2ecf20Sopenharmony_ci sock_put(u); 9818c2ecf20Sopenharmony_ci goto fail; 9828c2ecf20Sopenharmony_ci } 9838c2ecf20Sopenharmony_ci } else { 9848c2ecf20Sopenharmony_ci err = -ECONNREFUSED; 9858c2ecf20Sopenharmony_ci u = unix_find_socket_byname(net, sunname, len, type, hash); 9868c2ecf20Sopenharmony_ci if (u) { 9878c2ecf20Sopenharmony_ci struct dentry *dentry; 9888c2ecf20Sopenharmony_ci dentry = unix_sk(u)->path.dentry; 9898c2ecf20Sopenharmony_ci if (dentry) 9908c2ecf20Sopenharmony_ci touch_atime(&unix_sk(u)->path); 9918c2ecf20Sopenharmony_ci } else 9928c2ecf20Sopenharmony_ci goto fail; 9938c2ecf20Sopenharmony_ci } 9948c2ecf20Sopenharmony_ci return u; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ciput_fail: 9978c2ecf20Sopenharmony_ci path_put(&path); 9988c2ecf20Sopenharmony_cifail: 9998c2ecf20Sopenharmony_ci *error = err; 10008c2ecf20Sopenharmony_ci return NULL; 10018c2ecf20Sopenharmony_ci} 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_cistatic int unix_mknod(const char *sun_path, umode_t mode, struct path *res) 10048c2ecf20Sopenharmony_ci{ 10058c2ecf20Sopenharmony_ci struct dentry *dentry; 10068c2ecf20Sopenharmony_ci struct path path; 10078c2ecf20Sopenharmony_ci int err = 0; 10088c2ecf20Sopenharmony_ci /* 10098c2ecf20Sopenharmony_ci * Get the parent directory, calculate the hash for last 10108c2ecf20Sopenharmony_ci * component. 10118c2ecf20Sopenharmony_ci */ 10128c2ecf20Sopenharmony_ci dentry = kern_path_create(AT_FDCWD, sun_path, &path, 0); 10138c2ecf20Sopenharmony_ci err = PTR_ERR(dentry); 10148c2ecf20Sopenharmony_ci if (IS_ERR(dentry)) 10158c2ecf20Sopenharmony_ci return err; 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci /* 10188c2ecf20Sopenharmony_ci * All right, let's create it. 10198c2ecf20Sopenharmony_ci */ 10208c2ecf20Sopenharmony_ci err = security_path_mknod(&path, dentry, mode, 0); 10218c2ecf20Sopenharmony_ci if (!err) { 10228c2ecf20Sopenharmony_ci err = vfs_mknod(d_inode(path.dentry), dentry, mode, 0); 10238c2ecf20Sopenharmony_ci if (!err) { 10248c2ecf20Sopenharmony_ci res->mnt = mntget(path.mnt); 10258c2ecf20Sopenharmony_ci res->dentry = dget(dentry); 10268c2ecf20Sopenharmony_ci } 10278c2ecf20Sopenharmony_ci } 10288c2ecf20Sopenharmony_ci done_path_create(&path, dentry); 10298c2ecf20Sopenharmony_ci return err; 10308c2ecf20Sopenharmony_ci} 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_cistatic int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) 10338c2ecf20Sopenharmony_ci{ 10348c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 10358c2ecf20Sopenharmony_ci struct net *net = sock_net(sk); 10368c2ecf20Sopenharmony_ci struct unix_sock *u = unix_sk(sk); 10378c2ecf20Sopenharmony_ci struct sockaddr_un *sunaddr = (struct sockaddr_un *)uaddr; 10388c2ecf20Sopenharmony_ci char *sun_path = sunaddr->sun_path; 10398c2ecf20Sopenharmony_ci int err; 10408c2ecf20Sopenharmony_ci unsigned int hash; 10418c2ecf20Sopenharmony_ci struct unix_address *addr; 10428c2ecf20Sopenharmony_ci struct hlist_head *list; 10438c2ecf20Sopenharmony_ci struct path path = { }; 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci err = -EINVAL; 10468c2ecf20Sopenharmony_ci if (addr_len < offsetofend(struct sockaddr_un, sun_family) || 10478c2ecf20Sopenharmony_ci sunaddr->sun_family != AF_UNIX) 10488c2ecf20Sopenharmony_ci goto out; 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci if (addr_len == sizeof(short)) { 10518c2ecf20Sopenharmony_ci err = unix_autobind(sock); 10528c2ecf20Sopenharmony_ci goto out; 10538c2ecf20Sopenharmony_ci } 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci err = unix_mkname(sunaddr, addr_len, &hash); 10568c2ecf20Sopenharmony_ci if (err < 0) 10578c2ecf20Sopenharmony_ci goto out; 10588c2ecf20Sopenharmony_ci addr_len = err; 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci if (sun_path[0]) { 10618c2ecf20Sopenharmony_ci umode_t mode = S_IFSOCK | 10628c2ecf20Sopenharmony_ci (SOCK_INODE(sock)->i_mode & ~current_umask()); 10638c2ecf20Sopenharmony_ci err = unix_mknod(sun_path, mode, &path); 10648c2ecf20Sopenharmony_ci if (err) { 10658c2ecf20Sopenharmony_ci if (err == -EEXIST) 10668c2ecf20Sopenharmony_ci err = -EADDRINUSE; 10678c2ecf20Sopenharmony_ci goto out; 10688c2ecf20Sopenharmony_ci } 10698c2ecf20Sopenharmony_ci } 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci err = mutex_lock_interruptible(&u->bindlock); 10728c2ecf20Sopenharmony_ci if (err) 10738c2ecf20Sopenharmony_ci goto out_put; 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci err = -EINVAL; 10768c2ecf20Sopenharmony_ci if (u->addr) 10778c2ecf20Sopenharmony_ci goto out_up; 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci err = -ENOMEM; 10808c2ecf20Sopenharmony_ci addr = kmalloc(sizeof(*addr)+addr_len, GFP_KERNEL); 10818c2ecf20Sopenharmony_ci if (!addr) 10828c2ecf20Sopenharmony_ci goto out_up; 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci memcpy(addr->name, sunaddr, addr_len); 10858c2ecf20Sopenharmony_ci addr->len = addr_len; 10868c2ecf20Sopenharmony_ci addr->hash = hash ^ sk->sk_type; 10878c2ecf20Sopenharmony_ci refcount_set(&addr->refcnt, 1); 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci if (sun_path[0]) { 10908c2ecf20Sopenharmony_ci addr->hash = UNIX_HASH_SIZE; 10918c2ecf20Sopenharmony_ci hash = d_backing_inode(path.dentry)->i_ino & (UNIX_HASH_SIZE - 1); 10928c2ecf20Sopenharmony_ci spin_lock(&unix_table_lock); 10938c2ecf20Sopenharmony_ci u->path = path; 10948c2ecf20Sopenharmony_ci list = &unix_socket_table[hash]; 10958c2ecf20Sopenharmony_ci } else { 10968c2ecf20Sopenharmony_ci spin_lock(&unix_table_lock); 10978c2ecf20Sopenharmony_ci err = -EADDRINUSE; 10988c2ecf20Sopenharmony_ci if (__unix_find_socket_byname(net, sunaddr, addr_len, 10998c2ecf20Sopenharmony_ci sk->sk_type, hash)) { 11008c2ecf20Sopenharmony_ci unix_release_addr(addr); 11018c2ecf20Sopenharmony_ci goto out_unlock; 11028c2ecf20Sopenharmony_ci } 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci list = &unix_socket_table[addr->hash]; 11058c2ecf20Sopenharmony_ci } 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci err = 0; 11088c2ecf20Sopenharmony_ci __unix_remove_socket(sk); 11098c2ecf20Sopenharmony_ci smp_store_release(&u->addr, addr); 11108c2ecf20Sopenharmony_ci __unix_insert_socket(list, sk); 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ciout_unlock: 11138c2ecf20Sopenharmony_ci spin_unlock(&unix_table_lock); 11148c2ecf20Sopenharmony_ciout_up: 11158c2ecf20Sopenharmony_ci mutex_unlock(&u->bindlock); 11168c2ecf20Sopenharmony_ciout_put: 11178c2ecf20Sopenharmony_ci if (err) 11188c2ecf20Sopenharmony_ci path_put(&path); 11198c2ecf20Sopenharmony_ciout: 11208c2ecf20Sopenharmony_ci return err; 11218c2ecf20Sopenharmony_ci} 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_cistatic void unix_state_double_lock(struct sock *sk1, struct sock *sk2) 11248c2ecf20Sopenharmony_ci{ 11258c2ecf20Sopenharmony_ci if (unlikely(sk1 == sk2) || !sk2) { 11268c2ecf20Sopenharmony_ci unix_state_lock(sk1); 11278c2ecf20Sopenharmony_ci return; 11288c2ecf20Sopenharmony_ci } 11298c2ecf20Sopenharmony_ci if (sk1 > sk2) 11308c2ecf20Sopenharmony_ci swap(sk1, sk2); 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci unix_state_lock(sk1); 11338c2ecf20Sopenharmony_ci unix_state_lock_nested(sk2, U_LOCK_SECOND); 11348c2ecf20Sopenharmony_ci} 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_cistatic void unix_state_double_unlock(struct sock *sk1, struct sock *sk2) 11378c2ecf20Sopenharmony_ci{ 11388c2ecf20Sopenharmony_ci if (unlikely(sk1 == sk2) || !sk2) { 11398c2ecf20Sopenharmony_ci unix_state_unlock(sk1); 11408c2ecf20Sopenharmony_ci return; 11418c2ecf20Sopenharmony_ci } 11428c2ecf20Sopenharmony_ci unix_state_unlock(sk1); 11438c2ecf20Sopenharmony_ci unix_state_unlock(sk2); 11448c2ecf20Sopenharmony_ci} 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_cistatic int unix_dgram_connect(struct socket *sock, struct sockaddr *addr, 11478c2ecf20Sopenharmony_ci int alen, int flags) 11488c2ecf20Sopenharmony_ci{ 11498c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 11508c2ecf20Sopenharmony_ci struct net *net = sock_net(sk); 11518c2ecf20Sopenharmony_ci struct sockaddr_un *sunaddr = (struct sockaddr_un *)addr; 11528c2ecf20Sopenharmony_ci struct sock *other; 11538c2ecf20Sopenharmony_ci unsigned int hash; 11548c2ecf20Sopenharmony_ci int err; 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci err = -EINVAL; 11578c2ecf20Sopenharmony_ci if (alen < offsetofend(struct sockaddr, sa_family)) 11588c2ecf20Sopenharmony_ci goto out; 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci if (addr->sa_family != AF_UNSPEC) { 11618c2ecf20Sopenharmony_ci err = unix_mkname(sunaddr, alen, &hash); 11628c2ecf20Sopenharmony_ci if (err < 0) 11638c2ecf20Sopenharmony_ci goto out; 11648c2ecf20Sopenharmony_ci alen = err; 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci if (test_bit(SOCK_PASSCRED, &sock->flags) && 11678c2ecf20Sopenharmony_ci !unix_sk(sk)->addr && (err = unix_autobind(sock)) != 0) 11688c2ecf20Sopenharmony_ci goto out; 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_cirestart: 11718c2ecf20Sopenharmony_ci other = unix_find_other(net, sunaddr, alen, sock->type, hash, &err); 11728c2ecf20Sopenharmony_ci if (!other) 11738c2ecf20Sopenharmony_ci goto out; 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci unix_state_double_lock(sk, other); 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci /* Apparently VFS overslept socket death. Retry. */ 11788c2ecf20Sopenharmony_ci if (sock_flag(other, SOCK_DEAD)) { 11798c2ecf20Sopenharmony_ci unix_state_double_unlock(sk, other); 11808c2ecf20Sopenharmony_ci sock_put(other); 11818c2ecf20Sopenharmony_ci goto restart; 11828c2ecf20Sopenharmony_ci } 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci err = -EPERM; 11858c2ecf20Sopenharmony_ci if (!unix_may_send(sk, other)) 11868c2ecf20Sopenharmony_ci goto out_unlock; 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci err = security_unix_may_send(sk->sk_socket, other->sk_socket); 11898c2ecf20Sopenharmony_ci if (err) 11908c2ecf20Sopenharmony_ci goto out_unlock; 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci } else { 11938c2ecf20Sopenharmony_ci /* 11948c2ecf20Sopenharmony_ci * 1003.1g breaking connected state with AF_UNSPEC 11958c2ecf20Sopenharmony_ci */ 11968c2ecf20Sopenharmony_ci other = NULL; 11978c2ecf20Sopenharmony_ci unix_state_double_lock(sk, other); 11988c2ecf20Sopenharmony_ci } 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci /* 12018c2ecf20Sopenharmony_ci * If it was connected, reconnect. 12028c2ecf20Sopenharmony_ci */ 12038c2ecf20Sopenharmony_ci if (unix_peer(sk)) { 12048c2ecf20Sopenharmony_ci struct sock *old_peer = unix_peer(sk); 12058c2ecf20Sopenharmony_ci unix_peer(sk) = other; 12068c2ecf20Sopenharmony_ci unix_dgram_peer_wake_disconnect_wakeup(sk, old_peer); 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci unix_state_double_unlock(sk, other); 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci if (other != old_peer) 12118c2ecf20Sopenharmony_ci unix_dgram_disconnected(sk, old_peer); 12128c2ecf20Sopenharmony_ci sock_put(old_peer); 12138c2ecf20Sopenharmony_ci } else { 12148c2ecf20Sopenharmony_ci unix_peer(sk) = other; 12158c2ecf20Sopenharmony_ci unix_state_double_unlock(sk, other); 12168c2ecf20Sopenharmony_ci } 12178c2ecf20Sopenharmony_ci return 0; 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ciout_unlock: 12208c2ecf20Sopenharmony_ci unix_state_double_unlock(sk, other); 12218c2ecf20Sopenharmony_ci sock_put(other); 12228c2ecf20Sopenharmony_ciout: 12238c2ecf20Sopenharmony_ci return err; 12248c2ecf20Sopenharmony_ci} 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_cistatic long unix_wait_for_peer(struct sock *other, long timeo) 12278c2ecf20Sopenharmony_ci __releases(&unix_sk(other)->lock) 12288c2ecf20Sopenharmony_ci{ 12298c2ecf20Sopenharmony_ci struct unix_sock *u = unix_sk(other); 12308c2ecf20Sopenharmony_ci int sched; 12318c2ecf20Sopenharmony_ci DEFINE_WAIT(wait); 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci prepare_to_wait_exclusive(&u->peer_wait, &wait, TASK_INTERRUPTIBLE); 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci sched = !sock_flag(other, SOCK_DEAD) && 12368c2ecf20Sopenharmony_ci !(other->sk_shutdown & RCV_SHUTDOWN) && 12378c2ecf20Sopenharmony_ci unix_recvq_full_lockless(other); 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci unix_state_unlock(other); 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci if (sched) 12428c2ecf20Sopenharmony_ci timeo = schedule_timeout(timeo); 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci finish_wait(&u->peer_wait, &wait); 12458c2ecf20Sopenharmony_ci return timeo; 12468c2ecf20Sopenharmony_ci} 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_cistatic int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr, 12498c2ecf20Sopenharmony_ci int addr_len, int flags) 12508c2ecf20Sopenharmony_ci{ 12518c2ecf20Sopenharmony_ci struct sockaddr_un *sunaddr = (struct sockaddr_un *)uaddr; 12528c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 12538c2ecf20Sopenharmony_ci struct net *net = sock_net(sk); 12548c2ecf20Sopenharmony_ci struct unix_sock *u = unix_sk(sk), *newu, *otheru; 12558c2ecf20Sopenharmony_ci struct sock *newsk = NULL; 12568c2ecf20Sopenharmony_ci struct sock *other = NULL; 12578c2ecf20Sopenharmony_ci struct sk_buff *skb = NULL; 12588c2ecf20Sopenharmony_ci unsigned int hash; 12598c2ecf20Sopenharmony_ci int st; 12608c2ecf20Sopenharmony_ci int err; 12618c2ecf20Sopenharmony_ci long timeo; 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci err = unix_mkname(sunaddr, addr_len, &hash); 12648c2ecf20Sopenharmony_ci if (err < 0) 12658c2ecf20Sopenharmony_ci goto out; 12668c2ecf20Sopenharmony_ci addr_len = err; 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci if (test_bit(SOCK_PASSCRED, &sock->flags) && !u->addr && 12698c2ecf20Sopenharmony_ci (err = unix_autobind(sock)) != 0) 12708c2ecf20Sopenharmony_ci goto out; 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci timeo = sock_sndtimeo(sk, flags & O_NONBLOCK); 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci /* First of all allocate resources. 12758c2ecf20Sopenharmony_ci If we will make it after state is locked, 12768c2ecf20Sopenharmony_ci we will have to recheck all again in any case. 12778c2ecf20Sopenharmony_ci */ 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci err = -ENOMEM; 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci /* create new sock for complete connection */ 12828c2ecf20Sopenharmony_ci newsk = unix_create1(sock_net(sk), NULL, 0); 12838c2ecf20Sopenharmony_ci if (newsk == NULL) 12848c2ecf20Sopenharmony_ci goto out; 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci /* Allocate skb for sending to listening sock */ 12878c2ecf20Sopenharmony_ci skb = sock_wmalloc(newsk, 1, 0, GFP_KERNEL); 12888c2ecf20Sopenharmony_ci if (skb == NULL) 12898c2ecf20Sopenharmony_ci goto out; 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_cirestart: 12928c2ecf20Sopenharmony_ci /* Find listening sock. */ 12938c2ecf20Sopenharmony_ci other = unix_find_other(net, sunaddr, addr_len, sk->sk_type, hash, &err); 12948c2ecf20Sopenharmony_ci if (!other) 12958c2ecf20Sopenharmony_ci goto out; 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci /* Latch state of peer */ 12988c2ecf20Sopenharmony_ci unix_state_lock(other); 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci /* Apparently VFS overslept socket death. Retry. */ 13018c2ecf20Sopenharmony_ci if (sock_flag(other, SOCK_DEAD)) { 13028c2ecf20Sopenharmony_ci unix_state_unlock(other); 13038c2ecf20Sopenharmony_ci sock_put(other); 13048c2ecf20Sopenharmony_ci goto restart; 13058c2ecf20Sopenharmony_ci } 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci err = -ECONNREFUSED; 13088c2ecf20Sopenharmony_ci if (other->sk_state != TCP_LISTEN) 13098c2ecf20Sopenharmony_ci goto out_unlock; 13108c2ecf20Sopenharmony_ci if (other->sk_shutdown & RCV_SHUTDOWN) 13118c2ecf20Sopenharmony_ci goto out_unlock; 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci if (unix_recvq_full(other)) { 13148c2ecf20Sopenharmony_ci err = -EAGAIN; 13158c2ecf20Sopenharmony_ci if (!timeo) 13168c2ecf20Sopenharmony_ci goto out_unlock; 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci timeo = unix_wait_for_peer(other, timeo); 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci err = sock_intr_errno(timeo); 13218c2ecf20Sopenharmony_ci if (signal_pending(current)) 13228c2ecf20Sopenharmony_ci goto out; 13238c2ecf20Sopenharmony_ci sock_put(other); 13248c2ecf20Sopenharmony_ci goto restart; 13258c2ecf20Sopenharmony_ci } 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ci /* Latch our state. 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci It is tricky place. We need to grab our state lock and cannot 13308c2ecf20Sopenharmony_ci drop lock on peer. It is dangerous because deadlock is 13318c2ecf20Sopenharmony_ci possible. Connect to self case and simultaneous 13328c2ecf20Sopenharmony_ci attempt to connect are eliminated by checking socket 13338c2ecf20Sopenharmony_ci state. other is TCP_LISTEN, if sk is TCP_LISTEN we 13348c2ecf20Sopenharmony_ci check this before attempt to grab lock. 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci Well, and we have to recheck the state after socket locked. 13378c2ecf20Sopenharmony_ci */ 13388c2ecf20Sopenharmony_ci st = sk->sk_state; 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci switch (st) { 13418c2ecf20Sopenharmony_ci case TCP_CLOSE: 13428c2ecf20Sopenharmony_ci /* This is ok... continue with connect */ 13438c2ecf20Sopenharmony_ci break; 13448c2ecf20Sopenharmony_ci case TCP_ESTABLISHED: 13458c2ecf20Sopenharmony_ci /* Socket is already connected */ 13468c2ecf20Sopenharmony_ci err = -EISCONN; 13478c2ecf20Sopenharmony_ci goto out_unlock; 13488c2ecf20Sopenharmony_ci default: 13498c2ecf20Sopenharmony_ci err = -EINVAL; 13508c2ecf20Sopenharmony_ci goto out_unlock; 13518c2ecf20Sopenharmony_ci } 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_ci unix_state_lock_nested(sk, U_LOCK_SECOND); 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci if (sk->sk_state != st) { 13568c2ecf20Sopenharmony_ci unix_state_unlock(sk); 13578c2ecf20Sopenharmony_ci unix_state_unlock(other); 13588c2ecf20Sopenharmony_ci sock_put(other); 13598c2ecf20Sopenharmony_ci goto restart; 13608c2ecf20Sopenharmony_ci } 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci err = security_unix_stream_connect(sk, other, newsk); 13638c2ecf20Sopenharmony_ci if (err) { 13648c2ecf20Sopenharmony_ci unix_state_unlock(sk); 13658c2ecf20Sopenharmony_ci goto out_unlock; 13668c2ecf20Sopenharmony_ci } 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci /* The way is open! Fastly set all the necessary fields... */ 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_ci sock_hold(sk); 13718c2ecf20Sopenharmony_ci unix_peer(newsk) = sk; 13728c2ecf20Sopenharmony_ci newsk->sk_state = TCP_ESTABLISHED; 13738c2ecf20Sopenharmony_ci newsk->sk_type = sk->sk_type; 13748c2ecf20Sopenharmony_ci init_peercred(newsk); 13758c2ecf20Sopenharmony_ci newu = unix_sk(newsk); 13768c2ecf20Sopenharmony_ci RCU_INIT_POINTER(newsk->sk_wq, &newu->peer_wq); 13778c2ecf20Sopenharmony_ci otheru = unix_sk(other); 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci /* copy address information from listening to new sock 13808c2ecf20Sopenharmony_ci * 13818c2ecf20Sopenharmony_ci * The contents of *(otheru->addr) and otheru->path 13828c2ecf20Sopenharmony_ci * are seen fully set up here, since we have found 13838c2ecf20Sopenharmony_ci * otheru in hash under unix_table_lock. Insertion 13848c2ecf20Sopenharmony_ci * into the hash chain we'd found it in had been done 13858c2ecf20Sopenharmony_ci * in an earlier critical area protected by unix_table_lock, 13868c2ecf20Sopenharmony_ci * the same one where we'd set *(otheru->addr) contents, 13878c2ecf20Sopenharmony_ci * as well as otheru->path and otheru->addr itself. 13888c2ecf20Sopenharmony_ci * 13898c2ecf20Sopenharmony_ci * Using smp_store_release() here to set newu->addr 13908c2ecf20Sopenharmony_ci * is enough to make those stores, as well as stores 13918c2ecf20Sopenharmony_ci * to newu->path visible to anyone who gets newu->addr 13928c2ecf20Sopenharmony_ci * by smp_load_acquire(). IOW, the same warranties 13938c2ecf20Sopenharmony_ci * as for unix_sock instances bound in unix_bind() or 13948c2ecf20Sopenharmony_ci * in unix_autobind(). 13958c2ecf20Sopenharmony_ci */ 13968c2ecf20Sopenharmony_ci if (otheru->path.dentry) { 13978c2ecf20Sopenharmony_ci path_get(&otheru->path); 13988c2ecf20Sopenharmony_ci newu->path = otheru->path; 13998c2ecf20Sopenharmony_ci } 14008c2ecf20Sopenharmony_ci refcount_inc(&otheru->addr->refcnt); 14018c2ecf20Sopenharmony_ci smp_store_release(&newu->addr, otheru->addr); 14028c2ecf20Sopenharmony_ci 14038c2ecf20Sopenharmony_ci /* Set credentials */ 14048c2ecf20Sopenharmony_ci copy_peercred(sk, other); 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci sock->state = SS_CONNECTED; 14078c2ecf20Sopenharmony_ci sk->sk_state = TCP_ESTABLISHED; 14088c2ecf20Sopenharmony_ci sock_hold(newsk); 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci smp_mb__after_atomic(); /* sock_hold() does an atomic_inc() */ 14118c2ecf20Sopenharmony_ci unix_peer(sk) = newsk; 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci unix_state_unlock(sk); 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci /* take ten and and send info to listening sock */ 14168c2ecf20Sopenharmony_ci spin_lock(&other->sk_receive_queue.lock); 14178c2ecf20Sopenharmony_ci __skb_queue_tail(&other->sk_receive_queue, skb); 14188c2ecf20Sopenharmony_ci spin_unlock(&other->sk_receive_queue.lock); 14198c2ecf20Sopenharmony_ci unix_state_unlock(other); 14208c2ecf20Sopenharmony_ci other->sk_data_ready(other); 14218c2ecf20Sopenharmony_ci sock_put(other); 14228c2ecf20Sopenharmony_ci return 0; 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ciout_unlock: 14258c2ecf20Sopenharmony_ci if (other) 14268c2ecf20Sopenharmony_ci unix_state_unlock(other); 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ciout: 14298c2ecf20Sopenharmony_ci kfree_skb(skb); 14308c2ecf20Sopenharmony_ci if (newsk) 14318c2ecf20Sopenharmony_ci unix_release_sock(newsk, 0); 14328c2ecf20Sopenharmony_ci if (other) 14338c2ecf20Sopenharmony_ci sock_put(other); 14348c2ecf20Sopenharmony_ci return err; 14358c2ecf20Sopenharmony_ci} 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_cistatic int unix_socketpair(struct socket *socka, struct socket *sockb) 14388c2ecf20Sopenharmony_ci{ 14398c2ecf20Sopenharmony_ci struct sock *ska = socka->sk, *skb = sockb->sk; 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_ci /* Join our sockets back to back */ 14428c2ecf20Sopenharmony_ci sock_hold(ska); 14438c2ecf20Sopenharmony_ci sock_hold(skb); 14448c2ecf20Sopenharmony_ci unix_peer(ska) = skb; 14458c2ecf20Sopenharmony_ci unix_peer(skb) = ska; 14468c2ecf20Sopenharmony_ci init_peercred(ska); 14478c2ecf20Sopenharmony_ci init_peercred(skb); 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_ci if (ska->sk_type != SOCK_DGRAM) { 14508c2ecf20Sopenharmony_ci ska->sk_state = TCP_ESTABLISHED; 14518c2ecf20Sopenharmony_ci skb->sk_state = TCP_ESTABLISHED; 14528c2ecf20Sopenharmony_ci socka->state = SS_CONNECTED; 14538c2ecf20Sopenharmony_ci sockb->state = SS_CONNECTED; 14548c2ecf20Sopenharmony_ci } 14558c2ecf20Sopenharmony_ci return 0; 14568c2ecf20Sopenharmony_ci} 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_cistatic void unix_sock_inherit_flags(const struct socket *old, 14598c2ecf20Sopenharmony_ci struct socket *new) 14608c2ecf20Sopenharmony_ci{ 14618c2ecf20Sopenharmony_ci if (test_bit(SOCK_PASSCRED, &old->flags)) 14628c2ecf20Sopenharmony_ci set_bit(SOCK_PASSCRED, &new->flags); 14638c2ecf20Sopenharmony_ci if (test_bit(SOCK_PASSSEC, &old->flags)) 14648c2ecf20Sopenharmony_ci set_bit(SOCK_PASSSEC, &new->flags); 14658c2ecf20Sopenharmony_ci} 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_cistatic int unix_accept(struct socket *sock, struct socket *newsock, int flags, 14688c2ecf20Sopenharmony_ci bool kern) 14698c2ecf20Sopenharmony_ci{ 14708c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 14718c2ecf20Sopenharmony_ci struct sock *tsk; 14728c2ecf20Sopenharmony_ci struct sk_buff *skb; 14738c2ecf20Sopenharmony_ci int err; 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 14768c2ecf20Sopenharmony_ci if (sock->type != SOCK_STREAM && sock->type != SOCK_SEQPACKET) 14778c2ecf20Sopenharmony_ci goto out; 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci err = -EINVAL; 14808c2ecf20Sopenharmony_ci if (sk->sk_state != TCP_LISTEN) 14818c2ecf20Sopenharmony_ci goto out; 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci /* If socket state is TCP_LISTEN it cannot change (for now...), 14848c2ecf20Sopenharmony_ci * so that no locks are necessary. 14858c2ecf20Sopenharmony_ci */ 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci skb = skb_recv_datagram(sk, 0, flags&O_NONBLOCK, &err); 14888c2ecf20Sopenharmony_ci if (!skb) { 14898c2ecf20Sopenharmony_ci /* This means receive shutdown. */ 14908c2ecf20Sopenharmony_ci if (err == 0) 14918c2ecf20Sopenharmony_ci err = -EINVAL; 14928c2ecf20Sopenharmony_ci goto out; 14938c2ecf20Sopenharmony_ci } 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci tsk = skb->sk; 14968c2ecf20Sopenharmony_ci skb_free_datagram(sk, skb); 14978c2ecf20Sopenharmony_ci wake_up_interruptible(&unix_sk(sk)->peer_wait); 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci /* attach accepted sock to socket */ 15008c2ecf20Sopenharmony_ci unix_state_lock(tsk); 15018c2ecf20Sopenharmony_ci newsock->state = SS_CONNECTED; 15028c2ecf20Sopenharmony_ci unix_sock_inherit_flags(sock, newsock); 15038c2ecf20Sopenharmony_ci sock_graft(tsk, newsock); 15048c2ecf20Sopenharmony_ci unix_state_unlock(tsk); 15058c2ecf20Sopenharmony_ci return 0; 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ciout: 15088c2ecf20Sopenharmony_ci return err; 15098c2ecf20Sopenharmony_ci} 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_cistatic int unix_getname(struct socket *sock, struct sockaddr *uaddr, int peer) 15138c2ecf20Sopenharmony_ci{ 15148c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 15158c2ecf20Sopenharmony_ci struct unix_address *addr; 15168c2ecf20Sopenharmony_ci DECLARE_SOCKADDR(struct sockaddr_un *, sunaddr, uaddr); 15178c2ecf20Sopenharmony_ci int err = 0; 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci if (peer) { 15208c2ecf20Sopenharmony_ci sk = unix_peer_get(sk); 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci err = -ENOTCONN; 15238c2ecf20Sopenharmony_ci if (!sk) 15248c2ecf20Sopenharmony_ci goto out; 15258c2ecf20Sopenharmony_ci err = 0; 15268c2ecf20Sopenharmony_ci } else { 15278c2ecf20Sopenharmony_ci sock_hold(sk); 15288c2ecf20Sopenharmony_ci } 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_ci addr = smp_load_acquire(&unix_sk(sk)->addr); 15318c2ecf20Sopenharmony_ci if (!addr) { 15328c2ecf20Sopenharmony_ci sunaddr->sun_family = AF_UNIX; 15338c2ecf20Sopenharmony_ci sunaddr->sun_path[0] = 0; 15348c2ecf20Sopenharmony_ci err = sizeof(short); 15358c2ecf20Sopenharmony_ci } else { 15368c2ecf20Sopenharmony_ci err = addr->len; 15378c2ecf20Sopenharmony_ci memcpy(sunaddr, addr->name, addr->len); 15388c2ecf20Sopenharmony_ci } 15398c2ecf20Sopenharmony_ci sock_put(sk); 15408c2ecf20Sopenharmony_ciout: 15418c2ecf20Sopenharmony_ci return err; 15428c2ecf20Sopenharmony_ci} 15438c2ecf20Sopenharmony_ci 15448c2ecf20Sopenharmony_cistatic void unix_peek_fds(struct scm_cookie *scm, struct sk_buff *skb) 15458c2ecf20Sopenharmony_ci{ 15468c2ecf20Sopenharmony_ci scm->fp = scm_fp_dup(UNIXCB(skb).fp); 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_ci /* 15498c2ecf20Sopenharmony_ci * Garbage collection of unix sockets starts by selecting a set of 15508c2ecf20Sopenharmony_ci * candidate sockets which have reference only from being in flight 15518c2ecf20Sopenharmony_ci * (total_refs == inflight_refs). This condition is checked once during 15528c2ecf20Sopenharmony_ci * the candidate collection phase, and candidates are marked as such, so 15538c2ecf20Sopenharmony_ci * that non-candidates can later be ignored. While inflight_refs is 15548c2ecf20Sopenharmony_ci * protected by unix_gc_lock, total_refs (file count) is not, hence this 15558c2ecf20Sopenharmony_ci * is an instantaneous decision. 15568c2ecf20Sopenharmony_ci * 15578c2ecf20Sopenharmony_ci * Once a candidate, however, the socket must not be reinstalled into a 15588c2ecf20Sopenharmony_ci * file descriptor while the garbage collection is in progress. 15598c2ecf20Sopenharmony_ci * 15608c2ecf20Sopenharmony_ci * If the above conditions are met, then the directed graph of 15618c2ecf20Sopenharmony_ci * candidates (*) does not change while unix_gc_lock is held. 15628c2ecf20Sopenharmony_ci * 15638c2ecf20Sopenharmony_ci * Any operations that changes the file count through file descriptors 15648c2ecf20Sopenharmony_ci * (dup, close, sendmsg) does not change the graph since candidates are 15658c2ecf20Sopenharmony_ci * not installed in fds. 15668c2ecf20Sopenharmony_ci * 15678c2ecf20Sopenharmony_ci * Dequeing a candidate via recvmsg would install it into an fd, but 15688c2ecf20Sopenharmony_ci * that takes unix_gc_lock to decrement the inflight count, so it's 15698c2ecf20Sopenharmony_ci * serialized with garbage collection. 15708c2ecf20Sopenharmony_ci * 15718c2ecf20Sopenharmony_ci * MSG_PEEK is special in that it does not change the inflight count, 15728c2ecf20Sopenharmony_ci * yet does install the socket into an fd. The following lock/unlock 15738c2ecf20Sopenharmony_ci * pair is to ensure serialization with garbage collection. It must be 15748c2ecf20Sopenharmony_ci * done between incrementing the file count and installing the file into 15758c2ecf20Sopenharmony_ci * an fd. 15768c2ecf20Sopenharmony_ci * 15778c2ecf20Sopenharmony_ci * If garbage collection starts after the barrier provided by the 15788c2ecf20Sopenharmony_ci * lock/unlock, then it will see the elevated refcount and not mark this 15798c2ecf20Sopenharmony_ci * as a candidate. If a garbage collection is already in progress 15808c2ecf20Sopenharmony_ci * before the file count was incremented, then the lock/unlock pair will 15818c2ecf20Sopenharmony_ci * ensure that garbage collection is finished before progressing to 15828c2ecf20Sopenharmony_ci * installing the fd. 15838c2ecf20Sopenharmony_ci * 15848c2ecf20Sopenharmony_ci * (*) A -> B where B is on the queue of A or B is on the queue of C 15858c2ecf20Sopenharmony_ci * which is on the queue of listening socket A. 15868c2ecf20Sopenharmony_ci */ 15878c2ecf20Sopenharmony_ci spin_lock(&unix_gc_lock); 15888c2ecf20Sopenharmony_ci spin_unlock(&unix_gc_lock); 15898c2ecf20Sopenharmony_ci} 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_cistatic int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool send_fds) 15928c2ecf20Sopenharmony_ci{ 15938c2ecf20Sopenharmony_ci int err = 0; 15948c2ecf20Sopenharmony_ci 15958c2ecf20Sopenharmony_ci UNIXCB(skb).pid = get_pid(scm->pid); 15968c2ecf20Sopenharmony_ci UNIXCB(skb).uid = scm->creds.uid; 15978c2ecf20Sopenharmony_ci UNIXCB(skb).gid = scm->creds.gid; 15988c2ecf20Sopenharmony_ci UNIXCB(skb).fp = NULL; 15998c2ecf20Sopenharmony_ci unix_get_secdata(scm, skb); 16008c2ecf20Sopenharmony_ci if (scm->fp && send_fds) 16018c2ecf20Sopenharmony_ci err = unix_attach_fds(scm, skb); 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci skb->destructor = unix_destruct_scm; 16048c2ecf20Sopenharmony_ci return err; 16058c2ecf20Sopenharmony_ci} 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_cistatic bool unix_passcred_enabled(const struct socket *sock, 16088c2ecf20Sopenharmony_ci const struct sock *other) 16098c2ecf20Sopenharmony_ci{ 16108c2ecf20Sopenharmony_ci return test_bit(SOCK_PASSCRED, &sock->flags) || 16118c2ecf20Sopenharmony_ci !other->sk_socket || 16128c2ecf20Sopenharmony_ci test_bit(SOCK_PASSCRED, &other->sk_socket->flags); 16138c2ecf20Sopenharmony_ci} 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_ci/* 16168c2ecf20Sopenharmony_ci * Some apps rely on write() giving SCM_CREDENTIALS 16178c2ecf20Sopenharmony_ci * We include credentials if source or destination socket 16188c2ecf20Sopenharmony_ci * asserted SOCK_PASSCRED. 16198c2ecf20Sopenharmony_ci */ 16208c2ecf20Sopenharmony_cistatic void maybe_add_creds(struct sk_buff *skb, const struct socket *sock, 16218c2ecf20Sopenharmony_ci const struct sock *other) 16228c2ecf20Sopenharmony_ci{ 16238c2ecf20Sopenharmony_ci if (UNIXCB(skb).pid) 16248c2ecf20Sopenharmony_ci return; 16258c2ecf20Sopenharmony_ci if (unix_passcred_enabled(sock, other)) { 16268c2ecf20Sopenharmony_ci UNIXCB(skb).pid = get_pid(task_tgid(current)); 16278c2ecf20Sopenharmony_ci current_uid_gid(&UNIXCB(skb).uid, &UNIXCB(skb).gid); 16288c2ecf20Sopenharmony_ci } 16298c2ecf20Sopenharmony_ci} 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_cistatic int maybe_init_creds(struct scm_cookie *scm, 16328c2ecf20Sopenharmony_ci struct socket *socket, 16338c2ecf20Sopenharmony_ci const struct sock *other) 16348c2ecf20Sopenharmony_ci{ 16358c2ecf20Sopenharmony_ci int err; 16368c2ecf20Sopenharmony_ci struct msghdr msg = { .msg_controllen = 0 }; 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci err = scm_send(socket, &msg, scm, false); 16398c2ecf20Sopenharmony_ci if (err) 16408c2ecf20Sopenharmony_ci return err; 16418c2ecf20Sopenharmony_ci 16428c2ecf20Sopenharmony_ci if (unix_passcred_enabled(socket, other)) { 16438c2ecf20Sopenharmony_ci scm->pid = get_pid(task_tgid(current)); 16448c2ecf20Sopenharmony_ci current_uid_gid(&scm->creds.uid, &scm->creds.gid); 16458c2ecf20Sopenharmony_ci } 16468c2ecf20Sopenharmony_ci return err; 16478c2ecf20Sopenharmony_ci} 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_cistatic bool unix_skb_scm_eq(struct sk_buff *skb, 16508c2ecf20Sopenharmony_ci struct scm_cookie *scm) 16518c2ecf20Sopenharmony_ci{ 16528c2ecf20Sopenharmony_ci const struct unix_skb_parms *u = &UNIXCB(skb); 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_ci return u->pid == scm->pid && 16558c2ecf20Sopenharmony_ci uid_eq(u->uid, scm->creds.uid) && 16568c2ecf20Sopenharmony_ci gid_eq(u->gid, scm->creds.gid) && 16578c2ecf20Sopenharmony_ci unix_secdata_eq(scm, skb); 16588c2ecf20Sopenharmony_ci} 16598c2ecf20Sopenharmony_ci 16608c2ecf20Sopenharmony_cistatic void scm_stat_add(struct sock *sk, struct sk_buff *skb) 16618c2ecf20Sopenharmony_ci{ 16628c2ecf20Sopenharmony_ci struct scm_fp_list *fp = UNIXCB(skb).fp; 16638c2ecf20Sopenharmony_ci struct unix_sock *u = unix_sk(sk); 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_ci if (unlikely(fp && fp->count)) 16668c2ecf20Sopenharmony_ci atomic_add(fp->count, &u->scm_stat.nr_fds); 16678c2ecf20Sopenharmony_ci} 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_cistatic void scm_stat_del(struct sock *sk, struct sk_buff *skb) 16708c2ecf20Sopenharmony_ci{ 16718c2ecf20Sopenharmony_ci struct scm_fp_list *fp = UNIXCB(skb).fp; 16728c2ecf20Sopenharmony_ci struct unix_sock *u = unix_sk(sk); 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_ci if (unlikely(fp && fp->count)) 16758c2ecf20Sopenharmony_ci atomic_sub(fp->count, &u->scm_stat.nr_fds); 16768c2ecf20Sopenharmony_ci} 16778c2ecf20Sopenharmony_ci 16788c2ecf20Sopenharmony_ci/* 16798c2ecf20Sopenharmony_ci * Send AF_UNIX data. 16808c2ecf20Sopenharmony_ci */ 16818c2ecf20Sopenharmony_ci 16828c2ecf20Sopenharmony_cistatic int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg, 16838c2ecf20Sopenharmony_ci size_t len) 16848c2ecf20Sopenharmony_ci{ 16858c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 16868c2ecf20Sopenharmony_ci struct net *net = sock_net(sk); 16878c2ecf20Sopenharmony_ci struct unix_sock *u = unix_sk(sk); 16888c2ecf20Sopenharmony_ci DECLARE_SOCKADDR(struct sockaddr_un *, sunaddr, msg->msg_name); 16898c2ecf20Sopenharmony_ci struct sock *other = NULL; 16908c2ecf20Sopenharmony_ci int namelen = 0; /* fake GCC */ 16918c2ecf20Sopenharmony_ci int err; 16928c2ecf20Sopenharmony_ci unsigned int hash; 16938c2ecf20Sopenharmony_ci struct sk_buff *skb; 16948c2ecf20Sopenharmony_ci long timeo; 16958c2ecf20Sopenharmony_ci struct scm_cookie scm; 16968c2ecf20Sopenharmony_ci int data_len = 0; 16978c2ecf20Sopenharmony_ci int sk_locked; 16988c2ecf20Sopenharmony_ci 16998c2ecf20Sopenharmony_ci wait_for_unix_gc(); 17008c2ecf20Sopenharmony_ci err = scm_send(sock, msg, &scm, false); 17018c2ecf20Sopenharmony_ci if (err < 0) 17028c2ecf20Sopenharmony_ci return err; 17038c2ecf20Sopenharmony_ci 17048c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 17058c2ecf20Sopenharmony_ci if (msg->msg_flags&MSG_OOB) 17068c2ecf20Sopenharmony_ci goto out; 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ci if (msg->msg_namelen) { 17098c2ecf20Sopenharmony_ci err = unix_mkname(sunaddr, msg->msg_namelen, &hash); 17108c2ecf20Sopenharmony_ci if (err < 0) 17118c2ecf20Sopenharmony_ci goto out; 17128c2ecf20Sopenharmony_ci namelen = err; 17138c2ecf20Sopenharmony_ci } else { 17148c2ecf20Sopenharmony_ci sunaddr = NULL; 17158c2ecf20Sopenharmony_ci err = -ENOTCONN; 17168c2ecf20Sopenharmony_ci other = unix_peer_get(sk); 17178c2ecf20Sopenharmony_ci if (!other) 17188c2ecf20Sopenharmony_ci goto out; 17198c2ecf20Sopenharmony_ci } 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_ci if (test_bit(SOCK_PASSCRED, &sock->flags) && !u->addr 17228c2ecf20Sopenharmony_ci && (err = unix_autobind(sock)) != 0) 17238c2ecf20Sopenharmony_ci goto out; 17248c2ecf20Sopenharmony_ci 17258c2ecf20Sopenharmony_ci err = -EMSGSIZE; 17268c2ecf20Sopenharmony_ci if (len > sk->sk_sndbuf - 32) 17278c2ecf20Sopenharmony_ci goto out; 17288c2ecf20Sopenharmony_ci 17298c2ecf20Sopenharmony_ci if (len > SKB_MAX_ALLOC) { 17308c2ecf20Sopenharmony_ci data_len = min_t(size_t, 17318c2ecf20Sopenharmony_ci len - SKB_MAX_ALLOC, 17328c2ecf20Sopenharmony_ci MAX_SKB_FRAGS * PAGE_SIZE); 17338c2ecf20Sopenharmony_ci data_len = PAGE_ALIGN(data_len); 17348c2ecf20Sopenharmony_ci 17358c2ecf20Sopenharmony_ci BUILD_BUG_ON(SKB_MAX_ALLOC < PAGE_SIZE); 17368c2ecf20Sopenharmony_ci } 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_ci skb = sock_alloc_send_pskb(sk, len - data_len, data_len, 17398c2ecf20Sopenharmony_ci msg->msg_flags & MSG_DONTWAIT, &err, 17408c2ecf20Sopenharmony_ci PAGE_ALLOC_COSTLY_ORDER); 17418c2ecf20Sopenharmony_ci if (skb == NULL) 17428c2ecf20Sopenharmony_ci goto out; 17438c2ecf20Sopenharmony_ci 17448c2ecf20Sopenharmony_ci err = unix_scm_to_skb(&scm, skb, true); 17458c2ecf20Sopenharmony_ci if (err < 0) 17468c2ecf20Sopenharmony_ci goto out_free; 17478c2ecf20Sopenharmony_ci 17488c2ecf20Sopenharmony_ci skb_put(skb, len - data_len); 17498c2ecf20Sopenharmony_ci skb->data_len = data_len; 17508c2ecf20Sopenharmony_ci skb->len = len; 17518c2ecf20Sopenharmony_ci err = skb_copy_datagram_from_iter(skb, 0, &msg->msg_iter, len); 17528c2ecf20Sopenharmony_ci if (err) 17538c2ecf20Sopenharmony_ci goto out_free; 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); 17568c2ecf20Sopenharmony_ci 17578c2ecf20Sopenharmony_cirestart: 17588c2ecf20Sopenharmony_ci if (!other) { 17598c2ecf20Sopenharmony_ci err = -ECONNRESET; 17608c2ecf20Sopenharmony_ci if (sunaddr == NULL) 17618c2ecf20Sopenharmony_ci goto out_free; 17628c2ecf20Sopenharmony_ci 17638c2ecf20Sopenharmony_ci other = unix_find_other(net, sunaddr, namelen, sk->sk_type, 17648c2ecf20Sopenharmony_ci hash, &err); 17658c2ecf20Sopenharmony_ci if (other == NULL) 17668c2ecf20Sopenharmony_ci goto out_free; 17678c2ecf20Sopenharmony_ci } 17688c2ecf20Sopenharmony_ci 17698c2ecf20Sopenharmony_ci if (sk_filter(other, skb) < 0) { 17708c2ecf20Sopenharmony_ci /* Toss the packet but do not return any error to the sender */ 17718c2ecf20Sopenharmony_ci err = len; 17728c2ecf20Sopenharmony_ci goto out_free; 17738c2ecf20Sopenharmony_ci } 17748c2ecf20Sopenharmony_ci 17758c2ecf20Sopenharmony_ci sk_locked = 0; 17768c2ecf20Sopenharmony_ci unix_state_lock(other); 17778c2ecf20Sopenharmony_cirestart_locked: 17788c2ecf20Sopenharmony_ci err = -EPERM; 17798c2ecf20Sopenharmony_ci if (!unix_may_send(sk, other)) 17808c2ecf20Sopenharmony_ci goto out_unlock; 17818c2ecf20Sopenharmony_ci 17828c2ecf20Sopenharmony_ci if (unlikely(sock_flag(other, SOCK_DEAD))) { 17838c2ecf20Sopenharmony_ci /* 17848c2ecf20Sopenharmony_ci * Check with 1003.1g - what should 17858c2ecf20Sopenharmony_ci * datagram error 17868c2ecf20Sopenharmony_ci */ 17878c2ecf20Sopenharmony_ci unix_state_unlock(other); 17888c2ecf20Sopenharmony_ci sock_put(other); 17898c2ecf20Sopenharmony_ci 17908c2ecf20Sopenharmony_ci if (!sk_locked) 17918c2ecf20Sopenharmony_ci unix_state_lock(sk); 17928c2ecf20Sopenharmony_ci 17938c2ecf20Sopenharmony_ci err = 0; 17948c2ecf20Sopenharmony_ci if (unix_peer(sk) == other) { 17958c2ecf20Sopenharmony_ci unix_peer(sk) = NULL; 17968c2ecf20Sopenharmony_ci unix_dgram_peer_wake_disconnect_wakeup(sk, other); 17978c2ecf20Sopenharmony_ci 17988c2ecf20Sopenharmony_ci unix_state_unlock(sk); 17998c2ecf20Sopenharmony_ci 18008c2ecf20Sopenharmony_ci unix_dgram_disconnected(sk, other); 18018c2ecf20Sopenharmony_ci sock_put(other); 18028c2ecf20Sopenharmony_ci err = -ECONNREFUSED; 18038c2ecf20Sopenharmony_ci } else { 18048c2ecf20Sopenharmony_ci unix_state_unlock(sk); 18058c2ecf20Sopenharmony_ci } 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci other = NULL; 18088c2ecf20Sopenharmony_ci if (err) 18098c2ecf20Sopenharmony_ci goto out_free; 18108c2ecf20Sopenharmony_ci goto restart; 18118c2ecf20Sopenharmony_ci } 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_ci err = -EPIPE; 18148c2ecf20Sopenharmony_ci if (other->sk_shutdown & RCV_SHUTDOWN) 18158c2ecf20Sopenharmony_ci goto out_unlock; 18168c2ecf20Sopenharmony_ci 18178c2ecf20Sopenharmony_ci if (sk->sk_type != SOCK_SEQPACKET) { 18188c2ecf20Sopenharmony_ci err = security_unix_may_send(sk->sk_socket, other->sk_socket); 18198c2ecf20Sopenharmony_ci if (err) 18208c2ecf20Sopenharmony_ci goto out_unlock; 18218c2ecf20Sopenharmony_ci } 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_ci /* other == sk && unix_peer(other) != sk if 18248c2ecf20Sopenharmony_ci * - unix_peer(sk) == NULL, destination address bound to sk 18258c2ecf20Sopenharmony_ci * - unix_peer(sk) == sk by time of get but disconnected before lock 18268c2ecf20Sopenharmony_ci */ 18278c2ecf20Sopenharmony_ci if (other != sk && 18288c2ecf20Sopenharmony_ci unlikely(unix_peer(other) != sk && 18298c2ecf20Sopenharmony_ci unix_recvq_full_lockless(other))) { 18308c2ecf20Sopenharmony_ci if (timeo) { 18318c2ecf20Sopenharmony_ci timeo = unix_wait_for_peer(other, timeo); 18328c2ecf20Sopenharmony_ci 18338c2ecf20Sopenharmony_ci err = sock_intr_errno(timeo); 18348c2ecf20Sopenharmony_ci if (signal_pending(current)) 18358c2ecf20Sopenharmony_ci goto out_free; 18368c2ecf20Sopenharmony_ci 18378c2ecf20Sopenharmony_ci goto restart; 18388c2ecf20Sopenharmony_ci } 18398c2ecf20Sopenharmony_ci 18408c2ecf20Sopenharmony_ci if (!sk_locked) { 18418c2ecf20Sopenharmony_ci unix_state_unlock(other); 18428c2ecf20Sopenharmony_ci unix_state_double_lock(sk, other); 18438c2ecf20Sopenharmony_ci } 18448c2ecf20Sopenharmony_ci 18458c2ecf20Sopenharmony_ci if (unix_peer(sk) != other || 18468c2ecf20Sopenharmony_ci unix_dgram_peer_wake_me(sk, other)) { 18478c2ecf20Sopenharmony_ci err = -EAGAIN; 18488c2ecf20Sopenharmony_ci sk_locked = 1; 18498c2ecf20Sopenharmony_ci goto out_unlock; 18508c2ecf20Sopenharmony_ci } 18518c2ecf20Sopenharmony_ci 18528c2ecf20Sopenharmony_ci if (!sk_locked) { 18538c2ecf20Sopenharmony_ci sk_locked = 1; 18548c2ecf20Sopenharmony_ci goto restart_locked; 18558c2ecf20Sopenharmony_ci } 18568c2ecf20Sopenharmony_ci } 18578c2ecf20Sopenharmony_ci 18588c2ecf20Sopenharmony_ci if (unlikely(sk_locked)) 18598c2ecf20Sopenharmony_ci unix_state_unlock(sk); 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_ci if (sock_flag(other, SOCK_RCVTSTAMP)) 18628c2ecf20Sopenharmony_ci __net_timestamp(skb); 18638c2ecf20Sopenharmony_ci maybe_add_creds(skb, sock, other); 18648c2ecf20Sopenharmony_ci scm_stat_add(other, skb); 18658c2ecf20Sopenharmony_ci skb_queue_tail(&other->sk_receive_queue, skb); 18668c2ecf20Sopenharmony_ci unix_state_unlock(other); 18678c2ecf20Sopenharmony_ci other->sk_data_ready(other); 18688c2ecf20Sopenharmony_ci sock_put(other); 18698c2ecf20Sopenharmony_ci scm_destroy(&scm); 18708c2ecf20Sopenharmony_ci return len; 18718c2ecf20Sopenharmony_ci 18728c2ecf20Sopenharmony_ciout_unlock: 18738c2ecf20Sopenharmony_ci if (sk_locked) 18748c2ecf20Sopenharmony_ci unix_state_unlock(sk); 18758c2ecf20Sopenharmony_ci unix_state_unlock(other); 18768c2ecf20Sopenharmony_ciout_free: 18778c2ecf20Sopenharmony_ci kfree_skb(skb); 18788c2ecf20Sopenharmony_ciout: 18798c2ecf20Sopenharmony_ci if (other) 18808c2ecf20Sopenharmony_ci sock_put(other); 18818c2ecf20Sopenharmony_ci scm_destroy(&scm); 18828c2ecf20Sopenharmony_ci return err; 18838c2ecf20Sopenharmony_ci} 18848c2ecf20Sopenharmony_ci 18858c2ecf20Sopenharmony_ci/* We use paged skbs for stream sockets, and limit occupancy to 32768 18868c2ecf20Sopenharmony_ci * bytes, and a minimum of a full page. 18878c2ecf20Sopenharmony_ci */ 18888c2ecf20Sopenharmony_ci#define UNIX_SKB_FRAGS_SZ (PAGE_SIZE << get_order(32768)) 18898c2ecf20Sopenharmony_ci 18908c2ecf20Sopenharmony_cistatic int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg, 18918c2ecf20Sopenharmony_ci size_t len) 18928c2ecf20Sopenharmony_ci{ 18938c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 18948c2ecf20Sopenharmony_ci struct sock *other = NULL; 18958c2ecf20Sopenharmony_ci int err, size; 18968c2ecf20Sopenharmony_ci struct sk_buff *skb; 18978c2ecf20Sopenharmony_ci int sent = 0; 18988c2ecf20Sopenharmony_ci struct scm_cookie scm; 18998c2ecf20Sopenharmony_ci bool fds_sent = false; 19008c2ecf20Sopenharmony_ci int data_len; 19018c2ecf20Sopenharmony_ci 19028c2ecf20Sopenharmony_ci wait_for_unix_gc(); 19038c2ecf20Sopenharmony_ci err = scm_send(sock, msg, &scm, false); 19048c2ecf20Sopenharmony_ci if (err < 0) 19058c2ecf20Sopenharmony_ci return err; 19068c2ecf20Sopenharmony_ci 19078c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 19088c2ecf20Sopenharmony_ci if (msg->msg_flags&MSG_OOB) 19098c2ecf20Sopenharmony_ci goto out_err; 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_ci if (msg->msg_namelen) { 19128c2ecf20Sopenharmony_ci err = sk->sk_state == TCP_ESTABLISHED ? -EISCONN : -EOPNOTSUPP; 19138c2ecf20Sopenharmony_ci goto out_err; 19148c2ecf20Sopenharmony_ci } else { 19158c2ecf20Sopenharmony_ci err = -ENOTCONN; 19168c2ecf20Sopenharmony_ci other = unix_peer(sk); 19178c2ecf20Sopenharmony_ci if (!other) 19188c2ecf20Sopenharmony_ci goto out_err; 19198c2ecf20Sopenharmony_ci } 19208c2ecf20Sopenharmony_ci 19218c2ecf20Sopenharmony_ci if (READ_ONCE(sk->sk_shutdown) & SEND_SHUTDOWN) 19228c2ecf20Sopenharmony_ci goto pipe_err; 19238c2ecf20Sopenharmony_ci 19248c2ecf20Sopenharmony_ci while (sent < len) { 19258c2ecf20Sopenharmony_ci size = len - sent; 19268c2ecf20Sopenharmony_ci 19278c2ecf20Sopenharmony_ci /* Keep two messages in the pipe so it schedules better */ 19288c2ecf20Sopenharmony_ci size = min_t(int, size, (sk->sk_sndbuf >> 1) - 64); 19298c2ecf20Sopenharmony_ci 19308c2ecf20Sopenharmony_ci /* allow fallback to order-0 allocations */ 19318c2ecf20Sopenharmony_ci size = min_t(int, size, SKB_MAX_HEAD(0) + UNIX_SKB_FRAGS_SZ); 19328c2ecf20Sopenharmony_ci 19338c2ecf20Sopenharmony_ci data_len = max_t(int, 0, size - SKB_MAX_HEAD(0)); 19348c2ecf20Sopenharmony_ci 19358c2ecf20Sopenharmony_ci data_len = min_t(size_t, size, PAGE_ALIGN(data_len)); 19368c2ecf20Sopenharmony_ci 19378c2ecf20Sopenharmony_ci skb = sock_alloc_send_pskb(sk, size - data_len, data_len, 19388c2ecf20Sopenharmony_ci msg->msg_flags & MSG_DONTWAIT, &err, 19398c2ecf20Sopenharmony_ci get_order(UNIX_SKB_FRAGS_SZ)); 19408c2ecf20Sopenharmony_ci if (!skb) 19418c2ecf20Sopenharmony_ci goto out_err; 19428c2ecf20Sopenharmony_ci 19438c2ecf20Sopenharmony_ci /* Only send the fds in the first buffer */ 19448c2ecf20Sopenharmony_ci err = unix_scm_to_skb(&scm, skb, !fds_sent); 19458c2ecf20Sopenharmony_ci if (err < 0) { 19468c2ecf20Sopenharmony_ci kfree_skb(skb); 19478c2ecf20Sopenharmony_ci goto out_err; 19488c2ecf20Sopenharmony_ci } 19498c2ecf20Sopenharmony_ci fds_sent = true; 19508c2ecf20Sopenharmony_ci 19518c2ecf20Sopenharmony_ci skb_put(skb, size - data_len); 19528c2ecf20Sopenharmony_ci skb->data_len = data_len; 19538c2ecf20Sopenharmony_ci skb->len = size; 19548c2ecf20Sopenharmony_ci err = skb_copy_datagram_from_iter(skb, 0, &msg->msg_iter, size); 19558c2ecf20Sopenharmony_ci if (err) { 19568c2ecf20Sopenharmony_ci kfree_skb(skb); 19578c2ecf20Sopenharmony_ci goto out_err; 19588c2ecf20Sopenharmony_ci } 19598c2ecf20Sopenharmony_ci 19608c2ecf20Sopenharmony_ci unix_state_lock(other); 19618c2ecf20Sopenharmony_ci 19628c2ecf20Sopenharmony_ci if (sock_flag(other, SOCK_DEAD) || 19638c2ecf20Sopenharmony_ci (other->sk_shutdown & RCV_SHUTDOWN)) 19648c2ecf20Sopenharmony_ci goto pipe_err_free; 19658c2ecf20Sopenharmony_ci 19668c2ecf20Sopenharmony_ci maybe_add_creds(skb, sock, other); 19678c2ecf20Sopenharmony_ci scm_stat_add(other, skb); 19688c2ecf20Sopenharmony_ci skb_queue_tail(&other->sk_receive_queue, skb); 19698c2ecf20Sopenharmony_ci unix_state_unlock(other); 19708c2ecf20Sopenharmony_ci other->sk_data_ready(other); 19718c2ecf20Sopenharmony_ci sent += size; 19728c2ecf20Sopenharmony_ci } 19738c2ecf20Sopenharmony_ci 19748c2ecf20Sopenharmony_ci scm_destroy(&scm); 19758c2ecf20Sopenharmony_ci 19768c2ecf20Sopenharmony_ci return sent; 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_cipipe_err_free: 19798c2ecf20Sopenharmony_ci unix_state_unlock(other); 19808c2ecf20Sopenharmony_ci kfree_skb(skb); 19818c2ecf20Sopenharmony_cipipe_err: 19828c2ecf20Sopenharmony_ci if (sent == 0 && !(msg->msg_flags&MSG_NOSIGNAL)) 19838c2ecf20Sopenharmony_ci send_sig(SIGPIPE, current, 0); 19848c2ecf20Sopenharmony_ci err = -EPIPE; 19858c2ecf20Sopenharmony_ciout_err: 19868c2ecf20Sopenharmony_ci scm_destroy(&scm); 19878c2ecf20Sopenharmony_ci return sent ? : err; 19888c2ecf20Sopenharmony_ci} 19898c2ecf20Sopenharmony_ci 19908c2ecf20Sopenharmony_cistatic ssize_t unix_stream_sendpage(struct socket *socket, struct page *page, 19918c2ecf20Sopenharmony_ci int offset, size_t size, int flags) 19928c2ecf20Sopenharmony_ci{ 19938c2ecf20Sopenharmony_ci int err; 19948c2ecf20Sopenharmony_ci bool send_sigpipe = false; 19958c2ecf20Sopenharmony_ci bool init_scm = true; 19968c2ecf20Sopenharmony_ci struct scm_cookie scm; 19978c2ecf20Sopenharmony_ci struct sock *other, *sk = socket->sk; 19988c2ecf20Sopenharmony_ci struct sk_buff *skb, *newskb = NULL, *tail = NULL; 19998c2ecf20Sopenharmony_ci 20008c2ecf20Sopenharmony_ci if (flags & MSG_OOB) 20018c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 20028c2ecf20Sopenharmony_ci 20038c2ecf20Sopenharmony_ci other = unix_peer(sk); 20048c2ecf20Sopenharmony_ci if (!other || sk->sk_state != TCP_ESTABLISHED) 20058c2ecf20Sopenharmony_ci return -ENOTCONN; 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_ci if (false) { 20088c2ecf20Sopenharmony_cialloc_skb: 20098c2ecf20Sopenharmony_ci spin_unlock(&other->sk_receive_queue.lock); 20108c2ecf20Sopenharmony_ci unix_state_unlock(other); 20118c2ecf20Sopenharmony_ci mutex_unlock(&unix_sk(other)->iolock); 20128c2ecf20Sopenharmony_ci newskb = sock_alloc_send_pskb(sk, 0, 0, flags & MSG_DONTWAIT, 20138c2ecf20Sopenharmony_ci &err, 0); 20148c2ecf20Sopenharmony_ci if (!newskb) 20158c2ecf20Sopenharmony_ci goto err; 20168c2ecf20Sopenharmony_ci } 20178c2ecf20Sopenharmony_ci 20188c2ecf20Sopenharmony_ci /* we must acquire iolock as we modify already present 20198c2ecf20Sopenharmony_ci * skbs in the sk_receive_queue and mess with skb->len 20208c2ecf20Sopenharmony_ci */ 20218c2ecf20Sopenharmony_ci err = mutex_lock_interruptible(&unix_sk(other)->iolock); 20228c2ecf20Sopenharmony_ci if (err) { 20238c2ecf20Sopenharmony_ci err = flags & MSG_DONTWAIT ? -EAGAIN : -ERESTARTSYS; 20248c2ecf20Sopenharmony_ci goto err; 20258c2ecf20Sopenharmony_ci } 20268c2ecf20Sopenharmony_ci 20278c2ecf20Sopenharmony_ci if (sk->sk_shutdown & SEND_SHUTDOWN) { 20288c2ecf20Sopenharmony_ci err = -EPIPE; 20298c2ecf20Sopenharmony_ci send_sigpipe = true; 20308c2ecf20Sopenharmony_ci goto err_unlock; 20318c2ecf20Sopenharmony_ci } 20328c2ecf20Sopenharmony_ci 20338c2ecf20Sopenharmony_ci unix_state_lock(other); 20348c2ecf20Sopenharmony_ci 20358c2ecf20Sopenharmony_ci if (sock_flag(other, SOCK_DEAD) || 20368c2ecf20Sopenharmony_ci other->sk_shutdown & RCV_SHUTDOWN) { 20378c2ecf20Sopenharmony_ci err = -EPIPE; 20388c2ecf20Sopenharmony_ci send_sigpipe = true; 20398c2ecf20Sopenharmony_ci goto err_state_unlock; 20408c2ecf20Sopenharmony_ci } 20418c2ecf20Sopenharmony_ci 20428c2ecf20Sopenharmony_ci if (init_scm) { 20438c2ecf20Sopenharmony_ci err = maybe_init_creds(&scm, socket, other); 20448c2ecf20Sopenharmony_ci if (err) 20458c2ecf20Sopenharmony_ci goto err_state_unlock; 20468c2ecf20Sopenharmony_ci init_scm = false; 20478c2ecf20Sopenharmony_ci } 20488c2ecf20Sopenharmony_ci 20498c2ecf20Sopenharmony_ci spin_lock(&other->sk_receive_queue.lock); 20508c2ecf20Sopenharmony_ci skb = skb_peek_tail(&other->sk_receive_queue); 20518c2ecf20Sopenharmony_ci if (tail && tail == skb) { 20528c2ecf20Sopenharmony_ci skb = newskb; 20538c2ecf20Sopenharmony_ci } else if (!skb || !unix_skb_scm_eq(skb, &scm)) { 20548c2ecf20Sopenharmony_ci if (newskb) { 20558c2ecf20Sopenharmony_ci skb = newskb; 20568c2ecf20Sopenharmony_ci } else { 20578c2ecf20Sopenharmony_ci tail = skb; 20588c2ecf20Sopenharmony_ci goto alloc_skb; 20598c2ecf20Sopenharmony_ci } 20608c2ecf20Sopenharmony_ci } else if (newskb) { 20618c2ecf20Sopenharmony_ci /* this is fast path, we don't necessarily need to 20628c2ecf20Sopenharmony_ci * call to kfree_skb even though with newskb == NULL 20638c2ecf20Sopenharmony_ci * this - does no harm 20648c2ecf20Sopenharmony_ci */ 20658c2ecf20Sopenharmony_ci consume_skb(newskb); 20668c2ecf20Sopenharmony_ci newskb = NULL; 20678c2ecf20Sopenharmony_ci } 20688c2ecf20Sopenharmony_ci 20698c2ecf20Sopenharmony_ci if (skb_append_pagefrags(skb, page, offset, size)) { 20708c2ecf20Sopenharmony_ci tail = skb; 20718c2ecf20Sopenharmony_ci goto alloc_skb; 20728c2ecf20Sopenharmony_ci } 20738c2ecf20Sopenharmony_ci 20748c2ecf20Sopenharmony_ci skb->len += size; 20758c2ecf20Sopenharmony_ci skb->data_len += size; 20768c2ecf20Sopenharmony_ci skb->truesize += size; 20778c2ecf20Sopenharmony_ci refcount_add(size, &sk->sk_wmem_alloc); 20788c2ecf20Sopenharmony_ci 20798c2ecf20Sopenharmony_ci if (newskb) { 20808c2ecf20Sopenharmony_ci unix_scm_to_skb(&scm, skb, false); 20818c2ecf20Sopenharmony_ci __skb_queue_tail(&other->sk_receive_queue, newskb); 20828c2ecf20Sopenharmony_ci } 20838c2ecf20Sopenharmony_ci 20848c2ecf20Sopenharmony_ci spin_unlock(&other->sk_receive_queue.lock); 20858c2ecf20Sopenharmony_ci unix_state_unlock(other); 20868c2ecf20Sopenharmony_ci mutex_unlock(&unix_sk(other)->iolock); 20878c2ecf20Sopenharmony_ci 20888c2ecf20Sopenharmony_ci other->sk_data_ready(other); 20898c2ecf20Sopenharmony_ci scm_destroy(&scm); 20908c2ecf20Sopenharmony_ci return size; 20918c2ecf20Sopenharmony_ci 20928c2ecf20Sopenharmony_cierr_state_unlock: 20938c2ecf20Sopenharmony_ci unix_state_unlock(other); 20948c2ecf20Sopenharmony_cierr_unlock: 20958c2ecf20Sopenharmony_ci mutex_unlock(&unix_sk(other)->iolock); 20968c2ecf20Sopenharmony_cierr: 20978c2ecf20Sopenharmony_ci kfree_skb(newskb); 20988c2ecf20Sopenharmony_ci if (send_sigpipe && !(flags & MSG_NOSIGNAL)) 20998c2ecf20Sopenharmony_ci send_sig(SIGPIPE, current, 0); 21008c2ecf20Sopenharmony_ci if (!init_scm) 21018c2ecf20Sopenharmony_ci scm_destroy(&scm); 21028c2ecf20Sopenharmony_ci return err; 21038c2ecf20Sopenharmony_ci} 21048c2ecf20Sopenharmony_ci 21058c2ecf20Sopenharmony_cistatic int unix_seqpacket_sendmsg(struct socket *sock, struct msghdr *msg, 21068c2ecf20Sopenharmony_ci size_t len) 21078c2ecf20Sopenharmony_ci{ 21088c2ecf20Sopenharmony_ci int err; 21098c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 21108c2ecf20Sopenharmony_ci 21118c2ecf20Sopenharmony_ci err = sock_error(sk); 21128c2ecf20Sopenharmony_ci if (err) 21138c2ecf20Sopenharmony_ci return err; 21148c2ecf20Sopenharmony_ci 21158c2ecf20Sopenharmony_ci if (sk->sk_state != TCP_ESTABLISHED) 21168c2ecf20Sopenharmony_ci return -ENOTCONN; 21178c2ecf20Sopenharmony_ci 21188c2ecf20Sopenharmony_ci if (msg->msg_namelen) 21198c2ecf20Sopenharmony_ci msg->msg_namelen = 0; 21208c2ecf20Sopenharmony_ci 21218c2ecf20Sopenharmony_ci return unix_dgram_sendmsg(sock, msg, len); 21228c2ecf20Sopenharmony_ci} 21238c2ecf20Sopenharmony_ci 21248c2ecf20Sopenharmony_cistatic int unix_seqpacket_recvmsg(struct socket *sock, struct msghdr *msg, 21258c2ecf20Sopenharmony_ci size_t size, int flags) 21268c2ecf20Sopenharmony_ci{ 21278c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 21288c2ecf20Sopenharmony_ci 21298c2ecf20Sopenharmony_ci if (sk->sk_state != TCP_ESTABLISHED) 21308c2ecf20Sopenharmony_ci return -ENOTCONN; 21318c2ecf20Sopenharmony_ci 21328c2ecf20Sopenharmony_ci return unix_dgram_recvmsg(sock, msg, size, flags); 21338c2ecf20Sopenharmony_ci} 21348c2ecf20Sopenharmony_ci 21358c2ecf20Sopenharmony_cistatic void unix_copy_addr(struct msghdr *msg, struct sock *sk) 21368c2ecf20Sopenharmony_ci{ 21378c2ecf20Sopenharmony_ci struct unix_address *addr = smp_load_acquire(&unix_sk(sk)->addr); 21388c2ecf20Sopenharmony_ci 21398c2ecf20Sopenharmony_ci if (addr) { 21408c2ecf20Sopenharmony_ci msg->msg_namelen = addr->len; 21418c2ecf20Sopenharmony_ci memcpy(msg->msg_name, addr->name, addr->len); 21428c2ecf20Sopenharmony_ci } 21438c2ecf20Sopenharmony_ci} 21448c2ecf20Sopenharmony_ci 21458c2ecf20Sopenharmony_cistatic int unix_dgram_recvmsg(struct socket *sock, struct msghdr *msg, 21468c2ecf20Sopenharmony_ci size_t size, int flags) 21478c2ecf20Sopenharmony_ci{ 21488c2ecf20Sopenharmony_ci struct scm_cookie scm; 21498c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 21508c2ecf20Sopenharmony_ci struct unix_sock *u = unix_sk(sk); 21518c2ecf20Sopenharmony_ci struct sk_buff *skb, *last; 21528c2ecf20Sopenharmony_ci long timeo; 21538c2ecf20Sopenharmony_ci int skip; 21548c2ecf20Sopenharmony_ci int err; 21558c2ecf20Sopenharmony_ci 21568c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 21578c2ecf20Sopenharmony_ci if (flags&MSG_OOB) 21588c2ecf20Sopenharmony_ci goto out; 21598c2ecf20Sopenharmony_ci 21608c2ecf20Sopenharmony_ci timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); 21618c2ecf20Sopenharmony_ci 21628c2ecf20Sopenharmony_ci do { 21638c2ecf20Sopenharmony_ci mutex_lock(&u->iolock); 21648c2ecf20Sopenharmony_ci 21658c2ecf20Sopenharmony_ci skip = sk_peek_offset(sk, flags); 21668c2ecf20Sopenharmony_ci skb = __skb_try_recv_datagram(sk, &sk->sk_receive_queue, flags, 21678c2ecf20Sopenharmony_ci &skip, &err, &last); 21688c2ecf20Sopenharmony_ci if (skb) { 21698c2ecf20Sopenharmony_ci if (!(flags & MSG_PEEK)) 21708c2ecf20Sopenharmony_ci scm_stat_del(sk, skb); 21718c2ecf20Sopenharmony_ci break; 21728c2ecf20Sopenharmony_ci } 21738c2ecf20Sopenharmony_ci 21748c2ecf20Sopenharmony_ci mutex_unlock(&u->iolock); 21758c2ecf20Sopenharmony_ci 21768c2ecf20Sopenharmony_ci if (err != -EAGAIN) 21778c2ecf20Sopenharmony_ci break; 21788c2ecf20Sopenharmony_ci } while (timeo && 21798c2ecf20Sopenharmony_ci !__skb_wait_for_more_packets(sk, &sk->sk_receive_queue, 21808c2ecf20Sopenharmony_ci &err, &timeo, last)); 21818c2ecf20Sopenharmony_ci 21828c2ecf20Sopenharmony_ci if (!skb) { /* implies iolock unlocked */ 21838c2ecf20Sopenharmony_ci unix_state_lock(sk); 21848c2ecf20Sopenharmony_ci /* Signal EOF on disconnected non-blocking SEQPACKET socket. */ 21858c2ecf20Sopenharmony_ci if (sk->sk_type == SOCK_SEQPACKET && err == -EAGAIN && 21868c2ecf20Sopenharmony_ci (sk->sk_shutdown & RCV_SHUTDOWN)) 21878c2ecf20Sopenharmony_ci err = 0; 21888c2ecf20Sopenharmony_ci unix_state_unlock(sk); 21898c2ecf20Sopenharmony_ci goto out; 21908c2ecf20Sopenharmony_ci } 21918c2ecf20Sopenharmony_ci 21928c2ecf20Sopenharmony_ci if (wq_has_sleeper(&u->peer_wait)) 21938c2ecf20Sopenharmony_ci wake_up_interruptible_sync_poll(&u->peer_wait, 21948c2ecf20Sopenharmony_ci EPOLLOUT | EPOLLWRNORM | 21958c2ecf20Sopenharmony_ci EPOLLWRBAND); 21968c2ecf20Sopenharmony_ci 21978c2ecf20Sopenharmony_ci if (msg->msg_name) 21988c2ecf20Sopenharmony_ci unix_copy_addr(msg, skb->sk); 21998c2ecf20Sopenharmony_ci 22008c2ecf20Sopenharmony_ci if (size > skb->len - skip) 22018c2ecf20Sopenharmony_ci size = skb->len - skip; 22028c2ecf20Sopenharmony_ci else if (size < skb->len - skip) 22038c2ecf20Sopenharmony_ci msg->msg_flags |= MSG_TRUNC; 22048c2ecf20Sopenharmony_ci 22058c2ecf20Sopenharmony_ci err = skb_copy_datagram_msg(skb, skip, msg, size); 22068c2ecf20Sopenharmony_ci if (err) 22078c2ecf20Sopenharmony_ci goto out_free; 22088c2ecf20Sopenharmony_ci 22098c2ecf20Sopenharmony_ci if (sock_flag(sk, SOCK_RCVTSTAMP)) 22108c2ecf20Sopenharmony_ci __sock_recv_timestamp(msg, sk, skb); 22118c2ecf20Sopenharmony_ci 22128c2ecf20Sopenharmony_ci memset(&scm, 0, sizeof(scm)); 22138c2ecf20Sopenharmony_ci 22148c2ecf20Sopenharmony_ci scm_set_cred(&scm, UNIXCB(skb).pid, UNIXCB(skb).uid, UNIXCB(skb).gid); 22158c2ecf20Sopenharmony_ci unix_set_secdata(&scm, skb); 22168c2ecf20Sopenharmony_ci 22178c2ecf20Sopenharmony_ci if (!(flags & MSG_PEEK)) { 22188c2ecf20Sopenharmony_ci if (UNIXCB(skb).fp) 22198c2ecf20Sopenharmony_ci unix_detach_fds(&scm, skb); 22208c2ecf20Sopenharmony_ci 22218c2ecf20Sopenharmony_ci sk_peek_offset_bwd(sk, skb->len); 22228c2ecf20Sopenharmony_ci } else { 22238c2ecf20Sopenharmony_ci /* It is questionable: on PEEK we could: 22248c2ecf20Sopenharmony_ci - do not return fds - good, but too simple 8) 22258c2ecf20Sopenharmony_ci - return fds, and do not return them on read (old strategy, 22268c2ecf20Sopenharmony_ci apparently wrong) 22278c2ecf20Sopenharmony_ci - clone fds (I chose it for now, it is the most universal 22288c2ecf20Sopenharmony_ci solution) 22298c2ecf20Sopenharmony_ci 22308c2ecf20Sopenharmony_ci POSIX 1003.1g does not actually define this clearly 22318c2ecf20Sopenharmony_ci at all. POSIX 1003.1g doesn't define a lot of things 22328c2ecf20Sopenharmony_ci clearly however! 22338c2ecf20Sopenharmony_ci 22348c2ecf20Sopenharmony_ci */ 22358c2ecf20Sopenharmony_ci 22368c2ecf20Sopenharmony_ci sk_peek_offset_fwd(sk, size); 22378c2ecf20Sopenharmony_ci 22388c2ecf20Sopenharmony_ci if (UNIXCB(skb).fp) 22398c2ecf20Sopenharmony_ci unix_peek_fds(&scm, skb); 22408c2ecf20Sopenharmony_ci } 22418c2ecf20Sopenharmony_ci err = (flags & MSG_TRUNC) ? skb->len - skip : size; 22428c2ecf20Sopenharmony_ci 22438c2ecf20Sopenharmony_ci scm_recv(sock, msg, &scm, flags); 22448c2ecf20Sopenharmony_ci 22458c2ecf20Sopenharmony_ciout_free: 22468c2ecf20Sopenharmony_ci skb_free_datagram(sk, skb); 22478c2ecf20Sopenharmony_ci mutex_unlock(&u->iolock); 22488c2ecf20Sopenharmony_ciout: 22498c2ecf20Sopenharmony_ci return err; 22508c2ecf20Sopenharmony_ci} 22518c2ecf20Sopenharmony_ci 22528c2ecf20Sopenharmony_ci/* 22538c2ecf20Sopenharmony_ci * Sleep until more data has arrived. But check for races.. 22548c2ecf20Sopenharmony_ci */ 22558c2ecf20Sopenharmony_cistatic long unix_stream_data_wait(struct sock *sk, long timeo, 22568c2ecf20Sopenharmony_ci struct sk_buff *last, unsigned int last_len, 22578c2ecf20Sopenharmony_ci bool freezable) 22588c2ecf20Sopenharmony_ci{ 22598c2ecf20Sopenharmony_ci struct sk_buff *tail; 22608c2ecf20Sopenharmony_ci DEFINE_WAIT(wait); 22618c2ecf20Sopenharmony_ci 22628c2ecf20Sopenharmony_ci unix_state_lock(sk); 22638c2ecf20Sopenharmony_ci 22648c2ecf20Sopenharmony_ci for (;;) { 22658c2ecf20Sopenharmony_ci prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); 22668c2ecf20Sopenharmony_ci 22678c2ecf20Sopenharmony_ci tail = skb_peek_tail(&sk->sk_receive_queue); 22688c2ecf20Sopenharmony_ci if (tail != last || 22698c2ecf20Sopenharmony_ci (tail && tail->len != last_len) || 22708c2ecf20Sopenharmony_ci sk->sk_err || 22718c2ecf20Sopenharmony_ci (sk->sk_shutdown & RCV_SHUTDOWN) || 22728c2ecf20Sopenharmony_ci signal_pending(current) || 22738c2ecf20Sopenharmony_ci !timeo) 22748c2ecf20Sopenharmony_ci break; 22758c2ecf20Sopenharmony_ci 22768c2ecf20Sopenharmony_ci sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk); 22778c2ecf20Sopenharmony_ci unix_state_unlock(sk); 22788c2ecf20Sopenharmony_ci if (freezable) 22798c2ecf20Sopenharmony_ci timeo = freezable_schedule_timeout(timeo); 22808c2ecf20Sopenharmony_ci else 22818c2ecf20Sopenharmony_ci timeo = schedule_timeout(timeo); 22828c2ecf20Sopenharmony_ci unix_state_lock(sk); 22838c2ecf20Sopenharmony_ci 22848c2ecf20Sopenharmony_ci if (sock_flag(sk, SOCK_DEAD)) 22858c2ecf20Sopenharmony_ci break; 22868c2ecf20Sopenharmony_ci 22878c2ecf20Sopenharmony_ci sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk); 22888c2ecf20Sopenharmony_ci } 22898c2ecf20Sopenharmony_ci 22908c2ecf20Sopenharmony_ci finish_wait(sk_sleep(sk), &wait); 22918c2ecf20Sopenharmony_ci unix_state_unlock(sk); 22928c2ecf20Sopenharmony_ci return timeo; 22938c2ecf20Sopenharmony_ci} 22948c2ecf20Sopenharmony_ci 22958c2ecf20Sopenharmony_cistatic unsigned int unix_skb_len(const struct sk_buff *skb) 22968c2ecf20Sopenharmony_ci{ 22978c2ecf20Sopenharmony_ci return skb->len - UNIXCB(skb).consumed; 22988c2ecf20Sopenharmony_ci} 22998c2ecf20Sopenharmony_ci 23008c2ecf20Sopenharmony_cistruct unix_stream_read_state { 23018c2ecf20Sopenharmony_ci int (*recv_actor)(struct sk_buff *, int, int, 23028c2ecf20Sopenharmony_ci struct unix_stream_read_state *); 23038c2ecf20Sopenharmony_ci struct socket *socket; 23048c2ecf20Sopenharmony_ci struct msghdr *msg; 23058c2ecf20Sopenharmony_ci struct pipe_inode_info *pipe; 23068c2ecf20Sopenharmony_ci size_t size; 23078c2ecf20Sopenharmony_ci int flags; 23088c2ecf20Sopenharmony_ci unsigned int splice_flags; 23098c2ecf20Sopenharmony_ci}; 23108c2ecf20Sopenharmony_ci 23118c2ecf20Sopenharmony_cistatic int unix_stream_read_generic(struct unix_stream_read_state *state, 23128c2ecf20Sopenharmony_ci bool freezable) 23138c2ecf20Sopenharmony_ci{ 23148c2ecf20Sopenharmony_ci struct scm_cookie scm; 23158c2ecf20Sopenharmony_ci struct socket *sock = state->socket; 23168c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 23178c2ecf20Sopenharmony_ci struct unix_sock *u = unix_sk(sk); 23188c2ecf20Sopenharmony_ci int copied = 0; 23198c2ecf20Sopenharmony_ci int flags = state->flags; 23208c2ecf20Sopenharmony_ci int noblock = flags & MSG_DONTWAIT; 23218c2ecf20Sopenharmony_ci bool check_creds = false; 23228c2ecf20Sopenharmony_ci int target; 23238c2ecf20Sopenharmony_ci int err = 0; 23248c2ecf20Sopenharmony_ci long timeo; 23258c2ecf20Sopenharmony_ci int skip; 23268c2ecf20Sopenharmony_ci size_t size = state->size; 23278c2ecf20Sopenharmony_ci unsigned int last_len; 23288c2ecf20Sopenharmony_ci 23298c2ecf20Sopenharmony_ci if (unlikely(sk->sk_state != TCP_ESTABLISHED)) { 23308c2ecf20Sopenharmony_ci err = -EINVAL; 23318c2ecf20Sopenharmony_ci goto out; 23328c2ecf20Sopenharmony_ci } 23338c2ecf20Sopenharmony_ci 23348c2ecf20Sopenharmony_ci if (unlikely(flags & MSG_OOB)) { 23358c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 23368c2ecf20Sopenharmony_ci goto out; 23378c2ecf20Sopenharmony_ci } 23388c2ecf20Sopenharmony_ci 23398c2ecf20Sopenharmony_ci target = sock_rcvlowat(sk, flags & MSG_WAITALL, size); 23408c2ecf20Sopenharmony_ci timeo = sock_rcvtimeo(sk, noblock); 23418c2ecf20Sopenharmony_ci 23428c2ecf20Sopenharmony_ci memset(&scm, 0, sizeof(scm)); 23438c2ecf20Sopenharmony_ci 23448c2ecf20Sopenharmony_ci /* Lock the socket to prevent queue disordering 23458c2ecf20Sopenharmony_ci * while sleeps in memcpy_tomsg 23468c2ecf20Sopenharmony_ci */ 23478c2ecf20Sopenharmony_ci mutex_lock(&u->iolock); 23488c2ecf20Sopenharmony_ci 23498c2ecf20Sopenharmony_ci skip = max(sk_peek_offset(sk, flags), 0); 23508c2ecf20Sopenharmony_ci 23518c2ecf20Sopenharmony_ci do { 23528c2ecf20Sopenharmony_ci int chunk; 23538c2ecf20Sopenharmony_ci bool drop_skb; 23548c2ecf20Sopenharmony_ci struct sk_buff *skb, *last; 23558c2ecf20Sopenharmony_ci 23568c2ecf20Sopenharmony_ciredo: 23578c2ecf20Sopenharmony_ci unix_state_lock(sk); 23588c2ecf20Sopenharmony_ci if (sock_flag(sk, SOCK_DEAD)) { 23598c2ecf20Sopenharmony_ci err = -ECONNRESET; 23608c2ecf20Sopenharmony_ci goto unlock; 23618c2ecf20Sopenharmony_ci } 23628c2ecf20Sopenharmony_ci last = skb = skb_peek(&sk->sk_receive_queue); 23638c2ecf20Sopenharmony_ci last_len = last ? last->len : 0; 23648c2ecf20Sopenharmony_ciagain: 23658c2ecf20Sopenharmony_ci if (skb == NULL) { 23668c2ecf20Sopenharmony_ci if (copied >= target) 23678c2ecf20Sopenharmony_ci goto unlock; 23688c2ecf20Sopenharmony_ci 23698c2ecf20Sopenharmony_ci /* 23708c2ecf20Sopenharmony_ci * POSIX 1003.1g mandates this order. 23718c2ecf20Sopenharmony_ci */ 23728c2ecf20Sopenharmony_ci 23738c2ecf20Sopenharmony_ci err = sock_error(sk); 23748c2ecf20Sopenharmony_ci if (err) 23758c2ecf20Sopenharmony_ci goto unlock; 23768c2ecf20Sopenharmony_ci if (sk->sk_shutdown & RCV_SHUTDOWN) 23778c2ecf20Sopenharmony_ci goto unlock; 23788c2ecf20Sopenharmony_ci 23798c2ecf20Sopenharmony_ci unix_state_unlock(sk); 23808c2ecf20Sopenharmony_ci if (!timeo) { 23818c2ecf20Sopenharmony_ci err = -EAGAIN; 23828c2ecf20Sopenharmony_ci break; 23838c2ecf20Sopenharmony_ci } 23848c2ecf20Sopenharmony_ci 23858c2ecf20Sopenharmony_ci mutex_unlock(&u->iolock); 23868c2ecf20Sopenharmony_ci 23878c2ecf20Sopenharmony_ci timeo = unix_stream_data_wait(sk, timeo, last, 23888c2ecf20Sopenharmony_ci last_len, freezable); 23898c2ecf20Sopenharmony_ci 23908c2ecf20Sopenharmony_ci if (signal_pending(current)) { 23918c2ecf20Sopenharmony_ci err = sock_intr_errno(timeo); 23928c2ecf20Sopenharmony_ci scm_destroy(&scm); 23938c2ecf20Sopenharmony_ci goto out; 23948c2ecf20Sopenharmony_ci } 23958c2ecf20Sopenharmony_ci 23968c2ecf20Sopenharmony_ci mutex_lock(&u->iolock); 23978c2ecf20Sopenharmony_ci goto redo; 23988c2ecf20Sopenharmony_ciunlock: 23998c2ecf20Sopenharmony_ci unix_state_unlock(sk); 24008c2ecf20Sopenharmony_ci break; 24018c2ecf20Sopenharmony_ci } 24028c2ecf20Sopenharmony_ci 24038c2ecf20Sopenharmony_ci while (skip >= unix_skb_len(skb)) { 24048c2ecf20Sopenharmony_ci skip -= unix_skb_len(skb); 24058c2ecf20Sopenharmony_ci last = skb; 24068c2ecf20Sopenharmony_ci last_len = skb->len; 24078c2ecf20Sopenharmony_ci skb = skb_peek_next(skb, &sk->sk_receive_queue); 24088c2ecf20Sopenharmony_ci if (!skb) 24098c2ecf20Sopenharmony_ci goto again; 24108c2ecf20Sopenharmony_ci } 24118c2ecf20Sopenharmony_ci 24128c2ecf20Sopenharmony_ci unix_state_unlock(sk); 24138c2ecf20Sopenharmony_ci 24148c2ecf20Sopenharmony_ci if (check_creds) { 24158c2ecf20Sopenharmony_ci /* Never glue messages from different writers */ 24168c2ecf20Sopenharmony_ci if (!unix_skb_scm_eq(skb, &scm)) 24178c2ecf20Sopenharmony_ci break; 24188c2ecf20Sopenharmony_ci } else if (test_bit(SOCK_PASSCRED, &sock->flags)) { 24198c2ecf20Sopenharmony_ci /* Copy credentials */ 24208c2ecf20Sopenharmony_ci scm_set_cred(&scm, UNIXCB(skb).pid, UNIXCB(skb).uid, UNIXCB(skb).gid); 24218c2ecf20Sopenharmony_ci unix_set_secdata(&scm, skb); 24228c2ecf20Sopenharmony_ci check_creds = true; 24238c2ecf20Sopenharmony_ci } 24248c2ecf20Sopenharmony_ci 24258c2ecf20Sopenharmony_ci /* Copy address just once */ 24268c2ecf20Sopenharmony_ci if (state->msg && state->msg->msg_name) { 24278c2ecf20Sopenharmony_ci DECLARE_SOCKADDR(struct sockaddr_un *, sunaddr, 24288c2ecf20Sopenharmony_ci state->msg->msg_name); 24298c2ecf20Sopenharmony_ci unix_copy_addr(state->msg, skb->sk); 24308c2ecf20Sopenharmony_ci sunaddr = NULL; 24318c2ecf20Sopenharmony_ci } 24328c2ecf20Sopenharmony_ci 24338c2ecf20Sopenharmony_ci chunk = min_t(unsigned int, unix_skb_len(skb) - skip, size); 24348c2ecf20Sopenharmony_ci skb_get(skb); 24358c2ecf20Sopenharmony_ci chunk = state->recv_actor(skb, skip, chunk, state); 24368c2ecf20Sopenharmony_ci drop_skb = !unix_skb_len(skb); 24378c2ecf20Sopenharmony_ci /* skb is only safe to use if !drop_skb */ 24388c2ecf20Sopenharmony_ci consume_skb(skb); 24398c2ecf20Sopenharmony_ci if (chunk < 0) { 24408c2ecf20Sopenharmony_ci if (copied == 0) 24418c2ecf20Sopenharmony_ci copied = -EFAULT; 24428c2ecf20Sopenharmony_ci break; 24438c2ecf20Sopenharmony_ci } 24448c2ecf20Sopenharmony_ci copied += chunk; 24458c2ecf20Sopenharmony_ci size -= chunk; 24468c2ecf20Sopenharmony_ci 24478c2ecf20Sopenharmony_ci if (drop_skb) { 24488c2ecf20Sopenharmony_ci /* the skb was touched by a concurrent reader; 24498c2ecf20Sopenharmony_ci * we should not expect anything from this skb 24508c2ecf20Sopenharmony_ci * anymore and assume it invalid - we can be 24518c2ecf20Sopenharmony_ci * sure it was dropped from the socket queue 24528c2ecf20Sopenharmony_ci * 24538c2ecf20Sopenharmony_ci * let's report a short read 24548c2ecf20Sopenharmony_ci */ 24558c2ecf20Sopenharmony_ci err = 0; 24568c2ecf20Sopenharmony_ci break; 24578c2ecf20Sopenharmony_ci } 24588c2ecf20Sopenharmony_ci 24598c2ecf20Sopenharmony_ci /* Mark read part of skb as used */ 24608c2ecf20Sopenharmony_ci if (!(flags & MSG_PEEK)) { 24618c2ecf20Sopenharmony_ci UNIXCB(skb).consumed += chunk; 24628c2ecf20Sopenharmony_ci 24638c2ecf20Sopenharmony_ci sk_peek_offset_bwd(sk, chunk); 24648c2ecf20Sopenharmony_ci 24658c2ecf20Sopenharmony_ci if (UNIXCB(skb).fp) { 24668c2ecf20Sopenharmony_ci scm_stat_del(sk, skb); 24678c2ecf20Sopenharmony_ci unix_detach_fds(&scm, skb); 24688c2ecf20Sopenharmony_ci } 24698c2ecf20Sopenharmony_ci 24708c2ecf20Sopenharmony_ci if (unix_skb_len(skb)) 24718c2ecf20Sopenharmony_ci break; 24728c2ecf20Sopenharmony_ci 24738c2ecf20Sopenharmony_ci skb_unlink(skb, &sk->sk_receive_queue); 24748c2ecf20Sopenharmony_ci consume_skb(skb); 24758c2ecf20Sopenharmony_ci 24768c2ecf20Sopenharmony_ci if (scm.fp) 24778c2ecf20Sopenharmony_ci break; 24788c2ecf20Sopenharmony_ci } else { 24798c2ecf20Sopenharmony_ci /* It is questionable, see note in unix_dgram_recvmsg. 24808c2ecf20Sopenharmony_ci */ 24818c2ecf20Sopenharmony_ci if (UNIXCB(skb).fp) 24828c2ecf20Sopenharmony_ci unix_peek_fds(&scm, skb); 24838c2ecf20Sopenharmony_ci 24848c2ecf20Sopenharmony_ci sk_peek_offset_fwd(sk, chunk); 24858c2ecf20Sopenharmony_ci 24868c2ecf20Sopenharmony_ci if (UNIXCB(skb).fp) 24878c2ecf20Sopenharmony_ci break; 24888c2ecf20Sopenharmony_ci 24898c2ecf20Sopenharmony_ci skip = 0; 24908c2ecf20Sopenharmony_ci last = skb; 24918c2ecf20Sopenharmony_ci last_len = skb->len; 24928c2ecf20Sopenharmony_ci unix_state_lock(sk); 24938c2ecf20Sopenharmony_ci skb = skb_peek_next(skb, &sk->sk_receive_queue); 24948c2ecf20Sopenharmony_ci if (skb) 24958c2ecf20Sopenharmony_ci goto again; 24968c2ecf20Sopenharmony_ci unix_state_unlock(sk); 24978c2ecf20Sopenharmony_ci break; 24988c2ecf20Sopenharmony_ci } 24998c2ecf20Sopenharmony_ci } while (size); 25008c2ecf20Sopenharmony_ci 25018c2ecf20Sopenharmony_ci mutex_unlock(&u->iolock); 25028c2ecf20Sopenharmony_ci if (state->msg) 25038c2ecf20Sopenharmony_ci scm_recv(sock, state->msg, &scm, flags); 25048c2ecf20Sopenharmony_ci else 25058c2ecf20Sopenharmony_ci scm_destroy(&scm); 25068c2ecf20Sopenharmony_ciout: 25078c2ecf20Sopenharmony_ci return copied ? : err; 25088c2ecf20Sopenharmony_ci} 25098c2ecf20Sopenharmony_ci 25108c2ecf20Sopenharmony_cistatic int unix_stream_read_actor(struct sk_buff *skb, 25118c2ecf20Sopenharmony_ci int skip, int chunk, 25128c2ecf20Sopenharmony_ci struct unix_stream_read_state *state) 25138c2ecf20Sopenharmony_ci{ 25148c2ecf20Sopenharmony_ci int ret; 25158c2ecf20Sopenharmony_ci 25168c2ecf20Sopenharmony_ci ret = skb_copy_datagram_msg(skb, UNIXCB(skb).consumed + skip, 25178c2ecf20Sopenharmony_ci state->msg, chunk); 25188c2ecf20Sopenharmony_ci return ret ?: chunk; 25198c2ecf20Sopenharmony_ci} 25208c2ecf20Sopenharmony_ci 25218c2ecf20Sopenharmony_cistatic int unix_stream_recvmsg(struct socket *sock, struct msghdr *msg, 25228c2ecf20Sopenharmony_ci size_t size, int flags) 25238c2ecf20Sopenharmony_ci{ 25248c2ecf20Sopenharmony_ci struct unix_stream_read_state state = { 25258c2ecf20Sopenharmony_ci .recv_actor = unix_stream_read_actor, 25268c2ecf20Sopenharmony_ci .socket = sock, 25278c2ecf20Sopenharmony_ci .msg = msg, 25288c2ecf20Sopenharmony_ci .size = size, 25298c2ecf20Sopenharmony_ci .flags = flags 25308c2ecf20Sopenharmony_ci }; 25318c2ecf20Sopenharmony_ci 25328c2ecf20Sopenharmony_ci return unix_stream_read_generic(&state, true); 25338c2ecf20Sopenharmony_ci} 25348c2ecf20Sopenharmony_ci 25358c2ecf20Sopenharmony_cistatic int unix_stream_splice_actor(struct sk_buff *skb, 25368c2ecf20Sopenharmony_ci int skip, int chunk, 25378c2ecf20Sopenharmony_ci struct unix_stream_read_state *state) 25388c2ecf20Sopenharmony_ci{ 25398c2ecf20Sopenharmony_ci return skb_splice_bits(skb, state->socket->sk, 25408c2ecf20Sopenharmony_ci UNIXCB(skb).consumed + skip, 25418c2ecf20Sopenharmony_ci state->pipe, chunk, state->splice_flags); 25428c2ecf20Sopenharmony_ci} 25438c2ecf20Sopenharmony_ci 25448c2ecf20Sopenharmony_cistatic ssize_t unix_stream_splice_read(struct socket *sock, loff_t *ppos, 25458c2ecf20Sopenharmony_ci struct pipe_inode_info *pipe, 25468c2ecf20Sopenharmony_ci size_t size, unsigned int flags) 25478c2ecf20Sopenharmony_ci{ 25488c2ecf20Sopenharmony_ci struct unix_stream_read_state state = { 25498c2ecf20Sopenharmony_ci .recv_actor = unix_stream_splice_actor, 25508c2ecf20Sopenharmony_ci .socket = sock, 25518c2ecf20Sopenharmony_ci .pipe = pipe, 25528c2ecf20Sopenharmony_ci .size = size, 25538c2ecf20Sopenharmony_ci .splice_flags = flags, 25548c2ecf20Sopenharmony_ci }; 25558c2ecf20Sopenharmony_ci 25568c2ecf20Sopenharmony_ci if (unlikely(*ppos)) 25578c2ecf20Sopenharmony_ci return -ESPIPE; 25588c2ecf20Sopenharmony_ci 25598c2ecf20Sopenharmony_ci if (sock->file->f_flags & O_NONBLOCK || 25608c2ecf20Sopenharmony_ci flags & SPLICE_F_NONBLOCK) 25618c2ecf20Sopenharmony_ci state.flags = MSG_DONTWAIT; 25628c2ecf20Sopenharmony_ci 25638c2ecf20Sopenharmony_ci return unix_stream_read_generic(&state, false); 25648c2ecf20Sopenharmony_ci} 25658c2ecf20Sopenharmony_ci 25668c2ecf20Sopenharmony_cistatic int unix_shutdown(struct socket *sock, int mode) 25678c2ecf20Sopenharmony_ci{ 25688c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 25698c2ecf20Sopenharmony_ci struct sock *other; 25708c2ecf20Sopenharmony_ci 25718c2ecf20Sopenharmony_ci if (mode < SHUT_RD || mode > SHUT_RDWR) 25728c2ecf20Sopenharmony_ci return -EINVAL; 25738c2ecf20Sopenharmony_ci /* This maps: 25748c2ecf20Sopenharmony_ci * SHUT_RD (0) -> RCV_SHUTDOWN (1) 25758c2ecf20Sopenharmony_ci * SHUT_WR (1) -> SEND_SHUTDOWN (2) 25768c2ecf20Sopenharmony_ci * SHUT_RDWR (2) -> SHUTDOWN_MASK (3) 25778c2ecf20Sopenharmony_ci */ 25788c2ecf20Sopenharmony_ci ++mode; 25798c2ecf20Sopenharmony_ci 25808c2ecf20Sopenharmony_ci unix_state_lock(sk); 25818c2ecf20Sopenharmony_ci WRITE_ONCE(sk->sk_shutdown, sk->sk_shutdown | mode); 25828c2ecf20Sopenharmony_ci other = unix_peer(sk); 25838c2ecf20Sopenharmony_ci if (other) 25848c2ecf20Sopenharmony_ci sock_hold(other); 25858c2ecf20Sopenharmony_ci unix_state_unlock(sk); 25868c2ecf20Sopenharmony_ci sk->sk_state_change(sk); 25878c2ecf20Sopenharmony_ci 25888c2ecf20Sopenharmony_ci if (other && 25898c2ecf20Sopenharmony_ci (sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_SEQPACKET)) { 25908c2ecf20Sopenharmony_ci 25918c2ecf20Sopenharmony_ci int peer_mode = 0; 25928c2ecf20Sopenharmony_ci 25938c2ecf20Sopenharmony_ci if (mode&RCV_SHUTDOWN) 25948c2ecf20Sopenharmony_ci peer_mode |= SEND_SHUTDOWN; 25958c2ecf20Sopenharmony_ci if (mode&SEND_SHUTDOWN) 25968c2ecf20Sopenharmony_ci peer_mode |= RCV_SHUTDOWN; 25978c2ecf20Sopenharmony_ci unix_state_lock(other); 25988c2ecf20Sopenharmony_ci WRITE_ONCE(other->sk_shutdown, other->sk_shutdown | peer_mode); 25998c2ecf20Sopenharmony_ci unix_state_unlock(other); 26008c2ecf20Sopenharmony_ci other->sk_state_change(other); 26018c2ecf20Sopenharmony_ci if (peer_mode == SHUTDOWN_MASK) 26028c2ecf20Sopenharmony_ci sk_wake_async(other, SOCK_WAKE_WAITD, POLL_HUP); 26038c2ecf20Sopenharmony_ci else if (peer_mode & RCV_SHUTDOWN) 26048c2ecf20Sopenharmony_ci sk_wake_async(other, SOCK_WAKE_WAITD, POLL_IN); 26058c2ecf20Sopenharmony_ci } 26068c2ecf20Sopenharmony_ci if (other) 26078c2ecf20Sopenharmony_ci sock_put(other); 26088c2ecf20Sopenharmony_ci 26098c2ecf20Sopenharmony_ci return 0; 26108c2ecf20Sopenharmony_ci} 26118c2ecf20Sopenharmony_ci 26128c2ecf20Sopenharmony_cilong unix_inq_len(struct sock *sk) 26138c2ecf20Sopenharmony_ci{ 26148c2ecf20Sopenharmony_ci struct sk_buff *skb; 26158c2ecf20Sopenharmony_ci long amount = 0; 26168c2ecf20Sopenharmony_ci 26178c2ecf20Sopenharmony_ci if (sk->sk_state == TCP_LISTEN) 26188c2ecf20Sopenharmony_ci return -EINVAL; 26198c2ecf20Sopenharmony_ci 26208c2ecf20Sopenharmony_ci spin_lock(&sk->sk_receive_queue.lock); 26218c2ecf20Sopenharmony_ci if (sk->sk_type == SOCK_STREAM || 26228c2ecf20Sopenharmony_ci sk->sk_type == SOCK_SEQPACKET) { 26238c2ecf20Sopenharmony_ci skb_queue_walk(&sk->sk_receive_queue, skb) 26248c2ecf20Sopenharmony_ci amount += unix_skb_len(skb); 26258c2ecf20Sopenharmony_ci } else { 26268c2ecf20Sopenharmony_ci skb = skb_peek(&sk->sk_receive_queue); 26278c2ecf20Sopenharmony_ci if (skb) 26288c2ecf20Sopenharmony_ci amount = skb->len; 26298c2ecf20Sopenharmony_ci } 26308c2ecf20Sopenharmony_ci spin_unlock(&sk->sk_receive_queue.lock); 26318c2ecf20Sopenharmony_ci 26328c2ecf20Sopenharmony_ci return amount; 26338c2ecf20Sopenharmony_ci} 26348c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(unix_inq_len); 26358c2ecf20Sopenharmony_ci 26368c2ecf20Sopenharmony_cilong unix_outq_len(struct sock *sk) 26378c2ecf20Sopenharmony_ci{ 26388c2ecf20Sopenharmony_ci return sk_wmem_alloc_get(sk); 26398c2ecf20Sopenharmony_ci} 26408c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(unix_outq_len); 26418c2ecf20Sopenharmony_ci 26428c2ecf20Sopenharmony_cistatic int unix_open_file(struct sock *sk) 26438c2ecf20Sopenharmony_ci{ 26448c2ecf20Sopenharmony_ci struct path path; 26458c2ecf20Sopenharmony_ci struct file *f; 26468c2ecf20Sopenharmony_ci int fd; 26478c2ecf20Sopenharmony_ci 26488c2ecf20Sopenharmony_ci if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) 26498c2ecf20Sopenharmony_ci return -EPERM; 26508c2ecf20Sopenharmony_ci 26518c2ecf20Sopenharmony_ci if (!smp_load_acquire(&unix_sk(sk)->addr)) 26528c2ecf20Sopenharmony_ci return -ENOENT; 26538c2ecf20Sopenharmony_ci 26548c2ecf20Sopenharmony_ci path = unix_sk(sk)->path; 26558c2ecf20Sopenharmony_ci if (!path.dentry) 26568c2ecf20Sopenharmony_ci return -ENOENT; 26578c2ecf20Sopenharmony_ci 26588c2ecf20Sopenharmony_ci path_get(&path); 26598c2ecf20Sopenharmony_ci 26608c2ecf20Sopenharmony_ci fd = get_unused_fd_flags(O_CLOEXEC); 26618c2ecf20Sopenharmony_ci if (fd < 0) 26628c2ecf20Sopenharmony_ci goto out; 26638c2ecf20Sopenharmony_ci 26648c2ecf20Sopenharmony_ci f = dentry_open(&path, O_PATH, current_cred()); 26658c2ecf20Sopenharmony_ci if (IS_ERR(f)) { 26668c2ecf20Sopenharmony_ci put_unused_fd(fd); 26678c2ecf20Sopenharmony_ci fd = PTR_ERR(f); 26688c2ecf20Sopenharmony_ci goto out; 26698c2ecf20Sopenharmony_ci } 26708c2ecf20Sopenharmony_ci 26718c2ecf20Sopenharmony_ci fd_install(fd, f); 26728c2ecf20Sopenharmony_ciout: 26738c2ecf20Sopenharmony_ci path_put(&path); 26748c2ecf20Sopenharmony_ci 26758c2ecf20Sopenharmony_ci return fd; 26768c2ecf20Sopenharmony_ci} 26778c2ecf20Sopenharmony_ci 26788c2ecf20Sopenharmony_cistatic int unix_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) 26798c2ecf20Sopenharmony_ci{ 26808c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 26818c2ecf20Sopenharmony_ci long amount = 0; 26828c2ecf20Sopenharmony_ci int err; 26838c2ecf20Sopenharmony_ci 26848c2ecf20Sopenharmony_ci switch (cmd) { 26858c2ecf20Sopenharmony_ci case SIOCOUTQ: 26868c2ecf20Sopenharmony_ci amount = unix_outq_len(sk); 26878c2ecf20Sopenharmony_ci err = put_user(amount, (int __user *)arg); 26888c2ecf20Sopenharmony_ci break; 26898c2ecf20Sopenharmony_ci case SIOCINQ: 26908c2ecf20Sopenharmony_ci amount = unix_inq_len(sk); 26918c2ecf20Sopenharmony_ci if (amount < 0) 26928c2ecf20Sopenharmony_ci err = amount; 26938c2ecf20Sopenharmony_ci else 26948c2ecf20Sopenharmony_ci err = put_user(amount, (int __user *)arg); 26958c2ecf20Sopenharmony_ci break; 26968c2ecf20Sopenharmony_ci case SIOCUNIXFILE: 26978c2ecf20Sopenharmony_ci err = unix_open_file(sk); 26988c2ecf20Sopenharmony_ci break; 26998c2ecf20Sopenharmony_ci default: 27008c2ecf20Sopenharmony_ci err = -ENOIOCTLCMD; 27018c2ecf20Sopenharmony_ci break; 27028c2ecf20Sopenharmony_ci } 27038c2ecf20Sopenharmony_ci return err; 27048c2ecf20Sopenharmony_ci} 27058c2ecf20Sopenharmony_ci 27068c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 27078c2ecf20Sopenharmony_cistatic int unix_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) 27088c2ecf20Sopenharmony_ci{ 27098c2ecf20Sopenharmony_ci return unix_ioctl(sock, cmd, (unsigned long)compat_ptr(arg)); 27108c2ecf20Sopenharmony_ci} 27118c2ecf20Sopenharmony_ci#endif 27128c2ecf20Sopenharmony_ci 27138c2ecf20Sopenharmony_cistatic __poll_t unix_poll(struct file *file, struct socket *sock, poll_table *wait) 27148c2ecf20Sopenharmony_ci{ 27158c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 27168c2ecf20Sopenharmony_ci __poll_t mask; 27178c2ecf20Sopenharmony_ci u8 shutdown; 27188c2ecf20Sopenharmony_ci 27198c2ecf20Sopenharmony_ci sock_poll_wait(file, sock, wait); 27208c2ecf20Sopenharmony_ci mask = 0; 27218c2ecf20Sopenharmony_ci shutdown = READ_ONCE(sk->sk_shutdown); 27228c2ecf20Sopenharmony_ci 27238c2ecf20Sopenharmony_ci /* exceptional events? */ 27248c2ecf20Sopenharmony_ci if (sk->sk_err) 27258c2ecf20Sopenharmony_ci mask |= EPOLLERR; 27268c2ecf20Sopenharmony_ci if (shutdown == SHUTDOWN_MASK) 27278c2ecf20Sopenharmony_ci mask |= EPOLLHUP; 27288c2ecf20Sopenharmony_ci if (shutdown & RCV_SHUTDOWN) 27298c2ecf20Sopenharmony_ci mask |= EPOLLRDHUP | EPOLLIN | EPOLLRDNORM; 27308c2ecf20Sopenharmony_ci 27318c2ecf20Sopenharmony_ci /* readable? */ 27328c2ecf20Sopenharmony_ci if (!skb_queue_empty_lockless(&sk->sk_receive_queue)) 27338c2ecf20Sopenharmony_ci mask |= EPOLLIN | EPOLLRDNORM; 27348c2ecf20Sopenharmony_ci 27358c2ecf20Sopenharmony_ci /* Connection-based need to check for termination and startup */ 27368c2ecf20Sopenharmony_ci if ((sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_SEQPACKET) && 27378c2ecf20Sopenharmony_ci sk->sk_state == TCP_CLOSE) 27388c2ecf20Sopenharmony_ci mask |= EPOLLHUP; 27398c2ecf20Sopenharmony_ci 27408c2ecf20Sopenharmony_ci /* 27418c2ecf20Sopenharmony_ci * we set writable also when the other side has shut down the 27428c2ecf20Sopenharmony_ci * connection. This prevents stuck sockets. 27438c2ecf20Sopenharmony_ci */ 27448c2ecf20Sopenharmony_ci if (unix_writable(sk)) 27458c2ecf20Sopenharmony_ci mask |= EPOLLOUT | EPOLLWRNORM | EPOLLWRBAND; 27468c2ecf20Sopenharmony_ci 27478c2ecf20Sopenharmony_ci return mask; 27488c2ecf20Sopenharmony_ci} 27498c2ecf20Sopenharmony_ci 27508c2ecf20Sopenharmony_cistatic __poll_t unix_dgram_poll(struct file *file, struct socket *sock, 27518c2ecf20Sopenharmony_ci poll_table *wait) 27528c2ecf20Sopenharmony_ci{ 27538c2ecf20Sopenharmony_ci struct sock *sk = sock->sk, *other; 27548c2ecf20Sopenharmony_ci unsigned int writable; 27558c2ecf20Sopenharmony_ci __poll_t mask; 27568c2ecf20Sopenharmony_ci u8 shutdown; 27578c2ecf20Sopenharmony_ci 27588c2ecf20Sopenharmony_ci sock_poll_wait(file, sock, wait); 27598c2ecf20Sopenharmony_ci mask = 0; 27608c2ecf20Sopenharmony_ci shutdown = READ_ONCE(sk->sk_shutdown); 27618c2ecf20Sopenharmony_ci 27628c2ecf20Sopenharmony_ci /* exceptional events? */ 27638c2ecf20Sopenharmony_ci if (sk->sk_err || !skb_queue_empty_lockless(&sk->sk_error_queue)) 27648c2ecf20Sopenharmony_ci mask |= EPOLLERR | 27658c2ecf20Sopenharmony_ci (sock_flag(sk, SOCK_SELECT_ERR_QUEUE) ? EPOLLPRI : 0); 27668c2ecf20Sopenharmony_ci 27678c2ecf20Sopenharmony_ci if (shutdown & RCV_SHUTDOWN) 27688c2ecf20Sopenharmony_ci mask |= EPOLLRDHUP | EPOLLIN | EPOLLRDNORM; 27698c2ecf20Sopenharmony_ci if (shutdown == SHUTDOWN_MASK) 27708c2ecf20Sopenharmony_ci mask |= EPOLLHUP; 27718c2ecf20Sopenharmony_ci 27728c2ecf20Sopenharmony_ci /* readable? */ 27738c2ecf20Sopenharmony_ci if (!skb_queue_empty_lockless(&sk->sk_receive_queue)) 27748c2ecf20Sopenharmony_ci mask |= EPOLLIN | EPOLLRDNORM; 27758c2ecf20Sopenharmony_ci 27768c2ecf20Sopenharmony_ci /* Connection-based need to check for termination and startup */ 27778c2ecf20Sopenharmony_ci if (sk->sk_type == SOCK_SEQPACKET) { 27788c2ecf20Sopenharmony_ci if (sk->sk_state == TCP_CLOSE) 27798c2ecf20Sopenharmony_ci mask |= EPOLLHUP; 27808c2ecf20Sopenharmony_ci /* connection hasn't started yet? */ 27818c2ecf20Sopenharmony_ci if (sk->sk_state == TCP_SYN_SENT) 27828c2ecf20Sopenharmony_ci return mask; 27838c2ecf20Sopenharmony_ci } 27848c2ecf20Sopenharmony_ci 27858c2ecf20Sopenharmony_ci /* No write status requested, avoid expensive OUT tests. */ 27868c2ecf20Sopenharmony_ci if (!(poll_requested_events(wait) & (EPOLLWRBAND|EPOLLWRNORM|EPOLLOUT))) 27878c2ecf20Sopenharmony_ci return mask; 27888c2ecf20Sopenharmony_ci 27898c2ecf20Sopenharmony_ci writable = unix_writable(sk); 27908c2ecf20Sopenharmony_ci if (writable) { 27918c2ecf20Sopenharmony_ci unix_state_lock(sk); 27928c2ecf20Sopenharmony_ci 27938c2ecf20Sopenharmony_ci other = unix_peer(sk); 27948c2ecf20Sopenharmony_ci if (other && unix_peer(other) != sk && 27958c2ecf20Sopenharmony_ci unix_recvq_full_lockless(other) && 27968c2ecf20Sopenharmony_ci unix_dgram_peer_wake_me(sk, other)) 27978c2ecf20Sopenharmony_ci writable = 0; 27988c2ecf20Sopenharmony_ci 27998c2ecf20Sopenharmony_ci unix_state_unlock(sk); 28008c2ecf20Sopenharmony_ci } 28018c2ecf20Sopenharmony_ci 28028c2ecf20Sopenharmony_ci if (writable) 28038c2ecf20Sopenharmony_ci mask |= EPOLLOUT | EPOLLWRNORM | EPOLLWRBAND; 28048c2ecf20Sopenharmony_ci else 28058c2ecf20Sopenharmony_ci sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk); 28068c2ecf20Sopenharmony_ci 28078c2ecf20Sopenharmony_ci return mask; 28088c2ecf20Sopenharmony_ci} 28098c2ecf20Sopenharmony_ci 28108c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_FS 28118c2ecf20Sopenharmony_ci 28128c2ecf20Sopenharmony_ci#define BUCKET_SPACE (BITS_PER_LONG - (UNIX_HASH_BITS + 1) - 1) 28138c2ecf20Sopenharmony_ci 28148c2ecf20Sopenharmony_ci#define get_bucket(x) ((x) >> BUCKET_SPACE) 28158c2ecf20Sopenharmony_ci#define get_offset(x) ((x) & ((1L << BUCKET_SPACE) - 1)) 28168c2ecf20Sopenharmony_ci#define set_bucket_offset(b, o) ((b) << BUCKET_SPACE | (o)) 28178c2ecf20Sopenharmony_ci 28188c2ecf20Sopenharmony_cistatic struct sock *unix_from_bucket(struct seq_file *seq, loff_t *pos) 28198c2ecf20Sopenharmony_ci{ 28208c2ecf20Sopenharmony_ci unsigned long offset = get_offset(*pos); 28218c2ecf20Sopenharmony_ci unsigned long bucket = get_bucket(*pos); 28228c2ecf20Sopenharmony_ci struct sock *sk; 28238c2ecf20Sopenharmony_ci unsigned long count = 0; 28248c2ecf20Sopenharmony_ci 28258c2ecf20Sopenharmony_ci for (sk = sk_head(&unix_socket_table[bucket]); sk; sk = sk_next(sk)) { 28268c2ecf20Sopenharmony_ci if (sock_net(sk) != seq_file_net(seq)) 28278c2ecf20Sopenharmony_ci continue; 28288c2ecf20Sopenharmony_ci if (++count == offset) 28298c2ecf20Sopenharmony_ci break; 28308c2ecf20Sopenharmony_ci } 28318c2ecf20Sopenharmony_ci 28328c2ecf20Sopenharmony_ci return sk; 28338c2ecf20Sopenharmony_ci} 28348c2ecf20Sopenharmony_ci 28358c2ecf20Sopenharmony_cistatic struct sock *unix_next_socket(struct seq_file *seq, 28368c2ecf20Sopenharmony_ci struct sock *sk, 28378c2ecf20Sopenharmony_ci loff_t *pos) 28388c2ecf20Sopenharmony_ci{ 28398c2ecf20Sopenharmony_ci unsigned long bucket; 28408c2ecf20Sopenharmony_ci 28418c2ecf20Sopenharmony_ci while (sk > (struct sock *)SEQ_START_TOKEN) { 28428c2ecf20Sopenharmony_ci sk = sk_next(sk); 28438c2ecf20Sopenharmony_ci if (!sk) 28448c2ecf20Sopenharmony_ci goto next_bucket; 28458c2ecf20Sopenharmony_ci if (sock_net(sk) == seq_file_net(seq)) 28468c2ecf20Sopenharmony_ci return sk; 28478c2ecf20Sopenharmony_ci } 28488c2ecf20Sopenharmony_ci 28498c2ecf20Sopenharmony_ci do { 28508c2ecf20Sopenharmony_ci sk = unix_from_bucket(seq, pos); 28518c2ecf20Sopenharmony_ci if (sk) 28528c2ecf20Sopenharmony_ci return sk; 28538c2ecf20Sopenharmony_ci 28548c2ecf20Sopenharmony_cinext_bucket: 28558c2ecf20Sopenharmony_ci bucket = get_bucket(*pos) + 1; 28568c2ecf20Sopenharmony_ci *pos = set_bucket_offset(bucket, 1); 28578c2ecf20Sopenharmony_ci } while (bucket < ARRAY_SIZE(unix_socket_table)); 28588c2ecf20Sopenharmony_ci 28598c2ecf20Sopenharmony_ci return NULL; 28608c2ecf20Sopenharmony_ci} 28618c2ecf20Sopenharmony_ci 28628c2ecf20Sopenharmony_cistatic void *unix_seq_start(struct seq_file *seq, loff_t *pos) 28638c2ecf20Sopenharmony_ci __acquires(unix_table_lock) 28648c2ecf20Sopenharmony_ci{ 28658c2ecf20Sopenharmony_ci spin_lock(&unix_table_lock); 28668c2ecf20Sopenharmony_ci 28678c2ecf20Sopenharmony_ci if (!*pos) 28688c2ecf20Sopenharmony_ci return SEQ_START_TOKEN; 28698c2ecf20Sopenharmony_ci 28708c2ecf20Sopenharmony_ci if (get_bucket(*pos) >= ARRAY_SIZE(unix_socket_table)) 28718c2ecf20Sopenharmony_ci return NULL; 28728c2ecf20Sopenharmony_ci 28738c2ecf20Sopenharmony_ci return unix_next_socket(seq, NULL, pos); 28748c2ecf20Sopenharmony_ci} 28758c2ecf20Sopenharmony_ci 28768c2ecf20Sopenharmony_cistatic void *unix_seq_next(struct seq_file *seq, void *v, loff_t *pos) 28778c2ecf20Sopenharmony_ci{ 28788c2ecf20Sopenharmony_ci ++*pos; 28798c2ecf20Sopenharmony_ci return unix_next_socket(seq, v, pos); 28808c2ecf20Sopenharmony_ci} 28818c2ecf20Sopenharmony_ci 28828c2ecf20Sopenharmony_cistatic void unix_seq_stop(struct seq_file *seq, void *v) 28838c2ecf20Sopenharmony_ci __releases(unix_table_lock) 28848c2ecf20Sopenharmony_ci{ 28858c2ecf20Sopenharmony_ci spin_unlock(&unix_table_lock); 28868c2ecf20Sopenharmony_ci} 28878c2ecf20Sopenharmony_ci 28888c2ecf20Sopenharmony_cistatic int unix_seq_show(struct seq_file *seq, void *v) 28898c2ecf20Sopenharmony_ci{ 28908c2ecf20Sopenharmony_ci 28918c2ecf20Sopenharmony_ci if (v == SEQ_START_TOKEN) 28928c2ecf20Sopenharmony_ci seq_puts(seq, "Num RefCount Protocol Flags Type St " 28938c2ecf20Sopenharmony_ci "Inode Path\n"); 28948c2ecf20Sopenharmony_ci else { 28958c2ecf20Sopenharmony_ci struct sock *s = v; 28968c2ecf20Sopenharmony_ci struct unix_sock *u = unix_sk(s); 28978c2ecf20Sopenharmony_ci unix_state_lock(s); 28988c2ecf20Sopenharmony_ci 28998c2ecf20Sopenharmony_ci seq_printf(seq, "%pK: %08X %08X %08X %04X %02X %5lu", 29008c2ecf20Sopenharmony_ci s, 29018c2ecf20Sopenharmony_ci refcount_read(&s->sk_refcnt), 29028c2ecf20Sopenharmony_ci 0, 29038c2ecf20Sopenharmony_ci s->sk_state == TCP_LISTEN ? __SO_ACCEPTCON : 0, 29048c2ecf20Sopenharmony_ci s->sk_type, 29058c2ecf20Sopenharmony_ci s->sk_socket ? 29068c2ecf20Sopenharmony_ci (s->sk_state == TCP_ESTABLISHED ? SS_CONNECTED : SS_UNCONNECTED) : 29078c2ecf20Sopenharmony_ci (s->sk_state == TCP_ESTABLISHED ? SS_CONNECTING : SS_DISCONNECTING), 29088c2ecf20Sopenharmony_ci sock_i_ino(s)); 29098c2ecf20Sopenharmony_ci 29108c2ecf20Sopenharmony_ci if (u->addr) { // under unix_table_lock here 29118c2ecf20Sopenharmony_ci int i, len; 29128c2ecf20Sopenharmony_ci seq_putc(seq, ' '); 29138c2ecf20Sopenharmony_ci 29148c2ecf20Sopenharmony_ci i = 0; 29158c2ecf20Sopenharmony_ci len = u->addr->len - sizeof(short); 29168c2ecf20Sopenharmony_ci if (!UNIX_ABSTRACT(s)) 29178c2ecf20Sopenharmony_ci len--; 29188c2ecf20Sopenharmony_ci else { 29198c2ecf20Sopenharmony_ci seq_putc(seq, '@'); 29208c2ecf20Sopenharmony_ci i++; 29218c2ecf20Sopenharmony_ci } 29228c2ecf20Sopenharmony_ci for ( ; i < len; i++) 29238c2ecf20Sopenharmony_ci seq_putc(seq, u->addr->name->sun_path[i] ?: 29248c2ecf20Sopenharmony_ci '@'); 29258c2ecf20Sopenharmony_ci } 29268c2ecf20Sopenharmony_ci unix_state_unlock(s); 29278c2ecf20Sopenharmony_ci seq_putc(seq, '\n'); 29288c2ecf20Sopenharmony_ci } 29298c2ecf20Sopenharmony_ci 29308c2ecf20Sopenharmony_ci return 0; 29318c2ecf20Sopenharmony_ci} 29328c2ecf20Sopenharmony_ci 29338c2ecf20Sopenharmony_cistatic const struct seq_operations unix_seq_ops = { 29348c2ecf20Sopenharmony_ci .start = unix_seq_start, 29358c2ecf20Sopenharmony_ci .next = unix_seq_next, 29368c2ecf20Sopenharmony_ci .stop = unix_seq_stop, 29378c2ecf20Sopenharmony_ci .show = unix_seq_show, 29388c2ecf20Sopenharmony_ci}; 29398c2ecf20Sopenharmony_ci#endif 29408c2ecf20Sopenharmony_ci 29418c2ecf20Sopenharmony_cistatic const struct net_proto_family unix_family_ops = { 29428c2ecf20Sopenharmony_ci .family = PF_UNIX, 29438c2ecf20Sopenharmony_ci .create = unix_create, 29448c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 29458c2ecf20Sopenharmony_ci}; 29468c2ecf20Sopenharmony_ci 29478c2ecf20Sopenharmony_ci 29488c2ecf20Sopenharmony_cistatic int __net_init unix_net_init(struct net *net) 29498c2ecf20Sopenharmony_ci{ 29508c2ecf20Sopenharmony_ci int error = -ENOMEM; 29518c2ecf20Sopenharmony_ci 29528c2ecf20Sopenharmony_ci net->unx.sysctl_max_dgram_qlen = 10; 29538c2ecf20Sopenharmony_ci if (unix_sysctl_register(net)) 29548c2ecf20Sopenharmony_ci goto out; 29558c2ecf20Sopenharmony_ci 29568c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_FS 29578c2ecf20Sopenharmony_ci if (!proc_create_net("unix", 0, net->proc_net, &unix_seq_ops, 29588c2ecf20Sopenharmony_ci sizeof(struct seq_net_private))) { 29598c2ecf20Sopenharmony_ci unix_sysctl_unregister(net); 29608c2ecf20Sopenharmony_ci goto out; 29618c2ecf20Sopenharmony_ci } 29628c2ecf20Sopenharmony_ci#endif 29638c2ecf20Sopenharmony_ci error = 0; 29648c2ecf20Sopenharmony_ciout: 29658c2ecf20Sopenharmony_ci return error; 29668c2ecf20Sopenharmony_ci} 29678c2ecf20Sopenharmony_ci 29688c2ecf20Sopenharmony_cistatic void __net_exit unix_net_exit(struct net *net) 29698c2ecf20Sopenharmony_ci{ 29708c2ecf20Sopenharmony_ci unix_sysctl_unregister(net); 29718c2ecf20Sopenharmony_ci remove_proc_entry("unix", net->proc_net); 29728c2ecf20Sopenharmony_ci} 29738c2ecf20Sopenharmony_ci 29748c2ecf20Sopenharmony_cistatic struct pernet_operations unix_net_ops = { 29758c2ecf20Sopenharmony_ci .init = unix_net_init, 29768c2ecf20Sopenharmony_ci .exit = unix_net_exit, 29778c2ecf20Sopenharmony_ci}; 29788c2ecf20Sopenharmony_ci 29798c2ecf20Sopenharmony_cistatic int __init af_unix_init(void) 29808c2ecf20Sopenharmony_ci{ 29818c2ecf20Sopenharmony_ci int rc = -1; 29828c2ecf20Sopenharmony_ci 29838c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(struct unix_skb_parms) > sizeof_field(struct sk_buff, cb)); 29848c2ecf20Sopenharmony_ci 29858c2ecf20Sopenharmony_ci rc = proto_register(&unix_proto, 1); 29868c2ecf20Sopenharmony_ci if (rc != 0) { 29878c2ecf20Sopenharmony_ci pr_crit("%s: Cannot create unix_sock SLAB cache!\n", __func__); 29888c2ecf20Sopenharmony_ci goto out; 29898c2ecf20Sopenharmony_ci } 29908c2ecf20Sopenharmony_ci 29918c2ecf20Sopenharmony_ci sock_register(&unix_family_ops); 29928c2ecf20Sopenharmony_ci register_pernet_subsys(&unix_net_ops); 29938c2ecf20Sopenharmony_ciout: 29948c2ecf20Sopenharmony_ci return rc; 29958c2ecf20Sopenharmony_ci} 29968c2ecf20Sopenharmony_ci 29978c2ecf20Sopenharmony_cistatic void __exit af_unix_exit(void) 29988c2ecf20Sopenharmony_ci{ 29998c2ecf20Sopenharmony_ci sock_unregister(PF_UNIX); 30008c2ecf20Sopenharmony_ci proto_unregister(&unix_proto); 30018c2ecf20Sopenharmony_ci unregister_pernet_subsys(&unix_net_ops); 30028c2ecf20Sopenharmony_ci} 30038c2ecf20Sopenharmony_ci 30048c2ecf20Sopenharmony_ci/* Earlier than device_initcall() so that other drivers invoking 30058c2ecf20Sopenharmony_ci request_module() don't end up in a loop when modprobe tries 30068c2ecf20Sopenharmony_ci to use a UNIX socket. But later than subsys_initcall() because 30078c2ecf20Sopenharmony_ci we depend on stuff initialised there */ 30088c2ecf20Sopenharmony_cifs_initcall(af_unix_init); 30098c2ecf20Sopenharmony_cimodule_exit(af_unix_exit); 30108c2ecf20Sopenharmony_ci 30118c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 30128c2ecf20Sopenharmony_ciMODULE_ALIAS_NETPROTO(PF_UNIX); 3013