aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWillem de Bruijn <willemb@google.com>2016-07-12 18:18:57 -0400
committerDavid S. Miller <davem@davemloft.net>2016-07-13 14:53:41 -0400
commit4f0c40d94461cfd23893a17335b2ab78ecb333c8 (patch)
treebb43f8374b6e157c5a412b30d2e528a808939067
parentf4979fcea7fd36d8e2f556abef86f80e0d5af1ba (diff)
dccp: limit sk_filter trim to payload
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@google.com> Acked-by: Daniel Borkmann <daniel@iogearbox.net> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/sock.h8
-rw-r--r--net/core/sock.c7
-rw-r--r--net/dccp/ipv4.c2
-rw-r--r--net/dccp/ipv6.c2
4 files changed, 13 insertions, 6 deletions
diff --git a/include/net/sock.h b/include/net/sock.h
index 649d2a8c17fc..ff5be7e8ddea 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -1576,7 +1576,13 @@ static inline void sock_put(struct sock *sk)
1576 */ 1576 */
1577void sock_gen_put(struct sock *sk); 1577void sock_gen_put(struct sock *sk);
1578 1578
1579int sk_receive_skb(struct sock *sk, struct sk_buff *skb, const int nested); 1579int __sk_receive_skb(struct sock *sk, struct sk_buff *skb, const int nested,
1580 unsigned int trim_cap);
1581static inline int sk_receive_skb(struct sock *sk, struct sk_buff *skb,
1582 const int nested)
1583{
1584 return __sk_receive_skb(sk, skb, nested, 1);
1585}
1580 1586
1581static inline void sk_tx_queue_set(struct sock *sk, int tx_queue) 1587static inline void sk_tx_queue_set(struct sock *sk, int tx_queue)
1582{ 1588{
diff --git a/net/core/sock.c b/net/core/sock.c
index b7f12639c26a..25dab8b60223 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -452,11 +452,12 @@ int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
452} 452}
453EXPORT_SYMBOL(sock_queue_rcv_skb); 453EXPORT_SYMBOL(sock_queue_rcv_skb);
454 454
455int sk_receive_skb(struct sock *sk, struct sk_buff *skb, const int nested) 455int __sk_receive_skb(struct sock *sk, struct sk_buff *skb,
456 const int nested, unsigned int trim_cap)
456{ 457{
457 int rc = NET_RX_SUCCESS; 458 int rc = NET_RX_SUCCESS;
458 459
459 if (sk_filter(sk, skb)) 460 if (sk_filter_trim_cap(sk, skb, trim_cap))
460 goto discard_and_relse; 461 goto discard_and_relse;
461 462
462 skb->dev = NULL; 463 skb->dev = NULL;
@@ -492,7 +493,7 @@ discard_and_relse:
492 kfree_skb(skb); 493 kfree_skb(skb);
493 goto out; 494 goto out;
494} 495}
495EXPORT_SYMBOL(sk_receive_skb); 496EXPORT_SYMBOL(__sk_receive_skb);
496 497
497struct dst_entry *__sk_dst_check(struct sock *sk, u32 cookie) 498struct dst_entry *__sk_dst_check(struct sock *sk, u32 cookie)
498{ 499{
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index 25dd25b47d41..345a3aeb8c7e 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -868,7 +868,7 @@ lookup:
868 goto discard_and_relse; 868 goto discard_and_relse;
869 nf_reset(skb); 869 nf_reset(skb);
870 870
871 return sk_receive_skb(sk, skb, 1); 871 return __sk_receive_skb(sk, skb, 1, dh->dccph_doff * 4);
872 872
873no_dccp_socket: 873no_dccp_socket:
874 if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) 874 if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index d176f4e66369..3ff137d9471d 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -732,7 +732,7 @@ lookup:
732 if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) 732 if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
733 goto discard_and_relse; 733 goto discard_and_relse;
734 734
735 return sk_receive_skb(sk, skb, 1) ? -1 : 0; 735 return __sk_receive_skb(sk, skb, 1, dh->dccph_doff * 4) ? -1 : 0;
736 736
737no_dccp_socket: 737no_dccp_socket:
738 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) 738 if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))