From: Shmulik Ladkani <shmulik@metanetworks.com>
To: Willem de Bruijn <willemdebruijn.kernel@gmail.com>,
Daniel Borkmann <daniel@iogearbox.net>
Cc: Eric Dumazet <eric.dumazet@gmail.com>,
netdev <netdev@vger.kernel.org>,
Alexander Duyck <alexander.duyck@gmail.com>,
Alexei Starovoitov <ast@kernel.org>, Yonghong Song <yhs@fb.com>,
Steffen Klassert <steffen.klassert@secunet.com>,
Shmulik Ladkani <shmulik@metanetworks.com>,
eyal@metanetworks.com
Subject: Re: BUG_ON in skb_segment, after bpf_skb_change_proto was applied
Date: Tue, 3 Sep 2019 18:51:21 +0300 [thread overview]
Message-ID: <20190903185121.56906d31@pixies> (raw)
In-Reply-To: <CA+FuTSfVsgNDi7c=GUU8nMg2hWxF2SjCNLXetHeVPdnxAW5K-w@mail.gmail.com>
On Sun, 1 Sep 2019 16:05:48 -0400
Willem de Bruijn <willemdebruijn.kernel@gmail.com> wrote:
> One quick fix is to disable sg and thus revert to copying in this
> case. Not ideal, but better than a kernel splat:
>
> @@ -3714,6 +3714,9 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
> sg = !!(features & NETIF_F_SG);
> csum = !!can_checksum_protocol(features, proto);
>
> + if (list_skb && skb_headlen(list_skb) && !list_skb->head_frag)
> + sg = false;
> +
Thanks Willem.
I followed this approach, and further refined it based on the conditions
that lead to this BUG_ON:
- existance of frag_list
- mangled gso_size (using SKB_GSO_DODGY as a hint)
- some frag in the frag_list has a linear part that is NOT head_frag,
or length not equal to the requested gso_size
BTW, doing so allowed me to refactor a loop that tests for similar
conditions in the !(features & NETIF_F_GSO_PARTIAL) case, where an
attempt to execute partial splitting at the frag_list pointer (see
07b26c9454a2 and 43170c4e0ba7).
I've tested this using the reproducer, with various linear skbs in
the frag_list and different gso_size mangling. All resulting 'segs'
looked correct. Did not test on a live system yet.
Comments are welcome.
specifically, I would like to know whether we can
- better refine the condition where this "sg=false fallback" needs
to be applied
- consolidate my new 'list_skb && (type & SKB_GSO_DODGY)' case with
the existing '!(features & NETIF_F_GSO_PARTIAL)' case
see below:
@@ -3470,6 +3470,27 @@ static inline skb_frag_t skb_head_frag_to_page_desc(struct sk_buff *frag_skb)
return head_frag;
}
+static inline bool skb_is_nonlinear_equal_frags(struct sk_buff *skb,
+ unsigned int total_len,
+ unsigned int frag_len,
+ unsigned int *remain)
+{
+ struct sk_buff *iter;
+
+ skb_walk_frags(skb, iter) {
+ if (iter->len != frag_len && iter->next)
+ return false;
+ if (skb_headlen(iter) && !iter->head_frag)
+ return false;
+
+ total_len -= iter->len;
+ }
+
+ if (remain)
+ *remain = total_len;
+ return total_len == frag_len;
+}
+
/**
* skb_segment - Perform protocol segmentation on skb.
* @head_skb: buffer to segment
@@ -3486,6 +3507,7 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
struct sk_buff *tail = NULL;
struct sk_buff *list_skb = skb_shinfo(head_skb)->frag_list;
skb_frag_t *frag = skb_shinfo(head_skb)->frags;
+ unsigned int type = skb_shinfo(head_skb)->gso_type;
unsigned int mss = skb_shinfo(head_skb)->gso_size;
unsigned int doffset = head_skb->data - skb_mac_header(head_skb);
struct sk_buff *frag_skb = head_skb;
@@ -3510,13 +3532,29 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
sg = !!(features & NETIF_F_SG);
csum = !!can_checksum_protocol(features, proto);
- if (sg && csum && (mss != GSO_BY_FRAGS)) {
+ if (sg && (mss != GSO_BY_FRAGS)) {
+ if (list_skb && (type & SKB_GSO_DODGY)) {
+ /* gso_size is untrusted.
+ * if head_skb has a frag_list that contains a frag
+ * with a linear (non head_frag) part, or a frag whose
+ * length doesn't fit requested mss, fallback to skb
+ * copying by disabling sg.
+ */
+ if (!skb_is_nonlinear_equal_frags(head_skb, len, mss,
+ NULL)) {
+ sg = false;
+ goto normal;
+ }
+ }
+
+ if (!csum)
+ goto normal;
+
if (!(features & NETIF_F_GSO_PARTIAL)) {
- struct sk_buff *iter;
unsigned int frag_len;
if (!list_skb ||
- !net_gso_ok(features, skb_shinfo(head_skb)->gso_type))
+ !net_gso_ok(features, type))
goto normal;
/* If we get here then all the required
@@ -3528,17 +3566,10 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
* the last are of the same length.
*/
frag_len = list_skb->len;
- skb_walk_frags(head_skb, iter) {
- if (frag_len != iter->len && iter->next)
- goto normal;
- if (skb_headlen(iter) && !iter->head_frag)
- goto normal;
-
- len -= iter->len;
- }
-
- if (len != frag_len)
+ if (!skb_is_nonlinear_equal_frags(head_skb, len,
+ frag_len, &len)) {
goto normal;
+ }
}
/* GSO partial only requires that we trim off any excess that
next prev parent reply other threads:[~2019-09-03 15:51 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-08-26 14:07 BUG_ON in skb_segment, after bpf_skb_change_proto was applied Shmulik Ladkani
2019-08-26 17:47 ` Eric Dumazet
2019-08-27 11:42 ` Shmulik Ladkani
2019-08-27 12:10 ` Daniel Borkmann
2019-08-28 5:56 ` Shmulik Ladkani
2019-08-29 12:22 ` Shmulik Ladkani
2019-09-01 20:05 ` Willem de Bruijn
2019-09-02 13:44 ` Shmulik Ladkani
2019-09-03 15:51 ` Shmulik Ladkani [this message]
2019-09-03 16:23 ` Willem de Bruijn
2019-09-03 17:03 ` Shmulik Ladkani
2019-09-03 17:24 ` Willem de Bruijn
2019-08-27 15:09 ` Eric Dumazet
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20190903185121.56906d31@pixies \
--to=shmulik@metanetworks.com \
--cc=alexander.duyck@gmail.com \
--cc=ast@kernel.org \
--cc=daniel@iogearbox.net \
--cc=eric.dumazet@gmail.com \
--cc=eyal@metanetworks.com \
--cc=netdev@vger.kernel.org \
--cc=steffen.klassert@secunet.com \
--cc=willemdebruijn.kernel@gmail.com \
--cc=yhs@fb.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.