* [PATCH net 1/2] rose: limit sk_filter trim to payload
2016-07-12 22:18 [PATCH net 0/2] limit sk_filter trim to payload Willem de Bruijn
@ 2016-07-12 22:18 ` Willem de Bruijn
2016-07-12 22:49 ` Daniel Borkmann
2016-07-12 22:18 ` [PATCH net 2/2] dccp: " Willem de Bruijn
2016-07-13 18:57 ` [PATCH net 0/2] " David Miller
2 siblings, 1 reply; 6+ messages in thread
From: Willem de Bruijn @ 2016-07-12 22:18 UTC (permalink / raw)
To: netdev
Cc: alexei.starovoitov, daniel, davem, hannes, eric.dumazet,
Willem de Bruijn
From: Willem de Bruijn <willemb@google.com>
Sockets can have a filter program attached that drops or trims
incoming packets based on the filter program return value.
Rose requires data packets to have at least ROSE_MIN_LEN bytes. It
verifies this on arrival in rose_route_frame and unconditionally pulls
the bytes in rose_recvmsg. The filter can trim packets to below this
value in-between, causing pull to fail, leaving the partial header at
the time of skb_copy_datagram_msg.
Place a lower bound on the size to which sk_filter may trim packets
by introducing sk_filter_trim_cap and call this for rose packets.
Signed-off-by: Willem de Bruijn <willemb@google.com>
---
No Fixes tag, because this codepath goes back to the start of the
git repo history.
---
include/linux/filter.h | 6 +++++-
net/core/filter.c | 10 +++++-----
net/rose/rose_in.c | 3 ++-
3 files changed, 12 insertions(+), 7 deletions(-)
diff --git a/include/linux/filter.h b/include/linux/filter.h
index 6fc31ef..8f74f3d 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -467,7 +467,11 @@ static inline void bpf_prog_unlock_ro(struct bpf_prog *fp)
}
#endif /* CONFIG_DEBUG_SET_MODULE_RONX */
-int sk_filter(struct sock *sk, struct sk_buff *skb);
+int sk_filter_trim_cap(struct sock *sk, struct sk_buff *skb, unsigned int cap);
+static inline int sk_filter(struct sock *sk, struct sk_buff *skb)
+{
+ return sk_filter_trim_cap(sk, skb, 1);
+}
struct bpf_prog *bpf_prog_select_runtime(struct bpf_prog *fp, int *err);
void bpf_prog_free(struct bpf_prog *fp);
diff --git a/net/core/filter.c b/net/core/filter.c
index c4b330c..e759d90 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -53,9 +53,10 @@
#include <net/sock_reuseport.h>
/**
- * sk_filter - run a packet through a socket filter
+ * sk_filter_trim_cap - run a packet through a socket filter
* @sk: sock associated with &sk_buff
* @skb: buffer to filter
+ * @cap: limit on how short the eBPF program may trim the packet
*
* Run the eBPF program and then cut skb->data to correct size returned by
* the program. If pkt_len is 0 we toss packet. If skb->len is smaller
@@ -64,7 +65,7 @@
* be accepted or -EPERM if the packet should be tossed.
*
*/
-int sk_filter(struct sock *sk, struct sk_buff *skb)
+int sk_filter_trim_cap(struct sock *sk, struct sk_buff *skb, unsigned int cap)
{
int err;
struct sk_filter *filter;
@@ -85,14 +86,13 @@ int sk_filter(struct sock *sk, struct sk_buff *skb)
filter = rcu_dereference(sk->sk_filter);
if (filter) {
unsigned int pkt_len = bpf_prog_run_save_cb(filter->prog, skb);
-
- err = pkt_len ? pskb_trim(skb, pkt_len) : -EPERM;
+ err = pkt_len ? pskb_trim(skb, max(cap, pkt_len)) : -EPERM;
}
rcu_read_unlock();
return err;
}
-EXPORT_SYMBOL(sk_filter);
+EXPORT_SYMBOL(sk_filter_trim_cap);
static u64 __skb_get_pay_offset(u64 ctx, u64 a, u64 x, u64 r4, u64 r5)
{
diff --git a/net/rose/rose_in.c b/net/rose/rose_in.c
index 79c4abc..0a63947 100644
--- a/net/rose/rose_in.c
+++ b/net/rose/rose_in.c
@@ -164,7 +164,8 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety
rose_frames_acked(sk, nr);
if (ns == rose->vr) {
rose_start_idletimer(sk);
- if (sock_queue_rcv_skb(sk, skb) == 0) {
+ if (sk_filter_trim_cap(sk, skb, ROSE_MIN_LEN) == 0 &&
+ __sock_queue_rcv_skb(sk, skb) == 0) {
rose->vr = (rose->vr + 1) % ROSE_MODULUS;
queued = 1;
} else {
--
2.8.0.rc3.226.g39d4020
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH net 1/2] rose: limit sk_filter trim to payload
2016-07-12 22:18 ` [PATCH net 1/2] rose: " Willem de Bruijn
@ 2016-07-12 22:49 ` Daniel Borkmann
0 siblings, 0 replies; 6+ messages in thread
From: Daniel Borkmann @ 2016-07-12 22:49 UTC (permalink / raw)
To: Willem de Bruijn, netdev
Cc: alexei.starovoitov, davem, hannes, eric.dumazet, Willem de Bruijn
On 07/13/2016 12:18 AM, Willem de Bruijn wrote:
> From: Willem de Bruijn <willemb@google.com>
>
> Sockets can have a filter program attached that drops or trims
> incoming packets based on the filter program return value.
>
> Rose requires data packets to have at least ROSE_MIN_LEN bytes. It
> verifies this on arrival in rose_route_frame and unconditionally pulls
> the bytes in rose_recvmsg. The filter can trim packets to below this
> value in-between, causing pull to fail, leaving the partial header at
> the time of skb_copy_datagram_msg.
>
> Place a lower bound on the size to which sk_filter may trim packets
> by introducing sk_filter_trim_cap and call this for rose packets.
>
> Signed-off-by: Willem de Bruijn <willemb@google.com>
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH net 2/2] dccp: limit sk_filter trim to payload
2016-07-12 22:18 [PATCH net 0/2] limit sk_filter trim to payload Willem de Bruijn
2016-07-12 22:18 ` [PATCH net 1/2] rose: " Willem de Bruijn
@ 2016-07-12 22:18 ` Willem de Bruijn
2016-07-12 22:53 ` Daniel Borkmann
2016-07-13 18:57 ` [PATCH net 0/2] " David Miller
2 siblings, 1 reply; 6+ messages in thread
From: Willem de Bruijn @ 2016-07-12 22:18 UTC (permalink / raw)
To: netdev
Cc: alexei.starovoitov, daniel, davem, hannes, eric.dumazet,
Willem de Bruijn
From: Willem de Bruijn <willemb@google.com>
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>
---
include/net/sock.h | 8 +++++++-
net/core/sock.c | 7 ++++---
net/dccp/ipv4.c | 2 +-
net/dccp/ipv6.c | 2 +-
4 files changed, 13 insertions(+), 6 deletions(-)
diff --git a/include/net/sock.h b/include/net/sock.h
index 649d2a8..ff5be7e 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)
{
diff --git a/net/core/sock.c b/net/core/sock.c
index b7f1263..25dab8b 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)
}
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;
@@ -492,7 +493,7 @@ discard_and_relse:
kfree_skb(skb);
goto out;
}
-EXPORT_SYMBOL(sk_receive_skb);
+EXPORT_SYMBOL(__sk_receive_skb);
struct dst_entry *__sk_dst_check(struct sock *sk, u32 cookie)
{
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index 25dd25b..345a3ae 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -868,7 +868,7 @@ lookup:
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))
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index d176f4e..3ff137d 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -732,7 +732,7 @@ lookup:
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))
--
2.8.0.rc3.226.g39d4020
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH net 2/2] dccp: limit sk_filter trim to payload
2016-07-12 22:18 ` [PATCH net 2/2] dccp: " Willem de Bruijn
@ 2016-07-12 22:53 ` Daniel Borkmann
0 siblings, 0 replies; 6+ messages in thread
From: Daniel Borkmann @ 2016-07-12 22:53 UTC (permalink / raw)
To: Willem de Bruijn, netdev
Cc: alexei.starovoitov, davem, hannes, eric.dumazet, Willem de Bruijn
On 07/13/2016 12:18 AM, Willem de Bruijn wrote:
> From: Willem de Bruijn <willemb@google.com>
>
> 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>
LGTM, thanks Willem!
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH net 0/2] limit sk_filter trim to payload
2016-07-12 22:18 [PATCH net 0/2] limit sk_filter trim to payload Willem de Bruijn
2016-07-12 22:18 ` [PATCH net 1/2] rose: " Willem de Bruijn
2016-07-12 22:18 ` [PATCH net 2/2] dccp: " Willem de Bruijn
@ 2016-07-13 18:57 ` David Miller
2 siblings, 0 replies; 6+ messages in thread
From: David Miller @ 2016-07-13 18:57 UTC (permalink / raw)
To: willemdebruijn.kernel
Cc: netdev, alexei.starovoitov, daniel, hannes, eric.dumazet, willemb
From: Willem de Bruijn <willemdebruijn.kernel@gmail.com>
Date: Tue, 12 Jul 2016 18:18:55 -0400
> From: Willem de Bruijn <willemb@google.com>
>
> Sockets can apply a filter to incoming packets to drop or trim them.
> Fix two codepaths that call skb_pull/__skb_pull after sk_filter
> without checking for packet length.
>
> Reading beyond skb->tail after trimming happens in more codepaths, but
> safety of reading in the linear segment is based on minimum allocation
> size (MAX_HEADER, GRO_MAX_HEAD, ..).
Series applied and queued up for -stable, thanks.
^ permalink raw reply [flat|nested] 6+ messages in thread