[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