On 4/28/25 6:52 PM, Mike Pattrick via dev wrote:
> Currently while handling the 24 bit VNI field in VXLAN code,
> netdev-offload-dpdk will actually read and write 32 bits. The byte that
> is overwritten is reserved and supposed to be set to zero anyways, so
> this is mostly harmless.
> 
> However, Openscanhub correctly identified this as a buffer overrun. Now
> two new functions are added for using a 32 bit integer to set these
> fields without overwriting a 4th byte.
> 
> Reported-at: https://issues.redhat.com/browse/FDP-1122
> Signed-off-by: Mike Pattrick <m...@redhat.com>
> ---
>  include/openvswitch/types.h |  1 +
>  lib/netdev-offload-dpdk.c   | 23 +++++++++--------------
>  lib/unaligned.h             | 21 +++++++++++++++++++++
>  3 files changed, 31 insertions(+), 14 deletions(-)
> 
> diff --git a/include/openvswitch/types.h b/include/openvswitch/types.h
> index 8c5ec94a6..a364f024a 100644
> --- a/include/openvswitch/types.h
> +++ b/include/openvswitch/types.h
> @@ -36,6 +36,7 @@ extern "C" {
>  /* The ovs_be<N> types indicate that an object is in big-endian, not
>   * native-endian, byte order.  They are otherwise equivalent to uint<N>_t. */
>  typedef uint16_t OVS_BITWISE ovs_be16;
> +typedef uint8_t ovs_be24[3];
>  typedef uint32_t OVS_BITWISE ovs_be32;
>  typedef uint64_t OVS_BITWISE ovs_be64;
>  
> diff --git a/lib/netdev-offload-dpdk.c b/lib/netdev-offload-dpdk.c
> index 6ca271489..66ae23f28 100644
> --- a/lib/netdev-offload-dpdk.c
> +++ b/lib/netdev-offload-dpdk.c
> @@ -607,19 +607,17 @@ dump_flow_pattern(struct ds *s,
>      } else if (item->type == RTE_FLOW_ITEM_TYPE_VXLAN) {
>          const struct rte_flow_item_vxlan *vxlan_spec = item->spec;
>          const struct rte_flow_item_vxlan *vxlan_mask = item->mask;
> -        ovs_be32 spec_vni, mask_vni;
> +        uint32_t spec_vni, mask_vni;
>  
>          ds_put_cstr(s, "vxlan ");
>          if (vxlan_spec) {
>              if (!vxlan_mask) {
>                  vxlan_mask = &rte_flow_item_vxlan_mask;
>              }
> -            spec_vni = get_unaligned_be32(ALIGNED_CAST(ovs_be32 *,
> -                                                       vxlan_spec->vni));
> -            mask_vni = get_unaligned_be32(ALIGNED_CAST(ovs_be32 *,
> -                                                       vxlan_mask->vni));
> +            spec_vni = get_unaligned_be24(vxlan_spec->vni);
> +            mask_vni = get_unaligned_be24(vxlan_mask->vni);
>              DUMP_PATTERN_ITEM(vxlan_mask->vni, false, "vni", "%"PRIu32,
> -                              ntohl(spec_vni) >> 8, ntohl(mask_vni) >> 8, 0);
> +                              spec_vni, mask_vni, 0);
>          }
>          ds_put_cstr(s, "/ ");
>      } else if (item->type == RTE_FLOW_ITEM_TYPE_GRE) {
> @@ -693,11 +691,10 @@ dump_vxlan_encap(struct ds *s, const struct 
> rte_flow_item *items)
>      ds_put_format(s, "set vxlan ip-version %s ",
>                    ipv4 ? "ipv4" : ipv6 ? "ipv6" : "ERR");
>      if (vxlan) {
> -        ovs_be32 vni;
> +        uint32_t vni;
>  
> -        vni = get_unaligned_be32(ALIGNED_CAST(ovs_be32 *,
> -                                              vxlan->vni));
> -        ds_put_format(s, "vni %"PRIu32" ", ntohl(vni) >> 8);
> +        vni = get_unaligned_be24(vxlan->vni);
> +        ds_put_format(s, "vni %"PRIu32" ", vni);
>      }
>      if (udp) {
>          ds_put_format(s, "udp-src %"PRIu16" udp-dst %"PRIu16" ",
> @@ -1300,10 +1297,8 @@ parse_vxlan_match(struct flow_patterns *patterns,
>      vx_spec = xzalloc(sizeof *vx_spec);
>      vx_mask = xzalloc(sizeof *vx_mask);
>  
> -    put_unaligned_be32(ALIGNED_CAST(ovs_be32 *, vx_spec->vni),
> -                       htonl(ntohll(match->flow.tunnel.tun_id) << 8));
> -    put_unaligned_be32(ALIGNED_CAST(ovs_be32 *, vx_mask->vni),
> -                       htonl(ntohll(match->wc.masks.tunnel.tun_id) << 8));
> +    put_unaligned_be24(vx_spec->vni, ntohll(match->flow.tunnel.tun_id));
> +    put_unaligned_be24(vx_mask->vni, ntohll(match->wc.masks.tunnel.tun_id));
>  
>      consumed_masks->tunnel.tun_id = 0;
>      consumed_masks->tunnel.flags = 0;
> diff --git a/lib/unaligned.h b/lib/unaligned.h
> index 15334e3c7..212353e5f 100644
> --- a/lib/unaligned.h
> +++ b/lib/unaligned.h
> @@ -31,9 +31,11 @@ static inline void put_unaligned_u32(uint32_t *, uint32_t);
>  static inline void put_unaligned_u64(uint64_t *, uint64_t);
>  
>  static inline ovs_be16 get_unaligned_be16(const ovs_be16 *);
> +static inline uint32_t get_unaligned_be24(const ovs_be24);
>  static inline ovs_be32 get_unaligned_be32(const ovs_be32 *);
>  static inline ovs_be64 get_unaligned_be64(const ovs_be64 *);
>  static inline void put_unaligned_be16(ovs_be16 *, ovs_be16);
> +static inline void put_unaligned_be24(ovs_be24, uint64_t);

There is no such thing as "unaligned be24".  24-bit value is always aligned,
because it's alignment is 1 byte.  So, these new helpers do not make a lot
of sense.  Plain memcpy should be used if necessary.

However, we should just use 'hdr.vx_vni' instead of 'vni', as the non-'hdr'
fields in rte_flow structures are deprecated anyway.  'vx_vni' is a 32bit
field and can be accessed with the current 32bit functions.

Best regards, Ilya Maximets.
_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to