Commit fa42d910 authored by Al Viro's avatar Al Viro Committed by David S. Miller
Browse files

unix_bind(): take BSD and abstract address cases into new helpers



unix_bind_bsd() and unix_bind_abstract() respectively.

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent aee51517
Loading
Loading
Loading
Loading
+74 −73
Original line number Diff line number Diff line
@@ -1014,63 +1014,29 @@ static int unix_mknod(const char *sun_path, umode_t mode, struct path *res)
	return err;
}

static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
static int unix_bind_bsd(struct sock *sk, struct unix_address *addr)
{
	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;

	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;
	err = -ENOMEM;
	addr = kmalloc(sizeof(*addr)+addr_len, GFP_KERNEL);
	if (!addr)
		goto out;

	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]) {
	struct path path = { };
	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_addr;
		}
	       (SOCK_INODE(sk->sk_socket)->i_mode & ~current_umask());
	unsigned int hash;
	int err;

	err = unix_mknod(addr->name->sun_path, mode, &path);
	if (err)
		return err;

	err = mutex_lock_interruptible(&u->bindlock);
	if (err) {
		path_put(&path);
			goto out_addr;
		return err;
	}

		err = -EINVAL;
	if (u->addr) {
		mutex_unlock(&u->bindlock);
		path_put(&path);
			goto out_addr;
		return -EINVAL;
	}

	addr->hash = UNIX_HASH_SIZE;
@@ -1080,38 +1046,73 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
	__unix_set_addr(sk, addr, hash);
	spin_unlock(&unix_table_lock);
	mutex_unlock(&u->bindlock);
		addr = NULL;
		err = 0;
	} else {
	return 0;
}

static int unix_bind_abstract(struct sock *sk, unsigned hash,
			      struct unix_address *addr)
{
	struct unix_sock *u = unix_sk(sk);
	int err;

	err = mutex_lock_interruptible(&u->bindlock);
	if (err)
			goto out_addr;
		return err;

		err = -EINVAL;
	if (u->addr) {
		mutex_unlock(&u->bindlock);
			goto out_addr;
		return -EINVAL;
	}

	spin_lock(&unix_table_lock);
		err = -EADDRINUSE;
		if (__unix_find_socket_byname(net, sunaddr, addr_len,
	if (__unix_find_socket_byname(sock_net(sk), addr->name, addr->len,
				      sk->sk_type, hash)) {
		spin_unlock(&unix_table_lock);
		mutex_unlock(&u->bindlock);
			goto out_addr;
		return -EADDRINUSE;
	}
	__unix_set_addr(sk, addr, addr->hash);
	spin_unlock(&unix_table_lock);
	mutex_unlock(&u->bindlock);
		addr = NULL;
		err = 0;
	return 0;
}
out_addr:
	if (addr)
		unix_release_addr(addr);
out:

static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
{
	struct sock *sk = sock->sk;
	struct sockaddr_un *sunaddr = (struct sockaddr_un *)uaddr;
	char *sun_path = sunaddr->sun_path;
	int err;
	unsigned int hash;
	struct unix_address *addr;

	if (addr_len < offsetofend(struct sockaddr_un, sun_family) ||
	    sunaddr->sun_family != AF_UNIX)
		return -EINVAL;

	if (addr_len == sizeof(short))
		return unix_autobind(sock);

	err = unix_mkname(sunaddr, addr_len, &hash);
	if (err < 0)
		return err;
	addr_len = err;
	addr = kmalloc(sizeof(*addr)+addr_len, GFP_KERNEL);
	if (!addr)
		return -ENOMEM;

	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])
		err = unix_bind_bsd(sk, addr);
	else
		err = unix_bind_abstract(sk, hash, addr);
	if (err)
		unix_release_addr(addr);
	return err == -EEXIST ? -EADDRINUSE : err;
}

static void unix_state_double_lock(struct sock *sk1, struct sock *sk2)