Skip to content

The RNDIS USB device class includes a buffer overflow vulnerability

High
ceolin published GHSA-hvfp-w4h8-gxvj Feb 7, 2022

Package

zephyr (west)

Affected versions

v2.6.0

Patched versions

None

Description

Impact

The RNDIS USB device class includes a buffer overflow vulnerability.

When a "write to device" control transfer with command (bRequest)
CDC_SEND_ENC_CMD is handled by rndis_class_handler as defined in
function_rndis.c, in the queue_encapsulated_cmd function a RNDIS command pool
buffer is overwritten by user provided data violating buffer boundaries. The
control transfer request might be CONFIG_USB_REQUEST_BUFFER_SIZE (i.e. 2048)
bytes long, possibly significantly longer than the 512-byte RNDIS command
buffer.

This will result in a buffer overflow, allowing one to write data provided in
the control transfer request past buffer boundaries. Depending on actual memory
layout this might result in corruption of critical data structures or execution
of arbitrary code.

    static int rndis_class_handler(struct usb_setup_packet *setup, int32_ *len, uint8_t **data)
    {
        LOG_DBG("len %d req_type 0x%x req 0x%x enabled %u",
        *len, setup->bmRequestType, setup->bRequest,
        netusb_enabled());

        if (!netusb_enabled()) {
        LOG_ERR("interface disabled");
        return -ENODEV;
        }

        if (setup->bRequest == CDC_SEND_ENC_CMD &&
            REQTYPE_GET_DIR(setup->bmRequestType) == REQTYPE_DIR_TO_DEVICE) {
        /*
         * Instead of handling here, queue
         * handle_encapsulated_cmd(*data, *len);
         */
        queue_encapsulated_cmd(*data, *len);      // SH:
    CONFIG_USB_REQUEST_BUFFER_SIZE bytes provided in control transfer request
    are passed to function



    static int queue_encapsulated_cmd(uint8_t *data, uint32_t len)
    {
        struct net_buf *buf;

        buf = net_buf_alloc(&rndis_cmd_pool, K_NO_WAIT);
        if (!buf) {
            LOG_ERR("Cannot get free buffer");
            return -ENOMEM;
        }

        memcpy(net_buf_add(buf, len), data, len);  // SH: provided contents overwrite RNDIS CMD buffer violating boundaries
        net_buf_put(&rndis_cmd_queue, buf);

        LOG_DBG("queued buf %p", buf);

        return 0;
    }


    static inline void *net_buf_add(struct net_buf *buf, size_t len)
    {
        return net_buf_simple_add(&buf->b, len);
    }


    void *net_buf_simple_add(struct net_buf_simple *buf, size_t len)
    {
        uint8_t *tail = net_buf_simple_tail(buf);

        NET_BUF_SIMPLE_DBG("buf %p len %zu", buf, len);

        __ASSERT_NO_MSG(net_buf_simple_tailroom(buf) >= len);

        buf->len += len;  // SH: only buffer length incremented
        return tail;           // SH: no indication that the buffer is not
    large enough
    }

Patches

For more information

If you have any questions or comments about this advisory:

embargo: 2022-01-05

Severity

High
8.2
/ 10

CVSS base metrics

Attack vector
Adjacent
Attack complexity
High
Privileges required
None
User interaction
None
Scope
Changed
Confidentiality
Low
Integrity
High
Availability
High
CVSS:3.1/AV:A/AC:H/PR:N/UI:N/S:C/C:L/I:H/A:H

CVE ID

CVE-2021-3861

Weaknesses

Credits