Back to the articles

CVE-2023-31070 Broadcom BCM47xx SDK EMF slab-out-of-bounds write - the uncomfortable reality of the IoT Linux kernel space

picture of the author
Attila Szász
May 18, 2023 8 mins read
CVE-2023-31070 Broadcom BCM47xx SDK EMF slab-out-of-bounds write - the uncomfortable reality of the IoT Linux kernel space

Table of contents

  1. Disclosure timeline
  2. Affected products
  3. Product URLs
  4. What is Broadcom BCM47xx SDK? What is the EMF module used for?
  5. Summary
  6. Details
  7. Discovery
  8. Acknowledgments

Disclaimer: The following vulnerability was detected by BugProve's security research team conducting analysis on publicly available products/firmware. Firmware uploaded by users to BugProve's platform have no connection with any of our own research projects. For more information, check out our Vulnerability Disclosure Policy.

Disclosure timeline

Jan 16, 2023: BugProve reports the issue to Broadcom.

Feb 3, 2023: Broadcom acknowledges the issue.

Apr 12, 2023: Broadcom reports that the issue was forwarded to the product group, but there is no update yet.

Apr 13, 2023: Broadcom reports that EMF fix is being implemented. Notes that admin privilege is required to exploit it.

Apr 16, 2023: CVE requested from Broadcom, Broadcom reports that they are not aware of any Broadcom entity planning to obtain CVE numbers.

Apr 16, 2023: CVE requested from MITRE.

Apr 24, 2023: MITRE allocates CVE-2023-31070. BugProve notifies Broadcom of the ID, and it is acknowledged.

May 2, 2023: BugProve is recognized for this report in Broadcom's security acknowledgments.

May 22, 2023: Release of this write-up.

Affected products

Broadcom BCM47xx router SDK

The affected kernel module is used in the reference implementation of various router models. It is likely the case that the following models are vulnerable unless vendor-specific changes disable the feature:

Router vendor Models
TOTOLINK A6004NS
TP-LINK Archer C9 v1.x., Archer C9 v2.x, RE590T, Touch P5, Archer A9 v5.x, Archer C3200, Archer C9 v4.x, Archer C9 v5.x, Archer D9 v1.x, Archer VR900 v1.0, Archer VR900v (v1.0), SR20, Archer C3150, Archer C3150 v2.x, Archer C5400 v1.x, Archer C5400 v2.x
ASUS 4G-AC68U, RT-AC1900, RT-AC3200, RT-AC68P, RT-AC68UF, RT-AC87U, RT-AC1900P, RT-AC5300, RT-AC88U, RT-AC3100
Arris SBR-AC1900P, SBR-AC3200P
Buffalo WXR-1900DHP
D-Link DIR-890L rev A1, DIR-885L rev A1, DIR-895L rev A1
Linksys EA9200
Netgear R6700, R6900v1, R7000, R7100LG, R7300DST, R7900, R8000, R8500,R8300
TRENDnet TEW-828DRU V1.0R
Xiaomi MiWiFi (R1D), MiWiFi (R2D)
Linksys EA9400 v1, EA9500 v1, EA9500 v1.1
Luxul XAP-1610
Phicomm K3, K3N
Ubee RAC2V1U

Product URLs

https://www.broadcom.com/products/wireless/wireless-lan-infrastructure

What is Broadcom BCM47xx SDK? What is the EMF module used for?

The SDK that contains the vulnerability served as the reference implementation that Broadcom shipped with BCM4709 and related SoC's from that family. It is included in at least more than 70+ different router models from the past decade.

The vulnerable kernel driver implements Efficient Multicast Forwarding (EMF) Layer. The module does the efficient layer 2 forwarding of multicast streams, i.e., forward the streams only to the ports that have corresponding group members thereby reducing the bandwidth utilization and latency. It uses the information updated by IGMP Snooping layer to do the optimal forwarding.

One specific use case of IGMP snooping that might be familiar to the retail user is IPTV, where this feature optimizes the traffic on the network and eliminates the redundancy associated with normal multicasting that would end up eating prohibitively large bandwidths.

Summary

There is a slab-out-of-bounds write in emf.ko, a kernel driver used to support IGMP snooping. The issue is affecting Broadcom BCM47xx SDKs and it allows an attacker to elevate privileges by confusing the kernel module's data structures with crafted data, potentially allowing kernel-mode code execution.

Details

We identified the following piece of code in router firmware:

undefined4 emf_iflist_list(int param_1,int *param_2,size_t param_3)
{
  int iVar1;
  char *pcVar2;
  undefined4 *puVar3;
  int iVar4;
  
  if (param_1 == 0) {
    pcVar2 = "Invalid EMF instance handle passed\n";
  }
  else {
    if (param_2 != (int *)0x0) {
      iVar4 = 0;
      for (puVar3 = *(undefined4 **)(param_1 + 0x24); puVar3 != (undefined4 *)0x0;
          puVar3 = (undefined4 *)*puVar3) {
        iVar1 = iVar4 * 4;
        iVar4 = iVar4 + 1;
        strncpy((char *)(param_2 + iVar1 + 1),(char *)puVar3[1],0x10);
      }
      *param_2 = iVar4;
      return 0;
    }
    pcVar2 = "Invalid buffer input\n";
  }
  printk(pcVar2);
  return 0xffffffff;
}

Using the Asuswrt repository, we were able to match it to the corresponding source code (https://github.com/RMerl/asuswrt-merlin/blob/master/release/src/router/emf_arm_794/emf/emf_linux.c):


int32
emf_iflist_list(emf_info_t *emfi, emf_cfg_if_list_t *list, uint32 size)
{
	int32 index = 0;
	emf_iflist_t *ptr;

	if (emfi == NULL)
	{
		EMF_ERROR("Invalid EMF instance handle passed\n");
		return (FAILURE);
	}

	if (list == NULL)
	{
		EMF_ERROR("Invalid buffer input\n");
		return (FAILURE);
	}

	for (ptr = emfi->iflist_head; ptr != NULL; ptr = ptr->next)
	{
		if (strlen(ptr->if_ptr->name) >= 16) {
			EMF_ERROR("if_ptr name %s is longer than 15 chars\n", ptr->if_ptr->name);
			return (FAILURE);
		}
		else
			strncpy(list->if_entry[index++].if_name,
				ptr->if_ptr->name,16);
	}

	/* Update the total number of entries */
	list->num_entries = index;

	return (SUCCESS);
}

The loop in this function traverses a linked list of the interface data associated with the emf info. On the other hand, the index into list->if_entry[] is incremented without checking the bounds of the array. The size parameter is never used to limit the write, resulting in an out-of-bounds access in case the userspace-provided buffer is smaller than the length of the linked list. Adding interfaces to the list is possible using the nfnetlink interface, handled by emf_iflist_add.

The following PoC adds a large number of entries to the linked list and then triggers an emf list, resulting in segfaults, then eventually crashing the kernel space and rebooting the system (tested on ASUS AC87U):

https://github.com/bugprove/cve-2023-31070/blob/master/broadcom_poc.c

Discovery

First, we found various userspace vulnerabilities while scanning publicly available router firmware with our binary analysis engine PRIS™ (as we usually do).

Notably, on a Netgear firmware, PRIS flagged buffer overflows in a userspace utility called emf.

CVE-2023-31070 detected by PRIS
CVE-2023-31070 detected by PRIS

The report can also be seen within our platform, here is a link to a live report.

We quickly understood that this utility is part of Broadcom's reference SDK, and it would make more sense to directly talk to them, instead of the router manufacturers about a fix. Broadcom reported that (01/20/2023):

"strcpy() in emf/emfconf/emfu.c seems as if it may be against some very old version of the code."

We double checked and reported that (01/23/2023):

"The model is R7000 with this firmware version. The vulnerable function we trigger with the PoC is at 0x8b5c in the userspace emf. The returning instruction that pops stack content and triggers attacker-controlled code execution is at 0x8bf4."

We also sent the following gdb log to demonstrate exploitability:

Breakpoint 1, 0x00008b5c in ?? ()
(gdb) ni
0x00008b60 in ?? ()
(gdb) x/5s ($r0+0xc)
0xfffef030:     "v\361\376\377"
0xfffef035:     ""
0xfffef036:     ""
0xfffef037:     ""
0xfffef038:     "\254\365\376\377\310\365\376\377\333\365\376\377\373\365\376\377\024\366\376\377*\366\376\377Q\367\376\377^\367\376\377f\367\376\377\233\367\376\377\321\367\376\377\345\367\376\377\365\367\376\377\005\370\376\377\031\370\376\377'\370\376\377G\370\376\377X\370\376\377j\370\376\377\205\370\376\377\300\370\376\377\005\371\376\377\017\371\376\377&\371\376\377]\371\376\377k\371\376\377y\371\376\377\247\371\376\377\265\371\376\377\302\371\376\377\344\371\376\377\320\377\376\377"
(gdb) x/5x ($r0+0xc)
0xfffef030:     0x76    0xf1    0xfe    0xff    0x00
(gdb) x/5w ($r0+0xc)
0xfffef030:     0xfffef176      0x00000000      0xfffef5ac      0xfffef5c8
0xfffef040:     0xfffef5db
(gdb) x/20s 0xfffef176
0xfffef176:     'A' <repeats 200 times>...
0xfffef23e:     'A' <repeats 200 times>...
0xfffef306:     'A' <repeats 200 times>...
0xfffef3ce:     'A' <repeats 200 times>...
0xfffef496:     'A' <repeats 200 times>...
0xfffef55e:     'A' <repeats 77 times>
0xfffef5ac:     "OLDPWD=/home/ubuntu/netgear"
0xfffef5c8:     "_=/usr/sbin/chroot"
0xfffef5db:     "LESSOPEN=| /usr/bin/lesspipe %s"
0xfffef5fb:     "SDKMAN_PLATFORM=linuxx64"
0xfffef614:     "SDKMAN_VERSION=5.16.0"
0xfffef62a:     "PATH=/home/ubuntu/.sdkman/candidates/java/current/bin:/home/ubuntu/.sdkman/candidates/gradle/current/bin:/home/ubuntu/.nix-profile/bin:/nix/var/nix/profiles/default/bin:/usr/local/sbin:/usr/local/bin:"...
0xfffef6f2:     "/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin"
0xfffef751:     "LOGNAME=root"
0xfffef75e:     "SHLVL=1"
0xfffef766:     "NIX_SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt"
0xfffef79b:     "SDKMAN_CANDIDATES_DIR=/home/ubuntu/.sdkman/candidates"
0xfffef7d1:     "TERM=xterm-256color"
0xfffef7e5:     "SHELL=/bin/bash"
0xfffef7f5:     "NVM_RC_VERSION="
(gdb)
0x000085f8 in ?? ()
(gdb) break *0x8bf0
Breakpoint 2 at 0x8bf0
(gdb) c
Continuing.

Breakpoint 2, 0x00008bf0 in ?? ()
(gdb) ni
0x00008bf4 in ?? ()
(gdb)
0x41414140 in ?? ()
(gdb)

Eventually, Broadcom confirmed that the issue is on the side of the vendor (Netgear), as the Broadcom SDK fixed these buffer overflows years ago.

A natural follow-up of the investigation was to look inside the kernel side counterpart of this utility. The userspace utility just used the netlink interface to command a kernel driver, emf.ko, found in the firmware to carry out various network interface-related operations in the context of IGMP snooping, such as adding and removing bridge interfaces and so on. The vulnerable code discussed above was found by reverse engineering the kernel module and leveraging the static analysis capabilities of PRIS™ to find the vulnerable access with a loop-invariant violation.

Acknowledgments

The vulnerability was found by Attila Szasz at BugProve, using BugProve PRIS™.

Thanks to the Broadcom PSIRT team for the effective coordination process.

Was it worth your time?

Sign up for our newsletter to receive articles like this in your inbox 1-2 times per month.