aboutsummaryrefslogtreecommitdiffstats
path: root/net/unix/af_unix.c
diff options
context:
space:
mode:
authorDavid Herrmann <dh.herrmann@gmail.com>2017-07-17 05:35:54 -0400
committerDavid S. Miller <davem@davemloft.net>2017-07-17 11:57:59 -0400
commit27eac47b00789522ba00501b0838026e1ecb6f05 (patch)
tree8346a2f39052b1b3d3d06179dfe091555ddffe61 /net/unix/af_unix.c
parent3ccc6c6faaa93da70989177b91c7c3ef0df10937 (diff)
net/unix: drop obsolete fd-recursion limits
All unix sockets now account inflight FDs to the respective sender. This was introduced in: commit 712f4aad406bb1ed67f3f98d04c044191f0ff593 Author: willy tarreau <w@1wt.eu> Date: Sun Jan 10 07:54:56 2016 +0100 unix: properly account for FDs passed over unix sockets and further refined in: commit 415e3d3e90ce9e18727e8843ae343eda5a58fad6 Author: Hannes Frederic Sowa <hannes@stressinduktion.org> Date: Wed Feb 3 02:11:03 2016 +0100 unix: correctly track in-flight fds in sending process user_struct Hence, regardless of the stacking depth of FDs, the total number of inflight FDs is limited, and accounted. There is no known way for a local user to exceed those limits or exploit the accounting. Furthermore, the GC logic is independent of the recursion/stacking depth as well. It solely depends on the total number of inflight FDs, regardless of their layout. Lastly, the current `recursion_level' suffers a TOCTOU race, since it checks and inherits depths only at queue time. If we consider `A<-B' to mean `queue-B-on-A', the following sequence circumvents the recursion level easily: A<-B B<-C C<-D ... Y<-Z resulting in: A<-B<-C<-...<-Z With all of this in mind, lets drop the recursion limit. It has no additional security value, anymore. On the contrary, it randomly confuses message brokers that try to forward file-descriptors, since any sendmsg(2) call can fail spuriously with ETOOMANYREFS if a client maliciously modifies the FD while inflight. Cc: Alban Crequy <alban.crequy@collabora.co.uk> Cc: Simon McVittie <simon.mcvittie@collabora.co.uk> Signed-off-by: David Herrmann <dh.herrmann@gmail.com> Reviewed-by: Tom Gundersen <teg@jklm.no> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/unix/af_unix.c')
-rw-r--r--net/unix/af_unix.c24
1 files changed, 1 insertions, 23 deletions
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 7b52a380d710..5c53f22d62e8 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1528,26 +1528,13 @@ static inline bool too_many_unix_fds(struct task_struct *p)
1528 return false; 1528 return false;
1529} 1529}
1530 1530
1531#define MAX_RECURSION_LEVEL 4
1532
1533static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) 1531static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb)
1534{ 1532{
1535 int i; 1533 int i;
1536 unsigned char max_level = 0;
1537 1534
1538 if (too_many_unix_fds(current)) 1535 if (too_many_unix_fds(current))
1539 return -ETOOMANYREFS; 1536 return -ETOOMANYREFS;
1540 1537
1541 for (i = scm->fp->count - 1; i >= 0; i--) {
1542 struct sock *sk = unix_get_socket(scm->fp->fp[i]);
1543
1544 if (sk)
1545 max_level = max(max_level,
1546 unix_sk(sk)->recursion_level);
1547 }
1548 if (unlikely(max_level > MAX_RECURSION_LEVEL))
1549 return -ETOOMANYREFS;
1550
1551 /* 1538 /*
1552 * Need to duplicate file references for the sake of garbage 1539 * Need to duplicate file references for the sake of garbage
1553 * collection. Otherwise a socket in the fps might become a 1540 * collection. Otherwise a socket in the fps might become a
@@ -1559,7 +1546,7 @@ static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb)
1559 1546
1560 for (i = scm->fp->count - 1; i >= 0; i--) 1547 for (i = scm->fp->count - 1; i >= 0; i--)
1561 unix_inflight(scm->fp->user, scm->fp->fp[i]); 1548 unix_inflight(scm->fp->user, scm->fp->fp[i]);
1562 return max_level; 1549 return 0;
1563} 1550}
1564 1551
1565static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool send_fds) 1552static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool send_fds)
@@ -1649,7 +1636,6 @@ static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg,
1649 struct sk_buff *skb; 1636 struct sk_buff *skb;
1650 long timeo; 1637 long timeo;
1651 struct scm_cookie scm; 1638 struct scm_cookie scm;
1652 int max_level;
1653 int data_len = 0; 1639 int data_len = 0;
1654 int sk_locked; 1640 int sk_locked;
1655 1641
@@ -1701,7 +1687,6 @@ static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg,
1701 err = unix_scm_to_skb(&scm, skb, true); 1687 err = unix_scm_to_skb(&scm, skb, true);
1702 if (err < 0) 1688 if (err < 0)
1703 goto out_free; 1689 goto out_free;
1704 max_level = err + 1;
1705 1690
1706 skb_put(skb, len - data_len); 1691 skb_put(skb, len - data_len);
1707 skb->data_len = data_len; 1692 skb->data_len = data_len;
@@ -1819,8 +1804,6 @@ restart_locked:
1819 __net_timestamp(skb); 1804 __net_timestamp(skb);
1820 maybe_add_creds(skb, sock, other); 1805 maybe_add_creds(skb, sock, other);
1821 skb_queue_tail(&other->sk_receive_queue, skb); 1806 skb_queue_tail(&other->sk_receive_queue, skb);
1822 if (max_level > unix_sk(other)->recursion_level)
1823 unix_sk(other)->recursion_level = max_level;
1824 unix_state_unlock(other); 1807 unix_state_unlock(other);
1825 other->sk_data_ready(other); 1808 other->sk_data_ready(other);
1826 sock_put(other); 1809 sock_put(other);
@@ -1855,7 +1838,6 @@ static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg,
1855 int sent = 0; 1838 int sent = 0;
1856 struct scm_cookie scm; 1839 struct scm_cookie scm;
1857 bool fds_sent = false; 1840 bool fds_sent = false;
1858 int max_level;
1859 int data_len; 1841 int data_len;
1860 1842
1861 wait_for_unix_gc(); 1843 wait_for_unix_gc();
@@ -1905,7 +1887,6 @@ static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg,
1905 kfree_skb(skb); 1887 kfree_skb(skb);
1906 goto out_err; 1888 goto out_err;
1907 } 1889 }
1908 max_level = err + 1;
1909 fds_sent = true; 1890 fds_sent = true;
1910 1891
1911 skb_put(skb, size - data_len); 1892 skb_put(skb, size - data_len);
@@ -1925,8 +1906,6 @@ static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg,
1925 1906
1926 maybe_add_creds(skb, sock, other); 1907 maybe_add_creds(skb, sock, other);
1927 skb_queue_tail(&other->sk_receive_queue, skb); 1908 skb_queue_tail(&other->sk_receive_queue, skb);
1928 if (max_level > unix_sk(other)->recursion_level)
1929 unix_sk(other)->recursion_level = max_level;
1930 unix_state_unlock(other); 1909 unix_state_unlock(other);
1931 other->sk_data_ready(other); 1910 other->sk_data_ready(other);
1932 sent += size; 1911 sent += size;
@@ -2324,7 +2303,6 @@ redo:
2324 last_len = last ? last->len : 0; 2303 last_len = last ? last->len : 0;
2325again: 2304again:
2326 if (skb == NULL) { 2305 if (skb == NULL) {
2327 unix_sk(sk)->recursion_level = 0;
2328 if (copied >= target) 2306 if (copied >= target)
2329 goto unlock; 2307 goto unlock;
2330 2308