In the Linux kernel through version 5.17.1, there exists a double-free vulnerability. This security flaw, designated as CVE-2022-28390, affects the ems_usb_start_xmit function in the *drivers/net/can/usb/ems_usb.c* file. It has been reported by security researchers and subsequently patched by the community. In this article, we will explore the source of this vulnerability and delve into how it works, what its implications are, and what has been done to fix it. We'll also provide coding snippets and references to aid in understanding this issue.

What is the double-free vulnerability?

A double-free vulnerability occurs when a program frees memory twice. This could lead to memory corruption and potentially allow an attacker to execute arbitrary code or cause a denial of service (DoS) attack. Double-free vulnerabilities are a critical concern, and they must be addressed promptly.

Understanding ems_usb_start_xmit

Let's take a look at the vulnerable function, *ems_usb_start_xmit*, in the *drivers/net/can/usb/ems_usb.c* file:

static netdev_tx_t ems_usb_start_xmit(struct sk_buff *skb, struct net_device *netdev)
{
    struct ems_usb *dev = netdev_priv(netdev);
    struct ems_usb_tx_urb_context *context;
    int actual_len, ret;

    if (can_dropped_invalid_skb(netdev, skb))
        return NETDEV_TX_OK;

    ret = usb_autopm_get_interface(dev->intf);
    if (ret < ) {
        netif_device_detach(netdev);
        return NETDEV_TX_OK;
    }

    context = kzalloc(sizeof(*context), GFP_ATOMIC);
    if (!context) {
        usb_autopm_put_interface(dev->intf);
        goto drop;
    }

    skb_tx_timestamp(skb);

    ret = ems_usb_encode_buf(dev, skb->data, context->dlc, context->tx_can_msg, &actual_len);
    if (ret < ) {
        kfree(context);
        usb_autopm_put_interface(dev->intf);
        goto drop;
    }

    context->dev = dev;
    context->len = actual_len;
    context->skb = skb;

    usb_fill_bulk_urb(&context->urb, dev->udev, dev->tx_endpoint,
                      context->tx_can_msg, actual_len,
                      ems_usb_write_bulk_callback, skb);

    if (dev->state == EMS_USB_STATE_CONNECTED) {
        usb_anchor_urb(&context->urb, &dev->tx_submitted);
        ret = usb_submit_urb(&context->urb, GFP_ATOMIC);
        if (ret < ) {
            netdev_err(netdev, "failed to submit urb %p\n", &context->urb);
            usb_unanchor_urb(&context->urb);
            kfree(context); // <-- Issue: double-free vulnerability.
            usb_autopm_put_interface(dev->intf);
            goto drop;
        }
    } else {
        usb_autopm_put_interface(dev->intf);
        goto drop;
    }

    netdev->trans_start = jiffies;

    return NETDEV_TX_OK;

drop:
    can_put_echo_skb(skb, netdev, );
    return NETDEV_TX_OK;
}

Source of the Vulnerability

The vulnerability stems from a double-free occurring in the error handling code of the ems_usb_start_xmit function. Upon failure of the usb_submit_urb() call, the code attempts to free context using kfree(context). However, since context is also freed within ems_usb_write_bulk_callback(), this results in a double-free scenario.

Exploiting the Vulnerability

An attacker could potentially exploit this vulnerability by causing the usb_submit_urb() function to fail maliciously, thus triggering the double-free condition. This could lead to memory corruption, which could then be exploited to execute arbitrary code or cause a denial of service.

Fixing the Vulnerability

The Linux kernel developers have patched this vulnerability by removing the problematic kfree(context) call in the error handling code of the *ems_usb_start_xmit* function. You can find more information about the fix in the official patch submitted to the Linux kernel mailing list.

Conclusion

The double-free vulnerability (CVE-2022-28390) in the Linux kernel (up to 5.17.1) posed a potential risk for attackers to exploit memory corruption. By understanding the source of this vulnerability, developers and security professionals can better protect their systems from similar issues in the future. Always ensure that your kernel is updated to the latest version to minimize the risk of vulnerabilities in the Linux kernel.

Timeline

Published on: 04/03/2022 21:15:00 UTC
Last modified on: 07/04/2022 11:15:00 UTC