162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * NET4: Implementation of BSD Unix domain sockets. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Authors: Alan Cox, <alan@lxorguk.ukuu.org.uk> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Fixes: 862306a36Sopenharmony_ci * Linus Torvalds : Assorted bug cures. 962306a36Sopenharmony_ci * Niibe Yutaka : async I/O support. 1062306a36Sopenharmony_ci * Carsten Paeth : PF_UNIX check, address fixes. 1162306a36Sopenharmony_ci * Alan Cox : Limit size of allocated blocks. 1262306a36Sopenharmony_ci * Alan Cox : Fixed the stupid socketpair bug. 1362306a36Sopenharmony_ci * Alan Cox : BSD compatibility fine tuning. 1462306a36Sopenharmony_ci * Alan Cox : Fixed a bug in connect when interrupted. 1562306a36Sopenharmony_ci * Alan Cox : Sorted out a proper draft version of 1662306a36Sopenharmony_ci * file descriptor passing hacked up from 1762306a36Sopenharmony_ci * Mike Shaver's work. 1862306a36Sopenharmony_ci * Marty Leisner : Fixes to fd passing 1962306a36Sopenharmony_ci * Nick Nevin : recvmsg bugfix. 2062306a36Sopenharmony_ci * Alan Cox : Started proper garbage collector 2162306a36Sopenharmony_ci * Heiko EiBfeldt : Missing verify_area check 2262306a36Sopenharmony_ci * Alan Cox : Started POSIXisms 2362306a36Sopenharmony_ci * Andreas Schwab : Replace inode by dentry for proper 2462306a36Sopenharmony_ci * reference counting 2562306a36Sopenharmony_ci * Kirk Petersen : Made this a module 2662306a36Sopenharmony_ci * Christoph Rohland : Elegant non-blocking accept/connect algorithm. 2762306a36Sopenharmony_ci * Lots of bug fixes. 2862306a36Sopenharmony_ci * Alexey Kuznetosv : Repaired (I hope) bugs introduces 2962306a36Sopenharmony_ci * by above two patches. 3062306a36Sopenharmony_ci * Andrea Arcangeli : If possible we block in connect(2) 3162306a36Sopenharmony_ci * if the max backlog of the listen socket 3262306a36Sopenharmony_ci * is been reached. This won't break 3362306a36Sopenharmony_ci * old apps and it will avoid huge amount 3462306a36Sopenharmony_ci * of socks hashed (this for unix_gc() 3562306a36Sopenharmony_ci * performances reasons). 3662306a36Sopenharmony_ci * Security fix that limits the max 3762306a36Sopenharmony_ci * number of socks to 2*max_files and 3862306a36Sopenharmony_ci * the number of skb queueable in the 3962306a36Sopenharmony_ci * dgram receiver. 4062306a36Sopenharmony_ci * Artur Skawina : Hash function optimizations 4162306a36Sopenharmony_ci * Alexey Kuznetsov : Full scale SMP. Lot of bugs are introduced 8) 4262306a36Sopenharmony_ci * Malcolm Beattie : Set peercred for socketpair 4362306a36Sopenharmony_ci * Michal Ostrowski : Module initialization cleanup. 4462306a36Sopenharmony_ci * Arnaldo C. Melo : Remove MOD_{INC,DEC}_USE_COUNT, 4562306a36Sopenharmony_ci * the core infrastructure is doing that 4662306a36Sopenharmony_ci * for all net proto families now (2.5.69+) 4762306a36Sopenharmony_ci * 4862306a36Sopenharmony_ci * Known differences from reference BSD that was tested: 4962306a36Sopenharmony_ci * 5062306a36Sopenharmony_ci * [TO FIX] 5162306a36Sopenharmony_ci * ECONNREFUSED is not returned from one end of a connected() socket to the 5262306a36Sopenharmony_ci * other the moment one end closes. 5362306a36Sopenharmony_ci * fstat() doesn't return st_dev=0, and give the blksize as high water mark 5462306a36Sopenharmony_ci * and a fake inode identifier (nor the BSD first socket fstat twice bug). 5562306a36Sopenharmony_ci * [NOT TO FIX] 5662306a36Sopenharmony_ci * accept() returns a path name even if the connecting socket has closed 5762306a36Sopenharmony_ci * in the meantime (BSD loses the path and gives up). 5862306a36Sopenharmony_ci * accept() returns 0 length path for an unbound connector. BSD returns 16 5962306a36Sopenharmony_ci * and a null first byte in the path (but not for gethost/peername - BSD bug ??) 6062306a36Sopenharmony_ci * socketpair(...SOCK_RAW..) doesn't panic the kernel. 6162306a36Sopenharmony_ci * BSD af_unix apparently has connect forgetting to block properly. 6262306a36Sopenharmony_ci * (need to check this with the POSIX spec in detail) 6362306a36Sopenharmony_ci * 6462306a36Sopenharmony_ci * Differences from 2.0.0-11-... (ANK) 6562306a36Sopenharmony_ci * Bug fixes and improvements. 6662306a36Sopenharmony_ci * - client shutdown killed server socket. 6762306a36Sopenharmony_ci * - removed all useless cli/sti pairs. 6862306a36Sopenharmony_ci * 6962306a36Sopenharmony_ci * Semantic changes/extensions. 7062306a36Sopenharmony_ci * - generic control message passing. 7162306a36Sopenharmony_ci * - SCM_CREDENTIALS control message. 7262306a36Sopenharmony_ci * - "Abstract" (not FS based) socket bindings. 7362306a36Sopenharmony_ci * Abstract names are sequences of bytes (not zero terminated) 7462306a36Sopenharmony_ci * started by 0, so that this name space does not intersect 7562306a36Sopenharmony_ci * with BSD names. 7662306a36Sopenharmony_ci */ 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci#include <linux/module.h> 8162306a36Sopenharmony_ci#include <linux/kernel.h> 8262306a36Sopenharmony_ci#include <linux/signal.h> 8362306a36Sopenharmony_ci#include <linux/sched/signal.h> 8462306a36Sopenharmony_ci#include <linux/errno.h> 8562306a36Sopenharmony_ci#include <linux/string.h> 8662306a36Sopenharmony_ci#include <linux/stat.h> 8762306a36Sopenharmony_ci#include <linux/dcache.h> 8862306a36Sopenharmony_ci#include <linux/namei.h> 8962306a36Sopenharmony_ci#include <linux/socket.h> 9062306a36Sopenharmony_ci#include <linux/un.h> 9162306a36Sopenharmony_ci#include <linux/fcntl.h> 9262306a36Sopenharmony_ci#include <linux/filter.h> 9362306a36Sopenharmony_ci#include <linux/termios.h> 9462306a36Sopenharmony_ci#include <linux/sockios.h> 9562306a36Sopenharmony_ci#include <linux/net.h> 9662306a36Sopenharmony_ci#include <linux/in.h> 9762306a36Sopenharmony_ci#include <linux/fs.h> 9862306a36Sopenharmony_ci#include <linux/slab.h> 9962306a36Sopenharmony_ci#include <linux/uaccess.h> 10062306a36Sopenharmony_ci#include <linux/skbuff.h> 10162306a36Sopenharmony_ci#include <linux/netdevice.h> 10262306a36Sopenharmony_ci#include <net/net_namespace.h> 10362306a36Sopenharmony_ci#include <net/sock.h> 10462306a36Sopenharmony_ci#include <net/tcp_states.h> 10562306a36Sopenharmony_ci#include <net/af_unix.h> 10662306a36Sopenharmony_ci#include <linux/proc_fs.h> 10762306a36Sopenharmony_ci#include <linux/seq_file.h> 10862306a36Sopenharmony_ci#include <net/scm.h> 10962306a36Sopenharmony_ci#include <linux/init.h> 11062306a36Sopenharmony_ci#include <linux/poll.h> 11162306a36Sopenharmony_ci#include <linux/rtnetlink.h> 11262306a36Sopenharmony_ci#include <linux/mount.h> 11362306a36Sopenharmony_ci#include <net/checksum.h> 11462306a36Sopenharmony_ci#include <linux/security.h> 11562306a36Sopenharmony_ci#include <linux/splice.h> 11662306a36Sopenharmony_ci#include <linux/freezer.h> 11762306a36Sopenharmony_ci#include <linux/file.h> 11862306a36Sopenharmony_ci#include <linux/btf_ids.h> 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci#include "scm.h" 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic atomic_long_t unix_nr_socks; 12362306a36Sopenharmony_cistatic struct hlist_head bsd_socket_buckets[UNIX_HASH_SIZE / 2]; 12462306a36Sopenharmony_cistatic spinlock_t bsd_socket_locks[UNIX_HASH_SIZE / 2]; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci/* SMP locking strategy: 12762306a36Sopenharmony_ci * hash table is protected with spinlock. 12862306a36Sopenharmony_ci * each socket state is protected by separate spinlock. 12962306a36Sopenharmony_ci */ 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistatic unsigned int unix_unbound_hash(struct sock *sk) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci unsigned long hash = (unsigned long)sk; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci hash ^= hash >> 16; 13662306a36Sopenharmony_ci hash ^= hash >> 8; 13762306a36Sopenharmony_ci hash ^= sk->sk_type; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci return hash & UNIX_HASH_MOD; 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistatic unsigned int unix_bsd_hash(struct inode *i) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci return i->i_ino & UNIX_HASH_MOD; 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic unsigned int unix_abstract_hash(struct sockaddr_un *sunaddr, 14862306a36Sopenharmony_ci int addr_len, int type) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci __wsum csum = csum_partial(sunaddr, addr_len, 0); 15162306a36Sopenharmony_ci unsigned int hash; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci hash = (__force unsigned int)csum_fold(csum); 15462306a36Sopenharmony_ci hash ^= hash >> 8; 15562306a36Sopenharmony_ci hash ^= type; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci return UNIX_HASH_MOD + 1 + (hash & UNIX_HASH_MOD); 15862306a36Sopenharmony_ci} 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_cistatic void unix_table_double_lock(struct net *net, 16162306a36Sopenharmony_ci unsigned int hash1, unsigned int hash2) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci if (hash1 == hash2) { 16462306a36Sopenharmony_ci spin_lock(&net->unx.table.locks[hash1]); 16562306a36Sopenharmony_ci return; 16662306a36Sopenharmony_ci } 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci if (hash1 > hash2) 16962306a36Sopenharmony_ci swap(hash1, hash2); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci spin_lock(&net->unx.table.locks[hash1]); 17262306a36Sopenharmony_ci spin_lock_nested(&net->unx.table.locks[hash2], SINGLE_DEPTH_NESTING); 17362306a36Sopenharmony_ci} 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistatic void unix_table_double_unlock(struct net *net, 17662306a36Sopenharmony_ci unsigned int hash1, unsigned int hash2) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci if (hash1 == hash2) { 17962306a36Sopenharmony_ci spin_unlock(&net->unx.table.locks[hash1]); 18062306a36Sopenharmony_ci return; 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci spin_unlock(&net->unx.table.locks[hash1]); 18462306a36Sopenharmony_ci spin_unlock(&net->unx.table.locks[hash2]); 18562306a36Sopenharmony_ci} 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci#ifdef CONFIG_SECURITY_NETWORK 18862306a36Sopenharmony_cistatic void unix_get_secdata(struct scm_cookie *scm, struct sk_buff *skb) 18962306a36Sopenharmony_ci{ 19062306a36Sopenharmony_ci UNIXCB(skb).secid = scm->secid; 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_cistatic inline void unix_set_secdata(struct scm_cookie *scm, struct sk_buff *skb) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci scm->secid = UNIXCB(skb).secid; 19662306a36Sopenharmony_ci} 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_cistatic inline bool unix_secdata_eq(struct scm_cookie *scm, struct sk_buff *skb) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci return (scm->secid == UNIXCB(skb).secid); 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci#else 20362306a36Sopenharmony_cistatic inline void unix_get_secdata(struct scm_cookie *scm, struct sk_buff *skb) 20462306a36Sopenharmony_ci{ } 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistatic inline void unix_set_secdata(struct scm_cookie *scm, struct sk_buff *skb) 20762306a36Sopenharmony_ci{ } 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_cistatic inline bool unix_secdata_eq(struct scm_cookie *scm, struct sk_buff *skb) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci return true; 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci#endif /* CONFIG_SECURITY_NETWORK */ 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_cistatic inline int unix_our_peer(struct sock *sk, struct sock *osk) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci return unix_peer(osk) == sk; 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_cistatic inline int unix_may_send(struct sock *sk, struct sock *osk) 22162306a36Sopenharmony_ci{ 22262306a36Sopenharmony_ci return unix_peer(osk) == NULL || unix_our_peer(sk, osk); 22362306a36Sopenharmony_ci} 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_cistatic inline int unix_recvq_full(const struct sock *sk) 22662306a36Sopenharmony_ci{ 22762306a36Sopenharmony_ci return skb_queue_len(&sk->sk_receive_queue) > sk->sk_max_ack_backlog; 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_cistatic inline int unix_recvq_full_lockless(const struct sock *sk) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci return skb_queue_len_lockless(&sk->sk_receive_queue) > 23362306a36Sopenharmony_ci READ_ONCE(sk->sk_max_ack_backlog); 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistruct sock *unix_peer_get(struct sock *s) 23762306a36Sopenharmony_ci{ 23862306a36Sopenharmony_ci struct sock *peer; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci unix_state_lock(s); 24162306a36Sopenharmony_ci peer = unix_peer(s); 24262306a36Sopenharmony_ci if (peer) 24362306a36Sopenharmony_ci sock_hold(peer); 24462306a36Sopenharmony_ci unix_state_unlock(s); 24562306a36Sopenharmony_ci return peer; 24662306a36Sopenharmony_ci} 24762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(unix_peer_get); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_cistatic struct unix_address *unix_create_addr(struct sockaddr_un *sunaddr, 25062306a36Sopenharmony_ci int addr_len) 25162306a36Sopenharmony_ci{ 25262306a36Sopenharmony_ci struct unix_address *addr; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci addr = kmalloc(sizeof(*addr) + addr_len, GFP_KERNEL); 25562306a36Sopenharmony_ci if (!addr) 25662306a36Sopenharmony_ci return NULL; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci refcount_set(&addr->refcnt, 1); 25962306a36Sopenharmony_ci addr->len = addr_len; 26062306a36Sopenharmony_ci memcpy(addr->name, sunaddr, addr_len); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci return addr; 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_cistatic inline void unix_release_addr(struct unix_address *addr) 26662306a36Sopenharmony_ci{ 26762306a36Sopenharmony_ci if (refcount_dec_and_test(&addr->refcnt)) 26862306a36Sopenharmony_ci kfree(addr); 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci/* 27262306a36Sopenharmony_ci * Check unix socket name: 27362306a36Sopenharmony_ci * - should be not zero length. 27462306a36Sopenharmony_ci * - if started by not zero, should be NULL terminated (FS object) 27562306a36Sopenharmony_ci * - if started by zero, it is abstract name. 27662306a36Sopenharmony_ci */ 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_cistatic int unix_validate_addr(struct sockaddr_un *sunaddr, int addr_len) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci if (addr_len <= offsetof(struct sockaddr_un, sun_path) || 28162306a36Sopenharmony_ci addr_len > sizeof(*sunaddr)) 28262306a36Sopenharmony_ci return -EINVAL; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci if (sunaddr->sun_family != AF_UNIX) 28562306a36Sopenharmony_ci return -EINVAL; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci return 0; 28862306a36Sopenharmony_ci} 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_cistatic int unix_mkname_bsd(struct sockaddr_un *sunaddr, int addr_len) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci struct sockaddr_storage *addr = (struct sockaddr_storage *)sunaddr; 29362306a36Sopenharmony_ci short offset = offsetof(struct sockaddr_storage, __data); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci BUILD_BUG_ON(offset != offsetof(struct sockaddr_un, sun_path)); 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci /* This may look like an off by one error but it is a bit more 29862306a36Sopenharmony_ci * subtle. 108 is the longest valid AF_UNIX path for a binding. 29962306a36Sopenharmony_ci * sun_path[108] doesn't as such exist. However in kernel space 30062306a36Sopenharmony_ci * we are guaranteed that it is a valid memory location in our 30162306a36Sopenharmony_ci * kernel address buffer because syscall functions always pass 30262306a36Sopenharmony_ci * a pointer of struct sockaddr_storage which has a bigger buffer 30362306a36Sopenharmony_ci * than 108. Also, we must terminate sun_path for strlen() in 30462306a36Sopenharmony_ci * getname_kernel(). 30562306a36Sopenharmony_ci */ 30662306a36Sopenharmony_ci addr->__data[addr_len - offset] = 0; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci /* Don't pass sunaddr->sun_path to strlen(). Otherwise, 108 will 30962306a36Sopenharmony_ci * cause panic if CONFIG_FORTIFY_SOURCE=y. Let __fortify_strlen() 31062306a36Sopenharmony_ci * know the actual buffer. 31162306a36Sopenharmony_ci */ 31262306a36Sopenharmony_ci return strlen(addr->__data) + offset + 1; 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_cistatic void __unix_remove_socket(struct sock *sk) 31662306a36Sopenharmony_ci{ 31762306a36Sopenharmony_ci sk_del_node_init(sk); 31862306a36Sopenharmony_ci} 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_cistatic void __unix_insert_socket(struct net *net, struct sock *sk) 32162306a36Sopenharmony_ci{ 32262306a36Sopenharmony_ci DEBUG_NET_WARN_ON_ONCE(!sk_unhashed(sk)); 32362306a36Sopenharmony_ci sk_add_node(sk, &net->unx.table.buckets[sk->sk_hash]); 32462306a36Sopenharmony_ci} 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_cistatic void __unix_set_addr_hash(struct net *net, struct sock *sk, 32762306a36Sopenharmony_ci struct unix_address *addr, unsigned int hash) 32862306a36Sopenharmony_ci{ 32962306a36Sopenharmony_ci __unix_remove_socket(sk); 33062306a36Sopenharmony_ci smp_store_release(&unix_sk(sk)->addr, addr); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci sk->sk_hash = hash; 33362306a36Sopenharmony_ci __unix_insert_socket(net, sk); 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_cistatic void unix_remove_socket(struct net *net, struct sock *sk) 33762306a36Sopenharmony_ci{ 33862306a36Sopenharmony_ci spin_lock(&net->unx.table.locks[sk->sk_hash]); 33962306a36Sopenharmony_ci __unix_remove_socket(sk); 34062306a36Sopenharmony_ci spin_unlock(&net->unx.table.locks[sk->sk_hash]); 34162306a36Sopenharmony_ci} 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_cistatic void unix_insert_unbound_socket(struct net *net, struct sock *sk) 34462306a36Sopenharmony_ci{ 34562306a36Sopenharmony_ci spin_lock(&net->unx.table.locks[sk->sk_hash]); 34662306a36Sopenharmony_ci __unix_insert_socket(net, sk); 34762306a36Sopenharmony_ci spin_unlock(&net->unx.table.locks[sk->sk_hash]); 34862306a36Sopenharmony_ci} 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_cistatic void unix_insert_bsd_socket(struct sock *sk) 35162306a36Sopenharmony_ci{ 35262306a36Sopenharmony_ci spin_lock(&bsd_socket_locks[sk->sk_hash]); 35362306a36Sopenharmony_ci sk_add_bind_node(sk, &bsd_socket_buckets[sk->sk_hash]); 35462306a36Sopenharmony_ci spin_unlock(&bsd_socket_locks[sk->sk_hash]); 35562306a36Sopenharmony_ci} 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_cistatic void unix_remove_bsd_socket(struct sock *sk) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci if (!hlist_unhashed(&sk->sk_bind_node)) { 36062306a36Sopenharmony_ci spin_lock(&bsd_socket_locks[sk->sk_hash]); 36162306a36Sopenharmony_ci __sk_del_bind_node(sk); 36262306a36Sopenharmony_ci spin_unlock(&bsd_socket_locks[sk->sk_hash]); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci sk_node_init(&sk->sk_bind_node); 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci} 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_cistatic struct sock *__unix_find_socket_byname(struct net *net, 36962306a36Sopenharmony_ci struct sockaddr_un *sunname, 37062306a36Sopenharmony_ci int len, unsigned int hash) 37162306a36Sopenharmony_ci{ 37262306a36Sopenharmony_ci struct sock *s; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci sk_for_each(s, &net->unx.table.buckets[hash]) { 37562306a36Sopenharmony_ci struct unix_sock *u = unix_sk(s); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci if (u->addr->len == len && 37862306a36Sopenharmony_ci !memcmp(u->addr->name, sunname, len)) 37962306a36Sopenharmony_ci return s; 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci return NULL; 38262306a36Sopenharmony_ci} 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_cistatic inline struct sock *unix_find_socket_byname(struct net *net, 38562306a36Sopenharmony_ci struct sockaddr_un *sunname, 38662306a36Sopenharmony_ci int len, unsigned int hash) 38762306a36Sopenharmony_ci{ 38862306a36Sopenharmony_ci struct sock *s; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci spin_lock(&net->unx.table.locks[hash]); 39162306a36Sopenharmony_ci s = __unix_find_socket_byname(net, sunname, len, hash); 39262306a36Sopenharmony_ci if (s) 39362306a36Sopenharmony_ci sock_hold(s); 39462306a36Sopenharmony_ci spin_unlock(&net->unx.table.locks[hash]); 39562306a36Sopenharmony_ci return s; 39662306a36Sopenharmony_ci} 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_cistatic struct sock *unix_find_socket_byinode(struct inode *i) 39962306a36Sopenharmony_ci{ 40062306a36Sopenharmony_ci unsigned int hash = unix_bsd_hash(i); 40162306a36Sopenharmony_ci struct sock *s; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci spin_lock(&bsd_socket_locks[hash]); 40462306a36Sopenharmony_ci sk_for_each_bound(s, &bsd_socket_buckets[hash]) { 40562306a36Sopenharmony_ci struct dentry *dentry = unix_sk(s)->path.dentry; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci if (dentry && d_backing_inode(dentry) == i) { 40862306a36Sopenharmony_ci sock_hold(s); 40962306a36Sopenharmony_ci spin_unlock(&bsd_socket_locks[hash]); 41062306a36Sopenharmony_ci return s; 41162306a36Sopenharmony_ci } 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci spin_unlock(&bsd_socket_locks[hash]); 41462306a36Sopenharmony_ci return NULL; 41562306a36Sopenharmony_ci} 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci/* Support code for asymmetrically connected dgram sockets 41862306a36Sopenharmony_ci * 41962306a36Sopenharmony_ci * If a datagram socket is connected to a socket not itself connected 42062306a36Sopenharmony_ci * to the first socket (eg, /dev/log), clients may only enqueue more 42162306a36Sopenharmony_ci * messages if the present receive queue of the server socket is not 42262306a36Sopenharmony_ci * "too large". This means there's a second writeability condition 42362306a36Sopenharmony_ci * poll and sendmsg need to test. The dgram recv code will do a wake 42462306a36Sopenharmony_ci * up on the peer_wait wait queue of a socket upon reception of a 42562306a36Sopenharmony_ci * datagram which needs to be propagated to sleeping would-be writers 42662306a36Sopenharmony_ci * since these might not have sent anything so far. This can't be 42762306a36Sopenharmony_ci * accomplished via poll_wait because the lifetime of the server 42862306a36Sopenharmony_ci * socket might be less than that of its clients if these break their 42962306a36Sopenharmony_ci * association with it or if the server socket is closed while clients 43062306a36Sopenharmony_ci * are still connected to it and there's no way to inform "a polling 43162306a36Sopenharmony_ci * implementation" that it should let go of a certain wait queue 43262306a36Sopenharmony_ci * 43362306a36Sopenharmony_ci * In order to propagate a wake up, a wait_queue_entry_t of the client 43462306a36Sopenharmony_ci * socket is enqueued on the peer_wait queue of the server socket 43562306a36Sopenharmony_ci * whose wake function does a wake_up on the ordinary client socket 43662306a36Sopenharmony_ci * wait queue. This connection is established whenever a write (or 43762306a36Sopenharmony_ci * poll for write) hit the flow control condition and broken when the 43862306a36Sopenharmony_ci * association to the server socket is dissolved or after a wake up 43962306a36Sopenharmony_ci * was relayed. 44062306a36Sopenharmony_ci */ 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_cistatic int unix_dgram_peer_wake_relay(wait_queue_entry_t *q, unsigned mode, int flags, 44362306a36Sopenharmony_ci void *key) 44462306a36Sopenharmony_ci{ 44562306a36Sopenharmony_ci struct unix_sock *u; 44662306a36Sopenharmony_ci wait_queue_head_t *u_sleep; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci u = container_of(q, struct unix_sock, peer_wake); 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci __remove_wait_queue(&unix_sk(u->peer_wake.private)->peer_wait, 45162306a36Sopenharmony_ci q); 45262306a36Sopenharmony_ci u->peer_wake.private = NULL; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci /* relaying can only happen while the wq still exists */ 45562306a36Sopenharmony_ci u_sleep = sk_sleep(&u->sk); 45662306a36Sopenharmony_ci if (u_sleep) 45762306a36Sopenharmony_ci wake_up_interruptible_poll(u_sleep, key_to_poll(key)); 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci return 0; 46062306a36Sopenharmony_ci} 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_cistatic int unix_dgram_peer_wake_connect(struct sock *sk, struct sock *other) 46362306a36Sopenharmony_ci{ 46462306a36Sopenharmony_ci struct unix_sock *u, *u_other; 46562306a36Sopenharmony_ci int rc; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci u = unix_sk(sk); 46862306a36Sopenharmony_ci u_other = unix_sk(other); 46962306a36Sopenharmony_ci rc = 0; 47062306a36Sopenharmony_ci spin_lock(&u_other->peer_wait.lock); 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci if (!u->peer_wake.private) { 47362306a36Sopenharmony_ci u->peer_wake.private = other; 47462306a36Sopenharmony_ci __add_wait_queue(&u_other->peer_wait, &u->peer_wake); 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci rc = 1; 47762306a36Sopenharmony_ci } 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci spin_unlock(&u_other->peer_wait.lock); 48062306a36Sopenharmony_ci return rc; 48162306a36Sopenharmony_ci} 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_cistatic void unix_dgram_peer_wake_disconnect(struct sock *sk, 48462306a36Sopenharmony_ci struct sock *other) 48562306a36Sopenharmony_ci{ 48662306a36Sopenharmony_ci struct unix_sock *u, *u_other; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci u = unix_sk(sk); 48962306a36Sopenharmony_ci u_other = unix_sk(other); 49062306a36Sopenharmony_ci spin_lock(&u_other->peer_wait.lock); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci if (u->peer_wake.private == other) { 49362306a36Sopenharmony_ci __remove_wait_queue(&u_other->peer_wait, &u->peer_wake); 49462306a36Sopenharmony_ci u->peer_wake.private = NULL; 49562306a36Sopenharmony_ci } 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci spin_unlock(&u_other->peer_wait.lock); 49862306a36Sopenharmony_ci} 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_cistatic void unix_dgram_peer_wake_disconnect_wakeup(struct sock *sk, 50162306a36Sopenharmony_ci struct sock *other) 50262306a36Sopenharmony_ci{ 50362306a36Sopenharmony_ci unix_dgram_peer_wake_disconnect(sk, other); 50462306a36Sopenharmony_ci wake_up_interruptible_poll(sk_sleep(sk), 50562306a36Sopenharmony_ci EPOLLOUT | 50662306a36Sopenharmony_ci EPOLLWRNORM | 50762306a36Sopenharmony_ci EPOLLWRBAND); 50862306a36Sopenharmony_ci} 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci/* preconditions: 51162306a36Sopenharmony_ci * - unix_peer(sk) == other 51262306a36Sopenharmony_ci * - association is stable 51362306a36Sopenharmony_ci */ 51462306a36Sopenharmony_cistatic int unix_dgram_peer_wake_me(struct sock *sk, struct sock *other) 51562306a36Sopenharmony_ci{ 51662306a36Sopenharmony_ci int connected; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci connected = unix_dgram_peer_wake_connect(sk, other); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci /* If other is SOCK_DEAD, we want to make sure we signal 52162306a36Sopenharmony_ci * POLLOUT, such that a subsequent write() can get a 52262306a36Sopenharmony_ci * -ECONNREFUSED. Otherwise, if we haven't queued any skbs 52362306a36Sopenharmony_ci * to other and its full, we will hang waiting for POLLOUT. 52462306a36Sopenharmony_ci */ 52562306a36Sopenharmony_ci if (unix_recvq_full_lockless(other) && !sock_flag(other, SOCK_DEAD)) 52662306a36Sopenharmony_ci return 1; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci if (connected) 52962306a36Sopenharmony_ci unix_dgram_peer_wake_disconnect(sk, other); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci return 0; 53262306a36Sopenharmony_ci} 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_cistatic int unix_writable(const struct sock *sk) 53562306a36Sopenharmony_ci{ 53662306a36Sopenharmony_ci return sk->sk_state != TCP_LISTEN && 53762306a36Sopenharmony_ci (refcount_read(&sk->sk_wmem_alloc) << 2) <= sk->sk_sndbuf; 53862306a36Sopenharmony_ci} 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_cistatic void unix_write_space(struct sock *sk) 54162306a36Sopenharmony_ci{ 54262306a36Sopenharmony_ci struct socket_wq *wq; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci rcu_read_lock(); 54562306a36Sopenharmony_ci if (unix_writable(sk)) { 54662306a36Sopenharmony_ci wq = rcu_dereference(sk->sk_wq); 54762306a36Sopenharmony_ci if (skwq_has_sleeper(wq)) 54862306a36Sopenharmony_ci wake_up_interruptible_sync_poll(&wq->wait, 54962306a36Sopenharmony_ci EPOLLOUT | EPOLLWRNORM | EPOLLWRBAND); 55062306a36Sopenharmony_ci sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT); 55162306a36Sopenharmony_ci } 55262306a36Sopenharmony_ci rcu_read_unlock(); 55362306a36Sopenharmony_ci} 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci/* When dgram socket disconnects (or changes its peer), we clear its receive 55662306a36Sopenharmony_ci * queue of packets arrived from previous peer. First, it allows to do 55762306a36Sopenharmony_ci * flow control based only on wmem_alloc; second, sk connected to peer 55862306a36Sopenharmony_ci * may receive messages only from that peer. */ 55962306a36Sopenharmony_cistatic void unix_dgram_disconnected(struct sock *sk, struct sock *other) 56062306a36Sopenharmony_ci{ 56162306a36Sopenharmony_ci if (!skb_queue_empty(&sk->sk_receive_queue)) { 56262306a36Sopenharmony_ci skb_queue_purge(&sk->sk_receive_queue); 56362306a36Sopenharmony_ci wake_up_interruptible_all(&unix_sk(sk)->peer_wait); 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci /* If one link of bidirectional dgram pipe is disconnected, 56662306a36Sopenharmony_ci * we signal error. Messages are lost. Do not make this, 56762306a36Sopenharmony_ci * when peer was not connected to us. 56862306a36Sopenharmony_ci */ 56962306a36Sopenharmony_ci if (!sock_flag(other, SOCK_DEAD) && unix_peer(other) == sk) { 57062306a36Sopenharmony_ci WRITE_ONCE(other->sk_err, ECONNRESET); 57162306a36Sopenharmony_ci sk_error_report(other); 57262306a36Sopenharmony_ci } 57362306a36Sopenharmony_ci } 57462306a36Sopenharmony_ci other->sk_state = TCP_CLOSE; 57562306a36Sopenharmony_ci} 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_cistatic void unix_sock_destructor(struct sock *sk) 57862306a36Sopenharmony_ci{ 57962306a36Sopenharmony_ci struct unix_sock *u = unix_sk(sk); 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci skb_queue_purge(&sk->sk_receive_queue); 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci DEBUG_NET_WARN_ON_ONCE(refcount_read(&sk->sk_wmem_alloc)); 58462306a36Sopenharmony_ci DEBUG_NET_WARN_ON_ONCE(!sk_unhashed(sk)); 58562306a36Sopenharmony_ci DEBUG_NET_WARN_ON_ONCE(sk->sk_socket); 58662306a36Sopenharmony_ci if (!sock_flag(sk, SOCK_DEAD)) { 58762306a36Sopenharmony_ci pr_info("Attempt to release alive unix socket: %p\n", sk); 58862306a36Sopenharmony_ci return; 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci if (u->addr) 59262306a36Sopenharmony_ci unix_release_addr(u->addr); 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci atomic_long_dec(&unix_nr_socks); 59562306a36Sopenharmony_ci sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); 59662306a36Sopenharmony_ci#ifdef UNIX_REFCNT_DEBUG 59762306a36Sopenharmony_ci pr_debug("UNIX %p is destroyed, %ld are still alive.\n", sk, 59862306a36Sopenharmony_ci atomic_long_read(&unix_nr_socks)); 59962306a36Sopenharmony_ci#endif 60062306a36Sopenharmony_ci} 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_cistatic void unix_release_sock(struct sock *sk, int embrion) 60362306a36Sopenharmony_ci{ 60462306a36Sopenharmony_ci struct unix_sock *u = unix_sk(sk); 60562306a36Sopenharmony_ci struct sock *skpair; 60662306a36Sopenharmony_ci struct sk_buff *skb; 60762306a36Sopenharmony_ci struct path path; 60862306a36Sopenharmony_ci int state; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci unix_remove_socket(sock_net(sk), sk); 61162306a36Sopenharmony_ci unix_remove_bsd_socket(sk); 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci /* Clear state */ 61462306a36Sopenharmony_ci unix_state_lock(sk); 61562306a36Sopenharmony_ci sock_orphan(sk); 61662306a36Sopenharmony_ci WRITE_ONCE(sk->sk_shutdown, SHUTDOWN_MASK); 61762306a36Sopenharmony_ci path = u->path; 61862306a36Sopenharmony_ci u->path.dentry = NULL; 61962306a36Sopenharmony_ci u->path.mnt = NULL; 62062306a36Sopenharmony_ci state = sk->sk_state; 62162306a36Sopenharmony_ci sk->sk_state = TCP_CLOSE; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci skpair = unix_peer(sk); 62462306a36Sopenharmony_ci unix_peer(sk) = NULL; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci unix_state_unlock(sk); 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_AF_UNIX_OOB) 62962306a36Sopenharmony_ci if (u->oob_skb) { 63062306a36Sopenharmony_ci kfree_skb(u->oob_skb); 63162306a36Sopenharmony_ci u->oob_skb = NULL; 63262306a36Sopenharmony_ci } 63362306a36Sopenharmony_ci#endif 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci wake_up_interruptible_all(&u->peer_wait); 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci if (skpair != NULL) { 63862306a36Sopenharmony_ci if (sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_SEQPACKET) { 63962306a36Sopenharmony_ci unix_state_lock(skpair); 64062306a36Sopenharmony_ci /* No more writes */ 64162306a36Sopenharmony_ci WRITE_ONCE(skpair->sk_shutdown, SHUTDOWN_MASK); 64262306a36Sopenharmony_ci if (!skb_queue_empty(&sk->sk_receive_queue) || embrion) 64362306a36Sopenharmony_ci WRITE_ONCE(skpair->sk_err, ECONNRESET); 64462306a36Sopenharmony_ci unix_state_unlock(skpair); 64562306a36Sopenharmony_ci skpair->sk_state_change(skpair); 64662306a36Sopenharmony_ci sk_wake_async(skpair, SOCK_WAKE_WAITD, POLL_HUP); 64762306a36Sopenharmony_ci } 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci unix_dgram_peer_wake_disconnect(sk, skpair); 65062306a36Sopenharmony_ci sock_put(skpair); /* It may now die */ 65162306a36Sopenharmony_ci } 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci /* Try to flush out this socket. Throw out buffers at least */ 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { 65662306a36Sopenharmony_ci if (state == TCP_LISTEN) 65762306a36Sopenharmony_ci unix_release_sock(skb->sk, 1); 65862306a36Sopenharmony_ci /* passed fds are erased in the kfree_skb hook */ 65962306a36Sopenharmony_ci UNIXCB(skb).consumed = skb->len; 66062306a36Sopenharmony_ci kfree_skb(skb); 66162306a36Sopenharmony_ci } 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci if (path.dentry) 66462306a36Sopenharmony_ci path_put(&path); 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci sock_put(sk); 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci /* ---- Socket is dead now and most probably destroyed ---- */ 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci /* 67162306a36Sopenharmony_ci * Fixme: BSD difference: In BSD all sockets connected to us get 67262306a36Sopenharmony_ci * ECONNRESET and we die on the spot. In Linux we behave 67362306a36Sopenharmony_ci * like files and pipes do and wait for the last 67462306a36Sopenharmony_ci * dereference. 67562306a36Sopenharmony_ci * 67662306a36Sopenharmony_ci * Can't we simply set sock->err? 67762306a36Sopenharmony_ci * 67862306a36Sopenharmony_ci * What the above comment does talk about? --ANK(980817) 67962306a36Sopenharmony_ci */ 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci if (READ_ONCE(unix_tot_inflight)) 68262306a36Sopenharmony_ci unix_gc(); /* Garbage collect fds */ 68362306a36Sopenharmony_ci} 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_cistatic void init_peercred(struct sock *sk) 68662306a36Sopenharmony_ci{ 68762306a36Sopenharmony_ci const struct cred *old_cred; 68862306a36Sopenharmony_ci struct pid *old_pid; 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci spin_lock(&sk->sk_peer_lock); 69162306a36Sopenharmony_ci old_pid = sk->sk_peer_pid; 69262306a36Sopenharmony_ci old_cred = sk->sk_peer_cred; 69362306a36Sopenharmony_ci sk->sk_peer_pid = get_pid(task_tgid(current)); 69462306a36Sopenharmony_ci sk->sk_peer_cred = get_current_cred(); 69562306a36Sopenharmony_ci spin_unlock(&sk->sk_peer_lock); 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci put_pid(old_pid); 69862306a36Sopenharmony_ci put_cred(old_cred); 69962306a36Sopenharmony_ci} 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_cistatic void copy_peercred(struct sock *sk, struct sock *peersk) 70262306a36Sopenharmony_ci{ 70362306a36Sopenharmony_ci const struct cred *old_cred; 70462306a36Sopenharmony_ci struct pid *old_pid; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci if (sk < peersk) { 70762306a36Sopenharmony_ci spin_lock(&sk->sk_peer_lock); 70862306a36Sopenharmony_ci spin_lock_nested(&peersk->sk_peer_lock, SINGLE_DEPTH_NESTING); 70962306a36Sopenharmony_ci } else { 71062306a36Sopenharmony_ci spin_lock(&peersk->sk_peer_lock); 71162306a36Sopenharmony_ci spin_lock_nested(&sk->sk_peer_lock, SINGLE_DEPTH_NESTING); 71262306a36Sopenharmony_ci } 71362306a36Sopenharmony_ci old_pid = sk->sk_peer_pid; 71462306a36Sopenharmony_ci old_cred = sk->sk_peer_cred; 71562306a36Sopenharmony_ci sk->sk_peer_pid = get_pid(peersk->sk_peer_pid); 71662306a36Sopenharmony_ci sk->sk_peer_cred = get_cred(peersk->sk_peer_cred); 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci spin_unlock(&sk->sk_peer_lock); 71962306a36Sopenharmony_ci spin_unlock(&peersk->sk_peer_lock); 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci put_pid(old_pid); 72262306a36Sopenharmony_ci put_cred(old_cred); 72362306a36Sopenharmony_ci} 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_cistatic int unix_listen(struct socket *sock, int backlog) 72662306a36Sopenharmony_ci{ 72762306a36Sopenharmony_ci int err; 72862306a36Sopenharmony_ci struct sock *sk = sock->sk; 72962306a36Sopenharmony_ci struct unix_sock *u = unix_sk(sk); 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci err = -EOPNOTSUPP; 73262306a36Sopenharmony_ci if (sock->type != SOCK_STREAM && sock->type != SOCK_SEQPACKET) 73362306a36Sopenharmony_ci goto out; /* Only stream/seqpacket sockets accept */ 73462306a36Sopenharmony_ci err = -EINVAL; 73562306a36Sopenharmony_ci if (!u->addr) 73662306a36Sopenharmony_ci goto out; /* No listens on an unbound socket */ 73762306a36Sopenharmony_ci unix_state_lock(sk); 73862306a36Sopenharmony_ci if (sk->sk_state != TCP_CLOSE && sk->sk_state != TCP_LISTEN) 73962306a36Sopenharmony_ci goto out_unlock; 74062306a36Sopenharmony_ci if (backlog > sk->sk_max_ack_backlog) 74162306a36Sopenharmony_ci wake_up_interruptible_all(&u->peer_wait); 74262306a36Sopenharmony_ci sk->sk_max_ack_backlog = backlog; 74362306a36Sopenharmony_ci sk->sk_state = TCP_LISTEN; 74462306a36Sopenharmony_ci /* set credentials so connect can copy them */ 74562306a36Sopenharmony_ci init_peercred(sk); 74662306a36Sopenharmony_ci err = 0; 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ciout_unlock: 74962306a36Sopenharmony_ci unix_state_unlock(sk); 75062306a36Sopenharmony_ciout: 75162306a36Sopenharmony_ci return err; 75262306a36Sopenharmony_ci} 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_cistatic int unix_release(struct socket *); 75562306a36Sopenharmony_cistatic int unix_bind(struct socket *, struct sockaddr *, int); 75662306a36Sopenharmony_cistatic int unix_stream_connect(struct socket *, struct sockaddr *, 75762306a36Sopenharmony_ci int addr_len, int flags); 75862306a36Sopenharmony_cistatic int unix_socketpair(struct socket *, struct socket *); 75962306a36Sopenharmony_cistatic int unix_accept(struct socket *, struct socket *, int, bool); 76062306a36Sopenharmony_cistatic int unix_getname(struct socket *, struct sockaddr *, int); 76162306a36Sopenharmony_cistatic __poll_t unix_poll(struct file *, struct socket *, poll_table *); 76262306a36Sopenharmony_cistatic __poll_t unix_dgram_poll(struct file *, struct socket *, 76362306a36Sopenharmony_ci poll_table *); 76462306a36Sopenharmony_cistatic int unix_ioctl(struct socket *, unsigned int, unsigned long); 76562306a36Sopenharmony_ci#ifdef CONFIG_COMPAT 76662306a36Sopenharmony_cistatic int unix_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg); 76762306a36Sopenharmony_ci#endif 76862306a36Sopenharmony_cistatic int unix_shutdown(struct socket *, int); 76962306a36Sopenharmony_cistatic int unix_stream_sendmsg(struct socket *, struct msghdr *, size_t); 77062306a36Sopenharmony_cistatic int unix_stream_recvmsg(struct socket *, struct msghdr *, size_t, int); 77162306a36Sopenharmony_cistatic ssize_t unix_stream_splice_read(struct socket *, loff_t *ppos, 77262306a36Sopenharmony_ci struct pipe_inode_info *, size_t size, 77362306a36Sopenharmony_ci unsigned int flags); 77462306a36Sopenharmony_cistatic int unix_dgram_sendmsg(struct socket *, struct msghdr *, size_t); 77562306a36Sopenharmony_cistatic int unix_dgram_recvmsg(struct socket *, struct msghdr *, size_t, int); 77662306a36Sopenharmony_cistatic int unix_read_skb(struct sock *sk, skb_read_actor_t recv_actor); 77762306a36Sopenharmony_cistatic int unix_stream_read_skb(struct sock *sk, skb_read_actor_t recv_actor); 77862306a36Sopenharmony_cistatic int unix_dgram_connect(struct socket *, struct sockaddr *, 77962306a36Sopenharmony_ci int, int); 78062306a36Sopenharmony_cistatic int unix_seqpacket_sendmsg(struct socket *, struct msghdr *, size_t); 78162306a36Sopenharmony_cistatic int unix_seqpacket_recvmsg(struct socket *, struct msghdr *, size_t, 78262306a36Sopenharmony_ci int); 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_cistatic int unix_set_peek_off(struct sock *sk, int val) 78562306a36Sopenharmony_ci{ 78662306a36Sopenharmony_ci struct unix_sock *u = unix_sk(sk); 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci if (mutex_lock_interruptible(&u->iolock)) 78962306a36Sopenharmony_ci return -EINTR; 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci WRITE_ONCE(sk->sk_peek_off, val); 79262306a36Sopenharmony_ci mutex_unlock(&u->iolock); 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci return 0; 79562306a36Sopenharmony_ci} 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS 79862306a36Sopenharmony_cistatic int unix_count_nr_fds(struct sock *sk) 79962306a36Sopenharmony_ci{ 80062306a36Sopenharmony_ci struct sk_buff *skb; 80162306a36Sopenharmony_ci struct unix_sock *u; 80262306a36Sopenharmony_ci int nr_fds = 0; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci spin_lock(&sk->sk_receive_queue.lock); 80562306a36Sopenharmony_ci skb = skb_peek(&sk->sk_receive_queue); 80662306a36Sopenharmony_ci while (skb) { 80762306a36Sopenharmony_ci u = unix_sk(skb->sk); 80862306a36Sopenharmony_ci nr_fds += atomic_read(&u->scm_stat.nr_fds); 80962306a36Sopenharmony_ci skb = skb_peek_next(skb, &sk->sk_receive_queue); 81062306a36Sopenharmony_ci } 81162306a36Sopenharmony_ci spin_unlock(&sk->sk_receive_queue.lock); 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci return nr_fds; 81462306a36Sopenharmony_ci} 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_cistatic void unix_show_fdinfo(struct seq_file *m, struct socket *sock) 81762306a36Sopenharmony_ci{ 81862306a36Sopenharmony_ci struct sock *sk = sock->sk; 81962306a36Sopenharmony_ci unsigned char s_state; 82062306a36Sopenharmony_ci struct unix_sock *u; 82162306a36Sopenharmony_ci int nr_fds = 0; 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci if (sk) { 82462306a36Sopenharmony_ci s_state = READ_ONCE(sk->sk_state); 82562306a36Sopenharmony_ci u = unix_sk(sk); 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci /* SOCK_STREAM and SOCK_SEQPACKET sockets never change their 82862306a36Sopenharmony_ci * sk_state after switching to TCP_ESTABLISHED or TCP_LISTEN. 82962306a36Sopenharmony_ci * SOCK_DGRAM is ordinary. So, no lock is needed. 83062306a36Sopenharmony_ci */ 83162306a36Sopenharmony_ci if (sock->type == SOCK_DGRAM || s_state == TCP_ESTABLISHED) 83262306a36Sopenharmony_ci nr_fds = atomic_read(&u->scm_stat.nr_fds); 83362306a36Sopenharmony_ci else if (s_state == TCP_LISTEN) 83462306a36Sopenharmony_ci nr_fds = unix_count_nr_fds(sk); 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci seq_printf(m, "scm_fds: %u\n", nr_fds); 83762306a36Sopenharmony_ci } 83862306a36Sopenharmony_ci} 83962306a36Sopenharmony_ci#else 84062306a36Sopenharmony_ci#define unix_show_fdinfo NULL 84162306a36Sopenharmony_ci#endif 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_cistatic const struct proto_ops unix_stream_ops = { 84462306a36Sopenharmony_ci .family = PF_UNIX, 84562306a36Sopenharmony_ci .owner = THIS_MODULE, 84662306a36Sopenharmony_ci .release = unix_release, 84762306a36Sopenharmony_ci .bind = unix_bind, 84862306a36Sopenharmony_ci .connect = unix_stream_connect, 84962306a36Sopenharmony_ci .socketpair = unix_socketpair, 85062306a36Sopenharmony_ci .accept = unix_accept, 85162306a36Sopenharmony_ci .getname = unix_getname, 85262306a36Sopenharmony_ci .poll = unix_poll, 85362306a36Sopenharmony_ci .ioctl = unix_ioctl, 85462306a36Sopenharmony_ci#ifdef CONFIG_COMPAT 85562306a36Sopenharmony_ci .compat_ioctl = unix_compat_ioctl, 85662306a36Sopenharmony_ci#endif 85762306a36Sopenharmony_ci .listen = unix_listen, 85862306a36Sopenharmony_ci .shutdown = unix_shutdown, 85962306a36Sopenharmony_ci .sendmsg = unix_stream_sendmsg, 86062306a36Sopenharmony_ci .recvmsg = unix_stream_recvmsg, 86162306a36Sopenharmony_ci .read_skb = unix_stream_read_skb, 86262306a36Sopenharmony_ci .mmap = sock_no_mmap, 86362306a36Sopenharmony_ci .splice_read = unix_stream_splice_read, 86462306a36Sopenharmony_ci .set_peek_off = unix_set_peek_off, 86562306a36Sopenharmony_ci .show_fdinfo = unix_show_fdinfo, 86662306a36Sopenharmony_ci}; 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_cistatic const struct proto_ops unix_dgram_ops = { 86962306a36Sopenharmony_ci .family = PF_UNIX, 87062306a36Sopenharmony_ci .owner = THIS_MODULE, 87162306a36Sopenharmony_ci .release = unix_release, 87262306a36Sopenharmony_ci .bind = unix_bind, 87362306a36Sopenharmony_ci .connect = unix_dgram_connect, 87462306a36Sopenharmony_ci .socketpair = unix_socketpair, 87562306a36Sopenharmony_ci .accept = sock_no_accept, 87662306a36Sopenharmony_ci .getname = unix_getname, 87762306a36Sopenharmony_ci .poll = unix_dgram_poll, 87862306a36Sopenharmony_ci .ioctl = unix_ioctl, 87962306a36Sopenharmony_ci#ifdef CONFIG_COMPAT 88062306a36Sopenharmony_ci .compat_ioctl = unix_compat_ioctl, 88162306a36Sopenharmony_ci#endif 88262306a36Sopenharmony_ci .listen = sock_no_listen, 88362306a36Sopenharmony_ci .shutdown = unix_shutdown, 88462306a36Sopenharmony_ci .sendmsg = unix_dgram_sendmsg, 88562306a36Sopenharmony_ci .read_skb = unix_read_skb, 88662306a36Sopenharmony_ci .recvmsg = unix_dgram_recvmsg, 88762306a36Sopenharmony_ci .mmap = sock_no_mmap, 88862306a36Sopenharmony_ci .set_peek_off = unix_set_peek_off, 88962306a36Sopenharmony_ci .show_fdinfo = unix_show_fdinfo, 89062306a36Sopenharmony_ci}; 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_cistatic const struct proto_ops unix_seqpacket_ops = { 89362306a36Sopenharmony_ci .family = PF_UNIX, 89462306a36Sopenharmony_ci .owner = THIS_MODULE, 89562306a36Sopenharmony_ci .release = unix_release, 89662306a36Sopenharmony_ci .bind = unix_bind, 89762306a36Sopenharmony_ci .connect = unix_stream_connect, 89862306a36Sopenharmony_ci .socketpair = unix_socketpair, 89962306a36Sopenharmony_ci .accept = unix_accept, 90062306a36Sopenharmony_ci .getname = unix_getname, 90162306a36Sopenharmony_ci .poll = unix_dgram_poll, 90262306a36Sopenharmony_ci .ioctl = unix_ioctl, 90362306a36Sopenharmony_ci#ifdef CONFIG_COMPAT 90462306a36Sopenharmony_ci .compat_ioctl = unix_compat_ioctl, 90562306a36Sopenharmony_ci#endif 90662306a36Sopenharmony_ci .listen = unix_listen, 90762306a36Sopenharmony_ci .shutdown = unix_shutdown, 90862306a36Sopenharmony_ci .sendmsg = unix_seqpacket_sendmsg, 90962306a36Sopenharmony_ci .recvmsg = unix_seqpacket_recvmsg, 91062306a36Sopenharmony_ci .mmap = sock_no_mmap, 91162306a36Sopenharmony_ci .set_peek_off = unix_set_peek_off, 91262306a36Sopenharmony_ci .show_fdinfo = unix_show_fdinfo, 91362306a36Sopenharmony_ci}; 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_cistatic void unix_close(struct sock *sk, long timeout) 91662306a36Sopenharmony_ci{ 91762306a36Sopenharmony_ci /* Nothing to do here, unix socket does not need a ->close(). 91862306a36Sopenharmony_ci * This is merely for sockmap. 91962306a36Sopenharmony_ci */ 92062306a36Sopenharmony_ci} 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_cistatic void unix_unhash(struct sock *sk) 92362306a36Sopenharmony_ci{ 92462306a36Sopenharmony_ci /* Nothing to do here, unix socket does not need a ->unhash(). 92562306a36Sopenharmony_ci * This is merely for sockmap. 92662306a36Sopenharmony_ci */ 92762306a36Sopenharmony_ci} 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_cistatic bool unix_bpf_bypass_getsockopt(int level, int optname) 93062306a36Sopenharmony_ci{ 93162306a36Sopenharmony_ci if (level == SOL_SOCKET) { 93262306a36Sopenharmony_ci switch (optname) { 93362306a36Sopenharmony_ci case SO_PEERPIDFD: 93462306a36Sopenharmony_ci return true; 93562306a36Sopenharmony_ci default: 93662306a36Sopenharmony_ci return false; 93762306a36Sopenharmony_ci } 93862306a36Sopenharmony_ci } 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci return false; 94162306a36Sopenharmony_ci} 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_cistruct proto unix_dgram_proto = { 94462306a36Sopenharmony_ci .name = "UNIX", 94562306a36Sopenharmony_ci .owner = THIS_MODULE, 94662306a36Sopenharmony_ci .obj_size = sizeof(struct unix_sock), 94762306a36Sopenharmony_ci .close = unix_close, 94862306a36Sopenharmony_ci .bpf_bypass_getsockopt = unix_bpf_bypass_getsockopt, 94962306a36Sopenharmony_ci#ifdef CONFIG_BPF_SYSCALL 95062306a36Sopenharmony_ci .psock_update_sk_prot = unix_dgram_bpf_update_proto, 95162306a36Sopenharmony_ci#endif 95262306a36Sopenharmony_ci}; 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_cistruct proto unix_stream_proto = { 95562306a36Sopenharmony_ci .name = "UNIX-STREAM", 95662306a36Sopenharmony_ci .owner = THIS_MODULE, 95762306a36Sopenharmony_ci .obj_size = sizeof(struct unix_sock), 95862306a36Sopenharmony_ci .close = unix_close, 95962306a36Sopenharmony_ci .unhash = unix_unhash, 96062306a36Sopenharmony_ci .bpf_bypass_getsockopt = unix_bpf_bypass_getsockopt, 96162306a36Sopenharmony_ci#ifdef CONFIG_BPF_SYSCALL 96262306a36Sopenharmony_ci .psock_update_sk_prot = unix_stream_bpf_update_proto, 96362306a36Sopenharmony_ci#endif 96462306a36Sopenharmony_ci}; 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_cistatic struct sock *unix_create1(struct net *net, struct socket *sock, int kern, int type) 96762306a36Sopenharmony_ci{ 96862306a36Sopenharmony_ci struct unix_sock *u; 96962306a36Sopenharmony_ci struct sock *sk; 97062306a36Sopenharmony_ci int err; 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci atomic_long_inc(&unix_nr_socks); 97362306a36Sopenharmony_ci if (atomic_long_read(&unix_nr_socks) > 2 * get_max_files()) { 97462306a36Sopenharmony_ci err = -ENFILE; 97562306a36Sopenharmony_ci goto err; 97662306a36Sopenharmony_ci } 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci if (type == SOCK_STREAM) 97962306a36Sopenharmony_ci sk = sk_alloc(net, PF_UNIX, GFP_KERNEL, &unix_stream_proto, kern); 98062306a36Sopenharmony_ci else /*dgram and seqpacket */ 98162306a36Sopenharmony_ci sk = sk_alloc(net, PF_UNIX, GFP_KERNEL, &unix_dgram_proto, kern); 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci if (!sk) { 98462306a36Sopenharmony_ci err = -ENOMEM; 98562306a36Sopenharmony_ci goto err; 98662306a36Sopenharmony_ci } 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci sock_init_data(sock, sk); 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci sk->sk_hash = unix_unbound_hash(sk); 99162306a36Sopenharmony_ci sk->sk_allocation = GFP_KERNEL_ACCOUNT; 99262306a36Sopenharmony_ci sk->sk_write_space = unix_write_space; 99362306a36Sopenharmony_ci sk->sk_max_ack_backlog = net->unx.sysctl_max_dgram_qlen; 99462306a36Sopenharmony_ci sk->sk_destruct = unix_sock_destructor; 99562306a36Sopenharmony_ci u = unix_sk(sk); 99662306a36Sopenharmony_ci u->path.dentry = NULL; 99762306a36Sopenharmony_ci u->path.mnt = NULL; 99862306a36Sopenharmony_ci spin_lock_init(&u->lock); 99962306a36Sopenharmony_ci atomic_long_set(&u->inflight, 0); 100062306a36Sopenharmony_ci INIT_LIST_HEAD(&u->link); 100162306a36Sopenharmony_ci mutex_init(&u->iolock); /* single task reading lock */ 100262306a36Sopenharmony_ci mutex_init(&u->bindlock); /* single task binding lock */ 100362306a36Sopenharmony_ci init_waitqueue_head(&u->peer_wait); 100462306a36Sopenharmony_ci init_waitqueue_func_entry(&u->peer_wake, unix_dgram_peer_wake_relay); 100562306a36Sopenharmony_ci memset(&u->scm_stat, 0, sizeof(struct scm_stat)); 100662306a36Sopenharmony_ci unix_insert_unbound_socket(net, sk); 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci sock_prot_inuse_add(net, sk->sk_prot, 1); 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci return sk; 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_cierr: 101362306a36Sopenharmony_ci atomic_long_dec(&unix_nr_socks); 101462306a36Sopenharmony_ci return ERR_PTR(err); 101562306a36Sopenharmony_ci} 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_cistatic int unix_create(struct net *net, struct socket *sock, int protocol, 101862306a36Sopenharmony_ci int kern) 101962306a36Sopenharmony_ci{ 102062306a36Sopenharmony_ci struct sock *sk; 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci if (protocol && protocol != PF_UNIX) 102362306a36Sopenharmony_ci return -EPROTONOSUPPORT; 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci sock->state = SS_UNCONNECTED; 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci switch (sock->type) { 102862306a36Sopenharmony_ci case SOCK_STREAM: 102962306a36Sopenharmony_ci sock->ops = &unix_stream_ops; 103062306a36Sopenharmony_ci break; 103162306a36Sopenharmony_ci /* 103262306a36Sopenharmony_ci * Believe it or not BSD has AF_UNIX, SOCK_RAW though 103362306a36Sopenharmony_ci * nothing uses it. 103462306a36Sopenharmony_ci */ 103562306a36Sopenharmony_ci case SOCK_RAW: 103662306a36Sopenharmony_ci sock->type = SOCK_DGRAM; 103762306a36Sopenharmony_ci fallthrough; 103862306a36Sopenharmony_ci case SOCK_DGRAM: 103962306a36Sopenharmony_ci sock->ops = &unix_dgram_ops; 104062306a36Sopenharmony_ci break; 104162306a36Sopenharmony_ci case SOCK_SEQPACKET: 104262306a36Sopenharmony_ci sock->ops = &unix_seqpacket_ops; 104362306a36Sopenharmony_ci break; 104462306a36Sopenharmony_ci default: 104562306a36Sopenharmony_ci return -ESOCKTNOSUPPORT; 104662306a36Sopenharmony_ci } 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci sk = unix_create1(net, sock, kern, sock->type); 104962306a36Sopenharmony_ci if (IS_ERR(sk)) 105062306a36Sopenharmony_ci return PTR_ERR(sk); 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci return 0; 105362306a36Sopenharmony_ci} 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_cistatic int unix_release(struct socket *sock) 105662306a36Sopenharmony_ci{ 105762306a36Sopenharmony_ci struct sock *sk = sock->sk; 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci if (!sk) 106062306a36Sopenharmony_ci return 0; 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci sk->sk_prot->close(sk, 0); 106362306a36Sopenharmony_ci unix_release_sock(sk, 0); 106462306a36Sopenharmony_ci sock->sk = NULL; 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci return 0; 106762306a36Sopenharmony_ci} 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_cistatic struct sock *unix_find_bsd(struct sockaddr_un *sunaddr, int addr_len, 107062306a36Sopenharmony_ci int type) 107162306a36Sopenharmony_ci{ 107262306a36Sopenharmony_ci struct inode *inode; 107362306a36Sopenharmony_ci struct path path; 107462306a36Sopenharmony_ci struct sock *sk; 107562306a36Sopenharmony_ci int err; 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci unix_mkname_bsd(sunaddr, addr_len); 107862306a36Sopenharmony_ci err = kern_path(sunaddr->sun_path, LOOKUP_FOLLOW, &path); 107962306a36Sopenharmony_ci if (err) 108062306a36Sopenharmony_ci goto fail; 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci err = path_permission(&path, MAY_WRITE); 108362306a36Sopenharmony_ci if (err) 108462306a36Sopenharmony_ci goto path_put; 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci err = -ECONNREFUSED; 108762306a36Sopenharmony_ci inode = d_backing_inode(path.dentry); 108862306a36Sopenharmony_ci if (!S_ISSOCK(inode->i_mode)) 108962306a36Sopenharmony_ci goto path_put; 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci sk = unix_find_socket_byinode(inode); 109262306a36Sopenharmony_ci if (!sk) 109362306a36Sopenharmony_ci goto path_put; 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci err = -EPROTOTYPE; 109662306a36Sopenharmony_ci if (sk->sk_type == type) 109762306a36Sopenharmony_ci touch_atime(&path); 109862306a36Sopenharmony_ci else 109962306a36Sopenharmony_ci goto sock_put; 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci path_put(&path); 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci return sk; 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_cisock_put: 110662306a36Sopenharmony_ci sock_put(sk); 110762306a36Sopenharmony_cipath_put: 110862306a36Sopenharmony_ci path_put(&path); 110962306a36Sopenharmony_cifail: 111062306a36Sopenharmony_ci return ERR_PTR(err); 111162306a36Sopenharmony_ci} 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_cistatic struct sock *unix_find_abstract(struct net *net, 111462306a36Sopenharmony_ci struct sockaddr_un *sunaddr, 111562306a36Sopenharmony_ci int addr_len, int type) 111662306a36Sopenharmony_ci{ 111762306a36Sopenharmony_ci unsigned int hash = unix_abstract_hash(sunaddr, addr_len, type); 111862306a36Sopenharmony_ci struct dentry *dentry; 111962306a36Sopenharmony_ci struct sock *sk; 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci sk = unix_find_socket_byname(net, sunaddr, addr_len, hash); 112262306a36Sopenharmony_ci if (!sk) 112362306a36Sopenharmony_ci return ERR_PTR(-ECONNREFUSED); 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci dentry = unix_sk(sk)->path.dentry; 112662306a36Sopenharmony_ci if (dentry) 112762306a36Sopenharmony_ci touch_atime(&unix_sk(sk)->path); 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci return sk; 113062306a36Sopenharmony_ci} 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_cistatic struct sock *unix_find_other(struct net *net, 113362306a36Sopenharmony_ci struct sockaddr_un *sunaddr, 113462306a36Sopenharmony_ci int addr_len, int type) 113562306a36Sopenharmony_ci{ 113662306a36Sopenharmony_ci struct sock *sk; 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci if (sunaddr->sun_path[0]) 113962306a36Sopenharmony_ci sk = unix_find_bsd(sunaddr, addr_len, type); 114062306a36Sopenharmony_ci else 114162306a36Sopenharmony_ci sk = unix_find_abstract(net, sunaddr, addr_len, type); 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci return sk; 114462306a36Sopenharmony_ci} 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_cistatic int unix_autobind(struct sock *sk) 114762306a36Sopenharmony_ci{ 114862306a36Sopenharmony_ci unsigned int new_hash, old_hash = sk->sk_hash; 114962306a36Sopenharmony_ci struct unix_sock *u = unix_sk(sk); 115062306a36Sopenharmony_ci struct net *net = sock_net(sk); 115162306a36Sopenharmony_ci struct unix_address *addr; 115262306a36Sopenharmony_ci u32 lastnum, ordernum; 115362306a36Sopenharmony_ci int err; 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci err = mutex_lock_interruptible(&u->bindlock); 115662306a36Sopenharmony_ci if (err) 115762306a36Sopenharmony_ci return err; 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci if (u->addr) 116062306a36Sopenharmony_ci goto out; 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci err = -ENOMEM; 116362306a36Sopenharmony_ci addr = kzalloc(sizeof(*addr) + 116462306a36Sopenharmony_ci offsetof(struct sockaddr_un, sun_path) + 16, GFP_KERNEL); 116562306a36Sopenharmony_ci if (!addr) 116662306a36Sopenharmony_ci goto out; 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci addr->len = offsetof(struct sockaddr_un, sun_path) + 6; 116962306a36Sopenharmony_ci addr->name->sun_family = AF_UNIX; 117062306a36Sopenharmony_ci refcount_set(&addr->refcnt, 1); 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci ordernum = get_random_u32(); 117362306a36Sopenharmony_ci lastnum = ordernum & 0xFFFFF; 117462306a36Sopenharmony_ciretry: 117562306a36Sopenharmony_ci ordernum = (ordernum + 1) & 0xFFFFF; 117662306a36Sopenharmony_ci sprintf(addr->name->sun_path + 1, "%05x", ordernum); 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci new_hash = unix_abstract_hash(addr->name, addr->len, sk->sk_type); 117962306a36Sopenharmony_ci unix_table_double_lock(net, old_hash, new_hash); 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci if (__unix_find_socket_byname(net, addr->name, addr->len, new_hash)) { 118262306a36Sopenharmony_ci unix_table_double_unlock(net, old_hash, new_hash); 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci /* __unix_find_socket_byname() may take long time if many names 118562306a36Sopenharmony_ci * are already in use. 118662306a36Sopenharmony_ci */ 118762306a36Sopenharmony_ci cond_resched(); 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci if (ordernum == lastnum) { 119062306a36Sopenharmony_ci /* Give up if all names seems to be in use. */ 119162306a36Sopenharmony_ci err = -ENOSPC; 119262306a36Sopenharmony_ci unix_release_addr(addr); 119362306a36Sopenharmony_ci goto out; 119462306a36Sopenharmony_ci } 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci goto retry; 119762306a36Sopenharmony_ci } 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci __unix_set_addr_hash(net, sk, addr, new_hash); 120062306a36Sopenharmony_ci unix_table_double_unlock(net, old_hash, new_hash); 120162306a36Sopenharmony_ci err = 0; 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ciout: mutex_unlock(&u->bindlock); 120462306a36Sopenharmony_ci return err; 120562306a36Sopenharmony_ci} 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_cistatic int unix_bind_bsd(struct sock *sk, struct sockaddr_un *sunaddr, 120862306a36Sopenharmony_ci int addr_len) 120962306a36Sopenharmony_ci{ 121062306a36Sopenharmony_ci umode_t mode = S_IFSOCK | 121162306a36Sopenharmony_ci (SOCK_INODE(sk->sk_socket)->i_mode & ~current_umask()); 121262306a36Sopenharmony_ci unsigned int new_hash, old_hash = sk->sk_hash; 121362306a36Sopenharmony_ci struct unix_sock *u = unix_sk(sk); 121462306a36Sopenharmony_ci struct net *net = sock_net(sk); 121562306a36Sopenharmony_ci struct mnt_idmap *idmap; 121662306a36Sopenharmony_ci struct unix_address *addr; 121762306a36Sopenharmony_ci struct dentry *dentry; 121862306a36Sopenharmony_ci struct path parent; 121962306a36Sopenharmony_ci int err; 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci addr_len = unix_mkname_bsd(sunaddr, addr_len); 122262306a36Sopenharmony_ci addr = unix_create_addr(sunaddr, addr_len); 122362306a36Sopenharmony_ci if (!addr) 122462306a36Sopenharmony_ci return -ENOMEM; 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci /* 122762306a36Sopenharmony_ci * Get the parent directory, calculate the hash for last 122862306a36Sopenharmony_ci * component. 122962306a36Sopenharmony_ci */ 123062306a36Sopenharmony_ci dentry = kern_path_create(AT_FDCWD, addr->name->sun_path, &parent, 0); 123162306a36Sopenharmony_ci if (IS_ERR(dentry)) { 123262306a36Sopenharmony_ci err = PTR_ERR(dentry); 123362306a36Sopenharmony_ci goto out; 123462306a36Sopenharmony_ci } 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_ci /* 123762306a36Sopenharmony_ci * All right, let's create it. 123862306a36Sopenharmony_ci */ 123962306a36Sopenharmony_ci idmap = mnt_idmap(parent.mnt); 124062306a36Sopenharmony_ci err = security_path_mknod(&parent, dentry, mode, 0); 124162306a36Sopenharmony_ci if (!err) 124262306a36Sopenharmony_ci err = vfs_mknod(idmap, d_inode(parent.dentry), dentry, mode, 0); 124362306a36Sopenharmony_ci if (err) 124462306a36Sopenharmony_ci goto out_path; 124562306a36Sopenharmony_ci err = mutex_lock_interruptible(&u->bindlock); 124662306a36Sopenharmony_ci if (err) 124762306a36Sopenharmony_ci goto out_unlink; 124862306a36Sopenharmony_ci if (u->addr) 124962306a36Sopenharmony_ci goto out_unlock; 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_ci new_hash = unix_bsd_hash(d_backing_inode(dentry)); 125262306a36Sopenharmony_ci unix_table_double_lock(net, old_hash, new_hash); 125362306a36Sopenharmony_ci u->path.mnt = mntget(parent.mnt); 125462306a36Sopenharmony_ci u->path.dentry = dget(dentry); 125562306a36Sopenharmony_ci __unix_set_addr_hash(net, sk, addr, new_hash); 125662306a36Sopenharmony_ci unix_table_double_unlock(net, old_hash, new_hash); 125762306a36Sopenharmony_ci unix_insert_bsd_socket(sk); 125862306a36Sopenharmony_ci mutex_unlock(&u->bindlock); 125962306a36Sopenharmony_ci done_path_create(&parent, dentry); 126062306a36Sopenharmony_ci return 0; 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ciout_unlock: 126362306a36Sopenharmony_ci mutex_unlock(&u->bindlock); 126462306a36Sopenharmony_ci err = -EINVAL; 126562306a36Sopenharmony_ciout_unlink: 126662306a36Sopenharmony_ci /* failed after successful mknod? unlink what we'd created... */ 126762306a36Sopenharmony_ci vfs_unlink(idmap, d_inode(parent.dentry), dentry, NULL); 126862306a36Sopenharmony_ciout_path: 126962306a36Sopenharmony_ci done_path_create(&parent, dentry); 127062306a36Sopenharmony_ciout: 127162306a36Sopenharmony_ci unix_release_addr(addr); 127262306a36Sopenharmony_ci return err == -EEXIST ? -EADDRINUSE : err; 127362306a36Sopenharmony_ci} 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_cistatic int unix_bind_abstract(struct sock *sk, struct sockaddr_un *sunaddr, 127662306a36Sopenharmony_ci int addr_len) 127762306a36Sopenharmony_ci{ 127862306a36Sopenharmony_ci unsigned int new_hash, old_hash = sk->sk_hash; 127962306a36Sopenharmony_ci struct unix_sock *u = unix_sk(sk); 128062306a36Sopenharmony_ci struct net *net = sock_net(sk); 128162306a36Sopenharmony_ci struct unix_address *addr; 128262306a36Sopenharmony_ci int err; 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci addr = unix_create_addr(sunaddr, addr_len); 128562306a36Sopenharmony_ci if (!addr) 128662306a36Sopenharmony_ci return -ENOMEM; 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci err = mutex_lock_interruptible(&u->bindlock); 128962306a36Sopenharmony_ci if (err) 129062306a36Sopenharmony_ci goto out; 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci if (u->addr) { 129362306a36Sopenharmony_ci err = -EINVAL; 129462306a36Sopenharmony_ci goto out_mutex; 129562306a36Sopenharmony_ci } 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci new_hash = unix_abstract_hash(addr->name, addr->len, sk->sk_type); 129862306a36Sopenharmony_ci unix_table_double_lock(net, old_hash, new_hash); 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci if (__unix_find_socket_byname(net, addr->name, addr->len, new_hash)) 130162306a36Sopenharmony_ci goto out_spin; 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci __unix_set_addr_hash(net, sk, addr, new_hash); 130462306a36Sopenharmony_ci unix_table_double_unlock(net, old_hash, new_hash); 130562306a36Sopenharmony_ci mutex_unlock(&u->bindlock); 130662306a36Sopenharmony_ci return 0; 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ciout_spin: 130962306a36Sopenharmony_ci unix_table_double_unlock(net, old_hash, new_hash); 131062306a36Sopenharmony_ci err = -EADDRINUSE; 131162306a36Sopenharmony_ciout_mutex: 131262306a36Sopenharmony_ci mutex_unlock(&u->bindlock); 131362306a36Sopenharmony_ciout: 131462306a36Sopenharmony_ci unix_release_addr(addr); 131562306a36Sopenharmony_ci return err; 131662306a36Sopenharmony_ci} 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_cistatic int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) 131962306a36Sopenharmony_ci{ 132062306a36Sopenharmony_ci struct sockaddr_un *sunaddr = (struct sockaddr_un *)uaddr; 132162306a36Sopenharmony_ci struct sock *sk = sock->sk; 132262306a36Sopenharmony_ci int err; 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci if (addr_len == offsetof(struct sockaddr_un, sun_path) && 132562306a36Sopenharmony_ci sunaddr->sun_family == AF_UNIX) 132662306a36Sopenharmony_ci return unix_autobind(sk); 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_ci err = unix_validate_addr(sunaddr, addr_len); 132962306a36Sopenharmony_ci if (err) 133062306a36Sopenharmony_ci return err; 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci if (sunaddr->sun_path[0]) 133362306a36Sopenharmony_ci err = unix_bind_bsd(sk, sunaddr, addr_len); 133462306a36Sopenharmony_ci else 133562306a36Sopenharmony_ci err = unix_bind_abstract(sk, sunaddr, addr_len); 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci return err; 133862306a36Sopenharmony_ci} 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_cistatic void unix_state_double_lock(struct sock *sk1, struct sock *sk2) 134162306a36Sopenharmony_ci{ 134262306a36Sopenharmony_ci if (unlikely(sk1 == sk2) || !sk2) { 134362306a36Sopenharmony_ci unix_state_lock(sk1); 134462306a36Sopenharmony_ci return; 134562306a36Sopenharmony_ci } 134662306a36Sopenharmony_ci if (sk1 > sk2) 134762306a36Sopenharmony_ci swap(sk1, sk2); 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ci unix_state_lock(sk1); 135062306a36Sopenharmony_ci unix_state_lock_nested(sk2, U_LOCK_SECOND); 135162306a36Sopenharmony_ci} 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_cistatic void unix_state_double_unlock(struct sock *sk1, struct sock *sk2) 135462306a36Sopenharmony_ci{ 135562306a36Sopenharmony_ci if (unlikely(sk1 == sk2) || !sk2) { 135662306a36Sopenharmony_ci unix_state_unlock(sk1); 135762306a36Sopenharmony_ci return; 135862306a36Sopenharmony_ci } 135962306a36Sopenharmony_ci unix_state_unlock(sk1); 136062306a36Sopenharmony_ci unix_state_unlock(sk2); 136162306a36Sopenharmony_ci} 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_cistatic int unix_dgram_connect(struct socket *sock, struct sockaddr *addr, 136462306a36Sopenharmony_ci int alen, int flags) 136562306a36Sopenharmony_ci{ 136662306a36Sopenharmony_ci struct sockaddr_un *sunaddr = (struct sockaddr_un *)addr; 136762306a36Sopenharmony_ci struct sock *sk = sock->sk; 136862306a36Sopenharmony_ci struct sock *other; 136962306a36Sopenharmony_ci int err; 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_ci err = -EINVAL; 137262306a36Sopenharmony_ci if (alen < offsetofend(struct sockaddr, sa_family)) 137362306a36Sopenharmony_ci goto out; 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_ci if (addr->sa_family != AF_UNSPEC) { 137662306a36Sopenharmony_ci err = unix_validate_addr(sunaddr, alen); 137762306a36Sopenharmony_ci if (err) 137862306a36Sopenharmony_ci goto out; 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci if ((test_bit(SOCK_PASSCRED, &sock->flags) || 138162306a36Sopenharmony_ci test_bit(SOCK_PASSPIDFD, &sock->flags)) && 138262306a36Sopenharmony_ci !unix_sk(sk)->addr) { 138362306a36Sopenharmony_ci err = unix_autobind(sk); 138462306a36Sopenharmony_ci if (err) 138562306a36Sopenharmony_ci goto out; 138662306a36Sopenharmony_ci } 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_cirestart: 138962306a36Sopenharmony_ci other = unix_find_other(sock_net(sk), sunaddr, alen, sock->type); 139062306a36Sopenharmony_ci if (IS_ERR(other)) { 139162306a36Sopenharmony_ci err = PTR_ERR(other); 139262306a36Sopenharmony_ci goto out; 139362306a36Sopenharmony_ci } 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_ci unix_state_double_lock(sk, other); 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci /* Apparently VFS overslept socket death. Retry. */ 139862306a36Sopenharmony_ci if (sock_flag(other, SOCK_DEAD)) { 139962306a36Sopenharmony_ci unix_state_double_unlock(sk, other); 140062306a36Sopenharmony_ci sock_put(other); 140162306a36Sopenharmony_ci goto restart; 140262306a36Sopenharmony_ci } 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci err = -EPERM; 140562306a36Sopenharmony_ci if (!unix_may_send(sk, other)) 140662306a36Sopenharmony_ci goto out_unlock; 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci err = security_unix_may_send(sk->sk_socket, other->sk_socket); 140962306a36Sopenharmony_ci if (err) 141062306a36Sopenharmony_ci goto out_unlock; 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci sk->sk_state = other->sk_state = TCP_ESTABLISHED; 141362306a36Sopenharmony_ci } else { 141462306a36Sopenharmony_ci /* 141562306a36Sopenharmony_ci * 1003.1g breaking connected state with AF_UNSPEC 141662306a36Sopenharmony_ci */ 141762306a36Sopenharmony_ci other = NULL; 141862306a36Sopenharmony_ci unix_state_double_lock(sk, other); 141962306a36Sopenharmony_ci } 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci /* 142262306a36Sopenharmony_ci * If it was connected, reconnect. 142362306a36Sopenharmony_ci */ 142462306a36Sopenharmony_ci if (unix_peer(sk)) { 142562306a36Sopenharmony_ci struct sock *old_peer = unix_peer(sk); 142662306a36Sopenharmony_ci 142762306a36Sopenharmony_ci unix_peer(sk) = other; 142862306a36Sopenharmony_ci if (!other) 142962306a36Sopenharmony_ci sk->sk_state = TCP_CLOSE; 143062306a36Sopenharmony_ci unix_dgram_peer_wake_disconnect_wakeup(sk, old_peer); 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_ci unix_state_double_unlock(sk, other); 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_ci if (other != old_peer) 143562306a36Sopenharmony_ci unix_dgram_disconnected(sk, old_peer); 143662306a36Sopenharmony_ci sock_put(old_peer); 143762306a36Sopenharmony_ci } else { 143862306a36Sopenharmony_ci unix_peer(sk) = other; 143962306a36Sopenharmony_ci unix_state_double_unlock(sk, other); 144062306a36Sopenharmony_ci } 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci return 0; 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ciout_unlock: 144562306a36Sopenharmony_ci unix_state_double_unlock(sk, other); 144662306a36Sopenharmony_ci sock_put(other); 144762306a36Sopenharmony_ciout: 144862306a36Sopenharmony_ci return err; 144962306a36Sopenharmony_ci} 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_cistatic long unix_wait_for_peer(struct sock *other, long timeo) 145262306a36Sopenharmony_ci __releases(&unix_sk(other)->lock) 145362306a36Sopenharmony_ci{ 145462306a36Sopenharmony_ci struct unix_sock *u = unix_sk(other); 145562306a36Sopenharmony_ci int sched; 145662306a36Sopenharmony_ci DEFINE_WAIT(wait); 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci prepare_to_wait_exclusive(&u->peer_wait, &wait, TASK_INTERRUPTIBLE); 145962306a36Sopenharmony_ci 146062306a36Sopenharmony_ci sched = !sock_flag(other, SOCK_DEAD) && 146162306a36Sopenharmony_ci !(other->sk_shutdown & RCV_SHUTDOWN) && 146262306a36Sopenharmony_ci unix_recvq_full_lockless(other); 146362306a36Sopenharmony_ci 146462306a36Sopenharmony_ci unix_state_unlock(other); 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci if (sched) 146762306a36Sopenharmony_ci timeo = schedule_timeout(timeo); 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_ci finish_wait(&u->peer_wait, &wait); 147062306a36Sopenharmony_ci return timeo; 147162306a36Sopenharmony_ci} 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_cistatic int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr, 147462306a36Sopenharmony_ci int addr_len, int flags) 147562306a36Sopenharmony_ci{ 147662306a36Sopenharmony_ci struct sockaddr_un *sunaddr = (struct sockaddr_un *)uaddr; 147762306a36Sopenharmony_ci struct sock *sk = sock->sk, *newsk = NULL, *other = NULL; 147862306a36Sopenharmony_ci struct unix_sock *u = unix_sk(sk), *newu, *otheru; 147962306a36Sopenharmony_ci struct net *net = sock_net(sk); 148062306a36Sopenharmony_ci struct sk_buff *skb = NULL; 148162306a36Sopenharmony_ci long timeo; 148262306a36Sopenharmony_ci int err; 148362306a36Sopenharmony_ci int st; 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_ci err = unix_validate_addr(sunaddr, addr_len); 148662306a36Sopenharmony_ci if (err) 148762306a36Sopenharmony_ci goto out; 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_ci if ((test_bit(SOCK_PASSCRED, &sock->flags) || 149062306a36Sopenharmony_ci test_bit(SOCK_PASSPIDFD, &sock->flags)) && !u->addr) { 149162306a36Sopenharmony_ci err = unix_autobind(sk); 149262306a36Sopenharmony_ci if (err) 149362306a36Sopenharmony_ci goto out; 149462306a36Sopenharmony_ci } 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_ci timeo = sock_sndtimeo(sk, flags & O_NONBLOCK); 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci /* First of all allocate resources. 149962306a36Sopenharmony_ci If we will make it after state is locked, 150062306a36Sopenharmony_ci we will have to recheck all again in any case. 150162306a36Sopenharmony_ci */ 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci /* create new sock for complete connection */ 150462306a36Sopenharmony_ci newsk = unix_create1(net, NULL, 0, sock->type); 150562306a36Sopenharmony_ci if (IS_ERR(newsk)) { 150662306a36Sopenharmony_ci err = PTR_ERR(newsk); 150762306a36Sopenharmony_ci newsk = NULL; 150862306a36Sopenharmony_ci goto out; 150962306a36Sopenharmony_ci } 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci err = -ENOMEM; 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci /* Allocate skb for sending to listening sock */ 151462306a36Sopenharmony_ci skb = sock_wmalloc(newsk, 1, 0, GFP_KERNEL); 151562306a36Sopenharmony_ci if (skb == NULL) 151662306a36Sopenharmony_ci goto out; 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_cirestart: 151962306a36Sopenharmony_ci /* Find listening sock. */ 152062306a36Sopenharmony_ci other = unix_find_other(net, sunaddr, addr_len, sk->sk_type); 152162306a36Sopenharmony_ci if (IS_ERR(other)) { 152262306a36Sopenharmony_ci err = PTR_ERR(other); 152362306a36Sopenharmony_ci other = NULL; 152462306a36Sopenharmony_ci goto out; 152562306a36Sopenharmony_ci } 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_ci /* Latch state of peer */ 152862306a36Sopenharmony_ci unix_state_lock(other); 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci /* Apparently VFS overslept socket death. Retry. */ 153162306a36Sopenharmony_ci if (sock_flag(other, SOCK_DEAD)) { 153262306a36Sopenharmony_ci unix_state_unlock(other); 153362306a36Sopenharmony_ci sock_put(other); 153462306a36Sopenharmony_ci goto restart; 153562306a36Sopenharmony_ci } 153662306a36Sopenharmony_ci 153762306a36Sopenharmony_ci err = -ECONNREFUSED; 153862306a36Sopenharmony_ci if (other->sk_state != TCP_LISTEN) 153962306a36Sopenharmony_ci goto out_unlock; 154062306a36Sopenharmony_ci if (other->sk_shutdown & RCV_SHUTDOWN) 154162306a36Sopenharmony_ci goto out_unlock; 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_ci if (unix_recvq_full(other)) { 154462306a36Sopenharmony_ci err = -EAGAIN; 154562306a36Sopenharmony_ci if (!timeo) 154662306a36Sopenharmony_ci goto out_unlock; 154762306a36Sopenharmony_ci 154862306a36Sopenharmony_ci timeo = unix_wait_for_peer(other, timeo); 154962306a36Sopenharmony_ci 155062306a36Sopenharmony_ci err = sock_intr_errno(timeo); 155162306a36Sopenharmony_ci if (signal_pending(current)) 155262306a36Sopenharmony_ci goto out; 155362306a36Sopenharmony_ci sock_put(other); 155462306a36Sopenharmony_ci goto restart; 155562306a36Sopenharmony_ci } 155662306a36Sopenharmony_ci 155762306a36Sopenharmony_ci /* Latch our state. 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_ci It is tricky place. We need to grab our state lock and cannot 156062306a36Sopenharmony_ci drop lock on peer. It is dangerous because deadlock is 156162306a36Sopenharmony_ci possible. Connect to self case and simultaneous 156262306a36Sopenharmony_ci attempt to connect are eliminated by checking socket 156362306a36Sopenharmony_ci state. other is TCP_LISTEN, if sk is TCP_LISTEN we 156462306a36Sopenharmony_ci check this before attempt to grab lock. 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_ci Well, and we have to recheck the state after socket locked. 156762306a36Sopenharmony_ci */ 156862306a36Sopenharmony_ci st = sk->sk_state; 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci switch (st) { 157162306a36Sopenharmony_ci case TCP_CLOSE: 157262306a36Sopenharmony_ci /* This is ok... continue with connect */ 157362306a36Sopenharmony_ci break; 157462306a36Sopenharmony_ci case TCP_ESTABLISHED: 157562306a36Sopenharmony_ci /* Socket is already connected */ 157662306a36Sopenharmony_ci err = -EISCONN; 157762306a36Sopenharmony_ci goto out_unlock; 157862306a36Sopenharmony_ci default: 157962306a36Sopenharmony_ci err = -EINVAL; 158062306a36Sopenharmony_ci goto out_unlock; 158162306a36Sopenharmony_ci } 158262306a36Sopenharmony_ci 158362306a36Sopenharmony_ci unix_state_lock_nested(sk, U_LOCK_SECOND); 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_ci if (sk->sk_state != st) { 158662306a36Sopenharmony_ci unix_state_unlock(sk); 158762306a36Sopenharmony_ci unix_state_unlock(other); 158862306a36Sopenharmony_ci sock_put(other); 158962306a36Sopenharmony_ci goto restart; 159062306a36Sopenharmony_ci } 159162306a36Sopenharmony_ci 159262306a36Sopenharmony_ci err = security_unix_stream_connect(sk, other, newsk); 159362306a36Sopenharmony_ci if (err) { 159462306a36Sopenharmony_ci unix_state_unlock(sk); 159562306a36Sopenharmony_ci goto out_unlock; 159662306a36Sopenharmony_ci } 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_ci /* The way is open! Fastly set all the necessary fields... */ 159962306a36Sopenharmony_ci 160062306a36Sopenharmony_ci sock_hold(sk); 160162306a36Sopenharmony_ci unix_peer(newsk) = sk; 160262306a36Sopenharmony_ci newsk->sk_state = TCP_ESTABLISHED; 160362306a36Sopenharmony_ci newsk->sk_type = sk->sk_type; 160462306a36Sopenharmony_ci init_peercred(newsk); 160562306a36Sopenharmony_ci newu = unix_sk(newsk); 160662306a36Sopenharmony_ci RCU_INIT_POINTER(newsk->sk_wq, &newu->peer_wq); 160762306a36Sopenharmony_ci otheru = unix_sk(other); 160862306a36Sopenharmony_ci 160962306a36Sopenharmony_ci /* copy address information from listening to new sock 161062306a36Sopenharmony_ci * 161162306a36Sopenharmony_ci * The contents of *(otheru->addr) and otheru->path 161262306a36Sopenharmony_ci * are seen fully set up here, since we have found 161362306a36Sopenharmony_ci * otheru in hash under its lock. Insertion into the 161462306a36Sopenharmony_ci * hash chain we'd found it in had been done in an 161562306a36Sopenharmony_ci * earlier critical area protected by the chain's lock, 161662306a36Sopenharmony_ci * the same one where we'd set *(otheru->addr) contents, 161762306a36Sopenharmony_ci * as well as otheru->path and otheru->addr itself. 161862306a36Sopenharmony_ci * 161962306a36Sopenharmony_ci * Using smp_store_release() here to set newu->addr 162062306a36Sopenharmony_ci * is enough to make those stores, as well as stores 162162306a36Sopenharmony_ci * to newu->path visible to anyone who gets newu->addr 162262306a36Sopenharmony_ci * by smp_load_acquire(). IOW, the same warranties 162362306a36Sopenharmony_ci * as for unix_sock instances bound in unix_bind() or 162462306a36Sopenharmony_ci * in unix_autobind(). 162562306a36Sopenharmony_ci */ 162662306a36Sopenharmony_ci if (otheru->path.dentry) { 162762306a36Sopenharmony_ci path_get(&otheru->path); 162862306a36Sopenharmony_ci newu->path = otheru->path; 162962306a36Sopenharmony_ci } 163062306a36Sopenharmony_ci refcount_inc(&otheru->addr->refcnt); 163162306a36Sopenharmony_ci smp_store_release(&newu->addr, otheru->addr); 163262306a36Sopenharmony_ci 163362306a36Sopenharmony_ci /* Set credentials */ 163462306a36Sopenharmony_ci copy_peercred(sk, other); 163562306a36Sopenharmony_ci 163662306a36Sopenharmony_ci sock->state = SS_CONNECTED; 163762306a36Sopenharmony_ci sk->sk_state = TCP_ESTABLISHED; 163862306a36Sopenharmony_ci sock_hold(newsk); 163962306a36Sopenharmony_ci 164062306a36Sopenharmony_ci smp_mb__after_atomic(); /* sock_hold() does an atomic_inc() */ 164162306a36Sopenharmony_ci unix_peer(sk) = newsk; 164262306a36Sopenharmony_ci 164362306a36Sopenharmony_ci unix_state_unlock(sk); 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_ci /* take ten and send info to listening sock */ 164662306a36Sopenharmony_ci spin_lock(&other->sk_receive_queue.lock); 164762306a36Sopenharmony_ci __skb_queue_tail(&other->sk_receive_queue, skb); 164862306a36Sopenharmony_ci spin_unlock(&other->sk_receive_queue.lock); 164962306a36Sopenharmony_ci unix_state_unlock(other); 165062306a36Sopenharmony_ci other->sk_data_ready(other); 165162306a36Sopenharmony_ci sock_put(other); 165262306a36Sopenharmony_ci return 0; 165362306a36Sopenharmony_ci 165462306a36Sopenharmony_ciout_unlock: 165562306a36Sopenharmony_ci if (other) 165662306a36Sopenharmony_ci unix_state_unlock(other); 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ciout: 165962306a36Sopenharmony_ci kfree_skb(skb); 166062306a36Sopenharmony_ci if (newsk) 166162306a36Sopenharmony_ci unix_release_sock(newsk, 0); 166262306a36Sopenharmony_ci if (other) 166362306a36Sopenharmony_ci sock_put(other); 166462306a36Sopenharmony_ci return err; 166562306a36Sopenharmony_ci} 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_cistatic int unix_socketpair(struct socket *socka, struct socket *sockb) 166862306a36Sopenharmony_ci{ 166962306a36Sopenharmony_ci struct sock *ska = socka->sk, *skb = sockb->sk; 167062306a36Sopenharmony_ci 167162306a36Sopenharmony_ci /* Join our sockets back to back */ 167262306a36Sopenharmony_ci sock_hold(ska); 167362306a36Sopenharmony_ci sock_hold(skb); 167462306a36Sopenharmony_ci unix_peer(ska) = skb; 167562306a36Sopenharmony_ci unix_peer(skb) = ska; 167662306a36Sopenharmony_ci init_peercred(ska); 167762306a36Sopenharmony_ci init_peercred(skb); 167862306a36Sopenharmony_ci 167962306a36Sopenharmony_ci ska->sk_state = TCP_ESTABLISHED; 168062306a36Sopenharmony_ci skb->sk_state = TCP_ESTABLISHED; 168162306a36Sopenharmony_ci socka->state = SS_CONNECTED; 168262306a36Sopenharmony_ci sockb->state = SS_CONNECTED; 168362306a36Sopenharmony_ci return 0; 168462306a36Sopenharmony_ci} 168562306a36Sopenharmony_ci 168662306a36Sopenharmony_cistatic void unix_sock_inherit_flags(const struct socket *old, 168762306a36Sopenharmony_ci struct socket *new) 168862306a36Sopenharmony_ci{ 168962306a36Sopenharmony_ci if (test_bit(SOCK_PASSCRED, &old->flags)) 169062306a36Sopenharmony_ci set_bit(SOCK_PASSCRED, &new->flags); 169162306a36Sopenharmony_ci if (test_bit(SOCK_PASSPIDFD, &old->flags)) 169262306a36Sopenharmony_ci set_bit(SOCK_PASSPIDFD, &new->flags); 169362306a36Sopenharmony_ci if (test_bit(SOCK_PASSSEC, &old->flags)) 169462306a36Sopenharmony_ci set_bit(SOCK_PASSSEC, &new->flags); 169562306a36Sopenharmony_ci} 169662306a36Sopenharmony_ci 169762306a36Sopenharmony_cistatic int unix_accept(struct socket *sock, struct socket *newsock, int flags, 169862306a36Sopenharmony_ci bool kern) 169962306a36Sopenharmony_ci{ 170062306a36Sopenharmony_ci struct sock *sk = sock->sk; 170162306a36Sopenharmony_ci struct sock *tsk; 170262306a36Sopenharmony_ci struct sk_buff *skb; 170362306a36Sopenharmony_ci int err; 170462306a36Sopenharmony_ci 170562306a36Sopenharmony_ci err = -EOPNOTSUPP; 170662306a36Sopenharmony_ci if (sock->type != SOCK_STREAM && sock->type != SOCK_SEQPACKET) 170762306a36Sopenharmony_ci goto out; 170862306a36Sopenharmony_ci 170962306a36Sopenharmony_ci err = -EINVAL; 171062306a36Sopenharmony_ci if (sk->sk_state != TCP_LISTEN) 171162306a36Sopenharmony_ci goto out; 171262306a36Sopenharmony_ci 171362306a36Sopenharmony_ci /* If socket state is TCP_LISTEN it cannot change (for now...), 171462306a36Sopenharmony_ci * so that no locks are necessary. 171562306a36Sopenharmony_ci */ 171662306a36Sopenharmony_ci 171762306a36Sopenharmony_ci skb = skb_recv_datagram(sk, (flags & O_NONBLOCK) ? MSG_DONTWAIT : 0, 171862306a36Sopenharmony_ci &err); 171962306a36Sopenharmony_ci if (!skb) { 172062306a36Sopenharmony_ci /* This means receive shutdown. */ 172162306a36Sopenharmony_ci if (err == 0) 172262306a36Sopenharmony_ci err = -EINVAL; 172362306a36Sopenharmony_ci goto out; 172462306a36Sopenharmony_ci } 172562306a36Sopenharmony_ci 172662306a36Sopenharmony_ci tsk = skb->sk; 172762306a36Sopenharmony_ci skb_free_datagram(sk, skb); 172862306a36Sopenharmony_ci wake_up_interruptible(&unix_sk(sk)->peer_wait); 172962306a36Sopenharmony_ci 173062306a36Sopenharmony_ci /* attach accepted sock to socket */ 173162306a36Sopenharmony_ci unix_state_lock(tsk); 173262306a36Sopenharmony_ci newsock->state = SS_CONNECTED; 173362306a36Sopenharmony_ci unix_sock_inherit_flags(sock, newsock); 173462306a36Sopenharmony_ci sock_graft(tsk, newsock); 173562306a36Sopenharmony_ci unix_state_unlock(tsk); 173662306a36Sopenharmony_ci return 0; 173762306a36Sopenharmony_ci 173862306a36Sopenharmony_ciout: 173962306a36Sopenharmony_ci return err; 174062306a36Sopenharmony_ci} 174162306a36Sopenharmony_ci 174262306a36Sopenharmony_ci 174362306a36Sopenharmony_cistatic int unix_getname(struct socket *sock, struct sockaddr *uaddr, int peer) 174462306a36Sopenharmony_ci{ 174562306a36Sopenharmony_ci struct sock *sk = sock->sk; 174662306a36Sopenharmony_ci struct unix_address *addr; 174762306a36Sopenharmony_ci DECLARE_SOCKADDR(struct sockaddr_un *, sunaddr, uaddr); 174862306a36Sopenharmony_ci int err = 0; 174962306a36Sopenharmony_ci 175062306a36Sopenharmony_ci if (peer) { 175162306a36Sopenharmony_ci sk = unix_peer_get(sk); 175262306a36Sopenharmony_ci 175362306a36Sopenharmony_ci err = -ENOTCONN; 175462306a36Sopenharmony_ci if (!sk) 175562306a36Sopenharmony_ci goto out; 175662306a36Sopenharmony_ci err = 0; 175762306a36Sopenharmony_ci } else { 175862306a36Sopenharmony_ci sock_hold(sk); 175962306a36Sopenharmony_ci } 176062306a36Sopenharmony_ci 176162306a36Sopenharmony_ci addr = smp_load_acquire(&unix_sk(sk)->addr); 176262306a36Sopenharmony_ci if (!addr) { 176362306a36Sopenharmony_ci sunaddr->sun_family = AF_UNIX; 176462306a36Sopenharmony_ci sunaddr->sun_path[0] = 0; 176562306a36Sopenharmony_ci err = offsetof(struct sockaddr_un, sun_path); 176662306a36Sopenharmony_ci } else { 176762306a36Sopenharmony_ci err = addr->len; 176862306a36Sopenharmony_ci memcpy(sunaddr, addr->name, addr->len); 176962306a36Sopenharmony_ci } 177062306a36Sopenharmony_ci sock_put(sk); 177162306a36Sopenharmony_ciout: 177262306a36Sopenharmony_ci return err; 177362306a36Sopenharmony_ci} 177462306a36Sopenharmony_ci 177562306a36Sopenharmony_cistatic void unix_peek_fds(struct scm_cookie *scm, struct sk_buff *skb) 177662306a36Sopenharmony_ci{ 177762306a36Sopenharmony_ci scm->fp = scm_fp_dup(UNIXCB(skb).fp); 177862306a36Sopenharmony_ci 177962306a36Sopenharmony_ci /* 178062306a36Sopenharmony_ci * Garbage collection of unix sockets starts by selecting a set of 178162306a36Sopenharmony_ci * candidate sockets which have reference only from being in flight 178262306a36Sopenharmony_ci * (total_refs == inflight_refs). This condition is checked once during 178362306a36Sopenharmony_ci * the candidate collection phase, and candidates are marked as such, so 178462306a36Sopenharmony_ci * that non-candidates can later be ignored. While inflight_refs is 178562306a36Sopenharmony_ci * protected by unix_gc_lock, total_refs (file count) is not, hence this 178662306a36Sopenharmony_ci * is an instantaneous decision. 178762306a36Sopenharmony_ci * 178862306a36Sopenharmony_ci * Once a candidate, however, the socket must not be reinstalled into a 178962306a36Sopenharmony_ci * file descriptor while the garbage collection is in progress. 179062306a36Sopenharmony_ci * 179162306a36Sopenharmony_ci * If the above conditions are met, then the directed graph of 179262306a36Sopenharmony_ci * candidates (*) does not change while unix_gc_lock is held. 179362306a36Sopenharmony_ci * 179462306a36Sopenharmony_ci * Any operations that changes the file count through file descriptors 179562306a36Sopenharmony_ci * (dup, close, sendmsg) does not change the graph since candidates are 179662306a36Sopenharmony_ci * not installed in fds. 179762306a36Sopenharmony_ci * 179862306a36Sopenharmony_ci * Dequeing a candidate via recvmsg would install it into an fd, but 179962306a36Sopenharmony_ci * that takes unix_gc_lock to decrement the inflight count, so it's 180062306a36Sopenharmony_ci * serialized with garbage collection. 180162306a36Sopenharmony_ci * 180262306a36Sopenharmony_ci * MSG_PEEK is special in that it does not change the inflight count, 180362306a36Sopenharmony_ci * yet does install the socket into an fd. The following lock/unlock 180462306a36Sopenharmony_ci * pair is to ensure serialization with garbage collection. It must be 180562306a36Sopenharmony_ci * done between incrementing the file count and installing the file into 180662306a36Sopenharmony_ci * an fd. 180762306a36Sopenharmony_ci * 180862306a36Sopenharmony_ci * If garbage collection starts after the barrier provided by the 180962306a36Sopenharmony_ci * lock/unlock, then it will see the elevated refcount and not mark this 181062306a36Sopenharmony_ci * as a candidate. If a garbage collection is already in progress 181162306a36Sopenharmony_ci * before the file count was incremented, then the lock/unlock pair will 181262306a36Sopenharmony_ci * ensure that garbage collection is finished before progressing to 181362306a36Sopenharmony_ci * installing the fd. 181462306a36Sopenharmony_ci * 181562306a36Sopenharmony_ci * (*) A -> B where B is on the queue of A or B is on the queue of C 181662306a36Sopenharmony_ci * which is on the queue of listening socket A. 181762306a36Sopenharmony_ci */ 181862306a36Sopenharmony_ci spin_lock(&unix_gc_lock); 181962306a36Sopenharmony_ci spin_unlock(&unix_gc_lock); 182062306a36Sopenharmony_ci} 182162306a36Sopenharmony_ci 182262306a36Sopenharmony_cistatic int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool send_fds) 182362306a36Sopenharmony_ci{ 182462306a36Sopenharmony_ci int err = 0; 182562306a36Sopenharmony_ci 182662306a36Sopenharmony_ci UNIXCB(skb).pid = get_pid(scm->pid); 182762306a36Sopenharmony_ci UNIXCB(skb).uid = scm->creds.uid; 182862306a36Sopenharmony_ci UNIXCB(skb).gid = scm->creds.gid; 182962306a36Sopenharmony_ci UNIXCB(skb).fp = NULL; 183062306a36Sopenharmony_ci unix_get_secdata(scm, skb); 183162306a36Sopenharmony_ci if (scm->fp && send_fds) 183262306a36Sopenharmony_ci err = unix_attach_fds(scm, skb); 183362306a36Sopenharmony_ci 183462306a36Sopenharmony_ci skb->destructor = unix_destruct_scm; 183562306a36Sopenharmony_ci return err; 183662306a36Sopenharmony_ci} 183762306a36Sopenharmony_ci 183862306a36Sopenharmony_cistatic bool unix_passcred_enabled(const struct socket *sock, 183962306a36Sopenharmony_ci const struct sock *other) 184062306a36Sopenharmony_ci{ 184162306a36Sopenharmony_ci return test_bit(SOCK_PASSCRED, &sock->flags) || 184262306a36Sopenharmony_ci test_bit(SOCK_PASSPIDFD, &sock->flags) || 184362306a36Sopenharmony_ci !other->sk_socket || 184462306a36Sopenharmony_ci test_bit(SOCK_PASSCRED, &other->sk_socket->flags) || 184562306a36Sopenharmony_ci test_bit(SOCK_PASSPIDFD, &other->sk_socket->flags); 184662306a36Sopenharmony_ci} 184762306a36Sopenharmony_ci 184862306a36Sopenharmony_ci/* 184962306a36Sopenharmony_ci * Some apps rely on write() giving SCM_CREDENTIALS 185062306a36Sopenharmony_ci * We include credentials if source or destination socket 185162306a36Sopenharmony_ci * asserted SOCK_PASSCRED. 185262306a36Sopenharmony_ci */ 185362306a36Sopenharmony_cistatic void maybe_add_creds(struct sk_buff *skb, const struct socket *sock, 185462306a36Sopenharmony_ci const struct sock *other) 185562306a36Sopenharmony_ci{ 185662306a36Sopenharmony_ci if (UNIXCB(skb).pid) 185762306a36Sopenharmony_ci return; 185862306a36Sopenharmony_ci if (unix_passcred_enabled(sock, other)) { 185962306a36Sopenharmony_ci UNIXCB(skb).pid = get_pid(task_tgid(current)); 186062306a36Sopenharmony_ci current_uid_gid(&UNIXCB(skb).uid, &UNIXCB(skb).gid); 186162306a36Sopenharmony_ci } 186262306a36Sopenharmony_ci} 186362306a36Sopenharmony_ci 186462306a36Sopenharmony_cistatic bool unix_skb_scm_eq(struct sk_buff *skb, 186562306a36Sopenharmony_ci struct scm_cookie *scm) 186662306a36Sopenharmony_ci{ 186762306a36Sopenharmony_ci return UNIXCB(skb).pid == scm->pid && 186862306a36Sopenharmony_ci uid_eq(UNIXCB(skb).uid, scm->creds.uid) && 186962306a36Sopenharmony_ci gid_eq(UNIXCB(skb).gid, scm->creds.gid) && 187062306a36Sopenharmony_ci unix_secdata_eq(scm, skb); 187162306a36Sopenharmony_ci} 187262306a36Sopenharmony_ci 187362306a36Sopenharmony_cistatic void scm_stat_add(struct sock *sk, struct sk_buff *skb) 187462306a36Sopenharmony_ci{ 187562306a36Sopenharmony_ci struct scm_fp_list *fp = UNIXCB(skb).fp; 187662306a36Sopenharmony_ci struct unix_sock *u = unix_sk(sk); 187762306a36Sopenharmony_ci 187862306a36Sopenharmony_ci if (unlikely(fp && fp->count)) 187962306a36Sopenharmony_ci atomic_add(fp->count, &u->scm_stat.nr_fds); 188062306a36Sopenharmony_ci} 188162306a36Sopenharmony_ci 188262306a36Sopenharmony_cistatic void scm_stat_del(struct sock *sk, struct sk_buff *skb) 188362306a36Sopenharmony_ci{ 188462306a36Sopenharmony_ci struct scm_fp_list *fp = UNIXCB(skb).fp; 188562306a36Sopenharmony_ci struct unix_sock *u = unix_sk(sk); 188662306a36Sopenharmony_ci 188762306a36Sopenharmony_ci if (unlikely(fp && fp->count)) 188862306a36Sopenharmony_ci atomic_sub(fp->count, &u->scm_stat.nr_fds); 188962306a36Sopenharmony_ci} 189062306a36Sopenharmony_ci 189162306a36Sopenharmony_ci/* 189262306a36Sopenharmony_ci * Send AF_UNIX data. 189362306a36Sopenharmony_ci */ 189462306a36Sopenharmony_ci 189562306a36Sopenharmony_cistatic int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg, 189662306a36Sopenharmony_ci size_t len) 189762306a36Sopenharmony_ci{ 189862306a36Sopenharmony_ci DECLARE_SOCKADDR(struct sockaddr_un *, sunaddr, msg->msg_name); 189962306a36Sopenharmony_ci struct sock *sk = sock->sk, *other = NULL; 190062306a36Sopenharmony_ci struct unix_sock *u = unix_sk(sk); 190162306a36Sopenharmony_ci struct scm_cookie scm; 190262306a36Sopenharmony_ci struct sk_buff *skb; 190362306a36Sopenharmony_ci int data_len = 0; 190462306a36Sopenharmony_ci int sk_locked; 190562306a36Sopenharmony_ci long timeo; 190662306a36Sopenharmony_ci int err; 190762306a36Sopenharmony_ci 190862306a36Sopenharmony_ci wait_for_unix_gc(); 190962306a36Sopenharmony_ci err = scm_send(sock, msg, &scm, false); 191062306a36Sopenharmony_ci if (err < 0) 191162306a36Sopenharmony_ci return err; 191262306a36Sopenharmony_ci 191362306a36Sopenharmony_ci err = -EOPNOTSUPP; 191462306a36Sopenharmony_ci if (msg->msg_flags&MSG_OOB) 191562306a36Sopenharmony_ci goto out; 191662306a36Sopenharmony_ci 191762306a36Sopenharmony_ci if (msg->msg_namelen) { 191862306a36Sopenharmony_ci err = unix_validate_addr(sunaddr, msg->msg_namelen); 191962306a36Sopenharmony_ci if (err) 192062306a36Sopenharmony_ci goto out; 192162306a36Sopenharmony_ci } else { 192262306a36Sopenharmony_ci sunaddr = NULL; 192362306a36Sopenharmony_ci err = -ENOTCONN; 192462306a36Sopenharmony_ci other = unix_peer_get(sk); 192562306a36Sopenharmony_ci if (!other) 192662306a36Sopenharmony_ci goto out; 192762306a36Sopenharmony_ci } 192862306a36Sopenharmony_ci 192962306a36Sopenharmony_ci if ((test_bit(SOCK_PASSCRED, &sock->flags) || 193062306a36Sopenharmony_ci test_bit(SOCK_PASSPIDFD, &sock->flags)) && !u->addr) { 193162306a36Sopenharmony_ci err = unix_autobind(sk); 193262306a36Sopenharmony_ci if (err) 193362306a36Sopenharmony_ci goto out; 193462306a36Sopenharmony_ci } 193562306a36Sopenharmony_ci 193662306a36Sopenharmony_ci err = -EMSGSIZE; 193762306a36Sopenharmony_ci if (len > sk->sk_sndbuf - 32) 193862306a36Sopenharmony_ci goto out; 193962306a36Sopenharmony_ci 194062306a36Sopenharmony_ci if (len > SKB_MAX_ALLOC) { 194162306a36Sopenharmony_ci data_len = min_t(size_t, 194262306a36Sopenharmony_ci len - SKB_MAX_ALLOC, 194362306a36Sopenharmony_ci MAX_SKB_FRAGS * PAGE_SIZE); 194462306a36Sopenharmony_ci data_len = PAGE_ALIGN(data_len); 194562306a36Sopenharmony_ci 194662306a36Sopenharmony_ci BUILD_BUG_ON(SKB_MAX_ALLOC < PAGE_SIZE); 194762306a36Sopenharmony_ci } 194862306a36Sopenharmony_ci 194962306a36Sopenharmony_ci skb = sock_alloc_send_pskb(sk, len - data_len, data_len, 195062306a36Sopenharmony_ci msg->msg_flags & MSG_DONTWAIT, &err, 195162306a36Sopenharmony_ci PAGE_ALLOC_COSTLY_ORDER); 195262306a36Sopenharmony_ci if (skb == NULL) 195362306a36Sopenharmony_ci goto out; 195462306a36Sopenharmony_ci 195562306a36Sopenharmony_ci err = unix_scm_to_skb(&scm, skb, true); 195662306a36Sopenharmony_ci if (err < 0) 195762306a36Sopenharmony_ci goto out_free; 195862306a36Sopenharmony_ci 195962306a36Sopenharmony_ci skb_put(skb, len - data_len); 196062306a36Sopenharmony_ci skb->data_len = data_len; 196162306a36Sopenharmony_ci skb->len = len; 196262306a36Sopenharmony_ci err = skb_copy_datagram_from_iter(skb, 0, &msg->msg_iter, len); 196362306a36Sopenharmony_ci if (err) 196462306a36Sopenharmony_ci goto out_free; 196562306a36Sopenharmony_ci 196662306a36Sopenharmony_ci timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); 196762306a36Sopenharmony_ci 196862306a36Sopenharmony_cirestart: 196962306a36Sopenharmony_ci if (!other) { 197062306a36Sopenharmony_ci err = -ECONNRESET; 197162306a36Sopenharmony_ci if (sunaddr == NULL) 197262306a36Sopenharmony_ci goto out_free; 197362306a36Sopenharmony_ci 197462306a36Sopenharmony_ci other = unix_find_other(sock_net(sk), sunaddr, msg->msg_namelen, 197562306a36Sopenharmony_ci sk->sk_type); 197662306a36Sopenharmony_ci if (IS_ERR(other)) { 197762306a36Sopenharmony_ci err = PTR_ERR(other); 197862306a36Sopenharmony_ci other = NULL; 197962306a36Sopenharmony_ci goto out_free; 198062306a36Sopenharmony_ci } 198162306a36Sopenharmony_ci } 198262306a36Sopenharmony_ci 198362306a36Sopenharmony_ci if (sk_filter(other, skb) < 0) { 198462306a36Sopenharmony_ci /* Toss the packet but do not return any error to the sender */ 198562306a36Sopenharmony_ci err = len; 198662306a36Sopenharmony_ci goto out_free; 198762306a36Sopenharmony_ci } 198862306a36Sopenharmony_ci 198962306a36Sopenharmony_ci sk_locked = 0; 199062306a36Sopenharmony_ci unix_state_lock(other); 199162306a36Sopenharmony_cirestart_locked: 199262306a36Sopenharmony_ci err = -EPERM; 199362306a36Sopenharmony_ci if (!unix_may_send(sk, other)) 199462306a36Sopenharmony_ci goto out_unlock; 199562306a36Sopenharmony_ci 199662306a36Sopenharmony_ci if (unlikely(sock_flag(other, SOCK_DEAD))) { 199762306a36Sopenharmony_ci /* 199862306a36Sopenharmony_ci * Check with 1003.1g - what should 199962306a36Sopenharmony_ci * datagram error 200062306a36Sopenharmony_ci */ 200162306a36Sopenharmony_ci unix_state_unlock(other); 200262306a36Sopenharmony_ci sock_put(other); 200362306a36Sopenharmony_ci 200462306a36Sopenharmony_ci if (!sk_locked) 200562306a36Sopenharmony_ci unix_state_lock(sk); 200662306a36Sopenharmony_ci 200762306a36Sopenharmony_ci err = 0; 200862306a36Sopenharmony_ci if (sk->sk_type == SOCK_SEQPACKET) { 200962306a36Sopenharmony_ci /* We are here only when racing with unix_release_sock() 201062306a36Sopenharmony_ci * is clearing @other. Never change state to TCP_CLOSE 201162306a36Sopenharmony_ci * unlike SOCK_DGRAM wants. 201262306a36Sopenharmony_ci */ 201362306a36Sopenharmony_ci unix_state_unlock(sk); 201462306a36Sopenharmony_ci err = -EPIPE; 201562306a36Sopenharmony_ci } else if (unix_peer(sk) == other) { 201662306a36Sopenharmony_ci unix_peer(sk) = NULL; 201762306a36Sopenharmony_ci unix_dgram_peer_wake_disconnect_wakeup(sk, other); 201862306a36Sopenharmony_ci 201962306a36Sopenharmony_ci sk->sk_state = TCP_CLOSE; 202062306a36Sopenharmony_ci unix_state_unlock(sk); 202162306a36Sopenharmony_ci 202262306a36Sopenharmony_ci unix_dgram_disconnected(sk, other); 202362306a36Sopenharmony_ci sock_put(other); 202462306a36Sopenharmony_ci err = -ECONNREFUSED; 202562306a36Sopenharmony_ci } else { 202662306a36Sopenharmony_ci unix_state_unlock(sk); 202762306a36Sopenharmony_ci } 202862306a36Sopenharmony_ci 202962306a36Sopenharmony_ci other = NULL; 203062306a36Sopenharmony_ci if (err) 203162306a36Sopenharmony_ci goto out_free; 203262306a36Sopenharmony_ci goto restart; 203362306a36Sopenharmony_ci } 203462306a36Sopenharmony_ci 203562306a36Sopenharmony_ci err = -EPIPE; 203662306a36Sopenharmony_ci if (other->sk_shutdown & RCV_SHUTDOWN) 203762306a36Sopenharmony_ci goto out_unlock; 203862306a36Sopenharmony_ci 203962306a36Sopenharmony_ci if (sk->sk_type != SOCK_SEQPACKET) { 204062306a36Sopenharmony_ci err = security_unix_may_send(sk->sk_socket, other->sk_socket); 204162306a36Sopenharmony_ci if (err) 204262306a36Sopenharmony_ci goto out_unlock; 204362306a36Sopenharmony_ci } 204462306a36Sopenharmony_ci 204562306a36Sopenharmony_ci /* other == sk && unix_peer(other) != sk if 204662306a36Sopenharmony_ci * - unix_peer(sk) == NULL, destination address bound to sk 204762306a36Sopenharmony_ci * - unix_peer(sk) == sk by time of get but disconnected before lock 204862306a36Sopenharmony_ci */ 204962306a36Sopenharmony_ci if (other != sk && 205062306a36Sopenharmony_ci unlikely(unix_peer(other) != sk && 205162306a36Sopenharmony_ci unix_recvq_full_lockless(other))) { 205262306a36Sopenharmony_ci if (timeo) { 205362306a36Sopenharmony_ci timeo = unix_wait_for_peer(other, timeo); 205462306a36Sopenharmony_ci 205562306a36Sopenharmony_ci err = sock_intr_errno(timeo); 205662306a36Sopenharmony_ci if (signal_pending(current)) 205762306a36Sopenharmony_ci goto out_free; 205862306a36Sopenharmony_ci 205962306a36Sopenharmony_ci goto restart; 206062306a36Sopenharmony_ci } 206162306a36Sopenharmony_ci 206262306a36Sopenharmony_ci if (!sk_locked) { 206362306a36Sopenharmony_ci unix_state_unlock(other); 206462306a36Sopenharmony_ci unix_state_double_lock(sk, other); 206562306a36Sopenharmony_ci } 206662306a36Sopenharmony_ci 206762306a36Sopenharmony_ci if (unix_peer(sk) != other || 206862306a36Sopenharmony_ci unix_dgram_peer_wake_me(sk, other)) { 206962306a36Sopenharmony_ci err = -EAGAIN; 207062306a36Sopenharmony_ci sk_locked = 1; 207162306a36Sopenharmony_ci goto out_unlock; 207262306a36Sopenharmony_ci } 207362306a36Sopenharmony_ci 207462306a36Sopenharmony_ci if (!sk_locked) { 207562306a36Sopenharmony_ci sk_locked = 1; 207662306a36Sopenharmony_ci goto restart_locked; 207762306a36Sopenharmony_ci } 207862306a36Sopenharmony_ci } 207962306a36Sopenharmony_ci 208062306a36Sopenharmony_ci if (unlikely(sk_locked)) 208162306a36Sopenharmony_ci unix_state_unlock(sk); 208262306a36Sopenharmony_ci 208362306a36Sopenharmony_ci if (sock_flag(other, SOCK_RCVTSTAMP)) 208462306a36Sopenharmony_ci __net_timestamp(skb); 208562306a36Sopenharmony_ci maybe_add_creds(skb, sock, other); 208662306a36Sopenharmony_ci scm_stat_add(other, skb); 208762306a36Sopenharmony_ci skb_queue_tail(&other->sk_receive_queue, skb); 208862306a36Sopenharmony_ci unix_state_unlock(other); 208962306a36Sopenharmony_ci other->sk_data_ready(other); 209062306a36Sopenharmony_ci sock_put(other); 209162306a36Sopenharmony_ci scm_destroy(&scm); 209262306a36Sopenharmony_ci return len; 209362306a36Sopenharmony_ci 209462306a36Sopenharmony_ciout_unlock: 209562306a36Sopenharmony_ci if (sk_locked) 209662306a36Sopenharmony_ci unix_state_unlock(sk); 209762306a36Sopenharmony_ci unix_state_unlock(other); 209862306a36Sopenharmony_ciout_free: 209962306a36Sopenharmony_ci kfree_skb(skb); 210062306a36Sopenharmony_ciout: 210162306a36Sopenharmony_ci if (other) 210262306a36Sopenharmony_ci sock_put(other); 210362306a36Sopenharmony_ci scm_destroy(&scm); 210462306a36Sopenharmony_ci return err; 210562306a36Sopenharmony_ci} 210662306a36Sopenharmony_ci 210762306a36Sopenharmony_ci/* We use paged skbs for stream sockets, and limit occupancy to 32768 210862306a36Sopenharmony_ci * bytes, and a minimum of a full page. 210962306a36Sopenharmony_ci */ 211062306a36Sopenharmony_ci#define UNIX_SKB_FRAGS_SZ (PAGE_SIZE << get_order(32768)) 211162306a36Sopenharmony_ci 211262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_AF_UNIX_OOB) 211362306a36Sopenharmony_cistatic int queue_oob(struct socket *sock, struct msghdr *msg, struct sock *other, 211462306a36Sopenharmony_ci struct scm_cookie *scm, bool fds_sent) 211562306a36Sopenharmony_ci{ 211662306a36Sopenharmony_ci struct unix_sock *ousk = unix_sk(other); 211762306a36Sopenharmony_ci struct sk_buff *skb; 211862306a36Sopenharmony_ci int err = 0; 211962306a36Sopenharmony_ci 212062306a36Sopenharmony_ci skb = sock_alloc_send_skb(sock->sk, 1, msg->msg_flags & MSG_DONTWAIT, &err); 212162306a36Sopenharmony_ci 212262306a36Sopenharmony_ci if (!skb) 212362306a36Sopenharmony_ci return err; 212462306a36Sopenharmony_ci 212562306a36Sopenharmony_ci err = unix_scm_to_skb(scm, skb, !fds_sent); 212662306a36Sopenharmony_ci if (err < 0) { 212762306a36Sopenharmony_ci kfree_skb(skb); 212862306a36Sopenharmony_ci return err; 212962306a36Sopenharmony_ci } 213062306a36Sopenharmony_ci skb_put(skb, 1); 213162306a36Sopenharmony_ci err = skb_copy_datagram_from_iter(skb, 0, &msg->msg_iter, 1); 213262306a36Sopenharmony_ci 213362306a36Sopenharmony_ci if (err) { 213462306a36Sopenharmony_ci kfree_skb(skb); 213562306a36Sopenharmony_ci return err; 213662306a36Sopenharmony_ci } 213762306a36Sopenharmony_ci 213862306a36Sopenharmony_ci unix_state_lock(other); 213962306a36Sopenharmony_ci 214062306a36Sopenharmony_ci if (sock_flag(other, SOCK_DEAD) || 214162306a36Sopenharmony_ci (other->sk_shutdown & RCV_SHUTDOWN)) { 214262306a36Sopenharmony_ci unix_state_unlock(other); 214362306a36Sopenharmony_ci kfree_skb(skb); 214462306a36Sopenharmony_ci return -EPIPE; 214562306a36Sopenharmony_ci } 214662306a36Sopenharmony_ci 214762306a36Sopenharmony_ci maybe_add_creds(skb, sock, other); 214862306a36Sopenharmony_ci skb_get(skb); 214962306a36Sopenharmony_ci 215062306a36Sopenharmony_ci if (ousk->oob_skb) 215162306a36Sopenharmony_ci consume_skb(ousk->oob_skb); 215262306a36Sopenharmony_ci 215362306a36Sopenharmony_ci WRITE_ONCE(ousk->oob_skb, skb); 215462306a36Sopenharmony_ci 215562306a36Sopenharmony_ci scm_stat_add(other, skb); 215662306a36Sopenharmony_ci skb_queue_tail(&other->sk_receive_queue, skb); 215762306a36Sopenharmony_ci sk_send_sigurg(other); 215862306a36Sopenharmony_ci unix_state_unlock(other); 215962306a36Sopenharmony_ci other->sk_data_ready(other); 216062306a36Sopenharmony_ci 216162306a36Sopenharmony_ci return err; 216262306a36Sopenharmony_ci} 216362306a36Sopenharmony_ci#endif 216462306a36Sopenharmony_ci 216562306a36Sopenharmony_cistatic int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg, 216662306a36Sopenharmony_ci size_t len) 216762306a36Sopenharmony_ci{ 216862306a36Sopenharmony_ci struct sock *sk = sock->sk; 216962306a36Sopenharmony_ci struct sock *other = NULL; 217062306a36Sopenharmony_ci int err, size; 217162306a36Sopenharmony_ci struct sk_buff *skb; 217262306a36Sopenharmony_ci int sent = 0; 217362306a36Sopenharmony_ci struct scm_cookie scm; 217462306a36Sopenharmony_ci bool fds_sent = false; 217562306a36Sopenharmony_ci int data_len; 217662306a36Sopenharmony_ci 217762306a36Sopenharmony_ci wait_for_unix_gc(); 217862306a36Sopenharmony_ci err = scm_send(sock, msg, &scm, false); 217962306a36Sopenharmony_ci if (err < 0) 218062306a36Sopenharmony_ci return err; 218162306a36Sopenharmony_ci 218262306a36Sopenharmony_ci err = -EOPNOTSUPP; 218362306a36Sopenharmony_ci if (msg->msg_flags & MSG_OOB) { 218462306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_AF_UNIX_OOB) 218562306a36Sopenharmony_ci if (len) 218662306a36Sopenharmony_ci len--; 218762306a36Sopenharmony_ci else 218862306a36Sopenharmony_ci#endif 218962306a36Sopenharmony_ci goto out_err; 219062306a36Sopenharmony_ci } 219162306a36Sopenharmony_ci 219262306a36Sopenharmony_ci if (msg->msg_namelen) { 219362306a36Sopenharmony_ci err = sk->sk_state == TCP_ESTABLISHED ? -EISCONN : -EOPNOTSUPP; 219462306a36Sopenharmony_ci goto out_err; 219562306a36Sopenharmony_ci } else { 219662306a36Sopenharmony_ci err = -ENOTCONN; 219762306a36Sopenharmony_ci other = unix_peer(sk); 219862306a36Sopenharmony_ci if (!other) 219962306a36Sopenharmony_ci goto out_err; 220062306a36Sopenharmony_ci } 220162306a36Sopenharmony_ci 220262306a36Sopenharmony_ci if (sk->sk_shutdown & SEND_SHUTDOWN) 220362306a36Sopenharmony_ci goto pipe_err; 220462306a36Sopenharmony_ci 220562306a36Sopenharmony_ci while (sent < len) { 220662306a36Sopenharmony_ci size = len - sent; 220762306a36Sopenharmony_ci 220862306a36Sopenharmony_ci if (unlikely(msg->msg_flags & MSG_SPLICE_PAGES)) { 220962306a36Sopenharmony_ci skb = sock_alloc_send_pskb(sk, 0, 0, 221062306a36Sopenharmony_ci msg->msg_flags & MSG_DONTWAIT, 221162306a36Sopenharmony_ci &err, 0); 221262306a36Sopenharmony_ci } else { 221362306a36Sopenharmony_ci /* Keep two messages in the pipe so it schedules better */ 221462306a36Sopenharmony_ci size = min_t(int, size, (sk->sk_sndbuf >> 1) - 64); 221562306a36Sopenharmony_ci 221662306a36Sopenharmony_ci /* allow fallback to order-0 allocations */ 221762306a36Sopenharmony_ci size = min_t(int, size, SKB_MAX_HEAD(0) + UNIX_SKB_FRAGS_SZ); 221862306a36Sopenharmony_ci 221962306a36Sopenharmony_ci data_len = max_t(int, 0, size - SKB_MAX_HEAD(0)); 222062306a36Sopenharmony_ci 222162306a36Sopenharmony_ci data_len = min_t(size_t, size, PAGE_ALIGN(data_len)); 222262306a36Sopenharmony_ci 222362306a36Sopenharmony_ci skb = sock_alloc_send_pskb(sk, size - data_len, data_len, 222462306a36Sopenharmony_ci msg->msg_flags & MSG_DONTWAIT, &err, 222562306a36Sopenharmony_ci get_order(UNIX_SKB_FRAGS_SZ)); 222662306a36Sopenharmony_ci } 222762306a36Sopenharmony_ci if (!skb) 222862306a36Sopenharmony_ci goto out_err; 222962306a36Sopenharmony_ci 223062306a36Sopenharmony_ci /* Only send the fds in the first buffer */ 223162306a36Sopenharmony_ci err = unix_scm_to_skb(&scm, skb, !fds_sent); 223262306a36Sopenharmony_ci if (err < 0) { 223362306a36Sopenharmony_ci kfree_skb(skb); 223462306a36Sopenharmony_ci goto out_err; 223562306a36Sopenharmony_ci } 223662306a36Sopenharmony_ci fds_sent = true; 223762306a36Sopenharmony_ci 223862306a36Sopenharmony_ci if (unlikely(msg->msg_flags & MSG_SPLICE_PAGES)) { 223962306a36Sopenharmony_ci err = skb_splice_from_iter(skb, &msg->msg_iter, size, 224062306a36Sopenharmony_ci sk->sk_allocation); 224162306a36Sopenharmony_ci if (err < 0) { 224262306a36Sopenharmony_ci kfree_skb(skb); 224362306a36Sopenharmony_ci goto out_err; 224462306a36Sopenharmony_ci } 224562306a36Sopenharmony_ci size = err; 224662306a36Sopenharmony_ci refcount_add(size, &sk->sk_wmem_alloc); 224762306a36Sopenharmony_ci } else { 224862306a36Sopenharmony_ci skb_put(skb, size - data_len); 224962306a36Sopenharmony_ci skb->data_len = data_len; 225062306a36Sopenharmony_ci skb->len = size; 225162306a36Sopenharmony_ci err = skb_copy_datagram_from_iter(skb, 0, &msg->msg_iter, size); 225262306a36Sopenharmony_ci if (err) { 225362306a36Sopenharmony_ci kfree_skb(skb); 225462306a36Sopenharmony_ci goto out_err; 225562306a36Sopenharmony_ci } 225662306a36Sopenharmony_ci } 225762306a36Sopenharmony_ci 225862306a36Sopenharmony_ci unix_state_lock(other); 225962306a36Sopenharmony_ci 226062306a36Sopenharmony_ci if (sock_flag(other, SOCK_DEAD) || 226162306a36Sopenharmony_ci (other->sk_shutdown & RCV_SHUTDOWN)) 226262306a36Sopenharmony_ci goto pipe_err_free; 226362306a36Sopenharmony_ci 226462306a36Sopenharmony_ci maybe_add_creds(skb, sock, other); 226562306a36Sopenharmony_ci scm_stat_add(other, skb); 226662306a36Sopenharmony_ci skb_queue_tail(&other->sk_receive_queue, skb); 226762306a36Sopenharmony_ci unix_state_unlock(other); 226862306a36Sopenharmony_ci other->sk_data_ready(other); 226962306a36Sopenharmony_ci sent += size; 227062306a36Sopenharmony_ci } 227162306a36Sopenharmony_ci 227262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_AF_UNIX_OOB) 227362306a36Sopenharmony_ci if (msg->msg_flags & MSG_OOB) { 227462306a36Sopenharmony_ci err = queue_oob(sock, msg, other, &scm, fds_sent); 227562306a36Sopenharmony_ci if (err) 227662306a36Sopenharmony_ci goto out_err; 227762306a36Sopenharmony_ci sent++; 227862306a36Sopenharmony_ci } 227962306a36Sopenharmony_ci#endif 228062306a36Sopenharmony_ci 228162306a36Sopenharmony_ci scm_destroy(&scm); 228262306a36Sopenharmony_ci 228362306a36Sopenharmony_ci return sent; 228462306a36Sopenharmony_ci 228562306a36Sopenharmony_cipipe_err_free: 228662306a36Sopenharmony_ci unix_state_unlock(other); 228762306a36Sopenharmony_ci kfree_skb(skb); 228862306a36Sopenharmony_cipipe_err: 228962306a36Sopenharmony_ci if (sent == 0 && !(msg->msg_flags&MSG_NOSIGNAL)) 229062306a36Sopenharmony_ci send_sig(SIGPIPE, current, 0); 229162306a36Sopenharmony_ci err = -EPIPE; 229262306a36Sopenharmony_ciout_err: 229362306a36Sopenharmony_ci scm_destroy(&scm); 229462306a36Sopenharmony_ci return sent ? : err; 229562306a36Sopenharmony_ci} 229662306a36Sopenharmony_ci 229762306a36Sopenharmony_cistatic int unix_seqpacket_sendmsg(struct socket *sock, struct msghdr *msg, 229862306a36Sopenharmony_ci size_t len) 229962306a36Sopenharmony_ci{ 230062306a36Sopenharmony_ci int err; 230162306a36Sopenharmony_ci struct sock *sk = sock->sk; 230262306a36Sopenharmony_ci 230362306a36Sopenharmony_ci err = sock_error(sk); 230462306a36Sopenharmony_ci if (err) 230562306a36Sopenharmony_ci return err; 230662306a36Sopenharmony_ci 230762306a36Sopenharmony_ci if (sk->sk_state != TCP_ESTABLISHED) 230862306a36Sopenharmony_ci return -ENOTCONN; 230962306a36Sopenharmony_ci 231062306a36Sopenharmony_ci if (msg->msg_namelen) 231162306a36Sopenharmony_ci msg->msg_namelen = 0; 231262306a36Sopenharmony_ci 231362306a36Sopenharmony_ci return unix_dgram_sendmsg(sock, msg, len); 231462306a36Sopenharmony_ci} 231562306a36Sopenharmony_ci 231662306a36Sopenharmony_cistatic int unix_seqpacket_recvmsg(struct socket *sock, struct msghdr *msg, 231762306a36Sopenharmony_ci size_t size, int flags) 231862306a36Sopenharmony_ci{ 231962306a36Sopenharmony_ci struct sock *sk = sock->sk; 232062306a36Sopenharmony_ci 232162306a36Sopenharmony_ci if (sk->sk_state != TCP_ESTABLISHED) 232262306a36Sopenharmony_ci return -ENOTCONN; 232362306a36Sopenharmony_ci 232462306a36Sopenharmony_ci return unix_dgram_recvmsg(sock, msg, size, flags); 232562306a36Sopenharmony_ci} 232662306a36Sopenharmony_ci 232762306a36Sopenharmony_cistatic void unix_copy_addr(struct msghdr *msg, struct sock *sk) 232862306a36Sopenharmony_ci{ 232962306a36Sopenharmony_ci struct unix_address *addr = smp_load_acquire(&unix_sk(sk)->addr); 233062306a36Sopenharmony_ci 233162306a36Sopenharmony_ci if (addr) { 233262306a36Sopenharmony_ci msg->msg_namelen = addr->len; 233362306a36Sopenharmony_ci memcpy(msg->msg_name, addr->name, addr->len); 233462306a36Sopenharmony_ci } 233562306a36Sopenharmony_ci} 233662306a36Sopenharmony_ci 233762306a36Sopenharmony_ciint __unix_dgram_recvmsg(struct sock *sk, struct msghdr *msg, size_t size, 233862306a36Sopenharmony_ci int flags) 233962306a36Sopenharmony_ci{ 234062306a36Sopenharmony_ci struct scm_cookie scm; 234162306a36Sopenharmony_ci struct socket *sock = sk->sk_socket; 234262306a36Sopenharmony_ci struct unix_sock *u = unix_sk(sk); 234362306a36Sopenharmony_ci struct sk_buff *skb, *last; 234462306a36Sopenharmony_ci long timeo; 234562306a36Sopenharmony_ci int skip; 234662306a36Sopenharmony_ci int err; 234762306a36Sopenharmony_ci 234862306a36Sopenharmony_ci err = -EOPNOTSUPP; 234962306a36Sopenharmony_ci if (flags&MSG_OOB) 235062306a36Sopenharmony_ci goto out; 235162306a36Sopenharmony_ci 235262306a36Sopenharmony_ci timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); 235362306a36Sopenharmony_ci 235462306a36Sopenharmony_ci do { 235562306a36Sopenharmony_ci mutex_lock(&u->iolock); 235662306a36Sopenharmony_ci 235762306a36Sopenharmony_ci skip = sk_peek_offset(sk, flags); 235862306a36Sopenharmony_ci skb = __skb_try_recv_datagram(sk, &sk->sk_receive_queue, flags, 235962306a36Sopenharmony_ci &skip, &err, &last); 236062306a36Sopenharmony_ci if (skb) { 236162306a36Sopenharmony_ci if (!(flags & MSG_PEEK)) 236262306a36Sopenharmony_ci scm_stat_del(sk, skb); 236362306a36Sopenharmony_ci break; 236462306a36Sopenharmony_ci } 236562306a36Sopenharmony_ci 236662306a36Sopenharmony_ci mutex_unlock(&u->iolock); 236762306a36Sopenharmony_ci 236862306a36Sopenharmony_ci if (err != -EAGAIN) 236962306a36Sopenharmony_ci break; 237062306a36Sopenharmony_ci } while (timeo && 237162306a36Sopenharmony_ci !__skb_wait_for_more_packets(sk, &sk->sk_receive_queue, 237262306a36Sopenharmony_ci &err, &timeo, last)); 237362306a36Sopenharmony_ci 237462306a36Sopenharmony_ci if (!skb) { /* implies iolock unlocked */ 237562306a36Sopenharmony_ci unix_state_lock(sk); 237662306a36Sopenharmony_ci /* Signal EOF on disconnected non-blocking SEQPACKET socket. */ 237762306a36Sopenharmony_ci if (sk->sk_type == SOCK_SEQPACKET && err == -EAGAIN && 237862306a36Sopenharmony_ci (sk->sk_shutdown & RCV_SHUTDOWN)) 237962306a36Sopenharmony_ci err = 0; 238062306a36Sopenharmony_ci unix_state_unlock(sk); 238162306a36Sopenharmony_ci goto out; 238262306a36Sopenharmony_ci } 238362306a36Sopenharmony_ci 238462306a36Sopenharmony_ci if (wq_has_sleeper(&u->peer_wait)) 238562306a36Sopenharmony_ci wake_up_interruptible_sync_poll(&u->peer_wait, 238662306a36Sopenharmony_ci EPOLLOUT | EPOLLWRNORM | 238762306a36Sopenharmony_ci EPOLLWRBAND); 238862306a36Sopenharmony_ci 238962306a36Sopenharmony_ci if (msg->msg_name) 239062306a36Sopenharmony_ci unix_copy_addr(msg, skb->sk); 239162306a36Sopenharmony_ci 239262306a36Sopenharmony_ci if (size > skb->len - skip) 239362306a36Sopenharmony_ci size = skb->len - skip; 239462306a36Sopenharmony_ci else if (size < skb->len - skip) 239562306a36Sopenharmony_ci msg->msg_flags |= MSG_TRUNC; 239662306a36Sopenharmony_ci 239762306a36Sopenharmony_ci err = skb_copy_datagram_msg(skb, skip, msg, size); 239862306a36Sopenharmony_ci if (err) 239962306a36Sopenharmony_ci goto out_free; 240062306a36Sopenharmony_ci 240162306a36Sopenharmony_ci if (sock_flag(sk, SOCK_RCVTSTAMP)) 240262306a36Sopenharmony_ci __sock_recv_timestamp(msg, sk, skb); 240362306a36Sopenharmony_ci 240462306a36Sopenharmony_ci memset(&scm, 0, sizeof(scm)); 240562306a36Sopenharmony_ci 240662306a36Sopenharmony_ci scm_set_cred(&scm, UNIXCB(skb).pid, UNIXCB(skb).uid, UNIXCB(skb).gid); 240762306a36Sopenharmony_ci unix_set_secdata(&scm, skb); 240862306a36Sopenharmony_ci 240962306a36Sopenharmony_ci if (!(flags & MSG_PEEK)) { 241062306a36Sopenharmony_ci if (UNIXCB(skb).fp) 241162306a36Sopenharmony_ci unix_detach_fds(&scm, skb); 241262306a36Sopenharmony_ci 241362306a36Sopenharmony_ci sk_peek_offset_bwd(sk, skb->len); 241462306a36Sopenharmony_ci } else { 241562306a36Sopenharmony_ci /* It is questionable: on PEEK we could: 241662306a36Sopenharmony_ci - do not return fds - good, but too simple 8) 241762306a36Sopenharmony_ci - return fds, and do not return them on read (old strategy, 241862306a36Sopenharmony_ci apparently wrong) 241962306a36Sopenharmony_ci - clone fds (I chose it for now, it is the most universal 242062306a36Sopenharmony_ci solution) 242162306a36Sopenharmony_ci 242262306a36Sopenharmony_ci POSIX 1003.1g does not actually define this clearly 242362306a36Sopenharmony_ci at all. POSIX 1003.1g doesn't define a lot of things 242462306a36Sopenharmony_ci clearly however! 242562306a36Sopenharmony_ci 242662306a36Sopenharmony_ci */ 242762306a36Sopenharmony_ci 242862306a36Sopenharmony_ci sk_peek_offset_fwd(sk, size); 242962306a36Sopenharmony_ci 243062306a36Sopenharmony_ci if (UNIXCB(skb).fp) 243162306a36Sopenharmony_ci unix_peek_fds(&scm, skb); 243262306a36Sopenharmony_ci } 243362306a36Sopenharmony_ci err = (flags & MSG_TRUNC) ? skb->len - skip : size; 243462306a36Sopenharmony_ci 243562306a36Sopenharmony_ci scm_recv_unix(sock, msg, &scm, flags); 243662306a36Sopenharmony_ci 243762306a36Sopenharmony_ciout_free: 243862306a36Sopenharmony_ci skb_free_datagram(sk, skb); 243962306a36Sopenharmony_ci mutex_unlock(&u->iolock); 244062306a36Sopenharmony_ciout: 244162306a36Sopenharmony_ci return err; 244262306a36Sopenharmony_ci} 244362306a36Sopenharmony_ci 244462306a36Sopenharmony_cistatic int unix_dgram_recvmsg(struct socket *sock, struct msghdr *msg, size_t size, 244562306a36Sopenharmony_ci int flags) 244662306a36Sopenharmony_ci{ 244762306a36Sopenharmony_ci struct sock *sk = sock->sk; 244862306a36Sopenharmony_ci 244962306a36Sopenharmony_ci#ifdef CONFIG_BPF_SYSCALL 245062306a36Sopenharmony_ci const struct proto *prot = READ_ONCE(sk->sk_prot); 245162306a36Sopenharmony_ci 245262306a36Sopenharmony_ci if (prot != &unix_dgram_proto) 245362306a36Sopenharmony_ci return prot->recvmsg(sk, msg, size, flags, NULL); 245462306a36Sopenharmony_ci#endif 245562306a36Sopenharmony_ci return __unix_dgram_recvmsg(sk, msg, size, flags); 245662306a36Sopenharmony_ci} 245762306a36Sopenharmony_ci 245862306a36Sopenharmony_cistatic int unix_read_skb(struct sock *sk, skb_read_actor_t recv_actor) 245962306a36Sopenharmony_ci{ 246062306a36Sopenharmony_ci struct unix_sock *u = unix_sk(sk); 246162306a36Sopenharmony_ci struct sk_buff *skb; 246262306a36Sopenharmony_ci int err; 246362306a36Sopenharmony_ci 246462306a36Sopenharmony_ci mutex_lock(&u->iolock); 246562306a36Sopenharmony_ci skb = skb_recv_datagram(sk, MSG_DONTWAIT, &err); 246662306a36Sopenharmony_ci mutex_unlock(&u->iolock); 246762306a36Sopenharmony_ci if (!skb) 246862306a36Sopenharmony_ci return err; 246962306a36Sopenharmony_ci 247062306a36Sopenharmony_ci return recv_actor(sk, skb); 247162306a36Sopenharmony_ci} 247262306a36Sopenharmony_ci 247362306a36Sopenharmony_ci/* 247462306a36Sopenharmony_ci * Sleep until more data has arrived. But check for races.. 247562306a36Sopenharmony_ci */ 247662306a36Sopenharmony_cistatic long unix_stream_data_wait(struct sock *sk, long timeo, 247762306a36Sopenharmony_ci struct sk_buff *last, unsigned int last_len, 247862306a36Sopenharmony_ci bool freezable) 247962306a36Sopenharmony_ci{ 248062306a36Sopenharmony_ci unsigned int state = TASK_INTERRUPTIBLE | freezable * TASK_FREEZABLE; 248162306a36Sopenharmony_ci struct sk_buff *tail; 248262306a36Sopenharmony_ci DEFINE_WAIT(wait); 248362306a36Sopenharmony_ci 248462306a36Sopenharmony_ci unix_state_lock(sk); 248562306a36Sopenharmony_ci 248662306a36Sopenharmony_ci for (;;) { 248762306a36Sopenharmony_ci prepare_to_wait(sk_sleep(sk), &wait, state); 248862306a36Sopenharmony_ci 248962306a36Sopenharmony_ci tail = skb_peek_tail(&sk->sk_receive_queue); 249062306a36Sopenharmony_ci if (tail != last || 249162306a36Sopenharmony_ci (tail && tail->len != last_len) || 249262306a36Sopenharmony_ci sk->sk_err || 249362306a36Sopenharmony_ci (sk->sk_shutdown & RCV_SHUTDOWN) || 249462306a36Sopenharmony_ci signal_pending(current) || 249562306a36Sopenharmony_ci !timeo) 249662306a36Sopenharmony_ci break; 249762306a36Sopenharmony_ci 249862306a36Sopenharmony_ci sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk); 249962306a36Sopenharmony_ci unix_state_unlock(sk); 250062306a36Sopenharmony_ci timeo = schedule_timeout(timeo); 250162306a36Sopenharmony_ci unix_state_lock(sk); 250262306a36Sopenharmony_ci 250362306a36Sopenharmony_ci if (sock_flag(sk, SOCK_DEAD)) 250462306a36Sopenharmony_ci break; 250562306a36Sopenharmony_ci 250662306a36Sopenharmony_ci sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk); 250762306a36Sopenharmony_ci } 250862306a36Sopenharmony_ci 250962306a36Sopenharmony_ci finish_wait(sk_sleep(sk), &wait); 251062306a36Sopenharmony_ci unix_state_unlock(sk); 251162306a36Sopenharmony_ci return timeo; 251262306a36Sopenharmony_ci} 251362306a36Sopenharmony_ci 251462306a36Sopenharmony_cistatic unsigned int unix_skb_len(const struct sk_buff *skb) 251562306a36Sopenharmony_ci{ 251662306a36Sopenharmony_ci return skb->len - UNIXCB(skb).consumed; 251762306a36Sopenharmony_ci} 251862306a36Sopenharmony_ci 251962306a36Sopenharmony_cistruct unix_stream_read_state { 252062306a36Sopenharmony_ci int (*recv_actor)(struct sk_buff *, int, int, 252162306a36Sopenharmony_ci struct unix_stream_read_state *); 252262306a36Sopenharmony_ci struct socket *socket; 252362306a36Sopenharmony_ci struct msghdr *msg; 252462306a36Sopenharmony_ci struct pipe_inode_info *pipe; 252562306a36Sopenharmony_ci size_t size; 252662306a36Sopenharmony_ci int flags; 252762306a36Sopenharmony_ci unsigned int splice_flags; 252862306a36Sopenharmony_ci}; 252962306a36Sopenharmony_ci 253062306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_AF_UNIX_OOB) 253162306a36Sopenharmony_cistatic int unix_stream_recv_urg(struct unix_stream_read_state *state) 253262306a36Sopenharmony_ci{ 253362306a36Sopenharmony_ci struct socket *sock = state->socket; 253462306a36Sopenharmony_ci struct sock *sk = sock->sk; 253562306a36Sopenharmony_ci struct unix_sock *u = unix_sk(sk); 253662306a36Sopenharmony_ci int chunk = 1; 253762306a36Sopenharmony_ci struct sk_buff *oob_skb; 253862306a36Sopenharmony_ci 253962306a36Sopenharmony_ci mutex_lock(&u->iolock); 254062306a36Sopenharmony_ci unix_state_lock(sk); 254162306a36Sopenharmony_ci 254262306a36Sopenharmony_ci if (sock_flag(sk, SOCK_URGINLINE) || !u->oob_skb) { 254362306a36Sopenharmony_ci unix_state_unlock(sk); 254462306a36Sopenharmony_ci mutex_unlock(&u->iolock); 254562306a36Sopenharmony_ci return -EINVAL; 254662306a36Sopenharmony_ci } 254762306a36Sopenharmony_ci 254862306a36Sopenharmony_ci oob_skb = u->oob_skb; 254962306a36Sopenharmony_ci 255062306a36Sopenharmony_ci if (!(state->flags & MSG_PEEK)) 255162306a36Sopenharmony_ci WRITE_ONCE(u->oob_skb, NULL); 255262306a36Sopenharmony_ci else 255362306a36Sopenharmony_ci skb_get(oob_skb); 255462306a36Sopenharmony_ci unix_state_unlock(sk); 255562306a36Sopenharmony_ci 255662306a36Sopenharmony_ci chunk = state->recv_actor(oob_skb, 0, chunk, state); 255762306a36Sopenharmony_ci 255862306a36Sopenharmony_ci if (!(state->flags & MSG_PEEK)) 255962306a36Sopenharmony_ci UNIXCB(oob_skb).consumed += 1; 256062306a36Sopenharmony_ci 256162306a36Sopenharmony_ci consume_skb(oob_skb); 256262306a36Sopenharmony_ci 256362306a36Sopenharmony_ci mutex_unlock(&u->iolock); 256462306a36Sopenharmony_ci 256562306a36Sopenharmony_ci if (chunk < 0) 256662306a36Sopenharmony_ci return -EFAULT; 256762306a36Sopenharmony_ci 256862306a36Sopenharmony_ci state->msg->msg_flags |= MSG_OOB; 256962306a36Sopenharmony_ci return 1; 257062306a36Sopenharmony_ci} 257162306a36Sopenharmony_ci 257262306a36Sopenharmony_cistatic struct sk_buff *manage_oob(struct sk_buff *skb, struct sock *sk, 257362306a36Sopenharmony_ci int flags, int copied) 257462306a36Sopenharmony_ci{ 257562306a36Sopenharmony_ci struct unix_sock *u = unix_sk(sk); 257662306a36Sopenharmony_ci 257762306a36Sopenharmony_ci if (!unix_skb_len(skb) && !(flags & MSG_PEEK)) { 257862306a36Sopenharmony_ci skb_unlink(skb, &sk->sk_receive_queue); 257962306a36Sopenharmony_ci consume_skb(skb); 258062306a36Sopenharmony_ci skb = NULL; 258162306a36Sopenharmony_ci } else { 258262306a36Sopenharmony_ci if (skb == u->oob_skb) { 258362306a36Sopenharmony_ci if (copied) { 258462306a36Sopenharmony_ci skb = NULL; 258562306a36Sopenharmony_ci } else if (sock_flag(sk, SOCK_URGINLINE)) { 258662306a36Sopenharmony_ci if (!(flags & MSG_PEEK)) { 258762306a36Sopenharmony_ci WRITE_ONCE(u->oob_skb, NULL); 258862306a36Sopenharmony_ci consume_skb(skb); 258962306a36Sopenharmony_ci } 259062306a36Sopenharmony_ci } else if (!(flags & MSG_PEEK)) { 259162306a36Sopenharmony_ci skb_unlink(skb, &sk->sk_receive_queue); 259262306a36Sopenharmony_ci consume_skb(skb); 259362306a36Sopenharmony_ci skb = skb_peek(&sk->sk_receive_queue); 259462306a36Sopenharmony_ci } 259562306a36Sopenharmony_ci } 259662306a36Sopenharmony_ci } 259762306a36Sopenharmony_ci return skb; 259862306a36Sopenharmony_ci} 259962306a36Sopenharmony_ci#endif 260062306a36Sopenharmony_ci 260162306a36Sopenharmony_cistatic int unix_stream_read_skb(struct sock *sk, skb_read_actor_t recv_actor) 260262306a36Sopenharmony_ci{ 260362306a36Sopenharmony_ci if (unlikely(sk->sk_state != TCP_ESTABLISHED)) 260462306a36Sopenharmony_ci return -ENOTCONN; 260562306a36Sopenharmony_ci 260662306a36Sopenharmony_ci return unix_read_skb(sk, recv_actor); 260762306a36Sopenharmony_ci} 260862306a36Sopenharmony_ci 260962306a36Sopenharmony_cistatic int unix_stream_read_generic(struct unix_stream_read_state *state, 261062306a36Sopenharmony_ci bool freezable) 261162306a36Sopenharmony_ci{ 261262306a36Sopenharmony_ci struct scm_cookie scm; 261362306a36Sopenharmony_ci struct socket *sock = state->socket; 261462306a36Sopenharmony_ci struct sock *sk = sock->sk; 261562306a36Sopenharmony_ci struct unix_sock *u = unix_sk(sk); 261662306a36Sopenharmony_ci int copied = 0; 261762306a36Sopenharmony_ci int flags = state->flags; 261862306a36Sopenharmony_ci int noblock = flags & MSG_DONTWAIT; 261962306a36Sopenharmony_ci bool check_creds = false; 262062306a36Sopenharmony_ci int target; 262162306a36Sopenharmony_ci int err = 0; 262262306a36Sopenharmony_ci long timeo; 262362306a36Sopenharmony_ci int skip; 262462306a36Sopenharmony_ci size_t size = state->size; 262562306a36Sopenharmony_ci unsigned int last_len; 262662306a36Sopenharmony_ci 262762306a36Sopenharmony_ci if (unlikely(sk->sk_state != TCP_ESTABLISHED)) { 262862306a36Sopenharmony_ci err = -EINVAL; 262962306a36Sopenharmony_ci goto out; 263062306a36Sopenharmony_ci } 263162306a36Sopenharmony_ci 263262306a36Sopenharmony_ci if (unlikely(flags & MSG_OOB)) { 263362306a36Sopenharmony_ci err = -EOPNOTSUPP; 263462306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_AF_UNIX_OOB) 263562306a36Sopenharmony_ci err = unix_stream_recv_urg(state); 263662306a36Sopenharmony_ci#endif 263762306a36Sopenharmony_ci goto out; 263862306a36Sopenharmony_ci } 263962306a36Sopenharmony_ci 264062306a36Sopenharmony_ci target = sock_rcvlowat(sk, flags & MSG_WAITALL, size); 264162306a36Sopenharmony_ci timeo = sock_rcvtimeo(sk, noblock); 264262306a36Sopenharmony_ci 264362306a36Sopenharmony_ci memset(&scm, 0, sizeof(scm)); 264462306a36Sopenharmony_ci 264562306a36Sopenharmony_ci /* Lock the socket to prevent queue disordering 264662306a36Sopenharmony_ci * while sleeps in memcpy_tomsg 264762306a36Sopenharmony_ci */ 264862306a36Sopenharmony_ci mutex_lock(&u->iolock); 264962306a36Sopenharmony_ci 265062306a36Sopenharmony_ci skip = max(sk_peek_offset(sk, flags), 0); 265162306a36Sopenharmony_ci 265262306a36Sopenharmony_ci do { 265362306a36Sopenharmony_ci int chunk; 265462306a36Sopenharmony_ci bool drop_skb; 265562306a36Sopenharmony_ci struct sk_buff *skb, *last; 265662306a36Sopenharmony_ci 265762306a36Sopenharmony_ciredo: 265862306a36Sopenharmony_ci unix_state_lock(sk); 265962306a36Sopenharmony_ci if (sock_flag(sk, SOCK_DEAD)) { 266062306a36Sopenharmony_ci err = -ECONNRESET; 266162306a36Sopenharmony_ci goto unlock; 266262306a36Sopenharmony_ci } 266362306a36Sopenharmony_ci last = skb = skb_peek(&sk->sk_receive_queue); 266462306a36Sopenharmony_ci last_len = last ? last->len : 0; 266562306a36Sopenharmony_ci 266662306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_AF_UNIX_OOB) 266762306a36Sopenharmony_ci if (skb) { 266862306a36Sopenharmony_ci skb = manage_oob(skb, sk, flags, copied); 266962306a36Sopenharmony_ci if (!skb) { 267062306a36Sopenharmony_ci unix_state_unlock(sk); 267162306a36Sopenharmony_ci if (copied) 267262306a36Sopenharmony_ci break; 267362306a36Sopenharmony_ci goto redo; 267462306a36Sopenharmony_ci } 267562306a36Sopenharmony_ci } 267662306a36Sopenharmony_ci#endif 267762306a36Sopenharmony_ciagain: 267862306a36Sopenharmony_ci if (skb == NULL) { 267962306a36Sopenharmony_ci if (copied >= target) 268062306a36Sopenharmony_ci goto unlock; 268162306a36Sopenharmony_ci 268262306a36Sopenharmony_ci /* 268362306a36Sopenharmony_ci * POSIX 1003.1g mandates this order. 268462306a36Sopenharmony_ci */ 268562306a36Sopenharmony_ci 268662306a36Sopenharmony_ci err = sock_error(sk); 268762306a36Sopenharmony_ci if (err) 268862306a36Sopenharmony_ci goto unlock; 268962306a36Sopenharmony_ci if (sk->sk_shutdown & RCV_SHUTDOWN) 269062306a36Sopenharmony_ci goto unlock; 269162306a36Sopenharmony_ci 269262306a36Sopenharmony_ci unix_state_unlock(sk); 269362306a36Sopenharmony_ci if (!timeo) { 269462306a36Sopenharmony_ci err = -EAGAIN; 269562306a36Sopenharmony_ci break; 269662306a36Sopenharmony_ci } 269762306a36Sopenharmony_ci 269862306a36Sopenharmony_ci mutex_unlock(&u->iolock); 269962306a36Sopenharmony_ci 270062306a36Sopenharmony_ci timeo = unix_stream_data_wait(sk, timeo, last, 270162306a36Sopenharmony_ci last_len, freezable); 270262306a36Sopenharmony_ci 270362306a36Sopenharmony_ci if (signal_pending(current)) { 270462306a36Sopenharmony_ci err = sock_intr_errno(timeo); 270562306a36Sopenharmony_ci scm_destroy(&scm); 270662306a36Sopenharmony_ci goto out; 270762306a36Sopenharmony_ci } 270862306a36Sopenharmony_ci 270962306a36Sopenharmony_ci mutex_lock(&u->iolock); 271062306a36Sopenharmony_ci goto redo; 271162306a36Sopenharmony_ciunlock: 271262306a36Sopenharmony_ci unix_state_unlock(sk); 271362306a36Sopenharmony_ci break; 271462306a36Sopenharmony_ci } 271562306a36Sopenharmony_ci 271662306a36Sopenharmony_ci while (skip >= unix_skb_len(skb)) { 271762306a36Sopenharmony_ci skip -= unix_skb_len(skb); 271862306a36Sopenharmony_ci last = skb; 271962306a36Sopenharmony_ci last_len = skb->len; 272062306a36Sopenharmony_ci skb = skb_peek_next(skb, &sk->sk_receive_queue); 272162306a36Sopenharmony_ci if (!skb) 272262306a36Sopenharmony_ci goto again; 272362306a36Sopenharmony_ci } 272462306a36Sopenharmony_ci 272562306a36Sopenharmony_ci unix_state_unlock(sk); 272662306a36Sopenharmony_ci 272762306a36Sopenharmony_ci if (check_creds) { 272862306a36Sopenharmony_ci /* Never glue messages from different writers */ 272962306a36Sopenharmony_ci if (!unix_skb_scm_eq(skb, &scm)) 273062306a36Sopenharmony_ci break; 273162306a36Sopenharmony_ci } else if (test_bit(SOCK_PASSCRED, &sock->flags) || 273262306a36Sopenharmony_ci test_bit(SOCK_PASSPIDFD, &sock->flags)) { 273362306a36Sopenharmony_ci /* Copy credentials */ 273462306a36Sopenharmony_ci scm_set_cred(&scm, UNIXCB(skb).pid, UNIXCB(skb).uid, UNIXCB(skb).gid); 273562306a36Sopenharmony_ci unix_set_secdata(&scm, skb); 273662306a36Sopenharmony_ci check_creds = true; 273762306a36Sopenharmony_ci } 273862306a36Sopenharmony_ci 273962306a36Sopenharmony_ci /* Copy address just once */ 274062306a36Sopenharmony_ci if (state->msg && state->msg->msg_name) { 274162306a36Sopenharmony_ci DECLARE_SOCKADDR(struct sockaddr_un *, sunaddr, 274262306a36Sopenharmony_ci state->msg->msg_name); 274362306a36Sopenharmony_ci unix_copy_addr(state->msg, skb->sk); 274462306a36Sopenharmony_ci sunaddr = NULL; 274562306a36Sopenharmony_ci } 274662306a36Sopenharmony_ci 274762306a36Sopenharmony_ci chunk = min_t(unsigned int, unix_skb_len(skb) - skip, size); 274862306a36Sopenharmony_ci skb_get(skb); 274962306a36Sopenharmony_ci chunk = state->recv_actor(skb, skip, chunk, state); 275062306a36Sopenharmony_ci drop_skb = !unix_skb_len(skb); 275162306a36Sopenharmony_ci /* skb is only safe to use if !drop_skb */ 275262306a36Sopenharmony_ci consume_skb(skb); 275362306a36Sopenharmony_ci if (chunk < 0) { 275462306a36Sopenharmony_ci if (copied == 0) 275562306a36Sopenharmony_ci copied = -EFAULT; 275662306a36Sopenharmony_ci break; 275762306a36Sopenharmony_ci } 275862306a36Sopenharmony_ci copied += chunk; 275962306a36Sopenharmony_ci size -= chunk; 276062306a36Sopenharmony_ci 276162306a36Sopenharmony_ci if (drop_skb) { 276262306a36Sopenharmony_ci /* the skb was touched by a concurrent reader; 276362306a36Sopenharmony_ci * we should not expect anything from this skb 276462306a36Sopenharmony_ci * anymore and assume it invalid - we can be 276562306a36Sopenharmony_ci * sure it was dropped from the socket queue 276662306a36Sopenharmony_ci * 276762306a36Sopenharmony_ci * let's report a short read 276862306a36Sopenharmony_ci */ 276962306a36Sopenharmony_ci err = 0; 277062306a36Sopenharmony_ci break; 277162306a36Sopenharmony_ci } 277262306a36Sopenharmony_ci 277362306a36Sopenharmony_ci /* Mark read part of skb as used */ 277462306a36Sopenharmony_ci if (!(flags & MSG_PEEK)) { 277562306a36Sopenharmony_ci UNIXCB(skb).consumed += chunk; 277662306a36Sopenharmony_ci 277762306a36Sopenharmony_ci sk_peek_offset_bwd(sk, chunk); 277862306a36Sopenharmony_ci 277962306a36Sopenharmony_ci if (UNIXCB(skb).fp) { 278062306a36Sopenharmony_ci scm_stat_del(sk, skb); 278162306a36Sopenharmony_ci unix_detach_fds(&scm, skb); 278262306a36Sopenharmony_ci } 278362306a36Sopenharmony_ci 278462306a36Sopenharmony_ci if (unix_skb_len(skb)) 278562306a36Sopenharmony_ci break; 278662306a36Sopenharmony_ci 278762306a36Sopenharmony_ci skb_unlink(skb, &sk->sk_receive_queue); 278862306a36Sopenharmony_ci consume_skb(skb); 278962306a36Sopenharmony_ci 279062306a36Sopenharmony_ci if (scm.fp) 279162306a36Sopenharmony_ci break; 279262306a36Sopenharmony_ci } else { 279362306a36Sopenharmony_ci /* It is questionable, see note in unix_dgram_recvmsg. 279462306a36Sopenharmony_ci */ 279562306a36Sopenharmony_ci if (UNIXCB(skb).fp) 279662306a36Sopenharmony_ci unix_peek_fds(&scm, skb); 279762306a36Sopenharmony_ci 279862306a36Sopenharmony_ci sk_peek_offset_fwd(sk, chunk); 279962306a36Sopenharmony_ci 280062306a36Sopenharmony_ci if (UNIXCB(skb).fp) 280162306a36Sopenharmony_ci break; 280262306a36Sopenharmony_ci 280362306a36Sopenharmony_ci skip = 0; 280462306a36Sopenharmony_ci last = skb; 280562306a36Sopenharmony_ci last_len = skb->len; 280662306a36Sopenharmony_ci unix_state_lock(sk); 280762306a36Sopenharmony_ci skb = skb_peek_next(skb, &sk->sk_receive_queue); 280862306a36Sopenharmony_ci if (skb) 280962306a36Sopenharmony_ci goto again; 281062306a36Sopenharmony_ci unix_state_unlock(sk); 281162306a36Sopenharmony_ci break; 281262306a36Sopenharmony_ci } 281362306a36Sopenharmony_ci } while (size); 281462306a36Sopenharmony_ci 281562306a36Sopenharmony_ci mutex_unlock(&u->iolock); 281662306a36Sopenharmony_ci if (state->msg) 281762306a36Sopenharmony_ci scm_recv_unix(sock, state->msg, &scm, flags); 281862306a36Sopenharmony_ci else 281962306a36Sopenharmony_ci scm_destroy(&scm); 282062306a36Sopenharmony_ciout: 282162306a36Sopenharmony_ci return copied ? : err; 282262306a36Sopenharmony_ci} 282362306a36Sopenharmony_ci 282462306a36Sopenharmony_cistatic int unix_stream_read_actor(struct sk_buff *skb, 282562306a36Sopenharmony_ci int skip, int chunk, 282662306a36Sopenharmony_ci struct unix_stream_read_state *state) 282762306a36Sopenharmony_ci{ 282862306a36Sopenharmony_ci int ret; 282962306a36Sopenharmony_ci 283062306a36Sopenharmony_ci ret = skb_copy_datagram_msg(skb, UNIXCB(skb).consumed + skip, 283162306a36Sopenharmony_ci state->msg, chunk); 283262306a36Sopenharmony_ci return ret ?: chunk; 283362306a36Sopenharmony_ci} 283462306a36Sopenharmony_ci 283562306a36Sopenharmony_ciint __unix_stream_recvmsg(struct sock *sk, struct msghdr *msg, 283662306a36Sopenharmony_ci size_t size, int flags) 283762306a36Sopenharmony_ci{ 283862306a36Sopenharmony_ci struct unix_stream_read_state state = { 283962306a36Sopenharmony_ci .recv_actor = unix_stream_read_actor, 284062306a36Sopenharmony_ci .socket = sk->sk_socket, 284162306a36Sopenharmony_ci .msg = msg, 284262306a36Sopenharmony_ci .size = size, 284362306a36Sopenharmony_ci .flags = flags 284462306a36Sopenharmony_ci }; 284562306a36Sopenharmony_ci 284662306a36Sopenharmony_ci return unix_stream_read_generic(&state, true); 284762306a36Sopenharmony_ci} 284862306a36Sopenharmony_ci 284962306a36Sopenharmony_cistatic int unix_stream_recvmsg(struct socket *sock, struct msghdr *msg, 285062306a36Sopenharmony_ci size_t size, int flags) 285162306a36Sopenharmony_ci{ 285262306a36Sopenharmony_ci struct unix_stream_read_state state = { 285362306a36Sopenharmony_ci .recv_actor = unix_stream_read_actor, 285462306a36Sopenharmony_ci .socket = sock, 285562306a36Sopenharmony_ci .msg = msg, 285662306a36Sopenharmony_ci .size = size, 285762306a36Sopenharmony_ci .flags = flags 285862306a36Sopenharmony_ci }; 285962306a36Sopenharmony_ci 286062306a36Sopenharmony_ci#ifdef CONFIG_BPF_SYSCALL 286162306a36Sopenharmony_ci struct sock *sk = sock->sk; 286262306a36Sopenharmony_ci const struct proto *prot = READ_ONCE(sk->sk_prot); 286362306a36Sopenharmony_ci 286462306a36Sopenharmony_ci if (prot != &unix_stream_proto) 286562306a36Sopenharmony_ci return prot->recvmsg(sk, msg, size, flags, NULL); 286662306a36Sopenharmony_ci#endif 286762306a36Sopenharmony_ci return unix_stream_read_generic(&state, true); 286862306a36Sopenharmony_ci} 286962306a36Sopenharmony_ci 287062306a36Sopenharmony_cistatic int unix_stream_splice_actor(struct sk_buff *skb, 287162306a36Sopenharmony_ci int skip, int chunk, 287262306a36Sopenharmony_ci struct unix_stream_read_state *state) 287362306a36Sopenharmony_ci{ 287462306a36Sopenharmony_ci return skb_splice_bits(skb, state->socket->sk, 287562306a36Sopenharmony_ci UNIXCB(skb).consumed + skip, 287662306a36Sopenharmony_ci state->pipe, chunk, state->splice_flags); 287762306a36Sopenharmony_ci} 287862306a36Sopenharmony_ci 287962306a36Sopenharmony_cistatic ssize_t unix_stream_splice_read(struct socket *sock, loff_t *ppos, 288062306a36Sopenharmony_ci struct pipe_inode_info *pipe, 288162306a36Sopenharmony_ci size_t size, unsigned int flags) 288262306a36Sopenharmony_ci{ 288362306a36Sopenharmony_ci struct unix_stream_read_state state = { 288462306a36Sopenharmony_ci .recv_actor = unix_stream_splice_actor, 288562306a36Sopenharmony_ci .socket = sock, 288662306a36Sopenharmony_ci .pipe = pipe, 288762306a36Sopenharmony_ci .size = size, 288862306a36Sopenharmony_ci .splice_flags = flags, 288962306a36Sopenharmony_ci }; 289062306a36Sopenharmony_ci 289162306a36Sopenharmony_ci if (unlikely(*ppos)) 289262306a36Sopenharmony_ci return -ESPIPE; 289362306a36Sopenharmony_ci 289462306a36Sopenharmony_ci if (sock->file->f_flags & O_NONBLOCK || 289562306a36Sopenharmony_ci flags & SPLICE_F_NONBLOCK) 289662306a36Sopenharmony_ci state.flags = MSG_DONTWAIT; 289762306a36Sopenharmony_ci 289862306a36Sopenharmony_ci return unix_stream_read_generic(&state, false); 289962306a36Sopenharmony_ci} 290062306a36Sopenharmony_ci 290162306a36Sopenharmony_cistatic int unix_shutdown(struct socket *sock, int mode) 290262306a36Sopenharmony_ci{ 290362306a36Sopenharmony_ci struct sock *sk = sock->sk; 290462306a36Sopenharmony_ci struct sock *other; 290562306a36Sopenharmony_ci 290662306a36Sopenharmony_ci if (mode < SHUT_RD || mode > SHUT_RDWR) 290762306a36Sopenharmony_ci return -EINVAL; 290862306a36Sopenharmony_ci /* This maps: 290962306a36Sopenharmony_ci * SHUT_RD (0) -> RCV_SHUTDOWN (1) 291062306a36Sopenharmony_ci * SHUT_WR (1) -> SEND_SHUTDOWN (2) 291162306a36Sopenharmony_ci * SHUT_RDWR (2) -> SHUTDOWN_MASK (3) 291262306a36Sopenharmony_ci */ 291362306a36Sopenharmony_ci ++mode; 291462306a36Sopenharmony_ci 291562306a36Sopenharmony_ci unix_state_lock(sk); 291662306a36Sopenharmony_ci WRITE_ONCE(sk->sk_shutdown, sk->sk_shutdown | mode); 291762306a36Sopenharmony_ci other = unix_peer(sk); 291862306a36Sopenharmony_ci if (other) 291962306a36Sopenharmony_ci sock_hold(other); 292062306a36Sopenharmony_ci unix_state_unlock(sk); 292162306a36Sopenharmony_ci sk->sk_state_change(sk); 292262306a36Sopenharmony_ci 292362306a36Sopenharmony_ci if (other && 292462306a36Sopenharmony_ci (sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_SEQPACKET)) { 292562306a36Sopenharmony_ci 292662306a36Sopenharmony_ci int peer_mode = 0; 292762306a36Sopenharmony_ci const struct proto *prot = READ_ONCE(other->sk_prot); 292862306a36Sopenharmony_ci 292962306a36Sopenharmony_ci if (prot->unhash) 293062306a36Sopenharmony_ci prot->unhash(other); 293162306a36Sopenharmony_ci if (mode&RCV_SHUTDOWN) 293262306a36Sopenharmony_ci peer_mode |= SEND_SHUTDOWN; 293362306a36Sopenharmony_ci if (mode&SEND_SHUTDOWN) 293462306a36Sopenharmony_ci peer_mode |= RCV_SHUTDOWN; 293562306a36Sopenharmony_ci unix_state_lock(other); 293662306a36Sopenharmony_ci WRITE_ONCE(other->sk_shutdown, other->sk_shutdown | peer_mode); 293762306a36Sopenharmony_ci unix_state_unlock(other); 293862306a36Sopenharmony_ci other->sk_state_change(other); 293962306a36Sopenharmony_ci if (peer_mode == SHUTDOWN_MASK) 294062306a36Sopenharmony_ci sk_wake_async(other, SOCK_WAKE_WAITD, POLL_HUP); 294162306a36Sopenharmony_ci else if (peer_mode & RCV_SHUTDOWN) 294262306a36Sopenharmony_ci sk_wake_async(other, SOCK_WAKE_WAITD, POLL_IN); 294362306a36Sopenharmony_ci } 294462306a36Sopenharmony_ci if (other) 294562306a36Sopenharmony_ci sock_put(other); 294662306a36Sopenharmony_ci 294762306a36Sopenharmony_ci return 0; 294862306a36Sopenharmony_ci} 294962306a36Sopenharmony_ci 295062306a36Sopenharmony_cilong unix_inq_len(struct sock *sk) 295162306a36Sopenharmony_ci{ 295262306a36Sopenharmony_ci struct sk_buff *skb; 295362306a36Sopenharmony_ci long amount = 0; 295462306a36Sopenharmony_ci 295562306a36Sopenharmony_ci if (sk->sk_state == TCP_LISTEN) 295662306a36Sopenharmony_ci return -EINVAL; 295762306a36Sopenharmony_ci 295862306a36Sopenharmony_ci spin_lock(&sk->sk_receive_queue.lock); 295962306a36Sopenharmony_ci if (sk->sk_type == SOCK_STREAM || 296062306a36Sopenharmony_ci sk->sk_type == SOCK_SEQPACKET) { 296162306a36Sopenharmony_ci skb_queue_walk(&sk->sk_receive_queue, skb) 296262306a36Sopenharmony_ci amount += unix_skb_len(skb); 296362306a36Sopenharmony_ci } else { 296462306a36Sopenharmony_ci skb = skb_peek(&sk->sk_receive_queue); 296562306a36Sopenharmony_ci if (skb) 296662306a36Sopenharmony_ci amount = skb->len; 296762306a36Sopenharmony_ci } 296862306a36Sopenharmony_ci spin_unlock(&sk->sk_receive_queue.lock); 296962306a36Sopenharmony_ci 297062306a36Sopenharmony_ci return amount; 297162306a36Sopenharmony_ci} 297262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(unix_inq_len); 297362306a36Sopenharmony_ci 297462306a36Sopenharmony_cilong unix_outq_len(struct sock *sk) 297562306a36Sopenharmony_ci{ 297662306a36Sopenharmony_ci return sk_wmem_alloc_get(sk); 297762306a36Sopenharmony_ci} 297862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(unix_outq_len); 297962306a36Sopenharmony_ci 298062306a36Sopenharmony_cistatic int unix_open_file(struct sock *sk) 298162306a36Sopenharmony_ci{ 298262306a36Sopenharmony_ci struct path path; 298362306a36Sopenharmony_ci struct file *f; 298462306a36Sopenharmony_ci int fd; 298562306a36Sopenharmony_ci 298662306a36Sopenharmony_ci if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) 298762306a36Sopenharmony_ci return -EPERM; 298862306a36Sopenharmony_ci 298962306a36Sopenharmony_ci if (!smp_load_acquire(&unix_sk(sk)->addr)) 299062306a36Sopenharmony_ci return -ENOENT; 299162306a36Sopenharmony_ci 299262306a36Sopenharmony_ci path = unix_sk(sk)->path; 299362306a36Sopenharmony_ci if (!path.dentry) 299462306a36Sopenharmony_ci return -ENOENT; 299562306a36Sopenharmony_ci 299662306a36Sopenharmony_ci path_get(&path); 299762306a36Sopenharmony_ci 299862306a36Sopenharmony_ci fd = get_unused_fd_flags(O_CLOEXEC); 299962306a36Sopenharmony_ci if (fd < 0) 300062306a36Sopenharmony_ci goto out; 300162306a36Sopenharmony_ci 300262306a36Sopenharmony_ci f = dentry_open(&path, O_PATH, current_cred()); 300362306a36Sopenharmony_ci if (IS_ERR(f)) { 300462306a36Sopenharmony_ci put_unused_fd(fd); 300562306a36Sopenharmony_ci fd = PTR_ERR(f); 300662306a36Sopenharmony_ci goto out; 300762306a36Sopenharmony_ci } 300862306a36Sopenharmony_ci 300962306a36Sopenharmony_ci fd_install(fd, f); 301062306a36Sopenharmony_ciout: 301162306a36Sopenharmony_ci path_put(&path); 301262306a36Sopenharmony_ci 301362306a36Sopenharmony_ci return fd; 301462306a36Sopenharmony_ci} 301562306a36Sopenharmony_ci 301662306a36Sopenharmony_cistatic int unix_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) 301762306a36Sopenharmony_ci{ 301862306a36Sopenharmony_ci struct sock *sk = sock->sk; 301962306a36Sopenharmony_ci long amount = 0; 302062306a36Sopenharmony_ci int err; 302162306a36Sopenharmony_ci 302262306a36Sopenharmony_ci switch (cmd) { 302362306a36Sopenharmony_ci case SIOCOUTQ: 302462306a36Sopenharmony_ci amount = unix_outq_len(sk); 302562306a36Sopenharmony_ci err = put_user(amount, (int __user *)arg); 302662306a36Sopenharmony_ci break; 302762306a36Sopenharmony_ci case SIOCINQ: 302862306a36Sopenharmony_ci amount = unix_inq_len(sk); 302962306a36Sopenharmony_ci if (amount < 0) 303062306a36Sopenharmony_ci err = amount; 303162306a36Sopenharmony_ci else 303262306a36Sopenharmony_ci err = put_user(amount, (int __user *)arg); 303362306a36Sopenharmony_ci break; 303462306a36Sopenharmony_ci case SIOCUNIXFILE: 303562306a36Sopenharmony_ci err = unix_open_file(sk); 303662306a36Sopenharmony_ci break; 303762306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_AF_UNIX_OOB) 303862306a36Sopenharmony_ci case SIOCATMARK: 303962306a36Sopenharmony_ci { 304062306a36Sopenharmony_ci struct sk_buff *skb; 304162306a36Sopenharmony_ci int answ = 0; 304262306a36Sopenharmony_ci 304362306a36Sopenharmony_ci skb = skb_peek(&sk->sk_receive_queue); 304462306a36Sopenharmony_ci if (skb && skb == READ_ONCE(unix_sk(sk)->oob_skb)) 304562306a36Sopenharmony_ci answ = 1; 304662306a36Sopenharmony_ci err = put_user(answ, (int __user *)arg); 304762306a36Sopenharmony_ci } 304862306a36Sopenharmony_ci break; 304962306a36Sopenharmony_ci#endif 305062306a36Sopenharmony_ci default: 305162306a36Sopenharmony_ci err = -ENOIOCTLCMD; 305262306a36Sopenharmony_ci break; 305362306a36Sopenharmony_ci } 305462306a36Sopenharmony_ci return err; 305562306a36Sopenharmony_ci} 305662306a36Sopenharmony_ci 305762306a36Sopenharmony_ci#ifdef CONFIG_COMPAT 305862306a36Sopenharmony_cistatic int unix_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) 305962306a36Sopenharmony_ci{ 306062306a36Sopenharmony_ci return unix_ioctl(sock, cmd, (unsigned long)compat_ptr(arg)); 306162306a36Sopenharmony_ci} 306262306a36Sopenharmony_ci#endif 306362306a36Sopenharmony_ci 306462306a36Sopenharmony_cistatic __poll_t unix_poll(struct file *file, struct socket *sock, poll_table *wait) 306562306a36Sopenharmony_ci{ 306662306a36Sopenharmony_ci struct sock *sk = sock->sk; 306762306a36Sopenharmony_ci __poll_t mask; 306862306a36Sopenharmony_ci u8 shutdown; 306962306a36Sopenharmony_ci 307062306a36Sopenharmony_ci sock_poll_wait(file, sock, wait); 307162306a36Sopenharmony_ci mask = 0; 307262306a36Sopenharmony_ci shutdown = READ_ONCE(sk->sk_shutdown); 307362306a36Sopenharmony_ci 307462306a36Sopenharmony_ci /* exceptional events? */ 307562306a36Sopenharmony_ci if (READ_ONCE(sk->sk_err)) 307662306a36Sopenharmony_ci mask |= EPOLLERR; 307762306a36Sopenharmony_ci if (shutdown == SHUTDOWN_MASK) 307862306a36Sopenharmony_ci mask |= EPOLLHUP; 307962306a36Sopenharmony_ci if (shutdown & RCV_SHUTDOWN) 308062306a36Sopenharmony_ci mask |= EPOLLRDHUP | EPOLLIN | EPOLLRDNORM; 308162306a36Sopenharmony_ci 308262306a36Sopenharmony_ci /* readable? */ 308362306a36Sopenharmony_ci if (!skb_queue_empty_lockless(&sk->sk_receive_queue)) 308462306a36Sopenharmony_ci mask |= EPOLLIN | EPOLLRDNORM; 308562306a36Sopenharmony_ci if (sk_is_readable(sk)) 308662306a36Sopenharmony_ci mask |= EPOLLIN | EPOLLRDNORM; 308762306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_AF_UNIX_OOB) 308862306a36Sopenharmony_ci if (READ_ONCE(unix_sk(sk)->oob_skb)) 308962306a36Sopenharmony_ci mask |= EPOLLPRI; 309062306a36Sopenharmony_ci#endif 309162306a36Sopenharmony_ci 309262306a36Sopenharmony_ci /* Connection-based need to check for termination and startup */ 309362306a36Sopenharmony_ci if ((sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_SEQPACKET) && 309462306a36Sopenharmony_ci sk->sk_state == TCP_CLOSE) 309562306a36Sopenharmony_ci mask |= EPOLLHUP; 309662306a36Sopenharmony_ci 309762306a36Sopenharmony_ci /* 309862306a36Sopenharmony_ci * we set writable also when the other side has shut down the 309962306a36Sopenharmony_ci * connection. This prevents stuck sockets. 310062306a36Sopenharmony_ci */ 310162306a36Sopenharmony_ci if (unix_writable(sk)) 310262306a36Sopenharmony_ci mask |= EPOLLOUT | EPOLLWRNORM | EPOLLWRBAND; 310362306a36Sopenharmony_ci 310462306a36Sopenharmony_ci return mask; 310562306a36Sopenharmony_ci} 310662306a36Sopenharmony_ci 310762306a36Sopenharmony_cistatic __poll_t unix_dgram_poll(struct file *file, struct socket *sock, 310862306a36Sopenharmony_ci poll_table *wait) 310962306a36Sopenharmony_ci{ 311062306a36Sopenharmony_ci struct sock *sk = sock->sk, *other; 311162306a36Sopenharmony_ci unsigned int writable; 311262306a36Sopenharmony_ci __poll_t mask; 311362306a36Sopenharmony_ci u8 shutdown; 311462306a36Sopenharmony_ci 311562306a36Sopenharmony_ci sock_poll_wait(file, sock, wait); 311662306a36Sopenharmony_ci mask = 0; 311762306a36Sopenharmony_ci shutdown = READ_ONCE(sk->sk_shutdown); 311862306a36Sopenharmony_ci 311962306a36Sopenharmony_ci /* exceptional events? */ 312062306a36Sopenharmony_ci if (READ_ONCE(sk->sk_err) || 312162306a36Sopenharmony_ci !skb_queue_empty_lockless(&sk->sk_error_queue)) 312262306a36Sopenharmony_ci mask |= EPOLLERR | 312362306a36Sopenharmony_ci (sock_flag(sk, SOCK_SELECT_ERR_QUEUE) ? EPOLLPRI : 0); 312462306a36Sopenharmony_ci 312562306a36Sopenharmony_ci if (shutdown & RCV_SHUTDOWN) 312662306a36Sopenharmony_ci mask |= EPOLLRDHUP | EPOLLIN | EPOLLRDNORM; 312762306a36Sopenharmony_ci if (shutdown == SHUTDOWN_MASK) 312862306a36Sopenharmony_ci mask |= EPOLLHUP; 312962306a36Sopenharmony_ci 313062306a36Sopenharmony_ci /* readable? */ 313162306a36Sopenharmony_ci if (!skb_queue_empty_lockless(&sk->sk_receive_queue)) 313262306a36Sopenharmony_ci mask |= EPOLLIN | EPOLLRDNORM; 313362306a36Sopenharmony_ci if (sk_is_readable(sk)) 313462306a36Sopenharmony_ci mask |= EPOLLIN | EPOLLRDNORM; 313562306a36Sopenharmony_ci 313662306a36Sopenharmony_ci /* Connection-based need to check for termination and startup */ 313762306a36Sopenharmony_ci if (sk->sk_type == SOCK_SEQPACKET) { 313862306a36Sopenharmony_ci if (sk->sk_state == TCP_CLOSE) 313962306a36Sopenharmony_ci mask |= EPOLLHUP; 314062306a36Sopenharmony_ci /* connection hasn't started yet? */ 314162306a36Sopenharmony_ci if (sk->sk_state == TCP_SYN_SENT) 314262306a36Sopenharmony_ci return mask; 314362306a36Sopenharmony_ci } 314462306a36Sopenharmony_ci 314562306a36Sopenharmony_ci /* No write status requested, avoid expensive OUT tests. */ 314662306a36Sopenharmony_ci if (!(poll_requested_events(wait) & (EPOLLWRBAND|EPOLLWRNORM|EPOLLOUT))) 314762306a36Sopenharmony_ci return mask; 314862306a36Sopenharmony_ci 314962306a36Sopenharmony_ci writable = unix_writable(sk); 315062306a36Sopenharmony_ci if (writable) { 315162306a36Sopenharmony_ci unix_state_lock(sk); 315262306a36Sopenharmony_ci 315362306a36Sopenharmony_ci other = unix_peer(sk); 315462306a36Sopenharmony_ci if (other && unix_peer(other) != sk && 315562306a36Sopenharmony_ci unix_recvq_full_lockless(other) && 315662306a36Sopenharmony_ci unix_dgram_peer_wake_me(sk, other)) 315762306a36Sopenharmony_ci writable = 0; 315862306a36Sopenharmony_ci 315962306a36Sopenharmony_ci unix_state_unlock(sk); 316062306a36Sopenharmony_ci } 316162306a36Sopenharmony_ci 316262306a36Sopenharmony_ci if (writable) 316362306a36Sopenharmony_ci mask |= EPOLLOUT | EPOLLWRNORM | EPOLLWRBAND; 316462306a36Sopenharmony_ci else 316562306a36Sopenharmony_ci sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk); 316662306a36Sopenharmony_ci 316762306a36Sopenharmony_ci return mask; 316862306a36Sopenharmony_ci} 316962306a36Sopenharmony_ci 317062306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS 317162306a36Sopenharmony_ci 317262306a36Sopenharmony_ci#define BUCKET_SPACE (BITS_PER_LONG - (UNIX_HASH_BITS + 1) - 1) 317362306a36Sopenharmony_ci 317462306a36Sopenharmony_ci#define get_bucket(x) ((x) >> BUCKET_SPACE) 317562306a36Sopenharmony_ci#define get_offset(x) ((x) & ((1UL << BUCKET_SPACE) - 1)) 317662306a36Sopenharmony_ci#define set_bucket_offset(b, o) ((b) << BUCKET_SPACE | (o)) 317762306a36Sopenharmony_ci 317862306a36Sopenharmony_cistatic struct sock *unix_from_bucket(struct seq_file *seq, loff_t *pos) 317962306a36Sopenharmony_ci{ 318062306a36Sopenharmony_ci unsigned long offset = get_offset(*pos); 318162306a36Sopenharmony_ci unsigned long bucket = get_bucket(*pos); 318262306a36Sopenharmony_ci unsigned long count = 0; 318362306a36Sopenharmony_ci struct sock *sk; 318462306a36Sopenharmony_ci 318562306a36Sopenharmony_ci for (sk = sk_head(&seq_file_net(seq)->unx.table.buckets[bucket]); 318662306a36Sopenharmony_ci sk; sk = sk_next(sk)) { 318762306a36Sopenharmony_ci if (++count == offset) 318862306a36Sopenharmony_ci break; 318962306a36Sopenharmony_ci } 319062306a36Sopenharmony_ci 319162306a36Sopenharmony_ci return sk; 319262306a36Sopenharmony_ci} 319362306a36Sopenharmony_ci 319462306a36Sopenharmony_cistatic struct sock *unix_get_first(struct seq_file *seq, loff_t *pos) 319562306a36Sopenharmony_ci{ 319662306a36Sopenharmony_ci unsigned long bucket = get_bucket(*pos); 319762306a36Sopenharmony_ci struct net *net = seq_file_net(seq); 319862306a36Sopenharmony_ci struct sock *sk; 319962306a36Sopenharmony_ci 320062306a36Sopenharmony_ci while (bucket < UNIX_HASH_SIZE) { 320162306a36Sopenharmony_ci spin_lock(&net->unx.table.locks[bucket]); 320262306a36Sopenharmony_ci 320362306a36Sopenharmony_ci sk = unix_from_bucket(seq, pos); 320462306a36Sopenharmony_ci if (sk) 320562306a36Sopenharmony_ci return sk; 320662306a36Sopenharmony_ci 320762306a36Sopenharmony_ci spin_unlock(&net->unx.table.locks[bucket]); 320862306a36Sopenharmony_ci 320962306a36Sopenharmony_ci *pos = set_bucket_offset(++bucket, 1); 321062306a36Sopenharmony_ci } 321162306a36Sopenharmony_ci 321262306a36Sopenharmony_ci return NULL; 321362306a36Sopenharmony_ci} 321462306a36Sopenharmony_ci 321562306a36Sopenharmony_cistatic struct sock *unix_get_next(struct seq_file *seq, struct sock *sk, 321662306a36Sopenharmony_ci loff_t *pos) 321762306a36Sopenharmony_ci{ 321862306a36Sopenharmony_ci unsigned long bucket = get_bucket(*pos); 321962306a36Sopenharmony_ci 322062306a36Sopenharmony_ci sk = sk_next(sk); 322162306a36Sopenharmony_ci if (sk) 322262306a36Sopenharmony_ci return sk; 322362306a36Sopenharmony_ci 322462306a36Sopenharmony_ci 322562306a36Sopenharmony_ci spin_unlock(&seq_file_net(seq)->unx.table.locks[bucket]); 322662306a36Sopenharmony_ci 322762306a36Sopenharmony_ci *pos = set_bucket_offset(++bucket, 1); 322862306a36Sopenharmony_ci 322962306a36Sopenharmony_ci return unix_get_first(seq, pos); 323062306a36Sopenharmony_ci} 323162306a36Sopenharmony_ci 323262306a36Sopenharmony_cistatic void *unix_seq_start(struct seq_file *seq, loff_t *pos) 323362306a36Sopenharmony_ci{ 323462306a36Sopenharmony_ci if (!*pos) 323562306a36Sopenharmony_ci return SEQ_START_TOKEN; 323662306a36Sopenharmony_ci 323762306a36Sopenharmony_ci return unix_get_first(seq, pos); 323862306a36Sopenharmony_ci} 323962306a36Sopenharmony_ci 324062306a36Sopenharmony_cistatic void *unix_seq_next(struct seq_file *seq, void *v, loff_t *pos) 324162306a36Sopenharmony_ci{ 324262306a36Sopenharmony_ci ++*pos; 324362306a36Sopenharmony_ci 324462306a36Sopenharmony_ci if (v == SEQ_START_TOKEN) 324562306a36Sopenharmony_ci return unix_get_first(seq, pos); 324662306a36Sopenharmony_ci 324762306a36Sopenharmony_ci return unix_get_next(seq, v, pos); 324862306a36Sopenharmony_ci} 324962306a36Sopenharmony_ci 325062306a36Sopenharmony_cistatic void unix_seq_stop(struct seq_file *seq, void *v) 325162306a36Sopenharmony_ci{ 325262306a36Sopenharmony_ci struct sock *sk = v; 325362306a36Sopenharmony_ci 325462306a36Sopenharmony_ci if (sk) 325562306a36Sopenharmony_ci spin_unlock(&seq_file_net(seq)->unx.table.locks[sk->sk_hash]); 325662306a36Sopenharmony_ci} 325762306a36Sopenharmony_ci 325862306a36Sopenharmony_cistatic int unix_seq_show(struct seq_file *seq, void *v) 325962306a36Sopenharmony_ci{ 326062306a36Sopenharmony_ci 326162306a36Sopenharmony_ci if (v == SEQ_START_TOKEN) 326262306a36Sopenharmony_ci seq_puts(seq, "Num RefCount Protocol Flags Type St " 326362306a36Sopenharmony_ci "Inode Path\n"); 326462306a36Sopenharmony_ci else { 326562306a36Sopenharmony_ci struct sock *s = v; 326662306a36Sopenharmony_ci struct unix_sock *u = unix_sk(s); 326762306a36Sopenharmony_ci unix_state_lock(s); 326862306a36Sopenharmony_ci 326962306a36Sopenharmony_ci seq_printf(seq, "%pK: %08X %08X %08X %04X %02X %5lu", 327062306a36Sopenharmony_ci s, 327162306a36Sopenharmony_ci refcount_read(&s->sk_refcnt), 327262306a36Sopenharmony_ci 0, 327362306a36Sopenharmony_ci s->sk_state == TCP_LISTEN ? __SO_ACCEPTCON : 0, 327462306a36Sopenharmony_ci s->sk_type, 327562306a36Sopenharmony_ci s->sk_socket ? 327662306a36Sopenharmony_ci (s->sk_state == TCP_ESTABLISHED ? SS_CONNECTED : SS_UNCONNECTED) : 327762306a36Sopenharmony_ci (s->sk_state == TCP_ESTABLISHED ? SS_CONNECTING : SS_DISCONNECTING), 327862306a36Sopenharmony_ci sock_i_ino(s)); 327962306a36Sopenharmony_ci 328062306a36Sopenharmony_ci if (u->addr) { // under a hash table lock here 328162306a36Sopenharmony_ci int i, len; 328262306a36Sopenharmony_ci seq_putc(seq, ' '); 328362306a36Sopenharmony_ci 328462306a36Sopenharmony_ci i = 0; 328562306a36Sopenharmony_ci len = u->addr->len - 328662306a36Sopenharmony_ci offsetof(struct sockaddr_un, sun_path); 328762306a36Sopenharmony_ci if (u->addr->name->sun_path[0]) { 328862306a36Sopenharmony_ci len--; 328962306a36Sopenharmony_ci } else { 329062306a36Sopenharmony_ci seq_putc(seq, '@'); 329162306a36Sopenharmony_ci i++; 329262306a36Sopenharmony_ci } 329362306a36Sopenharmony_ci for ( ; i < len; i++) 329462306a36Sopenharmony_ci seq_putc(seq, u->addr->name->sun_path[i] ?: 329562306a36Sopenharmony_ci '@'); 329662306a36Sopenharmony_ci } 329762306a36Sopenharmony_ci unix_state_unlock(s); 329862306a36Sopenharmony_ci seq_putc(seq, '\n'); 329962306a36Sopenharmony_ci } 330062306a36Sopenharmony_ci 330162306a36Sopenharmony_ci return 0; 330262306a36Sopenharmony_ci} 330362306a36Sopenharmony_ci 330462306a36Sopenharmony_cistatic const struct seq_operations unix_seq_ops = { 330562306a36Sopenharmony_ci .start = unix_seq_start, 330662306a36Sopenharmony_ci .next = unix_seq_next, 330762306a36Sopenharmony_ci .stop = unix_seq_stop, 330862306a36Sopenharmony_ci .show = unix_seq_show, 330962306a36Sopenharmony_ci}; 331062306a36Sopenharmony_ci 331162306a36Sopenharmony_ci#if IS_BUILTIN(CONFIG_UNIX) && defined(CONFIG_BPF_SYSCALL) 331262306a36Sopenharmony_cistruct bpf_unix_iter_state { 331362306a36Sopenharmony_ci struct seq_net_private p; 331462306a36Sopenharmony_ci unsigned int cur_sk; 331562306a36Sopenharmony_ci unsigned int end_sk; 331662306a36Sopenharmony_ci unsigned int max_sk; 331762306a36Sopenharmony_ci struct sock **batch; 331862306a36Sopenharmony_ci bool st_bucket_done; 331962306a36Sopenharmony_ci}; 332062306a36Sopenharmony_ci 332162306a36Sopenharmony_cistruct bpf_iter__unix { 332262306a36Sopenharmony_ci __bpf_md_ptr(struct bpf_iter_meta *, meta); 332362306a36Sopenharmony_ci __bpf_md_ptr(struct unix_sock *, unix_sk); 332462306a36Sopenharmony_ci uid_t uid __aligned(8); 332562306a36Sopenharmony_ci}; 332662306a36Sopenharmony_ci 332762306a36Sopenharmony_cistatic int unix_prog_seq_show(struct bpf_prog *prog, struct bpf_iter_meta *meta, 332862306a36Sopenharmony_ci struct unix_sock *unix_sk, uid_t uid) 332962306a36Sopenharmony_ci{ 333062306a36Sopenharmony_ci struct bpf_iter__unix ctx; 333162306a36Sopenharmony_ci 333262306a36Sopenharmony_ci meta->seq_num--; /* skip SEQ_START_TOKEN */ 333362306a36Sopenharmony_ci ctx.meta = meta; 333462306a36Sopenharmony_ci ctx.unix_sk = unix_sk; 333562306a36Sopenharmony_ci ctx.uid = uid; 333662306a36Sopenharmony_ci return bpf_iter_run_prog(prog, &ctx); 333762306a36Sopenharmony_ci} 333862306a36Sopenharmony_ci 333962306a36Sopenharmony_cistatic int bpf_iter_unix_hold_batch(struct seq_file *seq, struct sock *start_sk) 334062306a36Sopenharmony_ci 334162306a36Sopenharmony_ci{ 334262306a36Sopenharmony_ci struct bpf_unix_iter_state *iter = seq->private; 334362306a36Sopenharmony_ci unsigned int expected = 1; 334462306a36Sopenharmony_ci struct sock *sk; 334562306a36Sopenharmony_ci 334662306a36Sopenharmony_ci sock_hold(start_sk); 334762306a36Sopenharmony_ci iter->batch[iter->end_sk++] = start_sk; 334862306a36Sopenharmony_ci 334962306a36Sopenharmony_ci for (sk = sk_next(start_sk); sk; sk = sk_next(sk)) { 335062306a36Sopenharmony_ci if (iter->end_sk < iter->max_sk) { 335162306a36Sopenharmony_ci sock_hold(sk); 335262306a36Sopenharmony_ci iter->batch[iter->end_sk++] = sk; 335362306a36Sopenharmony_ci } 335462306a36Sopenharmony_ci 335562306a36Sopenharmony_ci expected++; 335662306a36Sopenharmony_ci } 335762306a36Sopenharmony_ci 335862306a36Sopenharmony_ci spin_unlock(&seq_file_net(seq)->unx.table.locks[start_sk->sk_hash]); 335962306a36Sopenharmony_ci 336062306a36Sopenharmony_ci return expected; 336162306a36Sopenharmony_ci} 336262306a36Sopenharmony_ci 336362306a36Sopenharmony_cistatic void bpf_iter_unix_put_batch(struct bpf_unix_iter_state *iter) 336462306a36Sopenharmony_ci{ 336562306a36Sopenharmony_ci while (iter->cur_sk < iter->end_sk) 336662306a36Sopenharmony_ci sock_put(iter->batch[iter->cur_sk++]); 336762306a36Sopenharmony_ci} 336862306a36Sopenharmony_ci 336962306a36Sopenharmony_cistatic int bpf_iter_unix_realloc_batch(struct bpf_unix_iter_state *iter, 337062306a36Sopenharmony_ci unsigned int new_batch_sz) 337162306a36Sopenharmony_ci{ 337262306a36Sopenharmony_ci struct sock **new_batch; 337362306a36Sopenharmony_ci 337462306a36Sopenharmony_ci new_batch = kvmalloc(sizeof(*new_batch) * new_batch_sz, 337562306a36Sopenharmony_ci GFP_USER | __GFP_NOWARN); 337662306a36Sopenharmony_ci if (!new_batch) 337762306a36Sopenharmony_ci return -ENOMEM; 337862306a36Sopenharmony_ci 337962306a36Sopenharmony_ci bpf_iter_unix_put_batch(iter); 338062306a36Sopenharmony_ci kvfree(iter->batch); 338162306a36Sopenharmony_ci iter->batch = new_batch; 338262306a36Sopenharmony_ci iter->max_sk = new_batch_sz; 338362306a36Sopenharmony_ci 338462306a36Sopenharmony_ci return 0; 338562306a36Sopenharmony_ci} 338662306a36Sopenharmony_ci 338762306a36Sopenharmony_cistatic struct sock *bpf_iter_unix_batch(struct seq_file *seq, 338862306a36Sopenharmony_ci loff_t *pos) 338962306a36Sopenharmony_ci{ 339062306a36Sopenharmony_ci struct bpf_unix_iter_state *iter = seq->private; 339162306a36Sopenharmony_ci unsigned int expected; 339262306a36Sopenharmony_ci bool resized = false; 339362306a36Sopenharmony_ci struct sock *sk; 339462306a36Sopenharmony_ci 339562306a36Sopenharmony_ci if (iter->st_bucket_done) 339662306a36Sopenharmony_ci *pos = set_bucket_offset(get_bucket(*pos) + 1, 1); 339762306a36Sopenharmony_ci 339862306a36Sopenharmony_ciagain: 339962306a36Sopenharmony_ci /* Get a new batch */ 340062306a36Sopenharmony_ci iter->cur_sk = 0; 340162306a36Sopenharmony_ci iter->end_sk = 0; 340262306a36Sopenharmony_ci 340362306a36Sopenharmony_ci sk = unix_get_first(seq, pos); 340462306a36Sopenharmony_ci if (!sk) 340562306a36Sopenharmony_ci return NULL; /* Done */ 340662306a36Sopenharmony_ci 340762306a36Sopenharmony_ci expected = bpf_iter_unix_hold_batch(seq, sk); 340862306a36Sopenharmony_ci 340962306a36Sopenharmony_ci if (iter->end_sk == expected) { 341062306a36Sopenharmony_ci iter->st_bucket_done = true; 341162306a36Sopenharmony_ci return sk; 341262306a36Sopenharmony_ci } 341362306a36Sopenharmony_ci 341462306a36Sopenharmony_ci if (!resized && !bpf_iter_unix_realloc_batch(iter, expected * 3 / 2)) { 341562306a36Sopenharmony_ci resized = true; 341662306a36Sopenharmony_ci goto again; 341762306a36Sopenharmony_ci } 341862306a36Sopenharmony_ci 341962306a36Sopenharmony_ci return sk; 342062306a36Sopenharmony_ci} 342162306a36Sopenharmony_ci 342262306a36Sopenharmony_cistatic void *bpf_iter_unix_seq_start(struct seq_file *seq, loff_t *pos) 342362306a36Sopenharmony_ci{ 342462306a36Sopenharmony_ci if (!*pos) 342562306a36Sopenharmony_ci return SEQ_START_TOKEN; 342662306a36Sopenharmony_ci 342762306a36Sopenharmony_ci /* bpf iter does not support lseek, so it always 342862306a36Sopenharmony_ci * continue from where it was stop()-ped. 342962306a36Sopenharmony_ci */ 343062306a36Sopenharmony_ci return bpf_iter_unix_batch(seq, pos); 343162306a36Sopenharmony_ci} 343262306a36Sopenharmony_ci 343362306a36Sopenharmony_cistatic void *bpf_iter_unix_seq_next(struct seq_file *seq, void *v, loff_t *pos) 343462306a36Sopenharmony_ci{ 343562306a36Sopenharmony_ci struct bpf_unix_iter_state *iter = seq->private; 343662306a36Sopenharmony_ci struct sock *sk; 343762306a36Sopenharmony_ci 343862306a36Sopenharmony_ci /* Whenever seq_next() is called, the iter->cur_sk is 343962306a36Sopenharmony_ci * done with seq_show(), so advance to the next sk in 344062306a36Sopenharmony_ci * the batch. 344162306a36Sopenharmony_ci */ 344262306a36Sopenharmony_ci if (iter->cur_sk < iter->end_sk) 344362306a36Sopenharmony_ci sock_put(iter->batch[iter->cur_sk++]); 344462306a36Sopenharmony_ci 344562306a36Sopenharmony_ci ++*pos; 344662306a36Sopenharmony_ci 344762306a36Sopenharmony_ci if (iter->cur_sk < iter->end_sk) 344862306a36Sopenharmony_ci sk = iter->batch[iter->cur_sk]; 344962306a36Sopenharmony_ci else 345062306a36Sopenharmony_ci sk = bpf_iter_unix_batch(seq, pos); 345162306a36Sopenharmony_ci 345262306a36Sopenharmony_ci return sk; 345362306a36Sopenharmony_ci} 345462306a36Sopenharmony_ci 345562306a36Sopenharmony_cistatic int bpf_iter_unix_seq_show(struct seq_file *seq, void *v) 345662306a36Sopenharmony_ci{ 345762306a36Sopenharmony_ci struct bpf_iter_meta meta; 345862306a36Sopenharmony_ci struct bpf_prog *prog; 345962306a36Sopenharmony_ci struct sock *sk = v; 346062306a36Sopenharmony_ci uid_t uid; 346162306a36Sopenharmony_ci bool slow; 346262306a36Sopenharmony_ci int ret; 346362306a36Sopenharmony_ci 346462306a36Sopenharmony_ci if (v == SEQ_START_TOKEN) 346562306a36Sopenharmony_ci return 0; 346662306a36Sopenharmony_ci 346762306a36Sopenharmony_ci slow = lock_sock_fast(sk); 346862306a36Sopenharmony_ci 346962306a36Sopenharmony_ci if (unlikely(sk_unhashed(sk))) { 347062306a36Sopenharmony_ci ret = SEQ_SKIP; 347162306a36Sopenharmony_ci goto unlock; 347262306a36Sopenharmony_ci } 347362306a36Sopenharmony_ci 347462306a36Sopenharmony_ci uid = from_kuid_munged(seq_user_ns(seq), sock_i_uid(sk)); 347562306a36Sopenharmony_ci meta.seq = seq; 347662306a36Sopenharmony_ci prog = bpf_iter_get_info(&meta, false); 347762306a36Sopenharmony_ci ret = unix_prog_seq_show(prog, &meta, v, uid); 347862306a36Sopenharmony_ciunlock: 347962306a36Sopenharmony_ci unlock_sock_fast(sk, slow); 348062306a36Sopenharmony_ci return ret; 348162306a36Sopenharmony_ci} 348262306a36Sopenharmony_ci 348362306a36Sopenharmony_cistatic void bpf_iter_unix_seq_stop(struct seq_file *seq, void *v) 348462306a36Sopenharmony_ci{ 348562306a36Sopenharmony_ci struct bpf_unix_iter_state *iter = seq->private; 348662306a36Sopenharmony_ci struct bpf_iter_meta meta; 348762306a36Sopenharmony_ci struct bpf_prog *prog; 348862306a36Sopenharmony_ci 348962306a36Sopenharmony_ci if (!v) { 349062306a36Sopenharmony_ci meta.seq = seq; 349162306a36Sopenharmony_ci prog = bpf_iter_get_info(&meta, true); 349262306a36Sopenharmony_ci if (prog) 349362306a36Sopenharmony_ci (void)unix_prog_seq_show(prog, &meta, v, 0); 349462306a36Sopenharmony_ci } 349562306a36Sopenharmony_ci 349662306a36Sopenharmony_ci if (iter->cur_sk < iter->end_sk) 349762306a36Sopenharmony_ci bpf_iter_unix_put_batch(iter); 349862306a36Sopenharmony_ci} 349962306a36Sopenharmony_ci 350062306a36Sopenharmony_cistatic const struct seq_operations bpf_iter_unix_seq_ops = { 350162306a36Sopenharmony_ci .start = bpf_iter_unix_seq_start, 350262306a36Sopenharmony_ci .next = bpf_iter_unix_seq_next, 350362306a36Sopenharmony_ci .stop = bpf_iter_unix_seq_stop, 350462306a36Sopenharmony_ci .show = bpf_iter_unix_seq_show, 350562306a36Sopenharmony_ci}; 350662306a36Sopenharmony_ci#endif 350762306a36Sopenharmony_ci#endif 350862306a36Sopenharmony_ci 350962306a36Sopenharmony_cistatic const struct net_proto_family unix_family_ops = { 351062306a36Sopenharmony_ci .family = PF_UNIX, 351162306a36Sopenharmony_ci .create = unix_create, 351262306a36Sopenharmony_ci .owner = THIS_MODULE, 351362306a36Sopenharmony_ci}; 351462306a36Sopenharmony_ci 351562306a36Sopenharmony_ci 351662306a36Sopenharmony_cistatic int __net_init unix_net_init(struct net *net) 351762306a36Sopenharmony_ci{ 351862306a36Sopenharmony_ci int i; 351962306a36Sopenharmony_ci 352062306a36Sopenharmony_ci net->unx.sysctl_max_dgram_qlen = 10; 352162306a36Sopenharmony_ci if (unix_sysctl_register(net)) 352262306a36Sopenharmony_ci goto out; 352362306a36Sopenharmony_ci 352462306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS 352562306a36Sopenharmony_ci if (!proc_create_net("unix", 0, net->proc_net, &unix_seq_ops, 352662306a36Sopenharmony_ci sizeof(struct seq_net_private))) 352762306a36Sopenharmony_ci goto err_sysctl; 352862306a36Sopenharmony_ci#endif 352962306a36Sopenharmony_ci 353062306a36Sopenharmony_ci net->unx.table.locks = kvmalloc_array(UNIX_HASH_SIZE, 353162306a36Sopenharmony_ci sizeof(spinlock_t), GFP_KERNEL); 353262306a36Sopenharmony_ci if (!net->unx.table.locks) 353362306a36Sopenharmony_ci goto err_proc; 353462306a36Sopenharmony_ci 353562306a36Sopenharmony_ci net->unx.table.buckets = kvmalloc_array(UNIX_HASH_SIZE, 353662306a36Sopenharmony_ci sizeof(struct hlist_head), 353762306a36Sopenharmony_ci GFP_KERNEL); 353862306a36Sopenharmony_ci if (!net->unx.table.buckets) 353962306a36Sopenharmony_ci goto free_locks; 354062306a36Sopenharmony_ci 354162306a36Sopenharmony_ci for (i = 0; i < UNIX_HASH_SIZE; i++) { 354262306a36Sopenharmony_ci spin_lock_init(&net->unx.table.locks[i]); 354362306a36Sopenharmony_ci INIT_HLIST_HEAD(&net->unx.table.buckets[i]); 354462306a36Sopenharmony_ci } 354562306a36Sopenharmony_ci 354662306a36Sopenharmony_ci return 0; 354762306a36Sopenharmony_ci 354862306a36Sopenharmony_cifree_locks: 354962306a36Sopenharmony_ci kvfree(net->unx.table.locks); 355062306a36Sopenharmony_cierr_proc: 355162306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS 355262306a36Sopenharmony_ci remove_proc_entry("unix", net->proc_net); 355362306a36Sopenharmony_cierr_sysctl: 355462306a36Sopenharmony_ci#endif 355562306a36Sopenharmony_ci unix_sysctl_unregister(net); 355662306a36Sopenharmony_ciout: 355762306a36Sopenharmony_ci return -ENOMEM; 355862306a36Sopenharmony_ci} 355962306a36Sopenharmony_ci 356062306a36Sopenharmony_cistatic void __net_exit unix_net_exit(struct net *net) 356162306a36Sopenharmony_ci{ 356262306a36Sopenharmony_ci kvfree(net->unx.table.buckets); 356362306a36Sopenharmony_ci kvfree(net->unx.table.locks); 356462306a36Sopenharmony_ci unix_sysctl_unregister(net); 356562306a36Sopenharmony_ci remove_proc_entry("unix", net->proc_net); 356662306a36Sopenharmony_ci} 356762306a36Sopenharmony_ci 356862306a36Sopenharmony_cistatic struct pernet_operations unix_net_ops = { 356962306a36Sopenharmony_ci .init = unix_net_init, 357062306a36Sopenharmony_ci .exit = unix_net_exit, 357162306a36Sopenharmony_ci}; 357262306a36Sopenharmony_ci 357362306a36Sopenharmony_ci#if IS_BUILTIN(CONFIG_UNIX) && defined(CONFIG_BPF_SYSCALL) && defined(CONFIG_PROC_FS) 357462306a36Sopenharmony_ciDEFINE_BPF_ITER_FUNC(unix, struct bpf_iter_meta *meta, 357562306a36Sopenharmony_ci struct unix_sock *unix_sk, uid_t uid) 357662306a36Sopenharmony_ci 357762306a36Sopenharmony_ci#define INIT_BATCH_SZ 16 357862306a36Sopenharmony_ci 357962306a36Sopenharmony_cistatic int bpf_iter_init_unix(void *priv_data, struct bpf_iter_aux_info *aux) 358062306a36Sopenharmony_ci{ 358162306a36Sopenharmony_ci struct bpf_unix_iter_state *iter = priv_data; 358262306a36Sopenharmony_ci int err; 358362306a36Sopenharmony_ci 358462306a36Sopenharmony_ci err = bpf_iter_init_seq_net(priv_data, aux); 358562306a36Sopenharmony_ci if (err) 358662306a36Sopenharmony_ci return err; 358762306a36Sopenharmony_ci 358862306a36Sopenharmony_ci err = bpf_iter_unix_realloc_batch(iter, INIT_BATCH_SZ); 358962306a36Sopenharmony_ci if (err) { 359062306a36Sopenharmony_ci bpf_iter_fini_seq_net(priv_data); 359162306a36Sopenharmony_ci return err; 359262306a36Sopenharmony_ci } 359362306a36Sopenharmony_ci 359462306a36Sopenharmony_ci return 0; 359562306a36Sopenharmony_ci} 359662306a36Sopenharmony_ci 359762306a36Sopenharmony_cistatic void bpf_iter_fini_unix(void *priv_data) 359862306a36Sopenharmony_ci{ 359962306a36Sopenharmony_ci struct bpf_unix_iter_state *iter = priv_data; 360062306a36Sopenharmony_ci 360162306a36Sopenharmony_ci bpf_iter_fini_seq_net(priv_data); 360262306a36Sopenharmony_ci kvfree(iter->batch); 360362306a36Sopenharmony_ci} 360462306a36Sopenharmony_ci 360562306a36Sopenharmony_cistatic const struct bpf_iter_seq_info unix_seq_info = { 360662306a36Sopenharmony_ci .seq_ops = &bpf_iter_unix_seq_ops, 360762306a36Sopenharmony_ci .init_seq_private = bpf_iter_init_unix, 360862306a36Sopenharmony_ci .fini_seq_private = bpf_iter_fini_unix, 360962306a36Sopenharmony_ci .seq_priv_size = sizeof(struct bpf_unix_iter_state), 361062306a36Sopenharmony_ci}; 361162306a36Sopenharmony_ci 361262306a36Sopenharmony_cistatic const struct bpf_func_proto * 361362306a36Sopenharmony_cibpf_iter_unix_get_func_proto(enum bpf_func_id func_id, 361462306a36Sopenharmony_ci const struct bpf_prog *prog) 361562306a36Sopenharmony_ci{ 361662306a36Sopenharmony_ci switch (func_id) { 361762306a36Sopenharmony_ci case BPF_FUNC_setsockopt: 361862306a36Sopenharmony_ci return &bpf_sk_setsockopt_proto; 361962306a36Sopenharmony_ci case BPF_FUNC_getsockopt: 362062306a36Sopenharmony_ci return &bpf_sk_getsockopt_proto; 362162306a36Sopenharmony_ci default: 362262306a36Sopenharmony_ci return NULL; 362362306a36Sopenharmony_ci } 362462306a36Sopenharmony_ci} 362562306a36Sopenharmony_ci 362662306a36Sopenharmony_cistatic struct bpf_iter_reg unix_reg_info = { 362762306a36Sopenharmony_ci .target = "unix", 362862306a36Sopenharmony_ci .ctx_arg_info_size = 1, 362962306a36Sopenharmony_ci .ctx_arg_info = { 363062306a36Sopenharmony_ci { offsetof(struct bpf_iter__unix, unix_sk), 363162306a36Sopenharmony_ci PTR_TO_BTF_ID_OR_NULL }, 363262306a36Sopenharmony_ci }, 363362306a36Sopenharmony_ci .get_func_proto = bpf_iter_unix_get_func_proto, 363462306a36Sopenharmony_ci .seq_info = &unix_seq_info, 363562306a36Sopenharmony_ci}; 363662306a36Sopenharmony_ci 363762306a36Sopenharmony_cistatic void __init bpf_iter_register(void) 363862306a36Sopenharmony_ci{ 363962306a36Sopenharmony_ci unix_reg_info.ctx_arg_info[0].btf_id = btf_sock_ids[BTF_SOCK_TYPE_UNIX]; 364062306a36Sopenharmony_ci if (bpf_iter_reg_target(&unix_reg_info)) 364162306a36Sopenharmony_ci pr_warn("Warning: could not register bpf iterator unix\n"); 364262306a36Sopenharmony_ci} 364362306a36Sopenharmony_ci#endif 364462306a36Sopenharmony_ci 364562306a36Sopenharmony_cistatic int __init af_unix_init(void) 364662306a36Sopenharmony_ci{ 364762306a36Sopenharmony_ci int i, rc = -1; 364862306a36Sopenharmony_ci 364962306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct unix_skb_parms) > sizeof_field(struct sk_buff, cb)); 365062306a36Sopenharmony_ci 365162306a36Sopenharmony_ci for (i = 0; i < UNIX_HASH_SIZE / 2; i++) { 365262306a36Sopenharmony_ci spin_lock_init(&bsd_socket_locks[i]); 365362306a36Sopenharmony_ci INIT_HLIST_HEAD(&bsd_socket_buckets[i]); 365462306a36Sopenharmony_ci } 365562306a36Sopenharmony_ci 365662306a36Sopenharmony_ci rc = proto_register(&unix_dgram_proto, 1); 365762306a36Sopenharmony_ci if (rc != 0) { 365862306a36Sopenharmony_ci pr_crit("%s: Cannot create unix_sock SLAB cache!\n", __func__); 365962306a36Sopenharmony_ci goto out; 366062306a36Sopenharmony_ci } 366162306a36Sopenharmony_ci 366262306a36Sopenharmony_ci rc = proto_register(&unix_stream_proto, 1); 366362306a36Sopenharmony_ci if (rc != 0) { 366462306a36Sopenharmony_ci pr_crit("%s: Cannot create unix_sock SLAB cache!\n", __func__); 366562306a36Sopenharmony_ci proto_unregister(&unix_dgram_proto); 366662306a36Sopenharmony_ci goto out; 366762306a36Sopenharmony_ci } 366862306a36Sopenharmony_ci 366962306a36Sopenharmony_ci sock_register(&unix_family_ops); 367062306a36Sopenharmony_ci register_pernet_subsys(&unix_net_ops); 367162306a36Sopenharmony_ci unix_bpf_build_proto(); 367262306a36Sopenharmony_ci 367362306a36Sopenharmony_ci#if IS_BUILTIN(CONFIG_UNIX) && defined(CONFIG_BPF_SYSCALL) && defined(CONFIG_PROC_FS) 367462306a36Sopenharmony_ci bpf_iter_register(); 367562306a36Sopenharmony_ci#endif 367662306a36Sopenharmony_ci 367762306a36Sopenharmony_ciout: 367862306a36Sopenharmony_ci return rc; 367962306a36Sopenharmony_ci} 368062306a36Sopenharmony_ci 368162306a36Sopenharmony_cistatic void __exit af_unix_exit(void) 368262306a36Sopenharmony_ci{ 368362306a36Sopenharmony_ci sock_unregister(PF_UNIX); 368462306a36Sopenharmony_ci proto_unregister(&unix_dgram_proto); 368562306a36Sopenharmony_ci proto_unregister(&unix_stream_proto); 368662306a36Sopenharmony_ci unregister_pernet_subsys(&unix_net_ops); 368762306a36Sopenharmony_ci} 368862306a36Sopenharmony_ci 368962306a36Sopenharmony_ci/* Earlier than device_initcall() so that other drivers invoking 369062306a36Sopenharmony_ci request_module() don't end up in a loop when modprobe tries 369162306a36Sopenharmony_ci to use a UNIX socket. But later than subsys_initcall() because 369262306a36Sopenharmony_ci we depend on stuff initialised there */ 369362306a36Sopenharmony_cifs_initcall(af_unix_init); 369462306a36Sopenharmony_cimodule_exit(af_unix_exit); 369562306a36Sopenharmony_ci 369662306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 369762306a36Sopenharmony_ciMODULE_ALIAS_NETPROTO(PF_UNIX); 3698