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.c37
1 files changed, 32 insertions, 5 deletions
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 7ff31c60186a..417d7a6c36cf 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1344,9 +1344,25 @@ static void unix_destruct_scm(struct sk_buff *skb)
1344 sock_wfree(skb); 1344 sock_wfree(skb);
1345} 1345}
1346 1346
1347#define MAX_RECURSION_LEVEL 4
1348
1347static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) 1349static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb)
1348{ 1350{
1349 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;
1350 1366
1351 /* 1367 /*
1352 * Need to duplicate file references for the sake of garbage 1368 * Need to duplicate file references for the sake of garbage
@@ -1357,9 +1373,11 @@ static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb)
1357 if (!UNIXCB(skb).fp) 1373 if (!UNIXCB(skb).fp)
1358 return -ENOMEM; 1374 return -ENOMEM;
1359 1375
1360 for (i = scm->fp->count-1; i >= 0; i--) 1376 if (unix_sock_count) {
1361 unix_inflight(scm->fp->fp[i]); 1377 for (i = scm->fp->count - 1; i >= 0; i--)
1362 return 0; 1378 unix_inflight(scm->fp->fp[i]);
1379 }
1380 return max_level;
1363} 1381}
1364 1382
1365static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool send_fds) 1383static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool send_fds)
@@ -1394,6 +1412,7 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock,
1394 struct sk_buff *skb; 1412 struct sk_buff *skb;
1395 long timeo; 1413 long timeo;
1396 struct scm_cookie tmp_scm; 1414 struct scm_cookie tmp_scm;
1415 int max_level;
1397 1416
1398 if (NULL == siocb->scm) 1417 if (NULL == siocb->scm)
1399 siocb->scm = &tmp_scm; 1418 siocb->scm = &tmp_scm;
@@ -1432,8 +1451,9 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock,
1432 goto out; 1451 goto out;
1433 1452
1434 err = unix_scm_to_skb(siocb->scm, skb, true); 1453 err = unix_scm_to_skb(siocb->scm, skb, true);
1435 if (err) 1454 if (err < 0)
1436 goto out_free; 1455 goto out_free;
1456 max_level = err + 1;
1437 unix_get_secdata(siocb->scm, skb); 1457 unix_get_secdata(siocb->scm, skb);
1438 1458
1439 skb_reset_transport_header(skb); 1459 skb_reset_transport_header(skb);
@@ -1515,6 +1535,8 @@ restart:
1515 if (sock_flag(other, SOCK_RCVTSTAMP)) 1535 if (sock_flag(other, SOCK_RCVTSTAMP))
1516 __net_timestamp(skb); 1536 __net_timestamp(skb);
1517 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;
1518 unix_state_unlock(other); 1540 unix_state_unlock(other);
1519 other->sk_data_ready(other, len); 1541 other->sk_data_ready(other, len);
1520 sock_put(other); 1542 sock_put(other);
@@ -1545,6 +1567,7 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
1545 int sent = 0; 1567 int sent = 0;
1546 struct scm_cookie tmp_scm; 1568 struct scm_cookie tmp_scm;
1547 bool fds_sent = false; 1569 bool fds_sent = false;
1570 int max_level;
1548 1571
1549 if (NULL == siocb->scm) 1572 if (NULL == siocb->scm)
1550 siocb->scm = &tmp_scm; 1573 siocb->scm = &tmp_scm;
@@ -1608,10 +1631,11 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
1608 1631
1609 /* Only send the fds in the first buffer */ 1632 /* Only send the fds in the first buffer */
1610 err = unix_scm_to_skb(siocb->scm, skb, !fds_sent); 1633 err = unix_scm_to_skb(siocb->scm, skb, !fds_sent);
1611 if (err) { 1634 if (err < 0) {
1612 kfree_skb(skb); 1635 kfree_skb(skb);
1613 goto out_err; 1636 goto out_err;
1614 } 1637 }
1638 max_level = err + 1;
1615 fds_sent = true; 1639 fds_sent = true;
1616 1640
1617 err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size); 1641 err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
@@ -1627,6 +1651,8 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
1627 goto pipe_err_free; 1651 goto pipe_err_free;
1628 1652
1629 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;
1630 unix_state_unlock(other); 1656 unix_state_unlock(other);
1631 other->sk_data_ready(other, size); 1657 other->sk_data_ready(other, size);
1632 sent += size; 1658 sent += size;
@@ -1847,6 +1873,7 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
1847 unix_state_lock(sk); 1873 unix_state_lock(sk);
1848 skb = skb_dequeue(&sk->sk_receive_queue); 1874 skb = skb_dequeue(&sk->sk_receive_queue);
1849 if (skb == NULL) { 1875 if (skb == NULL) {
1876 unix_sk(sk)->recursion_level = 0;
1850 if (copied >= target) 1877 if (copied >= target)
1851 goto unlock; 1878 goto unlock;
1852 1879