Subject: [PATCH] af_unix nethost support From: Eric W. Biederman Date: 1133650739 -0700 Initially I thought af_unix needed no updates but it turns out that the af_unix namespace really isn't the filesystem namespace so I needed some additional checks. In addition looking at the code I realized that becasue of fork and unix domain open file passing the lifetime of sockets does not necessarily match the lifetime of the processes in a nethost. So af_unix sockets now get/put the struct nethost count. --- net/unix/af_unix.c | 43 ++++++++++++++++++++++++++----------------- 1 files changed, 26 insertions(+), 17 deletions(-) d40e1fb01e49633cbb736d576df66e0360678ee7 diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 3ccf9e0..08f4dce 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -117,6 +117,7 @@ #include #include #include +#include int sysctl_unix_max_dgram_qlen = 10; @@ -226,7 +227,8 @@ static inline void unix_insert_socket(st write_unlock(&unix_table_lock); } -static struct sock *__unix_find_socket_byname(struct sockaddr_un *sunname, +static struct sock *__unix_find_socket_byname(struct nethost *host, + struct sockaddr_un *sunname, int len, int type, unsigned hash) { struct sock *s; @@ -235,7 +237,7 @@ static struct sock *__unix_find_socket_b sk_for_each(s, node, &unix_socket_table[hash ^ type]) { struct unix_sock *u = unix_sk(s); - if (u->addr->len == len && + if (s->sk_host == host && u->addr->len == len && !memcmp(u->addr->name, sunname, len)) goto found; } @@ -244,21 +246,22 @@ found: return s; } -static inline struct sock *unix_find_socket_byname(struct sockaddr_un *sunname, +static inline struct sock *unix_find_socket_byname(struct nethost *host, + struct sockaddr_un *sunname, int len, int type, unsigned hash) { struct sock *s; read_lock(&unix_table_lock); - s = __unix_find_socket_byname(sunname, len, type, hash); + s = __unix_find_socket_byname(host, sunname, len, type, hash); if (s) sock_hold(s); read_unlock(&unix_table_lock); return s; } -static struct sock *unix_find_socket_byinode(struct inode *i) +static struct sock *unix_find_socket_byinode(struct nethost *host, struct inode *i) { struct sock *s; struct hlist_node *node; @@ -268,7 +271,7 @@ static struct sock *unix_find_socket_byi &unix_socket_table[i->i_ino & (UNIX_HASH_SIZE - 1)]) { struct dentry *dentry = unix_sk(s)->dentry; - if(dentry && dentry->d_inode == i) + if (s->sk_host == host && dentry && dentry->d_inode == i) { sock_hold(s); goto found; @@ -398,6 +401,8 @@ static int unix_release_sock (struct soc mntput(mnt); } + put_host(sk->sk_host); + sk->sk_host = NULL; sock_put(sk); /* ---- Socket is dead now and most probably destroyed ---- */ @@ -554,7 +559,8 @@ static struct sock * unix_create1(struct if (!sk) goto out; - sk->sk_host = NULL; + sk->sk_host = current->host; + get_host(sk->sk_host); atomic_inc(&unix_nr_socks); sock_init_data(sock,sk); @@ -646,8 +652,8 @@ retry: write_lock(&unix_table_lock); ordernum = (ordernum+1)&0xFFFFF; - if (__unix_find_socket_byname(addr->name, addr->len, sock->type, - addr->hash)) { + if (__unix_find_socket_byname(sk->sk_host, addr->name, addr->len, + sock->type, addr->hash)) { write_unlock(&unix_table_lock); /* Sanity yield. It is unusual case, but yet... */ if (!(ordernum&0xFF)) @@ -666,7 +672,8 @@ out: up(&u->readsem); return err; } -static struct sock *unix_find_other(struct sockaddr_un *sunname, int len, +static struct sock *unix_find_other(struct nethost *host, + struct sockaddr_un *sunname, int len, int type, unsigned hash, int *error) { struct sock *u; @@ -684,7 +691,7 @@ static struct sock *unix_find_other(stru err = -ECONNREFUSED; if (!S_ISSOCK(nd.dentry->d_inode->i_mode)) goto put_fail; - u=unix_find_socket_byinode(nd.dentry->d_inode); + u=unix_find_socket_byinode(host, nd.dentry->d_inode); if (!u) goto put_fail; @@ -700,7 +707,7 @@ static struct sock *unix_find_other(stru } } else { err = -ECONNREFUSED; - u=unix_find_socket_byname(sunname, len, type, hash); + u=unix_find_socket_byname(host, sunname, len, type, hash); if (u) { struct dentry *dentry; dentry = unix_sk(u)->dentry; @@ -796,7 +803,7 @@ static int unix_bind(struct socket *sock if (!sunaddr->sun_path[0]) { err = -EADDRINUSE; - if (__unix_find_socket_byname(sunaddr, addr_len, + if (__unix_find_socket_byname(sk->sk_host, sunaddr, addr_len, sk->sk_type, hash)) { unix_release_addr(addr); goto out_unlock; @@ -852,7 +859,8 @@ static int unix_dgram_connect(struct soc !unix_sk(sk)->addr && (err = unix_autobind(sock)) != 0) goto out; - other=unix_find_other(sunaddr, alen, sock->type, hash, &err); + other=unix_find_other(sk->sk_host, sunaddr, alen, sock->type, + hash, &err); if (!other) goto out; @@ -964,7 +972,8 @@ static int unix_stream_connect(struct so restart: /* Find listening sock. */ - other = unix_find_other(sunaddr, addr_len, sk->sk_type, hash, &err); + other = unix_find_other(sk->sk_host, sunaddr, addr_len, sk->sk_type, + hash, &err); if (!other) goto out; @@ -1303,8 +1312,8 @@ restart: if (sunaddr == NULL) goto out_free; - other = unix_find_other(sunaddr, namelen, sk->sk_type, - hash, &err); + other = unix_find_other(sk->sk_host, sunaddr, namelen, + sk->sk_type, hash, &err); if (other==NULL) goto out_free; } -- 1.0.GIT