|
|
@@ -888,7 +888,7 @@ retry:
|
|
|
addr->hash ^= sk->sk_type;
|
|
|
|
|
|
__unix_remove_socket(sk);
|
|
|
- u->addr = addr;
|
|
|
+ smp_store_release(&u->addr, addr);
|
|
|
__unix_insert_socket(&unix_socket_table[addr->hash], sk);
|
|
|
spin_unlock(&unix_table_lock);
|
|
|
err = 0;
|
|
|
@@ -1058,7 +1058,7 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
|
|
|
|
|
|
err = 0;
|
|
|
__unix_remove_socket(sk);
|
|
|
- u->addr = addr;
|
|
|
+ smp_store_release(&u->addr, addr);
|
|
|
__unix_insert_socket(list, sk);
|
|
|
|
|
|
out_unlock:
|
|
|
@@ -1329,15 +1329,29 @@ restart:
|
|
|
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;
|
|
|
- }
|
|
|
+ /* copy address information from listening to new sock
|
|
|
+ *
|
|
|
+ * The contents of *(otheru->addr) and otheru->path
|
|
|
+ * are seen fully set up here, since we have found
|
|
|
+ * otheru in hash under unix_table_lock. Insertion
|
|
|
+ * into the hash chain we'd found it in had been done
|
|
|
+ * in an earlier critical area protected by unix_table_lock,
|
|
|
+ * the same one where we'd set *(otheru->addr) contents,
|
|
|
+ * as well as otheru->path and otheru->addr itself.
|
|
|
+ *
|
|
|
+ * Using smp_store_release() here to set newu->addr
|
|
|
+ * is enough to make those stores, as well as stores
|
|
|
+ * to newu->path visible to anyone who gets newu->addr
|
|
|
+ * by smp_load_acquire(). IOW, the same warranties
|
|
|
+ * as for unix_sock instances bound in unix_bind() or
|
|
|
+ * in unix_autobind().
|
|
|
+ */
|
|
|
if (otheru->path.dentry) {
|
|
|
path_get(&otheru->path);
|
|
|
newu->path = otheru->path;
|
|
|
}
|
|
|
+ refcount_inc(&otheru->addr->refcnt);
|
|
|
+ smp_store_release(&newu->addr, otheru->addr);
|
|
|
|
|
|
/* Set credentials */
|
|
|
copy_peercred(sk, other);
|
|
|
@@ -1451,7 +1465,7 @@ out:
|
|
|
static int unix_getname(struct socket *sock, struct sockaddr *uaddr, int peer)
|
|
|
{
|
|
|
struct sock *sk = sock->sk;
|
|
|
- struct unix_sock *u;
|
|
|
+ struct unix_address *addr;
|
|
|
DECLARE_SOCKADDR(struct sockaddr_un *, sunaddr, uaddr);
|
|
|
int err = 0;
|
|
|
|
|
|
@@ -1466,19 +1480,15 @@ static int unix_getname(struct socket *sock, struct sockaddr *uaddr, int peer)
|
|
|
sock_hold(sk);
|
|
|
}
|
|
|
|
|
|
- u = unix_sk(sk);
|
|
|
- unix_state_lock(sk);
|
|
|
- if (!u->addr) {
|
|
|
+ addr = smp_load_acquire(&unix_sk(sk)->addr);
|
|
|
+ if (!addr) {
|
|
|
sunaddr->sun_family = AF_UNIX;
|
|
|
sunaddr->sun_path[0] = 0;
|
|
|
err = sizeof(short);
|
|
|
} else {
|
|
|
- struct unix_address *addr = u->addr;
|
|
|
-
|
|
|
err = addr->len;
|
|
|
memcpy(sunaddr, addr->name, addr->len);
|
|
|
}
|
|
|
- unix_state_unlock(sk);
|
|
|
sock_put(sk);
|
|
|
out:
|
|
|
return err;
|
|
|
@@ -2071,11 +2081,11 @@ static int unix_seqpacket_recvmsg(struct socket *sock, struct msghdr *msg,
|
|
|
|
|
|
static void unix_copy_addr(struct msghdr *msg, struct sock *sk)
|
|
|
{
|
|
|
- struct unix_sock *u = unix_sk(sk);
|
|
|
+ struct unix_address *addr = smp_load_acquire(&unix_sk(sk)->addr);
|
|
|
|
|
|
- if (u->addr) {
|
|
|
- msg->msg_namelen = u->addr->len;
|
|
|
- memcpy(msg->msg_name, u->addr->name, u->addr->len);
|
|
|
+ if (addr) {
|
|
|
+ msg->msg_namelen = addr->len;
|
|
|
+ memcpy(msg->msg_name, addr->name, addr->len);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -2579,15 +2589,14 @@ static int unix_open_file(struct sock *sk)
|
|
|
if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
|
|
|
return -EPERM;
|
|
|
|
|
|
- unix_state_lock(sk);
|
|
|
+ if (!smp_load_acquire(&unix_sk(sk)->addr))
|
|
|
+ return -ENOENT;
|
|
|
+
|
|
|
path = unix_sk(sk)->path;
|
|
|
- if (!path.dentry) {
|
|
|
- unix_state_unlock(sk);
|
|
|
+ if (!path.dentry)
|
|
|
return -ENOENT;
|
|
|
- }
|
|
|
|
|
|
path_get(&path);
|
|
|
- unix_state_unlock(sk);
|
|
|
|
|
|
fd = get_unused_fd_flags(O_CLOEXEC);
|
|
|
if (fd < 0)
|
|
|
@@ -2828,7 +2837,7 @@ static int unix_seq_show(struct seq_file *seq, void *v)
|
|
|
(s->sk_state == TCP_ESTABLISHED ? SS_CONNECTING : SS_DISCONNECTING),
|
|
|
sock_i_ino(s));
|
|
|
|
|
|
- if (u->addr) {
|
|
|
+ if (u->addr) { // under unix_table_lock here
|
|
|
int i, len;
|
|
|
seq_putc(seq, ' ');
|
|
|
|