[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <lsq.1487198494.467866356@decadent.org.uk>
Date: Wed, 15 Feb 2017 22:41:34 +0000
From: Ben Hutchings <ben@...adent.org.uk>
To: linux-kernel@...r.kernel.org, stable@...r.kernel.org
CC: akpm@...ux-foundation.org,
"Daniel Borkmann" <daniel@...earbox.net>,
"Willem de Bruijn" <willemb@...gle.com>,
"David S. Miller" <davem@...emloft.net>
Subject: [PATCH 3.2 120/126] dccp: limit sk_filter trim to payload
3.2.85-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Willem de Bruijn <willemb@...gle.com>
commit 4f0c40d94461cfd23893a17335b2ab78ecb333c8 upstream.
Dccp verifies packet integrity, including length, at initial rcv in
dccp_invalid_packet, later pulls headers in dccp_enqueue_skb.
A call to sk_filter in-between can cause __skb_pull to wrap skb->len.
skb_copy_datagram_msg interprets this as a negative value, so
(correctly) fails with EFAULT. The negative length is reported in
ioctl SIOCINQ or possibly in a DCCP_WARN in dccp_close.
Introduce an sk_receive_skb variant that caps how small a filter
program can trim packets, and call this in dccp with the header
length. Excessively trimmed packets are now processed normally and
queued for reception as 0B payloads.
Fixes: 7c657876b63c ("[DCCP]: Initial implementation")
Signed-off-by: Willem de Bruijn <willemb@...gle.com>
Acked-by: Daniel Borkmann <daniel@...earbox.net>
Signed-off-by: David S. Miller <davem@...emloft.net>
[bwh: Backported to 3.2: adjust context]
Signed-off-by: Ben Hutchings <ben@...adent.org.uk>
---
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -1268,8 +1268,13 @@ static inline void sock_put(struct sock
sk_free(sk);
}
-extern int sk_receive_skb(struct sock *sk, struct sk_buff *skb,
- const int nested);
+int __sk_receive_skb(struct sock *sk, struct sk_buff *skb, const int nested,
+ unsigned int trim_cap);
+static inline int sk_receive_skb(struct sock *sk, struct sk_buff *skb,
+ const int nested)
+{
+ return __sk_receive_skb(sk, skb, nested, 1);
+}
static inline void sk_tx_queue_set(struct sock *sk, int tx_queue)
{
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -336,11 +336,12 @@ int sock_queue_rcv_skb(struct sock *sk,
}
EXPORT_SYMBOL(sock_queue_rcv_skb);
-int sk_receive_skb(struct sock *sk, struct sk_buff *skb, const int nested)
+int __sk_receive_skb(struct sock *sk, struct sk_buff *skb,
+ const int nested, unsigned int trim_cap)
{
int rc = NET_RX_SUCCESS;
- if (sk_filter(sk, skb))
+ if (sk_filter_trim_cap(sk, skb, trim_cap))
goto discard_and_relse;
skb->dev = NULL;
@@ -376,7 +377,7 @@ discard_and_relse:
kfree_skb(skb);
goto out;
}
-EXPORT_SYMBOL(sk_receive_skb);
+EXPORT_SYMBOL(__sk_receive_skb);
void sk_reset_txq(struct sock *sk)
{
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -877,7 +877,7 @@ static int dccp_v4_rcv(struct sk_buff *s
goto discard_and_relse;
nf_reset(skb);
- return sk_receive_skb(sk, skb, 1);
+ return __sk_receive_skb(sk, skb, 1, dh->dccph_doff * 4);
no_dccp_socket:
if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -817,7 +817,7 @@ static int dccp_v6_rcv(struct sk_buff *s
if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
goto discard_and_relse;
- return sk_receive_skb(sk, skb, 1) ? -1 : 0;
+ return __sk_receive_skb(sk, skb, 1, dh->dccph_doff * 4) ? -1 : 0;
no_dccp_socket:
if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
Powered by blists - more mailing lists