Denial of Service (Infinite loop in kernel space via crafted multisync extension)
Description
The patch guards against a Denial of Service where a crafted, self-referential multisync extension could cause an infinite loop inside the V3D DRM driver. Previously, v3d_get_extensions() walked a user-supplied singly-linked list of ioctl extensions without a bound on the chain length. A user could construct an extension where ext->next == &ext and both in_sync_count and out_sync_count were zero. Because v3d_get_multisync_post_deps() returns immediately when the counts are zero, the loop could leave the extension state unchanged and repeat indefinitely, pegging a CPU core and blocking the calling thread. The fix adds a guard in v3d_get_multisync_submit_deps() to reject an empty multisync extension (both in_sync_count and out_sync_count zero) by returning -EINVAL, preventing the infinite loop. This is a defense-in-depth against a crafted user-space input leading to kernel DoS.
Proof of Concept
POC steps:
1) Open a V3D DRM device (e.g., /dev/dri/card0).
2) Allocate a multisync extension with a self-referential next pointer:
struct v3d_ext {
struct v3d_ext *next;
uint32_t in_sync_count;
uint32_t out_sync_count;
// ... additional fields as defined by the driver headers
} *ext = malloc(sizeof(struct v3d_ext));
ext->next = ext; // self-referential to form a cycle
ext->in_sync_count = 0;
ext->out_sync_count = 0;
3) Submit a multisync object containing this single extension via the V3D multisync/submit IOCTL (exact IOCTL and data layout depend on your kernel headers).
4) Observe behavior: prior to the patch, the kernel could spin indefinitely in the multisync walk due to the zero counts and self-referential extension; after the patch, the ioctl should fail with -EINVAL and the extension should be rejected (see log message like "Empty multisync extension").
Notes:
- The exact IOCTL name and structures vary by kernel headers for the V3D DRM driver. The PoC focuses on the vulnerability pattern (self-referential extension with zero sync counts) rather than a specific IOCTL signature.
- In a real test environment, ensure the test is performed on a non-production kernel with appropriate permissions and in a controlled lab.
Commit Details
Author: Ashutosh Desai
Date: 2026-04-15 05:00 UTC
Message:
drm/v3d: Reject empty multisync extension to prevent infinite loop
v3d_get_extensions() walks a userspace-provided singly-linked list of
ioctl extensions without any bound on the chain length. A local user
can craft a self-referential extension (ext->next == &ext) with zero
in_sync_count and out_sync_count, which bypasses the existing duplicate-
extension guard:
if (se->in_sync_count || se->out_sync_count)
return -EINVAL;
The guard never fires because v3d_get_multisync_post_deps() returns
immediately when count is zero, leaving both fields at zero on every
iteration. The result is an infinite loop in kernel context, blocking
the calling thread and pegging a CPU core indefinitely.
Fix this by rejecting a multisync extension where both in_sync_count
and out_sync_count are zero in v3d_get_multisync_submit_deps(). An
empty multisync carries no synchronization information and serves no
useful purpose, so returning -EINVAL for such an extension is the
correct defense against this attack vector.
Fixes: e4165ae8304e ("drm/v3d: add multiple syncobjs support")
Cc: stable@vger.kernel.org
Signed-off-by: Ashutosh Desai <ashutoshdesai993@gmail.com>
Link: https://patch.msgid.link/20260415050000.3816128-1-ashutoshdesai993@gmail.com
Signed-off-by: MaĆra Canal <mcanal@igalia.com>
Triage Assessment
Vulnerability Type: Denial of Service (Infinite loop)
Confidence: HIGH
Reasoning:
The patch adds a guard to reject an empty multisync extension (both in_sync_count and out_sync_count zero), which previously could lead to a crafted self-referential extension causing an infinite loop and CPU pegging. This is a defense against a potential DoS/vector in kernel space.
Verification Assessment
Vulnerability Type: Denial of Service (Infinite loop in kernel space via crafted multisync extension)
Confidence: HIGH
Affected Versions: v7.0-rc6 and earlier (pre-patch); fixed by commit fb44d589bf3148e13452185a6e772a7efbf2d684
Code Diff
diff --git a/drivers/gpu/drm/v3d/v3d_submit.c b/drivers/gpu/drm/v3d/v3d_submit.c
index 18f2bf1fe89fac..fc74351efad5ce 100644
--- a/drivers/gpu/drm/v3d/v3d_submit.c
+++ b/drivers/gpu/drm/v3d/v3d_submit.c
@@ -393,6 +393,11 @@ v3d_get_multisync_submit_deps(struct drm_file *file_priv,
if (multisync.pad)
return -EINVAL;
+ if (!multisync.in_sync_count && !multisync.out_sync_count) {
+ drm_dbg(&v3d->drm, "Empty multisync extension\n");
+ return -EINVAL;
+ }
+
ret = v3d_get_multisync_post_deps(file_priv, se, multisync.out_sync_count,
multisync.out_syncs);
if (ret)