From: Zijun Hu zijun.hu@oss.qualcomm.com
[ Upstream commit 1ba0fb42aa6a5f072b1b8c0b0520b32ad4ef4b45 ]
misc_open() may request module for miscdevice with dynamic minor, which is meaningless since:
- The dynamic minor allocated is unknown in advance without registering miscdevice firstly. - Macro MODULE_ALIAS_MISCDEV() is not applicable for dynamic minor.
Fix by only requesting module for miscdevice with fixed minor.
Acked-by: Thadeu Lima de Souza Cascardo cascardo@igalia.com Signed-off-by: Zijun Hu zijun.hu@oss.qualcomm.com Link: https://lore.kernel.org/r/20250714-rfc_miscdev-v6-6-2ed949665bde@oss.qualcom... Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Sasha Levin sashal@kernel.org ---
LLM Generated explanations, may be completely bogus:
YES
- What it fixes - Prevents meaningless module autoload attempts for misc devices with dynamically assigned minors. Such modules cannot advertise a stable alias, so `request_module("char-major-10-<minor>")` can never match them. This avoids pointless usermode helper invocations and potential delays or log noise when opening such device nodes.
- Code-level analysis - Current behavior: In `misc_open()` the code unconditionally requests a module if no matching `miscdevice` is found on first lookup, then retries the lookup (drivers/char/misc.c:118, drivers/char/misc.c:135–149). - Change: Only request a module when the minor is a fixed, known value; i.e., add a guard `minor < MISC_DYNAMIC_MINOR` around the autoload attempt, and move the final “not found” check outside the block so logic remains identical otherwise. The semantic change is that no autoload is attempted for dynamic minors. - Rationale supported by headers: - `MISC_DYNAMIC_MINOR` is a sentinel 255 (include/linux/miscdevice.h:74). Dynamic minors are allocated from `MISC_DYNAMIC_MINOR + 1` upward (drivers/char/misc.c:65–76), so they are unknown until registration and cannot be known in advance of module load. - `MODULE_ALIAS_MISCDEV(minor)` expands to a fixed `char- major-10-<minor>` alias (include/linux/miscdevice.h:105–107). It cannot be used for dynamically assigned minors (which aren’t constant at build time). Thus, `request_module("char-major-%d-%d", MISC_MAJOR, minor)` (drivers/char/misc.c:137) can never succeed for dynamic minors. - Correctness of control flow: - After patch, if `new_fops` is still NULL, the function immediately fails with `-ENODEV`, just as it did before when autoload didn’t resolve the device. Moving the `if (!new_fops) goto fail;` outside the conditional preserves behavior for fixed-minor flows and removes only the futile autoload for dynamic minors.
- User impact - Eliminates unnecessary invocations of modprobe/kmod when opening stale or handcrafted device nodes with dynamic minors. This reduces latency and log spam without changing any successful open path for valid misc devices.
- Security considerations - Reduces the surface for unintended autoloading by user-triggered opens of arbitrary `char-major-10-<large minor>` device nodes where no legitimate alias can exist. While not a direct vulnerability fix, it narrows pointless autoloading opportunities.
- Scope and risk - Small, localized change in `drivers/char/misc.c::misc_open()` (drivers/char/misc.c:118). No ABI/API changes. No architectural changes. - Only affects the autoload attempt for “not found” cases; normal open paths (where the `miscdevice` is registered) are unchanged. - Fixed-minor devices keep working as before because the autoload remains in place for minors `< MISC_DYNAMIC_MINOR`.
- Stable backport criteria - Fixes a real, user-visible misbehavior (unnecessary autoload attempts) with potential performance/log impact. - Minimal, well-scoped change to a mature code path. - No new features; purely a behavioral correction for an edge case. - Acknowledged and merged by subsystem maintainer; Signed-off-by Greg Kroah-Hartman indicates upstream acceptance. - Applies cleanly across stable series; `misc_open()` and the related defines/macros are long-stable and consistent.
- Conclusion - Recommended for backport: it’s a safe, contained fix that prevents futile module requests for dynamic minors and aligns behavior with the documented aliasing mechanism for misc devices.
drivers/char/misc.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/char/misc.c b/drivers/char/misc.c index 255a164eec86d..4c276b8066ff8 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -132,7 +132,8 @@ static int misc_open(struct inode *inode, struct file *file) break; }
- if (!new_fops) { + /* Only request module for fixed minor code */ + if (!new_fops && minor < MISC_DYNAMIC_MINOR) { mutex_unlock(&misc_mtx); request_module("char-major-%d-%d", MISC_MAJOR, minor); mutex_lock(&misc_mtx); @@ -144,10 +145,11 @@ static int misc_open(struct inode *inode, struct file *file) new_fops = fops_get(iter->fops); break; } - if (!new_fops) - goto fail; }
+ if (!new_fops) + goto fail; + /* * Place the miscdevice in the file's * private_data so it can be used by the