diff options
author | Willem de Bruijn | 2016-07-13 00:18:57 +0200 |
---|---|---|
committer | David S. Miller | 2016-07-13 20:53:41 +0200 |
commit | 4f0c40d94461cfd23893a17335b2ab78ecb333c8 (patch) | |
tree | bb43f8374b6e157c5a412b30d2e528a808939067 /include/net/sock.h | |
parent | rose: limit sk_filter trim to payload (diff) | |
download | kernel-qcow2-linux-4f0c40d94461cfd23893a17335b2ab78ecb333c8.tar.gz kernel-qcow2-linux-4f0c40d94461cfd23893a17335b2ab78ecb333c8.tar.xz kernel-qcow2-linux-4f0c40d94461cfd23893a17335b2ab78ecb333c8.zip |
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>
Diffstat (limited to 'include/net/sock.h')
-rw-r--r-- | include/net/sock.h | 8 |
1 files changed, 7 insertions, 1 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) */ void sock_gen_put(struct sock *sk); -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) { |