[PATCH RFC] drm/lease: use kvmalloc for user-controlled allocations

"syzbot" <[email protected]>
Newsgroups dev.linux.lists.syzbot
Message-ID <[email protected]>
In drm_mode_create_lease_ioctl(), a user-controlled object_count is used to
allocate memory for object_ids and objects. If a user provides a very large
object_count (e.g., 1,000,000), the kernel attempts to allocate a
contiguous memory chunk that exceeds the maximum allowed size by the slab
allocator (KMALLOC_MAX_SIZE).

For the objects array, kzalloc_objs() is used, which expands to a standard
kzalloc() call without the __GFP_NOWARN flag. When the requested size
exceeds KMALLOC_MAX_SIZE, the SLUB allocator passes the request to the page
allocator, which triggers a WARN_ON_ONCE_GFP because the required page
order is greater than MAX_PAGE_ORDER:

WARNING: mm/page_alloc.c:5197 at __alloc_frozen_pages_noprof+0x2ce/0x380
mm/page_alloc.c:5197
Call Trace:
 <TASK>
 alloc_pages_mpol+0x212/0x380 mm/mempolicy.c:2490
 ___kmalloc_large_node+0x4c/0x120 mm/slub.c:5237
 __kmalloc_large_node_noprof+0x18/0x90 mm/slub.c:5268
 __do_kmalloc_node mm/slub.c:5284 [inline]
 __kmalloc_noprof+0x3e4/0x750 mm/slub.c:5308
 kmalloc_noprof include/linux/slab.h:954 [inline]
 kzalloc_noprof include/linux/slab.h:1188 [inline]
 fill_object_idr drivers/gpu/drm/drm_lease.c:389 [inline]
 drm_mode_create_lease_ioctl+0x533/0x1ab0 drivers/gpu/drm/drm_lease.c:521

To fix this, replace memdup_array_user() with vmemdup_array_user() and
kzalloc_objs() with kvcalloc(), along with changing their respective
kfree() calls to kvfree(). The kvmalloc family of functions attempts a
kmalloc() first with __GFP_NOWARN applied internally, and gracefully falls
back to vmalloc() for large allocations. This prevents the kernel warning
and makes the allocations more robust against memory fragmentation,
gracefully returning -ENOMEM if the system cannot satisfy the request.

Fixes: 62884cd386b8 ("drm: Add four ioctls for managing drm mode object leases [v7]")
Assisted-by: Gemini:gemini-3.1-pro-preview syzbot
Reported-by: [email protected]
Closes: https://syzkaller.appspot.com/bug?extid=03fb58296859d8dbab4d
Link: https://syzkaller.appspot.com/ai_job?id=73f2715e-0f0e-4924-ad92-d4ef4f06a14f
To: "David Airlie" <[email protected]>
To: <[email protected]>
To: "Maarten Lankhorst" <[email protected]>
To: "Maxime Ripard" <[email protected]>
To: "Simona Vetter" <[email protected]>
To: "Thomas Zimmermann" <[email protected]>
Cc: <[email protected]>

---
diff --git a/drivers/gpu/drm/drm_lease.c b/drivers/gpu/drm/drm_lease.c
index 5d2cf724c..240e0ea6c 100644
--- a/drivers/gpu/drm/drm_lease.c
+++ b/drivers/gpu/drm/drm_lease.c
@@ -386,7 +386,8 @@ static int fill_object_idr(struct drm_device *dev,
 	int ret;
 	bool universal_planes = READ_ONCE(lessor_priv->universal_planes);
 
-	objects = kzalloc_objs(struct drm_mode_object *, object_count);
+	objects = kvcalloc(object_count, sizeof(struct drm_mode_object *),
+			   GFP_KERNEL);
 	if (!objects)
 		return -ENOMEM;
 
@@ -462,7 +463,7 @@ static int fill_object_idr(struct drm_device *dev,
 		if (objects[o])
 			drm_mode_object_put(objects[o]);
 	}
-	kfree(objects);
+	kvfree(objects);
 	return ret;
 }
 
@@ -509,8 +510,8 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev,
 	/* Handle leased objects, if any */
 	idr_init(&leases);
 	if (object_count != 0) {
-		object_ids = memdup_array_user(u64_to_user_ptr(cl->object_ids),
-					       object_count, sizeof(__u32));
+		object_ids = vmemdup_array_user(u64_to_user_ptr(cl->object_ids),
+						object_count, sizeof(__u32));
 		if (IS_ERR(object_ids)) {
 			ret = PTR_ERR(object_ids);
 			idr_destroy(&leases);
@@ -520,7 +521,7 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev,
 		/* fill and validate the object idr */
 		ret = fill_object_idr(dev, lessor_priv, &leases,
 				      object_count, object_ids);
-		kfree(object_ids);
+		kvfree(object_ids);
 		if (ret) {
 			drm_dbg_lease(dev, "lease object lookup failed: %i\n", ret);
 			idr_destroy(&leases);


base-commit: 8cd9520d35a6c38db6567e97dd93b1f11f185dc6
-- 
This is an AI-generated patch subject to moderation.
Reply with '#syz upstream' to Sign-off the patch as a human author
and send it to the upstream kernel mailing lists.
Reply with '#syz reject' to reject it ('#syz unreject' to undo).

See https://goo.gle/syzbot-ai-patches for information about AI-generated patches.
You can comment on the patch as usual, syzbot will try to address
the comments and send a new version of the patch if necessary.
syzbot engineers can be reached at [email protected].
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.