Re: [PATCH net-next 10/15] i40e: prepare for XDP metadata ops support

Kohei Enju <[email protected]>
Newsgroups dev.linux.lists.sashiko-reviews,org.kernel.vger.bpf
Message-ID <anYnt4a74hohZ-M1@x1>
On 08/06 21:36, [email protected] wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> 
> Pre-existing issues:
> - [Critical] Use-After-Free in the AF_XDP Zero-Copy receive path due to stagnant index variable on error.
> --
> 
> --- Patch [10]: [PATCH net-next 10/15] i40e: prepare for XDP metadata ops support ---
> commit cf380b8d06da010c94723db1eb6af6df8fb0fdc8
> Author: Kohei Enju <[email protected]>
> 
> i40e: prepare for XDP metadata ops support
> 
> This commit introduces struct i40e_xdp_buff to wrap an xdp_buff alongside
> a pointer to an i40e_rx_desc. It passes the RX descriptor to XDP kfuncs
> and adds bounds checking in the AF_XDP Zero-Copy path using
> XSK_CHECK_PRIV_TYPE.
> 
> > diff --git a/drivers/net/ethernet/intel/i40e/i40e_xsk.c b/drivers/net/ethernet/intel/i40e/i40e_xsk.c
> > index 9f47388eaba53..51a05ce4c7ce8 100644
> > --- a/drivers/net/ethernet/intel/i40e/i40e_xsk.c
> > +++ b/drivers/net/ethernet/intel/i40e/i40e_xsk.c
> 
> [ ... ]
> 
> > @@ -472,6 +482,8 @@ int i40e_clean_rx_irq_zc(struct i40e_ring *rx_ring, int budget)
> >  		if (i40e_is_non_eop(rx_ring, rx_desc))
> >  			continue;
> >  
> > +		xsk_buff_to_i40e_ctx(first)->desc = rx_desc;
> > +
> 
> [Severity: Critical]
> This is a pre-existing issue, but does this function have a use-after-free
> in its error handling path?
> 
> If xsk_buff_add_frag() fails earlier in the loop, it calls

IIUC, I40E_MAX_CHAINED_RX_BUFFERS (5) limits a packet to one head and at
most four frags. Since xsk_buff_add_frag() fails only when nr_frags ==
MAX_SKB_FRAGS, which is at least 17, this path is unreachable for a
valid i40e RX chain.

However, the UAF scenario looks valid if it does fail, so the
pre-existing error may still be worth fixing.

> xsk_buff_free(first) and breaks out of the loop without advancing
> next_to_clean:
> 
>     if (!first)
>         first = bi;
>     else if (!xsk_buff_add_frag(first, bi)) {
>         xsk_buff_free(first);
>         break;
>     }
> 
> On the subsequent NAPI poll, because next_to_process != next_to_clean,
> the code loads the freed buffer pointer from the stale next_to_clean
> index:
> 
>     if (next_to_process != next_to_clean)
>         first = *i40e_rx_bi(rx_ring, next_to_clean);
> 
> Could this cause the next packet to be built using a freed buffer?
> 
> >  		xdp_res = i40e_run_xdp_zc(rx_ring, first, xdp_prog);
> >  		i40e_handle_xdp_result_zc(rx_ring, first, rx_desc, &rx_packets,
> >  					  &rx_bytes, xdp_res, &failure);
> 
> -- 
> Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=10
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.