CVE-2024-49993 Information

Description

In the Linux kernel the following vulnerability has been resolved:

iommu/vt-d: Fix potential lockup if qi_submit_sync called with 0 count

If qi_submit_sync() is invoked with 0 invalidation descriptors (for instance for DMA draining purposes) we can run into a bug where a submitting thread fails to detect the completion of invalidation_wait. Subsequently this led to a soft lockup. Currently there is no impact by this bug on the existing users because no callers are submitting invalidations with 0 descriptors. This fix will enable future users (such as DMA drain) calling qi_submit_sync() with 0 count.

Suppose thread T1 invokes qi_submit_sync() with non-zero descriptors while concurrently thread T2 calls qi_submit_sync() with zero descriptors. Both threads then enter a while loop waiting for their respective descriptors to complete. T1 detects its completion (i.e. T1’s invalidation_wait status changes to QI_DONE by HW) and proceeds to call reclaim_free_desc() to reclaim all descriptors potentially including adjacent ones of other threads that are also marked as QI_DONE.

During this time while T2 is waiting to acquire the qi->q_lock the IOMMU hardware may complete the invalidation for T2 setting its status to QI_DONE. However if T1’s execution of reclaim_free_desc() frees T2’s invalidation_wait descriptor and changes its status to QI_FREE T2 will not observe the QI_DONE status for its invalidation_wait and will indefinitely remain stuck.

This soft lockup does not occur when only non-zero descriptors are submitted.In such cases invalidation descriptors are interspersed among wait descriptors with the status QI_IN_USE acting as barriers. These barriers prevent the reclaim code from mistakenly freeing descriptors belonging to other submitters.

Considered the following example timeline: T1 T2

ID1
WD1
while(WD1!=QI_DONE)
unlock
			lock
WD1=QI_DONE		WD2
			while(WD2!=QI_DONE)
			unlock
lock
WD1==QI_DONE?
ID1=QI_DONE		WD2=DONE
reclaim()
ID1=FREE
WD1=FREE
WD2=FREE
unlock
			soft lockup! T2 never sees QI_DONE in WD2

Where: ID = invalidation descriptor WD = wait descriptor Written by hardware

The root of the problem is that the descriptor status QI_DONE flag is used for two conflicting purposes:

  1. signal a descriptor is ready for reclaim (to be freed)
  2. signal by the hardware that a wait descriptor is complete

The solution (in this patch) is state separation by using QI_FREE flag for 1.

Once a thread’s invalidation descriptors are complete their status would be set to QI_FREE. The reclaim_free_desc() function would then only free descriptors marked as QI_FREE instead of those marked as QI_DONE. This change ensures that T2 (from the previous example) will correctly observe the completion of its invalidation_wait (marked as QI_DONE).

CVSS Vector

CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H

Reference

https://git.kernel.org/stable/c/de9e7f68762585f7532de8a06de9485bf39dbd38 https://git.kernel.org/stable/c/8840dc73ac9e1028291458ef1429ec3c2524ffec https://git.kernel.org/stable/c/e03f00aa4a6c0c49c17857a4048f586636abdc32 https://git.kernel.org/stable/c/dfdbc5ba10fb792c9d6d12ba8cb6e465f97365ed https://git.kernel.org/stable/c/07e4e92f84b7d3018b7064ef8d8438aeb54a2ca5 https://git.kernel.org/stable/c/92ba5b014d5435dd7a1ee02a2c7f2a0e8fe06c36 https://git.kernel.org/stable/c/3cf74230c139f208b7fb313ae0054386eee31a81

Attack Complexity

LOW

Privileges Required

LOW

User Interaction Required

LOW

Scope

NONE

Confidentiality Impact

UNCHANGED

Integrity Impact

NONE

Availability Impact

NONE

Base Score

HIGH

Base Severity

5.5

Share on: