On 17 Mar 2026, at 19:55, Mike Pattrick via dev wrote:

> When a batch is full, dp_packet_batch_add() frees the packet instead of
> adding it to the batch.  In dp_packet_gso__(), the code calls
> dp_packet_batch_add() to add the original packet 'p' back into the
> batch, but does not check if the packet was freed.  If the packet was
> freed, subsequent operations on 'p' (such as dp_packet_tunnel(),
> dp_packet_get_inner_tcp_payload(), and dp_packet_set_size()) cause
> undefined behavior.
>
> Fix by checking the return value and exiting early if the packet was
> freed.
>
> Found with clang analyze.
>
> Fixes: ef762327f6d3 ("dp-packet-gso: Refactor software segmentation code.")
> Signed-off-by: Mike Pattrick <[email protected]>
> ---
>  lib/dp-packet-gso.c |  4 +++-
>  lib/dp-packet.h     | 12 +++++++-----
>  2 files changed, 10 insertions(+), 6 deletions(-)
>
> diff --git a/lib/dp-packet-gso.c b/lib/dp-packet-gso.c
> index bceb851fb..0d4d52daf 100644
> --- a/lib/dp-packet-gso.c
> +++ b/lib/dp-packet-gso.c
> @@ -199,7 +199,9 @@ dp_packet_gso__(struct dp_packet *p, struct 
> dp_packet_batch **batches,
>      if (dp_packet_batch_is_full(curr_batch)) {
>          curr_batch++;
>      }
> -    dp_packet_batch_add(curr_batch, p);

Hi Mike,

Thanks for the patch. However, I don't believe this change is necessary.

Just one line above the proposed change, the code checks if the batch is
full via dp_packet_batch_is_full(curr_batch). If it is, it moves to the
next (empty) batch in the array.

This appears to be a false positive from the static analyzer (I have also
marked this as a false positive in Coverity previously). Furthermore, if
we were to adopt this check, it is missing from the other invocations of
dp_packet_batch_add() later in the same function.

Cheers,

Eelco

> +    if (!dp_packet_batch_add(curr_batch, p)) {
> +        goto out;
> +    }
>
>      if (n_segs <= 1) {
>          goto out;
> diff --git a/lib/dp-packet.h b/lib/dp-packet.h
> index d92b9d473..fb15a8546 100644
> --- a/lib/dp-packet.h
> +++ b/lib/dp-packet.h
> @@ -872,22 +872,24 @@ dp_packet_batch_init(struct dp_packet_batch *batch)
>      batch->trunc = false;
>  }
>
> -static inline void
> +static inline bool
>  dp_packet_batch_add__(struct dp_packet_batch *batch,
>                        struct dp_packet *packet, size_t limit)
>  {
>      if (batch->count < limit) {
>          batch->packets[batch->count++] = packet;
> +        return true;
>      } else {
>          dp_packet_delete(packet);
> +        return false;
>      }
>  }
>
>  /* When the batch is full, 'packet' will be dropped and freed. */
> -static inline void
> +static inline bool
>  dp_packet_batch_add(struct dp_packet_batch *batch, struct dp_packet *packet)
>  {
> -    dp_packet_batch_add__(batch, packet, NETDEV_MAX_BURST);
> +    return dp_packet_batch_add__(batch, packet, NETDEV_MAX_BURST);
>  }
>
>  static inline size_t
> @@ -904,11 +906,11 @@ dp_packet_batch_refill_init(struct dp_packet_batch 
> *batch)
>      batch->count = 0;
>  };
>
> -static inline void
> +static inline bool
>  dp_packet_batch_refill(struct dp_packet_batch *batch,
>                         struct dp_packet *packet, size_t idx)
>  {
> -    dp_packet_batch_add__(batch, packet, MIN(NETDEV_MAX_BURST, idx + 1));
> +    return dp_packet_batch_add__(batch, packet, MIN(NETDEV_MAX_BURST, idx + 
> 1));
>  }
>
>  static inline void
> -- 
> 2.53.0
>
> _______________________________________________
> dev mailing list
> [email protected]
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev

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

Reply via email to