Re: [PATCH bpf] bpf: fix bpf_skb_adjust_net/bpf_skb_proto_xlat to deal with gso sctp skbs

2018-03-03 Thread Alexei Starovoitov
On Sat, Mar 03, 2018 at 09:57:15PM +0100, Daniel Borkmann wrote:
> On 03/03/2018 05:02 PM, Daniel Axtens wrote:
> >> From: Daniel Axtens 
> >>
> >> SCTP GSO skbs have a gso_size of GSO_BY_FRAGS, so any sort of
> >> unconditionally mangling of that will result in nonsense value
> >> and would corrupt the skb later on.
> >>
> >> Therefore, i) add two helpers skb_increase_gso_size() and
> >> skb_decrease_gso_size() that would throw a one time warning and
> >> bail out for such skbs and ii) refuse and return early with an
> >> error in those BPF helpers that are affected. We do need to bail
> >> out as early as possible from there before any changes on the
> >> skb have been performed.
> >>
> >> Fixes: 6578171a7ff0 ("bpf: add bpf_skb_change_proto helper")
> >> Co-authored-by: Daniel Borkmann 
> >> Signed-off-by: Daniel Axtens 
> >> Cc: Marcelo Ricardo Leitner 
> >> Acked-by: Alexei Starovoitov 
> > 
> > I've looked over your changes and they all look good to me.
> > 
> >> +/* Note: Should be called only if skb_is_gso(skb) is true */
> >> +static inline bool skb_is_gso_sctp(const struct sk_buff *skb)
> >> +{
> >> +  return skb_shinfo(skb)->gso_type & SKB_GSO_SCTP;
> >> +}
> >> +
> > 
> > This helper is a fantastic idea and I will send a docs update to
> > highlight it.
> 
> Sounds good. There are infact several places in the code that
> could make use of this right away. If you have a chance, this
> could be done in net-next along with the doc update or so.

Applied to bpf tree, Thanks everyone.



Re: [PATCH bpf] bpf: fix bpf_skb_adjust_net/bpf_skb_proto_xlat to deal with gso sctp skbs

2018-03-03 Thread Daniel Borkmann
On 03/03/2018 05:02 PM, Daniel Axtens wrote:
>> From: Daniel Axtens 
>>
>> SCTP GSO skbs have a gso_size of GSO_BY_FRAGS, so any sort of
>> unconditionally mangling of that will result in nonsense value
>> and would corrupt the skb later on.
>>
>> Therefore, i) add two helpers skb_increase_gso_size() and
>> skb_decrease_gso_size() that would throw a one time warning and
>> bail out for such skbs and ii) refuse and return early with an
>> error in those BPF helpers that are affected. We do need to bail
>> out as early as possible from there before any changes on the
>> skb have been performed.
>>
>> Fixes: 6578171a7ff0 ("bpf: add bpf_skb_change_proto helper")
>> Co-authored-by: Daniel Borkmann 
>> Signed-off-by: Daniel Axtens 
>> Cc: Marcelo Ricardo Leitner 
>> Acked-by: Alexei Starovoitov 
> 
> I've looked over your changes and they all look good to me.
> 
>> +/* Note: Should be called only if skb_is_gso(skb) is true */
>> +static inline bool skb_is_gso_sctp(const struct sk_buff *skb)
>> +{
>> +return skb_shinfo(skb)->gso_type & SKB_GSO_SCTP;
>> +}
>> +
> 
> This helper is a fantastic idea and I will send a docs update to
> highlight it.

Sounds good. There are infact several places in the code that
could make use of this right away. If you have a chance, this
could be done in net-next along with the doc update or so.

Thanks,
Daniel


Re: [PATCH bpf] bpf: fix bpf_skb_adjust_net/bpf_skb_proto_xlat to deal with gso sctp skbs

2018-03-03 Thread Daniel Axtens
Hi Daniel,

> From: Daniel Axtens 
>
> SCTP GSO skbs have a gso_size of GSO_BY_FRAGS, so any sort of
> unconditionally mangling of that will result in nonsense value
> and would corrupt the skb later on.
>
> Therefore, i) add two helpers skb_increase_gso_size() and
> skb_decrease_gso_size() that would throw a one time warning and
> bail out for such skbs and ii) refuse and return early with an
> error in those BPF helpers that are affected. We do need to bail
> out as early as possible from there before any changes on the
> skb have been performed.
>
> Fixes: 6578171a7ff0 ("bpf: add bpf_skb_change_proto helper")
> Co-authored-by: Daniel Borkmann 
> Signed-off-by: Daniel Axtens 
> Cc: Marcelo Ricardo Leitner 
> Acked-by: Alexei Starovoitov 

I've looked over your changes and they all look good to me.

> +/* Note: Should be called only if skb_is_gso(skb) is true */
> +static inline bool skb_is_gso_sctp(const struct sk_buff *skb)
> +{
> + return skb_shinfo(skb)->gso_type & SKB_GSO_SCTP;
> +}
> +

This helper is a fantastic idea and I will send a docs update to
highlight it.

Regards,
Daniel


[PATCH bpf] bpf: fix bpf_skb_adjust_net/bpf_skb_proto_xlat to deal with gso sctp skbs

2018-03-02 Thread Daniel Borkmann
From: Daniel Axtens 

SCTP GSO skbs have a gso_size of GSO_BY_FRAGS, so any sort of
unconditionally mangling of that will result in nonsense value
and would corrupt the skb later on.

Therefore, i) add two helpers skb_increase_gso_size() and
skb_decrease_gso_size() that would throw a one time warning and
bail out for such skbs and ii) refuse and return early with an
error in those BPF helpers that are affected. We do need to bail
out as early as possible from there before any changes on the
skb have been performed.

Fixes: 6578171a7ff0 ("bpf: add bpf_skb_change_proto helper")
Co-authored-by: Daniel Borkmann 
Signed-off-by: Daniel Axtens 
Cc: Marcelo Ricardo Leitner 
Acked-by: Alexei Starovoitov 
---
 [ Also squashed the two into one, so that this is better for
   backporting and has no other dependency. ]

 Documentation/networking/segmentation-offloads.txt | 11 +++-
 include/linux/skbuff.h | 22 
 net/core/filter.c  | 60 +++---
 3 files changed, 73 insertions(+), 20 deletions(-)

diff --git a/Documentation/networking/segmentation-offloads.txt 
b/Documentation/networking/segmentation-offloads.txt
index d47480b..23a8dd9 100644
--- a/Documentation/networking/segmentation-offloads.txt
+++ b/Documentation/networking/segmentation-offloads.txt
@@ -153,8 +153,15 @@ To signal this, gso_size is set to the special value 
GSO_BY_FRAGS.
 
 Therefore, any code in the core networking stack must be aware of the
 possibility that gso_size will be GSO_BY_FRAGS and handle that case
-appropriately. (For size checks, the skb_gso_validate_*_len family of
-helpers do this automatically.)
+appropriately.
+
+There are a couple of helpers to make this easier:
+
+ - For size checks, the skb_gso_validate_*_len family of helpers correctly
+   considers GSO_BY_FRAGS.
+
+ - For manipulating packets, skb_increase_gso_size and skb_decrease_gso_size
+   will check for GSO_BY_FRAGS and WARN if asked to manipulate these skbs.
 
 This also affects drivers with the NETIF_F_FRAGLIST & NETIF_F_GSO_SCTP bits
 set. Note also that NETIF_F_GSO_SCTP is included in NETIF_F_GSO_SOFTWARE.
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index c1e66bd..8c67c33 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -4038,6 +4038,12 @@ static inline bool skb_is_gso_v6(const struct sk_buff 
*skb)
return skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6;
 }
 
+/* Note: Should be called only if skb_is_gso(skb) is true */
+static inline bool skb_is_gso_sctp(const struct sk_buff *skb)
+{
+   return skb_shinfo(skb)->gso_type & SKB_GSO_SCTP;
+}
+
 static inline void skb_gso_reset(struct sk_buff *skb)
 {
skb_shinfo(skb)->gso_size = 0;
@@ -4045,6 +4051,22 @@ static inline void skb_gso_reset(struct sk_buff *skb)
skb_shinfo(skb)->gso_type = 0;
 }
 
+static inline void skb_increase_gso_size(struct skb_shared_info *shinfo,
+u16 increment)
+{
+   if (WARN_ON_ONCE(shinfo->gso_size == GSO_BY_FRAGS))
+   return;
+   shinfo->gso_size += increment;
+}
+
+static inline void skb_decrease_gso_size(struct skb_shared_info *shinfo,
+u16 decrement)
+{
+   if (WARN_ON_ONCE(shinfo->gso_size == GSO_BY_FRAGS))
+   return;
+   shinfo->gso_size -= decrement;
+}
+
 void __skb_warn_lro_forwarding(const struct sk_buff *skb);
 
 static inline bool skb_warn_if_lro(const struct sk_buff *skb)
diff --git a/net/core/filter.c b/net/core/filter.c
index 0c121ad..48aa7c7 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -2087,6 +2087,10 @@ static int bpf_skb_proto_4_to_6(struct sk_buff *skb)
u32 off = skb_mac_header_len(skb);
int ret;
 
+   /* SCTP uses GSO_BY_FRAGS, thus cannot adjust it. */
+   if (skb_is_gso(skb) && unlikely(skb_is_gso_sctp(skb)))
+   return -ENOTSUPP;
+
ret = skb_cow(skb, len_diff);
if (unlikely(ret < 0))
return ret;
@@ -2096,19 +2100,21 @@ static int bpf_skb_proto_4_to_6(struct sk_buff *skb)
return ret;
 
if (skb_is_gso(skb)) {
+   struct skb_shared_info *shinfo = skb_shinfo(skb);
+
/* SKB_GSO_TCPV4 needs to be changed into
 * SKB_GSO_TCPV6.
 */
-   if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4) {
-   skb_shinfo(skb)->gso_type &= ~SKB_GSO_TCPV4;
-   skb_shinfo(skb)->gso_type |=  SKB_GSO_TCPV6;
+   if (shinfo->gso_type & SKB_GSO_TCPV4) {
+   shinfo->gso_type &= ~SKB_GSO_TCPV4;
+   shinfo->gso_type |=  SKB_GSO_TCPV6;
}
 
/* Due to IPv6 header, MSS needs to be downgraded. */
-   skb_shinfo(skb)->gso_size -= len_diff;
+   skb_decrease_gso_size(shinfo, len_diff);
/* Header must be checked, and gso_segs recompu