Skip to content

[BUG] Stack Overflow When Malformed CAN Data Is Received #19138

@catalinv-ncc

Description

@catalinv-ncc

Description / Steps to reproduce the issue

Impact

A malformed packet can trigger memory corruption in the kernel leading to a system crash or potentially arbitrary code execution in the kernel.

Description

The CAN driver for the CTU CAN FD IP Core connected to the NuttX device via a PCI / PCI Express (PCIe) bus shows a lack of consideration for malformed data, assuming the CAN frames are always correct.

begin_packed_struct struct ctucanfd_frame_fmt_s
{
  uint32_t dlc:4;               /* DLC */
...
  uint32_t rwcnt:5;             /* Size without FRAME_FORMAT WORD */
...
  uint32_t _reserved:4;         /* Reserved */
} end_packed_struct;

begin_packed_struct struct ctucanfd_frame_s
{
  struct ctucanfd_frame_fmt_s fmt;       /* Frame format */
...
} end_packed_struct;

The size of struct ctucanfd_frame_s is 84 bytes, therefore, in the following code snippet, the buff array used by the ctucanfd_chardev_receive() has 21 uint32_t elements.
The code uses ctucanfd_getreg() to read the first four bytes from the CAN bus line into the ctucanfd_frame_s structure (populates fmt structure member). Immediately after, it uses the data read in frame->fmt.rwcnt without validation in the for loop. The attacker controls the content, and rwcnt structure member is 5 bits long therefore it can store a maximum value of 25 - 1 = 31. Since the length of the buff array is 21 elements and attackers can write 10 uint32_t additional elements, they can cause a 40-byte overflow of buff array. Note that the attacker can also control the content retrieved in the overflowing bytes.

/*****************************************************************************
 * Name: ctucanfd_chardev_receive
 * Description: Receive CAN frame
 *****************************************************************************/
static void ctucanfd_chardev_receive(FAR struct ctucanfd_can_s *priv)
{
  FAR struct can_dev_s        *dev    = (FAR struct can_dev_s *)priv;
  FAR struct ctucanfd_frame_s *frame;
  struct can_hdr_s             hdr;
  uint32_t                     buff[sizeof(struct ctucanfd_frame_s) / 4];
...
  uint32_t                     regval = 0;
  memset(&hdr, 0, sizeof(hdr));
....
      /* We use a pointer to buffer to avoid an unaligned pointer compiler errors */
      frame = (struct ctucanfd_frame_s *)&buff;

      /* RX buffer in automatic mode */  // NCC Group read the 4-byte "fmt" element
      buff[0] = ctucanfd_getreg(priv, CTUCANFD_RXDATA);

      /* Read the rest of data */
      for (i = 0; i < frame->fmt.rwcnt; i++) // NCC Group: uses the size without checking
        {
          buff[i + 1] = ctucanfd_getreg(priv, CTUCANFD_RXDATA); // NCC Group buffer overflow
        }

There is a similar issue in ctucanfd_sock_recv(), it is not presented here due to brevity.

Recommendation

Ensure frame->fmt.rwcnt is 21 or less before it is used in the for loop.

On which OS does this issue occur?

[OS: Linux]

What is the version of your OS?

Ubuntu 24.04

NuttX Version

master

Issue Architecture

[Arch: all]

Issue Area

[Area: Debugging], [Area: Drivers]

Host information

N/A

Verification

  • I have verified before submitting the report.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Arch: allIssues that apply to all architecturesArea: DebuggingDebugging issuesArea: DriversDrivers issuesOS: LinuxIssues related to Linux (building system, etc)Type: BugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions