cregit-Linux how code gets into the kernel

Release 4.8 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.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 <asm/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>


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 dumazeteric dumazet4697.87%150.00%
pre-gitpre-git12.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 zhangcatherine zhang2385.19%266.67%
stephen d. smalleystephen 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 zhangcatherine zhang2589.29%266.67%
stephen d. smalleystephen 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. smalleystephen 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 zhangcatherine zhang1593.75%266.67%
andrew mortonandrew 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 zhangcatherine 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. smalleystephen 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
pre-gitpre-git2152.50%342.86%
al viroal viro1127.50%114.29%
eric dumazeteric dumazet37.50%114.29%
anton blanchardanton blanchard37.50%114.29%
linus torvaldslinus 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
pre-gitpre-git1976.00%250.00%
arnaldo carvalho de meloarnaldo carvalho de melo416.00%125.00%
linus torvaldslinus 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
pre-gitpre-git2681.25%571.43%
arnaldo carvalho de meloarnaldo carvalho de melo412.50%114.29%
linus torvaldslinus 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 weikusatrainer 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
pre-gitpre-git3882.61%675.00%
arnaldo carvalho de meloarnaldo carvalho de melo613.04%112.50%
david s. millerdavid 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 (atomic_dec_and_test(&addr->refcnt)) kfree(addr); }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git2592.59%250.00%
david s. millerdavid s. miller13.70%125.00%
linus torvaldslinus torvalds13.70%125.00%
Total27100.00%4100.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
pre-gitpre-git11598.29%250.00%
lucas de marchilucas de marchi10.85%125.00%
eric dumazeteric dumazet10.85%125.00%
Total117100.00%4100.00%


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

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git1168.75%360.00%
arnaldo carvalho de meloarnaldo 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
pre-gitpre-git1959.38%342.86%
arnaldo carvalho de meloarnaldo carvalho de melo1031.25%228.57%
ilpo jarvinenilpo jarvinen26.25%114.29%
david s. millerdavid 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
pre-gitpre-git2482.76%240.00%
david s. millerdavid s. miller26.90%120.00%
arnaldo carvalho de meloarnaldo carvalho de melo26.90%120.00%
linus torvaldslinus 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
pre-gitpre-git2980.56%233.33%
arnaldo carvalho de meloarnaldo carvalho de melo411.11%233.33%
david s. millerdavid s. miller25.56%116.67%
linus torvaldslinus 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
pre-gitpre-git4847.52%330.00%
arnaldo carvalho de meloarnaldo carvalho de melo1918.81%220.00%
david s. millerdavid s. miller1413.86%110.00%
denis v. lunevdenis v. lunev1110.89%110.00%
hideaki yoshifujihideaki yoshifuji87.92%220.00%
eric dumazeteric 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
pre-gitpre-git5879.45%337.50%
denis v. lunevdenis v. lunev79.59%112.50%
arnaldo carvalho de meloarnaldo carvalho de melo45.48%112.50%
david s. millerdavid s. miller22.74%112.50%
linus torvaldslinus torvalds11.37%112.50%
eric dumazeteric dumazet11.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_real_inode(dentry) == i) { sock_hold(s); goto found; } } s = NULL; found: spin_unlock(&unix_table_lock); return s; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git5464.29%436.36%
arnaldo carvalho de meloarnaldo carvalho de melo2023.81%218.18%
david s. millerdavid s. miller55.95%218.18%
david howellsdavid howells22.38%19.09%
al viroal viro22.38%19.09%
miklos szeredimiklos 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_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_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 weikusatrainer weikusat91100.00%1100.00%
Total91100.00%1100.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 weikusatrainer 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 weikusatrainer 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 weikusatrainer 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 weikusatrainer weikusat52100.00%1100.00%
Total52100.00%1100.00%


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

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git2674.29%360.00%
eric dumazeteric dumazet720.00%120.00%
arnaldo carvalho de meloarnaldo carvalho de melo25.71%120.00%
Total35100.00%5100.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
pre-gitpre-git3854.29%763.64%
eric dumazeteric dumazet3042.86%218.18%
herbert xuherbert xu11.43%19.09%
pavel emelianovpavel emelianov11.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
pre-gitpre-git6782.72%116.67%
arnaldo carvalho de meloarnaldo carvalho de melo78.64%233.33%
david s. millerdavid s. miller56.17%233.33%
james morrisjames 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(atomic_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
pre-gitpre-git7958.96%323.08%
david s. millerdavid s. miller1813.43%215.38%
eric dumazeteric dumazet1813.43%215.38%
arnaldo carvalho de meloarnaldo carvalho de melo107.46%323.08%
ilpo jarvinenilpo jarvinen42.99%17.69%
james morrisjames morris32.24%17.69%
wang weidongwang weidong21.49%17.69%
Total134100.00%13100.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
pre-gitpre-git21975.26%1150.00%
david s. millerdavid s. miller186.19%29.09%
arnaldo carvalho de meloarnaldo carvalho de melo144.81%29.09%
al viroal viro134.47%14.55%
hannes frederic sowahannes frederic sowa113.78%14.55%
rainer weikusatrainer weikusat72.41%14.55%
steven dakesteven dake62.06%14.55%
pavel emelianovpavel emelianov10.34%14.55%
paul moorepaul moore10.34%14.55%
alan coxalan cox10.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. biedermaneric w. biederman50100.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. biedermaneric w. biederman58100.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
pre-gitpre-git11874.21%750.00%
david s. millerdavid s. miller148.81%214.29%
eric w. biedermaneric w. biederman138.18%17.14%
steven dakesteven dake74.40%17.14%
arnaldo carvalho de meloarnaldo carvalho de melo53.14%17.14%
david howellsdavid howells10.63%17.14%
pavel emelianovpavel emelianov10.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); 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 emelianovpavel emelianov4174.55%133.33%
sasha levinsasha levin1221.82%133.33%
linus torvaldslinus 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