[PATCH] fs: Assert on module file_operations without an owner

From: Calvin Owens
Date: Fri Oct 07 2016 - 16:36:08 EST


Omitting the owner field in file_operations declared in modules is an
easy mistake to make, and can result in crashes when the module is
unloaded while userspace is poking the file.

This patch modifies fops_get() to WARN when it encounters a NULL owner,
since in this case it cannot take a reference on the containing module.

Signed-off-by: Calvin Owens <calvinowens@xxxxxx>
---
include/linux/fs.h | 13 ++++++++++++-
kernel/module.c | 1 +
2 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/include/linux/fs.h b/include/linux/fs.h
index 901e25d..fafda9e 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2081,10 +2081,21 @@ extern struct dentry *mount_pseudo(struct file_system_type *, char *,
unsigned long);

/* Alas, no aliases. Too much hassle with bringing module.h everywhere */
-#define fops_get(fops) \
+#define __fops_get(fops) \
(((fops) && try_module_get((fops)->owner) ? (fops) : NULL))
#define fops_put(fops) \
do { if (fops) module_put((fops)->owner); } while(0)
+
+#define unowned_fmt "No fops owner at %p in [%s]\n"
+#define fops_unowned(fops) \
+ (is_module_address((unsigned long)(fops)) && !(fops)->owner)
+#define fops_modname(fops) \
+ __module_address((unsigned long)(fops))->name
+#define fops_warn_unowned(fops) \
+ WARN(fops_unowned(fops), unowned_fmt, (fops), fops_modname(fops))
+#define fops_get(fops) \
+ ({ fops_warn_unowned(fops); __fops_get(fops); })
+
/*
* This one is to be used *ONLY* from ->open() instances.
* fops must be non-NULL, pinned down *and* module dependencies
diff --git a/kernel/module.c b/kernel/module.c
index 529efae..4443727 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -4181,6 +4181,7 @@ bool is_module_address(unsigned long addr)

return ret;
}
+EXPORT_SYMBOL_GPL(is_module_address);

/*
* __module_address - get the module which contains an address.
--
2.9.3