In the Linux kernel, a known vulnerability (CVE-2024-26933) regarding the USB core - specifically, a deadlock in the port "disable" sysfs attribute - has been resolved. This post will analyze the issue, its exploit details, and the solution implemented.

The Issue

Initially, the show and store callback routines for the "disable" sysfs attribute file in port.c acquired the device lock for the port's parent hub device. This situation created issues when another process had locked the hub to remove it or change its configuration.

The process would involve removing the hub or changing its configuration, which necessitated removing the hub interface. The removal of the port device could only proceed after all the outstanding sysfs attribute callbacks for the ports had returned; however, the lock could not be released until then.

Conversely, the disable_show() and disable_store() routines could not return until the lock was acquired. This deadlock caused significant difficulties in the synchronization of processes.

Exploit Details

An attacker who successfully exploited this vulnerability would create a deadlock situation, hindering the functioning of the USB port and potentially causing a system to freeze or hang. The result could have severe security implications, which might lead to data loss, system instability, and overall user dissatisfaction.

The Solution

The implemented resolution involves using the sysfs_break_active_protection() function, which allows the sysfs core to avoid waiting for the attribute's callback routine to return. This change enables the removal process to continue. However, there is a disadvantage: after making this call, there is no guarantee that the hub structure will not be deallocated at any moment.

To counter this issue, a reference to the hub structure is acquired with the hub_get() function call, thus ensuring the structure's stability and preventing deallocation.

Here is a code snippet for the resolution

/* Function: disable_show
 * Example of the solution applied to disable_show().
 */
static ssize_t disable_show(struct device *dev,
			    struct device_attribute *attr, char *buf)
{
	struct usb_port *port_dev = to_usb_port(dev);
	struct usb_hub *hub;
	int retval;

	/* Acquire hub structure reference */
	hub = hub_get(port_dev->parent);
	if (!hub)
		return -ENODEV;

	/* Avoid deadlock by calling sysfs_break_active_protection() */
	sysfs_break_active_protection(&attr->attr);
	down_read(&port_dev->status_rwsem);
	/* Perform whatever the function needs to do */
	retval = snprintf(buf, PAGE_SIZE, "%u\n", port_dev->disable);
	up_read(&port_dev->status_rwsem);

	/* Release hub reference */
	hub_put(hub);

	return retval;
}

For the detailed implementation and further information, you can find the original patch and references here:

- Linux Kernel Mailing List - Patch
- Linux Kernel Source Code - port.c

This solution effectively eliminates the deadlock in the port "disable" sysfs attribute, making the USB core functionality secure and stable. Users are encouraged to update their kernel versions and apply the patch to protect their systems from potential exploits targeting this vulnerability.

Timeline

Published on: 05/01/2024 06:15:07 UTC
Last modified on: 07/19/2024 08:41:12 UTC