All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH v2 0/2] module: Introduce module unload taint tracking
@ 2022-04-19 15:03 Aaron Tomlin
  2022-04-19 15:03 ` [RFC PATCH v2 1/2] module: Make module_flags_taint() accept a module's taints bitmap directly Aaron Tomlin
  2022-04-19 15:03 ` [RFC PATCH v2 2/2] module: Introduce module unload taint tracking Aaron Tomlin
  0 siblings, 2 replies; 5+ messages in thread
From: Aaron Tomlin @ 2022-04-19 15:03 UTC (permalink / raw)
  To: mcgrof
  Cc: cl, pmladek, mbenes, christophe.leroy, akpm, linux-kernel,
	linux-modules, atomlin, ghalat

Hi Luis,

This is based on the latest mcgrof/modules-next branch.  I have decided
still to use RCU even though no entry is ever removed from the unloaded
tainted modules list. That being said, if I understand correctly, it is not
safe in some instances to use 'module_mutex' in print_modules(). So instead
we disable preemption to ensure list traversal with concurrent list
manipulation e.g. list_add_rcu(), is safe too.

Please let me know your thoughts.

Aaron Tomlin (2):
  module: Make module_flags_taint() accept a module's taints bitmap
    directly
  module: Introduce module unload taint tracking

 init/Kconfig         | 11 +++++++
 kernel/module/main.c | 76 +++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 83 insertions(+), 4 deletions(-)


base-commit: eeaec7801c421e17edda6e45a32d4a5596b633da
-- 
2.34.1


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [RFC PATCH v2 1/2] module: Make module_flags_taint() accept a module's taints bitmap directly
  2022-04-19 15:03 [RFC PATCH v2 0/2] module: Introduce module unload taint tracking Aaron Tomlin
@ 2022-04-19 15:03 ` Aaron Tomlin
  2022-04-19 15:03 ` [RFC PATCH v2 2/2] module: Introduce module unload taint tracking Aaron Tomlin
  1 sibling, 0 replies; 5+ messages in thread
From: Aaron Tomlin @ 2022-04-19 15:03 UTC (permalink / raw)
  To: mcgrof
  Cc: cl, pmladek, mbenes, christophe.leroy, akpm, linux-kernel,
	linux-modules, atomlin, ghalat

No functional change.

The purpose of this patch is to modify module_flags_taint() to accept a
module's taints bitmap as a parameter and modifies all users accordingly.
This is in preparation for module unload taint tracking support.

Signed-off-by: Aaron Tomlin <atomlin@redhat.com>
---
 kernel/module/main.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/kernel/module/main.c b/kernel/module/main.c
index 05a42d8fcd7a..ea78cec316dd 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -890,13 +890,13 @@ static inline int module_unload_init(struct module *mod)
 }
 #endif /* CONFIG_MODULE_UNLOAD */
 
-static size_t module_flags_taint(struct module *mod, char *buf)
+static size_t module_flags_taint(unsigned long taints, char *buf)
 {
 	size_t l = 0;
 	int i;
 
 	for (i = 0; i < TAINT_FLAGS_COUNT; i++) {
-		if (taint_flags[i].module && test_bit(i, &mod->taints))
+		if (taint_flags[i].module && test_bit(i, &taints))
 			buf[l++] = taint_flags[i].c_true;
 	}
 
@@ -974,7 +974,7 @@ static ssize_t show_taint(struct module_attribute *mattr,
 {
 	size_t l;
 
-	l = module_flags_taint(mk->mod, buffer);
+	l = module_flags_taint(mk->mod->taints, buffer);
 	buffer[l++] = '\n';
 	return l;
 }
@@ -2993,7 +2993,7 @@ char *module_flags(struct module *mod, char *buf)
 	    mod->state == MODULE_STATE_GOING ||
 	    mod->state == MODULE_STATE_COMING) {
 		buf[bx++] = '(';
-		bx += module_flags_taint(mod, buf + bx);
+		bx += module_flags_taint(mod->taints, buf + bx);
 		/* Show a - for module-is-being-unloaded */
 		if (mod->state == MODULE_STATE_GOING)
 			buf[bx++] = '-';
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [RFC PATCH v2 2/2] module: Introduce module unload taint tracking
  2022-04-19 15:03 [RFC PATCH v2 0/2] module: Introduce module unload taint tracking Aaron Tomlin
  2022-04-19 15:03 ` [RFC PATCH v2 1/2] module: Make module_flags_taint() accept a module's taints bitmap directly Aaron Tomlin
@ 2022-04-19 15:03 ` Aaron Tomlin
  1 sibling, 0 replies; 5+ messages in thread
From: Aaron Tomlin @ 2022-04-19 15:03 UTC (permalink / raw)
  To: mcgrof
  Cc: cl, pmladek, mbenes, christophe.leroy, akpm, linux-kernel,
	linux-modules, atomlin, ghalat

Currently, only the initial module that tainted the kernel is
recorded e.g. when an out-of-tree module is loaded.

The purpose of this patch is to allow the kernel to maintain a record of
each unloaded module that taints the kernel. So, in addition to
displaying a list of linked modules (see print_modules()) e.g. in the
event of a detected bad page, unloaded modules that carried a taint/or
taints are displayed too. If a previously unloaded module with a
taint/or tains is loaded once again and then a count will be shown
accordingly.

The number of tracked modules is not fixed. This feature is disabled by
default.

Signed-off-by: Aaron Tomlin <atomlin@redhat.com>
---
 init/Kconfig         | 11 +++++++
 kernel/module/main.c | 68 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 79 insertions(+)

diff --git a/init/Kconfig b/init/Kconfig
index ddcbefe535e9..6b30210f787d 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -2118,6 +2118,17 @@ config MODULE_FORCE_UNLOAD
 	  rmmod).  This is mainly for kernel developers and desperate users.
 	  If unsure, say N.
 
+config MODULE_UNLOAD_TAINT_TRACKING
+	bool "Tainted module unload tracking"
+	depends on MODULE_UNLOAD
+	default n
+	help
+	  This option allows you to maintain a record of each unloaded
+	  module that tainted the kernel. In addition to displaying a
+	  list of linked (or loaded) modules e.g. on detection of a bad
+	  page (see bad_page()), the aforementioned details are also
+	  shown. If unsure, say N.
+
 config MODVERSIONS
 	bool "Module versioning support"
 	help
diff --git a/kernel/module/main.c b/kernel/module/main.c
index ea78cec316dd..0f7df9ac25ce 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -68,6 +68,16 @@
  */
 DEFINE_MUTEX(module_mutex);
 LIST_HEAD(modules);
+#ifdef CONFIG_MODULE_UNLOAD_TAINT_TRACKING
+static LIST_HEAD(unloaded_tainted_modules);
+
+struct mod_unload_taint {
+	struct list_head list;
+	char name[MODULE_NAME_LEN];
+	unsigned long taints;
+	u64 count;
+};
+#endif
 
 /* Work queue for freeing init sections in success case */
 static void do_free_init(struct work_struct *w);
@@ -150,6 +160,42 @@ int unregister_module_notifier(struct notifier_block *nb)
 }
 EXPORT_SYMBOL(unregister_module_notifier);
 
+#ifdef CONFIG_MODULE_UNLOAD_TAINT_TRACKING
+static int try_add_tainted_module(struct module *mod)
+{
+	struct mod_unload_taint *mod_taint;
+
+	module_assert_mutex_or_preempt();
+
+	list_for_each_entry_rcu(mod_taint, &unloaded_tainted_modules, list,
+				lockdep_is_held(&module_mutex)) {
+		size_t len = strlen(mod_taint->name);
+
+		if (len == strlen(mod->name) && !memcmp(mod_taint->name, mod->name, len) &&
+		    mod_taint->taints & mod->taints) {
+			mod_taint->count++;
+			goto out;
+		}
+	}
+
+	mod_taint = kmalloc(sizeof(*mod_taint), GFP_KERNEL);
+	if (unlikely(!mod_taint))
+		return -ENOMEM;
+	strlcpy(mod_taint->name, mod->name,
+		MODULE_NAME_LEN);
+	mod_taint->taints = mod->taints;
+	list_add_rcu(&mod_taint->list, &unloaded_tainted_modules);
+	mod_taint->count = 0;
+out:
+	return 0;
+}
+#else /* MODULE_UNLOAD_TAINT_TRACKING */
+static int try_add_tainted_module(struct module *mod)
+{
+	return 0;
+}
+#endif
+
 /*
  * We require a truly strong try_module_get(): 0 means success.
  * Otherwise an error is returned due to ongoing or failed
@@ -1201,6 +1247,9 @@ static void free_module(struct module *mod)
 	module_bug_cleanup(mod);
 	/* Wait for RCU-sched synchronizing before releasing mod->list and buglist. */
 	synchronize_rcu();
+	if (try_add_tainted_module(mod))
+		pr_err("%s: adding tainted module to the unloaded tainted modules list failed.\n",
+		       mod->name);
 	mutex_unlock(&module_mutex);
 
 	/* Clean up CFI for the module. */
@@ -3126,6 +3175,9 @@ struct module *__module_text_address(unsigned long addr)
 void print_modules(void)
 {
 	struct module *mod;
+#ifdef CONFIG_MODULE_UNLOAD_TAINT_TRACKING
+	struct mod_unload_taint *mod_taint;
+#endif
 	char buf[MODULE_FLAGS_BUF_SIZE];
 
 	printk(KERN_DEFAULT "Modules linked in:");
@@ -3136,6 +3188,22 @@ void print_modules(void)
 			continue;
 		pr_cont(" %s%s", mod->name, module_flags(mod, buf));
 	}
+#ifdef CONFIG_MODULE_UNLOAD_TAINT_TRACKING
+	if (!list_empty(&unloaded_tainted_modules)) {
+		printk(KERN_DEFAULT "\nUnloaded tainted modules:");
+		list_for_each_entry_rcu(mod_taint, &unloaded_tainted_modules,
+					list) {
+			size_t l;
+
+			l = module_flags_taint(mod_taint->taints, buf);
+			buf[l++] = '\0';
+			pr_cont(" %s(%s)%s", mod_taint->name, buf,
+				mod_taint->count ? ":" : "");
+			if (mod_taint->count)
+				pr_cont("%llu", mod_taint->count);
+		}
+#endif
+	}
 	preempt_enable();
 	if (last_unloaded_module[0])
 		pr_cont(" [last unloaded: %s]", last_unloaded_module);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [RFC PATCH v2 2/2] module: Introduce module unload taint tracking
       [not found] <02563952-1676-bd9f-6d1f-0f8da74babcb@intel.com>
@ 2022-04-25  9:26 ` Aaron Tomlin
  0 siblings, 0 replies; 5+ messages in thread
From: Aaron Tomlin @ 2022-04-25  9:26 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 1034 bytes --]

On Mon 2022-04-25 15:41 +0800, Chen, Rong A wrote:
> Hi Aaron,

Hi Rong,

> I think the problem is here (#endif is in a wrong place).

Oh right, sorry about that - I completely missed it.

> +#ifdef CONFIG_MODULE_UNLOAD_TAINT_TRACKING
> +       if (!list_empty(&unloaded_tainted_modules)) {
> +               printk(KERN_DEFAULT "\nUnloaded tainted modules:");
> +               list_for_each_entry_rcu(mod_taint,
> &unloaded_tainted_modules,
> +                                       list) {
> +                       size_t l;
> +
> +                       l = module_flags_taint(mod_taint->taints, buf);
> +                       buf[l++] = '\0';
> +                       pr_cont(" %s(%s)%s", mod_taint->name, buf,
> +                               mod_taint->count ? ":" : "");
> +                       if (mod_taint->count)
> +                               pr_cont("%llu", mod_taint->count);
> +               }
> +#endif
> +       }

Thanks for following up!

Kind regards,

-- 
Aaron Tomlin

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [RFC PATCH v2 2/2] module: Introduce module unload taint tracking
       [not found] <202204200758.bmFPcUVJ-lkp@intel.com>
@ 2022-04-22  9:47 ` Aaron Tomlin
  0 siblings, 0 replies; 5+ messages in thread
From: Aaron Tomlin @ 2022-04-22  9:47 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 5521 bytes --]

On Wed 2022-04-20 07:19 +0800, kernel test robot wrote:
> Hi Aaron,

Hi,

> [FYI, it's a private test report for your RFC patch.]
> [auto build test ERROR on eeaec7801c421e17edda6e45a32d4a5596b633da]
> 
> url:    https://github.com/intel-lab-lkp/linux/commits/Aaron-Tomlin/module-Introduce-module-unload-taint-tracking/20220419-230714
> base:   eeaec7801c421e17edda6e45a32d4a5596b633da
> config: sparc64-randconfig-r004-20220419 (https://download.01.org/0day-ci/archive/20220420/202204200758.bmFPcUVJ-lkp(a)intel.com/config)
> compiler: sparc64-linux-gcc (GCC) 11.2.0
> reproduce (this is a W=1 build):
>         wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
>         chmod +x ~/bin/make.cross
>         # https://github.com/intel-lab-lkp/linux/commit/772002b7cd0eb4bc1ed0684d1d9295670523ffe5
>         git remote add linux-review https://github.com/intel-lab-lkp/linux
>         git fetch --no-tags linux-review Aaron-Tomlin/module-Introduce-module-unload-taint-tracking/20220419-230714
>         git checkout 772002b7cd0eb4bc1ed0684d1d9295670523ffe5
>         # save the config file
>         mkdir build_dir && cp config build_dir/.config
>         COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross W=1 O=build_dir ARCH=sparc64 SHELL=/bin/bash
> 
> If you fix the issue, kindly add following tag as appropriate
> Reported-by: kernel test robot <lkp@intel.com>
> 
> All errors (new ones prefixed by >>):
> 
>    In file included from include/linux/build_bug.h:5,
>                     from include/linux/container_of.h:5,
>                     from include/linux/list.h:5,
>                     from include/linux/module.h:12,
>                     from include/linux/moduleloader.h:6,
>                     from kernel/module/main.c:11:
> >> include/linux/compiler.h:86:28: error: expected '(' before '__volatile__'
>       86 | # define barrier() __asm__ __volatile__("": : :"memory")
>          |                            ^~~~~~~~~~~~

I'm not sure what's the issue here? Is this a false positive?

>    include/linux/preempt.h:277:49: note: in expansion of macro 'barrier'
>      277 | #define preempt_enable()                        barrier()
>          |                                                 ^~~~~~~
>    kernel/module/main.c:3207:9: note: in expansion of macro 'preempt_enable'
>     3207 |         preempt_enable();
>          |         ^~~~~~~~~~~~~~
>    kernel/module/main.c:3208:9: error: expected identifier or '(' before 'if'
>     3208 |         if (last_unloaded_module[0])
>          |         ^~
>    In file included from include/linux/kernel.h:29,
>                     from include/linux/cpumask.h:10,
>                     from include/linux/mm_types_task.h:14,
>                     from include/linux/mm_types.h:5,
>                     from include/linux/buildid.h:5,
>                     from include/linux/module.h:14,
>                     from include/linux/moduleloader.h:6,
>                     from kernel/module/main.c:11:
>    include/linux/printk.h:419:10: error: expected identifier or '(' before ')' token
>      419 |         })
>          |          ^
>    include/linux/printk.h:446:26: note: in expansion of macro 'printk_index_wrap'
>      446 | #define printk(fmt, ...) printk_index_wrap(_printk, fmt, ##__VA_ARGS__)
>          |                          ^~~~~~~~~~~~~~~~~
>    include/linux/printk.h:531:9: note: in expansion of macro 'printk'
>      531 |         printk(KERN_CONT fmt, ##__VA_ARGS__)
>          |         ^~~~~~
>    kernel/module/main.c:3209:17: note: in expansion of macro 'pr_cont'
>     3209 |                 pr_cont(" [last unloaded: %s]", last_unloaded_module);
>          |                 ^~~~~~~
>    include/linux/printk.h:416:10: error: expected identifier or '(' before '{' token
>      416 |         ({                                                              \
>          |          ^
>    include/linux/printk.h:446:26: note: in expansion of macro 'printk_index_wrap'
>      446 | #define printk(fmt, ...) printk_index_wrap(_printk, fmt, ##__VA_ARGS__)
>          |                          ^~~~~~~~~~~~~~~~~
>    include/linux/printk.h:531:9: note: in expansion of macro 'printk'
>      531 |         printk(KERN_CONT fmt, ##__VA_ARGS__)
>          |         ^~~~~~
>    kernel/module/main.c:3210:9: note: in expansion of macro 'pr_cont'
>     3210 |         pr_cont("\n");
>          |         ^~~~~~~
>    kernel/module/main.c:3211:1: error: expected identifier or '(' before '}' token
>     3211 | }
>          | ^
>    kernel/module/main.c:594:13: warning: 'last_unloaded_module' defined but not used [-Wunused-variable]
>      594 | static char last_unloaded_module[MODULE_NAME_LEN+1];
>          |             ^~~~~~~~~~~~~~~~~~~~
> 
> 
> vim +86 include/linux/compiler.h
> 
> ^1da177e4c3f41 Linus Torvalds 2005-04-16  82  
> ^1da177e4c3f41 Linus Torvalds 2005-04-16  83  /* Optimization barrier */
> ^1da177e4c3f41 Linus Torvalds 2005-04-16  84  #ifndef barrier
> 3347acc6fcd4ee Arvind Sankar  2020-11-13  85  /* The "volatile" is due to gcc bugs */
> 3347acc6fcd4ee Arvind Sankar  2020-11-13 @86  # define barrier() __asm__ __volatile__("": : :"memory")
> ^1da177e4c3f41 Linus Torvalds 2005-04-16  87  #endif
> ^1da177e4c3f41 Linus Torvalds 2005-04-16  88  
> 
> -- 
> 0-DAY CI Kernel Test Service
> https://01.org/lkp
> 

-- 
Aaron Tomlin

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2022-04-25  9:26 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-04-19 15:03 [RFC PATCH v2 0/2] module: Introduce module unload taint tracking Aaron Tomlin
2022-04-19 15:03 ` [RFC PATCH v2 1/2] module: Make module_flags_taint() accept a module's taints bitmap directly Aaron Tomlin
2022-04-19 15:03 ` [RFC PATCH v2 2/2] module: Introduce module unload taint tracking Aaron Tomlin
     [not found] <202204200758.bmFPcUVJ-lkp@intel.com>
2022-04-22  9:47 ` Aaron Tomlin
     [not found] <02563952-1676-bd9f-6d1f-0f8da74babcb@intel.com>
2022-04-25  9:26 ` Aaron Tomlin

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.