9.11. Advisory TFV-11 (CVE-2023-49100)

Title

A Malformed SDEI SMC can cause out of bound memory read.

CVE ID

CVE-2023-49100

Date

Reported on 12 Oct 2023

Versions Affected

TF-A releases v1.5 to v2.9 LTS releases lts-v2.8.0 to lts-v2.8.11

Configurations Affected

Platforms with SDEI support

Impact

Denial of Service (secure world panic)

Fix Version

a7eff3477 “fix(sdei): ensure that interrupt ID is valid”

Credit

Christian Lindenmeier @_chli_ Marcel Busch @0ddc0de IT Security Infrastructures Lab

This security advisory describes a vulnerability in the SDEI services, where a rogue Non-secure caller invoking a SDEI_INTERRUPT_BIND SMC call with an invalid interrupt ID causes out of bound memory read.

SDEI_INTERRUPT_BIND is used to bind any physical interrupt into a normal priority SDEI event. The interrupt can be a private peripheral interrupt (PPI) or a shared peripheral interrupt (SPI). Refer to SDEI_INTERRUPT_BIND in the SDEI Specification for further details.

The vulnerability exists when the SDEI client passes an interrupt ID which is not implemented by the GIC. This will result in a data abort exception or a EL3 panic depending on the GIC version used in the system.

  • GICv2 systems:

Call stack:
      sdei_interrupt_bind(interrupt ID)
       -> plat_ic_get_interrupt_type(interrupt ID)
         -> gicv2_get_interrupt_group(interrupt ID)
           -> gicd_get_igroupr(distributor base, interrupt ID)
             -> gicd_read_igroupr(distributor base, interrupt ID).

gicd_read_igroupr() will eventually do a MMIO read to an unimplemented IGROUPR
register. Which may cause a data abort or an access to a random EL3 memory region.
  • GICv3 systems:

Call stack:
     sdei_interrupt_bind(interrupt ID)
       -> plat_ic_get_interrupt_type(interrupt ID)
         -> gicv3_get_interrupt_group(interrupt ID, core ID)
           -> is_sgi_ppi(interrupt ID)

is_sgi_ppi() will end up in an EL3 panic on encountering an invalid interrupt ID.

The vulnerability is fixed by ensuring that the Interrupt ID provided by the SDEI client is a valid PPI or SPI, otherwise return an error code indicating that the parameter is invalid.

/* Bind an SDEI event to an interrupt */
static int sdei_interrupt_bind(unsigned int intr_num)
{
     sdei_ev_map_t *map;
     bool retry = true, shared_mapping;

     /* Interrupt must be either PPI or SPI */
     if (!(plat_ic_is_ppi(intr_num) || plat_ic_is_spi(intr_num)))
           return SDEI_EINVAL;