Instituto Nacional de ciberseguridad. Sección Incibe
Instituto Nacional de Ciberseguridad. Sección INCIBE-CERT

CVE-2022-50483

Gravedad CVSS v3.1:
MEDIA
Tipo:
No Disponible / Otro tipo
Fecha de publicación:
04/10/2025
Última modificación:
23/01/2026

Descripción

*** Pendiente de traducción *** In the Linux kernel, the following vulnerability has been resolved:<br /> <br /> net: enetc: avoid buffer leaks on xdp_do_redirect() failure<br /> <br /> Before enetc_clean_rx_ring_xdp() calls xdp_do_redirect(), each software<br /> BD in the RX ring between index orig_i and i can have one of 2 refcount<br /> values on its page.<br /> <br /> We are the owner of the current buffer that is being processed, so the<br /> refcount will be at least 1.<br /> <br /> If the current owner of the buffer at the diametrically opposed index<br /> in the RX ring (i.o.w, the other half of this page) has not yet called<br /> kfree(), this page&amp;#39;s refcount could even be 2.<br /> <br /> enetc_page_reusable() in enetc_flip_rx_buff() tests for the page<br /> refcount against 1, and [ if it&amp;#39;s 2 ] does not attempt to reuse it.<br /> <br /> But if enetc_flip_rx_buff() is put after the xdp_do_redirect() call,<br /> the page refcount can have one of 3 values. It can also be 0, if there<br /> is no owner of the other page half, and xdp_do_redirect() for this<br /> buffer ran so far that it triggered a flush of the devmap/cpumap bulk<br /> queue, and the consumers of those bulk queues also freed the buffer,<br /> all by the time xdp_do_redirect() returns the execution back to enetc.<br /> <br /> This is the reason why enetc_flip_rx_buff() is called before<br /> xdp_do_redirect(), but there is a big flaw with that reasoning:<br /> enetc_flip_rx_buff() will set rx_swbd-&gt;page = NULL on both sides of the<br /> enetc_page_reusable() branch, and if xdp_do_redirect() returns an error,<br /> we call enetc_xdp_free(), which does not deal gracefully with that.<br /> <br /> In fact, what happens is quite special. The page refcounts start as 1.<br /> enetc_flip_rx_buff() figures they&amp;#39;re reusable, transfers these<br /> rx_swbd-&gt;page pointers to a different rx_swbd in enetc_reuse_page(), and<br /> bumps the refcount to 2. When xdp_do_redirect() later returns an error,<br /> we call the no-op enetc_xdp_free(), but we still haven&amp;#39;t lost the<br /> reference to that page. A copy of it is still at rx_ring-&gt;next_to_alloc,<br /> but that has refcount 2 (and there are no concurrent owners of it in<br /> flight, to drop the refcount). What really kills the system is when<br /> we&amp;#39;ll flip the rx_swbd-&gt;page the second time around. With an updated<br /> refcount of 2, the page will not be reusable and we&amp;#39;ll really leak it.<br /> Then enetc_new_page() will have to allocate more pages, which will then<br /> eventually leak again on further errors from xdp_do_redirect().<br /> <br /> The problem, summarized, is that we zeroize rx_swbd-&gt;page before we&amp;#39;re<br /> completely done with it, and this makes it impossible for the error path<br /> to do something with it.<br /> <br /> Since the packet is potentially multi-buffer and therefore the<br /> rx_swbd-&gt;page is potentially an array, manual passing of the old<br /> pointers between enetc_flip_rx_buff() and enetc_xdp_free() is a bit<br /> difficult.<br /> <br /> For the sake of going with a simple solution, we accept the possibility<br /> of racing with xdp_do_redirect(), and we move the flip procedure to<br /> execute only on the redirect success path. By racing, I mean that the<br /> page may be deemed as not reusable by enetc (having a refcount of 0),<br /> but there will be no leak in that case, either.<br /> <br /> Once we accept that, we have something better to do with buffers on<br /> XDP_REDIRECT failure. Since we haven&amp;#39;t performed half-page flipping yet,<br /> we won&amp;#39;t, either (and this way, we can avoid enetc_xdp_free()<br /> completely, which gives the entire page to the slab allocator).<br /> Instead, we&amp;#39;ll call enetc_xdp_drop(), which will recycle this half of<br /> the buffer back to the RX ring.

Productos y versiones vulnerables

CPE Desde Hasta
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* 5.13 (incluyendo) 5.15.86 (excluyendo)
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* 5.16 (incluyendo) 6.0.16 (excluyendo)
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* 6.1 (incluyendo) 6.1.2 (excluyendo)