aboutsummaryrefslogtreecommitdiffstats
path: root/net/unix/af_unix.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/unix/af_unix.c')
-rw-r--r--net/unix/af_unix.c57
1 files changed, 33 insertions, 24 deletions
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 74d1eed7cbd4..a95d479caeea 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -890,7 +890,7 @@ retry:
890 addr->hash ^= sk->sk_type; 890 addr->hash ^= sk->sk_type;
891 891
892 __unix_remove_socket(sk); 892 __unix_remove_socket(sk);
893 u->addr = addr; 893 smp_store_release(&u->addr, addr);
894 __unix_insert_socket(&unix_socket_table[addr->hash], sk); 894 __unix_insert_socket(&unix_socket_table[addr->hash], sk);
895 spin_unlock(&unix_table_lock); 895 spin_unlock(&unix_table_lock);
896 err = 0; 896 err = 0;
@@ -1060,7 +1060,7 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
1060 1060
1061 err = 0; 1061 err = 0;
1062 __unix_remove_socket(sk); 1062 __unix_remove_socket(sk);
1063 u->addr = addr; 1063 smp_store_release(&u->addr, addr);
1064 __unix_insert_socket(list, sk); 1064 __unix_insert_socket(list, sk);
1065 1065
1066out_unlock: 1066out_unlock:
@@ -1331,15 +1331,29 @@ restart:
1331 RCU_INIT_POINTER(newsk->sk_wq, &newu->peer_wq); 1331 RCU_INIT_POINTER(newsk->sk_wq, &newu->peer_wq);
1332 otheru = unix_sk(other); 1332 otheru = unix_sk(other);
1333 1333
1334 /* copy address information from listening to new sock*/ 1334 /* copy address information from listening to new sock
1335 if (otheru->addr) { 1335 *
1336 refcount_inc(&otheru->addr->refcnt); 1336 * The contents of *(otheru->addr) and otheru->path
1337 newu->addr = otheru->addr; 1337 * are seen fully set up here, since we have found
1338 } 1338 * otheru in hash under unix_table_lock. Insertion
1339 * into the hash chain we'd found it in had been done
1340 * in an earlier critical area protected by unix_table_lock,
1341 * the same one where we'd set *(otheru->addr) contents,
1342 * as well as otheru->path and otheru->addr itself.
1343 *
1344 * Using smp_store_release() here to set newu->addr
1345 * is enough to make those stores, as well as stores
1346 * to newu->path visible to anyone who gets newu->addr
1347 * by smp_load_acquire(). IOW, the same warranties
1348 * as for unix_sock instances bound in unix_bind() or
1349 * in unix_autobind().
1350 */
1339 if (otheru->path.dentry) { 1351 if (otheru->path.dentry) {
1340 path_get(&otheru->path); 1352 path_get(&otheru->path);
1341 newu->path = otheru->path; 1353 newu->path = otheru->path;
1342 } 1354 }
1355 refcount_inc(&otheru->addr->refcnt);
1356 smp_store_release(&newu->addr, otheru->addr);
1343 1357
1344 /* Set credentials */ 1358 /* Set credentials */
1345 copy_peercred(sk, other); 1359 copy_peercred(sk, other);
@@ -1453,7 +1467,7 @@ out:
1453static int unix_getname(struct socket *sock, struct sockaddr *uaddr, int peer) 1467static int unix_getname(struct socket *sock, struct sockaddr *uaddr, int peer)
1454{ 1468{
1455 struct sock *sk = sock->sk; 1469 struct sock *sk = sock->sk;
1456 struct unix_sock *u; 1470 struct unix_address *addr;
1457 DECLARE_SOCKADDR(struct sockaddr_un *, sunaddr, uaddr); 1471 DECLARE_SOCKADDR(struct sockaddr_un *, sunaddr, uaddr);
1458 int err = 0; 1472 int err = 0;
1459 1473
@@ -1468,19 +1482,15 @@ static int unix_getname(struct socket *sock, struct sockaddr *uaddr, int peer)
1468 sock_hold(sk); 1482 sock_hold(sk);
1469 } 1483 }
1470 1484
1471 u = unix_sk(sk); 1485 addr = smp_load_acquire(&unix_sk(sk)->addr);
1472 unix_state_lock(sk); 1486 if (!addr) {
1473 if (!u->addr) {
1474 sunaddr->sun_family = AF_UNIX; 1487 sunaddr->sun_family = AF_UNIX;
1475 sunaddr->sun_path[0] = 0; 1488 sunaddr->sun_path[0] = 0;
1476 err = sizeof(short); 1489 err = sizeof(short);
1477 } else { 1490 } else {
1478 struct unix_address *addr = u->addr;
1479
1480 err = addr->len; 1491 err = addr->len;
1481 memcpy(sunaddr, addr->name, addr->len); 1492 memcpy(sunaddr, addr->name, addr->len);
1482 } 1493 }
1483 unix_state_unlock(sk);
1484 sock_put(sk); 1494 sock_put(sk);
1485out: 1495out:
1486 return err; 1496 return err;
@@ -2073,11 +2083,11 @@ static int unix_seqpacket_recvmsg(struct socket *sock, struct msghdr *msg,
2073 2083
2074static void unix_copy_addr(struct msghdr *msg, struct sock *sk) 2084static void unix_copy_addr(struct msghdr *msg, struct sock *sk)
2075{ 2085{
2076 struct unix_sock *u = unix_sk(sk); 2086 struct unix_address *addr = smp_load_acquire(&unix_sk(sk)->addr);
2077 2087
2078 if (u->addr) { 2088 if (addr) {
2079 msg->msg_namelen = u->addr->len; 2089 msg->msg_namelen = addr->len;
2080 memcpy(msg->msg_name, u->addr->name, u->addr->len); 2090 memcpy(msg->msg_name, addr->name, addr->len);
2081 } 2091 }
2082} 2092}
2083 2093
@@ -2581,15 +2591,14 @@ static int unix_open_file(struct sock *sk)
2581 if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) 2591 if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
2582 return -EPERM; 2592 return -EPERM;
2583 2593
2584 unix_state_lock(sk); 2594 if (!smp_load_acquire(&unix_sk(sk)->addr))
2595 return -ENOENT;
2596
2585 path = unix_sk(sk)->path; 2597 path = unix_sk(sk)->path;
2586 if (!path.dentry) { 2598 if (!path.dentry)
2587 unix_state_unlock(sk);
2588 return -ENOENT; 2599 return -ENOENT;
2589 }
2590 2600
2591 path_get(&path); 2601 path_get(&path);
2592 unix_state_unlock(sk);
2593 2602
2594 fd = get_unused_fd_flags(O_CLOEXEC); 2603 fd = get_unused_fd_flags(O_CLOEXEC);
2595 if (fd < 0) 2604 if (fd < 0)
@@ -2830,7 +2839,7 @@ static int unix_seq_show(struct seq_file *seq, void *v)
2830 (s->sk_state == TCP_ESTABLISHED ? SS_CONNECTING : SS_DISCONNECTING), 2839 (s->sk_state == TCP_ESTABLISHED ? SS_CONNECTING : SS_DISCONNECTING),
2831 sock_i_ino(s)); 2840 sock_i_ino(s));
2832 2841
2833 if (u->addr) { 2842 if (u->addr) { // under unix_table_lock here
2834 int i, len; 2843 int i, len;
2835 seq_putc(seq, ' '); 2844 seq_putc(seq, ' ');
2836 2845