netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] sfc: handle NULL returned by xdp_convert_buff_to_frame()
@ 2025-07-23  0:32 Chenyuan Yang
  2025-07-24  9:57 ` Paolo Abeni
  0 siblings, 1 reply; 8+ messages in thread
From: Chenyuan Yang @ 2025-07-23  0:32 UTC (permalink / raw)
  To: ecree.xilinx, andrew+netdev, davem, edumazet, kuba, pabeni, ast,
	daniel, hawk, john.fastabend, sdf, lorenzo
  Cc: netdev, linux-net-drivers, bpf, zzjas98, Chenyuan Yang

The xdp_convert_buff_to_frame() function can return NULL when there is
insufficient headroom in the buffer to store the xdp_frame structure
or when the driver didn't reserve enough tailroom for skb_shared_info.

Currently, the sfc driver does not check for this NULL return value
in the XDP_TX case within efx_do_xdp(). While the efx_xdp_tx_buffers()
function has some defensive checks, passing a NULL xdpf can still lead
to undefined behavior when the function tries to access xdpf->len and
xdpf->data.

Fix by adding a proper NULL check in the XDP_TX case. If conversion
fails, free the RX buffer and increment the bad drops counter, following
the same pattern used for other XDP error conditions in this driver.

Signed-off-by: Chenyuan Yang <chenyuan0y@gmail.com>
Fixes: 1b698fa5d8ef ("xdp: Rename convert_to_xdp_frame in xdp_convert_buff_to_frame")
---
 drivers/net/ethernet/sfc/rx.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/net/ethernet/sfc/rx.c b/drivers/net/ethernet/sfc/rx.c
index ffca82207e47..6321ccd8c8fa 100644
--- a/drivers/net/ethernet/sfc/rx.c
+++ b/drivers/net/ethernet/sfc/rx.c
@@ -308,6 +308,12 @@ static bool efx_do_xdp(struct efx_nic *efx, struct efx_channel *channel,
 	case XDP_TX:
 		/* Buffer ownership passes to tx on success. */
 		xdpf = xdp_convert_buff_to_frame(&xdp);
+		if (unlikely(!xdpf)) {
+			efx_free_rx_buffers(rx_queue, rx_buf, 1);
+			channel->n_rx_xdp_bad_drops++;
+			break;
+		}
+
 		err = efx_xdp_tx_buffers(efx, 1, &xdpf, true);
 		if (unlikely(err != 1)) {
 			efx_free_rx_buffers(rx_queue, rx_buf, 1);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH] sfc: handle NULL returned by xdp_convert_buff_to_frame()
  2025-07-23  0:32 [PATCH] sfc: handle NULL returned by xdp_convert_buff_to_frame() Chenyuan Yang
@ 2025-07-24  9:57 ` Paolo Abeni
  2025-07-25 10:11   ` Edward Cree
  0 siblings, 1 reply; 8+ messages in thread
From: Paolo Abeni @ 2025-07-24  9:57 UTC (permalink / raw)
  To: Chenyuan Yang, ecree.xilinx, andrew+netdev, davem, edumazet, kuba,
	ast, daniel, hawk, john.fastabend, sdf, lorenzo
  Cc: netdev, linux-net-drivers, bpf, zzjas98

On 7/23/25 2:32 AM, Chenyuan Yang wrote:
> The xdp_convert_buff_to_frame() function can return NULL when there is
> insufficient headroom in the buffer to store the xdp_frame structure
> or when the driver didn't reserve enough tailroom for skb_shared_info.

AFAIC the sfc driver reserves both enough headroom and tailroom, but
this is after ebpf run, which in turn could consume enough headroom to
cause a failure, so I think this makes sense.

@Eduard: could you please have a look?

Thanks,

Paolo


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] sfc: handle NULL returned by xdp_convert_buff_to_frame()
  2025-07-24  9:57 ` Paolo Abeni
@ 2025-07-25 10:11   ` Edward Cree
  2025-07-25 12:38     ` Kunwu Chan
  2025-07-31  9:14     ` Jesper Dangaard Brouer
  0 siblings, 2 replies; 8+ messages in thread
From: Edward Cree @ 2025-07-25 10:11 UTC (permalink / raw)
  To: Paolo Abeni, Chenyuan Yang, ecree.xilinx, andrew+netdev, davem,
	edumazet, kuba, ast, daniel, hawk, john.fastabend, sdf, lorenzo
  Cc: netdev, linux-net-drivers, bpf, zzjas98

On 7/24/25 10:57, Paolo Abeni wrote:
> On 7/23/25 2:32 AM, Chenyuan Yang wrote:
>> The xdp_convert_buff_to_frame() function can return NULL when there is
>> insufficient headroom in the buffer to store the xdp_frame structure
>> or when the driver didn't reserve enough tailroom for skb_shared_info.
> 
> AFAIC the sfc driver reserves both enough headroom and tailroom, but
> this is after ebpf run, which in turn could consume enough headroom to
> cause a failure, so I think this makes sense.

Your reasoning seems plausible to me.
However, I think the error path ought to more closely follow the existing
 error cases in logging a ratelimited message and calling the tracepoint.
I think the cleanest way to do this would be:
	if (unlikely(!xdpf))
		err = -ENOBUFS;
	else
		err = efx_xdp_tx_buffers(efx, 1, &xdpf, true);
 so that it can make use of the existing failure path.
Adding the check to efx_xdp_tx_buffers() is also an option.

-ed

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] sfc: handle NULL returned by xdp_convert_buff_to_frame()
  2025-07-25 10:11   ` Edward Cree
@ 2025-07-25 12:38     ` Kunwu Chan
  2025-07-26 19:56       ` Chenyuan Yang
  2025-07-28 14:28       ` Edward Cree
  2025-07-31  9:14     ` Jesper Dangaard Brouer
  1 sibling, 2 replies; 8+ messages in thread
From: Kunwu Chan @ 2025-07-25 12:38 UTC (permalink / raw)
  To: Edward Cree, Paolo Abeni, Chenyuan Yang, ecree.xilinx,
	andrew+netdev, davem, edumazet, kuba, ast, daniel, hawk,
	john.fastabend, sdf, lorenzo
  Cc: netdev, linux-net-drivers, bpf, zzjas98

On 2025/7/25 18:11, Edward Cree wrote:
> On 7/24/25 10:57, Paolo Abeni wrote:
>> On 7/23/25 2:32 AM, Chenyuan Yang wrote:
>>> The xdp_convert_buff_to_frame() function can return NULL when there is
>>> insufficient headroom in the buffer to store the xdp_frame structure
>>> or when the driver didn't reserve enough tailroom for skb_shared_info.
>> AFAIC the sfc driver reserves both enough headroom and tailroom, but
>> this is after ebpf run, which in turn could consume enough headroom to
>> cause a failure, so I think this makes sense.
> Your reasoning seems plausible to me.
> However, I think the error path ought to more closely follow the existing
>   error cases in logging a ratelimited message and calling the tracepoint.
> I think the cleanest way to do this would be:
> 	if (unlikely(!xdpf))
> 		err = -ENOBUFS;
> 	else
> 		err = efx_xdp_tx_buffers(efx, 1, &xdpf, true);
>   so that it can make use of the existing failure path.
> Adding the check to efx_xdp_tx_buffers() is also an option.
>
> -ed
>
Hi Chenyuan,

THX for addressing this edge case. I concur with Edward's suggestion to 
integrate this with the existing error handling flow. This will ensure:
Consistent observability (ratelimited logs + tracepoints)
Centralized resource cleanup
Clear error type differentiation via -ENOBUFS

Proposed refinement:

diff
  case XDP_TX:
      /* Buffer ownership passes to tx on success. */
      xdpf = xdp_convert_buff_to_frame(&xdp);
+    if (unlikely(!xdpf)) {
+        err = -ENOBUFS;
+    } else {
+        err = efx_siena_xdp_tx_buffers(efx, 1, &xdpf, true);
+    }

-    err = efx_siena_xdp_tx_buffers(efx, 1, &xdpf, true);
      if (unlikely(err != 1)) {
          efx_siena_free_rx_buffers(rx_queue, rx_buf, 1);
          if (net_ratelimit())
              netif_err(efx, rx_err, efx->net_dev,
-                  "XDP TX failed (%d)\n", err);
+                  "XDP TX failed (%d)%s\n", err,
+                  err == -ENOBUFS ? " [frame conversion]" : "");
          channel->n_rx_xdp_bad_drops++;
-        trace_xdp_exception(efx->net_dev, xdp_prog, xdp_act);
+        if (err != -ENOBUFS)
+            trace_xdp_exception(efx->net_dev, xdp_prog, xdp_act);
      } else {
          channel->n_rx_xdp_tx++;
      }
      break;


-- Thanks, TAO. --- “Life finds a way.”

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] sfc: handle NULL returned by xdp_convert_buff_to_frame()
  2025-07-25 12:38     ` Kunwu Chan
@ 2025-07-26 19:56       ` Chenyuan Yang
  2025-07-28 14:28       ` Edward Cree
  1 sibling, 0 replies; 8+ messages in thread
From: Chenyuan Yang @ 2025-07-26 19:56 UTC (permalink / raw)
  To: Kunwu Chan
  Cc: Edward Cree, Paolo Abeni, ecree.xilinx, andrew+netdev, davem,
	edumazet, kuba, ast, daniel, hawk, john.fastabend, sdf, lorenzo,
	netdev, linux-net-drivers, bpf, zzjas98

Thanks so much for your suggestion! I just submitted the v2 based on
your comments for this issue :)

On Fri, Jul 25, 2025 at 5:39 AM Kunwu Chan <kunwu.chan@linux.dev> wrote:
>
> On 2025/7/25 18:11, Edward Cree wrote:
> > On 7/24/25 10:57, Paolo Abeni wrote:
> >> On 7/23/25 2:32 AM, Chenyuan Yang wrote:
> >>> The xdp_convert_buff_to_frame() function can return NULL when there is
> >>> insufficient headroom in the buffer to store the xdp_frame structure
> >>> or when the driver didn't reserve enough tailroom for skb_shared_info.
> >> AFAIC the sfc driver reserves both enough headroom and tailroom, but
> >> this is after ebpf run, which in turn could consume enough headroom to
> >> cause a failure, so I think this makes sense.
> > Your reasoning seems plausible to me.
> > However, I think the error path ought to more closely follow the existing
> >   error cases in logging a ratelimited message and calling the tracepoint.
> > I think the cleanest way to do this would be:
> >       if (unlikely(!xdpf))
> >               err = -ENOBUFS;
> >       else
> >               err = efx_xdp_tx_buffers(efx, 1, &xdpf, true);
> >   so that it can make use of the existing failure path.
> > Adding the check to efx_xdp_tx_buffers() is also an option.
> >
> > -ed
> >
> Hi Chenyuan,
>
> THX for addressing this edge case. I concur with Edward's suggestion to
> integrate this with the existing error handling flow. This will ensure:
> Consistent observability (ratelimited logs + tracepoints)
> Centralized resource cleanup
> Clear error type differentiation via -ENOBUFS
>
> Proposed refinement:
>
> diff
>   case XDP_TX:
>       /* Buffer ownership passes to tx on success. */
>       xdpf = xdp_convert_buff_to_frame(&xdp);
> +    if (unlikely(!xdpf)) {
> +        err = -ENOBUFS;
> +    } else {
> +        err = efx_siena_xdp_tx_buffers(efx, 1, &xdpf, true);
> +    }
>
> -    err = efx_siena_xdp_tx_buffers(efx, 1, &xdpf, true);
>       if (unlikely(err != 1)) {
>           efx_siena_free_rx_buffers(rx_queue, rx_buf, 1);
>           if (net_ratelimit())
>               netif_err(efx, rx_err, efx->net_dev,
> -                  "XDP TX failed (%d)\n", err);
> +                  "XDP TX failed (%d)%s\n", err,
> +                  err == -ENOBUFS ? " [frame conversion]" : "");
>           channel->n_rx_xdp_bad_drops++;
> -        trace_xdp_exception(efx->net_dev, xdp_prog, xdp_act);
> +        if (err != -ENOBUFS)
> +            trace_xdp_exception(efx->net_dev, xdp_prog, xdp_act);
>       } else {
>           channel->n_rx_xdp_tx++;
>       }
>       break;
>
>
> -- Thanks, TAO. --- “Life finds a way.”

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] sfc: handle NULL returned by xdp_convert_buff_to_frame()
  2025-07-25 12:38     ` Kunwu Chan
  2025-07-26 19:56       ` Chenyuan Yang
@ 2025-07-28 14:28       ` Edward Cree
  2025-07-30  7:38         ` Kunwu Chan
  1 sibling, 1 reply; 8+ messages in thread
From: Edward Cree @ 2025-07-28 14:28 UTC (permalink / raw)
  To: Kunwu Chan, Edward Cree, Paolo Abeni, Chenyuan Yang,
	andrew+netdev, davem, edumazet, kuba, ast, daniel, hawk,
	john.fastabend, sdf, lorenzo
  Cc: netdev, linux-net-drivers, bpf, zzjas98

On 25/07/2025 13:38, Kunwu Chan wrote:
> Proposed refinement:
...
>          if (net_ratelimit())
>              netif_err(efx, rx_err, efx->net_dev,
> -                  "XDP TX failed (%d)\n", err);
> +                  "XDP TX failed (%d)%s\n", err,
> +                  err == -ENOBUFS ? " [frame conversion]" : "");

Unnecessary, since efx_xdp_tx_buffers() never returns ENOBUFS.

>          channel->n_rx_xdp_bad_drops++;
> -        trace_xdp_exception(efx->net_dev, xdp_prog, xdp_act);
> +        if (err != -ENOBUFS)
> +            trace_xdp_exception(efx->net_dev, xdp_prog, xdp_act);

Why prevent the tracepoint in this case??

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] sfc: handle NULL returned by xdp_convert_buff_to_frame()
  2025-07-28 14:28       ` Edward Cree
@ 2025-07-30  7:38         ` Kunwu Chan
  0 siblings, 0 replies; 8+ messages in thread
From: Kunwu Chan @ 2025-07-30  7:38 UTC (permalink / raw)
  To: Edward Cree, Edward Cree, Paolo Abeni, Chenyuan Yang,
	andrew+netdev, davem, edumazet, kuba, ast, daniel, hawk,
	john.fastabend, sdf, lorenzo
  Cc: netdev, linux-net-drivers, bpf, zzjas98

On 2025/7/28 22:28, Edward Cree wrote:
> On 25/07/2025 13:38, Kunwu Chan wrote:
>> Proposed refinement:
> ...
>>           if (net_ratelimit())
>>               netif_err(efx, rx_err, efx->net_dev,
>> -                  "XDP TX failed (%d)\n", err);
>> +                  "XDP TX failed (%d)%s\n", err,
>> +                  err == -ENOBUFS ? " [frame conversion]" : "");
> Unnecessary, since efx_xdp_tx_buffers() never returns ENOBUFS.

You're correct that efx_siena_xdp_tx_buffers() never returns -ENOBUFS,

and xdp_convert_buff_to_frame() returns NULL on failure.

Whether we need a log to distinguish where the errors come from?

  +   if (unlikely(!xdpf))

  +          err = -ENOBUFS;

  +   else

  +      err = efx_xdp_tx_buffers(efx, 1, &xdpf, true);

  -    err = efx_siena_xdp_tx_buffers(efx, 1, &xdpf, true);
       if (unlikely(err != 1)) {
           efx_siena_free_rx_buffers(rx_queue, rx_buf, 1);
           if (net_ratelimit())
               netif_err(efx, rx_err, efx->net_dev,
-                  "XDP TX failed (%d)\n", err);
+                  "XDP TX failed (%d)%s\n", err,
+                  err == -ENOBUFS ? " [xdp_convert_buff_to_frame]" : 
"efx_siena_xdp_tx_buffers");

Just a personal thought.


>
>>           channel->n_rx_xdp_bad_drops++;
>> -        trace_xdp_exception(efx->net_dev, xdp_prog, xdp_act);
>> +        if (err != -ENOBUFS)
>> +            trace_xdp_exception(efx->net_dev, xdp_prog, xdp_act);
> Why prevent the tracepoint in this case??
You're correct, my mistake.

-- 
Thanks,
        TAO.
---
“Life finds a way.”


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] sfc: handle NULL returned by xdp_convert_buff_to_frame()
  2025-07-25 10:11   ` Edward Cree
  2025-07-25 12:38     ` Kunwu Chan
@ 2025-07-31  9:14     ` Jesper Dangaard Brouer
  1 sibling, 0 replies; 8+ messages in thread
From: Jesper Dangaard Brouer @ 2025-07-31  9:14 UTC (permalink / raw)
  To: Edward Cree, Paolo Abeni, Chenyuan Yang, ecree.xilinx,
	andrew+netdev, davem, edumazet, kuba, ast, daniel, john.fastabend,
	sdf, lorenzo
  Cc: netdev, linux-net-drivers, bpf, zzjas98



On 25/07/2025 12.11, Edward Cree wrote:
> On 7/24/25 10:57, Paolo Abeni wrote:
>> On 7/23/25 2:32 AM, Chenyuan Yang wrote:
>>> The xdp_convert_buff_to_frame() function can return NULL when there is
>>> insufficient headroom in the buffer to store the xdp_frame structure
>>> or when the driver didn't reserve enough tailroom for skb_shared_info.
>>
>> AFAIC the sfc driver reserves both enough headroom and tailroom, but
>> this is after ebpf run, which in turn could consume enough headroom to
>> cause a failure, so I think this makes sense.
> 
> Your reasoning seems plausible to me.

Hmm... have you actually tested that XDP/BPF can adjust headroom so much
that xdp_convert_buff_to_frame() function fails?

I really doubt this possible for BPF-progs to violate this.

The XDP BPF-prog can only adjust the headroom via the helpers
bpf_xdp_adjust_head() and bpf_xdp_adjust_meta().  These helpers reserve
room for sizeof(struct xdp_frame).

The tailroom can be adjusted via helper bpf_xdp_adjust_tail() and it
also reserve room for sizeof(struct skb_shared_info) such that BPF-progs
cannot get access to this area. See define for xdp_data_hard_end.

--Jesper

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2025-07-31  9:14 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-07-23  0:32 [PATCH] sfc: handle NULL returned by xdp_convert_buff_to_frame() Chenyuan Yang
2025-07-24  9:57 ` Paolo Abeni
2025-07-25 10:11   ` Edward Cree
2025-07-25 12:38     ` Kunwu Chan
2025-07-26 19:56       ` Chenyuan Yang
2025-07-28 14:28       ` Edward Cree
2025-07-30  7:38         ` Kunwu Chan
2025-07-31  9:14     ` Jesper Dangaard Brouer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).