// For flags

CVE-2024-26837

net: bridge: switchdev: Skip MDB replays of deferred events on offload

Severity Score

5.5
*CVSS v3.1

Exploit Likelihood

*EPSS

Affected Versions

*CPE

Public Exploits

0
*Multiple Sources

Exploited in Wild

-
*KEV

Decision

Track
*SSVC
Descriptions

In the Linux kernel, the following vulnerability has been resolved:

net: bridge: switchdev: Skip MDB replays of deferred events on offload

Before this change, generation of the list of MDB events to replay
would race against the creation of new group memberships, either from
the IGMP/MLD snooping logic or from user configuration.

While new memberships are immediately visible to walkers of
br->mdb_list, the notification of their existence to switchdev event
subscribers is deferred until a later point in time. So if a replay
list was generated during a time that overlapped with such a window,
it would also contain a replay of the not-yet-delivered event.

The driver would thus receive two copies of what the bridge internally
considered to be one single event. On destruction of the bridge, only
a single membership deletion event was therefore sent. As a
consequence of this, drivers which reference count memberships (at
least DSA), would be left with orphan groups in their hardware
database when the bridge was destroyed.

This is only an issue when replaying additions. While deletion events
may still be pending on the deferred queue, they will already have
been removed from br->mdb_list, so no duplicates can be generated in
that scenario.

To a user this meant that old group memberships, from a bridge in
which a port was previously attached, could be reanimated (in
hardware) when the port joined a new bridge, without the new bridge's
knowledge.

For example, on an mv88e6xxx system, create a snooping bridge and
immediately add a port to it:

root@infix-06-0b-00:~$ ip link add dev br0 up type bridge mcast_snooping 1 && \n > ip link set dev x3 up master br0

And then destroy the bridge:

root@infix-06-0b-00:~$ ip link del dev br0
root@infix-06-0b-00:~$ mvls atu
ADDRESS FID STATE Q F 0 1 2 3 4 5 6 7 8 9 a
DEV:0 Marvell 88E6393X
33:33:00:00:00:6a 1 static - - 0 . . . . . . . . . .
33:33:ff:87:e4:3f 1 static - - 0 . . . . . . . . . .
ff:ff:ff:ff:ff:ff 1 static - - 0 1 2 3 4 5 6 7 8 9 a
root@infix-06-0b-00:~$

The two IPv6 groups remain in the hardware database because the
port (x3) is notified of the host's membership twice: once via the
original event and once via a replay. Since only a single delete
notification is sent, the count remains at 1 when the bridge is
destroyed.

Then add the same port (or another port belonging to the same hardware
domain) to a new bridge, this time with snooping disabled:

root@infix-06-0b-00:~$ ip link add dev br1 up type bridge mcast_snooping 0 && \n > ip link set dev x3 up master br1

All multicast, including the two IPv6 groups from br0, should now be
flooded, according to the policy of br1. But instead the old
memberships are still active in the hardware database, causing the
switch to only forward traffic to those groups towards the CPU (port
0).

Eliminate the race in two steps:

1. Grab the write-side lock of the MDB while generating the replay
list.

This prevents new memberships from showing up while we are generating
the replay list. But it leaves the scenario in which a deferred event
was already generated, but not delivered, before we grabbed the
lock. Therefore:

2. Make sure that no deferred version of a replay event is already
enqueued to the switchdev deferred queue, before adding it to the
replay list, when replaying additions.

En el kernel de Linux, se ha resuelto la siguiente vulnerabilidad: net: bridge: switchdev: omitir repeticiones MDB de eventos diferidos durante la descarga. Antes de este cambio, la generación de la lista de eventos MDB para reproducir competiría con la creación de nuevas membresías de grupos, ya sea desde la lógica de espionaje IGMP/MLD o desde la configuración del usuario. Si bien las nuevas membresías son visibles inmediatamente para los caminantes de br->mdb_list, la notificación de su existencia a los suscriptores del evento switchdev se difiere hasta un momento posterior. Entonces, si se generó una lista de reproducción durante un tiempo que se superpuso con dicha ventana, también contendría una repetición del evento aún no entregado. El conductor recibiría así dos copias de lo que internamente el puente consideraba un único evento. Por lo tanto, tras la destrucción del puente, solo se envió un evento de eliminación de membresía. Como consecuencia de esto, los controladores que hacen referencia al recuento de membresías (al menos DSA) quedarían con grupos huérfanos en su base de datos de hardware cuando se destruyera el puente. Esto sólo es un problema al reproducir adiciones. Si bien es posible que los eventos de eliminación aún estén pendientes en la cola diferida, ya se habrán eliminado de br->mdb_list, por lo que no se pueden generar duplicados en ese escenario. Para un usuario, esto significaba que las antiguas membresías de grupos, de un puente al que previamente se había conectado un puerto, podían reanimarse (en hardware) cuando el puerto se unía a un nuevo puente, sin el conocimiento del nuevo puente. Por ejemplo, en un sistema mv88e6xxx, cree un puente de vigilancia e inmediatamente agréguele un puerto: root@infix-06-0b-00:~$ ip link add dev br0 up type bridge mcast_snooping 1 && \ > ip link set dev x3 up master br0 Y luego destruye el puente: root@infix-06-0b-00:~$ ip link del dev br0 root@infix-06-0b-00:~$ mvls atu DIRECCIÓN FID ESTADO QF 0 1 2 3 4 5 6 7 8 9 a DEV:0 Marvell 88E6393X 33:33:00:00:00:6a 1 estático - - 0 . . . . . . . . . . 33:33:ff:87:e4:3f 1 estático - - 0 . . . . . . . . . . ff:ff:ff:ff:ff:ff 1 static - - 0 1 2 3 4 5 6 7 8 9 a root@infix-06-0b-00:~$ Los dos grupos IPv6 permanecen en la base de datos de hardware porque el puerto (x3) recibe dos notificaciones sobre la membresía del anfitrión: una vez a través del evento original y otra a través de una repetición. Dado que solo se envía una notificación de eliminación, el recuento permanece en 1 cuando se destruye el puente. Luego agregue el mismo puerto (u otro puerto que pertenezca al mismo dominio de hardware) a un nuevo puente, esta vez con el snooping deshabilitado: root@infix-06-0b-00:~$ ip link add dev br1 up type bridge mcast_snooping 0 && \ > ip link set dev x3 up master br1 Toda la multidifusión, incluidos los dos grupos IPv6 de br0, ahora debería estar inundada, de acuerdo con la política de br1. Pero, en cambio, las membresías antiguas todavía están activas en la base de datos del hardware, lo que hace que el conmutador solo reenvíe el tráfico a esos grupos hacia la CPU (puerto 0). Elimine la carrera en dos pasos: 1. Tome el bloqueo del lado de escritura del MDB mientras genera la lista de reproducción. Esto evita que aparezcan nuevas membresías mientras generamos la lista de reproducción. Pero deja el escenario en el que ya se generó un evento diferido, pero no se entregó, antes de que tomáramos el bloqueo. Por lo tanto: 2. Asegúrese de que ninguna versión diferida de un evento de reproducción ya esté en cola en la cola diferida de switchdev, antes de agregarla a la lista de reproducción, al reproducir adiciones.

A flaw was found in the Linux kernel. A race condition in network bridge management could lead to a denial of service.

*Credits: N/A
CVSS Scores
Attack Vector
Local
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Unchanged
Confidentiality
None
Integrity
None
Availability
High
* Common Vulnerability Scoring System
SSVC
  • Decision:Track
Exploitation
None
Automatable
No
Tech. Impact
Partial
* Organization's Worst-case Scenario
Timeline
  • 2024-02-19 CVE Reserved
  • 2024-04-17 CVE Published
  • 2024-04-18 EPSS Updated
  • 2024-08-02 CVE Updated
  • ---------- Exploited in Wild
  • ---------- KEV Due Date
  • ---------- First Exploit
CWE
  • CWE-362: Concurrent Execution using Shared Resource with Improper Synchronization ('Race Condition')
CAPEC
Affected Vendors, Products, and Versions
Vendor Product Version Other Status
Vendor Product Version Other Status <-- --> Vendor Product Version Other Status
Linux
Search vendor "Linux"
Linux Kernel
Search vendor "Linux" for product "Linux Kernel"
>= 5.13 < 6.1.80
Search vendor "Linux" for product "Linux Kernel" and version " >= 5.13 < 6.1.80"
en
Affected
Linux
Search vendor "Linux"
Linux Kernel
Search vendor "Linux" for product "Linux Kernel"
>= 5.13 < 6.6.19
Search vendor "Linux" for product "Linux Kernel" and version " >= 5.13 < 6.6.19"
en
Affected
Linux
Search vendor "Linux"
Linux Kernel
Search vendor "Linux" for product "Linux Kernel"
>= 5.13 < 6.7.7
Search vendor "Linux" for product "Linux Kernel" and version " >= 5.13 < 6.7.7"
en
Affected
Linux
Search vendor "Linux"
Linux Kernel
Search vendor "Linux" for product "Linux Kernel"
>= 5.13 < 6.8
Search vendor "Linux" for product "Linux Kernel" and version " >= 5.13 < 6.8"
en
Affected