News Tech: The Synopsys Cybersecurity Research Center’s (CyRC) main objective is to assess the potential for exploiting vulnerabilities. Publicly accessible advisories frequently use boilerplate scores to categorise vulnerabilities and characterise the implications of vulnerabilities in generic terms. On current systems, however, exploit mitigation features like Address Space Layout Randomization and Pointer Authentication make it difficult to take advantage of memory corruption issues. The afflicted application will typically crash as a result of the proof-of-concept “exploits” listed in the warnings for memory corruption vulnerabilities, illustrating an availability effect. More severe proof-of-concept vulnerabilities, such those that demonstrate arbitrary code execution, are less common.
Advanced threat actors are a reality of the modern world, a reality that many of our customers are all too familiar with. Numerous software flaws, particularly those involving memory corruption, might be cleverly exploited to completely subvert the intended application. To the untrained eye, figuring out how easily a given vulnerability might be exploited is a mysterious skill. Throughout our work, we frequently uncover vulnerabilities whose purported implications are called into question by our team’s expertise and experience.
On November 5, 2020, a notice describing a vulnerability in the Sun Microsystems keyboard driver for the Linux kernel (found in drivers/input/keyboard/sunkbd.c) was posted on the oss-security mailing list. This advisory outlines a use-after-free event that can happen in the sunkbd reinit() function and gives a proof-of-concept exploit for it. The use-after-free event is reliably triggered by the proof-of-concept exploit, but it does not show any other effects outside a potential denial of service.
As you can see, the sunkbd->tq member is of type struct work_struct. This structure is used to perform deferred work within the kernel. “Deferred work” refers to code that will be executed at some point in the future. A range of mechanisms are available within the kernel for performing deferred work. These deferred work mechanisms are required by various components of the kernel, with one particularly important component being interrupt handlers. Deferred work is vital to the implementation of interrupt handlers due to the constraints that these handlers are subjected to. One such constraint is that interrupt handlers cannot execute code that might sleep, because interrupt handlers execute in interrupt context instead of process context. If an interrupt handler needs to execute code that might sleep, a workqueue can be used. These are deferred work mechanisms that will cause the deferred code to be executed in process context. The function to be executed in process context can be associated with a work_struct instance whenever it is initialized. In this case, that task is performed in sunkbd_connect():
This will add the work to the global workqueue, and sunkbd_reinit() will eventually be executed via a kernel worker thread.
It is within the sunkbd_reinit() function that the use-after-free event will occur. Whenever the function is invoked, it is passed a pointer to the struct work_struct instance that was used to schedule it. The first action performed by sunkbd_reinit() is to obtain a pointer to the struct sunkbd instance that contains this struct work_struct instance: The function will then call wait_event_interruptible_timeout():
This will put the worker thread to sleep if the condition sunkbd->reset >= 0 || !sunkbd->enabled is true. The third argument specifies how long the worker thread will sleep. In this case, a hardcoded sleep duration of one second has been specified. The sunkbd_reinit() function will reawaken after one second and will continue executing the code that follows the call to wait_event_interruptible_timeout(). The first line of this code is an invocation of serio_write(). We will examine serio_write() momentarily; let us first examine how the use-after-free event can occur. Recall that the first action performed by sunkbd_reinit() is to obtain a pointer to a struct sunkbd instance, which will be stored in the sunkbd variable. We have seen that this instance resides within heap memory. If that memory is freed whenever sunkbd_reinit() is sleeping, a use-after-free event will occur whenever sunkbd_reinit() awakens and attempts to dereference the pointer stored in sunkbd. The memory that sunkbd points to can be freed via the sunkbd_disconnect() function. This function is used to deregister a given keyboard device. This involves releasing the resources allocated for that device. The definition of this function is as follows:
So how can this vulnerability be leveraged to achieve arbitrary code execution? Let us return to the line of code that is executed once sunkbd_reinit() awakens: This function call involves dereferencing sunkbd in order to retrieve the value of sunkbd->serio. If sunkbd references freed memory, a fault will occur. Under normal circumstances, however, sunkbd->serio denotes a valid pointer to a struct serio instance. If we examine the definition of this structure, we will see that it contains numerous functions pointers:
As you can see, the final action performed by this function is to free the sunkbd object. If sunkbd_disconnect() is invoked whenever sunkbd_reinit() is sleeping, and it deregisters the device that the sunkbd variable refers to, a user-after-free event will occur whenever sunkbd_reinit() awakens. This is precisely how the publicly available proof-of-concept exploit operates. The hardcoded sleep period of one second that is specified within sunkbd_reinit() provides a large and dependable race window. This makes the proof-of-concept reliable.
Check the latest news about tech news section for best information.