cregit-Linux how code gets into the kernel

Release 4.15 net/unix/af_unix.c

Directory: net/unix
/*
 * NET4:        Implementation of BSD Unix domain sockets.
 *
 * Authors:     Alan Cox, <alan@lxorguk.ukuu.org.uk>
 *
 *              This program is free software; you can redistribute it and/or
 *              modify it under the terms of the GNU General Public License
 *              as published by the Free Software Foundation; either version
 *              2 of the License, or (at your option) any later version.
 *
 * Fixes:
 *              Linus Torvalds  :       Assorted bug cures.
 *              Niibe Yutaka    :       async I/O support.
 *              Carsten Paeth   :       PF_UNIX check, address fixes.
 *              Alan Cox        :       Limit size of allocated blocks.
 *              Alan Cox        :       Fixed the stupid socketpair bug.
 *              Alan Cox        :       BSD compatibility fine tuning.
 *              Alan Cox        :       Fixed a bug in connect when interrupted.
 *              Alan Cox        :       Sorted out a proper draft version of
 *                                      file descriptor passing hacked up from
 *                                      Mike Shaver's work.
 *              Marty Leisner   :       Fixes to fd passing
 *              Nick Nevin      :       recvmsg bugfix.
 *              Alan Cox        :       Started proper garbage collector
 *              Heiko EiBfeldt  :       Missing verify_area check
 *              Alan Cox        :       Started POSIXisms
 *              Andreas Schwab  :       Replace inode by dentry for proper
 *                                      reference counting
 *              Kirk Petersen   :       Made this a module
 *          Christoph Rohland   :       Elegant non-blocking accept/connect algorithm.
 *                                      Lots of bug fixes.
 *           Alexey Kuznetosv   :       Repaired (I hope) bugs introduces
 *                                      by above two patches.
 *           Andrea Arcangeli   :       If possible we block in connect(2)
 *                                      if the max backlog of the listen socket
 *                                      is been reached. This won't break
 *                                      old apps and it will avoid huge amount
 *                                      of socks hashed (this for unix_gc()
 *                                      performances reasons).
 *                                      Security fix that limits the max
 *                                      number of socks to 2*max_files and
 *                                      the number of skb queueable in the
 *                                      dgram receiver.
 *              Artur Skawina   :       Hash function optimizations
 *           Alexey Kuznetsov   :       Full scale SMP. Lot of bugs are introduced 8)
 *            Malcolm Beattie   :       Set peercred for socketpair
 *           Michal Ostrowski   :       Module initialization cleanup.
 *           Arnaldo C. Melo    :       Remove MOD_{INC,DEC}_USE_COUNT,
 *                                      the core infrastructure is doing that
 *                                      for all net proto families now (2.5.69+)
 *
 *
 * Known differences from reference BSD that was tested:
 *
 *      [TO FIX]
 *      ECONNREFUSED is not returned from one end of a connected() socket to the
 *              other the moment one end closes.
 *      fstat() doesn't return st_dev=0, and give the blksize as high water mark
 *              and a fake inode identifier (nor the BSD first socket fstat twice bug).
 *      [NOT TO FIX]
 *      accept() returns a path name even if the connecting socket has closed
 *              in the meantime (BSD loses the path and gives up).
 *      accept() returns 0 length path for an unbound connector. BSD returns 16
 *              and a null first byte in the path (but not for gethost/peername - BSD bug ??)
 *      socketpair(...SOCK_RAW..) doesn't panic the kernel.
 *      BSD af_unix apparently has connect forgetting to block properly.
 *              (need to check this with the POSIX spec in detail)
 *
 * Differences from 2.0.0-11-... (ANK)
 *      Bug fixes and improvements.
 *              - client shutdown killed server socket.
 *              - removed all useless cli/sti pairs.
 *
 *      Semantic changes/extensions.
 *              - generic control message passing.
 *              - SCM_CREDENTIALS control message.
 *              - "Abstract" (not FS based) socket bindings.
 *                Abstract names are sequences of bytes (not zero terminated)
 *                started by 0, so that this name space does not intersect
 *                with BSD names.
 */


#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/sched/signal.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/stat.h>
#include <linux/dcache.h>
#include <linux/namei.h>
#include <linux/socket.h>
#include <linux/un.h>
#include <linux/fcntl.h>
#include <linux/termios.h>
#include <linux/sockios.h>
#include <linux/net.h>
#include <linux/in.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <net/net_namespace.h>
#include <net/sock.h>
#include <net/tcp_states.h>
#include <net/af_unix.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <net/scm.h>
#include <linux/init.h>
#include <linux/poll.h>
#include <linux/rtnetlink.h>
#include <linux/mount.h>
#include <net/checksum.h>
#include <linux/security.h>
#include <linux/freezer.h>
#include <linux/file.h>


struct hlist_head unix_socket_table[2 * UNIX_HASH_SIZE];

EXPORT_SYMBOL_GPL(unix_socket_table);

DEFINE_SPINLOCK(unix_table_lock);

EXPORT_SYMBOL_GPL(unix_table_lock);

static atomic_long_t unix_nr_socks;



static struct hlist_head *unix_sockets_unbound(void *addr) { unsigned long hash = (unsigned long)addr; hash ^= hash >> 16; hash ^= hash >> 8; hash %= UNIX_HASH_SIZE; return &unix_socket_table[UNIX_HASH_SIZE + hash]; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Dumazet4697.87%150.00%
Linus Torvalds (pre-git)12.13%150.00%
Total47100.00%2100.00%

#define UNIX_ABSTRACT(sk) (unix_sk(sk)->addr->hash < UNIX_HASH_SIZE) #ifdef CONFIG_SECURITY_NETWORK
static void unix_get_secdata(struct scm_cookie *scm, struct sk_buff *skb) { UNIXCB(skb).secid = scm->secid; }

Contributors

PersonTokensPropCommitsCommitProp
Catherine Zhang2385.19%266.67%
Stephen D. Smalley414.81%133.33%
Total27100.00%3100.00%


static inline void unix_set_secdata(struct scm_cookie *scm, struct sk_buff *skb) { scm->secid = UNIXCB(skb).secid; }

Contributors

PersonTokensPropCommitsCommitProp
Catherine Zhang2589.29%266.67%
Stephen D. Smalley310.71%133.33%
Total28100.00%3100.00%


static inline bool unix_secdata_eq(struct scm_cookie *scm, struct sk_buff *skb) { return (scm->secid == UNIXCB(skb).secid); }

Contributors

PersonTokensPropCommitsCommitProp
Stephen D. Smalley31100.00%1100.00%
Total31100.00%1100.00%

#else
static inline void unix_get_secdata(struct scm_cookie *scm, struct sk_buff *skb) { }

Contributors

PersonTokensPropCommitsCommitProp
Catherine Zhang1593.75%266.67%
Andrew Morton16.25%133.33%
Total16100.00%3100.00%


static inline void unix_set_secdata(struct scm_cookie *scm, struct sk_buff *skb) { }

Contributors

PersonTokensPropCommitsCommitProp
Catherine Zhang16100.00%1100.00%
Total16100.00%1100.00%


static inline bool unix_secdata_eq(struct scm_cookie *scm, struct sk_buff *skb) { return true; }

Contributors

PersonTokensPropCommitsCommitProp
Stephen D. Smalley20100.00%1100.00%
Total20100.00%1100.00%

#endif /* CONFIG_SECURITY_NETWORK */ /* * SMP locking strategy: * hash table is protected with spinlock unix_table_lock * each socket state is protected by separate spin lock. */
static inline unsigned int unix_hash_fold(__wsum n) { unsigned int hash = (__force unsigned int)csum_fold(n); hash ^= hash>>8; return hash&(UNIX_HASH_SIZE-1); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)2152.50%342.86%
Al Viro1127.50%114.29%
Eric Dumazet37.50%114.29%
Anton Blanchard37.50%114.29%
Linus Torvalds25.00%114.29%
Total40100.00%7100.00%

#define unix_peer(sk) (unix_sk(sk)->peer)
static inline int unix_our_peer(struct sock *sk, struct sock *osk) { return unix_peer(osk) == sk; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)1976.00%250.00%
Arnaldo Carvalho de Melo416.00%125.00%
Linus Torvalds28.00%125.00%
Total25100.00%4100.00%


static inline int unix_may_send(struct sock *sk, struct sock *osk) { return unix_peer(osk) == NULL || unix_our_peer(sk, osk); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)2681.25%571.43%
Arnaldo Carvalho de Melo412.50%114.29%
Linus Torvalds26.25%114.29%
Total32100.00%7100.00%


static inline int unix_recvq_full(struct sock const *sk) { return skb_queue_len(&sk->sk_receive_queue) > sk->sk_max_ack_backlog; }

Contributors

PersonTokensPropCommitsCommitProp
Rainer Weikusat26100.00%1100.00%
Total26100.00%1100.00%


struct sock *unix_peer_get(struct sock *s) { struct sock *peer; unix_state_lock(s); peer = unix_peer(s); if (peer) sock_hold(peer); unix_state_unlock(s); return peer; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)3882.61%675.00%
Arnaldo Carvalho de Melo613.04%112.50%
David S. Miller24.35%112.50%
Total46100.00%8100.00%

EXPORT_SYMBOL_GPL(unix_peer_get);
static inline void unix_release_addr(struct unix_address *addr) { if (refcount_dec_and_test(&addr->refcnt)) kfree(addr); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)2488.89%240.00%
Elena Reshetova13.70%120.00%
David S. Miller13.70%120.00%
Linus Torvalds13.70%120.00%
Total27100.00%5100.00%

/* * Check unix socket name: * - should be not zero length. * - if started by not zero, should be NULL terminated (FS object) * - if started by zero, it is abstract name. */
static int unix_mkname(struct sockaddr_un *sunaddr, int len, unsigned int *hashp) { if (len <= sizeof(short) || len > sizeof(*sunaddr)) return -EINVAL; if (!sunaddr || sunaddr->sun_family != AF_UNIX) return -EINVAL; if (sunaddr->sun_path[0]) { /* * This may look like an off by one error but it is a bit more * subtle. 108 is the longest valid AF_UNIX path for a binding. * sun_path[108] doesn't as such exist. However in kernel space * we are guaranteed that it is a valid memory location in our * kernel address buffer. */ ((char *)sunaddr)[len] = 0; len = strlen(sunaddr->sun_path)+1+sizeof(short); return len; } *hashp = unix_hash_fold(csum_partial(sunaddr, len, 0)); return len; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)11598.29%250.00%
Lucas De Marchi10.85%125.00%
Eric Dumazet10.85%125.00%
Total117100.00%4100.00%


static void __unix_remove_socket(struct sock *sk) { sk_del_node_init(sk); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)1168.75%360.00%
Arnaldo Carvalho de Melo531.25%240.00%
Total16100.00%5100.00%


static void __unix_insert_socket(struct hlist_head *list, struct sock *sk) { WARN_ON(!sk_unhashed(sk)); sk_add_node(sk, list); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)1959.38%342.86%
Arnaldo Carvalho de Melo1031.25%228.57%
Ilpo Järvinen26.25%114.29%
David S. Miller13.12%114.29%
Total32100.00%7100.00%


static inline void unix_remove_socket(struct sock *sk) { spin_lock(&unix_table_lock); __unix_remove_socket(sk); spin_unlock(&unix_table_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)2482.76%240.00%
David S. Miller26.90%120.00%
Arnaldo Carvalho de Melo26.90%120.00%
Linus Torvalds13.45%120.00%
Total29100.00%5100.00%


static inline void unix_insert_socket(struct hlist_head *list, struct sock *sk) { spin_lock(&unix_table_lock); __unix_insert_socket(list, sk); spin_unlock(&unix_table_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)2980.56%233.33%
Arnaldo Carvalho de Melo411.11%233.33%
David S. Miller25.56%116.67%
Linus Torvalds12.78%116.67%
Total36100.00%6100.00%


static struct sock *__unix_find_socket_byname(struct net *net, struct sockaddr_un *sunname, int len, int type, unsigned int hash) { struct sock *s; sk_for_each(s, &unix_socket_table[hash ^ type]) { struct unix_sock *u = unix_sk(s); if (!net_eq(sock_net(s), net)) continue; if (u->addr->len == len && !memcmp(u->addr->name, sunname, len)) goto found; } s = NULL; found: return s; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)4847.52%330.00%
Arnaldo Carvalho de Melo1918.81%220.00%
David S. Miller1413.86%110.00%
Denis V. Lunev1110.89%110.00%
Hideaki Yoshifuji / 吉藤英明87.92%220.00%
Eric Dumazet10.99%110.00%
Total101100.00%10100.00%


static inline struct sock *unix_find_socket_byname(struct net *net, struct sockaddr_un *sunname, int len, int type, unsigned int hash) { struct sock *s; spin_lock(&unix_table_lock); s = __unix_find_socket_byname(net, sunname, len, type, hash); if (s) sock_hold(s); spin_unlock(&unix_table_lock); return s; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)5879.45%337.50%
Denis V. Lunev79.59%112.50%
Arnaldo Carvalho de Melo45.48%112.50%
David S. Miller22.74%112.50%
Eric Dumazet11.37%112.50%
Linus Torvalds11.37%112.50%
Total73100.00%8100.00%


static struct sock *unix_find_socket_byinode(struct inode *i) { struct sock *s; spin_lock(&unix_table_lock); sk_for_each(s, &unix_socket_table[i->i_ino & (UNIX_HASH_SIZE - 1)]) { struct dentry *dentry = unix_sk(s)->path.dentry; if (dentry && d_backing_inode(dentry) == i) { sock_hold(s); goto found; } } s = NULL; found: spin_unlock(&unix_table_lock); return s; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)5464.29%436.36%
Arnaldo Carvalho de Melo2023.81%218.18%
David S. Miller55.95%218.18%
Al Viro22.38%19.09%
David Howells22.38%19.09%
Miklos Szeredi11.19%19.09%
Total84100.00%11100.00%

/* Support code for asymmetrically connected dgram sockets * * If a datagram socket is connected to a socket not itself connected * to the first socket (eg, /dev/log), clients may only enqueue more * messages if the present receive queue of the server socket is not * "too large". This means there's a second writeability condition * poll and sendmsg need to test. The dgram recv code will do a wake * up on the peer_wait wait queue of a socket upon reception of a * datagram which needs to be propagated to sleeping would-be writers * since these might not have sent anything so far. This can't be * accomplished via poll_wait because the lifetime of the server * socket might be less than that of its clients if these break their * association with it or if the server socket is closed while clients * are still connected to it and there's no way to inform "a polling * implementation" that it should let go of a certain wait queue * * In order to propagate a wake up, a wait_queue_entry_t of the client * socket is enqueued on the peer_wait queue of the server socket * whose wake function does a wake_up on the ordinary client socket * wait queue. This connection is established whenever a write (or * poll for write) hit the flow control condition and broken when the * association to the server socket is dissolved or after a wake up * was relayed. */
static int unix_dgram_peer_wake_relay(wait_queue_entry_t *q, unsigned mode, int flags, void *key) { struct unix_sock *u; wait_queue_head_t *u_sleep; u = container_of(q, struct unix_sock, peer_wake); __remove_wait_queue(&unix_sk(u->peer_wake.private)->peer_wait, q); u->peer_wake.private = NULL; /* relaying can only happen while the wq still exists */ u_sleep = sk_sleep(&u->sk); if (u_sleep) wake_up_interruptible_poll(u_sleep, key); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Rainer Weikusat9098.90%150.00%
Ingo Molnar11.10%150.00%
Total91100.00%2100.00%


static int unix_dgram_peer_wake_connect(struct sock *sk, struct sock *other) { struct unix_sock *u, *u_other; int rc; u = unix_sk(sk); u_other = unix_sk(other); rc = 0; spin_lock(&u_other->peer_wait.lock); if (!u->peer_wake.private) { u->peer_wake.private = other; __add_wait_queue(&u_other->peer_wait, &u->peer_wake); rc = 1; } spin_unlock(&u_other->peer_wait.lock); return rc; }

Contributors

PersonTokensPropCommitsCommitProp
Rainer Weikusat104100.00%1100.00%
Total104100.00%1100.00%


static void unix_dgram_peer_wake_disconnect(struct sock *sk, struct sock *other) { struct unix_sock *u, *u_other; u = unix_sk(sk); u_other = unix_sk(other); spin_lock(&u_other->peer_wait.lock); if (u->peer_wake.private == other) { __remove_wait_queue(&u_other->peer_wait, &u->peer_wake); u->peer_wake.private = NULL; } spin_unlock(&u_other->peer_wait.lock); }

Contributors

PersonTokensPropCommitsCommitProp
Rainer Weikusat91100.00%1100.00%
Total91100.00%1100.00%


static void unix_dgram_peer_wake_disconnect_wakeup(struct sock *sk, struct sock *other) { unix_dgram_peer_wake_disconnect(sk, other); wake_up_interruptible_poll(sk_sleep(sk), POLLOUT | POLLWRNORM | POLLWRBAND); }

Contributors

PersonTokensPropCommitsCommitProp
Rainer Weikusat37100.00%1100.00%
Total37100.00%1100.00%

/* preconditions: * - unix_peer(sk) == other * - association is stable */
static int unix_dgram_peer_wake_me(struct sock *sk, struct sock *other) { int connected; connected = unix_dgram_peer_wake_connect(sk, other); if (unix_recvq_full(other)) return 1; if (connected) unix_dgram_peer_wake_disconnect(sk, other); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Rainer Weikusat52100.00%1100.00%
Total52100.00%1100.00%


static int unix_writable(const struct sock *sk) { return sk->sk_state != TCP_LISTEN && (refcount_read(&sk->sk_wmem_alloc) << 2) <= sk->sk_sndbuf; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)2571.43%350.00%
Eric Dumazet720.00%116.67%
Arnaldo Carvalho de Melo25.71%116.67%
Elena Reshetova12.86%116.67%
Total35100.00%6100.00%


static void unix_write_space(struct sock *sk) { struct socket_wq *wq; rcu_read_lock(); if (unix_writable(sk)) { wq = rcu_dereference(sk->sk_wq); if (skwq_has_sleeper(wq)) wake_up_interruptible_sync_poll(&wq->wait, POLLOUT | POLLWRNORM | POLLWRBAND); sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT); } rcu_read_unlock(); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)3854.29%763.64%
Eric Dumazet3042.86%218.18%
Pavel Emelyanov11.43%19.09%
Herbert Xu11.43%19.09%
Total70100.00%11100.00%

/* When dgram socket disconnects (or changes its peer), we clear its receive * queue of packets arrived from previous peer. First, it allows to do * flow control based only on wmem_alloc; second, sk connected to peer * may receive messages only from that peer. */
static void unix_dgram_disconnected(struct sock *sk, struct sock *other) { if (!skb_queue_empty(&sk->sk_receive_queue)) { skb_queue_purge(&sk->sk_receive_queue); wake_up_interruptible_all(&unix_sk(sk)->peer_wait); /* If one link of bidirectional dgram pipe is disconnected, * we signal error. Messages are lost. Do not make this, * when peer was not connected to us. */ if (!sock_flag(other, SOCK_DEAD) && unix_peer(other) == sk) { other->sk_err = ECONNRESET; other->sk_error_report(other); } } }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)6782.72%116.67%
Arnaldo Carvalho de Melo78.64%233.33%
David S. Miller56.17%233.33%
James Morris22.47%116.67%
Total81100.00%6100.00%


static void unix_sock_destructor(struct sock *sk) { struct unix_sock *u = unix_sk(sk); skb_queue_purge(&sk->sk_receive_queue); WARN_ON(refcount_read(&sk->sk_wmem_alloc)); WARN_ON(!sk_unhashed(sk)); WARN_ON(sk->sk_socket); if (!sock_flag(sk, SOCK_DEAD)) { pr_info("Attempt to release alive unix socket: %p\n", sk); return; } if (u->addr) unix_release_addr(u->addr); atomic_long_dec(&unix_nr_socks); local_bh_disable(); sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); local_bh_enable(); #ifdef UNIX_REFCNT_DEBUG pr_debug("UNIX %p is destroyed, %ld are still alive.\n", sk, atomic_long_read(&unix_nr_socks)); #endif }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)7858.21%426.67%
Eric Dumazet1813.43%213.33%
David S. Miller1813.43%213.33%
Arnaldo Carvalho de Melo107.46%320.00%
Ilpo Järvinen42.99%16.67%
James Morris32.24%16.67%
Wang Weidong21.49%16.67%
Elena Reshetova10.75%16.67%
Total134100.00%15100.00%


static void unix_release_sock(struct sock *sk, int embrion) { struct unix_sock *u = unix_sk(sk); struct path path; struct sock *skpair; struct sk_buff *skb; int state; unix_remove_socket(sk); /* Clear state */ unix_state_lock(sk); sock_orphan(sk); sk->sk_shutdown = SHUTDOWN_MASK; path = u->path; u->path.dentry = NULL; u->path.mnt = NULL; state = sk->sk_state; sk->sk_state = TCP_CLOSE; unix_state_unlock(sk); wake_up_interruptible_all(&u->peer_wait); skpair = unix_peer(sk); if (skpair != NULL) { if (sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_SEQPACKET) { unix_state_lock(skpair); /* No more writes */ skpair->sk_shutdown = SHUTDOWN_MASK; if (!skb_queue_empty(&sk->sk_receive_queue) || embrion) skpair->sk_err = ECONNRESET; unix_state_unlock(skpair); skpair->sk_state_change(skpair); sk_wake_async(skpair, SOCK_WAKE_WAITD, POLL_HUP); } unix_dgram_peer_wake_disconnect(sk, skpair); sock_put(skpair); /* It may now die */ unix_peer(sk) = NULL; } /* Try to flush out this socket. Throw out buffers at least */ while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { if (state == TCP_LISTEN) unix_release_sock(skb->sk, 1); /* passed fds are erased in the kfree_skb hook */ UNIXCB(skb).consumed = skb->len; kfree_skb(skb); } if (path.dentry) path_put(&path); sock_put(sk); /* ---- Socket is dead now and most probably destroyed ---- */ /* * Fixme: BSD difference: In BSD all sockets connected to us get * ECONNRESET and we die on the spot. In Linux we behave * like files and pipes do and wait for the last * dereference. * * Can't we simply set sock->err? * * What the above comment does talk about? --ANK(980817) */ if (unix_tot_inflight) unix_gc(); /* Garbage collect fds */ }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)21975.26%1150.00%
David S. Miller186.19%29.09%
Arnaldo Carvalho de Melo144.81%29.09%
Al Viro134.47%14.55%
Hannes Frederic Sowa113.78%14.55%
Rainer Weikusat72.41%14.55%
Steven Dake62.06%14.55%
Paul Moore10.34%14.55%
Alan Cox10.34%14.55%
Pavel Emelyanov10.34%14.55%
Total291100.00%22100.00%


static void init_peercred(struct sock *sk) { put_pid(sk->sk_peer_pid); if (sk->sk_peer_cred) put_cred(sk->sk_peer_cred); sk->sk_peer_pid = get_pid(task_tgid(current)); sk->sk_peer_cred = get_current_cred(); }

Contributors

PersonTokensPropCommitsCommitProp
Eric W. Biedermann50100.00%1100.00%
Total50100.00%1100.00%


static void copy_peercred(struct sock *sk, struct sock *peersk) { put_pid(sk->sk_peer_pid); if (sk->sk_peer_cred) put_cred(sk->sk_peer_cred); sk->sk_peer_pid = get_pid(peersk->sk_peer_pid); sk->sk_peer_cred = get_cred(peersk->sk_peer_cred); }

Contributors

PersonTokensPropCommitsCommitProp
Eric W. Biedermann58100.00%1100.00%
Total58100.00%1100.00%


static int unix_listen(struct socket *sock, int backlog) { int err; struct sock *sk = sock->sk; struct unix_sock *u = unix_sk(sk); struct pid *old_pid = NULL; err = -EOPNOTSUPP; if (sock->type != SOCK_STREAM && sock->type != SOCK_SEQPACKET) goto out; /* Only stream/seqpacket sockets accept */ err = -EINVAL; if (!u->addr) goto out; /* No listens on an unbound socket */ unix_state_lock(sk); if (sk->sk_state != TCP_CLOSE && sk->sk_state != TCP_LISTEN) goto out_unlock; if (backlog > sk->sk_max_ack_backlog) wake_up_interruptible_all(&u->peer_wait); sk->sk_max_ack_backlog = backlog; sk->sk_state = TCP_LISTEN; /* set credentials so connect can copy them */ init_peercred(sk); err = 0; out_unlock: unix_state_unlock(sk); put_pid(old_pid); out: return err; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)11874.21%750.00%
David S. Miller148.81%214.29%
Eric W. Biedermann138.18%17.14%
Steven Dake74.40%17.14%
Arnaldo Carvalho de Melo53.14%17.14%
Pavel Emelyanov10.63%17.14%
David Howells10.63%17.14%
Total159100.00%14100.00%

static int unix_release(struct socket *); static int unix_bind(struct socket *, struct sockaddr *, int); static int unix_stream_connect(struct socket *, struct sockaddr *, int addr_len, int flags); static int unix_socketpair(struct socket *, struct socket *); static int unix_accept(struct socket *, struct socket *, int, bool); static int unix_getname(struct socket *, struct sockaddr *, int *, int); static unsigned int unix_poll(struct file *, struct socket *, poll_table *); static unsigned int unix_dgram_poll(struct file *, struct socket *, poll_table *); static int unix_ioctl(struct socket *, unsigned int, unsigned long); static int unix_shutdown(struct socket *, int); static int unix_stream_sendmsg(struct socket *, struct msghdr *, size_t); static int unix_stream_recvmsg(struct socket *, struct msghdr *, size_t, int); static ssize_t unix_stream_sendpage(struct socket *, struct page *, int offset, size_t size, int flags); static ssize_t unix_stream_splice_read(struct socket *, loff_t *ppos, struct pipe_inode_info *, size_t size, unsigned int flags); static int unix_dgram_sendmsg(struct socket *, struct msghdr *, size_t); static int unix_dgram_recvmsg(struct socket *, struct msghdr *, size_t, int); static int unix_dgram_connect(struct socket *, struct sockaddr *, int, int); static int unix_seqpacket_sendmsg(struct socket *, struct msghdr *, size_t); static int unix_seqpacket_recvmsg(struct socket *, struct msghdr *, size_t, int);
static int unix_set_peek_off(struct sock *sk, int val) { struct unix_sock *u = unix_sk(sk); if (mutex_lock_interruptible(&u->iolock)) return -EINTR; sk->sk_peek_off = val; mutex_unlock(&u->iolock); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Pavel Emelyanov4174.55%133.33%
Sasha Levin1221.82%133.33%
Linus Torvalds23.64%133.33%
Total55100.00%3100.00%

static const struct proto_ops unix_stream_ops = { .family = PF_UNIX, .owner = THIS_MODULE, .release = unix_release, .bind = unix_bind, .connect = unix_stream_connect, .socketpair = unix_socketpair, .accept = unix_accept, .getname = unix_getname, .poll = unix_poll, .ioctl = unix_ioctl, .listen = unix_listen, .shutdown = unix_shutdown, .setsockopt = sock_no_setsockopt, .getsockopt = sock_no_getsockopt, .sendmsg = unix_stream_sendmsg, .recvmsg = unix_stream_recvmsg, .mmap = sock_no_mmap, .sendpage = unix_stream_sendpage, .splice_read = unix_stream_splice_read, .set_peek_off = unix_set_peek_off, }; static const struct proto_ops unix_dgram_ops = { .family = PF_UNIX, .owner = THIS_MODULE, .release = unix_release, .bind = unix_bind, .connect = unix_dgram_connect, .socketpair = unix_socketpair, .accept = sock_no_accept, .getname = unix_getname, .poll = unix_dgram_poll, .ioctl = unix_ioctl, .listen = sock_no_listen, .shutdown = unix_shutdown, .setsockopt = sock_no_setsockopt, .getsockopt = sock_no_getsockopt, .sendmsg = unix_dgram_sendmsg, .recvmsg = unix_dgram_recvmsg, .mmap = sock_no_mmap, .sendpage = sock_no_sendpage, .set_peek_off = unix_set_peek_off, }; static const struct proto_ops unix_seqpacket_ops = { .family = PF_UNIX, .owner = THIS_MODULE, .release = unix_release, .bind = unix_bind, .connect = unix_stream_connect, .socketpair = unix_socketpair, .accept = unix_accept, .getname = unix_getname, .poll = unix_dgram_poll, .ioctl = unix_ioctl, .listen = unix_listen, .shutdown = unix_shutdown, .setsockopt = sock_no_setsockopt, .getsockopt = sock_no_getsockopt, .sendmsg = unix_seqpacket_sendmsg, .recvmsg = unix_seqpacket_recvmsg, .mmap = sock_no_mmap, .sendpage = sock_no_sendpage, .set_peek_off = unix_set_peek_off, }; static struct proto unix_proto = { .name = "UNIX", .owner = THIS_MODULE, .obj_size = sizeof(struct unix_sock), }; /* * AF_UNIX sockets do not interact with hardware, hence they * dont trigger interrupts - so it's safe for them to have * bh-unsafe locking for their sk_receive_queue.lock. Split off * this special lock-class by reinitializing the spinlock key: */ static struct lock_class_key af_unix_sk_receive_queue_lock_key;
static struct sock *unix_create1(struct net *net, struct socket *sock, int kern) { struct sock *sk = NULL; struct unix_sock *u; atomic_long_inc(&unix_nr_socks); if (atomic_long_read(&unix_nr_socks) > 2 * get_max_files()) goto out; sk = sk_alloc(net, PF_UNIX, GFP_KERNEL, &unix_proto, kern); if (!sk) goto out; sock_init_data(sock, sk); lockdep_set_class(&sk->sk_receive_queue.lock, &af_unix_sk_receive_queue_lock_key); sk->sk_allocation = GFP_KERNEL_ACCOUNT; sk->sk_write_space = unix_write_space; sk->sk_max_ack_backlog = net->unx.sysctl_max_dgram_qlen; sk->sk_destruct = unix_sock_destructor; u = unix_sk(sk); u->path.dentry = NULL; u->path.mnt = NULL; spin_lock_init(&u->lock); atomic_long_set(&u->inflight, 0); INIT_LIST_HEAD(&u->link); mutex_init(&u->iolock); /* single task reading lock */ mutex_init(&u->bindlock); /* single task binding lock */ init_waitqueue_head(&u->peer_wait); init_waitqueue_func_entry(&u->peer_wake, unix_dgram_peer_wake_relay); unix_insert_socket(unix_sockets_unbound(sk), sk); out: if (sk == NULL) atomic_long_dec(&unix_nr_socks); else { local_bh_disable(); sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); local_bh_enable(); } return sk; }

Contributors

PersonTokensPropCommitsCommitProp
David S. Miller14153.82%14.76%
Eric Dumazet2911.07%419.05%
Pavel Emelyanov197.25%29.52%
Ingo Molnar145.34%29.52%
Eric W. Biedermann124.58%29.52%
Linus Torvalds103.82%14.76%
Rainer Weikusat103.82%14.76%
Miklos Szeredi83.05%14.76%
Vladimir Davydov62.29%14.76%
Al Viro51.91%29.52%
Denis V. Lunev31.15%14.76%
Dipankar Sarma20.76%14.76%
Arnaldo Carvalho de Melo20.76%14.76%
Benjamin LaHaise10.38%14.76%
Total262100.00%21100.00%


static int unix_create(struct net *net, struct socket *sock, int protocol, int kern) { if (protocol && protocol != PF_UNIX) return -EPROTONOSUPPORT; sock->state = SS_UNCONNECTED; switch (sock->type) { case SOCK_STREAM: sock->ops = &unix_stream_ops; break; /* * Believe it or not BSD has AF_UNIX, SOCK_RAW though * nothing uses it. */ case SOCK_RAW: sock->type = SOCK_DGRAM; /* fall through */ case SOCK_DGRAM: sock->ops = &unix_dgram_ops; break; case SOCK_SEQPACKET: sock->ops = &unix_seqpacket_ops; break; default: return -ESOCKTNOSUPPORT; } return unix_create1(net, sock, kern) ? 0 : -ENOMEM; }

Contributors

PersonTokensPropCommitsCommitProp
David S. Miller9988.39%120.00%
Eric W. Biedermann98.04%240.00%
Eric Paris32.68%120.00%
Gustavo A. R. Silva10.89%120.00%
Total112100.00%5100.00%


static int unix_release(struct socket *sock) { struct sock *sk = sock->sk; if (!sk) return 0; unix_release_sock(sk, 0); sock->sk = NULL; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
David S. Miller3784.09%150.00%
Paul Moore715.91%150.00%
Total44100.00%2100.00%


static int unix_autobind(struct socket *sock) { struct sock *sk = sock->sk; struct net *net = sock_net(sk); struct unix_sock *u = unix_sk(sk); static u32 ordernum = 1; struct unix_address *addr; int err; unsigned int retries = 0; err = mutex_lock_interruptible(&u->bindlock); if (err) return err; err = 0; if (u->addr) goto out; err = -ENOMEM; addr = kzalloc(sizeof(*addr) + sizeof(short) + 16, GFP_KERNEL); if (!addr) goto out; addr->name->sun_family = AF_UNIX; refcount_set(&addr->refcnt, 1); retry: addr->len = sprintf(addr->name->sun_path+1, "%05x", ordernum) + 1 + sizeof(short); addr->hash = unix_hash_fold(csum_partial(addr->name, addr->len, 0)); spin_lock(&unix_table_lock); ordernum = (ordernum+1)&0xFFFFF; if (__unix_find_socket_byname(net, addr->name, addr->len, sock->type, addr->hash)) { spin_unlock(&unix_table_lock); /* * __unix_find_socket_byname() may take long time if many names * are already in use. */ cond_resched(); /* Give up if all names seems to be in use. */ if (retries++ == 0xFFFFF) { err = -ENOSPC; kfree(addr); goto out; } goto retry; } addr->hash ^= sk->sk_type; __unix_remove_socket(sk); u->addr = addr; __unix_insert_socket(&unix_socket_table[addr->hash], sk); spin_unlock(&unix_table_lock); err = 0; out: mutex_unlock(&u->bindlock); return err; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)20363.24%736.84%
David S. Miller6119.00%315.79%
Tetsuo Handa299.03%15.26%
Sasha Levin103.12%15.26%
Denis V. Lunev92.80%15.26%
Hideaki Yoshifuji / 吉藤英明30.93%15.26%
Linus Torvalds20.62%15.26%
Ingo Molnar10.31%15.26%
Panagiotis Issaris10.31%15.26%
Elena Reshetova10.31%15.26%
Arnaldo Carvalho de Melo10.31%15.26%
Total321100.00%19100.00%


static struct sock *unix_find_other(struct net *net, struct sockaddr_un *sunname, int len, int type, unsigned int hash, int *error) { struct sock *u; struct path path; int err = 0; if (sunname->sun_path[0]) { struct inode *inode; err = kern_path(sunname->sun_path, LOOKUP_FOLLOW, &path); if (err) goto fail; inode = d_backing_inode(path.dentry); err = inode_permission(inode, MAY_WRITE); if (err) goto put_fail; err = -ECONNREFUSED; if (!S_ISSOCK(inode->i_mode)) goto put_fail; u = unix_find_socket_byinode(inode); if (!u) goto put_fail; if (u->sk_type == type) touch_atime(&path); path_put(&path); err = -EPROTOTYPE; if (u->sk_type != type) { sock_put(u); goto fail; } } else { err = -ECONNREFUSED; u = unix_find_socket_byname(net, sunname, len, type, hash); if (u) { struct dentry *dentry; dentry = unix_sk(u)->path.dentry; if (dentry) touch_atime(&unix_sk(u)->path); } else goto fail; } return u; put_fail: path_put(&path); fail: *error = err; return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)18066.91%731.82%
Al Viro3211.90%522.73%
Solar Designer3211.90%14.55%
Denis V. Lunev72.60%14.55%
Arnaldo Carvalho de Melo62.23%29.09%
Jan Blunck51.86%29.09%
David S. Miller31.12%14.55%
David Howells20.74%14.55%
Eric Dumazet10.37%14.55%
Miklos Szeredi10.37%14.55%
Total269100.00%22100.00%


static int unix_mknod(const char *sun_path, umode_t mode, struct path *res) { struct dentry *dentry; struct path path; int err = 0; /* * Get the parent directory, calculate the hash for last * component. */ dentry = kern_path_create(AT_FDCWD, sun_path, &path, 0); err = PTR_ERR(dentry); if (IS_ERR(dentry)) return err; /* * All right, let's create it. */ err = security_path_mknod(&path, dentry, mode, 0); if (!err) { err = vfs_mknod(d_inode(path.dentry), dentry, mode, 0); if (!err) { res->mnt = mntget(path.mnt); res->dentry = dget(dentry); } } done_path_create(&path, dentry); return err; }

Contributors

PersonTokensPropCommitsCommitProp
Al Viro8257.34%240.00%
Linus Torvalds5739.86%120.00%
David Howells32.10%120.00%
Rainer Weikusat10.70%120.00%
Total143100.00%5100.00%


static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) { struct sock *sk = sock->sk; struct net *net = sock_net(sk); struct unix_sock *u = unix_sk(sk); struct sockaddr_un *sunaddr = (struct sockaddr_un *)uaddr; char *sun_path = sunaddr->sun_path; int err; unsigned int hash; struct unix_address *addr; struct hlist_head *list; struct path path = { }; err = -EINVAL; if (addr_len < offsetofend(struct sockaddr_un, sun_family) || sunaddr->sun_family != AF_UNIX) goto out; if (addr_len == sizeof(short)) { err = unix_autobind(sock); goto out; } err = unix_mkname(sunaddr, addr_len, &hash); if (err < 0) goto out; addr_len = err; if (sun_path[0]) { umode_t mode = S_IFSOCK | (SOCK_INODE(sock)->i_mode & ~current_umask()); err = unix_mknod(sun_path, mode, &path); if (err) { if (err == -EEXIST) err = -EADDRINUSE; goto out; } } err = mutex_lock_interruptible(&u->bindlock); if (err) goto out_put; err = -EINVAL; if (u->addr) goto out_up; err = -ENOMEM; addr = kmalloc(sizeof(*addr)+addr_len, GFP_KERNEL); if (!addr) goto out_up; memcpy(addr->name, sunaddr, addr_len); addr->len = addr_len; addr->hash = hash ^ sk->sk_type; refcount_set(&addr->refcnt, 1); if (sun_path[0]) { addr->hash = UNIX_HASH_SIZE; hash = d_backing_inode(path.dentry)->i_ino & (UNIX_HASH_SIZE - 1); spin_lock(&unix_table_lock); u->path = path; list = &unix_socket_table[hash]; } else { spin_lock(&unix_table_lock); err = -EADDRINUSE; if (__unix_find_socket_byname(net, sunaddr, addr_len, sk->sk_type, hash)) { unix_release_addr(addr); goto out_unlock; } list = &unix_socket_table[addr->hash]; } err = 0; __unix_remove_socket(sk); u->addr = addr; __unix_insert_socket(list, sk); out_unlock: spin_unlock(&unix_table_lock); out_up: mutex_unlock(&u->bindlock); out_put: if (err) path_put(&path); out: return err; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)29762.00%622.22%
Américo Wang7816.28%13.70%
Al Viro367.52%311.11%
David S. Miller163.34%27.41%
Mateusz Jurczyk102.09%13.70%
Linus Torvalds91.88%27.41%
Denis V. Lunev91.88%13.70%
Sasha Levin91.88%13.70%
Arnaldo Carvalho de Melo40.84%27.41%
Hideaki Yoshifuji / 吉藤英明30.63%13.70%
David Howells20.42%13.70%
Eric Dumazet10.21%13.70%
Miklos Szeredi10.21%13.70%
Elena Reshetova10.21%13.70%
Jan Blunck10.21%13.70%
Kees Cook10.21%13.70%
Ingo Molnar10.21%13.70%
Total479100.00%27100.00%


static void unix_state_double_lock(struct sock *sk1, struct sock *sk2) { if (unlikely(sk1 == sk2) || !sk2) { unix_state_lock(sk1); return; } if (sk1 < sk2) { unix_state_lock(sk1); unix_state_lock_nested(sk2); } else { unix_state_lock(sk2); unix_state_lock_nested(sk1); } }

Contributors

PersonTokensPropCommitsCommitProp
David S. Miller67100.00%1100.00%
Total67100.00%1100.00%


static void unix_state_double_unlock(struct sock *sk1, struct sock *sk2) { if (unlikely(sk1 == sk2) || !sk2) { unix_state_unlock(sk1); return; } unix_state_unlock(sk1); unix_state_unlock(sk2); }

Contributors

PersonTokensPropCommitsCommitProp
David S. Miller46100.00%1100.00%
Total46100.00%1100.00%


static int unix_dgram_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags) { struct sock *sk = sock->sk; struct net *net = sock_net(sk); struct sockaddr_un *sunaddr = (struct sockaddr_un *)addr; struct sock *other; unsigned int hash; int err; err = -EINVAL; if (alen < offsetofend(struct sockaddr, sa_family)) goto out; if (addr->sa_family != AF_UNSPEC) { err = unix_mkname(sunaddr, alen, &hash); if (err < 0) goto out; alen = err; if (test_bit(SOCK_PASSCRED, &sock->flags) && !unix_sk(sk)->addr && (err = unix_autobind(sock)) != 0) goto out; restart: other = unix_find_other(net, sunaddr, alen, sock->type, hash, &err); if (!other) goto out; unix_state_double_lock(sk, other); /* Apparently VFS overslept socket death. Retry. */ if (sock_flag(other, SOCK_DEAD)) { unix_state_double_unlock(sk, other); sock_put(other); goto restart; } err = -EPERM; if (!unix_may_send(sk, other)) goto out_unlock; err = security_unix_may_send(sk->sk_socket, other->sk_socket); if (err) goto out_unlock; } else { /* * 1003.1g breaking connected state with AF_UNSPEC */ other = NULL; unix_state_double_lock(sk, other); } /* * If it was connected, reconnect. */ if (unix_peer(sk)) { struct sock *old_peer = unix_peer(sk); unix_peer(sk) = other; unix_dgram_peer_wake_disconnect_wakeup(sk, old_peer); unix_state_double_unlock(sk, other); if (other != old_peer) unix_dgram_disconnected(sk, old_peer); sock_put(old_peer); } else { unix_peer(sk) = other; unix_state_double_unlock(sk, other); } return 0; out_unlock: unix_state_double_unlock(sk, other); sock_put(other); out: return err; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)25569.11%844.44%
David S. Miller4712.74%211.11%
Mateusz Jurczyk205.42%15.56%
James Morris184.88%15.56%
Denis V. Lunev92.44%15.56%
Rainer Weikusat71.90%15.56%
Herbert Pötzl71.90%15.56%
Hideaki Yoshifuji / 吉藤英明30.81%15.56%
Arnaldo Carvalho de Melo20.54%15.56%
Eric Dumazet10.27%15.56%
Total369100.00%18100.00%


static long unix_wait_for_peer(struct sock *other, long timeo) { struct unix_sock *u = unix_sk(other); int sched; DEFINE_WAIT(wait); prepare_to_wait_exclusive(&u->peer_wait, &wait, TASK_INTERRUPTIBLE); sched = !sock_flag(other, SOCK_DEAD) && !(other->sk_shutdown & RCV_SHUTDOWN) && unix_recvq_full(other); unix_state_unlock(other); if (sched) timeo = schedule_timeout(timeo); finish_wait(&u->peer_wait, &wait); return timeo; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)7272.73%538.46%
David S. Miller1313.13%215.38%
Arnaldo Carvalho de Melo66.06%323.08%
Andrew Morton55.05%17.69%
James Morris22.02%17.69%
Rainer Weikusat11.01%17.69%
Total99100.00%13100.00%


static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags) { struct sockaddr_un *sunaddr = (struct sockaddr_un *)uaddr; struct sock *sk = sock->sk; struct net *net = sock_net(sk); struct unix_sock *u = unix_sk(sk), *newu, *otheru; struct sock *newsk = NULL; struct sock *other = NULL; struct sk_buff *skb = NULL; unsigned int hash; int st; int err; long timeo; err = unix_mkname(sunaddr, addr_len, &hash); if (err < 0) goto out; addr_len = err; if (test_bit(SOCK_PASSCRED, &sock->flags) && !u->addr && (err = unix_autobind(sock)) != 0) goto out; timeo = sock_sndtimeo(sk, flags & O_NONBLOCK); /* First of all allocate resources. If we will make it after state is locked, we will have to recheck all again in any case. */ err = -ENOMEM; /* create new sock for complete connection */ newsk = unix_create1(sock_net(sk), NULL, 0); if (newsk == NULL) goto out; /* Allocate skb for sending to listening sock */ skb = sock_wmalloc(newsk, 1, 0, GFP_KERNEL); if (skb == NULL) goto out; restart: /* Find listening sock. */ other = unix_find_other(net, sunaddr, addr_len, sk->sk_type, hash, &err); if (!other) goto out; /* Latch state of peer */ unix_state_lock(other); /* Apparently VFS overslept socket death. Retry. */ if (sock_flag(other, SOCK_DEAD)) { unix_state_unlock(other); sock_put(other); goto restart; } err = -ECONNREFUSED; if (other->sk_state != TCP_LISTEN) goto out_unlock; if (other->sk_shutdown & RCV_SHUTDOWN) goto out_unlock; if (unix_recvq_full(other)) { err = -EAGAIN; if (!timeo) goto out_unlock; timeo = unix_wait_for_peer(other, timeo); err = sock_intr_errno(timeo); if (signal_pending(current)) goto out; sock_put(other); goto restart; } /* Latch our state. It is tricky place. We need to grab our state lock and cannot drop lock on peer. It is dangerous because deadlock is possible. Connect to self case and simultaneous attempt to connect are eliminated by checking socket state. other is TCP_LISTEN, if sk is TCP_LISTEN we check this before attempt to grab lock. Well, and we have to recheck the state after socket locked. */ st = sk->sk_state; switch (st) { case TCP_CLOSE: /* This is ok... continue with connect */ break; case TCP_ESTABLISHED: /* Socket is already connected */ err = -EISCONN; goto out_unlock; default: err = -EINVAL; goto out_unlock; } unix_state_lock_nested(sk); if (sk->sk_state != st) { unix_state_unlock(sk); unix_state_unlock(other); sock_put(other); goto restart; } err = security_unix_stream_connect(sk, other, newsk); if (err) { unix_state_unlock(sk); goto out_unlock; } /* The way is open! Fastly set all the necessary fields... */ sock_hold(sk); unix_peer(newsk) = sk; newsk->sk_state = TCP_ESTABLISHED; newsk->sk_type = sk->sk_type; init_peercred(newsk); newu = unix_sk(newsk); RCU_INIT_POINTER(newsk->sk_wq, &newu->peer_wq); otheru = unix_sk(other); /* copy address information from listening to new sock*/ if (otheru->addr) { refcount_inc(&otheru->addr->refcnt); newu->addr = otheru->addr; } if (otheru->path.dentry) { path_get(&otheru->path); newu->path = otheru->path; } /* Set credentials */ copy_peercred(sk, other); sock->state = SS_CONNECTED; sk->sk_state = TCP_ESTABLISHED; sock_hold(newsk); smp_mb__after_atomic(); /* sock_hold() does an atomic_inc() */ unix_peer(sk) = newsk; unix_state_unlock(sk); /* take ten and and send info to listening sock */ spin_lock(&other->sk_receive_queue.lock); __skb_queue_tail(&other->sk_receive_queue, skb); spin_unlock(&other->sk_receive_queue.lock); unix_state_unlock(other); other->sk_data_ready(other); sock_put(other); return 0; out_unlock: if (other) unix_state_unlock(other); out: kfree_skb(skb); if (newsk) unix_release_sock(newsk, 0); if (other) sock_put(other); return err; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)51973.20%1128.21%
David S. Miller507.05%37.69%
James Morris253.53%25.13%
Linus Torvalds192.68%12.56%
Arnaldo Carvalho de Melo162.26%37.69%
Benjamin LaHaise152.12%12.56%
Tomoki Sekiyama111.55%12.56%
Denis V. Lunev91.27%12.56%
Eric W. Biedermann91.27%37.69%
Eric Dumazet70.99%37.69%
Herbert Pötzl70.99%12.56%
Al Viro70.99%12.56%
Hideaki Yoshifuji / 吉藤英明60.85%12.56%
Steven Dake30.42%12.56%
David Howells10.14%12.56%
Peter Zijlstra10.14%12.56%
Elena Reshetova10.14%12.56%
Rainer Weikusat10.14%12.56%
Pavel Emelyanov10.14%12.56%
Daniel Baluta10.14%12.56%
Total709100.00%39100.00%


static int unix_socketpair(struct socket *socka, struct socket *sockb) { struct sock *ska = socka->sk, *skb = sockb->sk; /* Join our sockets back to back */ sock_hold(ska); sock_hold(skb); unix_peer(ska) = skb; unix_peer(skb) = ska; init_peercred(ska); init_peercred(skb); if (ska->sk_type != SOCK_DGRAM) { ska->sk_state = TCP_ESTABLISHED; skb->sk_state = TCP_ESTABLISHED; socka->state = SS_CONNECTED; sockb->state = SS_CONNECTED; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)9288.46%342.86%
David Howells43.85%114.29%
Arnaldo Carvalho de Melo32.88%114.29%
Eric W. Biedermann32.88%114.29%
Pavel Emelyanov21.92%114.29%
Total104100.00%7100.00%


static void unix_sock_inherit_flags(const struct socket *old, struct socket *new) { if (test_bit(SOCK_PASSCRED, &old->flags)) set_bit(SOCK_PASSCRED, &new->flags); if (test_bit(SOCK_PASSSEC, &old->flags)) set_bit(SOCK_PASSSEC, &new->flags); }

Contributors

PersonTokensPropCommitsCommitProp
Daniel Borkmann61100.00%1100.00%
Total61100.00%1100.00%


static int unix_accept(struct socket *sock, struct socket *newsock, int flags, bool kern) { struct sock *sk = sock->sk; struct sock *tsk; struct sk_buff *skb; int err; err = -EOPNOTSUPP; if (sock->type != SOCK_STREAM && sock->type != SOCK_SEQPACKET) goto out; err = -EINVAL; if (sk->sk_state != TCP_LISTEN) goto out; /* If socket state is TCP_LISTEN it cannot change (for now...), * so that no locks are necessary. */ skb = skb_recv_datagram(sk, 0, flags&O_NONBLOCK, &err); if (!skb) { /* This means receive shutdown. */ if (err == 0) err = -EINVAL; goto out; } tsk = skb->sk; skb_free_datagram(sk, skb); wake_up_interruptible(&unix_sk(sk)->peer_wait); /* attach accepted sock to socket */ unix_state_lock(tsk); newsock->state = SS_CONNECTED; unix_sock_inherit_flags(sock, newsock); sock_graft(tsk, newsock); unix_state_unlock(tsk); return 0; out: return err; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)14478.26%538.46%
Linus Torvalds147.61%17.69%
Daniel Borkmann73.80%17.69%
Steven Dake63.26%17.69%
David S. Miller52.72%215.38%
Arnaldo Carvalho de Melo52.72%215.38%
David Howells31.63%17.69%
Total184100.00%13100.00%


static int unix_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer) { struct sock *sk = sock->sk; struct unix_sock *u; DECLARE_SOCKADDR(struct sockaddr_un *, sunaddr, uaddr); int err = 0; if (peer) { sk = unix_peer_get(sk); err = -ENOTCONN; if (!sk) goto out; err = 0; } else { sock_hold(sk); } u = unix_sk(sk); unix_state_lock(sk); if (!u->addr) { sunaddr->sun_family = AF_UNIX; sunaddr->sun_path[0] = 0; *uaddr_len = sizeof(short); } else { struct unix_address *addr = u->addr; *uaddr_len = addr->len; memcpy(sunaddr, addr->name, *uaddr_len); } unix_state_unlock(sk); sock_put(sk); out: return err; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)15987.85%342.86%
David S. Miller84.42%228.57%
Ray Lee73.87%114.29%
Cyrill V. Gorcunov73.87%114.29%
Total181100.00%7100.00%


static void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb) { int i; scm->fp = UNIXCB(skb).fp; UNIXCB(skb).fp = NULL; for (i = scm->fp->count-1; i >= 0; i--) unix_notinflight(scm->fp->user, scm->fp->fp[i]); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)7092.11%266.67%
Hannes Frederic Sowa67.89%133.33%
Total76100.00%3100.00%


static void unix_destruct_scm(struct sk_buff *skb) { struct scm_cookie scm; memset(&scm, 0, sizeof(scm)); scm.pid = UNIXCB(skb).pid; if (UNIXCB(skb).fp) unix_detach_fds(&scm, skb); /* Alas, it calls VFS */ /* So fscking what? fput() had been SMP-safe since the last Summer */ scm_destroy(&scm); sock_wfree(skb); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)4869.57%375.00%
Eric W. Biedermann2130.43%125.00%
Total69100.00%4100.00%

/* * The "user->unix_inflight" variable is protected by the garbage * collection lock, and we just read it locklessly here. If you go * over the limit, there might be a tiny race in actually noticing * it across threads. Tough. */
static inline bool too_many_unix_fds(struct task_struct *p) { struct user_struct *user = current_user(); if (unlikely(user->unix_inflight > task_rlimit(p, RLIMIT_NOFILE))) return !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN); return false; }

Contributors

PersonTokensPropCommitsCommitProp
Willy Tarreau52100.00%1100.00%
Total52100.00%1100.00%


static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) { int i; if (too_many_unix_fds(current)) return -ETOOMANYREFS; /* * Need to duplicate file references for the sake of garbage * collection. Otherwise a socket in the fps might become a * candidate for GC while the skb is not yet queued. */ UNIXCB(skb).fp = scm_fp_dup(scm->fp); if (!UNIXCB(skb).fp) return -ENOMEM; for (i = scm->fp->count - 1; i >= 0; i--) unix_inflight(scm->fp->user, scm->fp->fp[i]); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)4848.48%228.57%
Miklos Szeredi3030.30%114.29%
Willy Tarreau1111.11%114.29%
Hannes Frederic Sowa66.06%114.29%
Eric W. Biedermann33.03%114.29%
David Herrmann11.01%114.29%
Total99100.00%7100.00%


static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool send_fds) { int err = 0; UNIXCB(skb).pid = get_pid(scm->pid); UNIXCB(skb).uid = scm->creds.uid; UNIXCB(skb).gid = scm->creds.gid; UNIXCB(skb).fp = NULL; unix_get_secdata(scm, skb); if (scm->fp && send_fds) err = unix_attach_fds(scm, skb); skb->destructor = unix_destruct_scm; return err; }

Contributors

PersonTokensPropCommitsCommitProp
Eric W. Biedermann8983.96%228.57%
Stephen D. Smalley76.60%114.29%
Linus Torvalds (pre-git)65.66%228.57%
Miklos Szeredi21.89%114.29%
Eric Dumazet21.89%114.29%
Total106100.00%7100.00%


static bool unix_passcred_enabled(const struct socket *sock, const struct sock *other) { return test_bit(SOCK_PASSCRED, &sock->flags) || !other->sk_socket || test_bit(SOCK_PASSCRED, &other->sk_socket->flags); }

Contributors

PersonTokensPropCommitsCommitProp
Hannes Frederic Sowa46100.00%1100.00%
Total46100.00%1100.00%

/* * Some apps rely on write() giving SCM_CREDENTIALS * We include credentials if source or destination socket * asserted SOCK_PASSCRED. */
static void maybe_add_creds(struct sk_buff *skb, const struct socket *sock, const struct sock *other) { if (UNIXCB(skb).pid) return; if (unix_passcred_enabled(sock, other)) { UNIXCB(skb).pid = get_pid(task_tgid(current)); current_uid_gid(&UNIXCB(skb).uid, &UNIXCB(skb).gid); } }

Contributors

PersonTokensPropCommitsCommitProp
Eric Dumazet6380.77%125.00%
Eric W. Biedermann1316.67%125.00%
Hannes Frederic Sowa11.28%125.00%
David S. Miller11.28%125.00%
Total78100.00%4100.00%


static int maybe_init_creds(struct scm_cookie *scm, struct socket *socket, const struct sock *other) { int err; struct msghdr msg = { .msg_controllen = 0 }; err = scm_send(socket, &msg, scm, false); if (err) return err; if (unix_passcred_enabled(socket, other)) { scm->pid = get_pid(task_tgid(current)); current_uid_gid(&scm->creds.uid, &scm->creds.gid); } return err; }

Contributors

PersonTokensPropCommitsCommitProp
Hannes Frederic Sowa9090.00%120.00%
Eric W. Biedermann55.00%120.00%
Linus Torvalds (pre-git)33.00%240.00%
Miklos Szeredi22.00%120.00%
Total100100.00%5100.00%


static bool unix_skb_scm_eq(struct sk_buff *skb, struct scm_cookie *scm) { const struct unix_skb_parms *u = &UNIXCB(skb); return u->pid == scm->pid && uid_eq(u->uid, scm->creds.uid) && gid_eq(u->gid, scm->creds.gid) && unix_secdata_eq(scm, skb); }

Contributors

PersonTokensPropCommitsCommitProp
Hannes Frederic Sowa3955.71%133.33%
Eric Dumazet2738.57%133.33%
Eric W. Biedermann45.71%133.33%
Total70100.00%3100.00%

/* * Send AF_UNIX data. */
static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) { struct sock *sk = sock->sk; struct net *net = sock_net(sk); struct unix_sock *u = unix_sk(sk); DECLARE_SOCKADDR(struct sockaddr_un *, sunaddr, msg->msg_name); struct sock *other = NULL; int namelen = 0; /* fake GCC */ int err; unsigned int hash; struct sk_buff *skb; long timeo; struct scm_cookie scm; int data_len = 0; int sk_locked; wait_for_unix_gc(); err = scm_send(sock, msg, &scm, false); if (err < 0) return err; err = -EOPNOTSUPP; if (msg->msg_flags&MSG_OOB) goto out; if (msg->msg_namelen) { err = unix_mkname(sunaddr, msg->msg_namelen, &hash); if (err < 0) goto out; namelen = err; } else { sunaddr = NULL; err = -ENOTCONN; other = unix_peer_get(sk); if (!other) goto out; } if (test_bit(SOCK_PASSCRED, &sock->flags) && !u->addr && (err = unix_autobind(sock)) != 0) goto out; err = -EMSGSIZE; if (len > sk->sk_sndbuf - 32) goto out; if (len > SKB_MAX_ALLOC) { data_len = min_t(size_t, len - SKB_MAX_ALLOC, MAX_SKB_FRAGS * PAGE_SIZE); data_len = PAGE_ALIGN(data_len); BUILD_BUG_ON(SKB_MAX_ALLOC < PAGE_SIZE); } skb = sock_alloc_send_pskb(sk, len - data_len, data_len, msg->msg_flags & MSG_DONTWAIT, &err, PAGE_ALLOC_COSTLY_ORDER); if (skb == NULL) goto out; err = unix_scm_to_skb(&scm, skb, true); if (err < 0) goto out_free; skb_put(skb, len - data_len); skb->data_len = data_len; skb->len = len; err = skb_copy_datagram_from_iter(skb, 0, &msg->msg_iter, len); if (err) goto out_free; timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); restart: if (!other) { err = -ECONNRESET; if (sunaddr == NULL) goto out_free; other = unix_find_other(net, sunaddr, namelen, sk->sk_type, hash, &err); if (other == NULL) goto out_free; } if (sk_filter(other, skb) < 0) { /* Toss the packet but do not return any error to the sender */ err = len; goto out_free; } sk_locked = 0; unix_state_lock(other); restart_locked: err = -EPERM; if (!unix_may_send(sk, other)) goto out_unlock; if (unlikely(sock_flag(other, SOCK_DEAD))) { /* * Check with 1003.1g - what should * datagram error */ unix_state_unlock(other); sock_put(other); if (!sk_locked) unix_state_lock(sk); err = 0; if (unix_peer(sk) == other) { unix_peer(sk) = NULL; unix_dgram_peer_wake_disconnect_wakeup(sk, other); unix_state_unlock(sk); unix_dgram_disconnected(sk, other); sock_put(other); err = -ECONNREFUSED; } else { unix_state_unlock(sk); } other = NULL; if (err) goto out_free; goto restart; } err = -EPIPE; if (other->sk_shutdown & RCV_SHUTDOWN) goto out_unlock; if (sk->sk_type != SOCK_SEQPACKET) { err = security_unix_may_send(sk->sk_socket, other->sk_socket); if (err) goto out_unlock; } /* other == sk && unix_peer(other) != sk if * - unix_peer(sk) == NULL, destination address bound to sk * - unix_peer(sk) == sk by time of get but disconnected before lock */ if (other != sk && unlikely(unix_peer(other) != sk && unix_recvq_full(other))) { if (timeo) { timeo = unix_wait_for_peer(other, timeo); err = sock_intr_errno(timeo); if (signal_pending(current)) goto out_free; goto restart; } if (!sk_locked) { unix_state_unlock(other); unix_state_double_lock(sk, other); } if (unix_peer(sk) != other || unix_dgram_peer_wake_me(sk, other)) { err = -EAGAIN; sk_locked = 1; goto out_unlock; } if (!sk_locked) { sk_locked = 1; goto restart_locked; } } if (unlikely(sk_locked)) unix_state_unlock(sk); if (sock_flag(other, SOCK_RCVTSTAMP)) __net_timestamp(skb); maybe_add_creds(skb, sock, other); skb_queue_tail(&other->sk_receive_queue, skb); unix_state_unlock(other); other->sk_data_ready(other); sock_put(other); scm_destroy(&scm); return len; out_unlock: if (sk_locked) unix_state_unlock(sk); unix_state_unlock(other); out_free: kfree_skb(skb); out: if (other) sock_put(other); scm_destroy(&scm); return err; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)51958.05%1530.61%
Rainer Weikusat10912.19%36.12%
Eric Dumazet667.38%612.24%
Alban Crequy374.14%24.08%
Benjamin LaHaise323.58%12.04%
James Morris303.36%36.12%
David S. Miller182.01%36.12%
Kirill Tkhai161.79%12.04%
Arnaldo Carvalho de Melo141.57%48.16%
Miklos Szeredi91.01%12.04%
Denis V. Lunev91.01%12.04%
Steffen Hurrle80.89%12.04%
Herbert Pötzl70.78%12.04%
Christoph Hellwig50.56%12.04%
Al Viro50.56%24.08%
dann frazier30.34%12.04%
Eric W. Biedermann30.34%12.04%
Hideaki Yoshifuji / 吉藤英明30.34%12.04%
Stephen Hemminger10.11%12.04%
Total894100.00%49100.00%

/* We use paged skbs for stream sockets, and limit occupancy to 32768 * bytes, and a minimun of a full page. */ #define UNIX_SKB_FRAGS_SZ (PAGE_SIZE << get_order(32768))
static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) { struct sock *sk = sock->sk; struct sock *other = NULL; int err, size; struct sk_buff *skb; int sent = 0; struct scm_cookie scm; bool fds_sent = false; int data_len; wait_for_unix_gc(); err = scm_send(sock, msg, &scm, false); if (err < 0) return err; err = -EOPNOTSUPP; if (msg->msg_flags&MSG_OOB) goto out_err; if (msg->msg_namelen) { err = sk->sk_state == TCP_ESTABLISHED ? -EISCONN : -EOPNOTSUPP; goto out_err; } else { err = -ENOTCONN; other = unix_peer(sk); if (!other) goto out_err; } if (sk->sk_shutdown & SEND_SHUTDOWN) goto pipe_err; while (sent < len) { size = len - sent; /* Keep two messages in the pipe so it schedules better */ size = min_t(int, size, (sk->sk_sndbuf >> 1) - 64); /* allow fallback to order-0 allocations */ size = min_t(int, size, SKB_MAX_HEAD(0) + UNIX_SKB_FRAGS_SZ); data_len = max_t(int, 0, size - SKB_MAX_HEAD(0)); data_len = min_t(size_t, size, PAGE_ALIGN(data_len)); skb = sock_alloc_send_pskb(sk, size - data_len, data_len, msg->msg_flags & MSG_DONTWAIT, &err, get_order(UNIX_SKB_FRAGS_SZ)); if (!skb) goto out_err; /* Only send the fds in the first buffer */ err = unix_scm_to_skb(&scm, skb, !fds_sent); if (err < 0) { kfree_skb(skb); goto out_err; } fds_sent = true; skb_put(skb, size - data_len); skb->data_len = data_len; skb->len = size; err = skb_copy_datagram_from_iter(skb, 0, &msg->msg_iter, size); if (err) { kfree_skb(skb); goto out_err; } unix_state_lock(other); if (sock_flag(other, SOCK_DEAD) || (other->sk_shutdown & RCV_SHUTDOWN)) goto pipe_err_free; maybe_add_creds(skb, sock, other); skb_queue_tail(&other->sk_receive_queue, skb); unix_state_unlock(other); other->sk_data_ready(other); sent += size; } scm_destroy(&scm); return sent; pipe_err_free: unix_state_unlock(other); kfree_skb(skb); pipe_err: if (sent == 0 && !(msg->msg_flags&MSG_NOSIGNAL)) send_sig(SIGPIPE, current, 0); err = -EPIPE; out_err: scm_destroy(&scm); return sent ? : err; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)28558.16%1435.90%
Eric Dumazet8918.16%615.38%
Benjamin LaHaise387.76%37.69%
Miklos Szeredi224.49%25.13%
Kirill Tkhai142.86%12.56%
Arnaldo Carvalho de Melo112.24%37.69%
David S. Miller61.22%25.13%
Al Viro51.02%25.13%
Christoph Hellwig51.02%12.56%
Linus Torvalds51.02%12.56%
Eric W. Biedermann40.82%12.56%
dann frazier30.61%12.56%
James Morris20.41%12.56%
Stephen Hemminger10.20%12.56%
Total490100.00%39100.00%


static ssize_t unix_stream_sendpage(struct socket *socket, struct page *page, int offset, size_t size, int flags) { int err; bool send_sigpipe = false; bool init_scm = true; struct scm_cookie scm; struct sock *other, *sk = socket->sk; struct sk_buff *skb, *newskb = NULL, *tail = NULL; if (flags & MSG_OOB) return -EOPNOTSUPP; other = unix_peer(sk); if (!other || sk->sk_state != TCP_ESTABLISHED) return -ENOTCONN; if (false) { alloc_skb: unix_state_unlock(other); mutex_unlock(&unix_sk(other)->iolock); newskb = sock_alloc_send_pskb(sk, 0, 0, flags & MSG_DONTWAIT, &err, 0); if (!newskb) goto err; } /* we must acquire iolock as we modify already present * skbs in the sk_receive_queue and mess with skb->len */ err = mutex_lock_interruptible(&unix_sk(other)->iolock); if (err) { err = flags & MSG_DONTWAIT ? -EAGAIN : -ERESTARTSYS; goto err; } if (sk->sk_shutdown & SEND_SHUTDOWN) { err = -EPIPE; send_sigpipe = true; goto err_unlock; } unix_state_lock(other); if (sock_flag(other, SOCK_DEAD) || other->sk_shutdown & RCV_SHUTDOWN) { err = -EPIPE; send_sigpipe = true; goto err_state_unlock; } if (init_scm) { err = maybe_init_creds(&scm, socket, other); if (err) goto err_state_unlock; init_scm = false; } skb = skb_peek_tail(&other->sk_receive_queue); if (tail && tail == skb) { skb = newskb; } else if (!skb || !unix_skb_scm_eq(skb, &scm)) { if (newskb) { skb = newskb; } else { tail = skb; goto alloc_skb; } } else if (newskb) { /* this is fast path, we don't necessarily need to * call to kfree_skb even though with newskb == NULL * this - does no harm */ consume_skb(newskb); newskb = NULL; } if (skb_append_pagefrags(skb, page, offset, size)) { tail = skb; goto alloc_skb; } skb->len += size; skb->data_len += size; skb->truesize += size; refcount_add(size, &sk->sk_wmem_alloc); if (newskb) { err = unix_scm_to_skb(&scm, skb, false); if (err) goto err_state_unlock; spin_lock(&other->sk_receive_queue.lock); __skb_queue_tail(&other->sk_receive_queue, newskb); spin_unlock(&other->sk_receive_queue.lock); } unix_state_unlock(other); mutex_unlock(&unix_sk(other)->iolock); other->sk_data_ready(other); scm_destroy(&scm); return size; err_state_unlock: unix_state_unlock(other); err_unlock: mutex_unlock(&unix_sk(other)->iolock); err: kfree_skb(newskb); if (send_sigpipe && !(flags & MSG_NOSIGNAL)) send_sig(SIGPIPE, current, 0); if (!init_scm) scm_destroy(&scm); return err; }

Contributors

PersonTokensPropCommitsCommitProp
Hannes Frederic Sowa54398.91%466.67%
Linus Torvalds50.91%116.67%
Elena Reshetova10.18%116.67%
Total549100.00%6100.00%


static int unix_seqpacket_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) { int err; struct sock *sk = sock->sk; err = sock_error(sk); if (err) return err; if (sk->sk_state != TCP_ESTABLISHED) return -ENOTCONN; if (msg->msg_namelen) msg->msg_namelen = 0; return unix_dgram_sendmsg(sock, msg, len); }

Contributors

PersonTokensPropCommitsCommitProp
James Morris79100.00%2100.00%
Total79100.00%2100.00%


static int unix_seqpacket_recvmsg(struct socket *sock, struct msghdr *msg, size_t size, int flags) { struct sock *sk = sock->sk; if (sk->sk_state != TCP_ESTABLISHED) return -ENOTCONN; return unix_dgram_recvmsg(sock, msg, size, flags); }

Contributors

PersonTokensPropCommitsCommitProp
Eric W. Biedermann55100.00%1100.00%
Total55100.00%1100.00%


static void unix_copy_addr(struct msghdr *msg, struct sock *sk) { struct unix_sock *u = unix_sk(sk); if (u->addr) { msg->msg_namelen = u->addr->len; memcpy(msg->msg_name, u->addr->name, u->addr->len); } }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)4977.78%685.71%
David S. Miller1422.22%114.29%
Total63100.00%7100.00%


static int unix_dgram_recvmsg(struct socket *sock, struct msghdr *msg, size_t size, int flags) { struct scm_cookie scm; struct sock *sk = sock->sk; struct unix_sock *u = unix_sk(sk); struct sk_buff *skb, *last; long timeo; int err; int peeked, skip; err = -EOPNOTSUPP; if (flags&MSG_OOB) goto out; timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); do { mutex_lock(&u->iolock); skip = sk_peek_offset(sk, flags); skb = __skb_try_recv_datagram(sk, flags, NULL, &peeked, &skip, &err, &last); if (skb) break; mutex_unlock(&u->iolock); if (err != -EAGAIN) break; } while (timeo && !__skb_wait_for_more_packets(sk, &err, &timeo, last)); if (!skb) { /* implies iolock unlocked */ unix_state_lock(sk); /* Signal EOF on disconnected non-blocking SEQPACKET socket. */ if (sk->sk_type == SOCK_SEQPACKET && err == -EAGAIN && (sk->sk_shutdown & RCV_SHUTDOWN)) err = 0; unix_state_unlock(sk); goto out; } if (wq_has_sleeper(&u->peer_wait)) wake_up_interruptible_sync_poll(&u->peer_wait, POLLOUT | POLLWRNORM | POLLWRBAND); if (msg->msg_name) unix_copy_addr(msg, skb->sk); if (size > skb->len - skip) size = skb->len - skip; else if (size < skb->len - skip) msg->msg_flags |= MSG_TRUNC; err = skb_copy_datagram_msg(skb, skip, msg, size); if (err) goto out_free; if (sock_flag(sk, SOCK_RCVTSTAMP)) __sock_recv_timestamp(msg, sk, skb); memset(&scm, 0, sizeof(scm)); scm_set_cred(&scm, UNIXCB(skb).pid, UNIXCB(skb).uid, UNIXCB(skb).gid); unix_set_secdata(&scm, skb); if (!(flags & MSG_PEEK)) { if (UNIXCB(skb).fp) unix_detach_fds(&scm, skb); sk_peek_offset_bwd(sk, skb->len); } else { /* It is questionable: on PEEK we could: - do not return fds - good, but too simple 8) - return fds, and do not return them on read (old strategy, apparently wrong) - clone fds (I chose it for now, it is the most universal solution) POSIX 1003.1g does not actually define this clearly at all. POSIX 1003.1g doesn't define a lot of things clearly however! */ sk_peek_offset_fwd(sk, size); if (UNIXCB(skb).fp) scm.fp = scm_fp_dup(UNIXCB(skb).fp); } err = (flags & MSG_TRUNC) ? skb->len - skip : size; scm_recv(sock, msg, &scm, flags); out_free: skb_free_datagram(sk, skb); mutex_unlock(&u->iolock); out: return err; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)21442.80%1132.35%
Rainer Weikusat7515.00%38.82%
Pavel Emelyanov428.40%12.94%
Florian Zumbiehl387.60%12.94%
Benjamin LaHaise275.40%12.94%
David S. Miller234.60%411.76%
Eric Dumazet214.20%38.82%
Eric W. Biedermann204.00%25.88%
Alban Crequy163.20%12.94%
Christoph Hellwig81.60%12.94%
Catherine Zhang71.40%12.94%
Linus Torvalds40.80%12.94%
Paolo Abeni20.40%12.94%
Ingo Molnar10.20%12.94%
Hideaki Yoshifuji / 吉藤英明10.20%12.94%
Stephen Hemminger10.20%12.94%
Total500100.00%34100.00%

/* * Sleep until more data has arrived. But check for races.. */
static long unix_stream_data_wait(struct sock *sk, long timeo, struct sk_buff *last, unsigned int last_len, bool freezable) { struct sk_buff *tail; DEFINE_WAIT(wait); unix_state_lock(sk); for (;;) { prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); tail = skb_peek_tail(&sk->sk_receive_queue); if (tail != last || (tail && tail->len != last_len) || sk->sk_err || (sk->sk_shutdown & RCV_SHUTDOWN) || signal_pending(current) || !timeo) break; sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk); unix_state_unlock(sk); if (freezable) timeo = freezable_schedule_timeout(timeo); else timeo = schedule_timeout(timeo); unix_state_lock(sk); if (sock_flag(sk, SOCK_DEAD)) break; sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk); } finish_wait(sk_sleep(sk), &wait); unix_state_unlock(sk); return timeo; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)9351.67%635.29%
Hannes Frederic Sowa2513.89%15.88%
Américo Wang158.33%15.88%
David S. Miller147.78%211.76%
Eric Dumazet105.56%211.76%
Benjamin Poirier84.44%15.88%
Arnaldo Carvalho de Melo73.89%211.76%
Andrew Morton73.89%15.88%
Colin Cross10.56%15.88%
Total180100.00%17100.00%


static unsigned int unix_skb_len(const struct sk_buff *skb) { return skb->len - UNIXCB(skb).consumed; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Dumazet25100.00%1100.00%
Total25100.00%1100.00%

struct unix_stream_read_state { int (*recv_actor)(struct sk_buff *, int, int, struct unix_stream_read_state *); struct socket *socket; struct msghdr *msg; struct pipe_inode_info *pipe; size_t size; int flags; unsigned int splice_flags; };
static int unix_stream_read_generic(struct unix_stream_read_state *state, bool freezable) { struct scm_cookie scm; struct socket *sock = state->socket; struct sock *sk = sock->sk; struct unix_sock *u = unix_sk(sk); int copied = 0; int flags = state->flags; int noblock = flags & MSG_DONTWAIT; bool check_creds = false; int target; int err = 0; long timeo; int skip; size_t size = state->size; unsigned int last_len; if (unlikely(sk->sk_state != TCP_ESTABLISHED)) { err = -EINVAL; goto out; } if (unlikely(flags & MSG_OOB)) { err = -EOPNOTSUPP; goto out; } target = sock_rcvlowat(sk, flags & MSG_WAITALL, size); timeo = sock_rcvtimeo(sk, noblock); memset(&scm, 0, sizeof(scm)); /* Lock the socket to prevent queue disordering * while sleeps in memcpy_tomsg */ mutex_lock(&u->iolock); skip = max(sk_peek_offset(sk, flags), 0); do { int chunk; bool drop_skb; struct sk_buff *skb, *last; redo: unix_state_lock(sk); if (sock_flag(sk, SOCK_DEAD)) { err = -ECONNRESET; goto unlock; } last = skb = skb_peek(&sk->sk_receive_queue); last_len = last ? last->len : 0; again: if (skb == NULL) { if (copied >= target) goto unlock; /* * POSIX 1003.1g mandates this order. */ err = sock_error(sk); if (err) goto unlock; if (sk->sk_shutdown & RCV_SHUTDOWN) goto unlock; unix_state_unlock(sk); if (!timeo) { err = -EAGAIN; break; } mutex_unlock(&u->iolock); timeo = unix_stream_data_wait(sk, timeo, last, last_len, freezable); if (signal_pending(current)) { err = sock_intr_errno(timeo); scm_destroy(&scm); goto out; } mutex_lock(&u->iolock); goto redo; unlock: unix_state_unlock(sk); break; } while (skip >= unix_skb_len(skb)) { skip -= unix_skb_len(skb); last = skb; last_len = skb->len; skb = skb_peek_next(skb, &sk->sk_receive_queue); if (!skb) goto again; } unix_state_unlock(sk); if (check_creds) { /* Never glue messages from different writers */ if (!unix_skb_scm_eq(skb, &scm)) break; } else if (test_bit(SOCK_PASSCRED, &sock->flags)) { /* Copy credentials */ scm_set_cred(&scm, UNIXCB(skb).pid, UNIXCB(skb).uid, UNIXCB(skb).gid); unix_set_secdata(&scm, skb); check_creds = true; } /* Copy address just once */ if (state->msg && state->msg->msg_name) { DECLARE_SOCKADDR(struct sockaddr_un *, sunaddr, state->msg->msg_name); unix_copy_addr(state->msg, skb->sk); sunaddr = NULL; } chunk = min_t(unsigned int, unix_skb_len(skb) - skip, size); skb_get(skb); chunk = state->recv_actor(skb, skip, chunk, state); drop_skb = !unix_skb_len(skb); /* skb is only safe to use if !drop_skb */ consume_skb(skb); if (chunk < 0) { if (copied == 0) copied = -EFAULT; break; } copied += chunk; size -= chunk; if (drop_skb) { /* the skb was touched by a concurrent reader; * we should not expect anything from this skb * anymore and assume it invalid - we can be * sure it was dropped from the socket queue * * let's report a short read */ err = 0; break; } /* Mark read part of skb as used */ if (!(flags & MSG_PEEK)) { UNIXCB(skb).consumed += chunk; sk_peek_offset_bwd(sk, chunk); if (UNIXCB(skb).fp) unix_detach_fds(&scm, skb); if (unix_skb_len(skb)) break; skb_unlink(skb, &sk->sk_receive_queue); consume_skb(skb); if (scm.fp) break; } else { /* It is questionable, see note in unix_dgram_recvmsg. */ if (UNIXCB(skb).fp) scm.fp = scm_fp_dup(UNIXCB(skb).fp); sk_peek_offset_fwd(sk, chunk); if (UNIXCB(skb).fp) break; skip = 0; last = skb; last_len = skb->len; unix_state_lock(sk); skb = skb_peek_next(skb, &sk->sk_receive_queue); if (skb) goto again; unix_state_unlock(sk); break; } } while (size); mutex_unlock(&u->iolock); if (state->msg) scm_recv(sock, state->msg, &scm, flags); else scm_destroy(&scm); out: return copied ? : err; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)33839.49%1531.25%
Hannes Frederic Sowa14617.06%36.25%
Aaron Conole495.72%12.08%
Pavel Emelyanov465.37%12.08%
Rainer Weikusat394.56%36.25%
Eric Dumazet384.44%510.42%
Eric W. Biedermann374.32%36.25%
David S. Miller323.74%36.25%
Miklos Szeredi323.74%12.08%
Benjamin LaHaise252.92%12.08%
Benjamin Poirier171.99%12.08%
Andrey Vagin141.64%12.08%
Stephen D. Smalley111.29%12.08%
Linus Torvalds80.93%36.25%
Christoph Hellwig80.93%12.08%
Américo Wang50.58%12.08%
Arnaldo Carvalho de Melo40.47%12.08%
Matthew Dawson40.47%12.08%
Ingo Molnar20.23%12.08%
Neil Horman10.12%12.08%
Total856100.00%48100.00%


static int unix_stream_read_actor(struct sk_buff *skb, int skip, int chunk, struct unix_stream_read_state *state) { int ret; ret = skb_copy_datagram_msg(skb, UNIXCB(skb).consumed + skip, state->msg, chunk); return ret ?: chunk; }

Contributors

PersonTokensPropCommitsCommitProp
Hannes Frederic Sowa53100.00%1100.00%
Total53100.00%1100.00%


static int unix_stream_recvmsg(struct socket *sock, struct msghdr *msg, size_t size, int flags) { struct unix_stream_read_state state = { .recv_actor = unix_stream_read_actor, .socket = sock, .msg = msg, .size = size, .flags = flags }; return unix_stream_read_generic(&state, true); }

Contributors

PersonTokensPropCommitsCommitProp
Hannes Frederic Sowa6096.77%150.00%
Américo Wang23.23%150.00%
Total62100.00%2100.00%


static int unix_stream_splice_actor(struct sk_buff *skb, int skip, int chunk, struct unix_stream_read_state *state) { return skb_splice_bits(skb, state->socket->sk, UNIXCB(skb).consumed + skip, state->pipe, chunk, state->splice_flags); }

Contributors

PersonTokensPropCommitsCommitProp
Hannes Frederic Sowa53100.00%1100.00%
Total53100.00%1100.00%


static ssize_t unix_stream_splice_read(struct socket *sock, loff_t *ppos, struct pipe_inode_info *pipe, size_t size, unsigned int flags) { struct unix_stream_read_state state = { .recv_actor = unix_stream_splice_actor, .socket = sock, .pipe = pipe, .size = size, .splice_flags = flags, }; if (unlikely(*ppos)) return -ESPIPE; if (sock->file->f_flags & O_NONBLOCK || flags & SPLICE_F_NONBLOCK) state.flags = MSG_DONTWAIT; return unix_stream_read_generic(&state, false); }

Contributors

PersonTokensPropCommitsCommitProp
Hannes Frederic Sowa9797.98%150.00%
Américo Wang22.02%150.00%
Total99100.00%2100.00%


static int unix_shutdown(struct socket *sock, int mode) { struct sock *sk = sock->sk; struct sock *other; if (mode < SHUT_RD || mode > SHUT_RDWR) return -EINVAL; /* This maps: * SHUT_RD (0) -> RCV_SHUTDOWN (1) * SHUT_WR (1) -> SEND_SHUTDOWN (2) * SHUT_RDWR (2) -> SHUTDOWN_MASK (3) */ ++mode; unix_state_lock(sk); sk->sk_shutdown |= mode; other = unix_peer(sk); if (other) sock_hold(other); unix_state_unlock(sk); sk->sk_state_change(sk); if (other && (sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_SEQPACKET)) { int peer_mode = 0; if (mode&RCV_SHUTDOWN) peer_mode |= SEND_SHUTDOWN; if (mode&SEND_SHUTDOWN) peer_mode |= RCV_SHUTDOWN; unix_state_lock(other); other->sk_shutdown |= peer_mode; unix_state_unlock(other); other->sk_state_change(other); if (peer_mode == SHUTDOWN_MASK) sk_wake_async(other, SOCK_WAKE_WAITD, POLL_HUP); else if (peer_mode & RCV_SHUTDOWN) sk_wake_async(other, SOCK_WAKE_WAITD, POLL_IN); } if (other) sock_put(other); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)16182.14%956.25%
Xi Wang126.12%16.25%
Steven Dake84.08%16.25%
Arnaldo Carvalho de Melo73.57%212.50%
David S. Miller42.04%16.25%
Alban Crequy21.02%16.25%
Pavel Emelyanov21.02%16.25%
Total196100.00%16100.00%


long unix_inq_len(struct sock *sk) { struct sk_buff *skb; long amount = 0; if (sk->sk_state == TCP_LISTEN) return -EINVAL; spin_lock(&sk->sk_receive_queue.lock); if (sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_SEQPACKET) { skb_queue_walk(&sk->sk_receive_queue, skb) amount += unix_skb_len(skb); } else { skb = skb_peek(&sk->sk_receive_queue); if (skb) amount = skb->len; } spin_unlock(&sk->sk_receive_queue.lock); return amount; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)5551.40%342.86%
David S. Miller2927.10%114.29%
Pavel Emelyanov1211.21%114.29%
Arnaldo Carvalho de Melo87.48%114.29%
Eric Dumazet32.80%114.29%
Total107100.00%7100.00%

EXPORT_SYMBOL_GPL(unix_inq_len);
long unix_outq_len(struct sock *sk) { return sk_wmem_alloc_get(sk); }

Contributors

PersonTokensPropCommitsCommitProp
Pavel Emelyanov16100.00%1100.00%
Total16100.00%1100.00%

EXPORT_SYMBOL_GPL(unix_outq_len);
static int unix_open_file(struct sock *sk) { struct path path; struct file *f; int fd; if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) return -EPERM; unix_state_lock(sk); path = unix_sk(sk)->path; if (!path.dentry) { unix_state_unlock(sk); return -ENOENT; } path_get(&path); unix_state_unlock(sk); fd = get_unused_fd_flags(O_CLOEXEC); if (fd < 0) goto out; f = dentry_open(&path, O_PATH, current_cred()); if (IS_ERR(f)) { put_unused_fd(fd); fd = PTR_ERR(f); goto out; } fd_install(fd, f); out: path_put(&path); return fd; }

Contributors

PersonTokensPropCommitsCommitProp
Andrey Vagin156100.00%1100.00%
Total156100.00%1100.00%


static int unix_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { struct sock *sk = sock->sk; long amount = 0; int err; switch (cmd) { case SIOCOUTQ: amount = unix_outq_len(sk); err = put_user(amount, (int __user *)arg); break; case SIOCINQ: amount = unix_inq_len(sk); if (amount < 0) err = amount; else err = put_user(amount, (int __user *)arg); break; case SIOCUNIXFILE: err = unix_open_file(sk); break; default: err = -ENOIOCTLCMD; break; } return err; }

Contributors

PersonTokensPropCommitsCommitProp
Pavel Emelyanov8669.35%114.29%
Linus Torvalds (pre-git)2419.35%342.86%
Andrey Vagin118.87%114.29%
Christoph Hellwig21.61%114.29%
Al Viro10.81%114.29%
Total124100.00%7100.00%


static unsigned int unix_poll(struct file *file, struct socket *sock, poll_table *wait) { struct sock *sk = sock->sk; unsigned int mask; sock_poll_wait(file, sk_sleep(sk), wait); mask = 0; /* exceptional events? */ if (sk->sk_err) mask |= POLLERR; if (sk->sk_shutdown == SHUTDOWN_MASK) mask |= POLLHUP; if (sk->sk_shutdown & RCV_SHUTDOWN) mask |= POLLRDHUP | POLLIN | POLLRDNORM; /* readable? */ if (!skb_queue_empty(&sk->sk_receive_queue)) mask |= POLLIN | POLLRDNORM; /* Connection-based need to check for termination and startup */ if ((sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_SEQPACKET) && sk->sk_state == TCP_CLOSE) mask |= POLLHUP; /* * we set writable also when the other side has shut down the * connection. This prevents stuck sockets. */ if (unix_writable(sk)) mask |= POLLOUT | POLLWRNORM | POLLWRBAND; return mask; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)11977.78%333.33%
Davide Libenzi127.84%111.11%
Steven Dake85.23%111.11%
Eric Dumazet74.58%222.22%
Arnaldo Carvalho de Melo63.92%111.11%
Jiri Olsa10.65%111.11%
Total153100.00%9100.00%


static unsigned int unix_dgram_poll(struct file *file, struct socket *sock, poll_table *wait) { struct sock *sk = sock->sk, *other; unsigned int mask, writable; sock_poll_wait(file, sk_sleep(sk), wait); mask = 0; /* exceptional events? */ if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue)) mask |= POLLERR | (sock_flag(sk, SOCK_SELECT_ERR_QUEUE) ? POLLPRI : 0); if (sk->sk_shutdown & RCV_SHUTDOWN) mask |= POLLRDHUP | POLLIN | POLLRDNORM; if (sk->sk_shutdown == SHUTDOWN_MASK) mask |= POLLHUP; /* readable? */ if (!skb_queue_empty(&sk->sk_receive_queue)) mask |= POLLIN | POLLRDNORM; /* Connection-based need to check for termination and startup */ if (sk->sk_type == SOCK_SEQPACKET) { if (sk->sk_state == TCP_CLOSE) mask |= POLLHUP; /* connection hasn't started yet? */ if (sk->sk_state == TCP_SYN_SENT) return mask; } /* No write status requested, avoid expensive OUT tests. */ if (!(poll_requested_events(wait) & (POLLWRBAND|POLLWRNORM|POLLOUT))) return mask; writable = unix_writable(sk); if (writable) { unix_state_lock(sk); other = unix_peer(sk); if (other && unix_peer(other) != sk && unix_recvq_full(other) && unix_dgram_peer_wake_me(sk, other)) writable = 0; unix_state_unlock(sk); } if (writable) mask |= POLLOUT | POLLWRNORM | POLLWRBAND; else sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk); return mask; }

Contributors

PersonTokensPropCommitsCommitProp
Rainer Weikusat22683.39%327.27%
Eric Dumazet2810.33%436.36%
Jacob E Keller134.80%218.18%
Hans Verkuil31.11%19.09%
Jiri Olsa10.37%19.09%
Total271100.00%11100.00%

#ifdef CONFIG_PROC_FS #define BUCKET_SPACE (BITS_PER_LONG - (UNIX_HASH_BITS + 1) - 1) #define get_bucket(x) ((x) >> BUCKET_SPACE) #define get_offset(x) ((x) & ((1L << BUCKET_SPACE) - 1)) #define set_bucket_offset(b, o) ((b) << BUCKET_SPACE | (o))
static struct sock *unix_from_bucket(struct seq_file *seq, loff_t *pos) { unsigned long offset = get_offset(*pos); unsigned long bucket = get_bucket(*pos); struct sock *sk; unsigned long count = 0; for (sk = sk_head(&unix_socket_table[bucket]); sk; sk = sk_next(sk)) { if (sock_net(sk) != seq_file_net(seq)) continue; if (++count == offset) break; } return sk; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Dumazet4748.96%111.11%
Stephen Hemminger1717.71%111.11%
Linus Torvalds (pre-git)1212.50%333.33%
Hideaki Yoshifuji / 吉藤英明1111.46%222.22%
Denis V. Lunev77.29%111.11%
Arnaldo Carvalho de Melo22.08%111.11%
Total96100.00%9100.00%


static struct sock *unix_next_socket(struct seq_file *seq, struct sock *sk, loff_t *pos) { unsigned long bucket; while (sk > (struct sock *)SEQ_START_TOKEN) { sk = sk_next(sk); if (!sk) goto next_bucket; if (sock_net(sk) == seq_file_net(seq)) return sk; } do { sk = unix_from_bucket(seq, pos); if (sk) return sk; next_bucket: bucket = get_bucket(*pos) + 1; *pos = set_bucket_offset(bucket, 1); } while (bucket < ARRAY_SIZE(unix_socket_table)); return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Dumazet11291.06%133.33%
Stephen Hemminger108.13%133.33%
Linus Torvalds (pre-git)10.81%133.33%
Total123100.00%3100.00%


static void *unix_seq_start(struct seq_file *seq, loff_t *pos) __acquires(unix_table_lock) { spin_lock(&unix_table_lock); if (!*pos) return SEQ_START_TOKEN; if (get_bucket(*pos) >= ARRAY_SIZE(unix_socket_table)) return NULL; return unix_next_socket(seq, NULL, pos); }

Contributors

PersonTokensPropCommitsCommitProp
Eric Dumazet3049.18%228.57%
Stephen Hemminger2134.43%114.29%
Linus Torvalds (pre-git)813.11%228.57%
Hideaki Yoshifuji / 吉藤英明11.64%114.29%
David S. Miller11.64%114.29%
Total61100.00%7100.00%


static void *unix_seq_next(struct seq_file *seq, void *v, loff_t *pos) { ++*pos; return unix_next_socket(seq, v, pos); }

Contributors

PersonTokensPropCommitsCommitProp
Stephen Hemminger2676.47%125.00%
Eric Dumazet514.71%125.00%
Hideaki Yoshifuji / 吉藤英明25.88%125.00%
Denis V. Lunev12.94%125.00%
Total34100.00%4100.00%


static void unix_seq_stop(struct seq_file *seq, void *v) __releases(unix_table_lock) { spin_unlock(&unix_table_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Stephen Hemminger2080.00%133.33%
Eric Dumazet416.00%133.33%
David S. Miller14.00%133.33%
Total25100.00%3100.00%


static int unix_seq_show(struct seq_file *seq, void *v) { if (v == SEQ_START_TOKEN) seq_puts(seq, "Num RefCount Protocol Flags Type St " "Inode Path\n"); else { struct sock *s = v; struct unix_sock *u = unix_sk(s); unix_state_lock(s); seq_printf(seq, "%pK: %08X %08X %08X %04X %02X %5lu", s, refcount_read(&s->sk_refcnt), 0, s->sk_state == TCP_LISTEN ? __SO_ACCEPTCON : 0, s->sk_type, s->sk_socket ? (s->sk_state == TCP_ESTABLISHED ? SS_CONNECTED : SS_UNCONNECTED) : (s->sk_state == TCP_ESTABLISHED ? SS_CONNECTING : SS_DISCONNECTING), sock_i_ino(s)); if (u->addr) { int i, len; seq_putc(seq, ' '); i = 0; len = u->addr->len - sizeof(short); if (!UNIX_ABSTRACT(s)) len--; else { seq_putc(seq, '@'); i++; } for ( ; i < len; i++) seq_putc(seq, u->addr->name->sun_path[i] ?: '@'); } unix_state_unlock(s); seq_putc(seq, '\n'); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)8136.00%844.44%
David S. Miller6528.89%316.67%
Stephen Hemminger5323.56%15.56%
Hirofumi Ogawa146.22%15.56%
Arnaldo Carvalho de Melo62.67%15.56%
Isaac Boukris31.33%15.56%
Dan Rosenberg10.44%15.56%
Elena Reshetova10.44%15.56%
Joe Perches10.44%15.56%
Total225100.00%18100.00%

static const struct seq_operations unix_seq_ops = { .start = unix_seq_start, .next = unix_seq_next, .stop = unix_seq_stop, .show = unix_seq_show, };
static int unix_seq_open(struct inode *inode, struct file *file) { return seq_open_net(inode, file, &unix_seq_ops, sizeof(struct seq_net_private)); }

Contributors

PersonTokensPropCommitsCommitProp
David S. Miller2266.67%120.00%
Denis V. Lunev721.21%240.00%
Pavel Emelyanov39.09%120.00%
Eric Dumazet13.03%120.00%
Total33100.00%5100.00%

static const struct file_operations unix_seq_fops = { .owner = THIS_MODULE, .open = unix_seq_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release_net, }; #endif static const struct net_proto_family unix_family_ops = { .family = PF_UNIX, .create = unix_create, .owner = THIS_MODULE, };
static int __net_init unix_net_init(struct net *net) { int error = -ENOMEM; net->unx.sysctl_max_dgram_qlen = 10; if (unix_sysctl_register(net)) goto out; #ifdef CONFIG_PROC_FS if (!proc_create("unix", 0, net->proc_net, &unix_seq_fops)) { unix_sysctl_unregister(net); goto out; } #endif error = 0; out: return error; }

Contributors

PersonTokensPropCommitsCommitProp
Denis V. Lunev4862.34%228.57%
Pavel Emelyanov2228.57%228.57%
Gao Feng56.49%114.29%
Alexey Dobriyan11.30%114.29%
Jianjun Kong11.30%114.29%
Total77100.00%7100.00%


static void __net_exit unix_net_exit(struct net *net) { unix_sysctl_unregister(net); remove_proc_entry("unix", net->proc_net); }

Contributors

PersonTokensPropCommitsCommitProp
Denis V. Lunev1557.69%125.00%
Gao Feng519.23%125.00%
Pavel Emelyanov519.23%125.00%
Alexey Dobriyan13.85%125.00%
Total26100.00%4100.00%

static struct pernet_operations unix_net_ops = { .init = unix_net_init, .exit = unix_net_exit, };
static int __init af_unix_init(void) { int rc = -1; BUILD_BUG_ON(sizeof(struct unix_skb_parms) > FIELD_SIZEOF(struct sk_buff, cb)); rc = proto_register(&unix_proto, 1); if (rc != 0) { pr_crit("%s: Cannot create unix_sock SLAB cache!\n", __func__); goto out; } sock_register(&unix_family_ops); register_pernet_subsys(&unix_net_ops); out: return rc; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)3140.26%847.06%
Arnaldo Carvalho de Melo2431.17%15.88%
David S. Miller1114.29%211.76%
Hideaki Yoshifuji / 吉藤英明67.79%211.76%
Denis V. Lunev22.60%15.88%
Wang Weidong11.30%15.88%
Eric W. Biedermann11.30%15.88%
Harvey Harrison11.30%15.88%
Total77100.00%17100.00%


static void __exit af_unix_exit(void) { sock_unregister(PF_UNIX); proto_unregister(&unix_proto); unregister_pernet_subsys(&unix_net_ops); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)1765.38%450.00%
Denis V. Lunev415.38%112.50%
David S. Miller311.54%112.50%
Eric W. Biedermann13.85%112.50%
Arnaldo Carvalho de Melo13.85%112.50%
Total26100.00%8100.00%

/* Earlier than device_initcall() so that other drivers invoking request_module() don't end up in a loop when modprobe tries to use a UNIX socket. But later than subsys_initcall() because we depend on stuff initialised there */ fs_initcall(af_unix_init); module_exit(af_unix_exit); MODULE_LICENSE("GPL"); MODULE_ALIAS_NETPROTO(PF_UNIX);

Overall Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)531440.38%6321.43%
David S. Miller141610.76%186.12%
Hannes Frederic Sowa12649.60%72.38%
Rainer Weikusat8966.81%113.74%
Eric Dumazet7595.77%289.52%
Eric W. Biedermann4313.27%82.72%
Pavel Emelyanov3452.62%113.74%
Arnaldo Carvalho de Melo2872.18%93.06%
Al Viro1991.51%144.76%
Andrey Vagin1841.40%20.68%
James Morris1801.37%41.36%
Denis V. Lunev1751.33%31.02%
Stephen Hemminger1561.19%41.36%
Linus Torvalds1531.16%93.06%
Benjamin LaHaise1381.05%41.36%
Miklos Szeredi1080.82%51.70%
Américo Wang1020.78%20.68%
Catherine Zhang940.71%20.68%
Stephen D. Smalley760.58%10.34%
Daniel Borkmann680.52%10.34%
Willy Tarreau640.49%10.34%
Alban Crequy550.42%31.02%
Steven Dake490.37%10.34%
Aaron Conole490.37%10.34%
Hideaki Yoshifuji / 吉藤英明470.36%62.04%
Florian Zumbiehl380.29%10.34%
Christoph Hellwig340.26%41.36%
Solar Designer320.24%10.34%
Sasha Levin310.24%20.68%
Mateusz Jurczyk300.23%10.34%
Kirill Tkhai300.23%10.34%
Tetsuo Handa290.22%10.34%
Ingo Molnar280.21%41.36%
Benjamin Poirier260.20%10.34%
Rusty Russell230.17%20.68%
Herbert Pötzl210.16%10.34%
David Howells200.15%41.36%
Hirofumi Ogawa140.11%10.34%
Jacob E Keller130.10%20.68%
Andrew Morton130.10%20.68%
Davide Libenzi120.09%10.34%
Xi Wang120.09%10.34%
Tomoki Sekiyama110.08%10.34%
Gao Feng100.08%20.68%
Wang Weidong100.08%10.34%
Paul Moore80.06%10.34%
Elena Reshetova80.06%31.02%
Steffen Hurrle80.06%10.34%
Cyrill V. Gorcunov70.05%10.34%
Ray Lee70.05%10.34%
Jan Blunck60.05%20.68%
Ilpo Järvinen60.05%10.34%
dann frazier60.05%10.34%
Vladimir Davydov60.05%10.34%
Matthew Dawson40.03%10.34%
Colin Cross40.03%10.34%
Anton Blanchard30.02%10.34%
Hans Verkuil30.02%10.34%
Eric Paris30.02%10.34%
Thomas Gleixner30.02%10.34%
Greg Kroah-Hartman30.02%10.34%
Isaac Boukris30.02%10.34%
Dipankar Sarma20.02%10.34%
Alexey Dobriyan20.02%10.34%
Alan Cox20.02%20.68%
Paolo Abeni20.02%10.34%
David Woodhouse20.02%10.34%
Jiri Olsa20.02%10.34%
Philippe De Muyter10.01%10.34%
Neil Horman10.01%10.34%
Lucas De Marchi10.01%10.34%
Daniel Baluta10.01%10.34%
Joe Perches10.01%10.34%
Jianjun Kong10.01%10.34%
Peter Zijlstra10.01%10.34%
Panagiotis Issaris10.01%10.34%
Herbert Xu10.01%10.34%
Gustavo A. R. Silva10.01%10.34%
David Herrmann10.01%10.34%
Kees Cook10.01%10.34%
Harvey Harrison10.01%10.34%
Arjan van de Ven10.01%10.34%
Dan Rosenberg10.01%10.34%
Total13161100.00%294100.00%
Directory: net/unix
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.