[PATCH v2 9/9] drm/debugfs: hold device reference for the lifetime of open files

Alvin Sun <[email protected]> Fri, 31 Jul 2026 01:05:47 +0800
Newsgroups dev.linux.lists.driver-core,org.freedesktop.lists.dri-devel,org.kernel.feeds.b4-sent,org.kernel.vger.rust-for-linux
Message-ID <[email protected]>
Hold a device reference (via drm_dev_get/put) across the lifetime of open
debugfs files. Prevents use-after-free when a device is unregistered while
a debugfs file remains open. Both drm_debugfs_open (legacy info_list)
and drm_debugfs_entry_open (drm_debugfs_add_file) paths are covered.

Fixes: 1c9cacbea8805 ("drm/debugfs: create device-centered debugfs functions")
Fixes: 28a62277e06f9 ("drm: Convert proc files to seq_file and introduce debugfs")

Signed-off-by: Alvin Sun <[email protected]>
---
 drivers/gpu/drm/drm_debugfs.c | 42 ++++++++++++++++++++++++++++++++++++++----
 1 file changed, 38 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c
index 38cf6ce387cc8..5262a708f1602 100644
--- a/drivers/gpu/drm/drm_debugfs.c
+++ b/drivers/gpu/drm/drm_debugfs.c
@@ -159,11 +159,28 @@ static const struct drm_debugfs_info drm_debugfs_list[] = {
 static int drm_debugfs_open(struct inode *inode, struct file *file)
 {
 	struct drm_info_node *node = inode->i_private;
+	struct drm_device *dev = node->minor->dev;
+	int ret;
 
 	if (!device_is_registered(node->minor->kdev))
 		return -ENODEV;
 
-	return single_open(file, node->info_ent->show, node);
+	drm_dev_get(dev);
+
+	ret = single_open(file, node->info_ent->show, node);
+	if (ret)
+		drm_dev_put(dev);
+
+	return ret;
+}
+
+static int drm_debugfs_release(struct inode *inode, struct file *file)
+{
+	struct drm_info_node *node =
+		((struct seq_file *)file->private_data)->private;
+
+	drm_dev_put(node->minor->dev);
+	return single_release(inode, file);
 }
 
 static int drm_debugfs_entry_open(struct inode *inode, struct file *file)
@@ -171,11 +188,28 @@ static int drm_debugfs_entry_open(struct inode *inode, struct file *file)
 	struct drm_debugfs_entry *entry = inode->i_private;
 	struct drm_debugfs_info *node = &entry->file;
 	struct drm_minor *minor = entry->dev->primary ?: entry->dev->accel;
+	struct drm_device *dev = entry->dev;
+	int ret;
 
 	if (!device_is_registered(minor->kdev))
 		return -ENODEV;
 
-	return single_open(file, node->show, entry);
+	drm_dev_get(dev);
+
+	ret = single_open(file, node->show, entry);
+	if (ret)
+		drm_dev_put(dev);
+
+	return ret;
+}
+
+static int drm_debugfs_entry_release(struct inode *inode, struct file *file)
+{
+	struct drm_debugfs_entry *entry =
+		((struct seq_file *)file->private_data)->private;
+
+	drm_dev_put(entry->dev);
+	return single_release(inode, file);
 }
 
 static const struct file_operations drm_debugfs_entry_fops = {
@@ -183,7 +217,7 @@ static const struct file_operations drm_debugfs_entry_fops = {
 	.open = drm_debugfs_entry_open,
 	.read = seq_read,
 	.llseek = seq_lseek,
-	.release = single_release,
+	.release = drm_debugfs_entry_release,
 };
 
 static const struct file_operations drm_debugfs_fops = {
@@ -191,7 +225,7 @@ static const struct file_operations drm_debugfs_fops = {
 	.open = drm_debugfs_open,
 	.read = seq_read,
 	.llseek = seq_lseek,
-	.release = single_release,
+	.release = drm_debugfs_release,
 };
 
 /**

-- 
2.43.0