skb_zerocopy() fails to propagate the unreadable flag when copying
unreadable fragments, causing target skbs to appear as readable memory.

This patch fixes the flag propagation. Additionally, it returns -EFAULT
if readable fragments are mixed with unreadable fragments during
extraction, and returns -EFAULT in openvswitch queue_userspace_packet().

Fixes: 65249feb6b3d ("net: add support for skbs with unreadable frags")
Cc: Pavel Begunkov <[email protected]>
Cc: Stanislav Fomichev <[email protected]>
Cc: Bobby Eshleman <[email protected]>
Cc: Florian Westphal <[email protected]>
Cc: Aaron Conole <[email protected]>
Cc: Eelco Chaudron <[email protected]>
Cc: Ilya Maximets <[email protected]>
Cc: Willem de Bruijn <[email protected]>
Signed-off-by: Mina Almasry <[email protected]>
Reviewed-by: Pavel Begunkov <[email protected]>
Reviewed-by: Ilya Maximets <[email protected]>
---
v4:
- Changed commit references from payload types to readable/unreadable
  fragments.
---
 net/core/skbuff.c          | 13 ++++++++++++-
 net/openvswitch/datapath.c |  3 +++
 2 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index ba3dbac80fb49..d21af68156950 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -3870,7 +3870,8 @@ EXPORT_SYMBOL_GPL(skb_zerocopy_headlen);
  *     Return value:
  *     0: everything is OK
  *     -ENOMEM: couldn't orphan frags of @from due to lack of memory
- *     -EFAULT: skb_copy_bits() found some problem with skb geometry
+ *     -EFAULT: skb_copy_bits() found some problem with skb geometry, or 
readable head
+ *      payload would be mixed with unreadable frags.
  */
 int
 skb_zerocopy(struct sk_buff *to, struct sk_buff *from, int len, int hlen)
@@ -3905,10 +3906,17 @@ skb_zerocopy(struct sk_buff *to, struct sk_buff *from, 
int len, int hlen)
                }
        }
 
+       if (!skb_frags_readable(from) && j > 0 && len) {
+               put_page(virt_to_head_page(from->head));
+               return -EFAULT;
+       }
+
        skb_len_add(to, len + plen);
 
        if (unlikely(skb_orphan_frags(from, GFP_ATOMIC))) {
                skb_tx_error(from);
+               if (j > 0)
+                       put_page(virt_to_head_page(from->head));
                return -ENOMEM;
        }
        skb_zerocopy_clone(to, from, GFP_ATOMIC);
@@ -3928,6 +3936,9 @@ skb_zerocopy(struct sk_buff *to, struct sk_buff *from, 
int len, int hlen)
        }
        skb_shinfo(to)->nr_frags = j;
 
+       if (i > 0 && from->unreadable)
+               to->unreadable = 1;
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(skb_zerocopy);
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
index ae69b2cabab9e..482893a5f67dc 100644
--- a/net/openvswitch/datapath.c
+++ b/net/openvswitch/datapath.c
@@ -467,6 +467,9 @@ static int queue_userspace_packet(struct datapath *dp, 
struct sk_buff *skb,
        if (!dp_ifindex)
                return -ENODEV;
 
+       if (!skb_frags_readable(skb))
+               return -EFAULT;
+
        if (skb_vlan_tag_present(skb)) {
                nskb = skb_clone(skb, GFP_ATOMIC);
                if (!nskb)

base-commit: 24ef02f934eeb48830cff6b739abc3c62b1d107b
-- 
2.55.0.691.gc56d675ccc-goog

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to