diff options
Diffstat (limited to 'net/unix/af_unix.c')
-rw-r--r-- | net/unix/af_unix.c | 73 |
1 files changed, 50 insertions, 23 deletions
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 3c95304a0817..dd419d286204 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c | |||
@@ -316,7 +316,8 @@ static void unix_write_space(struct sock *sk) | |||
316 | if (unix_writable(sk)) { | 316 | if (unix_writable(sk)) { |
317 | wq = rcu_dereference(sk->sk_wq); | 317 | wq = rcu_dereference(sk->sk_wq); |
318 | if (wq_has_sleeper(wq)) | 318 | if (wq_has_sleeper(wq)) |
319 | wake_up_interruptible_sync(&wq->wait); | 319 | wake_up_interruptible_sync_poll(&wq->wait, |
320 | POLLOUT | POLLWRNORM | POLLWRBAND); | ||
320 | sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT); | 321 | sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT); |
321 | } | 322 | } |
322 | rcu_read_unlock(); | 323 | rcu_read_unlock(); |
@@ -1156,7 +1157,7 @@ restart: | |||
1156 | goto restart; | 1157 | goto restart; |
1157 | } | 1158 | } |
1158 | 1159 | ||
1159 | err = security_unix_stream_connect(sock, other->sk_socket, newsk); | 1160 | err = security_unix_stream_connect(sk, other, newsk); |
1160 | if (err) { | 1161 | if (err) { |
1161 | unix_state_unlock(sk); | 1162 | unix_state_unlock(sk); |
1162 | goto out_unlock; | 1163 | goto out_unlock; |
@@ -1343,9 +1344,25 @@ static void unix_destruct_scm(struct sk_buff *skb) | |||
1343 | sock_wfree(skb); | 1344 | sock_wfree(skb); |
1344 | } | 1345 | } |
1345 | 1346 | ||
1347 | #define MAX_RECURSION_LEVEL 4 | ||
1348 | |||
1346 | static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) | 1349 | static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) |
1347 | { | 1350 | { |
1348 | int i; | 1351 | int i; |
1352 | unsigned char max_level = 0; | ||
1353 | int unix_sock_count = 0; | ||
1354 | |||
1355 | for (i = scm->fp->count - 1; i >= 0; i--) { | ||
1356 | struct sock *sk = unix_get_socket(scm->fp->fp[i]); | ||
1357 | |||
1358 | if (sk) { | ||
1359 | unix_sock_count++; | ||
1360 | max_level = max(max_level, | ||
1361 | unix_sk(sk)->recursion_level); | ||
1362 | } | ||
1363 | } | ||
1364 | if (unlikely(max_level > MAX_RECURSION_LEVEL)) | ||
1365 | return -ETOOMANYREFS; | ||
1349 | 1366 | ||
1350 | /* | 1367 | /* |
1351 | * Need to duplicate file references for the sake of garbage | 1368 | * Need to duplicate file references for the sake of garbage |
@@ -1356,9 +1373,11 @@ static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) | |||
1356 | if (!UNIXCB(skb).fp) | 1373 | if (!UNIXCB(skb).fp) |
1357 | return -ENOMEM; | 1374 | return -ENOMEM; |
1358 | 1375 | ||
1359 | for (i = scm->fp->count-1; i >= 0; i--) | 1376 | if (unix_sock_count) { |
1360 | unix_inflight(scm->fp->fp[i]); | 1377 | for (i = scm->fp->count - 1; i >= 0; i--) |
1361 | return 0; | 1378 | unix_inflight(scm->fp->fp[i]); |
1379 | } | ||
1380 | return max_level; | ||
1362 | } | 1381 | } |
1363 | 1382 | ||
1364 | static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool send_fds) | 1383 | static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool send_fds) |
@@ -1393,6 +1412,7 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
1393 | struct sk_buff *skb; | 1412 | struct sk_buff *skb; |
1394 | long timeo; | 1413 | long timeo; |
1395 | struct scm_cookie tmp_scm; | 1414 | struct scm_cookie tmp_scm; |
1415 | int max_level; | ||
1396 | 1416 | ||
1397 | if (NULL == siocb->scm) | 1417 | if (NULL == siocb->scm) |
1398 | siocb->scm = &tmp_scm; | 1418 | siocb->scm = &tmp_scm; |
@@ -1431,8 +1451,9 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
1431 | goto out; | 1451 | goto out; |
1432 | 1452 | ||
1433 | err = unix_scm_to_skb(siocb->scm, skb, true); | 1453 | err = unix_scm_to_skb(siocb->scm, skb, true); |
1434 | if (err) | 1454 | if (err < 0) |
1435 | goto out_free; | 1455 | goto out_free; |
1456 | max_level = err + 1; | ||
1436 | unix_get_secdata(siocb->scm, skb); | 1457 | unix_get_secdata(siocb->scm, skb); |
1437 | 1458 | ||
1438 | skb_reset_transport_header(skb); | 1459 | skb_reset_transport_header(skb); |
@@ -1514,6 +1535,8 @@ restart: | |||
1514 | if (sock_flag(other, SOCK_RCVTSTAMP)) | 1535 | if (sock_flag(other, SOCK_RCVTSTAMP)) |
1515 | __net_timestamp(skb); | 1536 | __net_timestamp(skb); |
1516 | skb_queue_tail(&other->sk_receive_queue, skb); | 1537 | skb_queue_tail(&other->sk_receive_queue, skb); |
1538 | if (max_level > unix_sk(other)->recursion_level) | ||
1539 | unix_sk(other)->recursion_level = max_level; | ||
1517 | unix_state_unlock(other); | 1540 | unix_state_unlock(other); |
1518 | other->sk_data_ready(other, len); | 1541 | other->sk_data_ready(other, len); |
1519 | sock_put(other); | 1542 | sock_put(other); |
@@ -1544,6 +1567,7 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
1544 | int sent = 0; | 1567 | int sent = 0; |
1545 | struct scm_cookie tmp_scm; | 1568 | struct scm_cookie tmp_scm; |
1546 | bool fds_sent = false; | 1569 | bool fds_sent = false; |
1570 | int max_level; | ||
1547 | 1571 | ||
1548 | if (NULL == siocb->scm) | 1572 | if (NULL == siocb->scm) |
1549 | siocb->scm = &tmp_scm; | 1573 | siocb->scm = &tmp_scm; |
@@ -1607,10 +1631,11 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
1607 | 1631 | ||
1608 | /* Only send the fds in the first buffer */ | 1632 | /* Only send the fds in the first buffer */ |
1609 | err = unix_scm_to_skb(siocb->scm, skb, !fds_sent); | 1633 | err = unix_scm_to_skb(siocb->scm, skb, !fds_sent); |
1610 | if (err) { | 1634 | if (err < 0) { |
1611 | kfree_skb(skb); | 1635 | kfree_skb(skb); |
1612 | goto out_err; | 1636 | goto out_err; |
1613 | } | 1637 | } |
1638 | max_level = err + 1; | ||
1614 | fds_sent = true; | 1639 | fds_sent = true; |
1615 | 1640 | ||
1616 | err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size); | 1641 | err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size); |
@@ -1626,6 +1651,8 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
1626 | goto pipe_err_free; | 1651 | goto pipe_err_free; |
1627 | 1652 | ||
1628 | skb_queue_tail(&other->sk_receive_queue, skb); | 1653 | skb_queue_tail(&other->sk_receive_queue, skb); |
1654 | if (max_level > unix_sk(other)->recursion_level) | ||
1655 | unix_sk(other)->recursion_level = max_level; | ||
1629 | unix_state_unlock(other); | 1656 | unix_state_unlock(other); |
1630 | other->sk_data_ready(other, size); | 1657 | other->sk_data_ready(other, size); |
1631 | sent += size; | 1658 | sent += size; |
@@ -1710,7 +1737,8 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
1710 | goto out_unlock; | 1737 | goto out_unlock; |
1711 | } | 1738 | } |
1712 | 1739 | ||
1713 | wake_up_interruptible_sync(&u->peer_wait); | 1740 | wake_up_interruptible_sync_poll(&u->peer_wait, |
1741 | POLLOUT | POLLWRNORM | POLLWRBAND); | ||
1714 | 1742 | ||
1715 | if (msg->msg_name) | 1743 | if (msg->msg_name) |
1716 | unix_copy_addr(msg, skb->sk); | 1744 | unix_copy_addr(msg, skb->sk); |
@@ -1845,6 +1873,7 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
1845 | unix_state_lock(sk); | 1873 | unix_state_lock(sk); |
1846 | skb = skb_dequeue(&sk->sk_receive_queue); | 1874 | skb = skb_dequeue(&sk->sk_receive_queue); |
1847 | if (skb == NULL) { | 1875 | if (skb == NULL) { |
1876 | unix_sk(sk)->recursion_level = 0; | ||
1848 | if (copied >= target) | 1877 | if (copied >= target) |
1849 | goto unlock; | 1878 | goto unlock; |
1850 | 1879 | ||
@@ -2072,13 +2101,12 @@ static unsigned int unix_dgram_poll(struct file *file, struct socket *sock, | |||
2072 | if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue)) | 2101 | if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue)) |
2073 | mask |= POLLERR; | 2102 | mask |= POLLERR; |
2074 | if (sk->sk_shutdown & RCV_SHUTDOWN) | 2103 | if (sk->sk_shutdown & RCV_SHUTDOWN) |
2075 | mask |= POLLRDHUP; | 2104 | mask |= POLLRDHUP | POLLIN | POLLRDNORM; |
2076 | if (sk->sk_shutdown == SHUTDOWN_MASK) | 2105 | if (sk->sk_shutdown == SHUTDOWN_MASK) |
2077 | mask |= POLLHUP; | 2106 | mask |= POLLHUP; |
2078 | 2107 | ||
2079 | /* readable? */ | 2108 | /* readable? */ |
2080 | if (!skb_queue_empty(&sk->sk_receive_queue) || | 2109 | if (!skb_queue_empty(&sk->sk_receive_queue)) |
2081 | (sk->sk_shutdown & RCV_SHUTDOWN)) | ||
2082 | mask |= POLLIN | POLLRDNORM; | 2110 | mask |= POLLIN | POLLRDNORM; |
2083 | 2111 | ||
2084 | /* Connection-based need to check for termination and startup */ | 2112 | /* Connection-based need to check for termination and startup */ |
@@ -2090,20 +2118,19 @@ static unsigned int unix_dgram_poll(struct file *file, struct socket *sock, | |||
2090 | return mask; | 2118 | return mask; |
2091 | } | 2119 | } |
2092 | 2120 | ||
2093 | /* writable? */ | 2121 | /* No write status requested, avoid expensive OUT tests. */ |
2094 | writable = unix_writable(sk); | 2122 | if (wait && !(wait->key & (POLLWRBAND | POLLWRNORM | POLLOUT))) |
2095 | if (writable) { | 2123 | return mask; |
2096 | other = unix_peer_get(sk); | ||
2097 | if (other) { | ||
2098 | if (unix_peer(other) != sk) { | ||
2099 | sock_poll_wait(file, &unix_sk(other)->peer_wait, | ||
2100 | wait); | ||
2101 | if (unix_recvq_full(other)) | ||
2102 | writable = 0; | ||
2103 | } | ||
2104 | 2124 | ||
2105 | sock_put(other); | 2125 | writable = unix_writable(sk); |
2126 | other = unix_peer_get(sk); | ||
2127 | if (other) { | ||
2128 | if (unix_peer(other) != sk) { | ||
2129 | sock_poll_wait(file, &unix_sk(other)->peer_wait, wait); | ||
2130 | if (unix_recvq_full(other)) | ||
2131 | writable = 0; | ||
2106 | } | 2132 | } |
2133 | sock_put(other); | ||
2107 | } | 2134 | } |
2108 | 2135 | ||
2109 | if (writable) | 2136 | if (writable) |