Le jeu. 5 nov. 2026 à 11:08, <[email protected]> a écrit :
>
> Thank you for your contribution! Sashiko AI review found 2 potential
> issue(s) to consider.
>
> Critical: 0 · High: 0 · Medium: 1 · Low: 1
>
> If you believe none of the issues are legitimate, please reply to each
> issue of Medium severity or higher and explain why the AI is wrong.
> If any of them are legitimate and you plan to respin, please let patchwork
> know by including "pw-bot: cr" as a separate line at the end of your reply
> (one such reply per series is enough).
>
> - [Medium] The new tun_vnet_udptnl_proto and tun_vnet_udptnl_proto_l3
>   tests do not work on big-endian hosts.
> - [Low] The new comment in virtio_net_l4_start()
>   (include/linux/virtio_net.h) says the code does something it does not.
>
> --
>
> selftests: net: tun: test outer protocol of UDP tunnel GSO packets
>
> This adds tun selftests that write single 4in4 Geneve GSO frames to tap
> and IFF_TUN devices with UDP tunnel offloads enabled. They check that
> frames with a matching outer IPv4 header are accepted. They also check
> that a mismatched outer ethertype, tun_pi protocol or IP version is
> rejected with EINVAL.
>
> > diff --git a/tools/testing/selftests/net/tun.c 
> > b/tools/testing/selftests/net/tun.c
> > index 34de2580e32ec..81410afbbcc8d 100644
> > --- a/tools/testing/selftests/net/tun.c
> > +++ b/tools/testing/selftests/net/tun.c
> > @@ -683,6 +683,275 @@ TEST_F(tun_vnet_gso, vlan_tcpv4_gso_no_csum_64k)
>
> [ ... ]
>
> > +static int build_udptnl_frame(uint8_t *buf, bool vlan, uint16_t l3proto,
> > +                           int payload_len)
> > +{
> > +     struct virtio_net_hdr_v1_hash_tunnel *vh = (void *)buf;
> > +     int vlan_len = vlan ? 4 : 0;
> > +     int hlen = ETH_HLEN + vlan_len + UDP_TUNNEL_GENEVE_4IN4_HDRLEN;
> > +     uint8_t *outer_udph, *cur = buf;
> > +     int pktlen;
> > +
> > +     /* The buffer is reused: do not leave bytes from a previous frame. */
> > +     memset(buf, 0, TUN_VNET_TNL_SIZE + hlen + payload_len);
> > +
> > +     cur += build_virtio_net_hdr_v1_hash_tunnel(cur, true, hlen, 1400,
> > +                                                AF_INET, AF_INET);
> > +     vh->outer_th_offset += vlan_len;
> > +     vh->inner_nh_offset += vlan_len;
> > +     vh->hash_hdr.hdr.csum_start += vlan_len;
>
> [Severity: Medium]
> Do these new tests work on big-endian hosts? In struct
> virtio_net_hdr_v1_hash_tunnel, outer_th_offset and inner_nh_offset are
> __le16. Here they get native-endian arithmetic, applied on top of the
> host-order values that build_virtio_net_hdr_v1_hash_tunnel() in
> tuntap_helpers.h already wrote:
>
>     vh_tunnel->outer_th_offset = eth_hlen + outer_iphlen;
>     vh_tunnel->inner_nh_offset = vh_tunnel->outer_th_offset + ETH_HLEN +
>                                  GENEVE_HLEN + sizeof(struct udphdr);
>
> The kernel always decodes the tunnel offsets as little-endian. csum_start,
> on the other hand, follows the tun vnet endianness:
>
> include/linux/virtio_net.h:virtio_net_hdr_tnl_to_skb() {
>     ...
>     inner_th = __virtio16_to_cpu(little_endian, hdr->csum_start);
>     inner_nh = le16_to_cpu(vhdr->inner_nh_offset);
>     outer_th = le16_to_cpu(vhdr->outer_th_offset);
>     if (outer_th < outer_l3min ||
>         inner_nh < outer_th + sizeof(struct udphdr) ||
>         inner_th < inner_nh + inner_l3min)
>         return -EINVAL;
>     ...
> }
>
> tun_open() never issues TUNSETVNETLE. On s390x or BE ppc64, csum_start is
> therefore read in host order, but outer_th 34 is read as 0x2200 and
> inner_nh 64 as 0x4000. The offset check above then returns -EINVAL before
> virtio_net_tnl_offsets_ok() is reached.
>
> Wouldn't outer_proto_ok then fail on BE? And wouldn't outer_proto_bad
> pass there without ever reaching the new outer protocol validation?
>
> build_udptnl_l3_frame() does the same:
>
>     vh->outer_th_offset += IPV4_OPT_LEN;
>     vh->inner_nh_offset += IPV4_OPT_LEN;
>
> The helper's host-order writes predate this patch, and the existing
> tun_vnet_udptnl tests share the problem. Could these fields be converted
> with htole16()/le16toh() here and in the helper?


Right. build_virtio_net_hdr_v1_hash_tunnel() writes the tunnel offsets
in host order since commit a942fcd72e97 ("selftest: tun: Introduce
tuntap_helpers.h header for TUN/TAP testing"), so all UDP tunnel tests
in tun.c are broken on big-endian hosts, not only the new ones.

v3 adds a patch converting the offsets with htole16() in the helper,
and le16toh()/htole16() where the tests adjust them.


>
> > +
> > +     if (vlan) {
> > +             uint16_t vlan_tag[2] = { htons(100), htons(l3proto) };
>
> [ ... ]
>
> The following is about the first patch in this series, commit
> fca58b5faf90 ("net: virtio: validate outer protocol of UDP tunnel GSO
> packets"), which adds the code that the outer_proto_bad tests exercise.
>
> > diff --git a/include/linux/virtio_net.h b/include/linux/virtio_net.h
> > index d6466f96cdd00..b9c8babb1fd73 100644
> > --- a/include/linux/virtio_net.h
> > +++ b/include/linux/virtio_net.h
>
> [ ... ]
>
> > +     if (proto == htons(ETH_P_IPV6)) {
> > +             const struct ipv6hdr *iph;
> > +             int flags = IP6_FH_F_AUTH;
> > +
> > +             if (!pskb_may_pull(skb, nhoff + sizeof(*iph)))
> > +                     return false;
> > +             iph = (const void *)(skb->data + nhoff);
> > +             if (iph->version != 6)
> > +                     return false;
> > +             *thoff = nhoff + sizeof(*iph);
> > +             *ip_proto = iph->nexthdr;
> > +             if (*ip_proto != IPPROTO_TCP && *ip_proto != IPPROTO_UDP) {
> > +                     *thoff = nhoff;
> > +                     /* Find the transport header behind any
> > +                      * extension headers, AH included.
> > +                      */
> > +                     *ip_proto = ipv6_find_hdr(skb, thoff, -1, NULL,
> > +                                               &flags);
>
> [Severity: Low]
> This isn't a bug, but does this comment in virtio_net_l4_start() match
> what ipv6_find_hdr() does with these arguments?

Same as for patch 1: the comment is wrong, I will fix it in v3.


>With flags = IP6_FH_F_AUTH
> and target = -1, it stops at the AH header instead of walking past it:
>
> net/ipv6/exthdrs_core.c:ipv6_find_hdr() {
>     ...
>     } else if (nexthdr == NEXTHDR_AUTH) {
>         if (flags && (*flags & IP6_FH_F_AUTH) && (target < 0))
>             break;
>     ...
> }
>
> So for an outer IPv6 header followed by AH, ip_proto comes back as
> NEXTHDR_AUTH and virtio_net_tnl_offsets_ok() rejects the frame. The commit
> message says this is intended:
>
>   Unlike the original helpers, ipv6_find_hdr() stops at an AH header,
>   as Willem suggested in the review of that series.
>
> Could the comment say that the walk stops at AH?
>
> > +                     if (*ip_proto < 0 || flags & IP6_FH_F_FRAG)
> > +                             return false;
> > +             }
> > +             return true;
> > +     }
>
> [ ... ]
>
> --
> Sashiko AI review · 
> https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261104050131.629967-1-edumazet%40kernel.org

Reply via email to