linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v8 00/13] module: core code clean up
@ 2022-02-22 14:12 Aaron Tomlin
  2022-02-22 14:12 ` [PATCH v8 01/13] module: Move all into module/ Aaron Tomlin
                   ` (12 more replies)
  0 siblings, 13 replies; 43+ messages in thread
From: Aaron Tomlin @ 2022-02-22 14:12 UTC (permalink / raw)
  To: mcgrof, christophe.leroy
  Cc: cl, pmladek, mbenes, akpm, jeyu, linux-kernel, linux-modules,
	void, atomlin, allen.lkml, joe, msuchanek, oleksandr

Hi Luis, Christophe,

As per your suggestion [1], this is an attempt to refactor and split
optional code out of core module support code into separate components.
This version is based on Linus' commit 7993e65fdd0f ("Merge tag
'mtd/fixes-for-5.17-rc5' of
git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux").

Hopefully this iteration is all right. Please let me know your thoughts.

Changes since v7 [2]

 - Removed redundant ifdef CONFIG_MODULES and endif pairing from
   kernel/module/Makefile

Changes since v6 [3]

 - Moved KCOV_INSTRUMENT_module.o out of kernel/Makefile into
   kernel/module/Makefile (Christophe Leroy)
 - Moved kernel/module/signature.c back into kernel/
   (Christophe Leroy)
 - Fixed Oops in add_kallsyms() due to an invalid pointer assignment
   (Christophe Leroy)

Changes since v5 [4]:

 - Updated MAINTAINERS to include the entire kernel/module/ directory
   (Christophe Leroy)
 - Reintroduce commit a97ac8cb24a3 ("module: fix signature check failures
   when using in-kernel decompression") (Michal Suchánek)
 - Refactored code to address some (i.e.
   --ignore=MULTIPLE_ASSIGNMENTS,ASSIGN_IN_IF was used) style violations
   e.g. "Alignment should match open parenthesis", reported by
   scripts/checkpatch.pl --strict (Christophe Leroy)
 - Used PAGE_ALIGN() and PAGE_ALIGNED() instead (Christophe Leroy)
 - Removed sig_enforce from include/linux/module.h as it is only
   used in kernel/module/signing.c (Christophe Leroy)
 - Added static keyword for anything not used outside a source file
   (Christophe Leroy)
 - Moved mod_sysfs_teardown() to kernel/module/sysfs.c (Christophe Leroy)
 - Removed kdb_modules from kernel/debug/kdb/kdb_private.h
   (Christophe Leroy)

Changes since v4 [5]:

 - Moved is_livepatch_module() and set_livepatch_module() to
   kernel/module/livepatch.c
 - Addressed minor compiler warning concerning
   kernel/module/internal.h (0-day)
 - Resolved style violations reported by scripts/checkpatch.pl
 - Dropped patch 5 [6] so external patch [7] can be applied at
   a later date post merge into module-next (Christophe Leroy)

Changes since v3 [8]:

 - Refactored both is_livepatch_module() and set_livepatch_module(),
   respectively, to use IS_ENABLED(CONFIG_LIVEPATCH) (Joe Perches)
 - Addressed various compiler warnings e.g., no previous prototype (0-day)

Changes since v2 [9]:

 - Moved module decompress support to a separate file
 - Made check_modinfo_livepatch() generic (Petr Mladek)
 - Removed filename from each newly created file (Luis Chamberlain)
 - Addressed some (i.e. --ignore=ASSIGN_IN_IF,AVOID_BUG was used)
   minor scripts/checkpatch.pl concerns e.g., use strscpy over
   strlcpy and missing a blank line after declarations (Allen)

Changes since v1 [10]:

  - Moved module version support code into a new file

[1]: https://lore.kernel.org/lkml/YbEZ4HgSYQEPuRmS@bombadil.infradead.org/
[2]: https://lore.kernel.org/lkml/20220222130911.1348513-1-atomlin@redhat.com/
[3]: https://lore.kernel.org/lkml/20220218212511.887059-1-atomlin@redhat.com/
[4]: https://lore.kernel.org/lkml/20220209170358.3266629-1-atomlin@redhat.com/
[5]: https://lore.kernel.org/lkml/20220130213214.1042497-1-atomlin@redhat.com/
[6]: https://lore.kernel.org/lkml/20220130213214.1042497-6-atomlin@redhat.com/
[7]: https://lore.kernel.org/lkml/203348805c9ac9851d8939d15cb9802ef047b5e2.1643919758.git.christophe.leroy@csgroup.eu/
[8]: https://lore.kernel.org/lkml/20220128203934.600247-1-atomlin@redhat.com/
[9]: https://lore.kernel.org/lkml/20220106234319.2067842-1-atomlin@redhat.com/
[10]: https://lore.kernel.org/lkml/20211228213041.1356334-1-atomlin@redhat.com/

Aaron Tomlin (13):
  module: Move all into module/
  module: Simple refactor in preparation for split
  module: Make internal.h and decompress.c more compliant
  module: Move livepatch support to a separate file
  module: Move latched RB-tree support to a separate file
  module: Move strict rwx support to a separate file
  module: Move extra signature support out of core code
  module: Move kmemleak support to a separate file
  module: Move kallsyms support into a separate file
  module: Move procfs support into a separate file
  module: Move sysfs support into a separate file
  module: Move kdb_modules list out of core code
  module: Move version support into a separate file

 MAINTAINERS                                   |    2 +-
 include/linux/module.h                        |    9 +-
 kernel/Makefile                               |    5 +-
 kernel/debug/kdb/kdb_main.c                   |    5 +
 kernel/debug/kdb/kdb_private.h                |    4 -
 kernel/module-internal.h                      |   50 -
 kernel/module/Makefile                        |   20 +
 kernel/module/debug_kmemleak.c                |   30 +
 .../decompress.c}                             |    5 +-
 kernel/module/internal.h                      |  275 +++
 kernel/module/kallsyms.c                      |  506 +++++
 kernel/module/livepatch.c                     |   74 +
 kernel/{module.c => module/main.c}            | 1856 +----------------
 kernel/module/procfs.c                        |  142 ++
 kernel/module/signing.c                       |  122 ++
 kernel/module/strict_rwx.c                    |   85 +
 kernel/module/sysfs.c                         |  436 ++++
 kernel/module/tree_lookup.c                   |  109 +
 kernel/module/version.c                       |  109 +
 kernel/module_signing.c                       |   45 -
 20 files changed, 2007 insertions(+), 1882 deletions(-)
 delete mode 100644 kernel/module-internal.h
 create mode 100644 kernel/module/Makefile
 create mode 100644 kernel/module/debug_kmemleak.c
 rename kernel/{module_decompress.c => module/decompress.c} (99%)
 create mode 100644 kernel/module/internal.h
 create mode 100644 kernel/module/kallsyms.c
 create mode 100644 kernel/module/livepatch.c
 rename kernel/{module.c => module/main.c} (64%)
 create mode 100644 kernel/module/procfs.c
 create mode 100644 kernel/module/signing.c
 create mode 100644 kernel/module/strict_rwx.c
 create mode 100644 kernel/module/sysfs.c
 create mode 100644 kernel/module/tree_lookup.c
 create mode 100644 kernel/module/version.c
 delete mode 100644 kernel/module_signing.c


base-commit: 7993e65fdd0fe07beb9f36f998f9bbef2c0ee391
-- 
2.34.1


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

* [PATCH v8 01/13] module: Move all into module/
  2022-02-22 14:12 [PATCH v8 00/13] module: core code clean up Aaron Tomlin
@ 2022-02-22 14:12 ` Aaron Tomlin
  2022-02-22 17:58   ` Christophe Leroy
  2022-02-22 20:00   ` Allen
  2022-02-22 14:12 ` [PATCH v8 02/13] module: Simple refactor in preparation for split Aaron Tomlin
                   ` (11 subsequent siblings)
  12 siblings, 2 replies; 43+ messages in thread
From: Aaron Tomlin @ 2022-02-22 14:12 UTC (permalink / raw)
  To: mcgrof, christophe.leroy
  Cc: cl, pmladek, mbenes, akpm, jeyu, linux-kernel, linux-modules,
	void, atomlin, allen.lkml, joe, msuchanek, oleksandr

No functional changes.

This patch moves all module related code into a separate directory,
modifies each file name and creates a new Makefile. Note: this effort
is in preparation to refactor core module code.

Signed-off-by: Aaron Tomlin <atomlin@redhat.com>
---
 MAINTAINERS                                         |  2 +-
 kernel/Makefile                                     |  5 +----
 kernel/module/Makefile                              | 12 ++++++++++++
 kernel/{module_decompress.c => module/decompress.c} |  2 +-
 kernel/{module-internal.h => module/internal.h}     |  0
 kernel/{module.c => module/main.c}                  |  2 +-
 kernel/{module_signing.c => module/signing.c}       |  2 +-
 7 files changed, 17 insertions(+), 8 deletions(-)
 create mode 100644 kernel/module/Makefile
 rename kernel/{module_decompress.c => module/decompress.c} (99%)
 rename kernel/{module-internal.h => module/internal.h} (100%)
 rename kernel/{module.c => module/main.c} (99%)
 rename kernel/{module_signing.c => module/signing.c} (97%)

diff --git a/MAINTAINERS b/MAINTAINERS
index bd86ed9fbc79..463bdb829db4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13012,7 +13012,7 @@ L:	linux-kernel@vger.kernel.org
 S:	Maintained
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mcgrof/linux.git modules-next
 F:	include/linux/module.h
-F:	kernel/module.c
+F:	kernel/module/
 
 MONOLITHIC POWER SYSTEM PMIC DRIVER
 M:	Saravanan Sekar <sravanhome@gmail.com>
diff --git a/kernel/Makefile b/kernel/Makefile
index 56f4ee97f328..717075b65deb 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -29,7 +29,6 @@ KCOV_INSTRUMENT_softirq.o := n
 KCSAN_SANITIZE_softirq.o = n
 # These are called from save_stack_trace() on slub debug path,
 # and produce insane amounts of uninteresting coverage.
-KCOV_INSTRUMENT_module.o := n
 KCOV_INSTRUMENT_extable.o := n
 KCOV_INSTRUMENT_stacktrace.o := n
 # Don't self-instrument.
@@ -53,6 +52,7 @@ obj-y += rcu/
 obj-y += livepatch/
 obj-y += dma/
 obj-y += entry/
+obj-$(CONFIG_MODULES) += module/
 
 obj-$(CONFIG_KCMP) += kcmp.o
 obj-$(CONFIG_FREEZER) += freezer.o
@@ -66,9 +66,6 @@ ifneq ($(CONFIG_SMP),y)
 obj-y += up.o
 endif
 obj-$(CONFIG_UID16) += uid16.o
-obj-$(CONFIG_MODULES) += module.o
-obj-$(CONFIG_MODULE_DECOMPRESS) += module_decompress.o
-obj-$(CONFIG_MODULE_SIG) += module_signing.o
 obj-$(CONFIG_MODULE_SIG_FORMAT) += module_signature.o
 obj-$(CONFIG_KALLSYMS) += kallsyms.o
 obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
diff --git a/kernel/module/Makefile b/kernel/module/Makefile
new file mode 100644
index 000000000000..cdd5c61b8c7f
--- /dev/null
+++ b/kernel/module/Makefile
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Makefile for linux kernel module support
+#
+
+# These are called from save_stack_trace() on slub debug path,
+# and produce insane amounts of uninteresting coverage.
+KCOV_INSTRUMENT_module.o := n
+
+obj-y += main.o
+obj-$(CONFIG_MODULE_DECOMPRESS) += decompress.o
+obj-$(CONFIG_MODULE_SIG) += signing.o
diff --git a/kernel/module_decompress.c b/kernel/module/decompress.c
similarity index 99%
rename from kernel/module_decompress.c
rename to kernel/module/decompress.c
index ffef98a20320..d14d6443225a 100644
--- a/kernel/module_decompress.c
+++ b/kernel/module/decompress.c
@@ -12,7 +12,7 @@
 #include <linux/sysfs.h>
 #include <linux/vmalloc.h>
 
-#include "module-internal.h"
+#include "internal.h"
 
 static int module_extend_max_pages(struct load_info *info, unsigned int extent)
 {
diff --git a/kernel/module-internal.h b/kernel/module/internal.h
similarity index 100%
rename from kernel/module-internal.h
rename to kernel/module/internal.h
diff --git a/kernel/module.c b/kernel/module/main.c
similarity index 99%
rename from kernel/module.c
rename to kernel/module/main.c
index 46a5c2ed1928..34a2b0cf3c3e 100644
--- a/kernel/module.c
+++ b/kernel/module/main.c
@@ -58,7 +58,7 @@
 #include <linux/dynamic_debug.h>
 #include <linux/audit.h>
 #include <uapi/linux/module.h>
-#include "module-internal.h"
+#include "internal.h"
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/module.h>
diff --git a/kernel/module_signing.c b/kernel/module/signing.c
similarity index 97%
rename from kernel/module_signing.c
rename to kernel/module/signing.c
index 8723ae70ea1f..8aeb6d2ee94b 100644
--- a/kernel/module_signing.c
+++ b/kernel/module/signing.c
@@ -12,7 +12,7 @@
 #include <linux/string.h>
 #include <linux/verification.h>
 #include <crypto/public_key.h>
-#include "module-internal.h"
+#include "internal.h"
 
 /*
  * Verify the signature on a module.
-- 
2.34.1


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

* [PATCH v8 02/13] module: Simple refactor in preparation for split
  2022-02-22 14:12 [PATCH v8 00/13] module: core code clean up Aaron Tomlin
  2022-02-22 14:12 ` [PATCH v8 01/13] module: Move all into module/ Aaron Tomlin
@ 2022-02-22 14:12 ` Aaron Tomlin
  2022-02-22 17:58   ` Christophe Leroy
  2022-02-22 14:12 ` [PATCH v8 03/13] module: Make internal.h and decompress.c more compliant Aaron Tomlin
                   ` (10 subsequent siblings)
  12 siblings, 1 reply; 43+ messages in thread
From: Aaron Tomlin @ 2022-02-22 14:12 UTC (permalink / raw)
  To: mcgrof, christophe.leroy
  Cc: cl, pmladek, mbenes, akpm, jeyu, linux-kernel, linux-modules,
	void, atomlin, allen.lkml, joe, msuchanek, oleksandr

No functional change.

This patch makes it possible to move non-essential code
out of core module code.

Signed-off-by: Aaron Tomlin <atomlin@redhat.com>
---
 kernel/module/internal.h | 21 +++++++++++++++++++++
 kernel/module/main.c     | 22 ++--------------------
 2 files changed, 23 insertions(+), 20 deletions(-)

diff --git a/kernel/module/internal.h b/kernel/module/internal.h
index 8c381c99062f..ea8c4c02614c 100644
--- a/kernel/module/internal.h
+++ b/kernel/module/internal.h
@@ -7,6 +7,27 @@
 
 #include <linux/elf.h>
 #include <asm/module.h>
+#include <linux/mutex.h>
+
+#ifndef ARCH_SHF_SMALL
+#define ARCH_SHF_SMALL 0
+#endif
+
+/* If this is set, the section belongs in the init part of the module */
+#define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG - 1))
+/* Maximum number of characters written by module_flags() */
+#define MODULE_FLAGS_BUF_SIZE (TAINT_FLAGS_COUNT + 4)
+
+extern struct mutex module_mutex;
+extern struct list_head modules;
+
+/* Provided by the linker */
+extern const struct kernel_symbol __start___ksymtab[];
+extern const struct kernel_symbol __stop___ksymtab[];
+extern const struct kernel_symbol __start___ksymtab_gpl[];
+extern const struct kernel_symbol __stop___ksymtab_gpl[];
+extern const s32 __start___kcrctab[];
+extern const s32 __start___kcrctab_gpl[];
 
 struct load_info {
 	const char *name;
diff --git a/kernel/module/main.c b/kernel/module/main.c
index 34a2b0cf3c3e..5f5e21f972dd 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -63,10 +63,6 @@
 #define CREATE_TRACE_POINTS
 #include <trace/events/module.h>
 
-#ifndef ARCH_SHF_SMALL
-#define ARCH_SHF_SMALL 0
-#endif
-
 /*
  * Modules' sections will be aligned on page boundaries
  * to ensure complete separation of code and data, but
@@ -78,9 +74,6 @@
 # define debug_align(X) (X)
 #endif
 
-/* If this is set, the section belongs in the init part of the module */
-#define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1))
-
 /*
  * Mutex protects:
  * 1) List of modules (also safely readable with preempt_disable),
@@ -88,8 +81,8 @@
  * 3) module_addr_min/module_addr_max.
  * (delete and add uses RCU list operations).
  */
-static DEFINE_MUTEX(module_mutex);
-static LIST_HEAD(modules);
+DEFINE_MUTEX(module_mutex);
+LIST_HEAD(modules);
 
 /* Work queue for freeing init sections in success case */
 static void do_free_init(struct work_struct *w);
@@ -408,14 +401,6 @@ static __maybe_unused void *any_section_objs(const struct load_info *info,
 	return (void *)info->sechdrs[sec].sh_addr;
 }
 
-/* Provided by the linker */
-extern const struct kernel_symbol __start___ksymtab[];
-extern const struct kernel_symbol __stop___ksymtab[];
-extern const struct kernel_symbol __start___ksymtab_gpl[];
-extern const struct kernel_symbol __stop___ksymtab_gpl[];
-extern const s32 __start___kcrctab[];
-extern const s32 __start___kcrctab_gpl[];
-
 #ifndef CONFIG_MODVERSIONS
 #define symversion(base, idx) NULL
 #else
@@ -4542,9 +4527,6 @@ static void cfi_cleanup(struct module *mod)
 #endif
 }
 
-/* Maximum number of characters written by module_flags() */
-#define MODULE_FLAGS_BUF_SIZE (TAINT_FLAGS_COUNT + 4)
-
 /* Keep in sync with MODULE_FLAGS_BUF_SIZE !!! */
 static char *module_flags(struct module *mod, char *buf)
 {
-- 
2.34.1


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

* [PATCH v8 03/13] module: Make internal.h and decompress.c more compliant
  2022-02-22 14:12 [PATCH v8 00/13] module: core code clean up Aaron Tomlin
  2022-02-22 14:12 ` [PATCH v8 01/13] module: Move all into module/ Aaron Tomlin
  2022-02-22 14:12 ` [PATCH v8 02/13] module: Simple refactor in preparation for split Aaron Tomlin
@ 2022-02-22 14:12 ` Aaron Tomlin
  2022-02-22 14:12 ` [PATCH v8 04/13] module: Move livepatch support to a separate file Aaron Tomlin
                   ` (9 subsequent siblings)
  12 siblings, 0 replies; 43+ messages in thread
From: Aaron Tomlin @ 2022-02-22 14:12 UTC (permalink / raw)
  To: mcgrof, christophe.leroy
  Cc: cl, pmladek, mbenes, akpm, jeyu, linux-kernel, linux-modules,
	void, atomlin, allen.lkml, joe, msuchanek, oleksandr

This patch will address the following warning and style violations
generated by ./scripts/checkpatch.pl in strict mode:

  WARNING: Use #include <linux/module.h> instead of <asm/module.h>
  #10: FILE: kernel/module/internal.h:10:
  +#include <asm/module.h>

  CHECK: spaces preferred around that '-' (ctx:VxV)
  #18: FILE: kernel/module/internal.h:18:
  +#define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1))

  CHECK: Please use a blank line after function/struct/union/enum declarations
  #69: FILE: kernel/module/internal.h:69:
  +}
  +static inline void module_decompress_cleanup(struct load_info *info)
						   ^
  CHECK: extern prototypes should be avoided in .h files
  #84: FILE: kernel/module/internal.h:84:
  +extern int mod_verify_sig(const void *mod, struct load_info *info);

  WARNING: Missing a blank line after declarations
  #116: FILE: kernel/module/decompress.c:116:
  +               struct page *page = module_get_next_page(info);
  +               if (!page) {

  WARNING: Missing a blank line after declarations
  #174: FILE: kernel/module/decompress.c:174:
  +               struct page *page = module_get_next_page(info);
  +               if (!page) {

  CHECK: Please use a blank line after function/struct/union/enum declarations
  #258: FILE: kernel/module/decompress.c:258:
  +}
  +static struct kobj_attribute module_compression_attr = __ATTR_RO(compression);

Note: Fortunately, the multiple-include optimisation found in
include/linux/module.h will prevent duplication/or inclusion more than
once.

Fixes: f314dfea16a ("modsign: log module name in the event of an error")
Reviewed-by: Christophe Leroy <christophe.leroy@csgroup.eu>
Signed-off-by: Aaron Tomlin <atomlin@redhat.com>
---
 kernel/module/decompress.c | 3 +++
 kernel/module/internal.h   | 6 ++++--
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/kernel/module/decompress.c b/kernel/module/decompress.c
index d14d6443225a..2fc7081dd7c1 100644
--- a/kernel/module/decompress.c
+++ b/kernel/module/decompress.c
@@ -113,6 +113,7 @@ static ssize_t module_gzip_decompress(struct load_info *info,
 
 	do {
 		struct page *page = module_get_next_page(info);
+
 		if (!page) {
 			retval = -ENOMEM;
 			goto out_inflate_end;
@@ -171,6 +172,7 @@ static ssize_t module_xz_decompress(struct load_info *info,
 
 	do {
 		struct page *page = module_get_next_page(info);
+
 		if (!page) {
 			retval = -ENOMEM;
 			goto out;
@@ -256,6 +258,7 @@ static ssize_t compression_show(struct kobject *kobj,
 {
 	return sysfs_emit(buf, "%s\n", __stringify(MODULE_COMPRESSION));
 }
+
 static struct kobj_attribute module_compression_attr = __ATTR_RO(compression);
 
 static int __init module_decompress_sysfs_init(void)
diff --git a/kernel/module/internal.h b/kernel/module/internal.h
index ea8c4c02614c..e0775e66bcf7 100644
--- a/kernel/module/internal.h
+++ b/kernel/module/internal.h
@@ -6,7 +6,8 @@
  */
 
 #include <linux/elf.h>
-#include <asm/module.h>
+#include <linux/compiler.h>
+#include <linux/module.h>
 #include <linux/mutex.h>
 
 #ifndef ARCH_SHF_SMALL
@@ -54,7 +55,7 @@ struct load_info {
 	} index;
 };
 
-extern int mod_verify_sig(const void *mod, struct load_info *info);
+int mod_verify_sig(const void *mod, struct load_info *info);
 
 #ifdef CONFIG_MODULE_DECOMPRESS
 int module_decompress(struct load_info *info, const void *buf, size_t size);
@@ -65,6 +66,7 @@ static inline int module_decompress(struct load_info *info,
 {
 	return -EOPNOTSUPP;
 }
+
 static inline void module_decompress_cleanup(struct load_info *info)
 {
 }
-- 
2.34.1


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

* [PATCH v8 04/13] module: Move livepatch support to a separate file
  2022-02-22 14:12 [PATCH v8 00/13] module: core code clean up Aaron Tomlin
                   ` (2 preceding siblings ...)
  2022-02-22 14:12 ` [PATCH v8 03/13] module: Make internal.h and decompress.c more compliant Aaron Tomlin
@ 2022-02-22 14:12 ` Aaron Tomlin
  2022-02-22 17:58   ` Christophe Leroy
  2022-02-25  9:34   ` Petr Mladek
  2022-02-22 14:12 ` [PATCH v8 05/13] module: Move latched RB-tree " Aaron Tomlin
                   ` (8 subsequent siblings)
  12 siblings, 2 replies; 43+ messages in thread
From: Aaron Tomlin @ 2022-02-22 14:12 UTC (permalink / raw)
  To: mcgrof, christophe.leroy
  Cc: cl, pmladek, mbenes, akpm, jeyu, linux-kernel, linux-modules,
	void, atomlin, allen.lkml, joe, msuchanek, oleksandr

No functional change.

This patch migrates livepatch support (i.e. used during module
add/or load and remove/or deletion) from core module code into
kernel/module/livepatch.c. At the moment it contains code to
persist Elf information about a given livepatch module, only.

Signed-off-by: Aaron Tomlin <atomlin@redhat.com>
---
 include/linux/module.h    |   9 ++--
 kernel/module/Makefile    |   1 +
 kernel/module/internal.h  |  22 ++++++++
 kernel/module/livepatch.c |  74 +++++++++++++++++++++++++++
 kernel/module/main.c      | 102 ++++----------------------------------
 5 files changed, 110 insertions(+), 98 deletions(-)
 create mode 100644 kernel/module/livepatch.c

diff --git a/include/linux/module.h b/include/linux/module.h
index 1e135fd5c076..7ec9715de7dc 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -663,17 +663,14 @@ static inline bool module_requested_async_probing(struct module *module)
 	return module && module->async_probe_requested;
 }
 
-#ifdef CONFIG_LIVEPATCH
 static inline bool is_livepatch_module(struct module *mod)
 {
+#ifdef CONFIG_LIVEPATCH
 	return mod->klp;
-}
-#else /* !CONFIG_LIVEPATCH */
-static inline bool is_livepatch_module(struct module *mod)
-{
+#else
 	return false;
+#endif
 }
-#endif /* CONFIG_LIVEPATCH */
 
 bool is_module_sig_enforced(void);
 void set_module_sig_enforced(void);
diff --git a/kernel/module/Makefile b/kernel/module/Makefile
index cdd5c61b8c7f..ed3aacb04f17 100644
--- a/kernel/module/Makefile
+++ b/kernel/module/Makefile
@@ -10,3 +10,4 @@ KCOV_INSTRUMENT_module.o := n
 obj-y += main.o
 obj-$(CONFIG_MODULE_DECOMPRESS) += decompress.o
 obj-$(CONFIG_MODULE_SIG) += signing.o
+obj-$(CONFIG_LIVEPATCH) += livepatch.o
diff --git a/kernel/module/internal.h b/kernel/module/internal.h
index e0775e66bcf7..ad7a444253ed 100644
--- a/kernel/module/internal.h
+++ b/kernel/module/internal.h
@@ -57,6 +57,28 @@ struct load_info {
 
 int mod_verify_sig(const void *mod, struct load_info *info);
 
+#ifdef CONFIG_LIVEPATCH
+int copy_module_elf(struct module *mod, struct load_info *info);
+void free_module_elf(struct module *mod);
+#else /* !CONFIG_LIVEPATCH */
+static inline int copy_module_elf(struct module *mod, struct load_info *info)
+{
+	return 0;
+}
+
+static inline void free_module_elf(struct module *mod) { }
+#endif /* CONFIG_LIVEPATCH */
+
+static inline bool set_livepatch_module(struct module *mod)
+{
+#ifdef CONFIG_LIVEPATCH
+	mod->klp = true;
+	return true;
+#else
+	return false;
+#endif
+}
+
 #ifdef CONFIG_MODULE_DECOMPRESS
 int module_decompress(struct load_info *info, const void *buf, size_t size);
 void module_decompress_cleanup(struct load_info *info);
diff --git a/kernel/module/livepatch.c b/kernel/module/livepatch.c
new file mode 100644
index 000000000000..486d4ff92719
--- /dev/null
+++ b/kernel/module/livepatch.c
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Module livepatch support
+ *
+ * Copyright (C) 2016 Jessica Yu <jeyu@redhat.com>
+ */
+
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include "internal.h"
+
+/*
+ * Persist Elf information about a module. Copy the Elf header,
+ * section header table, section string table, and symtab section
+ * index from info to mod->klp_info.
+ */
+int copy_module_elf(struct module *mod, struct load_info *info)
+{
+	unsigned int size, symndx;
+	int ret;
+
+	size = sizeof(*mod->klp_info);
+	mod->klp_info = kmalloc(size, GFP_KERNEL);
+	if (!mod->klp_info)
+		return -ENOMEM;
+
+	/* Elf header */
+	size = sizeof(mod->klp_info->hdr);
+	memcpy(&mod->klp_info->hdr, info->hdr, size);
+
+	/* Elf section header table */
+	size = sizeof(*info->sechdrs) * info->hdr->e_shnum;
+	mod->klp_info->sechdrs = kmemdup(info->sechdrs, size, GFP_KERNEL);
+	if (!mod->klp_info->sechdrs) {
+		ret = -ENOMEM;
+		goto free_info;
+	}
+
+	/* Elf section name string table */
+	size = info->sechdrs[info->hdr->e_shstrndx].sh_size;
+	mod->klp_info->secstrings = kmemdup(info->secstrings, size, GFP_KERNEL);
+	if (!mod->klp_info->secstrings) {
+		ret = -ENOMEM;
+		goto free_sechdrs;
+	}
+
+	/* Elf symbol section index */
+	symndx = info->index.sym;
+	mod->klp_info->symndx = symndx;
+
+	/*
+	 * For livepatch modules, core_kallsyms.symtab is a complete
+	 * copy of the original symbol table. Adjust sh_addr to point
+	 * to core_kallsyms.symtab since the copy of the symtab in module
+	 * init memory is freed at the end of do_init_module().
+	 */
+	mod->klp_info->sechdrs[symndx].sh_addr = (unsigned long)mod->core_kallsyms.symtab;
+
+	return 0;
+
+free_sechdrs:
+	kfree(mod->klp_info->sechdrs);
+free_info:
+	kfree(mod->klp_info);
+	return ret;
+}
+
+void free_module_elf(struct module *mod)
+{
+	kfree(mod->klp_info->sechdrs);
+	kfree(mod->klp_info->secstrings);
+	kfree(mod->klp_info);
+}
diff --git a/kernel/module/main.c b/kernel/module/main.c
index 5f5e21f972dd..3596ebf3a6c3 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -2043,81 +2043,6 @@ static int module_enforce_rwx_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
 }
 #endif /*  CONFIG_STRICT_MODULE_RWX */
 
-#ifdef CONFIG_LIVEPATCH
-/*
- * Persist Elf information about a module. Copy the Elf header,
- * section header table, section string table, and symtab section
- * index from info to mod->klp_info.
- */
-static int copy_module_elf(struct module *mod, struct load_info *info)
-{
-	unsigned int size, symndx;
-	int ret;
-
-	size = sizeof(*mod->klp_info);
-	mod->klp_info = kmalloc(size, GFP_KERNEL);
-	if (mod->klp_info == NULL)
-		return -ENOMEM;
-
-	/* Elf header */
-	size = sizeof(mod->klp_info->hdr);
-	memcpy(&mod->klp_info->hdr, info->hdr, size);
-
-	/* Elf section header table */
-	size = sizeof(*info->sechdrs) * info->hdr->e_shnum;
-	mod->klp_info->sechdrs = kmemdup(info->sechdrs, size, GFP_KERNEL);
-	if (mod->klp_info->sechdrs == NULL) {
-		ret = -ENOMEM;
-		goto free_info;
-	}
-
-	/* Elf section name string table */
-	size = info->sechdrs[info->hdr->e_shstrndx].sh_size;
-	mod->klp_info->secstrings = kmemdup(info->secstrings, size, GFP_KERNEL);
-	if (mod->klp_info->secstrings == NULL) {
-		ret = -ENOMEM;
-		goto free_sechdrs;
-	}
-
-	/* Elf symbol section index */
-	symndx = info->index.sym;
-	mod->klp_info->symndx = symndx;
-
-	/*
-	 * For livepatch modules, core_kallsyms.symtab is a complete
-	 * copy of the original symbol table. Adjust sh_addr to point
-	 * to core_kallsyms.symtab since the copy of the symtab in module
-	 * init memory is freed at the end of do_init_module().
-	 */
-	mod->klp_info->sechdrs[symndx].sh_addr = \
-		(unsigned long) mod->core_kallsyms.symtab;
-
-	return 0;
-
-free_sechdrs:
-	kfree(mod->klp_info->sechdrs);
-free_info:
-	kfree(mod->klp_info);
-	return ret;
-}
-
-static void free_module_elf(struct module *mod)
-{
-	kfree(mod->klp_info->sechdrs);
-	kfree(mod->klp_info->secstrings);
-	kfree(mod->klp_info);
-}
-#else /* !CONFIG_LIVEPATCH */
-static int copy_module_elf(struct module *mod, struct load_info *info)
-{
-	return 0;
-}
-
-static void free_module_elf(struct module *mod)
-{
-}
-#endif /* CONFIG_LIVEPATCH */
-
 void __weak module_memfree(void *module_region)
 {
 	/*
@@ -3092,30 +3017,23 @@ static int copy_chunked_from_user(void *dst, const void __user *usrc, unsigned l
 	return 0;
 }
 
-#ifdef CONFIG_LIVEPATCH
 static int check_modinfo_livepatch(struct module *mod, struct load_info *info)
 {
-	if (get_modinfo(info, "livepatch")) {
-		mod->klp = true;
+	if (!get_modinfo(info, "livepatch"))
+		/* Nothing more to do */
+		return 0;
+
+	if (set_livepatch_module(mod)) {
 		add_taint_module(mod, TAINT_LIVEPATCH, LOCKDEP_STILL_OK);
 		pr_notice_once("%s: tainting kernel with TAINT_LIVEPATCH\n",
-			       mod->name);
-	}
-
-	return 0;
-}
-#else /* !CONFIG_LIVEPATCH */
-static int check_modinfo_livepatch(struct module *mod, struct load_info *info)
-{
-	if (get_modinfo(info, "livepatch")) {
-		pr_err("%s: module is marked as livepatch module, but livepatch support is disabled",
-		       mod->name);
-		return -ENOEXEC;
+				mod->name);
+		return 0;
 	}
 
-	return 0;
+	pr_err("%s: module is marked as livepatch module, but livepatch support is disabled",
+	       mod->name);
+	return -ENOEXEC;
 }
-#endif /* CONFIG_LIVEPATCH */
 
 static void check_modinfo_retpoline(struct module *mod, struct load_info *info)
 {
-- 
2.34.1


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

* [PATCH v8 05/13] module: Move latched RB-tree support to a separate file
  2022-02-22 14:12 [PATCH v8 00/13] module: core code clean up Aaron Tomlin
                   ` (3 preceding siblings ...)
  2022-02-22 14:12 ` [PATCH v8 04/13] module: Move livepatch support to a separate file Aaron Tomlin
@ 2022-02-22 14:12 ` Aaron Tomlin
  2022-02-22 17:58   ` Christophe Leroy
  2022-02-22 14:12 ` [PATCH v8 06/13] module: Move strict rwx " Aaron Tomlin
                   ` (7 subsequent siblings)
  12 siblings, 1 reply; 43+ messages in thread
From: Aaron Tomlin @ 2022-02-22 14:12 UTC (permalink / raw)
  To: mcgrof, christophe.leroy
  Cc: cl, pmladek, mbenes, akpm, jeyu, linux-kernel, linux-modules,
	void, atomlin, allen.lkml, joe, msuchanek, oleksandr

No functional change.

This patch migrates module latched RB-tree support
(e.g. see __module_address()) from core module code
into kernel/module/tree_lookup.c.

Signed-off-by: Aaron Tomlin <atomlin@redhat.com>
---
 kernel/module/Makefile      |   1 +
 kernel/module/internal.h    |  33 +++++++++
 kernel/module/main.c        | 130 ++----------------------------------
 kernel/module/tree_lookup.c | 109 ++++++++++++++++++++++++++++++
 4 files changed, 147 insertions(+), 126 deletions(-)
 create mode 100644 kernel/module/tree_lookup.c

diff --git a/kernel/module/Makefile b/kernel/module/Makefile
index ed3aacb04f17..88774e386276 100644
--- a/kernel/module/Makefile
+++ b/kernel/module/Makefile
@@ -11,3 +11,4 @@ obj-y += main.o
 obj-$(CONFIG_MODULE_DECOMPRESS) += decompress.o
 obj-$(CONFIG_MODULE_SIG) += signing.o
 obj-$(CONFIG_LIVEPATCH) += livepatch.o
+obj-$(CONFIG_MODULES_TREE_LOOKUP) += tree_lookup.o
diff --git a/kernel/module/internal.h b/kernel/module/internal.h
index ad7a444253ed..f1682e3677be 100644
--- a/kernel/module/internal.h
+++ b/kernel/module/internal.h
@@ -9,6 +9,7 @@
 #include <linux/compiler.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
+#include <linux/rculist.h>
 
 #ifndef ARCH_SHF_SMALL
 #define ARCH_SHF_SMALL 0
@@ -93,3 +94,35 @@ static inline void module_decompress_cleanup(struct load_info *info)
 {
 }
 #endif
+
+#ifdef CONFIG_MODULES_TREE_LOOKUP
+struct mod_tree_root {
+	struct latch_tree_root root;
+	unsigned long addr_min;
+	unsigned long addr_max;
+};
+
+extern struct mod_tree_root mod_tree;
+
+void mod_tree_insert(struct module *mod);
+void mod_tree_remove_init(struct module *mod);
+void mod_tree_remove(struct module *mod);
+struct module *mod_find(unsigned long addr);
+#else /* !CONFIG_MODULES_TREE_LOOKUP */
+
+static inline void mod_tree_insert(struct module *mod) { }
+static inline void mod_tree_remove_init(struct module *mod) { }
+static inline void mod_tree_remove(struct module *mod) { }
+static inline struct module *mod_find(unsigned long addr)
+{
+	struct module *mod;
+
+	list_for_each_entry_rcu(mod, &modules, list,
+				lockdep_is_held(&module_mutex)) {
+		if (within_module(addr, mod))
+			return mod;
+	}
+
+	return NULL;
+}
+#endif /* CONFIG_MODULES_TREE_LOOKUP */
diff --git a/kernel/module/main.c b/kernel/module/main.c
index 3596ebf3a6c3..76b53880ad91 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -90,138 +90,16 @@ static DECLARE_WORK(init_free_wq, do_free_init);
 static LLIST_HEAD(init_free_list);
 
 #ifdef CONFIG_MODULES_TREE_LOOKUP
-
-/*
- * Use a latched RB-tree for __module_address(); this allows us to use
- * RCU-sched lookups of the address from any context.
- *
- * This is conditional on PERF_EVENTS || TRACING because those can really hit
- * __module_address() hard by doing a lot of stack unwinding; potentially from
- * NMI context.
- */
-
-static __always_inline unsigned long __mod_tree_val(struct latch_tree_node *n)
-{
-	struct module_layout *layout = container_of(n, struct module_layout, mtn.node);
-
-	return (unsigned long)layout->base;
-}
-
-static __always_inline unsigned long __mod_tree_size(struct latch_tree_node *n)
-{
-	struct module_layout *layout = container_of(n, struct module_layout, mtn.node);
-
-	return (unsigned long)layout->size;
-}
-
-static __always_inline bool
-mod_tree_less(struct latch_tree_node *a, struct latch_tree_node *b)
-{
-	return __mod_tree_val(a) < __mod_tree_val(b);
-}
-
-static __always_inline int
-mod_tree_comp(void *key, struct latch_tree_node *n)
-{
-	unsigned long val = (unsigned long)key;
-	unsigned long start, end;
-
-	start = __mod_tree_val(n);
-	if (val < start)
-		return -1;
-
-	end = start + __mod_tree_size(n);
-	if (val >= end)
-		return 1;
-
-	return 0;
-}
-
-static const struct latch_tree_ops mod_tree_ops = {
-	.less = mod_tree_less,
-	.comp = mod_tree_comp,
-};
-
-static struct mod_tree_root {
-	struct latch_tree_root root;
-	unsigned long addr_min;
-	unsigned long addr_max;
-} mod_tree __cacheline_aligned = {
+struct mod_tree_root mod_tree __cacheline_aligned = {
 	.addr_min = -1UL,
 };
 
 #define module_addr_min mod_tree.addr_min
 #define module_addr_max mod_tree.addr_max
 
-static noinline void __mod_tree_insert(struct mod_tree_node *node)
-{
-	latch_tree_insert(&node->node, &mod_tree.root, &mod_tree_ops);
-}
-
-static void __mod_tree_remove(struct mod_tree_node *node)
-{
-	latch_tree_erase(&node->node, &mod_tree.root, &mod_tree_ops);
-}
-
-/*
- * These modifications: insert, remove_init and remove; are serialized by the
- * module_mutex.
- */
-static void mod_tree_insert(struct module *mod)
-{
-	mod->core_layout.mtn.mod = mod;
-	mod->init_layout.mtn.mod = mod;
-
-	__mod_tree_insert(&mod->core_layout.mtn);
-	if (mod->init_layout.size)
-		__mod_tree_insert(&mod->init_layout.mtn);
-}
-
-static void mod_tree_remove_init(struct module *mod)
-{
-	if (mod->init_layout.size)
-		__mod_tree_remove(&mod->init_layout.mtn);
-}
-
-static void mod_tree_remove(struct module *mod)
-{
-	__mod_tree_remove(&mod->core_layout.mtn);
-	mod_tree_remove_init(mod);
-}
-
-static struct module *mod_find(unsigned long addr)
-{
-	struct latch_tree_node *ltn;
-
-	ltn = latch_tree_find((void *)addr, &mod_tree.root, &mod_tree_ops);
-	if (!ltn)
-		return NULL;
-
-	return container_of(ltn, struct mod_tree_node, node)->mod;
-}
-
-#else /* MODULES_TREE_LOOKUP */
-
-static unsigned long module_addr_min = -1UL, module_addr_max = 0;
-
-static void mod_tree_insert(struct module *mod) { }
-static void mod_tree_remove_init(struct module *mod) { }
-static void mod_tree_remove(struct module *mod) { }
-
-static struct module *mod_find(unsigned long addr)
-{
-	struct module *mod;
-
-	list_for_each_entry_rcu(mod, &modules, list,
-				lockdep_is_held(&module_mutex)) {
-		if (within_module(addr, mod))
-			return mod;
-	}
-
-	return NULL;
-}
-
-#endif /* MODULES_TREE_LOOKUP */
+#else /* !CONFIG_MODULES_TREE_LOOKUP */
+static unsigned long module_addr_min = -1UL, module_addr_max;
+#endif /* CONFIG_MODULES_TREE_LOOKUP */
 
 /*
  * Bounds of module text, for speeding up __module_address.
diff --git a/kernel/module/tree_lookup.c b/kernel/module/tree_lookup.c
new file mode 100644
index 000000000000..0bc4ec3b22ce
--- /dev/null
+++ b/kernel/module/tree_lookup.c
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Modules tree lookup
+ *
+ * Copyright (C) 2015 Peter Zijlstra
+ * Copyright (C) 2015 Rusty Russell
+ */
+
+#include <linux/module.h>
+#include <linux/rbtree_latch.h>
+#include "internal.h"
+
+/*
+ * Use a latched RB-tree for __module_address(); this allows us to use
+ * RCU-sched lookups of the address from any context.
+ *
+ * This is conditional on PERF_EVENTS || TRACING because those can really hit
+ * __module_address() hard by doing a lot of stack unwinding; potentially from
+ * NMI context.
+ */
+
+static __always_inline unsigned long __mod_tree_val(struct latch_tree_node *n)
+{
+	struct module_layout *layout = container_of(n, struct module_layout, mtn.node);
+
+	return (unsigned long)layout->base;
+}
+
+static __always_inline unsigned long __mod_tree_size(struct latch_tree_node *n)
+{
+	struct module_layout *layout = container_of(n, struct module_layout, mtn.node);
+
+	return (unsigned long)layout->size;
+}
+
+static __always_inline bool
+mod_tree_less(struct latch_tree_node *a, struct latch_tree_node *b)
+{
+	return __mod_tree_val(a) < __mod_tree_val(b);
+}
+
+static __always_inline int
+mod_tree_comp(void *key, struct latch_tree_node *n)
+{
+	unsigned long val = (unsigned long)key;
+	unsigned long start, end;
+
+	start = __mod_tree_val(n);
+	if (val < start)
+		return -1;
+
+	end = start + __mod_tree_size(n);
+	if (val >= end)
+		return 1;
+
+	return 0;
+}
+
+static const struct latch_tree_ops mod_tree_ops = {
+	.less = mod_tree_less,
+	.comp = mod_tree_comp,
+};
+
+static noinline void __mod_tree_insert(struct mod_tree_node *node)
+{
+	latch_tree_insert(&node->node, &mod_tree.root, &mod_tree_ops);
+}
+
+static void __mod_tree_remove(struct mod_tree_node *node)
+{
+	latch_tree_erase(&node->node, &mod_tree.root, &mod_tree_ops);
+}
+
+/*
+ * These modifications: insert, remove_init and remove; are serialized by the
+ * module_mutex.
+ */
+void mod_tree_insert(struct module *mod)
+{
+	mod->core_layout.mtn.mod = mod;
+	mod->init_layout.mtn.mod = mod;
+
+	__mod_tree_insert(&mod->core_layout.mtn);
+	if (mod->init_layout.size)
+		__mod_tree_insert(&mod->init_layout.mtn);
+}
+
+void mod_tree_remove_init(struct module *mod)
+{
+	if (mod->init_layout.size)
+		__mod_tree_remove(&mod->init_layout.mtn);
+}
+
+void mod_tree_remove(struct module *mod)
+{
+	__mod_tree_remove(&mod->core_layout.mtn);
+	mod_tree_remove_init(mod);
+}
+
+struct module *mod_find(unsigned long addr)
+{
+	struct latch_tree_node *ltn;
+
+	ltn = latch_tree_find((void *)addr, &mod_tree.root, &mod_tree_ops);
+	if (!ltn)
+		return NULL;
+
+	return container_of(ltn, struct mod_tree_node, node)->mod;
+}
-- 
2.34.1


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

* [PATCH v8 06/13] module: Move strict rwx support to a separate file
  2022-02-22 14:12 [PATCH v8 00/13] module: core code clean up Aaron Tomlin
                   ` (4 preceding siblings ...)
  2022-02-22 14:12 ` [PATCH v8 05/13] module: Move latched RB-tree " Aaron Tomlin
@ 2022-02-22 14:12 ` Aaron Tomlin
  2022-02-22 17:59   ` Christophe Leroy
  2022-02-22 14:12 ` [PATCH v8 07/13] module: Move extra signature support out of core code Aaron Tomlin
                   ` (6 subsequent siblings)
  12 siblings, 1 reply; 43+ messages in thread
From: Aaron Tomlin @ 2022-02-22 14:12 UTC (permalink / raw)
  To: mcgrof, christophe.leroy
  Cc: cl, pmladek, mbenes, akpm, jeyu, linux-kernel, linux-modules,
	void, atomlin, allen.lkml, joe, msuchanek, oleksandr

No functional change.

This patch migrates code that makes module text
and rodata memory read-only and non-text memory
non-executable from core module code into
kernel/module/strict_rwx.c.

Signed-off-by: Aaron Tomlin <atomlin@redhat.com>
---
 kernel/module/Makefile     |  1 +
 kernel/module/internal.h   | 32 ++++++++++++
 kernel/module/main.c       | 99 +-------------------------------------
 kernel/module/strict_rwx.c | 85 ++++++++++++++++++++++++++++++++
 4 files changed, 120 insertions(+), 97 deletions(-)
 create mode 100644 kernel/module/strict_rwx.c

diff --git a/kernel/module/Makefile b/kernel/module/Makefile
index 88774e386276..d313c8472cb3 100644
--- a/kernel/module/Makefile
+++ b/kernel/module/Makefile
@@ -12,3 +12,4 @@ obj-$(CONFIG_MODULE_DECOMPRESS) += decompress.o
 obj-$(CONFIG_MODULE_SIG) += signing.o
 obj-$(CONFIG_LIVEPATCH) += livepatch.o
 obj-$(CONFIG_MODULES_TREE_LOOKUP) += tree_lookup.o
+obj-$(CONFIG_STRICT_MODULE_RWX) += strict_rwx.o
diff --git a/kernel/module/internal.h b/kernel/module/internal.h
index f1682e3677be..a6895bb5598a 100644
--- a/kernel/module/internal.h
+++ b/kernel/module/internal.h
@@ -20,6 +20,17 @@
 /* Maximum number of characters written by module_flags() */
 #define MODULE_FLAGS_BUF_SIZE (TAINT_FLAGS_COUNT + 4)
 
+/*
+ * Modules' sections will be aligned on page boundaries
+ * to ensure complete separation of code and data, but
+ * only when CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y
+ */
+#ifdef CONFIG_ARCH_HAS_STRICT_MODULE_RWX
+# define debug_align(X) PAGE_ALIGN(X)
+#else
+# define debug_align(X) (X)
+#endif
+
 extern struct mutex module_mutex;
 extern struct list_head modules;
 
@@ -126,3 +137,24 @@ static inline struct module *mod_find(unsigned long addr)
 	return NULL;
 }
 #endif /* CONFIG_MODULES_TREE_LOOKUP */
+
+#ifdef CONFIG_ARCH_HAS_STRICT_MODULE_RWX
+void frob_text(const struct module_layout *layout, int (*set_memory)(unsigned long start,
+								     int num_pages));
+#endif /* CONFIG_ARCH_HAS_STRICT_MODULE_RWX */
+
+#ifdef CONFIG_STRICT_MODULE_RWX
+void module_enable_ro(const struct module *mod, bool after_init);
+void module_enable_nx(const struct module *mod);
+int module_enforce_rwx_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
+				char *secstrings, struct module *mod);
+
+#else /* !CONFIG_STRICT_MODULE_RWX */
+static inline void module_enable_nx(const struct module *mod) { }
+static inline void module_enable_ro(const struct module *mod, bool after_init) {}
+static inline int module_enforce_rwx_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
+				       char *secstrings, struct module *mod)
+{
+	return 0;
+}
+#endif /* CONFIG_STRICT_MODULE_RWX */
diff --git a/kernel/module/main.c b/kernel/module/main.c
index 76b53880ad91..5cd63f14b1ef 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -63,17 +63,6 @@
 #define CREATE_TRACE_POINTS
 #include <trace/events/module.h>
 
-/*
- * Modules' sections will be aligned on page boundaries
- * to ensure complete separation of code and data, but
- * only when CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y
- */
-#ifdef CONFIG_ARCH_HAS_STRICT_MODULE_RWX
-# define debug_align(X) ALIGN(X, PAGE_SIZE)
-#else
-# define debug_align(X) (X)
-#endif
-
 /*
  * Mutex protects:
  * 1) List of modules (also safely readable with preempt_disable),
@@ -1819,8 +1808,8 @@ static void mod_sysfs_teardown(struct module *mod)
  * whether we are strict.
  */
 #ifdef CONFIG_ARCH_HAS_STRICT_MODULE_RWX
-static void frob_text(const struct module_layout *layout,
-		      int (*set_memory)(unsigned long start, int num_pages))
+void frob_text(const struct module_layout *layout,
+	       int (*set_memory)(unsigned long start, int num_pages))
 {
 	BUG_ON((unsigned long)layout->base & (PAGE_SIZE-1));
 	BUG_ON((unsigned long)layout->text_size & (PAGE_SIZE-1));
@@ -1837,90 +1826,6 @@ static void module_enable_x(const struct module *mod)
 static void module_enable_x(const struct module *mod) { }
 #endif /* CONFIG_ARCH_HAS_STRICT_MODULE_RWX */
 
-#ifdef CONFIG_STRICT_MODULE_RWX
-static void frob_rodata(const struct module_layout *layout,
-			int (*set_memory)(unsigned long start, int num_pages))
-{
-	BUG_ON((unsigned long)layout->base & (PAGE_SIZE-1));
-	BUG_ON((unsigned long)layout->text_size & (PAGE_SIZE-1));
-	BUG_ON((unsigned long)layout->ro_size & (PAGE_SIZE-1));
-	set_memory((unsigned long)layout->base + layout->text_size,
-		   (layout->ro_size - layout->text_size) >> PAGE_SHIFT);
-}
-
-static void frob_ro_after_init(const struct module_layout *layout,
-				int (*set_memory)(unsigned long start, int num_pages))
-{
-	BUG_ON((unsigned long)layout->base & (PAGE_SIZE-1));
-	BUG_ON((unsigned long)layout->ro_size & (PAGE_SIZE-1));
-	BUG_ON((unsigned long)layout->ro_after_init_size & (PAGE_SIZE-1));
-	set_memory((unsigned long)layout->base + layout->ro_size,
-		   (layout->ro_after_init_size - layout->ro_size) >> PAGE_SHIFT);
-}
-
-static void frob_writable_data(const struct module_layout *layout,
-			       int (*set_memory)(unsigned long start, int num_pages))
-{
-	BUG_ON((unsigned long)layout->base & (PAGE_SIZE-1));
-	BUG_ON((unsigned long)layout->ro_after_init_size & (PAGE_SIZE-1));
-	BUG_ON((unsigned long)layout->size & (PAGE_SIZE-1));
-	set_memory((unsigned long)layout->base + layout->ro_after_init_size,
-		   (layout->size - layout->ro_after_init_size) >> PAGE_SHIFT);
-}
-
-static void module_enable_ro(const struct module *mod, bool after_init)
-{
-	if (!rodata_enabled)
-		return;
-
-	set_vm_flush_reset_perms(mod->core_layout.base);
-	set_vm_flush_reset_perms(mod->init_layout.base);
-	frob_text(&mod->core_layout, set_memory_ro);
-
-	frob_rodata(&mod->core_layout, set_memory_ro);
-	frob_text(&mod->init_layout, set_memory_ro);
-	frob_rodata(&mod->init_layout, set_memory_ro);
-
-	if (after_init)
-		frob_ro_after_init(&mod->core_layout, set_memory_ro);
-}
-
-static void module_enable_nx(const struct module *mod)
-{
-	frob_rodata(&mod->core_layout, set_memory_nx);
-	frob_ro_after_init(&mod->core_layout, set_memory_nx);
-	frob_writable_data(&mod->core_layout, set_memory_nx);
-	frob_rodata(&mod->init_layout, set_memory_nx);
-	frob_writable_data(&mod->init_layout, set_memory_nx);
-}
-
-static int module_enforce_rwx_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
-				       char *secstrings, struct module *mod)
-{
-	const unsigned long shf_wx = SHF_WRITE|SHF_EXECINSTR;
-	int i;
-
-	for (i = 0; i < hdr->e_shnum; i++) {
-		if ((sechdrs[i].sh_flags & shf_wx) == shf_wx) {
-			pr_err("%s: section %s (index %d) has invalid WRITE|EXEC flags\n",
-				mod->name, secstrings + sechdrs[i].sh_name, i);
-			return -ENOEXEC;
-		}
-	}
-
-	return 0;
-}
-
-#else /* !CONFIG_STRICT_MODULE_RWX */
-static void module_enable_nx(const struct module *mod) { }
-static void module_enable_ro(const struct module *mod, bool after_init) {}
-static int module_enforce_rwx_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
-				       char *secstrings, struct module *mod)
-{
-	return 0;
-}
-#endif /*  CONFIG_STRICT_MODULE_RWX */
-
 void __weak module_memfree(void *module_region)
 {
 	/*
diff --git a/kernel/module/strict_rwx.c b/kernel/module/strict_rwx.c
new file mode 100644
index 000000000000..7949dfd449c2
--- /dev/null
+++ b/kernel/module/strict_rwx.c
@@ -0,0 +1,85 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Module strict rwx
+ *
+ * Copyright (C) 2015 Rusty Russell
+ */
+
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/set_memory.h>
+#include "internal.h"
+
+static void frob_rodata(const struct module_layout *layout,
+		 int (*set_memory)(unsigned long start, int num_pages))
+{
+	BUG_ON(!PAGE_ALIGNED(layout->base));
+	BUG_ON(!PAGE_ALIGNED(layout->text_size));
+	BUG_ON(!PAGE_ALIGNED(layout->ro_size));
+	set_memory((unsigned long)layout->base + layout->text_size,
+		   (layout->ro_size - layout->text_size) >> PAGE_SHIFT);
+}
+
+static void frob_ro_after_init(const struct module_layout *layout,
+			int (*set_memory)(unsigned long start, int num_pages))
+{
+	BUG_ON(!PAGE_ALIGNED(layout->base));
+	BUG_ON(!PAGE_ALIGNED(layout->ro_size));
+	BUG_ON(!PAGE_ALIGNED(layout->ro_after_init_size));
+	set_memory((unsigned long)layout->base + layout->ro_size,
+		   (layout->ro_after_init_size - layout->ro_size) >> PAGE_SHIFT);
+}
+
+static void frob_writable_data(const struct module_layout *layout,
+			int (*set_memory)(unsigned long start, int num_pages))
+{
+	BUG_ON(!PAGE_ALIGNED(layout->base));
+	BUG_ON(!PAGE_ALIGNED(layout->ro_after_init_size));
+	BUG_ON(!PAGE_ALIGNED(layout->size));
+	set_memory((unsigned long)layout->base + layout->ro_after_init_size,
+		   (layout->size - layout->ro_after_init_size) >> PAGE_SHIFT);
+}
+
+void module_enable_ro(const struct module *mod, bool after_init)
+{
+	if (!rodata_enabled)
+		return;
+
+	set_vm_flush_reset_perms(mod->core_layout.base);
+	set_vm_flush_reset_perms(mod->init_layout.base);
+	frob_text(&mod->core_layout, set_memory_ro);
+
+	frob_rodata(&mod->core_layout, set_memory_ro);
+	frob_text(&mod->init_layout, set_memory_ro);
+	frob_rodata(&mod->init_layout, set_memory_ro);
+
+	if (after_init)
+		frob_ro_after_init(&mod->core_layout, set_memory_ro);
+}
+
+void module_enable_nx(const struct module *mod)
+{
+	frob_rodata(&mod->core_layout, set_memory_nx);
+	frob_ro_after_init(&mod->core_layout, set_memory_nx);
+	frob_writable_data(&mod->core_layout, set_memory_nx);
+	frob_rodata(&mod->init_layout, set_memory_nx);
+	frob_writable_data(&mod->init_layout, set_memory_nx);
+}
+
+int module_enforce_rwx_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
+				char *secstrings, struct module *mod)
+{
+	const unsigned long shf_wx = SHF_WRITE | SHF_EXECINSTR;
+	int i;
+
+	for (i = 0; i < hdr->e_shnum; i++) {
+		if ((sechdrs[i].sh_flags & shf_wx) == shf_wx) {
+			pr_err("%s: section %s (index %d) has invalid WRITE|EXEC flags\n",
+			       mod->name, secstrings + sechdrs[i].sh_name, i);
+			return -ENOEXEC;
+		}
+	}
+
+	return 0;
+}
-- 
2.34.1


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

* [PATCH v8 07/13] module: Move extra signature support out of core code
  2022-02-22 14:12 [PATCH v8 00/13] module: core code clean up Aaron Tomlin
                   ` (5 preceding siblings ...)
  2022-02-22 14:12 ` [PATCH v8 06/13] module: Move strict rwx " Aaron Tomlin
@ 2022-02-22 14:12 ` Aaron Tomlin
  2022-02-22 17:59   ` Christophe Leroy
  2022-02-22 14:12 ` [PATCH v8 08/13] module: Move kmemleak support to a separate file Aaron Tomlin
                   ` (5 subsequent siblings)
  12 siblings, 1 reply; 43+ messages in thread
From: Aaron Tomlin @ 2022-02-22 14:12 UTC (permalink / raw)
  To: mcgrof, christophe.leroy
  Cc: cl, pmladek, mbenes, akpm, jeyu, linux-kernel, linux-modules,
	void, atomlin, allen.lkml, joe, msuchanek, oleksandr

No functional change.

This patch migrates additional module signature check
code from core module code into kernel/module/signing.c.

Signed-off-by: Aaron Tomlin <atomlin@redhat.com>
---
 kernel/module/internal.h |  9 +++++
 kernel/module/main.c     | 87 ----------------------------------------
 kernel/module/signing.c  | 77 +++++++++++++++++++++++++++++++++++
 3 files changed, 86 insertions(+), 87 deletions(-)

diff --git a/kernel/module/internal.h b/kernel/module/internal.h
index a6895bb5598a..d6f646a5da41 100644
--- a/kernel/module/internal.h
+++ b/kernel/module/internal.h
@@ -158,3 +158,12 @@ static inline int module_enforce_rwx_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
 	return 0;
 }
 #endif /* CONFIG_STRICT_MODULE_RWX */
+
+#ifdef CONFIG_MODULE_SIG
+int module_sig_check(struct load_info *info, int flags);
+#else /* !CONFIG_MODULE_SIG */
+static inline int module_sig_check(struct load_info *info, int flags)
+{
+	return 0;
+}
+#endif /* !CONFIG_MODULE_SIG */
diff --git a/kernel/module/main.c b/kernel/module/main.c
index 5cd63f14b1ef..c63e10c61694 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -23,7 +23,6 @@
 #include <linux/vmalloc.h>
 #include <linux/elf.h>
 #include <linux/proc_fs.h>
-#include <linux/security.h>
 #include <linux/seq_file.h>
 #include <linux/syscalls.h>
 #include <linux/fcntl.h>
@@ -127,28 +126,6 @@ static void module_assert_mutex_or_preempt(void)
 #endif
 }
 
-#ifdef CONFIG_MODULE_SIG
-static bool sig_enforce = IS_ENABLED(CONFIG_MODULE_SIG_FORCE);
-module_param(sig_enforce, bool_enable_only, 0644);
-
-void set_module_sig_enforced(void)
-{
-	sig_enforce = true;
-}
-#else
-#define sig_enforce false
-#endif
-
-/*
- * Export sig_enforce kernel cmdline parameter to allow other subsystems rely
- * on that instead of directly to CONFIG_MODULE_SIG_FORCE config.
- */
-bool is_module_sig_enforced(void)
-{
-	return sig_enforce;
-}
-EXPORT_SYMBOL(is_module_sig_enforced);
-
 /* Block module loading/unloading? */
 int modules_disabled = 0;
 core_param(nomodule, modules_disabled, bint, 0);
@@ -2569,70 +2546,6 @@ static inline void kmemleak_load_module(const struct module *mod,
 }
 #endif
 
-#ifdef CONFIG_MODULE_SIG
-static int module_sig_check(struct load_info *info, int flags)
-{
-	int err = -ENODATA;
-	const unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1;
-	const char *reason;
-	const void *mod = info->hdr;
-	bool mangled_module = flags & (MODULE_INIT_IGNORE_MODVERSIONS |
-				       MODULE_INIT_IGNORE_VERMAGIC);
-	/*
-	 * Do not allow mangled modules as a module with version information
-	 * removed is no longer the module that was signed.
-	 */
-	if (!mangled_module &&
-	    info->len > markerlen &&
-	    memcmp(mod + info->len - markerlen, MODULE_SIG_STRING, markerlen) == 0) {
-		/* We truncate the module to discard the signature */
-		info->len -= markerlen;
-		err = mod_verify_sig(mod, info);
-		if (!err) {
-			info->sig_ok = true;
-			return 0;
-		}
-	}
-
-	/*
-	 * We don't permit modules to be loaded into the trusted kernels
-	 * without a valid signature on them, but if we're not enforcing,
-	 * certain errors are non-fatal.
-	 */
-	switch (err) {
-	case -ENODATA:
-		reason = "unsigned module";
-		break;
-	case -ENOPKG:
-		reason = "module with unsupported crypto";
-		break;
-	case -ENOKEY:
-		reason = "module with unavailable key";
-		break;
-
-	default:
-		/*
-		 * All other errors are fatal, including lack of memory,
-		 * unparseable signatures, and signature check failures --
-		 * even if signatures aren't required.
-		 */
-		return err;
-	}
-
-	if (is_module_sig_enforced()) {
-		pr_notice("Loading of %s is rejected\n", reason);
-		return -EKEYREJECTED;
-	}
-
-	return security_locked_down(LOCKDOWN_MODULE_SIGNATURE);
-}
-#else /* !CONFIG_MODULE_SIG */
-static int module_sig_check(struct load_info *info, int flags)
-{
-	return 0;
-}
-#endif /* !CONFIG_MODULE_SIG */
-
 static int validate_section_offset(struct load_info *info, Elf_Shdr *shdr)
 {
 #if defined(CONFIG_64BIT)
diff --git a/kernel/module/signing.c b/kernel/module/signing.c
index 8aeb6d2ee94b..85c8999dfecf 100644
--- a/kernel/module/signing.c
+++ b/kernel/module/signing.c
@@ -11,9 +11,29 @@
 #include <linux/module_signature.h>
 #include <linux/string.h>
 #include <linux/verification.h>
+#include <linux/security.h>
 #include <crypto/public_key.h>
+#include <uapi/linux/module.h>
 #include "internal.h"
 
+static bool sig_enforce = IS_ENABLED(CONFIG_MODULE_SIG_FORCE);
+module_param(sig_enforce, bool_enable_only, 0644);
+
+/*
+ * Export sig_enforce kernel cmdline parameter to allow other subsystems rely
+ * on that instead of directly to CONFIG_MODULE_SIG_FORCE config.
+ */
+bool is_module_sig_enforced(void)
+{
+	return sig_enforce;
+}
+EXPORT_SYMBOL(is_module_sig_enforced);
+
+void set_module_sig_enforced(void)
+{
+	sig_enforce = true;
+}
+
 /*
  * Verify the signature on a module.
  */
@@ -43,3 +63,60 @@ int mod_verify_sig(const void *mod, struct load_info *info)
 				      VERIFYING_MODULE_SIGNATURE,
 				      NULL, NULL);
 }
+
+int module_sig_check(struct load_info *info, int flags)
+{
+	int err = -ENODATA;
+	const unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1;
+	const char *reason;
+	const void *mod = info->hdr;
+	bool mangled_module = flags & (MODULE_INIT_IGNORE_MODVERSIONS |
+				       MODULE_INIT_IGNORE_VERMAGIC);
+	/*
+	 * Do not allow mangled modules as a module with version information
+	 * removed is no longer the module that was signed.
+	 */
+	if (!mangled_module &&
+	    info->len > markerlen &&
+	    memcmp(mod + info->len - markerlen, MODULE_SIG_STRING, markerlen) == 0) {
+		/* We truncate the module to discard the signature */
+		info->len -= markerlen;
+		err = mod_verify_sig(mod, info);
+		if (!err) {
+			info->sig_ok = true;
+			return 0;
+		}
+	}
+
+	/*
+	 * We don't permit modules to be loaded into the trusted kernels
+	 * without a valid signature on them, but if we're not enforcing,
+	 * certain errors are non-fatal.
+	 */
+	switch (err) {
+	case -ENODATA:
+		reason = "unsigned module";
+		break;
+	case -ENOPKG:
+		reason = "module with unsupported crypto";
+		break;
+	case -ENOKEY:
+		reason = "module with unavailable key";
+		break;
+
+	default:
+		/*
+		 * All other errors are fatal, including lack of memory,
+		 * unparseable signatures, and signature check failures --
+		 * even if signatures aren't required.
+		 */
+		return err;
+	}
+
+	if (is_module_sig_enforced()) {
+		pr_notice("Loading of %s is rejected\n", reason);
+		return -EKEYREJECTED;
+	}
+
+	return security_locked_down(LOCKDOWN_MODULE_SIGNATURE);
+}
-- 
2.34.1


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

* [PATCH v8 08/13] module: Move kmemleak support to a separate file
  2022-02-22 14:12 [PATCH v8 00/13] module: core code clean up Aaron Tomlin
                   ` (6 preceding siblings ...)
  2022-02-22 14:12 ` [PATCH v8 07/13] module: Move extra signature support out of core code Aaron Tomlin
@ 2022-02-22 14:12 ` Aaron Tomlin
  2022-02-22 17:59   ` Christophe Leroy
  2022-02-22 14:12 ` [PATCH v8 09/13] module: Move kallsyms support into " Aaron Tomlin
                   ` (4 subsequent siblings)
  12 siblings, 1 reply; 43+ messages in thread
From: Aaron Tomlin @ 2022-02-22 14:12 UTC (permalink / raw)
  To: mcgrof, christophe.leroy
  Cc: cl, pmladek, mbenes, akpm, jeyu, linux-kernel, linux-modules,
	void, atomlin, allen.lkml, joe, msuchanek, oleksandr

No functional change.

This patch migrates kmemleak code out of core module
code into kernel/module/debug_kmemleak.c

Signed-off-by: Aaron Tomlin <atomlin@redhat.com>
---
 kernel/module/Makefile         |  1 +
 kernel/module/debug_kmemleak.c | 30 ++++++++++++++++++++++++++++++
 kernel/module/internal.h       |  7 +++++++
 kernel/module/main.c           | 27 ---------------------------
 4 files changed, 38 insertions(+), 27 deletions(-)
 create mode 100644 kernel/module/debug_kmemleak.c

diff --git a/kernel/module/Makefile b/kernel/module/Makefile
index d313c8472cb3..12388627725c 100644
--- a/kernel/module/Makefile
+++ b/kernel/module/Makefile
@@ -13,3 +13,4 @@ obj-$(CONFIG_MODULE_SIG) += signing.o
 obj-$(CONFIG_LIVEPATCH) += livepatch.o
 obj-$(CONFIG_MODULES_TREE_LOOKUP) += tree_lookup.o
 obj-$(CONFIG_STRICT_MODULE_RWX) += strict_rwx.o
+obj-$(CONFIG_DEBUG_KMEMLEAK) += debug_kmemleak.o
diff --git a/kernel/module/debug_kmemleak.c b/kernel/module/debug_kmemleak.c
new file mode 100644
index 000000000000..12a569d361e8
--- /dev/null
+++ b/kernel/module/debug_kmemleak.c
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Module kmemleak support
+ *
+ * Copyright (C) 2009 Catalin Marinas
+ */
+
+#include <linux/module.h>
+#include <linux/kmemleak.h>
+#include "internal.h"
+
+void kmemleak_load_module(const struct module *mod,
+			  const struct load_info *info)
+{
+	unsigned int i;
+
+	/* only scan the sections containing data */
+	kmemleak_scan_area(mod, sizeof(struct module), GFP_KERNEL);
+
+	for (i = 1; i < info->hdr->e_shnum; i++) {
+		/* Scan all writable sections that's not executable */
+		if (!(info->sechdrs[i].sh_flags & SHF_ALLOC) ||
+		    !(info->sechdrs[i].sh_flags & SHF_WRITE) ||
+		    (info->sechdrs[i].sh_flags & SHF_EXECINSTR))
+			continue;
+
+		kmemleak_scan_area((void *)info->sechdrs[i].sh_addr,
+				   info->sechdrs[i].sh_size, GFP_KERNEL);
+	}
+}
diff --git a/kernel/module/internal.h b/kernel/module/internal.h
index d6f646a5da41..b0c360839f63 100644
--- a/kernel/module/internal.h
+++ b/kernel/module/internal.h
@@ -167,3 +167,10 @@ static inline int module_sig_check(struct load_info *info, int flags)
 	return 0;
 }
 #endif /* !CONFIG_MODULE_SIG */
+
+#ifdef CONFIG_DEBUG_KMEMLEAK
+void kmemleak_load_module(const struct module *mod, const struct load_info *info);
+#else /* !CONFIG_DEBUG_KMEMLEAK */
+static inline void kmemleak_load_module(const struct module *mod,
+					const struct load_info *info) { }
+#endif /* CONFIG_DEBUG_KMEMLEAK */
diff --git a/kernel/module/main.c b/kernel/module/main.c
index c63e10c61694..7dd283959c5c 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -2519,33 +2519,6 @@ bool __weak module_exit_section(const char *name)
 	return strstarts(name, ".exit");
 }
 
-#ifdef CONFIG_DEBUG_KMEMLEAK
-static void kmemleak_load_module(const struct module *mod,
-				 const struct load_info *info)
-{
-	unsigned int i;
-
-	/* only scan the sections containing data */
-	kmemleak_scan_area(mod, sizeof(struct module), GFP_KERNEL);
-
-	for (i = 1; i < info->hdr->e_shnum; i++) {
-		/* Scan all writable sections that's not executable */
-		if (!(info->sechdrs[i].sh_flags & SHF_ALLOC) ||
-		    !(info->sechdrs[i].sh_flags & SHF_WRITE) ||
-		    (info->sechdrs[i].sh_flags & SHF_EXECINSTR))
-			continue;
-
-		kmemleak_scan_area((void *)info->sechdrs[i].sh_addr,
-				   info->sechdrs[i].sh_size, GFP_KERNEL);
-	}
-}
-#else
-static inline void kmemleak_load_module(const struct module *mod,
-					const struct load_info *info)
-{
-}
-#endif
-
 static int validate_section_offset(struct load_info *info, Elf_Shdr *shdr)
 {
 #if defined(CONFIG_64BIT)
-- 
2.34.1


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

* [PATCH v8 09/13] module: Move kallsyms support into a separate file
  2022-02-22 14:12 [PATCH v8 00/13] module: core code clean up Aaron Tomlin
                   ` (7 preceding siblings ...)
  2022-02-22 14:12 ` [PATCH v8 08/13] module: Move kmemleak support to a separate file Aaron Tomlin
@ 2022-02-22 14:12 ` Aaron Tomlin
  2022-02-22 17:59   ` Christophe Leroy
  2022-02-25  9:15   ` Petr Mladek
  2022-02-22 14:13 ` [PATCH v8 10/13] module: Move procfs " Aaron Tomlin
                   ` (3 subsequent siblings)
  12 siblings, 2 replies; 43+ messages in thread
From: Aaron Tomlin @ 2022-02-22 14:12 UTC (permalink / raw)
  To: mcgrof, christophe.leroy
  Cc: cl, pmladek, mbenes, akpm, jeyu, linux-kernel, linux-modules,
	void, atomlin, allen.lkml, joe, msuchanek, oleksandr

No functional change.

This patch migrates kallsyms code out of core module
code kernel/module/kallsyms.c

Signed-off-by: Aaron Tomlin <atomlin@redhat.com>
---
 kernel/module/Makefile   |   1 +
 kernel/module/internal.h |  29 +++
 kernel/module/kallsyms.c | 506 +++++++++++++++++++++++++++++++++++++
 kernel/module/main.c     | 531 +--------------------------------------
 4 files changed, 542 insertions(+), 525 deletions(-)
 create mode 100644 kernel/module/kallsyms.c

diff --git a/kernel/module/Makefile b/kernel/module/Makefile
index 12388627725c..9901bed3ab5b 100644
--- a/kernel/module/Makefile
+++ b/kernel/module/Makefile
@@ -14,3 +14,4 @@ obj-$(CONFIG_LIVEPATCH) += livepatch.o
 obj-$(CONFIG_MODULES_TREE_LOOKUP) += tree_lookup.o
 obj-$(CONFIG_STRICT_MODULE_RWX) += strict_rwx.o
 obj-$(CONFIG_DEBUG_KMEMLEAK) += debug_kmemleak.o
+obj-$(CONFIG_KALLSYMS) += kallsyms.o
diff --git a/kernel/module/internal.h b/kernel/module/internal.h
index b0c360839f63..44ca05b9eb8f 100644
--- a/kernel/module/internal.h
+++ b/kernel/module/internal.h
@@ -68,6 +68,19 @@ struct load_info {
 };
 
 int mod_verify_sig(const void *mod, struct load_info *info);
+struct module *find_module_all(const char *name, size_t len, bool even_unformed);
+int cmp_name(const void *name, const void *sym);
+long module_get_offset(struct module *mod, unsigned int *size, Elf_Shdr *sechdr,
+		       unsigned int section);
+
+static inline unsigned long kernel_symbol_value(const struct kernel_symbol *sym)
+{
+#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
+	return (unsigned long)offset_to_ptr(&sym->value_offset);
+#else
+	return sym->value;
+#endif
+}
 
 #ifdef CONFIG_LIVEPATCH
 int copy_module_elf(struct module *mod, struct load_info *info);
@@ -174,3 +187,19 @@ void kmemleak_load_module(const struct module *mod, const struct load_info *info
 static inline void kmemleak_load_module(const struct module *mod,
 					const struct load_info *info) { }
 #endif /* CONFIG_DEBUG_KMEMLEAK */
+
+#ifdef CONFIG_KALLSYMS
+void init_build_id(struct module *mod, const struct load_info *info);
+void layout_symtab(struct module *mod, struct load_info *info);
+void add_kallsyms(struct module *mod, const struct load_info *info);
+unsigned long find_kallsyms_symbol_value(struct module *mod, const char *name);
+
+static inline bool sect_empty(const Elf_Shdr *sect)
+{
+	return !(sect->sh_flags & SHF_ALLOC) || sect->sh_size == 0;
+}
+#else /* !CONFIG_KALLSYMS */
+static inline void init_build_id(struct module *mod, const struct load_info *info) { }
+static inline void layout_symtab(struct module *mod, struct load_info *info) { }
+static inline void add_kallsyms(struct module *mod, const struct load_info *info) { }
+#endif /* CONFIG_KALLSYMS */
diff --git a/kernel/module/kallsyms.c b/kernel/module/kallsyms.c
new file mode 100644
index 000000000000..b6d49bb5afed
--- /dev/null
+++ b/kernel/module/kallsyms.c
@@ -0,0 +1,506 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Module kallsyms support
+ *
+ * Copyright (C) 2010 Rusty Russell
+ */
+
+#include <linux/module.h>
+#include <linux/kallsyms.h>
+#include <linux/buildid.h>
+#include <linux/bsearch.h>
+#include "internal.h"
+
+/* Lookup exported symbol in given range of kernel_symbols */
+static const struct kernel_symbol *lookup_exported_symbol(const char *name,
+							  const struct kernel_symbol *start,
+							  const struct kernel_symbol *stop)
+{
+	return bsearch(name, start, stop - start,
+			sizeof(struct kernel_symbol), cmp_name);
+}
+
+static int is_exported(const char *name, unsigned long value,
+		       const struct module *mod)
+{
+	const struct kernel_symbol *ks;
+
+	if (!mod)
+		ks = lookup_exported_symbol(name, __start___ksymtab, __stop___ksymtab);
+	else
+		ks = lookup_exported_symbol(name, mod->syms, mod->syms + mod->num_syms);
+
+	return ks && kernel_symbol_value(ks) == value;
+}
+
+/* As per nm */
+static char elf_type(const Elf_Sym *sym, const struct load_info *info)
+{
+	const Elf_Shdr *sechdrs = info->sechdrs;
+
+	if (ELF_ST_BIND(sym->st_info) == STB_WEAK) {
+		if (ELF_ST_TYPE(sym->st_info) == STT_OBJECT)
+			return 'v';
+		else
+			return 'w';
+	}
+	if (sym->st_shndx == SHN_UNDEF)
+		return 'U';
+	if (sym->st_shndx == SHN_ABS || sym->st_shndx == info->index.pcpu)
+		return 'a';
+	if (sym->st_shndx >= SHN_LORESERVE)
+		return '?';
+	if (sechdrs[sym->st_shndx].sh_flags & SHF_EXECINSTR)
+		return 't';
+	if (sechdrs[sym->st_shndx].sh_flags & SHF_ALLOC &&
+	    sechdrs[sym->st_shndx].sh_type != SHT_NOBITS) {
+		if (!(sechdrs[sym->st_shndx].sh_flags & SHF_WRITE))
+			return 'r';
+		else if (sechdrs[sym->st_shndx].sh_flags & ARCH_SHF_SMALL)
+			return 'g';
+		else
+			return 'd';
+	}
+	if (sechdrs[sym->st_shndx].sh_type == SHT_NOBITS) {
+		if (sechdrs[sym->st_shndx].sh_flags & ARCH_SHF_SMALL)
+			return 's';
+		else
+			return 'b';
+	}
+	if (strstarts(info->secstrings + sechdrs[sym->st_shndx].sh_name,
+		      ".debug")) {
+		return 'n';
+	}
+	return '?';
+}
+
+static bool is_core_symbol(const Elf_Sym *src, const Elf_Shdr *sechdrs,
+			   unsigned int shnum, unsigned int pcpundx)
+{
+	const Elf_Shdr *sec;
+
+	if (src->st_shndx == SHN_UNDEF ||
+	    src->st_shndx >= shnum ||
+	    !src->st_name)
+		return false;
+
+#ifdef CONFIG_KALLSYMS_ALL
+	if (src->st_shndx == pcpundx)
+		return true;
+#endif
+
+	sec = sechdrs + src->st_shndx;
+	if (!(sec->sh_flags & SHF_ALLOC)
+#ifndef CONFIG_KALLSYMS_ALL
+	    || !(sec->sh_flags & SHF_EXECINSTR)
+#endif
+	    || (sec->sh_entsize & INIT_OFFSET_MASK))
+		return false;
+
+	return true;
+}
+
+/*
+ * We only allocate and copy the strings needed by the parts of symtab
+ * we keep.  This is simple, but has the effect of making multiple
+ * copies of duplicates.  We could be more sophisticated, see
+ * linux-kernel thread starting with
+ * <73defb5e4bca04a6431392cc341112b1@localhost>.
+ */
+void layout_symtab(struct module *mod, struct load_info *info)
+{
+	Elf_Shdr *symsect = info->sechdrs + info->index.sym;
+	Elf_Shdr *strsect = info->sechdrs + info->index.str;
+	const Elf_Sym *src;
+	unsigned int i, nsrc, ndst, strtab_size = 0;
+
+	/* Put symbol section at end of init part of module. */
+	symsect->sh_flags |= SHF_ALLOC;
+	symsect->sh_entsize = module_get_offset(mod, &mod->init_layout.size, symsect,
+						info->index.sym) | INIT_OFFSET_MASK;
+	pr_debug("\t%s\n", info->secstrings + symsect->sh_name);
+
+	src = (void *)info->hdr + symsect->sh_offset;
+	nsrc = symsect->sh_size / sizeof(*src);
+
+	/* Compute total space required for the core symbols' strtab. */
+	for (ndst = i = 0; i < nsrc; i++) {
+		if (i == 0 || is_livepatch_module(mod) ||
+		    is_core_symbol(src + i, info->sechdrs, info->hdr->e_shnum,
+				   info->index.pcpu)) {
+			strtab_size += strlen(&info->strtab[src[i].st_name]) + 1;
+			ndst++;
+		}
+	}
+
+	/* Append room for core symbols at end of core part. */
+	info->symoffs = ALIGN(mod->core_layout.size, symsect->sh_addralign ?: 1);
+	info->stroffs = mod->core_layout.size = info->symoffs + ndst * sizeof(Elf_Sym);
+	mod->core_layout.size += strtab_size;
+	info->core_typeoffs = mod->core_layout.size;
+	mod->core_layout.size += ndst * sizeof(char);
+	mod->core_layout.size = debug_align(mod->core_layout.size);
+
+	/* Put string table section at end of init part of module. */
+	strsect->sh_flags |= SHF_ALLOC;
+	strsect->sh_entsize = module_get_offset(mod, &mod->init_layout.size, strsect,
+						info->index.str) | INIT_OFFSET_MASK;
+	pr_debug("\t%s\n", info->secstrings + strsect->sh_name);
+
+	/* We'll tack temporary mod_kallsyms on the end. */
+	mod->init_layout.size = ALIGN(mod->init_layout.size,
+				      __alignof__(struct mod_kallsyms));
+	info->mod_kallsyms_init_off = mod->init_layout.size;
+	mod->init_layout.size += sizeof(struct mod_kallsyms);
+	info->init_typeoffs = mod->init_layout.size;
+	mod->init_layout.size += nsrc * sizeof(char);
+	mod->init_layout.size = debug_align(mod->init_layout.size);
+}
+
+/*
+ * We use the full symtab and strtab which layout_symtab arranged to
+ * be appended to the init section.  Later we switch to the cut-down
+ * core-only ones.
+ */
+void add_kallsyms(struct module *mod, const struct load_info *info)
+{
+	unsigned int i, ndst;
+	const Elf_Sym *src;
+	Elf_Sym *dst;
+	char *s;
+	Elf_Shdr *symsec = &info->sechdrs[info->index.sym];
+
+	/* Set up to point into init section. */
+	mod->kallsyms = (void __rcu *)mod->init_layout.base +
+		info->mod_kallsyms_init_off;
+
+	/* The following is safe since this pointer cannot change */
+	rcu_dereference_sched(mod->kallsyms)->symtab = (void *)symsec->sh_addr;
+	rcu_dereference_sched(mod->kallsyms)->num_symtab = symsec->sh_size / sizeof(Elf_Sym);
+	/* Make sure we get permanent strtab: don't use info->strtab. */
+	rcu_dereference_sched(mod->kallsyms)->strtab =
+		(void *)info->sechdrs[info->index.str].sh_addr;
+	rcu_dereference_sched(mod->kallsyms)->typetab =
+		mod->init_layout.base + info->init_typeoffs;
+
+	/*
+	 * Now populate the cut down core kallsyms for after init
+	 * and set types up while we still have access to sections.
+	 */
+	mod->core_kallsyms.symtab = dst = mod->core_layout.base + info->symoffs;
+	mod->core_kallsyms.strtab = s = mod->core_layout.base + info->stroffs;
+	mod->core_kallsyms.typetab = mod->core_layout.base + info->core_typeoffs;
+	src = rcu_dereference_sched(mod->kallsyms)->symtab;
+	for (ndst = i = 0; i < rcu_dereference_sched(mod->kallsyms)->num_symtab; i++) {
+		rcu_dereference_sched(mod->kallsyms)->typetab[i] = elf_type(src + i, info);
+		if (i == 0 || is_livepatch_module(mod) ||
+		    is_core_symbol(src + i, info->sechdrs, info->hdr->e_shnum,
+				   info->index.pcpu)) {
+			mod->core_kallsyms.typetab[ndst] =
+			    rcu_dereference_sched(mod->kallsyms)->typetab[i];
+			dst[ndst] = src[i];
+			dst[ndst++].st_name = s - mod->core_kallsyms.strtab;
+			s += strscpy(s,
+				     &rcu_dereference_sched(mod->kallsyms)->strtab[src[i].st_name],
+				     KSYM_NAME_LEN) + 1;
+		}
+	}
+	mod->core_kallsyms.num_symtab = ndst;
+}
+
+#if IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID)
+void init_build_id(struct module *mod, const struct load_info *info)
+{
+	const Elf_Shdr *sechdr;
+	unsigned int i;
+
+	for (i = 0; i < info->hdr->e_shnum; i++) {
+		sechdr = &info->sechdrs[i];
+		if (!sect_empty(sechdr) && sechdr->sh_type == SHT_NOTE &&
+		    !build_id_parse_buf((void *)sechdr->sh_addr, mod->build_id,
+					sechdr->sh_size))
+			break;
+	}
+}
+#else
+void init_build_id(struct module *mod, const struct load_info *info)
+{
+}
+#endif
+
+/*
+ * This ignores the intensely annoying "mapping symbols" found
+ * in ARM ELF files: $a, $t and $d.
+ */
+static inline int is_arm_mapping_symbol(const char *str)
+{
+	if (str[0] == '.' && str[1] == 'L')
+		return true;
+	return str[0] == '$' && strchr("axtd", str[1]) &&
+	       (str[2] == '\0' || str[2] == '.');
+}
+
+static const char *kallsyms_symbol_name(struct mod_kallsyms *kallsyms, unsigned int symnum)
+{
+	return kallsyms->strtab + kallsyms->symtab[symnum].st_name;
+}
+
+/*
+ * Given a module and address, find the corresponding symbol and return its name
+ * while providing its size and offset if needed.
+ */
+static const char *find_kallsyms_symbol(struct module *mod,
+					unsigned long addr,
+					unsigned long *size,
+					unsigned long *offset)
+{
+	unsigned int i, best = 0;
+	unsigned long nextval, bestval;
+	struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms);
+
+	/* At worse, next value is at end of module */
+	if (within_module_init(addr, mod))
+		nextval = (unsigned long)mod->init_layout.base + mod->init_layout.text_size;
+	else
+		nextval = (unsigned long)mod->core_layout.base + mod->core_layout.text_size;
+
+	bestval = kallsyms_symbol_value(&kallsyms->symtab[best]);
+
+	/*
+	 * Scan for closest preceding symbol, and next symbol. (ELF
+	 * starts real symbols at 1).
+	 */
+	for (i = 1; i < kallsyms->num_symtab; i++) {
+		const Elf_Sym *sym = &kallsyms->symtab[i];
+		unsigned long thisval = kallsyms_symbol_value(sym);
+
+		if (sym->st_shndx == SHN_UNDEF)
+			continue;
+
+		/*
+		 * We ignore unnamed symbols: they're uninformative
+		 * and inserted at a whim.
+		 */
+		if (*kallsyms_symbol_name(kallsyms, i) == '\0' ||
+		    is_arm_mapping_symbol(kallsyms_symbol_name(kallsyms, i)))
+			continue;
+
+		if (thisval <= addr && thisval > bestval) {
+			best = i;
+			bestval = thisval;
+		}
+		if (thisval > addr && thisval < nextval)
+			nextval = thisval;
+	}
+
+	if (!best)
+		return NULL;
+
+	if (size)
+		*size = nextval - bestval;
+	if (offset)
+		*offset = addr - bestval;
+
+	return kallsyms_symbol_name(kallsyms, best);
+}
+
+void * __weak dereference_module_function_descriptor(struct module *mod,
+						     void *ptr)
+{
+	return ptr;
+}
+
+/*
+ * For kallsyms to ask for address resolution.  NULL means not found.  Careful
+ * not to lock to avoid deadlock on oopses, simply disable preemption.
+ */
+const char *module_address_lookup(unsigned long addr,
+				  unsigned long *size,
+			    unsigned long *offset,
+			    char **modname,
+			    const unsigned char **modbuildid,
+			    char *namebuf)
+{
+	const char *ret = NULL;
+	struct module *mod;
+
+	preempt_disable();
+	mod = __module_address(addr);
+	if (mod) {
+		if (modname)
+			*modname = mod->name;
+		if (modbuildid) {
+#if IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID)
+			*modbuildid = mod->build_id;
+#else
+			*modbuildid = NULL;
+#endif
+		}
+
+		ret = find_kallsyms_symbol(mod, addr, size, offset);
+	}
+	/* Make a copy in here where it's safe */
+	if (ret) {
+		strncpy(namebuf, ret, KSYM_NAME_LEN - 1);
+		ret = namebuf;
+	}
+	preempt_enable();
+
+	return ret;
+}
+
+int lookup_module_symbol_name(unsigned long addr, char *symname)
+{
+	struct module *mod;
+
+	preempt_disable();
+	list_for_each_entry_rcu(mod, &modules, list) {
+		if (mod->state == MODULE_STATE_UNFORMED)
+			continue;
+		if (within_module(addr, mod)) {
+			const char *sym;
+
+			sym = find_kallsyms_symbol(mod, addr, NULL, NULL);
+			if (!sym)
+				goto out;
+
+			strscpy(symname, sym, KSYM_NAME_LEN);
+			preempt_enable();
+			return 0;
+		}
+	}
+out:
+	preempt_enable();
+	return -ERANGE;
+}
+
+int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size,
+			       unsigned long *offset, char *modname, char *name)
+{
+	struct module *mod;
+
+	preempt_disable();
+	list_for_each_entry_rcu(mod, &modules, list) {
+		if (mod->state == MODULE_STATE_UNFORMED)
+			continue;
+		if (within_module(addr, mod)) {
+			const char *sym;
+
+			sym = find_kallsyms_symbol(mod, addr, size, offset);
+			if (!sym)
+				goto out;
+			if (modname)
+				strscpy(modname, mod->name, MODULE_NAME_LEN);
+			if (name)
+				strscpy(name, sym, KSYM_NAME_LEN);
+			preempt_enable();
+			return 0;
+		}
+	}
+out:
+	preempt_enable();
+	return -ERANGE;
+}
+
+int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
+		       char *name, char *module_name, int *exported)
+{
+	struct module *mod;
+
+	preempt_disable();
+	list_for_each_entry_rcu(mod, &modules, list) {
+		struct mod_kallsyms *kallsyms;
+
+		if (mod->state == MODULE_STATE_UNFORMED)
+			continue;
+		kallsyms = rcu_dereference_sched(mod->kallsyms);
+		if (symnum < kallsyms->num_symtab) {
+			const Elf_Sym *sym = &kallsyms->symtab[symnum];
+
+			*value = kallsyms_symbol_value(sym);
+			*type = kallsyms->typetab[symnum];
+			strscpy(name, kallsyms_symbol_name(kallsyms, symnum), KSYM_NAME_LEN);
+			strscpy(module_name, mod->name, MODULE_NAME_LEN);
+			*exported = is_exported(name, *value, mod);
+			preempt_enable();
+			return 0;
+		}
+		symnum -= kallsyms->num_symtab;
+	}
+	preempt_enable();
+	return -ERANGE;
+}
+
+/* Given a module and name of symbol, find and return the symbol's value */
+unsigned long find_kallsyms_symbol_value(struct module *mod, const char *name)
+{
+	unsigned int i;
+	struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms);
+
+	for (i = 0; i < kallsyms->num_symtab; i++) {
+		const Elf_Sym *sym = &kallsyms->symtab[i];
+
+		if (strcmp(name, kallsyms_symbol_name(kallsyms, i)) == 0 &&
+		    sym->st_shndx != SHN_UNDEF)
+			return kallsyms_symbol_value(sym);
+	}
+	return 0;
+}
+
+/* Look for this name: can be of form module:name. */
+unsigned long module_kallsyms_lookup_name(const char *name)
+{
+	struct module *mod;
+	char *colon;
+	unsigned long ret = 0;
+
+	/* Don't lock: we're in enough trouble already. */
+	preempt_disable();
+	if ((colon = strnchr(name, MODULE_NAME_LEN, ':')) != NULL) {
+		if ((mod = find_module_all(name, colon - name, false)) != NULL)
+			ret = find_kallsyms_symbol_value(mod, colon + 1);
+	} else {
+		list_for_each_entry_rcu(mod, &modules, list) {
+			if (mod->state == MODULE_STATE_UNFORMED)
+				continue;
+			if ((ret = find_kallsyms_symbol_value(mod, name)) != 0)
+				break;
+		}
+	}
+	preempt_enable();
+	return ret;
+}
+
+#ifdef CONFIG_LIVEPATCH
+int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *,
+					     struct module *, unsigned long),
+				   void *data)
+{
+	struct module *mod;
+	unsigned int i;
+	int ret = 0;
+
+	mutex_lock(&module_mutex);
+	list_for_each_entry(mod, &modules, list) {
+		/* Still use rcu_dereference_sched to remain compliant with sparse */
+		struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms);
+
+		if (mod->state == MODULE_STATE_UNFORMED)
+			continue;
+		for (i = 0; i < kallsyms->num_symtab; i++) {
+			const Elf_Sym *sym = &kallsyms->symtab[i];
+
+			if (sym->st_shndx == SHN_UNDEF)
+				continue;
+
+			ret = fn(data, kallsyms_symbol_name(kallsyms, i),
+				 mod, kallsyms_symbol_value(sym));
+			if (ret != 0)
+				goto out;
+		}
+	}
+out:
+	mutex_unlock(&module_mutex);
+	return ret;
+}
+#endif /* CONFIG_LIVEPATCH */
diff --git a/kernel/module/main.c b/kernel/module/main.c
index 7dd283959c5c..952079987ea4 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -288,15 +288,6 @@ static bool check_exported_symbol(const struct symsearch *syms,
 	return true;
 }
 
-static unsigned long kernel_symbol_value(const struct kernel_symbol *sym)
-{
-#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
-	return (unsigned long)offset_to_ptr(&sym->value_offset);
-#else
-	return sym->value;
-#endif
-}
-
 static const char *kernel_symbol_name(const struct kernel_symbol *sym)
 {
 #ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
@@ -317,7 +308,7 @@ static const char *kernel_symbol_namespace(const struct kernel_symbol *sym)
 #endif
 }
 
-static int cmp_name(const void *name, const void *sym)
+int cmp_name(const void *name, const void *sym)
 {
 	return strcmp(name, kernel_symbol_name(sym));
 }
@@ -387,8 +378,8 @@ static bool find_symbol(struct find_symbol_arg *fsa)
  * Search for module by name: must hold module_mutex (or preempt disabled
  * for read-only access).
  */
-static struct module *find_module_all(const char *name, size_t len,
-				      bool even_unformed)
+struct module *find_module_all(const char *name, size_t len,
+			       bool even_unformed)
 {
 	struct module *mod;
 
@@ -1294,13 +1285,6 @@ resolve_symbol_wait(struct module *mod,
 	return ksym;
 }
 
-#ifdef CONFIG_KALLSYMS
-static inline bool sect_empty(const Elf_Shdr *sect)
-{
-	return !(sect->sh_flags & SHF_ALLOC) || sect->sh_size == 0;
-}
-#endif
-
 /*
  * /sys/module/foo/sections stuff
  * J. Corbet <corbet@lwn.net>
@@ -2065,7 +2049,7 @@ unsigned int __weak arch_mod_section_prepend(struct module *mod,
 }
 
 /* Update size with this section: return offset. */
-static long get_offset(struct module *mod, unsigned int *size,
+long module_get_offset(struct module *mod, unsigned int *size,
 		       Elf_Shdr *sechdr, unsigned int section)
 {
 	long ret;
@@ -2121,7 +2105,7 @@ static void layout_sections(struct module *mod, struct load_info *info)
 			    || s->sh_entsize != ~0UL
 			    || module_init_layout_section(sname))
 				continue;
-			s->sh_entsize = get_offset(mod, &mod->core_layout.size, s, i);
+			s->sh_entsize = module_get_offset(mod, &mod->core_layout.size, s, i);
 			pr_debug("\t%s\n", sname);
 		}
 		switch (m) {
@@ -2154,7 +2138,7 @@ static void layout_sections(struct module *mod, struct load_info *info)
 			    || s->sh_entsize != ~0UL
 			    || !module_init_layout_section(sname))
 				continue;
-			s->sh_entsize = (get_offset(mod, &mod->init_layout.size, s, i)
+			s->sh_entsize = (module_get_offset(mod, &mod->init_layout.size, s, i)
 					 | INIT_OFFSET_MASK);
 			pr_debug("\t%s\n", sname);
 		}
@@ -2267,228 +2251,6 @@ static void free_modinfo(struct module *mod)
 	}
 }
 
-#ifdef CONFIG_KALLSYMS
-
-/* Lookup exported symbol in given range of kernel_symbols */
-static const struct kernel_symbol *lookup_exported_symbol(const char *name,
-							  const struct kernel_symbol *start,
-							  const struct kernel_symbol *stop)
-{
-	return bsearch(name, start, stop - start,
-			sizeof(struct kernel_symbol), cmp_name);
-}
-
-static int is_exported(const char *name, unsigned long value,
-		       const struct module *mod)
-{
-	const struct kernel_symbol *ks;
-	if (!mod)
-		ks = lookup_exported_symbol(name, __start___ksymtab, __stop___ksymtab);
-	else
-		ks = lookup_exported_symbol(name, mod->syms, mod->syms + mod->num_syms);
-
-	return ks != NULL && kernel_symbol_value(ks) == value;
-}
-
-/* As per nm */
-static char elf_type(const Elf_Sym *sym, const struct load_info *info)
-{
-	const Elf_Shdr *sechdrs = info->sechdrs;
-
-	if (ELF_ST_BIND(sym->st_info) == STB_WEAK) {
-		if (ELF_ST_TYPE(sym->st_info) == STT_OBJECT)
-			return 'v';
-		else
-			return 'w';
-	}
-	if (sym->st_shndx == SHN_UNDEF)
-		return 'U';
-	if (sym->st_shndx == SHN_ABS || sym->st_shndx == info->index.pcpu)
-		return 'a';
-	if (sym->st_shndx >= SHN_LORESERVE)
-		return '?';
-	if (sechdrs[sym->st_shndx].sh_flags & SHF_EXECINSTR)
-		return 't';
-	if (sechdrs[sym->st_shndx].sh_flags & SHF_ALLOC
-	    && sechdrs[sym->st_shndx].sh_type != SHT_NOBITS) {
-		if (!(sechdrs[sym->st_shndx].sh_flags & SHF_WRITE))
-			return 'r';
-		else if (sechdrs[sym->st_shndx].sh_flags & ARCH_SHF_SMALL)
-			return 'g';
-		else
-			return 'd';
-	}
-	if (sechdrs[sym->st_shndx].sh_type == SHT_NOBITS) {
-		if (sechdrs[sym->st_shndx].sh_flags & ARCH_SHF_SMALL)
-			return 's';
-		else
-			return 'b';
-	}
-	if (strstarts(info->secstrings + sechdrs[sym->st_shndx].sh_name,
-		      ".debug")) {
-		return 'n';
-	}
-	return '?';
-}
-
-static bool is_core_symbol(const Elf_Sym *src, const Elf_Shdr *sechdrs,
-			unsigned int shnum, unsigned int pcpundx)
-{
-	const Elf_Shdr *sec;
-
-	if (src->st_shndx == SHN_UNDEF
-	    || src->st_shndx >= shnum
-	    || !src->st_name)
-		return false;
-
-#ifdef CONFIG_KALLSYMS_ALL
-	if (src->st_shndx == pcpundx)
-		return true;
-#endif
-
-	sec = sechdrs + src->st_shndx;
-	if (!(sec->sh_flags & SHF_ALLOC)
-#ifndef CONFIG_KALLSYMS_ALL
-	    || !(sec->sh_flags & SHF_EXECINSTR)
-#endif
-	    || (sec->sh_entsize & INIT_OFFSET_MASK))
-		return false;
-
-	return true;
-}
-
-/*
- * We only allocate and copy the strings needed by the parts of symtab
- * we keep.  This is simple, but has the effect of making multiple
- * copies of duplicates.  We could be more sophisticated, see
- * linux-kernel thread starting with
- * <73defb5e4bca04a6431392cc341112b1@localhost>.
- */
-static void layout_symtab(struct module *mod, struct load_info *info)
-{
-	Elf_Shdr *symsect = info->sechdrs + info->index.sym;
-	Elf_Shdr *strsect = info->sechdrs + info->index.str;
-	const Elf_Sym *src;
-	unsigned int i, nsrc, ndst, strtab_size = 0;
-
-	/* Put symbol section at end of init part of module. */
-	symsect->sh_flags |= SHF_ALLOC;
-	symsect->sh_entsize = get_offset(mod, &mod->init_layout.size, symsect,
-					 info->index.sym) | INIT_OFFSET_MASK;
-	pr_debug("\t%s\n", info->secstrings + symsect->sh_name);
-
-	src = (void *)info->hdr + symsect->sh_offset;
-	nsrc = symsect->sh_size / sizeof(*src);
-
-	/* Compute total space required for the core symbols' strtab. */
-	for (ndst = i = 0; i < nsrc; i++) {
-		if (i == 0 || is_livepatch_module(mod) ||
-		    is_core_symbol(src+i, info->sechdrs, info->hdr->e_shnum,
-				   info->index.pcpu)) {
-			strtab_size += strlen(&info->strtab[src[i].st_name])+1;
-			ndst++;
-		}
-	}
-
-	/* Append room for core symbols at end of core part. */
-	info->symoffs = ALIGN(mod->core_layout.size, symsect->sh_addralign ?: 1);
-	info->stroffs = mod->core_layout.size = info->symoffs + ndst * sizeof(Elf_Sym);
-	mod->core_layout.size += strtab_size;
-	info->core_typeoffs = mod->core_layout.size;
-	mod->core_layout.size += ndst * sizeof(char);
-	mod->core_layout.size = debug_align(mod->core_layout.size);
-
-	/* Put string table section at end of init part of module. */
-	strsect->sh_flags |= SHF_ALLOC;
-	strsect->sh_entsize = get_offset(mod, &mod->init_layout.size, strsect,
-					 info->index.str) | INIT_OFFSET_MASK;
-	pr_debug("\t%s\n", info->secstrings + strsect->sh_name);
-
-	/* We'll tack temporary mod_kallsyms on the end. */
-	mod->init_layout.size = ALIGN(mod->init_layout.size,
-				      __alignof__(struct mod_kallsyms));
-	info->mod_kallsyms_init_off = mod->init_layout.size;
-	mod->init_layout.size += sizeof(struct mod_kallsyms);
-	info->init_typeoffs = mod->init_layout.size;
-	mod->init_layout.size += nsrc * sizeof(char);
-	mod->init_layout.size = debug_align(mod->init_layout.size);
-}
-
-/*
- * We use the full symtab and strtab which layout_symtab arranged to
- * be appended to the init section.  Later we switch to the cut-down
- * core-only ones.
- */
-static void add_kallsyms(struct module *mod, const struct load_info *info)
-{
-	unsigned int i, ndst;
-	const Elf_Sym *src;
-	Elf_Sym *dst;
-	char *s;
-	Elf_Shdr *symsec = &info->sechdrs[info->index.sym];
-
-	/* Set up to point into init section. */
-	mod->kallsyms = mod->init_layout.base + info->mod_kallsyms_init_off;
-
-	mod->kallsyms->symtab = (void *)symsec->sh_addr;
-	mod->kallsyms->num_symtab = symsec->sh_size / sizeof(Elf_Sym);
-	/* Make sure we get permanent strtab: don't use info->strtab. */
-	mod->kallsyms->strtab = (void *)info->sechdrs[info->index.str].sh_addr;
-	mod->kallsyms->typetab = mod->init_layout.base + info->init_typeoffs;
-
-	/*
-	 * Now populate the cut down core kallsyms for after init
-	 * and set types up while we still have access to sections.
-	 */
-	mod->core_kallsyms.symtab = dst = mod->core_layout.base + info->symoffs;
-	mod->core_kallsyms.strtab = s = mod->core_layout.base + info->stroffs;
-	mod->core_kallsyms.typetab = mod->core_layout.base + info->core_typeoffs;
-	src = mod->kallsyms->symtab;
-	for (ndst = i = 0; i < mod->kallsyms->num_symtab; i++) {
-		mod->kallsyms->typetab[i] = elf_type(src + i, info);
-		if (i == 0 || is_livepatch_module(mod) ||
-		    is_core_symbol(src+i, info->sechdrs, info->hdr->e_shnum,
-				   info->index.pcpu)) {
-			mod->core_kallsyms.typetab[ndst] =
-			    mod->kallsyms->typetab[i];
-			dst[ndst] = src[i];
-			dst[ndst++].st_name = s - mod->core_kallsyms.strtab;
-			s += strlcpy(s, &mod->kallsyms->strtab[src[i].st_name],
-				     KSYM_NAME_LEN) + 1;
-		}
-	}
-	mod->core_kallsyms.num_symtab = ndst;
-}
-#else
-static inline void layout_symtab(struct module *mod, struct load_info *info)
-{
-}
-
-static void add_kallsyms(struct module *mod, const struct load_info *info)
-{
-}
-#endif /* CONFIG_KALLSYMS */
-
-#if IS_ENABLED(CONFIG_KALLSYMS) && IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID)
-static void init_build_id(struct module *mod, const struct load_info *info)
-{
-	const Elf_Shdr *sechdr;
-	unsigned int i;
-
-	for (i = 0; i < info->hdr->e_shnum; i++) {
-		sechdr = &info->sechdrs[i];
-		if (!sect_empty(sechdr) && sechdr->sh_type == SHT_NOTE &&
-		    !build_id_parse_buf((void *)sechdr->sh_addr, mod->build_id,
-					sechdr->sh_size))
-			break;
-	}
-}
-#else
-static void init_build_id(struct module *mod, const struct load_info *info)
-{
-}
-#endif
-
 static void dynamic_debug_setup(struct module *mod, struct _ddebug *debug, unsigned int num)
 {
 	if (!debug)
@@ -3799,287 +3561,6 @@ static inline int within(unsigned long addr, void *start, unsigned long size)
 	return ((void *)addr >= start && (void *)addr < start + size);
 }
 
-#ifdef CONFIG_KALLSYMS
-/*
- * This ignores the intensely annoying "mapping symbols" found
- * in ARM ELF files: $a, $t and $d.
- */
-static inline int is_arm_mapping_symbol(const char *str)
-{
-	if (str[0] == '.' && str[1] == 'L')
-		return true;
-	return str[0] == '$' && strchr("axtd", str[1])
-	       && (str[2] == '\0' || str[2] == '.');
-}
-
-static const char *kallsyms_symbol_name(struct mod_kallsyms *kallsyms, unsigned int symnum)
-{
-	return kallsyms->strtab + kallsyms->symtab[symnum].st_name;
-}
-
-/*
- * Given a module and address, find the corresponding symbol and return its name
- * while providing its size and offset if needed.
- */
-static const char *find_kallsyms_symbol(struct module *mod,
-					unsigned long addr,
-					unsigned long *size,
-					unsigned long *offset)
-{
-	unsigned int i, best = 0;
-	unsigned long nextval, bestval;
-	struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms);
-
-	/* At worse, next value is at end of module */
-	if (within_module_init(addr, mod))
-		nextval = (unsigned long)mod->init_layout.base+mod->init_layout.text_size;
-	else
-		nextval = (unsigned long)mod->core_layout.base+mod->core_layout.text_size;
-
-	bestval = kallsyms_symbol_value(&kallsyms->symtab[best]);
-
-	/*
-	 * Scan for closest preceding symbol, and next symbol. (ELF
-	 * starts real symbols at 1).
-	 */
-	for (i = 1; i < kallsyms->num_symtab; i++) {
-		const Elf_Sym *sym = &kallsyms->symtab[i];
-		unsigned long thisval = kallsyms_symbol_value(sym);
-
-		if (sym->st_shndx == SHN_UNDEF)
-			continue;
-
-		/*
-		 * We ignore unnamed symbols: they're uninformative
-		 * and inserted at a whim.
-		 */
-		if (*kallsyms_symbol_name(kallsyms, i) == '\0'
-		    || is_arm_mapping_symbol(kallsyms_symbol_name(kallsyms, i)))
-			continue;
-
-		if (thisval <= addr && thisval > bestval) {
-			best = i;
-			bestval = thisval;
-		}
-		if (thisval > addr && thisval < nextval)
-			nextval = thisval;
-	}
-
-	if (!best)
-		return NULL;
-
-	if (size)
-		*size = nextval - bestval;
-	if (offset)
-		*offset = addr - bestval;
-
-	return kallsyms_symbol_name(kallsyms, best);
-}
-
-void * __weak dereference_module_function_descriptor(struct module *mod,
-						     void *ptr)
-{
-	return ptr;
-}
-
-/*
- * For kallsyms to ask for address resolution.  NULL means not found.  Careful
- * not to lock to avoid deadlock on oopses, simply disable preemption.
- */
-const char *module_address_lookup(unsigned long addr,
-			    unsigned long *size,
-			    unsigned long *offset,
-			    char **modname,
-			    const unsigned char **modbuildid,
-			    char *namebuf)
-{
-	const char *ret = NULL;
-	struct module *mod;
-
-	preempt_disable();
-	mod = __module_address(addr);
-	if (mod) {
-		if (modname)
-			*modname = mod->name;
-		if (modbuildid) {
-#if IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID)
-			*modbuildid = mod->build_id;
-#else
-			*modbuildid = NULL;
-#endif
-		}
-
-		ret = find_kallsyms_symbol(mod, addr, size, offset);
-	}
-	/* Make a copy in here where it's safe */
-	if (ret) {
-		strncpy(namebuf, ret, KSYM_NAME_LEN - 1);
-		ret = namebuf;
-	}
-	preempt_enable();
-
-	return ret;
-}
-
-int lookup_module_symbol_name(unsigned long addr, char *symname)
-{
-	struct module *mod;
-
-	preempt_disable();
-	list_for_each_entry_rcu(mod, &modules, list) {
-		if (mod->state == MODULE_STATE_UNFORMED)
-			continue;
-		if (within_module(addr, mod)) {
-			const char *sym;
-
-			sym = find_kallsyms_symbol(mod, addr, NULL, NULL);
-			if (!sym)
-				goto out;
-
-			strlcpy(symname, sym, KSYM_NAME_LEN);
-			preempt_enable();
-			return 0;
-		}
-	}
-out:
-	preempt_enable();
-	return -ERANGE;
-}
-
-int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size,
-			unsigned long *offset, char *modname, char *name)
-{
-	struct module *mod;
-
-	preempt_disable();
-	list_for_each_entry_rcu(mod, &modules, list) {
-		if (mod->state == MODULE_STATE_UNFORMED)
-			continue;
-		if (within_module(addr, mod)) {
-			const char *sym;
-
-			sym = find_kallsyms_symbol(mod, addr, size, offset);
-			if (!sym)
-				goto out;
-			if (modname)
-				strlcpy(modname, mod->name, MODULE_NAME_LEN);
-			if (name)
-				strlcpy(name, sym, KSYM_NAME_LEN);
-			preempt_enable();
-			return 0;
-		}
-	}
-out:
-	preempt_enable();
-	return -ERANGE;
-}
-
-int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
-			char *name, char *module_name, int *exported)
-{
-	struct module *mod;
-
-	preempt_disable();
-	list_for_each_entry_rcu(mod, &modules, list) {
-		struct mod_kallsyms *kallsyms;
-
-		if (mod->state == MODULE_STATE_UNFORMED)
-			continue;
-		kallsyms = rcu_dereference_sched(mod->kallsyms);
-		if (symnum < kallsyms->num_symtab) {
-			const Elf_Sym *sym = &kallsyms->symtab[symnum];
-
-			*value = kallsyms_symbol_value(sym);
-			*type = kallsyms->typetab[symnum];
-			strlcpy(name, kallsyms_symbol_name(kallsyms, symnum), KSYM_NAME_LEN);
-			strlcpy(module_name, mod->name, MODULE_NAME_LEN);
-			*exported = is_exported(name, *value, mod);
-			preempt_enable();
-			return 0;
-		}
-		symnum -= kallsyms->num_symtab;
-	}
-	preempt_enable();
-	return -ERANGE;
-}
-
-/* Given a module and name of symbol, find and return the symbol's value */
-static unsigned long find_kallsyms_symbol_value(struct module *mod, const char *name)
-{
-	unsigned int i;
-	struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms);
-
-	for (i = 0; i < kallsyms->num_symtab; i++) {
-		const Elf_Sym *sym = &kallsyms->symtab[i];
-
-		if (strcmp(name, kallsyms_symbol_name(kallsyms, i)) == 0 &&
-		    sym->st_shndx != SHN_UNDEF)
-			return kallsyms_symbol_value(sym);
-	}
-	return 0;
-}
-
-/* Look for this name: can be of form module:name. */
-unsigned long module_kallsyms_lookup_name(const char *name)
-{
-	struct module *mod;
-	char *colon;
-	unsigned long ret = 0;
-
-	/* Don't lock: we're in enough trouble already. */
-	preempt_disable();
-	if ((colon = strnchr(name, MODULE_NAME_LEN, ':')) != NULL) {
-		if ((mod = find_module_all(name, colon - name, false)) != NULL)
-			ret = find_kallsyms_symbol_value(mod, colon+1);
-	} else {
-		list_for_each_entry_rcu(mod, &modules, list) {
-			if (mod->state == MODULE_STATE_UNFORMED)
-				continue;
-			if ((ret = find_kallsyms_symbol_value(mod, name)) != 0)
-				break;
-		}
-	}
-	preempt_enable();
-	return ret;
-}
-
-#ifdef CONFIG_LIVEPATCH
-int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *,
-					     struct module *, unsigned long),
-				   void *data)
-{
-	struct module *mod;
-	unsigned int i;
-	int ret = 0;
-
-	mutex_lock(&module_mutex);
-	list_for_each_entry(mod, &modules, list) {
-		/* We hold module_mutex: no need for rcu_dereference_sched */
-		struct mod_kallsyms *kallsyms = mod->kallsyms;
-
-		if (mod->state == MODULE_STATE_UNFORMED)
-			continue;
-		for (i = 0; i < kallsyms->num_symtab; i++) {
-			const Elf_Sym *sym = &kallsyms->symtab[i];
-
-			if (sym->st_shndx == SHN_UNDEF)
-				continue;
-
-			ret = fn(data, kallsyms_symbol_name(kallsyms, i),
-				 mod, kallsyms_symbol_value(sym));
-			if (ret != 0)
-				goto out;
-
-			cond_resched();
-		}
-	}
-out:
-	mutex_unlock(&module_mutex);
-	return ret;
-}
-#endif /* CONFIG_LIVEPATCH */
-#endif /* CONFIG_KALLSYMS */
-
 static void cfi_init(struct module *mod)
 {
 #ifdef CONFIG_CFI_CLANG
-- 
2.34.1


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

* [PATCH v8 10/13] module: Move procfs support into a separate file
  2022-02-22 14:12 [PATCH v8 00/13] module: core code clean up Aaron Tomlin
                   ` (8 preceding siblings ...)
  2022-02-22 14:12 ` [PATCH v8 09/13] module: Move kallsyms support into " Aaron Tomlin
@ 2022-02-22 14:13 ` Aaron Tomlin
  2022-02-22 17:59   ` Christophe Leroy
  2022-02-22 14:13 ` [PATCH v8 11/13] module: Move sysfs " Aaron Tomlin
                   ` (2 subsequent siblings)
  12 siblings, 1 reply; 43+ messages in thread
From: Aaron Tomlin @ 2022-02-22 14:13 UTC (permalink / raw)
  To: mcgrof, christophe.leroy
  Cc: cl, pmladek, mbenes, akpm, jeyu, linux-kernel, linux-modules,
	void, atomlin, allen.lkml, joe, msuchanek, oleksandr

No functional change.

This patch migrates code that allows one to generate a
list of loaded/or linked modules via /proc when procfs
support is enabled into kernel/module/procfs.c.

Signed-off-by: Aaron Tomlin <atomlin@redhat.com>
---
 kernel/module/Makefile   |   1 +
 kernel/module/internal.h |   1 +
 kernel/module/main.c     | 131 +-----------------------------------
 kernel/module/procfs.c   | 142 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 145 insertions(+), 130 deletions(-)
 create mode 100644 kernel/module/procfs.c

diff --git a/kernel/module/Makefile b/kernel/module/Makefile
index 9901bed3ab5b..94296c98a67f 100644
--- a/kernel/module/Makefile
+++ b/kernel/module/Makefile
@@ -15,3 +15,4 @@ obj-$(CONFIG_MODULES_TREE_LOOKUP) += tree_lookup.o
 obj-$(CONFIG_STRICT_MODULE_RWX) += strict_rwx.o
 obj-$(CONFIG_DEBUG_KMEMLEAK) += debug_kmemleak.o
 obj-$(CONFIG_KALLSYMS) += kallsyms.o
+obj-$(CONFIG_PROC_FS) += procfs.o
diff --git a/kernel/module/internal.h b/kernel/module/internal.h
index 44ca05b9eb8f..6af40c2d145f 100644
--- a/kernel/module/internal.h
+++ b/kernel/module/internal.h
@@ -72,6 +72,7 @@ struct module *find_module_all(const char *name, size_t len, bool even_unformed)
 int cmp_name(const void *name, const void *sym);
 long module_get_offset(struct module *mod, unsigned int *size, Elf_Shdr *sechdr,
 		       unsigned int section);
+char *module_flags(struct module *mod, char *buf);
 
 static inline unsigned long kernel_symbol_value(const struct kernel_symbol *sym)
 {
diff --git a/kernel/module/main.c b/kernel/module/main.c
index 952079987ea4..44b6fd1acc44 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -22,7 +22,6 @@
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/elf.h>
-#include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #include <linux/syscalls.h>
 #include <linux/fcntl.h>
@@ -805,31 +804,6 @@ SYSCALL_DEFINE2(delete_module, const char __user *, name_user,
 	return ret;
 }
 
-static inline void print_unload_info(struct seq_file *m, struct module *mod)
-{
-	struct module_use *use;
-	int printed_something = 0;
-
-	seq_printf(m, " %i ", module_refcount(mod));
-
-	/*
-	 * Always include a trailing , so userspace can differentiate
-	 * between this and the old multi-field proc format.
-	 */
-	list_for_each_entry(use, &mod->source_list, source_list) {
-		printed_something = 1;
-		seq_printf(m, "%s,", use->source->name);
-	}
-
-	if (mod->init != NULL && mod->exit == NULL) {
-		printed_something = 1;
-		seq_puts(m, "[permanent],");
-	}
-
-	if (!printed_something)
-		seq_puts(m, "-");
-}
-
 void __symbol_put(const char *symbol)
 {
 	struct find_symbol_arg fsa = {
@@ -919,12 +893,6 @@ void module_put(struct module *module)
 EXPORT_SYMBOL(module_put);
 
 #else /* !CONFIG_MODULE_UNLOAD */
-static inline void print_unload_info(struct seq_file *m, struct module *mod)
-{
-	/* We don't know the usage count, or what modules are using. */
-	seq_puts(m, " - -");
-}
-
 static inline void module_unload_free(struct module *mod)
 {
 }
@@ -3596,7 +3564,7 @@ static void cfi_cleanup(struct module *mod)
 }
 
 /* Keep in sync with MODULE_FLAGS_BUF_SIZE !!! */
-static char *module_flags(struct module *mod, char *buf)
+char *module_flags(struct module *mod, char *buf)
 {
 	int bx = 0;
 
@@ -3619,103 +3587,6 @@ static char *module_flags(struct module *mod, char *buf)
 	return buf;
 }
 
-#ifdef CONFIG_PROC_FS
-/* Called by the /proc file system to return a list of modules. */
-static void *m_start(struct seq_file *m, loff_t *pos)
-{
-	mutex_lock(&module_mutex);
-	return seq_list_start(&modules, *pos);
-}
-
-static void *m_next(struct seq_file *m, void *p, loff_t *pos)
-{
-	return seq_list_next(p, &modules, pos);
-}
-
-static void m_stop(struct seq_file *m, void *p)
-{
-	mutex_unlock(&module_mutex);
-}
-
-static int m_show(struct seq_file *m, void *p)
-{
-	struct module *mod = list_entry(p, struct module, list);
-	char buf[MODULE_FLAGS_BUF_SIZE];
-	void *value;
-
-	/* We always ignore unformed modules. */
-	if (mod->state == MODULE_STATE_UNFORMED)
-		return 0;
-
-	seq_printf(m, "%s %u",
-		   mod->name, mod->init_layout.size + mod->core_layout.size);
-	print_unload_info(m, mod);
-
-	/* Informative for users. */
-	seq_printf(m, " %s",
-		   mod->state == MODULE_STATE_GOING ? "Unloading" :
-		   mod->state == MODULE_STATE_COMING ? "Loading" :
-		   "Live");
-	/* Used by oprofile and other similar tools. */
-	value = m->private ? NULL : mod->core_layout.base;
-	seq_printf(m, " 0x%px", value);
-
-	/* Taints info */
-	if (mod->taints)
-		seq_printf(m, " %s", module_flags(mod, buf));
-
-	seq_puts(m, "\n");
-	return 0;
-}
-
-/*
- * Format: modulename size refcount deps address
- *
- * Where refcount is a number or -, and deps is a comma-separated list
- * of depends or -.
- */
-static const struct seq_operations modules_op = {
-	.start	= m_start,
-	.next	= m_next,
-	.stop	= m_stop,
-	.show	= m_show
-};
-
-/*
- * This also sets the "private" pointer to non-NULL if the
- * kernel pointers should be hidden (so you can just test
- * "m->private" to see if you should keep the values private).
- *
- * We use the same logic as for /proc/kallsyms.
- */
-static int modules_open(struct inode *inode, struct file *file)
-{
-	int err = seq_open(file, &modules_op);
-
-	if (!err) {
-		struct seq_file *m = file->private_data;
-		m->private = kallsyms_show_value(file->f_cred) ? NULL : (void *)8ul;
-	}
-
-	return err;
-}
-
-static const struct proc_ops modules_proc_ops = {
-	.proc_flags	= PROC_ENTRY_PERMANENT,
-	.proc_open	= modules_open,
-	.proc_read	= seq_read,
-	.proc_lseek	= seq_lseek,
-	.proc_release	= seq_release,
-};
-
-static int __init proc_modules_init(void)
-{
-	proc_create("modules", 0, NULL, &modules_proc_ops);
-	return 0;
-}
-module_init(proc_modules_init);
-#endif
-
 /* Given an address, look for it in the module exception tables. */
 const struct exception_table_entry *search_module_extables(unsigned long addr)
 {
diff --git a/kernel/module/procfs.c b/kernel/module/procfs.c
new file mode 100644
index 000000000000..2717e130788e
--- /dev/null
+++ b/kernel/module/procfs.c
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Module proc support
+ *
+ * Copyright (C) 2008 Alexey Dobriyan
+ */
+
+#include <linux/module.h>
+#include <linux/kallsyms.h>
+#include <linux/mutex.h>
+#include <linux/seq_file.h>
+#include <linux/proc_fs.h>
+#include "internal.h"
+
+#ifdef CONFIG_MODULE_UNLOAD
+static inline void print_unload_info(struct seq_file *m, struct module *mod)
+{
+	struct module_use *use;
+	int printed_something = 0;
+
+	seq_printf(m, " %i ", module_refcount(mod));
+
+	/*
+	 * Always include a trailing , so userspace can differentiate
+	 * between this and the old multi-field proc format.
+	 */
+	list_for_each_entry(use, &mod->source_list, source_list) {
+		printed_something = 1;
+		seq_printf(m, "%s,", use->source->name);
+	}
+
+	if (mod->init && !mod->exit) {
+		printed_something = 1;
+		seq_puts(m, "[permanent],");
+	}
+
+	if (!printed_something)
+		seq_puts(m, "-");
+}
+#else /* !CONFIG_MODULE_UNLOAD */
+static inline void print_unload_info(struct seq_file *m, struct module *mod)
+{
+	/* We don't know the usage count, or what modules are using. */
+	seq_puts(m, " - -");
+}
+#endif /* CONFIG_MODULE_UNLOAD */
+
+/* Called by the /proc file system to return a list of modules. */
+static void *m_start(struct seq_file *m, loff_t *pos)
+{
+	mutex_lock(&module_mutex);
+	return seq_list_start(&modules, *pos);
+}
+
+static void *m_next(struct seq_file *m, void *p, loff_t *pos)
+{
+	return seq_list_next(p, &modules, pos);
+}
+
+static void m_stop(struct seq_file *m, void *p)
+{
+	mutex_unlock(&module_mutex);
+}
+
+static int m_show(struct seq_file *m, void *p)
+{
+	struct module *mod = list_entry(p, struct module, list);
+	char buf[MODULE_FLAGS_BUF_SIZE];
+	void *value;
+
+	/* We always ignore unformed modules. */
+	if (mod->state == MODULE_STATE_UNFORMED)
+		return 0;
+
+	seq_printf(m, "%s %u",
+		   mod->name, mod->init_layout.size + mod->core_layout.size);
+	print_unload_info(m, mod);
+
+	/* Informative for users. */
+	seq_printf(m, " %s",
+		   mod->state == MODULE_STATE_GOING ? "Unloading" :
+		   mod->state == MODULE_STATE_COMING ? "Loading" :
+		   "Live");
+	/* Used by oprofile and other similar tools. */
+	value = m->private ? NULL : mod->core_layout.base;
+	seq_printf(m, " 0x%px", value);
+
+	/* Taints info */
+	if (mod->taints)
+		seq_printf(m, " %s", module_flags(mod, buf));
+
+	seq_puts(m, "\n");
+	return 0;
+}
+
+/*
+ * Format: modulename size refcount deps address
+ *
+ * Where refcount is a number or -, and deps is a comma-separated list
+ * of depends or -.
+ */
+static const struct seq_operations modules_op = {
+	.start	= m_start,
+	.next	= m_next,
+	.stop	= m_stop,
+	.show	= m_show
+};
+
+/*
+ * This also sets the "private" pointer to non-NULL if the
+ * kernel pointers should be hidden (so you can just test
+ * "m->private" to see if you should keep the values private).
+ *
+ * We use the same logic as for /proc/kallsyms.
+ */
+static int modules_open(struct inode *inode, struct file *file)
+{
+	int err = seq_open(file, &modules_op);
+
+	if (!err) {
+		struct seq_file *m = file->private_data;
+
+		m->private = kallsyms_show_value(file->f_cred) ? NULL : (void *)8ul;
+	}
+
+	return err;
+}
+
+static const struct proc_ops modules_proc_ops = {
+	.proc_flags	= PROC_ENTRY_PERMANENT,
+	.proc_open	= modules_open,
+	.proc_read	= seq_read,
+	.proc_lseek	= seq_lseek,
+	.proc_release	= seq_release,
+};
+
+static int __init proc_modules_init(void)
+{
+	proc_create("modules", 0, NULL, &modules_proc_ops);
+	return 0;
+}
+module_init(proc_modules_init);
-- 
2.34.1


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

* [PATCH v8 11/13] module: Move sysfs support into a separate file
  2022-02-22 14:12 [PATCH v8 00/13] module: core code clean up Aaron Tomlin
                   ` (9 preceding siblings ...)
  2022-02-22 14:13 ` [PATCH v8 10/13] module: Move procfs " Aaron Tomlin
@ 2022-02-22 14:13 ` Aaron Tomlin
  2022-02-22 17:59   ` Christophe Leroy
  2022-02-22 14:13 ` [PATCH v8 12/13] module: Move kdb_modules list out of core code Aaron Tomlin
  2022-02-22 14:13 ` [PATCH v8 13/13] module: Move version support into a separate file Aaron Tomlin
  12 siblings, 1 reply; 43+ messages in thread
From: Aaron Tomlin @ 2022-02-22 14:13 UTC (permalink / raw)
  To: mcgrof, christophe.leroy
  Cc: cl, pmladek, mbenes, akpm, jeyu, linux-kernel, linux-modules,
	void, atomlin, allen.lkml, joe, msuchanek, oleksandr

No functional change.

This patch migrates module sysfs support out of core code into
kernel/module/sysfs.c. In addition simple code refactoring to
make this possible.

Signed-off-by: Aaron Tomlin <atomlin@redhat.com>
---
 kernel/module/Makefile   |   1 +
 kernel/module/internal.h |  21 ++
 kernel/module/main.c     | 469 +--------------------------------------
 kernel/module/sysfs.c    | 436 ++++++++++++++++++++++++++++++++++++
 4 files changed, 461 insertions(+), 466 deletions(-)
 create mode 100644 kernel/module/sysfs.c

diff --git a/kernel/module/Makefile b/kernel/module/Makefile
index 94296c98a67f..cf8dcdc6b55f 100644
--- a/kernel/module/Makefile
+++ b/kernel/module/Makefile
@@ -16,3 +16,4 @@ obj-$(CONFIG_STRICT_MODULE_RWX) += strict_rwx.o
 obj-$(CONFIG_DEBUG_KMEMLEAK) += debug_kmemleak.o
 obj-$(CONFIG_KALLSYMS) += kallsyms.o
 obj-$(CONFIG_PROC_FS) += procfs.o
+obj-$(CONFIG_SYSFS) += sysfs.o
diff --git a/kernel/module/internal.h b/kernel/module/internal.h
index 6af40c2d145f..62d749ef695e 100644
--- a/kernel/module/internal.h
+++ b/kernel/module/internal.h
@@ -34,6 +34,9 @@
 extern struct mutex module_mutex;
 extern struct list_head modules;
 
+extern struct module_attribute *modinfo_attrs[];
+extern size_t modinfo_attrs_count;
+
 /* Provided by the linker */
 extern const struct kernel_symbol __start___ksymtab[];
 extern const struct kernel_symbol __stop___ksymtab[];
@@ -204,3 +207,21 @@ static inline void init_build_id(struct module *mod, const struct load_info *inf
 static inline void layout_symtab(struct module *mod, struct load_info *info) { }
 static inline void add_kallsyms(struct module *mod, const struct load_info *info) { }
 #endif /* CONFIG_KALLSYMS */
+
+#ifdef CONFIG_SYSFS
+int mod_sysfs_setup(struct module *mod, const struct load_info *info,
+		    struct kernel_param *kparam, unsigned int num_params);
+void mod_sysfs_teardown(struct module *mod);
+void init_param_lock(struct module *mod);
+#else /* !CONFIG_SYSFS */
+static inline int mod_sysfs_setup(struct module *mod,
+			   	  const struct load_info *info,
+			   	  struct kernel_param *kparam,
+			   	  unsigned int num_params)
+{
+	return 0;
+}
+
+static inline void mod_sysfs_teardown(struct module *mod) { }
+static inline void init_param_lock(struct module *mod) { }
+#endif /* CONFIG_SYSFS */
diff --git a/kernel/module/main.c b/kernel/module/main.c
index 44b6fd1acc44..b8a59b5c3e3a 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -14,9 +14,7 @@
 #include <linux/init.h>
 #include <linux/kallsyms.h>
 #include <linux/buildid.h>
-#include <linux/file.h>
 #include <linux/fs.h>
-#include <linux/sysfs.h>
 #include <linux/kernel.h>
 #include <linux/kernel_read_file.h>
 #include <linux/slab.h>
@@ -989,7 +987,7 @@ static ssize_t show_taint(struct module_attribute *mattr,
 static struct module_attribute modinfo_taint =
 	__ATTR(taint, 0444, show_taint, NULL);
 
-static struct module_attribute *modinfo_attrs[] = {
+struct module_attribute *modinfo_attrs[] = {
 	&module_uevent,
 	&modinfo_version,
 	&modinfo_srcversion,
@@ -1003,6 +1001,8 @@ static struct module_attribute *modinfo_attrs[] = {
 	NULL,
 };
 
+size_t modinfo_attrs_count = ARRAY_SIZE(modinfo_attrs);
+
 static const char vermagic[] = VERMAGIC_STRING;
 
 static int try_to_force_load(struct module *mod, const char *reason)
@@ -1253,469 +1253,6 @@ resolve_symbol_wait(struct module *mod,
 	return ksym;
 }
 
-/*
- * /sys/module/foo/sections stuff
- * J. Corbet <corbet@lwn.net>
- */
-#ifdef CONFIG_SYSFS
-
-#ifdef CONFIG_KALLSYMS
-struct module_sect_attr {
-	struct bin_attribute battr;
-	unsigned long address;
-};
-
-struct module_sect_attrs {
-	struct attribute_group grp;
-	unsigned int nsections;
-	struct module_sect_attr attrs[];
-};
-
-#define MODULE_SECT_READ_SIZE (3 /* "0x", "\n" */ + (BITS_PER_LONG / 4))
-static ssize_t module_sect_read(struct file *file, struct kobject *kobj,
-				struct bin_attribute *battr,
-				char *buf, loff_t pos, size_t count)
-{
-	struct module_sect_attr *sattr =
-		container_of(battr, struct module_sect_attr, battr);
-	char bounce[MODULE_SECT_READ_SIZE + 1];
-	size_t wrote;
-
-	if (pos != 0)
-		return -EINVAL;
-
-	/*
-	 * Since we're a binary read handler, we must account for the
-	 * trailing NUL byte that sprintf will write: if "buf" is
-	 * too small to hold the NUL, or the NUL is exactly the last
-	 * byte, the read will look like it got truncated by one byte.
-	 * Since there is no way to ask sprintf nicely to not write
-	 * the NUL, we have to use a bounce buffer.
-	 */
-	wrote = scnprintf(bounce, sizeof(bounce), "0x%px\n",
-			 kallsyms_show_value(file->f_cred)
-				? (void *)sattr->address : NULL);
-	count = min(count, wrote);
-	memcpy(buf, bounce, count);
-
-	return count;
-}
-
-static void free_sect_attrs(struct module_sect_attrs *sect_attrs)
-{
-	unsigned int section;
-
-	for (section = 0; section < sect_attrs->nsections; section++)
-		kfree(sect_attrs->attrs[section].battr.attr.name);
-	kfree(sect_attrs);
-}
-
-static void add_sect_attrs(struct module *mod, const struct load_info *info)
-{
-	unsigned int nloaded = 0, i, size[2];
-	struct module_sect_attrs *sect_attrs;
-	struct module_sect_attr *sattr;
-	struct bin_attribute **gattr;
-
-	/* Count loaded sections and allocate structures */
-	for (i = 0; i < info->hdr->e_shnum; i++)
-		if (!sect_empty(&info->sechdrs[i]))
-			nloaded++;
-	size[0] = ALIGN(struct_size(sect_attrs, attrs, nloaded),
-			sizeof(sect_attrs->grp.bin_attrs[0]));
-	size[1] = (nloaded + 1) * sizeof(sect_attrs->grp.bin_attrs[0]);
-	sect_attrs = kzalloc(size[0] + size[1], GFP_KERNEL);
-	if (sect_attrs == NULL)
-		return;
-
-	/* Setup section attributes. */
-	sect_attrs->grp.name = "sections";
-	sect_attrs->grp.bin_attrs = (void *)sect_attrs + size[0];
-
-	sect_attrs->nsections = 0;
-	sattr = &sect_attrs->attrs[0];
-	gattr = &sect_attrs->grp.bin_attrs[0];
-	for (i = 0; i < info->hdr->e_shnum; i++) {
-		Elf_Shdr *sec = &info->sechdrs[i];
-		if (sect_empty(sec))
-			continue;
-		sysfs_bin_attr_init(&sattr->battr);
-		sattr->address = sec->sh_addr;
-		sattr->battr.attr.name =
-			kstrdup(info->secstrings + sec->sh_name, GFP_KERNEL);
-		if (sattr->battr.attr.name == NULL)
-			goto out;
-		sect_attrs->nsections++;
-		sattr->battr.read = module_sect_read;
-		sattr->battr.size = MODULE_SECT_READ_SIZE;
-		sattr->battr.attr.mode = 0400;
-		*(gattr++) = &(sattr++)->battr;
-	}
-	*gattr = NULL;
-
-	if (sysfs_create_group(&mod->mkobj.kobj, &sect_attrs->grp))
-		goto out;
-
-	mod->sect_attrs = sect_attrs;
-	return;
-  out:
-	free_sect_attrs(sect_attrs);
-}
-
-static void remove_sect_attrs(struct module *mod)
-{
-	if (mod->sect_attrs) {
-		sysfs_remove_group(&mod->mkobj.kobj,
-				   &mod->sect_attrs->grp);
-		/*
-		 * We are positive that no one is using any sect attrs
-		 * at this point.  Deallocate immediately.
-		 */
-		free_sect_attrs(mod->sect_attrs);
-		mod->sect_attrs = NULL;
-	}
-}
-
-/*
- * /sys/module/foo/notes/.section.name gives contents of SHT_NOTE sections.
- */
-
-struct module_notes_attrs {
-	struct kobject *dir;
-	unsigned int notes;
-	struct bin_attribute attrs[];
-};
-
-static ssize_t module_notes_read(struct file *filp, struct kobject *kobj,
-				 struct bin_attribute *bin_attr,
-				 char *buf, loff_t pos, size_t count)
-{
-	/*
-	 * The caller checked the pos and count against our size.
-	 */
-	memcpy(buf, bin_attr->private + pos, count);
-	return count;
-}
-
-static void free_notes_attrs(struct module_notes_attrs *notes_attrs,
-			     unsigned int i)
-{
-	if (notes_attrs->dir) {
-		while (i-- > 0)
-			sysfs_remove_bin_file(notes_attrs->dir,
-					      &notes_attrs->attrs[i]);
-		kobject_put(notes_attrs->dir);
-	}
-	kfree(notes_attrs);
-}
-
-static void add_notes_attrs(struct module *mod, const struct load_info *info)
-{
-	unsigned int notes, loaded, i;
-	struct module_notes_attrs *notes_attrs;
-	struct bin_attribute *nattr;
-
-	/* failed to create section attributes, so can't create notes */
-	if (!mod->sect_attrs)
-		return;
-
-	/* Count notes sections and allocate structures.  */
-	notes = 0;
-	for (i = 0; i < info->hdr->e_shnum; i++)
-		if (!sect_empty(&info->sechdrs[i]) &&
-		    (info->sechdrs[i].sh_type == SHT_NOTE))
-			++notes;
-
-	if (notes == 0)
-		return;
-
-	notes_attrs = kzalloc(struct_size(notes_attrs, attrs, notes),
-			      GFP_KERNEL);
-	if (notes_attrs == NULL)
-		return;
-
-	notes_attrs->notes = notes;
-	nattr = &notes_attrs->attrs[0];
-	for (loaded = i = 0; i < info->hdr->e_shnum; ++i) {
-		if (sect_empty(&info->sechdrs[i]))
-			continue;
-		if (info->sechdrs[i].sh_type == SHT_NOTE) {
-			sysfs_bin_attr_init(nattr);
-			nattr->attr.name = mod->sect_attrs->attrs[loaded].battr.attr.name;
-			nattr->attr.mode = S_IRUGO;
-			nattr->size = info->sechdrs[i].sh_size;
-			nattr->private = (void *) info->sechdrs[i].sh_addr;
-			nattr->read = module_notes_read;
-			++nattr;
-		}
-		++loaded;
-	}
-
-	notes_attrs->dir = kobject_create_and_add("notes", &mod->mkobj.kobj);
-	if (!notes_attrs->dir)
-		goto out;
-
-	for (i = 0; i < notes; ++i)
-		if (sysfs_create_bin_file(notes_attrs->dir,
-					  &notes_attrs->attrs[i]))
-			goto out;
-
-	mod->notes_attrs = notes_attrs;
-	return;
-
-  out:
-	free_notes_attrs(notes_attrs, i);
-}
-
-static void remove_notes_attrs(struct module *mod)
-{
-	if (mod->notes_attrs)
-		free_notes_attrs(mod->notes_attrs, mod->notes_attrs->notes);
-}
-
-#else
-
-static inline void add_sect_attrs(struct module *mod,
-				  const struct load_info *info)
-{
-}
-
-static inline void remove_sect_attrs(struct module *mod)
-{
-}
-
-static inline void add_notes_attrs(struct module *mod,
-				   const struct load_info *info)
-{
-}
-
-static inline void remove_notes_attrs(struct module *mod)
-{
-}
-#endif /* CONFIG_KALLSYMS */
-
-static void del_usage_links(struct module *mod)
-{
-#ifdef CONFIG_MODULE_UNLOAD
-	struct module_use *use;
-
-	mutex_lock(&module_mutex);
-	list_for_each_entry(use, &mod->target_list, target_list)
-		sysfs_remove_link(use->target->holders_dir, mod->name);
-	mutex_unlock(&module_mutex);
-#endif
-}
-
-static int add_usage_links(struct module *mod)
-{
-	int ret = 0;
-#ifdef CONFIG_MODULE_UNLOAD
-	struct module_use *use;
-
-	mutex_lock(&module_mutex);
-	list_for_each_entry(use, &mod->target_list, target_list) {
-		ret = sysfs_create_link(use->target->holders_dir,
-					&mod->mkobj.kobj, mod->name);
-		if (ret)
-			break;
-	}
-	mutex_unlock(&module_mutex);
-	if (ret)
-		del_usage_links(mod);
-#endif
-	return ret;
-}
-
-static void module_remove_modinfo_attrs(struct module *mod, int end);
-
-static int module_add_modinfo_attrs(struct module *mod)
-{
-	struct module_attribute *attr;
-	struct module_attribute *temp_attr;
-	int error = 0;
-	int i;
-
-	mod->modinfo_attrs = kzalloc((sizeof(struct module_attribute) *
-					(ARRAY_SIZE(modinfo_attrs) + 1)),
-					GFP_KERNEL);
-	if (!mod->modinfo_attrs)
-		return -ENOMEM;
-
-	temp_attr = mod->modinfo_attrs;
-	for (i = 0; (attr = modinfo_attrs[i]); i++) {
-		if (!attr->test || attr->test(mod)) {
-			memcpy(temp_attr, attr, sizeof(*temp_attr));
-			sysfs_attr_init(&temp_attr->attr);
-			error = sysfs_create_file(&mod->mkobj.kobj,
-					&temp_attr->attr);
-			if (error)
-				goto error_out;
-			++temp_attr;
-		}
-	}
-
-	return 0;
-
-error_out:
-	if (i > 0)
-		module_remove_modinfo_attrs(mod, --i);
-	else
-		kfree(mod->modinfo_attrs);
-	return error;
-}
-
-static void module_remove_modinfo_attrs(struct module *mod, int end)
-{
-	struct module_attribute *attr;
-	int i;
-
-	for (i = 0; (attr = &mod->modinfo_attrs[i]); i++) {
-		if (end >= 0 && i > end)
-			break;
-		/* pick a field to test for end of list */
-		if (!attr->attr.name)
-			break;
-		sysfs_remove_file(&mod->mkobj.kobj, &attr->attr);
-		if (attr->free)
-			attr->free(mod);
-	}
-	kfree(mod->modinfo_attrs);
-}
-
-static void mod_kobject_put(struct module *mod)
-{
-	DECLARE_COMPLETION_ONSTACK(c);
-	mod->mkobj.kobj_completion = &c;
-	kobject_put(&mod->mkobj.kobj);
-	wait_for_completion(&c);
-}
-
-static int mod_sysfs_init(struct module *mod)
-{
-	int err;
-	struct kobject *kobj;
-
-	if (!module_sysfs_initialized) {
-		pr_err("%s: module sysfs not initialized\n", mod->name);
-		err = -EINVAL;
-		goto out;
-	}
-
-	kobj = kset_find_obj(module_kset, mod->name);
-	if (kobj) {
-		pr_err("%s: module is already loaded\n", mod->name);
-		kobject_put(kobj);
-		err = -EINVAL;
-		goto out;
-	}
-
-	mod->mkobj.mod = mod;
-
-	memset(&mod->mkobj.kobj, 0, sizeof(mod->mkobj.kobj));
-	mod->mkobj.kobj.kset = module_kset;
-	err = kobject_init_and_add(&mod->mkobj.kobj, &module_ktype, NULL,
-				   "%s", mod->name);
-	if (err)
-		mod_kobject_put(mod);
-
-out:
-	return err;
-}
-
-static int mod_sysfs_setup(struct module *mod,
-			   const struct load_info *info,
-			   struct kernel_param *kparam,
-			   unsigned int num_params)
-{
-	int err;
-
-	err = mod_sysfs_init(mod);
-	if (err)
-		goto out;
-
-	mod->holders_dir = kobject_create_and_add("holders", &mod->mkobj.kobj);
-	if (!mod->holders_dir) {
-		err = -ENOMEM;
-		goto out_unreg;
-	}
-
-	err = module_param_sysfs_setup(mod, kparam, num_params);
-	if (err)
-		goto out_unreg_holders;
-
-	err = module_add_modinfo_attrs(mod);
-	if (err)
-		goto out_unreg_param;
-
-	err = add_usage_links(mod);
-	if (err)
-		goto out_unreg_modinfo_attrs;
-
-	add_sect_attrs(mod, info);
-	add_notes_attrs(mod, info);
-
-	return 0;
-
-out_unreg_modinfo_attrs:
-	module_remove_modinfo_attrs(mod, -1);
-out_unreg_param:
-	module_param_sysfs_remove(mod);
-out_unreg_holders:
-	kobject_put(mod->holders_dir);
-out_unreg:
-	mod_kobject_put(mod);
-out:
-	return err;
-}
-
-static void mod_sysfs_fini(struct module *mod)
-{
-	remove_notes_attrs(mod);
-	remove_sect_attrs(mod);
-	mod_kobject_put(mod);
-}
-
-static void init_param_lock(struct module *mod)
-{
-	mutex_init(&mod->param_lock);
-}
-#else /* !CONFIG_SYSFS */
-
-static int mod_sysfs_setup(struct module *mod,
-			   const struct load_info *info,
-			   struct kernel_param *kparam,
-			   unsigned int num_params)
-{
-	return 0;
-}
-
-static void mod_sysfs_fini(struct module *mod)
-{
-}
-
-static void module_remove_modinfo_attrs(struct module *mod, int end)
-{
-}
-
-static void del_usage_links(struct module *mod)
-{
-}
-
-static void init_param_lock(struct module *mod)
-{
-}
-#endif /* CONFIG_SYSFS */
-
-static void mod_sysfs_teardown(struct module *mod)
-{
-	del_usage_links(mod);
-	module_remove_modinfo_attrs(mod, -1);
-	module_param_sysfs_remove(mod);
-	kobject_put(mod->mkobj.drivers_dir);
-	kobject_put(mod->holders_dir);
-	mod_sysfs_fini(mod);
-}
-
 /*
  * LKM RO/NX protection: protect module's text/ro-data
  * from modification and any data from execution.
diff --git a/kernel/module/sysfs.c b/kernel/module/sysfs.c
new file mode 100644
index 000000000000..ce68f821dcd1
--- /dev/null
+++ b/kernel/module/sysfs.c
@@ -0,0 +1,436 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Module sysfs support
+ *
+ * Copyright (C) 2008 Rusty Russell
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/sysfs.h>
+#include <linux/slab.h>
+#include <linux/kallsyms.h>
+#include <linux/mutex.h>
+#include "internal.h"
+
+/*
+ * /sys/module/foo/sections stuff
+ * J. Corbet <corbet@lwn.net>
+ */
+#ifdef CONFIG_KALLSYMS
+struct module_sect_attr {
+	struct bin_attribute battr;
+	unsigned long address;
+};
+
+struct module_sect_attrs {
+	struct attribute_group grp;
+	unsigned int nsections;
+	struct module_sect_attr attrs[];
+};
+
+#define MODULE_SECT_READ_SIZE (3 /* "0x", "\n" */ + (BITS_PER_LONG / 4))
+static ssize_t module_sect_read(struct file *file, struct kobject *kobj,
+				struct bin_attribute *battr,
+				char *buf, loff_t pos, size_t count)
+{
+	struct module_sect_attr *sattr =
+		container_of(battr, struct module_sect_attr, battr);
+	char bounce[MODULE_SECT_READ_SIZE + 1];
+	size_t wrote;
+
+	if (pos != 0)
+		return -EINVAL;
+
+	/*
+	 * Since we're a binary read handler, we must account for the
+	 * trailing NUL byte that sprintf will write: if "buf" is
+	 * too small to hold the NUL, or the NUL is exactly the last
+	 * byte, the read will look like it got truncated by one byte.
+	 * Since there is no way to ask sprintf nicely to not write
+	 * the NUL, we have to use a bounce buffer.
+	 */
+	wrote = scnprintf(bounce, sizeof(bounce), "0x%px\n",
+			  kallsyms_show_value(file->f_cred)
+				? (void *)sattr->address : NULL);
+	count = min(count, wrote);
+	memcpy(buf, bounce, count);
+
+	return count;
+}
+
+static void free_sect_attrs(struct module_sect_attrs *sect_attrs)
+{
+	unsigned int section;
+
+	for (section = 0; section < sect_attrs->nsections; section++)
+		kfree(sect_attrs->attrs[section].battr.attr.name);
+	kfree(sect_attrs);
+}
+
+static void add_sect_attrs(struct module *mod, const struct load_info *info)
+{
+	unsigned int nloaded = 0, i, size[2];
+	struct module_sect_attrs *sect_attrs;
+	struct module_sect_attr *sattr;
+	struct bin_attribute **gattr;
+
+	/* Count loaded sections and allocate structures */
+	for (i = 0; i < info->hdr->e_shnum; i++)
+		if (!sect_empty(&info->sechdrs[i]))
+			nloaded++;
+	size[0] = ALIGN(struct_size(sect_attrs, attrs, nloaded),
+			sizeof(sect_attrs->grp.bin_attrs[0]));
+	size[1] = (nloaded + 1) * sizeof(sect_attrs->grp.bin_attrs[0]);
+	sect_attrs = kzalloc(size[0] + size[1], GFP_KERNEL);
+	if (!sect_attrs)
+		return;
+
+	/* Setup section attributes. */
+	sect_attrs->grp.name = "sections";
+	sect_attrs->grp.bin_attrs = (void *)sect_attrs + size[0];
+
+	sect_attrs->nsections = 0;
+	sattr = &sect_attrs->attrs[0];
+	gattr = &sect_attrs->grp.bin_attrs[0];
+	for (i = 0; i < info->hdr->e_shnum; i++) {
+		Elf_Shdr *sec = &info->sechdrs[i];
+
+		if (sect_empty(sec))
+			continue;
+		sysfs_bin_attr_init(&sattr->battr);
+		sattr->address = sec->sh_addr;
+		sattr->battr.attr.name =
+			kstrdup(info->secstrings + sec->sh_name, GFP_KERNEL);
+		if (!sattr->battr.attr.name)
+			goto out;
+		sect_attrs->nsections++;
+		sattr->battr.read = module_sect_read;
+		sattr->battr.size = MODULE_SECT_READ_SIZE;
+		sattr->battr.attr.mode = 0400;
+		*(gattr++) = &(sattr++)->battr;
+	}
+	*gattr = NULL;
+
+	if (sysfs_create_group(&mod->mkobj.kobj, &sect_attrs->grp))
+		goto out;
+
+	mod->sect_attrs = sect_attrs;
+	return;
+out:
+	free_sect_attrs(sect_attrs);
+}
+
+static void remove_sect_attrs(struct module *mod)
+{
+	if (mod->sect_attrs) {
+		sysfs_remove_group(&mod->mkobj.kobj,
+				   &mod->sect_attrs->grp);
+		/*
+		 * We are positive that no one is using any sect attrs
+		 * at this point.  Deallocate immediately.
+		 */
+		free_sect_attrs(mod->sect_attrs);
+		mod->sect_attrs = NULL;
+	}
+}
+
+/*
+ * /sys/module/foo/notes/.section.name gives contents of SHT_NOTE sections.
+ */
+
+struct module_notes_attrs {
+	struct kobject *dir;
+	unsigned int notes;
+	struct bin_attribute attrs[];
+};
+
+static ssize_t module_notes_read(struct file *filp, struct kobject *kobj,
+				 struct bin_attribute *bin_attr,
+				 char *buf, loff_t pos, size_t count)
+{
+	/*
+	 * The caller checked the pos and count against our size.
+	 */
+	memcpy(buf, bin_attr->private + pos, count);
+	return count;
+}
+
+static void free_notes_attrs(struct module_notes_attrs *notes_attrs,
+			     unsigned int i)
+{
+	if (notes_attrs->dir) {
+		while (i-- > 0)
+			sysfs_remove_bin_file(notes_attrs->dir,
+					      &notes_attrs->attrs[i]);
+		kobject_put(notes_attrs->dir);
+	}
+	kfree(notes_attrs);
+}
+
+static void add_notes_attrs(struct module *mod, const struct load_info *info)
+{
+	unsigned int notes, loaded, i;
+	struct module_notes_attrs *notes_attrs;
+	struct bin_attribute *nattr;
+
+	/* failed to create section attributes, so can't create notes */
+	if (!mod->sect_attrs)
+		return;
+
+	/* Count notes sections and allocate structures.  */
+	notes = 0;
+	for (i = 0; i < info->hdr->e_shnum; i++)
+		if (!sect_empty(&info->sechdrs[i]) &&
+		    info->sechdrs[i].sh_type == SHT_NOTE)
+			++notes;
+
+	if (notes == 0)
+		return;
+
+	notes_attrs = kzalloc(struct_size(notes_attrs, attrs, notes),
+			      GFP_KERNEL);
+	if (!notes_attrs)
+		return;
+
+	notes_attrs->notes = notes;
+	nattr = &notes_attrs->attrs[0];
+	for (loaded = i = 0; i < info->hdr->e_shnum; ++i) {
+		if (sect_empty(&info->sechdrs[i]))
+			continue;
+		if (info->sechdrs[i].sh_type == SHT_NOTE) {
+			sysfs_bin_attr_init(nattr);
+			nattr->attr.name = mod->sect_attrs->attrs[loaded].battr.attr.name;
+			nattr->attr.mode = 0444;
+			nattr->size = info->sechdrs[i].sh_size;
+			nattr->private = (void *)info->sechdrs[i].sh_addr;
+			nattr->read = module_notes_read;
+			++nattr;
+		}
+		++loaded;
+	}
+
+	notes_attrs->dir = kobject_create_and_add("notes", &mod->mkobj.kobj);
+	if (!notes_attrs->dir)
+		goto out;
+
+	for (i = 0; i < notes; ++i)
+		if (sysfs_create_bin_file(notes_attrs->dir,
+					  &notes_attrs->attrs[i]))
+			goto out;
+
+	mod->notes_attrs = notes_attrs;
+	return;
+
+out:
+	free_notes_attrs(notes_attrs, i);
+}
+
+static void remove_notes_attrs(struct module *mod)
+{
+	if (mod->notes_attrs)
+		free_notes_attrs(mod->notes_attrs, mod->notes_attrs->notes);
+}
+
+#else /* !CONFIG_KALLSYMS */
+static inline void add_sect_attrs(struct module *mod, const struct load_info *info) { }
+static inline void remove_sect_attrs(struct module *mod) { }
+static inline void add_notes_attrs(struct module *mod, const struct load_info *info) { }
+static inline void remove_notes_attrs(struct module *mod) { }
+#endif /* CONFIG_KALLSYMS */
+
+static void del_usage_links(struct module *mod)
+{
+#ifdef CONFIG_MODULE_UNLOAD
+	struct module_use *use;
+
+	mutex_lock(&module_mutex);
+	list_for_each_entry(use, &mod->target_list, target_list)
+		sysfs_remove_link(use->target->holders_dir, mod->name);
+	mutex_unlock(&module_mutex);
+#endif
+}
+
+static int add_usage_links(struct module *mod)
+{
+	int ret = 0;
+#ifdef CONFIG_MODULE_UNLOAD
+	struct module_use *use;
+
+	mutex_lock(&module_mutex);
+	list_for_each_entry(use, &mod->target_list, target_list) {
+		ret = sysfs_create_link(use->target->holders_dir,
+					&mod->mkobj.kobj, mod->name);
+		if (ret)
+			break;
+	}
+	mutex_unlock(&module_mutex);
+	if (ret)
+		del_usage_links(mod);
+#endif
+	return ret;
+}
+
+static void module_remove_modinfo_attrs(struct module *mod, int end)
+{
+	struct module_attribute *attr;
+	int i;
+
+	for (i = 0; (attr = &mod->modinfo_attrs[i]); i++) {
+		if (end >= 0 && i > end)
+			break;
+		/* pick a field to test for end of list */
+		if (!attr->attr.name)
+			break;
+		sysfs_remove_file(&mod->mkobj.kobj, &attr->attr);
+		if (attr->free)
+			attr->free(mod);
+	}
+	kfree(mod->modinfo_attrs);
+}
+
+static int module_add_modinfo_attrs(struct module *mod)
+{
+	struct module_attribute *attr;
+	struct module_attribute *temp_attr;
+	int error = 0;
+	int i;
+
+	mod->modinfo_attrs = kzalloc((sizeof(struct module_attribute) *
+					(modinfo_attrs_count + 1)),
+					GFP_KERNEL);
+	if (!mod->modinfo_attrs)
+		return -ENOMEM;
+
+	temp_attr = mod->modinfo_attrs;
+	for (i = 0; (attr = modinfo_attrs[i]); i++) {
+		if (!attr->test || attr->test(mod)) {
+			memcpy(temp_attr, attr, sizeof(*temp_attr));
+			sysfs_attr_init(&temp_attr->attr);
+			error = sysfs_create_file(&mod->mkobj.kobj,
+						  &temp_attr->attr);
+			if (error)
+				goto error_out;
+			++temp_attr;
+		}
+	}
+
+	return 0;
+
+error_out:
+	if (i > 0)
+		module_remove_modinfo_attrs(mod, --i);
+	else
+		kfree(mod->modinfo_attrs);
+	return error;
+}
+
+static void mod_kobject_put(struct module *mod)
+{
+	DECLARE_COMPLETION_ONSTACK(c);
+
+	mod->mkobj.kobj_completion = &c;
+	kobject_put(&mod->mkobj.kobj);
+	wait_for_completion(&c);
+}
+
+static int mod_sysfs_init(struct module *mod)
+{
+	int err;
+	struct kobject *kobj;
+
+	if (!module_sysfs_initialized) {
+		pr_err("%s: module sysfs not initialized\n", mod->name);
+		err = -EINVAL;
+		goto out;
+	}
+
+	kobj = kset_find_obj(module_kset, mod->name);
+	if (kobj) {
+		pr_err("%s: module is already loaded\n", mod->name);
+		kobject_put(kobj);
+		err = -EINVAL;
+		goto out;
+	}
+
+	mod->mkobj.mod = mod;
+
+	memset(&mod->mkobj.kobj, 0, sizeof(mod->mkobj.kobj));
+	mod->mkobj.kobj.kset = module_kset;
+	err = kobject_init_and_add(&mod->mkobj.kobj, &module_ktype, NULL,
+				   "%s", mod->name);
+	if (err)
+		mod_kobject_put(mod);
+
+out:
+	return err;
+}
+
+int mod_sysfs_setup(struct module *mod,
+		    const struct load_info *info,
+			   struct kernel_param *kparam,
+			   unsigned int num_params)
+{
+	int err;
+
+	err = mod_sysfs_init(mod);
+	if (err)
+		goto out;
+
+	mod->holders_dir = kobject_create_and_add("holders", &mod->mkobj.kobj);
+	if (!mod->holders_dir) {
+		err = -ENOMEM;
+		goto out_unreg;
+	}
+
+	err = module_param_sysfs_setup(mod, kparam, num_params);
+	if (err)
+		goto out_unreg_holders;
+
+	err = module_add_modinfo_attrs(mod);
+	if (err)
+		goto out_unreg_param;
+
+	err = add_usage_links(mod);
+	if (err)
+		goto out_unreg_modinfo_attrs;
+
+	add_sect_attrs(mod, info);
+	add_notes_attrs(mod, info);
+
+	return 0;
+
+out_unreg_modinfo_attrs:
+	module_remove_modinfo_attrs(mod, -1);
+out_unreg_param:
+	module_param_sysfs_remove(mod);
+out_unreg_holders:
+	kobject_put(mod->holders_dir);
+out_unreg:
+	mod_kobject_put(mod);
+out:
+	return err;
+}
+
+static void mod_sysfs_fini(struct module *mod)
+{
+	remove_notes_attrs(mod);
+	remove_sect_attrs(mod);
+	mod_kobject_put(mod);
+}
+
+void mod_sysfs_teardown(struct module *mod)
+{
+	del_usage_links(mod);
+	module_remove_modinfo_attrs(mod, -1);
+	module_param_sysfs_remove(mod);
+	kobject_put(mod->mkobj.drivers_dir);
+	kobject_put(mod->holders_dir);
+	mod_sysfs_fini(mod);
+}
+
+void init_param_lock(struct module *mod)
+{
+	mutex_init(&mod->param_lock);
+}
-- 
2.34.1


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

* [PATCH v8 12/13] module: Move kdb_modules list out of core code
  2022-02-22 14:12 [PATCH v8 00/13] module: core code clean up Aaron Tomlin
                   ` (10 preceding siblings ...)
  2022-02-22 14:13 ` [PATCH v8 11/13] module: Move sysfs " Aaron Tomlin
@ 2022-02-22 14:13 ` Aaron Tomlin
  2022-02-22 18:05   ` Christophe Leroy
  2022-02-22 14:13 ` [PATCH v8 13/13] module: Move version support into a separate file Aaron Tomlin
  12 siblings, 1 reply; 43+ messages in thread
From: Aaron Tomlin @ 2022-02-22 14:13 UTC (permalink / raw)
  To: mcgrof, christophe.leroy
  Cc: cl, pmladek, mbenes, akpm, jeyu, linux-kernel, linux-modules,
	void, atomlin, allen.lkml, joe, msuchanek, oleksandr

No functional change.

This patch migrates kdb_modules list to core kdb code
since the list of added/or loaded modules is no longer
private.

Signed-off-by: Aaron Tomlin <atomlin@redhat.com>
---
 kernel/debug/kdb/kdb_main.c    | 5 +++++
 kernel/debug/kdb/kdb_private.h | 4 ----
 kernel/module/main.c           | 4 ----
 3 files changed, 5 insertions(+), 8 deletions(-)

diff --git a/kernel/debug/kdb/kdb_main.c b/kernel/debug/kdb/kdb_main.c
index 0852a537dad4..5369bf45c5d4 100644
--- a/kernel/debug/kdb/kdb_main.c
+++ b/kernel/debug/kdb/kdb_main.c
@@ -59,6 +59,11 @@ EXPORT_SYMBOL(kdb_grepping_flag);
 int kdb_grep_leading;
 int kdb_grep_trailing;
 
+#ifdef CONFIG_MODULES
+extern struct list_head modules;
+static struct list_head *kdb_modules = &modules; /* kdb needs the list of modules */
+#endif /* CONFIG_MODULES */
+
 /*
  * Kernel debugger state flags
  */
diff --git a/kernel/debug/kdb/kdb_private.h b/kernel/debug/kdb/kdb_private.h
index 0d2f9feea0a4..1f8c519a5f81 100644
--- a/kernel/debug/kdb/kdb_private.h
+++ b/kernel/debug/kdb/kdb_private.h
@@ -226,10 +226,6 @@ extern void kdb_kbd_cleanup_state(void);
 #define kdb_kbd_cleanup_state()
 #endif /* ! CONFIG_KDB_KEYBOARD */
 
-#ifdef CONFIG_MODULES
-extern struct list_head *kdb_modules;
-#endif /* CONFIG_MODULES */
-
 extern char kdb_prompt_str[];
 
 #define	KDB_WORD_SIZE	((int)sizeof(unsigned long))
diff --git a/kernel/module/main.c b/kernel/module/main.c
index b8a59b5c3e3a..bcc4f7a82649 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -108,10 +108,6 @@ static void mod_update_bounds(struct module *mod)
 		__mod_update_bounds(mod->init_layout.base, mod->init_layout.size);
 }
 
-#ifdef CONFIG_KGDB_KDB
-struct list_head *kdb_modules = &modules; /* kdb needs the list of modules */
-#endif /* CONFIG_KGDB_KDB */
-
 static void module_assert_mutex_or_preempt(void)
 {
 #ifdef CONFIG_LOCKDEP
-- 
2.34.1


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

* [PATCH v8 13/13] module: Move version support into a separate file
  2022-02-22 14:12 [PATCH v8 00/13] module: core code clean up Aaron Tomlin
                   ` (11 preceding siblings ...)
  2022-02-22 14:13 ` [PATCH v8 12/13] module: Move kdb_modules list out of core code Aaron Tomlin
@ 2022-02-22 14:13 ` Aaron Tomlin
  2022-02-22 18:06   ` Christophe Leroy
  12 siblings, 1 reply; 43+ messages in thread
From: Aaron Tomlin @ 2022-02-22 14:13 UTC (permalink / raw)
  To: mcgrof, christophe.leroy
  Cc: cl, pmladek, mbenes, akpm, jeyu, linux-kernel, linux-modules,
	void, atomlin, allen.lkml, joe, msuchanek, oleksandr

No functional change.

This patch migrates module version support out of core code into
kernel/module/version.c. In addition simple code refactoring to
make this possible.

Signed-off-by: Aaron Tomlin <atomlin@redhat.com>
---
 kernel/module/Makefile   |   1 +
 kernel/module/internal.h |  48 ++++++++++++
 kernel/module/main.c     | 156 ++-------------------------------------
 kernel/module/version.c  | 109 +++++++++++++++++++++++++++
 4 files changed, 166 insertions(+), 148 deletions(-)
 create mode 100644 kernel/module/version.c

diff --git a/kernel/module/Makefile b/kernel/module/Makefile
index cf8dcdc6b55f..a46e6361017f 100644
--- a/kernel/module/Makefile
+++ b/kernel/module/Makefile
@@ -17,3 +17,4 @@ obj-$(CONFIG_DEBUG_KMEMLEAK) += debug_kmemleak.o
 obj-$(CONFIG_KALLSYMS) += kallsyms.o
 obj-$(CONFIG_PROC_FS) += procfs.o
 obj-$(CONFIG_SYSFS) += sysfs.o
+obj-$(CONFIG_MODVERSIONS) += version.o
diff --git a/kernel/module/internal.h b/kernel/module/internal.h
index 62d749ef695e..3fc139d5074b 100644
--- a/kernel/module/internal.h
+++ b/kernel/module/internal.h
@@ -70,7 +70,27 @@ struct load_info {
 	} index;
 };
 
+enum mod_license {
+	NOT_GPL_ONLY,
+	GPL_ONLY,
+};
+
+struct find_symbol_arg {
+	/* Input */
+	const char *name;
+	bool gplok;
+	bool warn;
+
+	/* Output */
+	struct module *owner;
+	const s32 *crc;
+	const struct kernel_symbol *sym;
+	enum mod_license license;
+};
+
 int mod_verify_sig(const void *mod, struct load_info *info);
+int try_to_force_load(struct module *mod, const char *reason);
+bool find_symbol(struct find_symbol_arg *fsa);
 struct module *find_module_all(const char *name, size_t len, bool even_unformed);
 int cmp_name(const void *name, const void *sym);
 long module_get_offset(struct module *mod, unsigned int *size, Elf_Shdr *sechdr,
@@ -225,3 +245,31 @@ static inline int mod_sysfs_setup(struct module *mod,
 static inline void mod_sysfs_teardown(struct module *mod) { }
 static inline void init_param_lock(struct module *mod) { }
 #endif /* CONFIG_SYSFS */
+
+#ifdef CONFIG_MODVERSIONS
+int check_version(const struct load_info *info,
+		  const char *symname, struct module *mod, const s32 *crc);
+void module_layout(struct module *mod, struct modversion_info *ver, struct kernel_param *kp,
+		   struct kernel_symbol *ks, struct tracepoint * const *tp);
+int check_modstruct_version(const struct load_info *info, struct module *mod);
+int same_magic(const char *amagic, const char *bmagic, bool has_crcs);
+#else /* !CONFIG_MODVERSIONS */
+static inline int check_version(const struct load_info *info,
+				const char *symname,
+				struct module *mod,
+				const s32 *crc)
+{
+	return 1;
+}
+
+static inline int check_modstruct_version(const struct load_info *info,
+					  struct module *mod)
+{
+	return 1;
+}
+
+static inline int same_magic(const char *amagic, const char *bmagic, bool has_crcs)
+{
+	return strcmp(amagic, bmagic) == 0;
+}
+#endif /* CONFIG_MODVERSIONS */
diff --git a/kernel/module/main.c b/kernel/module/main.c
index bcc4f7a82649..0749afdc34b5 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -86,6 +86,12 @@ struct mod_tree_root mod_tree __cacheline_aligned = {
 static unsigned long module_addr_min = -1UL, module_addr_max;
 #endif /* CONFIG_MODULES_TREE_LOOKUP */
 
+struct symsearch {
+	const struct kernel_symbol *start, *stop;
+	const s32 *crcs;
+	enum mod_license license;
+};
+
 /*
  * Bounds of module text, for speeding up __module_address.
  * Protected by module_mutex.
@@ -244,28 +250,6 @@ static __maybe_unused void *any_section_objs(const struct load_info *info,
 #define symversion(base, idx) ((base != NULL) ? ((base) + (idx)) : NULL)
 #endif
 
-struct symsearch {
-	const struct kernel_symbol *start, *stop;
-	const s32 *crcs;
-	enum mod_license {
-		NOT_GPL_ONLY,
-		GPL_ONLY,
-	} license;
-};
-
-struct find_symbol_arg {
-	/* Input */
-	const char *name;
-	bool gplok;
-	bool warn;
-
-	/* Output */
-	struct module *owner;
-	const s32 *crc;
-	const struct kernel_symbol *sym;
-	enum mod_license license;
-};
-
 static bool check_exported_symbol(const struct symsearch *syms,
 				  struct module *owner,
 				  unsigned int symnum, void *data)
@@ -327,7 +311,7 @@ static bool find_exported_symbol_in_section(const struct symsearch *syms,
  * Find an exported symbol and return it, along with, (optional) crc and
  * (optional) module which owns it.  Needs preempt disabled or module_mutex.
  */
-static bool find_symbol(struct find_symbol_arg *fsa)
+bool find_symbol(struct find_symbol_arg *fsa)
 {
 	static const struct symsearch arr[] = {
 		{ __start___ksymtab, __stop___ksymtab, __start___kcrctab,
@@ -1001,7 +985,7 @@ size_t modinfo_attrs_count = ARRAY_SIZE(modinfo_attrs);
 
 static const char vermagic[] = VERMAGIC_STRING;
 
-static int try_to_force_load(struct module *mod, const char *reason)
+int try_to_force_load(struct module *mod, const char *reason)
 {
 #ifdef CONFIG_MODULE_FORCE_LOAD
 	if (!test_taint(TAINT_FORCED_MODULE))
@@ -1013,115 +997,6 @@ static int try_to_force_load(struct module *mod, const char *reason)
 #endif
 }
 
-#ifdef CONFIG_MODVERSIONS
-
-static u32 resolve_rel_crc(const s32 *crc)
-{
-	return *(u32 *)((void *)crc + *crc);
-}
-
-static int check_version(const struct load_info *info,
-			 const char *symname,
-			 struct module *mod,
-			 const s32 *crc)
-{
-	Elf_Shdr *sechdrs = info->sechdrs;
-	unsigned int versindex = info->index.vers;
-	unsigned int i, num_versions;
-	struct modversion_info *versions;
-
-	/* Exporting module didn't supply crcs?  OK, we're already tainted. */
-	if (!crc)
-		return 1;
-
-	/* No versions at all?  modprobe --force does this. */
-	if (versindex == 0)
-		return try_to_force_load(mod, symname) == 0;
-
-	versions = (void *) sechdrs[versindex].sh_addr;
-	num_versions = sechdrs[versindex].sh_size
-		/ sizeof(struct modversion_info);
-
-	for (i = 0; i < num_versions; i++) {
-		u32 crcval;
-
-		if (strcmp(versions[i].name, symname) != 0)
-			continue;
-
-		if (IS_ENABLED(CONFIG_MODULE_REL_CRCS))
-			crcval = resolve_rel_crc(crc);
-		else
-			crcval = *crc;
-		if (versions[i].crc == crcval)
-			return 1;
-		pr_debug("Found checksum %X vs module %lX\n",
-			 crcval, versions[i].crc);
-		goto bad_version;
-	}
-
-	/* Broken toolchain. Warn once, then let it go.. */
-	pr_warn_once("%s: no symbol version for %s\n", info->name, symname);
-	return 1;
-
-bad_version:
-	pr_warn("%s: disagrees about version of symbol %s\n",
-	       info->name, symname);
-	return 0;
-}
-
-static inline int check_modstruct_version(const struct load_info *info,
-					  struct module *mod)
-{
-	struct find_symbol_arg fsa = {
-		.name	= "module_layout",
-		.gplok	= true,
-	};
-
-	/*
-	 * Since this should be found in kernel (which can't be removed), no
-	 * locking is necessary -- use preempt_disable() to placate lockdep.
-	 */
-	preempt_disable();
-	if (!find_symbol(&fsa)) {
-		preempt_enable();
-		BUG();
-	}
-	preempt_enable();
-	return check_version(info, "module_layout", mod, fsa.crc);
-}
-
-/* First part is kernel version, which we ignore if module has crcs. */
-static inline int same_magic(const char *amagic, const char *bmagic,
-			     bool has_crcs)
-{
-	if (has_crcs) {
-		amagic += strcspn(amagic, " ");
-		bmagic += strcspn(bmagic, " ");
-	}
-	return strcmp(amagic, bmagic) == 0;
-}
-#else
-static inline int check_version(const struct load_info *info,
-				const char *symname,
-				struct module *mod,
-				const s32 *crc)
-{
-	return 1;
-}
-
-static inline int check_modstruct_version(const struct load_info *info,
-					  struct module *mod)
-{
-	return 1;
-}
-
-static inline int same_magic(const char *amagic, const char *bmagic,
-			     bool has_crcs)
-{
-	return strcmp(amagic, bmagic) == 0;
-}
-#endif /* CONFIG_MODVERSIONS */
-
 static char *get_modinfo(const struct load_info *info, const char *tag);
 static char *get_next_modinfo(const struct load_info *info, const char *tag,
 			      char *prev);
@@ -3247,18 +3122,3 @@ void print_modules(void)
 		pr_cont(" [last unloaded: %s]", last_unloaded_module);
 	pr_cont("\n");
 }
-
-#ifdef CONFIG_MODVERSIONS
-/*
- * Generate the signature for all relevant module structures here.
- * If these change, we don't want to try to parse the module.
- */
-void module_layout(struct module *mod,
-		   struct modversion_info *ver,
-		   struct kernel_param *kp,
-		   struct kernel_symbol *ks,
-		   struct tracepoint * const *tp)
-{
-}
-EXPORT_SYMBOL(module_layout);
-#endif
diff --git a/kernel/module/version.c b/kernel/module/version.c
new file mode 100644
index 000000000000..adaedce1dc97
--- /dev/null
+++ b/kernel/module/version.c
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Module version support
+ *
+ * Copyright (C) 2008 Rusty Russell
+ */
+
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/printk.h>
+#include "internal.h"
+
+static u32 resolve_rel_crc(const s32 *crc)
+{
+	return *(u32 *)((void *)crc + *crc);
+}
+
+int check_version(const struct load_info *info,
+		  const char *symname,
+			 struct module *mod,
+			 const s32 *crc)
+{
+	Elf_Shdr *sechdrs = info->sechdrs;
+	unsigned int versindex = info->index.vers;
+	unsigned int i, num_versions;
+	struct modversion_info *versions;
+
+	/* Exporting module didn't supply crcs?  OK, we're already tainted. */
+	if (!crc)
+		return 1;
+
+	/* No versions at all?  modprobe --force does this. */
+	if (versindex == 0)
+		return try_to_force_load(mod, symname) == 0;
+
+	versions = (void *)sechdrs[versindex].sh_addr;
+	num_versions = sechdrs[versindex].sh_size
+		/ sizeof(struct modversion_info);
+
+	for (i = 0; i < num_versions; i++) {
+		u32 crcval;
+
+		if (strcmp(versions[i].name, symname) != 0)
+			continue;
+
+		if (IS_ENABLED(CONFIG_MODULE_REL_CRCS))
+			crcval = resolve_rel_crc(crc);
+		else
+			crcval = *crc;
+		if (versions[i].crc == crcval)
+			return 1;
+		pr_debug("Found checksum %X vs module %lX\n",
+			 crcval, versions[i].crc);
+		goto bad_version;
+	}
+
+	/* Broken toolchain. Warn once, then let it go.. */
+	pr_warn_once("%s: no symbol version for %s\n", info->name, symname);
+	return 1;
+
+bad_version:
+	pr_warn("%s: disagrees about version of symbol %s\n", info->name, symname);
+	return 0;
+}
+
+int check_modstruct_version(const struct load_info *info,
+			    struct module *mod)
+{
+	struct find_symbol_arg fsa = {
+		.name	= "module_layout",
+		.gplok	= true,
+	};
+
+	/*
+	 * Since this should be found in kernel (which can't be removed), no
+	 * locking is necessary -- use preempt_disable() to placate lockdep.
+	 */
+	preempt_disable();
+	if (!find_symbol(&fsa)) {
+		preempt_enable();
+		BUG();
+	}
+	preempt_enable();
+	return check_version(info, "module_layout", mod, fsa.crc);
+}
+
+/* First part is kernel version, which we ignore if module has crcs. */
+int same_magic(const char *amagic, const char *bmagic,
+	       bool has_crcs)
+{
+	if (has_crcs) {
+		amagic += strcspn(amagic, " ");
+		bmagic += strcspn(bmagic, " ");
+	}
+	return strcmp(amagic, bmagic) == 0;
+}
+
+/*
+ * Generate the signature for all relevant module structures here.
+ * If these change, we don't want to try to parse the module.
+ */
+void module_layout(struct module *mod,
+		   struct modversion_info *ver,
+		   struct kernel_param *kp,
+		   struct kernel_symbol *ks,
+		   struct tracepoint * const *tp)
+{
+}
+EXPORT_SYMBOL(module_layout);
-- 
2.34.1


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

* Re: [PATCH v8 01/13] module: Move all into module/
  2022-02-22 14:12 ` [PATCH v8 01/13] module: Move all into module/ Aaron Tomlin
@ 2022-02-22 17:58   ` Christophe Leroy
  2022-02-22 20:00   ` Allen
  1 sibling, 0 replies; 43+ messages in thread
From: Christophe Leroy @ 2022-02-22 17:58 UTC (permalink / raw)
  To: Aaron Tomlin, mcgrof
  Cc: cl, pmladek, mbenes, akpm, jeyu, linux-kernel, linux-modules,
	void, atomlin, allen.lkml, joe, msuchanek, oleksandr



Le 22/02/2022 à 15:12, Aaron Tomlin a écrit :
> No functional changes.
> 
> This patch moves all module related code into a separate directory,
> modifies each file name and creates a new Makefile. Note: this effort
> is in preparation to refactor core module code.
> 
> Signed-off-by: Aaron Tomlin <atomlin@redhat.com>

Reviewed-by: Christophe Leroy <christophe.leroy@csgroup.eu>

> ---
>   MAINTAINERS                                         |  2 +-
>   kernel/Makefile                                     |  5 +----
>   kernel/module/Makefile                              | 12 ++++++++++++
>   kernel/{module_decompress.c => module/decompress.c} |  2 +-
>   kernel/{module-internal.h => module/internal.h}     |  0
>   kernel/{module.c => module/main.c}                  |  2 +-
>   kernel/{module_signing.c => module/signing.c}       |  2 +-
>   7 files changed, 17 insertions(+), 8 deletions(-)
>   create mode 100644 kernel/module/Makefile
>   rename kernel/{module_decompress.c => module/decompress.c} (99%)
>   rename kernel/{module-internal.h => module/internal.h} (100%)
>   rename kernel/{module.c => module/main.c} (99%)
>   rename kernel/{module_signing.c => module/signing.c} (97%)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index bd86ed9fbc79..463bdb829db4 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -13012,7 +13012,7 @@ L:	linux-kernel@vger.kernel.org
>   S:	Maintained
>   T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mcgrof/linux.git modules-next
>   F:	include/linux/module.h
> -F:	kernel/module.c
> +F:	kernel/module/
>   
>   MONOLITHIC POWER SYSTEM PMIC DRIVER
>   M:	Saravanan Sekar <sravanhome@gmail.com>
> diff --git a/kernel/Makefile b/kernel/Makefile
> index 56f4ee97f328..717075b65deb 100644
> --- a/kernel/Makefile
> +++ b/kernel/Makefile
> @@ -29,7 +29,6 @@ KCOV_INSTRUMENT_softirq.o := n
>   KCSAN_SANITIZE_softirq.o = n
>   # These are called from save_stack_trace() on slub debug path,
>   # and produce insane amounts of uninteresting coverage.
> -KCOV_INSTRUMENT_module.o := n
>   KCOV_INSTRUMENT_extable.o := n
>   KCOV_INSTRUMENT_stacktrace.o := n
>   # Don't self-instrument.
> @@ -53,6 +52,7 @@ obj-y += rcu/
>   obj-y += livepatch/
>   obj-y += dma/
>   obj-y += entry/
> +obj-$(CONFIG_MODULES) += module/
>   
>   obj-$(CONFIG_KCMP) += kcmp.o
>   obj-$(CONFIG_FREEZER) += freezer.o
> @@ -66,9 +66,6 @@ ifneq ($(CONFIG_SMP),y)
>   obj-y += up.o
>   endif
>   obj-$(CONFIG_UID16) += uid16.o
> -obj-$(CONFIG_MODULES) += module.o
> -obj-$(CONFIG_MODULE_DECOMPRESS) += module_decompress.o
> -obj-$(CONFIG_MODULE_SIG) += module_signing.o
>   obj-$(CONFIG_MODULE_SIG_FORMAT) += module_signature.o
>   obj-$(CONFIG_KALLSYMS) += kallsyms.o
>   obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
> diff --git a/kernel/module/Makefile b/kernel/module/Makefile
> new file mode 100644
> index 000000000000..cdd5c61b8c7f
> --- /dev/null
> +++ b/kernel/module/Makefile
> @@ -0,0 +1,12 @@
> +# SPDX-License-Identifier: GPL-2.0-only
> +#
> +# Makefile for linux kernel module support
> +#
> +
> +# These are called from save_stack_trace() on slub debug path,
> +# and produce insane amounts of uninteresting coverage.
> +KCOV_INSTRUMENT_module.o := n
> +
> +obj-y += main.o
> +obj-$(CONFIG_MODULE_DECOMPRESS) += decompress.o
> +obj-$(CONFIG_MODULE_SIG) += signing.o
> diff --git a/kernel/module_decompress.c b/kernel/module/decompress.c
> similarity index 99%
> rename from kernel/module_decompress.c
> rename to kernel/module/decompress.c
> index ffef98a20320..d14d6443225a 100644
> --- a/kernel/module_decompress.c
> +++ b/kernel/module/decompress.c
> @@ -12,7 +12,7 @@
>   #include <linux/sysfs.h>
>   #include <linux/vmalloc.h>
>   
> -#include "module-internal.h"
> +#include "internal.h"
>   
>   static int module_extend_max_pages(struct load_info *info, unsigned int extent)
>   {
> diff --git a/kernel/module-internal.h b/kernel/module/internal.h
> similarity index 100%
> rename from kernel/module-internal.h
> rename to kernel/module/internal.h
> diff --git a/kernel/module.c b/kernel/module/main.c
> similarity index 99%
> rename from kernel/module.c
> rename to kernel/module/main.c
> index 46a5c2ed1928..34a2b0cf3c3e 100644
> --- a/kernel/module.c
> +++ b/kernel/module/main.c
> @@ -58,7 +58,7 @@
>   #include <linux/dynamic_debug.h>
>   #include <linux/audit.h>
>   #include <uapi/linux/module.h>
> -#include "module-internal.h"
> +#include "internal.h"
>   
>   #define CREATE_TRACE_POINTS
>   #include <trace/events/module.h>
> diff --git a/kernel/module_signing.c b/kernel/module/signing.c
> similarity index 97%
> rename from kernel/module_signing.c
> rename to kernel/module/signing.c
> index 8723ae70ea1f..8aeb6d2ee94b 100644
> --- a/kernel/module_signing.c
> +++ b/kernel/module/signing.c
> @@ -12,7 +12,7 @@
>   #include <linux/string.h>
>   #include <linux/verification.h>
>   #include <crypto/public_key.h>
> -#include "module-internal.h"
> +#include "internal.h"
>   
>   /*
>    * Verify the signature on a module.

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

* Re: [PATCH v8 02/13] module: Simple refactor in preparation for split
  2022-02-22 14:12 ` [PATCH v8 02/13] module: Simple refactor in preparation for split Aaron Tomlin
@ 2022-02-22 17:58   ` Christophe Leroy
  0 siblings, 0 replies; 43+ messages in thread
From: Christophe Leroy @ 2022-02-22 17:58 UTC (permalink / raw)
  To: Aaron Tomlin, mcgrof
  Cc: cl, pmladek, mbenes, akpm, jeyu, linux-kernel, linux-modules,
	void, atomlin, allen.lkml, joe, msuchanek, oleksandr



Le 22/02/2022 à 15:12, Aaron Tomlin a écrit :
> No functional change.
> 
> This patch makes it possible to move non-essential code
> out of core module code.
> 
> Signed-off-by: Aaron Tomlin <atomlin@redhat.com>

Reviewed-by: Christophe Leroy <christophe.leroy@csgroup.eu>

> ---
>   kernel/module/internal.h | 21 +++++++++++++++++++++
>   kernel/module/main.c     | 22 ++--------------------
>   2 files changed, 23 insertions(+), 20 deletions(-)
> 
> diff --git a/kernel/module/internal.h b/kernel/module/internal.h
> index 8c381c99062f..ea8c4c02614c 100644
> --- a/kernel/module/internal.h
> +++ b/kernel/module/internal.h
> @@ -7,6 +7,27 @@
>   
>   #include <linux/elf.h>
>   #include <asm/module.h>
> +#include <linux/mutex.h>
> +
> +#ifndef ARCH_SHF_SMALL
> +#define ARCH_SHF_SMALL 0
> +#endif
> +
> +/* If this is set, the section belongs in the init part of the module */
> +#define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG - 1))
> +/* Maximum number of characters written by module_flags() */
> +#define MODULE_FLAGS_BUF_SIZE (TAINT_FLAGS_COUNT + 4)
> +
> +extern struct mutex module_mutex;
> +extern struct list_head modules;
> +
> +/* Provided by the linker */
> +extern const struct kernel_symbol __start___ksymtab[];
> +extern const struct kernel_symbol __stop___ksymtab[];
> +extern const struct kernel_symbol __start___ksymtab_gpl[];
> +extern const struct kernel_symbol __stop___ksymtab_gpl[];
> +extern const s32 __start___kcrctab[];
> +extern const s32 __start___kcrctab_gpl[];
>   
>   struct load_info {
>   	const char *name;
> diff --git a/kernel/module/main.c b/kernel/module/main.c
> index 34a2b0cf3c3e..5f5e21f972dd 100644
> --- a/kernel/module/main.c
> +++ b/kernel/module/main.c
> @@ -63,10 +63,6 @@
>   #define CREATE_TRACE_POINTS
>   #include <trace/events/module.h>
>   
> -#ifndef ARCH_SHF_SMALL
> -#define ARCH_SHF_SMALL 0
> -#endif
> -
>   /*
>    * Modules' sections will be aligned on page boundaries
>    * to ensure complete separation of code and data, but
> @@ -78,9 +74,6 @@
>   # define debug_align(X) (X)
>   #endif
>   
> -/* If this is set, the section belongs in the init part of the module */
> -#define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1))
> -
>   /*
>    * Mutex protects:
>    * 1) List of modules (also safely readable with preempt_disable),
> @@ -88,8 +81,8 @@
>    * 3) module_addr_min/module_addr_max.
>    * (delete and add uses RCU list operations).
>    */
> -static DEFINE_MUTEX(module_mutex);
> -static LIST_HEAD(modules);
> +DEFINE_MUTEX(module_mutex);
> +LIST_HEAD(modules);
>   
>   /* Work queue for freeing init sections in success case */
>   static void do_free_init(struct work_struct *w);
> @@ -408,14 +401,6 @@ static __maybe_unused void *any_section_objs(const struct load_info *info,
>   	return (void *)info->sechdrs[sec].sh_addr;
>   }
>   
> -/* Provided by the linker */
> -extern const struct kernel_symbol __start___ksymtab[];
> -extern const struct kernel_symbol __stop___ksymtab[];
> -extern const struct kernel_symbol __start___ksymtab_gpl[];
> -extern const struct kernel_symbol __stop___ksymtab_gpl[];
> -extern const s32 __start___kcrctab[];
> -extern const s32 __start___kcrctab_gpl[];
> -
>   #ifndef CONFIG_MODVERSIONS
>   #define symversion(base, idx) NULL
>   #else
> @@ -4542,9 +4527,6 @@ static void cfi_cleanup(struct module *mod)
>   #endif
>   }
>   
> -/* Maximum number of characters written by module_flags() */
> -#define MODULE_FLAGS_BUF_SIZE (TAINT_FLAGS_COUNT + 4)
> -
>   /* Keep in sync with MODULE_FLAGS_BUF_SIZE !!! */
>   static char *module_flags(struct module *mod, char *buf)
>   {

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

* Re: [PATCH v8 04/13] module: Move livepatch support to a separate file
  2022-02-22 14:12 ` [PATCH v8 04/13] module: Move livepatch support to a separate file Aaron Tomlin
@ 2022-02-22 17:58   ` Christophe Leroy
  2022-02-25  9:34   ` Petr Mladek
  1 sibling, 0 replies; 43+ messages in thread
From: Christophe Leroy @ 2022-02-22 17:58 UTC (permalink / raw)
  To: Aaron Tomlin, mcgrof
  Cc: cl, pmladek, mbenes, akpm, jeyu, linux-kernel, linux-modules,
	void, atomlin, allen.lkml, joe, msuchanek, oleksandr



Le 22/02/2022 à 15:12, Aaron Tomlin a écrit :
> No functional change.
> 
> This patch migrates livepatch support (i.e. used during module
> add/or load and remove/or deletion) from core module code into
> kernel/module/livepatch.c. At the moment it contains code to
> persist Elf information about a given livepatch module, only.
> 
> Signed-off-by: Aaron Tomlin <atomlin@redhat.com>

Reviewed-by: Christophe Leroy <christophe.leroy@csgroup.eu>

> ---
>   include/linux/module.h    |   9 ++--
>   kernel/module/Makefile    |   1 +
>   kernel/module/internal.h  |  22 ++++++++
>   kernel/module/livepatch.c |  74 +++++++++++++++++++++++++++
>   kernel/module/main.c      | 102 ++++----------------------------------
>   5 files changed, 110 insertions(+), 98 deletions(-)
>   create mode 100644 kernel/module/livepatch.c
> 
> diff --git a/include/linux/module.h b/include/linux/module.h
> index 1e135fd5c076..7ec9715de7dc 100644
> --- a/include/linux/module.h
> +++ b/include/linux/module.h
> @@ -663,17 +663,14 @@ static inline bool module_requested_async_probing(struct module *module)
>   	return module && module->async_probe_requested;
>   }
>   
> -#ifdef CONFIG_LIVEPATCH
>   static inline bool is_livepatch_module(struct module *mod)
>   {
> +#ifdef CONFIG_LIVEPATCH
>   	return mod->klp;
> -}
> -#else /* !CONFIG_LIVEPATCH */
> -static inline bool is_livepatch_module(struct module *mod)
> -{
> +#else
>   	return false;
> +#endif
>   }
> -#endif /* CONFIG_LIVEPATCH */
>   
>   bool is_module_sig_enforced(void);
>   void set_module_sig_enforced(void);
> diff --git a/kernel/module/Makefile b/kernel/module/Makefile
> index cdd5c61b8c7f..ed3aacb04f17 100644
> --- a/kernel/module/Makefile
> +++ b/kernel/module/Makefile
> @@ -10,3 +10,4 @@ KCOV_INSTRUMENT_module.o := n
>   obj-y += main.o
>   obj-$(CONFIG_MODULE_DECOMPRESS) += decompress.o
>   obj-$(CONFIG_MODULE_SIG) += signing.o
> +obj-$(CONFIG_LIVEPATCH) += livepatch.o
> diff --git a/kernel/module/internal.h b/kernel/module/internal.h
> index e0775e66bcf7..ad7a444253ed 100644
> --- a/kernel/module/internal.h
> +++ b/kernel/module/internal.h
> @@ -57,6 +57,28 @@ struct load_info {
>   
>   int mod_verify_sig(const void *mod, struct load_info *info);
>   
> +#ifdef CONFIG_LIVEPATCH
> +int copy_module_elf(struct module *mod, struct load_info *info);
> +void free_module_elf(struct module *mod);
> +#else /* !CONFIG_LIVEPATCH */
> +static inline int copy_module_elf(struct module *mod, struct load_info *info)
> +{
> +	return 0;
> +}
> +
> +static inline void free_module_elf(struct module *mod) { }
> +#endif /* CONFIG_LIVEPATCH */
> +
> +static inline bool set_livepatch_module(struct module *mod)
> +{
> +#ifdef CONFIG_LIVEPATCH
> +	mod->klp = true;
> +	return true;
> +#else
> +	return false;
> +#endif
> +}
> +
>   #ifdef CONFIG_MODULE_DECOMPRESS
>   int module_decompress(struct load_info *info, const void *buf, size_t size);
>   void module_decompress_cleanup(struct load_info *info);
> diff --git a/kernel/module/livepatch.c b/kernel/module/livepatch.c
> new file mode 100644
> index 000000000000..486d4ff92719
> --- /dev/null
> +++ b/kernel/module/livepatch.c
> @@ -0,0 +1,74 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Module livepatch support
> + *
> + * Copyright (C) 2016 Jessica Yu <jeyu@redhat.com>
> + */
> +
> +#include <linux/module.h>
> +#include <linux/string.h>
> +#include <linux/slab.h>
> +#include "internal.h"
> +
> +/*
> + * Persist Elf information about a module. Copy the Elf header,
> + * section header table, section string table, and symtab section
> + * index from info to mod->klp_info.
> + */
> +int copy_module_elf(struct module *mod, struct load_info *info)
> +{
> +	unsigned int size, symndx;
> +	int ret;
> +
> +	size = sizeof(*mod->klp_info);
> +	mod->klp_info = kmalloc(size, GFP_KERNEL);
> +	if (!mod->klp_info)
> +		return -ENOMEM;
> +
> +	/* Elf header */
> +	size = sizeof(mod->klp_info->hdr);
> +	memcpy(&mod->klp_info->hdr, info->hdr, size);
> +
> +	/* Elf section header table */
> +	size = sizeof(*info->sechdrs) * info->hdr->e_shnum;
> +	mod->klp_info->sechdrs = kmemdup(info->sechdrs, size, GFP_KERNEL);
> +	if (!mod->klp_info->sechdrs) {
> +		ret = -ENOMEM;
> +		goto free_info;
> +	}
> +
> +	/* Elf section name string table */
> +	size = info->sechdrs[info->hdr->e_shstrndx].sh_size;
> +	mod->klp_info->secstrings = kmemdup(info->secstrings, size, GFP_KERNEL);
> +	if (!mod->klp_info->secstrings) {
> +		ret = -ENOMEM;
> +		goto free_sechdrs;
> +	}
> +
> +	/* Elf symbol section index */
> +	symndx = info->index.sym;
> +	mod->klp_info->symndx = symndx;
> +
> +	/*
> +	 * For livepatch modules, core_kallsyms.symtab is a complete
> +	 * copy of the original symbol table. Adjust sh_addr to point
> +	 * to core_kallsyms.symtab since the copy of the symtab in module
> +	 * init memory is freed at the end of do_init_module().
> +	 */
> +	mod->klp_info->sechdrs[symndx].sh_addr = (unsigned long)mod->core_kallsyms.symtab;
> +
> +	return 0;
> +
> +free_sechdrs:
> +	kfree(mod->klp_info->sechdrs);
> +free_info:
> +	kfree(mod->klp_info);
> +	return ret;
> +}
> +
> +void free_module_elf(struct module *mod)
> +{
> +	kfree(mod->klp_info->sechdrs);
> +	kfree(mod->klp_info->secstrings);
> +	kfree(mod->klp_info);
> +}
> diff --git a/kernel/module/main.c b/kernel/module/main.c
> index 5f5e21f972dd..3596ebf3a6c3 100644
> --- a/kernel/module/main.c
> +++ b/kernel/module/main.c
> @@ -2043,81 +2043,6 @@ static int module_enforce_rwx_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
>   }
>   #endif /*  CONFIG_STRICT_MODULE_RWX */
>   
> -#ifdef CONFIG_LIVEPATCH
> -/*
> - * Persist Elf information about a module. Copy the Elf header,
> - * section header table, section string table, and symtab section
> - * index from info to mod->klp_info.
> - */
> -static int copy_module_elf(struct module *mod, struct load_info *info)
> -{
> -	unsigned int size, symndx;
> -	int ret;
> -
> -	size = sizeof(*mod->klp_info);
> -	mod->klp_info = kmalloc(size, GFP_KERNEL);
> -	if (mod->klp_info == NULL)
> -		return -ENOMEM;
> -
> -	/* Elf header */
> -	size = sizeof(mod->klp_info->hdr);
> -	memcpy(&mod->klp_info->hdr, info->hdr, size);
> -
> -	/* Elf section header table */
> -	size = sizeof(*info->sechdrs) * info->hdr->e_shnum;
> -	mod->klp_info->sechdrs = kmemdup(info->sechdrs, size, GFP_KERNEL);
> -	if (mod->klp_info->sechdrs == NULL) {
> -		ret = -ENOMEM;
> -		goto free_info;
> -	}
> -
> -	/* Elf section name string table */
> -	size = info->sechdrs[info->hdr->e_shstrndx].sh_size;
> -	mod->klp_info->secstrings = kmemdup(info->secstrings, size, GFP_KERNEL);
> -	if (mod->klp_info->secstrings == NULL) {
> -		ret = -ENOMEM;
> -		goto free_sechdrs;
> -	}
> -
> -	/* Elf symbol section index */
> -	symndx = info->index.sym;
> -	mod->klp_info->symndx = symndx;
> -
> -	/*
> -	 * For livepatch modules, core_kallsyms.symtab is a complete
> -	 * copy of the original symbol table. Adjust sh_addr to point
> -	 * to core_kallsyms.symtab since the copy of the symtab in module
> -	 * init memory is freed at the end of do_init_module().
> -	 */
> -	mod->klp_info->sechdrs[symndx].sh_addr = \
> -		(unsigned long) mod->core_kallsyms.symtab;
> -
> -	return 0;
> -
> -free_sechdrs:
> -	kfree(mod->klp_info->sechdrs);
> -free_info:
> -	kfree(mod->klp_info);
> -	return ret;
> -}
> -
> -static void free_module_elf(struct module *mod)
> -{
> -	kfree(mod->klp_info->sechdrs);
> -	kfree(mod->klp_info->secstrings);
> -	kfree(mod->klp_info);
> -}
> -#else /* !CONFIG_LIVEPATCH */
> -static int copy_module_elf(struct module *mod, struct load_info *info)
> -{
> -	return 0;
> -}
> -
> -static void free_module_elf(struct module *mod)
> -{
> -}
> -#endif /* CONFIG_LIVEPATCH */
> -
>   void __weak module_memfree(void *module_region)
>   {
>   	/*
> @@ -3092,30 +3017,23 @@ static int copy_chunked_from_user(void *dst, const void __user *usrc, unsigned l
>   	return 0;
>   }
>   
> -#ifdef CONFIG_LIVEPATCH
>   static int check_modinfo_livepatch(struct module *mod, struct load_info *info)
>   {
> -	if (get_modinfo(info, "livepatch")) {
> -		mod->klp = true;
> +	if (!get_modinfo(info, "livepatch"))
> +		/* Nothing more to do */
> +		return 0;
> +
> +	if (set_livepatch_module(mod)) {
>   		add_taint_module(mod, TAINT_LIVEPATCH, LOCKDEP_STILL_OK);
>   		pr_notice_once("%s: tainting kernel with TAINT_LIVEPATCH\n",
> -			       mod->name);
> -	}
> -
> -	return 0;
> -}
> -#else /* !CONFIG_LIVEPATCH */
> -static int check_modinfo_livepatch(struct module *mod, struct load_info *info)
> -{
> -	if (get_modinfo(info, "livepatch")) {
> -		pr_err("%s: module is marked as livepatch module, but livepatch support is disabled",
> -		       mod->name);
> -		return -ENOEXEC;
> +				mod->name);
> +		return 0;
>   	}
>   
> -	return 0;
> +	pr_err("%s: module is marked as livepatch module, but livepatch support is disabled",
> +	       mod->name);
> +	return -ENOEXEC;
>   }
> -#endif /* CONFIG_LIVEPATCH */
>   
>   static void check_modinfo_retpoline(struct module *mod, struct load_info *info)
>   {

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

* Re: [PATCH v8 05/13] module: Move latched RB-tree support to a separate file
  2022-02-22 14:12 ` [PATCH v8 05/13] module: Move latched RB-tree " Aaron Tomlin
@ 2022-02-22 17:58   ` Christophe Leroy
  0 siblings, 0 replies; 43+ messages in thread
From: Christophe Leroy @ 2022-02-22 17:58 UTC (permalink / raw)
  To: Aaron Tomlin, mcgrof
  Cc: cl, pmladek, mbenes, akpm, jeyu, linux-kernel, linux-modules,
	void, atomlin, allen.lkml, joe, msuchanek, oleksandr



Le 22/02/2022 à 15:12, Aaron Tomlin a écrit :
> No functional change.
> 
> This patch migrates module latched RB-tree support
> (e.g. see __module_address()) from core module code
> into kernel/module/tree_lookup.c.
> 
> Signed-off-by: Aaron Tomlin <atomlin@redhat.com>

Reviewed-by: Christophe Leroy <christophe.leroy@csgroup.eu>

> ---
>   kernel/module/Makefile      |   1 +
>   kernel/module/internal.h    |  33 +++++++++
>   kernel/module/main.c        | 130 ++----------------------------------
>   kernel/module/tree_lookup.c | 109 ++++++++++++++++++++++++++++++
>   4 files changed, 147 insertions(+), 126 deletions(-)
>   create mode 100644 kernel/module/tree_lookup.c
> 
> diff --git a/kernel/module/Makefile b/kernel/module/Makefile
> index ed3aacb04f17..88774e386276 100644
> --- a/kernel/module/Makefile
> +++ b/kernel/module/Makefile
> @@ -11,3 +11,4 @@ obj-y += main.o
>   obj-$(CONFIG_MODULE_DECOMPRESS) += decompress.o
>   obj-$(CONFIG_MODULE_SIG) += signing.o
>   obj-$(CONFIG_LIVEPATCH) += livepatch.o
> +obj-$(CONFIG_MODULES_TREE_LOOKUP) += tree_lookup.o
> diff --git a/kernel/module/internal.h b/kernel/module/internal.h
> index ad7a444253ed..f1682e3677be 100644
> --- a/kernel/module/internal.h
> +++ b/kernel/module/internal.h
> @@ -9,6 +9,7 @@
>   #include <linux/compiler.h>
>   #include <linux/module.h>
>   #include <linux/mutex.h>
> +#include <linux/rculist.h>
>   
>   #ifndef ARCH_SHF_SMALL
>   #define ARCH_SHF_SMALL 0
> @@ -93,3 +94,35 @@ static inline void module_decompress_cleanup(struct load_info *info)
>   {
>   }
>   #endif
> +
> +#ifdef CONFIG_MODULES_TREE_LOOKUP
> +struct mod_tree_root {
> +	struct latch_tree_root root;
> +	unsigned long addr_min;
> +	unsigned long addr_max;
> +};
> +
> +extern struct mod_tree_root mod_tree;
> +
> +void mod_tree_insert(struct module *mod);
> +void mod_tree_remove_init(struct module *mod);
> +void mod_tree_remove(struct module *mod);
> +struct module *mod_find(unsigned long addr);
> +#else /* !CONFIG_MODULES_TREE_LOOKUP */
> +
> +static inline void mod_tree_insert(struct module *mod) { }
> +static inline void mod_tree_remove_init(struct module *mod) { }
> +static inline void mod_tree_remove(struct module *mod) { }
> +static inline struct module *mod_find(unsigned long addr)
> +{
> +	struct module *mod;
> +
> +	list_for_each_entry_rcu(mod, &modules, list,
> +				lockdep_is_held(&module_mutex)) {
> +		if (within_module(addr, mod))
> +			return mod;
> +	}
> +
> +	return NULL;
> +}
> +#endif /* CONFIG_MODULES_TREE_LOOKUP */
> diff --git a/kernel/module/main.c b/kernel/module/main.c
> index 3596ebf3a6c3..76b53880ad91 100644
> --- a/kernel/module/main.c
> +++ b/kernel/module/main.c
> @@ -90,138 +90,16 @@ static DECLARE_WORK(init_free_wq, do_free_init);
>   static LLIST_HEAD(init_free_list);
>   
>   #ifdef CONFIG_MODULES_TREE_LOOKUP
> -
> -/*
> - * Use a latched RB-tree for __module_address(); this allows us to use
> - * RCU-sched lookups of the address from any context.
> - *
> - * This is conditional on PERF_EVENTS || TRACING because those can really hit
> - * __module_address() hard by doing a lot of stack unwinding; potentially from
> - * NMI context.
> - */
> -
> -static __always_inline unsigned long __mod_tree_val(struct latch_tree_node *n)
> -{
> -	struct module_layout *layout = container_of(n, struct module_layout, mtn.node);
> -
> -	return (unsigned long)layout->base;
> -}
> -
> -static __always_inline unsigned long __mod_tree_size(struct latch_tree_node *n)
> -{
> -	struct module_layout *layout = container_of(n, struct module_layout, mtn.node);
> -
> -	return (unsigned long)layout->size;
> -}
> -
> -static __always_inline bool
> -mod_tree_less(struct latch_tree_node *a, struct latch_tree_node *b)
> -{
> -	return __mod_tree_val(a) < __mod_tree_val(b);
> -}
> -
> -static __always_inline int
> -mod_tree_comp(void *key, struct latch_tree_node *n)
> -{
> -	unsigned long val = (unsigned long)key;
> -	unsigned long start, end;
> -
> -	start = __mod_tree_val(n);
> -	if (val < start)
> -		return -1;
> -
> -	end = start + __mod_tree_size(n);
> -	if (val >= end)
> -		return 1;
> -
> -	return 0;
> -}
> -
> -static const struct latch_tree_ops mod_tree_ops = {
> -	.less = mod_tree_less,
> -	.comp = mod_tree_comp,
> -};
> -
> -static struct mod_tree_root {
> -	struct latch_tree_root root;
> -	unsigned long addr_min;
> -	unsigned long addr_max;
> -} mod_tree __cacheline_aligned = {
> +struct mod_tree_root mod_tree __cacheline_aligned = {
>   	.addr_min = -1UL,
>   };
>   
>   #define module_addr_min mod_tree.addr_min
>   #define module_addr_max mod_tree.addr_max
>   
> -static noinline void __mod_tree_insert(struct mod_tree_node *node)
> -{
> -	latch_tree_insert(&node->node, &mod_tree.root, &mod_tree_ops);
> -}
> -
> -static void __mod_tree_remove(struct mod_tree_node *node)
> -{
> -	latch_tree_erase(&node->node, &mod_tree.root, &mod_tree_ops);
> -}
> -
> -/*
> - * These modifications: insert, remove_init and remove; are serialized by the
> - * module_mutex.
> - */
> -static void mod_tree_insert(struct module *mod)
> -{
> -	mod->core_layout.mtn.mod = mod;
> -	mod->init_layout.mtn.mod = mod;
> -
> -	__mod_tree_insert(&mod->core_layout.mtn);
> -	if (mod->init_layout.size)
> -		__mod_tree_insert(&mod->init_layout.mtn);
> -}
> -
> -static void mod_tree_remove_init(struct module *mod)
> -{
> -	if (mod->init_layout.size)
> -		__mod_tree_remove(&mod->init_layout.mtn);
> -}
> -
> -static void mod_tree_remove(struct module *mod)
> -{
> -	__mod_tree_remove(&mod->core_layout.mtn);
> -	mod_tree_remove_init(mod);
> -}
> -
> -static struct module *mod_find(unsigned long addr)
> -{
> -	struct latch_tree_node *ltn;
> -
> -	ltn = latch_tree_find((void *)addr, &mod_tree.root, &mod_tree_ops);
> -	if (!ltn)
> -		return NULL;
> -
> -	return container_of(ltn, struct mod_tree_node, node)->mod;
> -}
> -
> -#else /* MODULES_TREE_LOOKUP */
> -
> -static unsigned long module_addr_min = -1UL, module_addr_max = 0;
> -
> -static void mod_tree_insert(struct module *mod) { }
> -static void mod_tree_remove_init(struct module *mod) { }
> -static void mod_tree_remove(struct module *mod) { }
> -
> -static struct module *mod_find(unsigned long addr)
> -{
> -	struct module *mod;
> -
> -	list_for_each_entry_rcu(mod, &modules, list,
> -				lockdep_is_held(&module_mutex)) {
> -		if (within_module(addr, mod))
> -			return mod;
> -	}
> -
> -	return NULL;
> -}
> -
> -#endif /* MODULES_TREE_LOOKUP */
> +#else /* !CONFIG_MODULES_TREE_LOOKUP */
> +static unsigned long module_addr_min = -1UL, module_addr_max;
> +#endif /* CONFIG_MODULES_TREE_LOOKUP */
>   
>   /*
>    * Bounds of module text, for speeding up __module_address.
> diff --git a/kernel/module/tree_lookup.c b/kernel/module/tree_lookup.c
> new file mode 100644
> index 000000000000..0bc4ec3b22ce
> --- /dev/null
> +++ b/kernel/module/tree_lookup.c
> @@ -0,0 +1,109 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Modules tree lookup
> + *
> + * Copyright (C) 2015 Peter Zijlstra
> + * Copyright (C) 2015 Rusty Russell
> + */
> +
> +#include <linux/module.h>
> +#include <linux/rbtree_latch.h>
> +#include "internal.h"
> +
> +/*
> + * Use a latched RB-tree for __module_address(); this allows us to use
> + * RCU-sched lookups of the address from any context.
> + *
> + * This is conditional on PERF_EVENTS || TRACING because those can really hit
> + * __module_address() hard by doing a lot of stack unwinding; potentially from
> + * NMI context.
> + */
> +
> +static __always_inline unsigned long __mod_tree_val(struct latch_tree_node *n)
> +{
> +	struct module_layout *layout = container_of(n, struct module_layout, mtn.node);
> +
> +	return (unsigned long)layout->base;
> +}
> +
> +static __always_inline unsigned long __mod_tree_size(struct latch_tree_node *n)
> +{
> +	struct module_layout *layout = container_of(n, struct module_layout, mtn.node);
> +
> +	return (unsigned long)layout->size;
> +}
> +
> +static __always_inline bool
> +mod_tree_less(struct latch_tree_node *a, struct latch_tree_node *b)
> +{
> +	return __mod_tree_val(a) < __mod_tree_val(b);
> +}
> +
> +static __always_inline int
> +mod_tree_comp(void *key, struct latch_tree_node *n)
> +{
> +	unsigned long val = (unsigned long)key;
> +	unsigned long start, end;
> +
> +	start = __mod_tree_val(n);
> +	if (val < start)
> +		return -1;
> +
> +	end = start + __mod_tree_size(n);
> +	if (val >= end)
> +		return 1;
> +
> +	return 0;
> +}
> +
> +static const struct latch_tree_ops mod_tree_ops = {
> +	.less = mod_tree_less,
> +	.comp = mod_tree_comp,
> +};
> +
> +static noinline void __mod_tree_insert(struct mod_tree_node *node)
> +{
> +	latch_tree_insert(&node->node, &mod_tree.root, &mod_tree_ops);
> +}
> +
> +static void __mod_tree_remove(struct mod_tree_node *node)
> +{
> +	latch_tree_erase(&node->node, &mod_tree.root, &mod_tree_ops);
> +}
> +
> +/*
> + * These modifications: insert, remove_init and remove; are serialized by the
> + * module_mutex.
> + */
> +void mod_tree_insert(struct module *mod)
> +{
> +	mod->core_layout.mtn.mod = mod;
> +	mod->init_layout.mtn.mod = mod;
> +
> +	__mod_tree_insert(&mod->core_layout.mtn);
> +	if (mod->init_layout.size)
> +		__mod_tree_insert(&mod->init_layout.mtn);
> +}
> +
> +void mod_tree_remove_init(struct module *mod)
> +{
> +	if (mod->init_layout.size)
> +		__mod_tree_remove(&mod->init_layout.mtn);
> +}
> +
> +void mod_tree_remove(struct module *mod)
> +{
> +	__mod_tree_remove(&mod->core_layout.mtn);
> +	mod_tree_remove_init(mod);
> +}
> +
> +struct module *mod_find(unsigned long addr)
> +{
> +	struct latch_tree_node *ltn;
> +
> +	ltn = latch_tree_find((void *)addr, &mod_tree.root, &mod_tree_ops);
> +	if (!ltn)
> +		return NULL;
> +
> +	return container_of(ltn, struct mod_tree_node, node)->mod;
> +}

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

* Re: [PATCH v8 06/13] module: Move strict rwx support to a separate file
  2022-02-22 14:12 ` [PATCH v8 06/13] module: Move strict rwx " Aaron Tomlin
@ 2022-02-22 17:59   ` Christophe Leroy
  0 siblings, 0 replies; 43+ messages in thread
From: Christophe Leroy @ 2022-02-22 17:59 UTC (permalink / raw)
  To: Aaron Tomlin, mcgrof
  Cc: cl, pmladek, mbenes, akpm, jeyu, linux-kernel, linux-modules,
	void, atomlin, allen.lkml, joe, msuchanek, oleksandr



Le 22/02/2022 à 15:12, Aaron Tomlin a écrit :
> No functional change.
> 
> This patch migrates code that makes module text
> and rodata memory read-only and non-text memory
> non-executable from core module code into
> kernel/module/strict_rwx.c.
> 
> Signed-off-by: Aaron Tomlin <atomlin@redhat.com>

Reviewed-by: Christophe Leroy <christophe.leroy@csgroup.eu>

> ---
>   kernel/module/Makefile     |  1 +
>   kernel/module/internal.h   | 32 ++++++++++++
>   kernel/module/main.c       | 99 +-------------------------------------
>   kernel/module/strict_rwx.c | 85 ++++++++++++++++++++++++++++++++
>   4 files changed, 120 insertions(+), 97 deletions(-)
>   create mode 100644 kernel/module/strict_rwx.c
> 
> diff --git a/kernel/module/Makefile b/kernel/module/Makefile
> index 88774e386276..d313c8472cb3 100644
> --- a/kernel/module/Makefile
> +++ b/kernel/module/Makefile
> @@ -12,3 +12,4 @@ obj-$(CONFIG_MODULE_DECOMPRESS) += decompress.o
>   obj-$(CONFIG_MODULE_SIG) += signing.o
>   obj-$(CONFIG_LIVEPATCH) += livepatch.o
>   obj-$(CONFIG_MODULES_TREE_LOOKUP) += tree_lookup.o
> +obj-$(CONFIG_STRICT_MODULE_RWX) += strict_rwx.o
> diff --git a/kernel/module/internal.h b/kernel/module/internal.h
> index f1682e3677be..a6895bb5598a 100644
> --- a/kernel/module/internal.h
> +++ b/kernel/module/internal.h
> @@ -20,6 +20,17 @@
>   /* Maximum number of characters written by module_flags() */
>   #define MODULE_FLAGS_BUF_SIZE (TAINT_FLAGS_COUNT + 4)
>   
> +/*
> + * Modules' sections will be aligned on page boundaries
> + * to ensure complete separation of code and data, but
> + * only when CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y
> + */
> +#ifdef CONFIG_ARCH_HAS_STRICT_MODULE_RWX
> +# define debug_align(X) PAGE_ALIGN(X)
> +#else
> +# define debug_align(X) (X)
> +#endif
> +
>   extern struct mutex module_mutex;
>   extern struct list_head modules;
>   
> @@ -126,3 +137,24 @@ static inline struct module *mod_find(unsigned long addr)
>   	return NULL;
>   }
>   #endif /* CONFIG_MODULES_TREE_LOOKUP */
> +
> +#ifdef CONFIG_ARCH_HAS_STRICT_MODULE_RWX
> +void frob_text(const struct module_layout *layout, int (*set_memory)(unsigned long start,
> +								     int num_pages));
> +#endif /* CONFIG_ARCH_HAS_STRICT_MODULE_RWX */
> +
> +#ifdef CONFIG_STRICT_MODULE_RWX
> +void module_enable_ro(const struct module *mod, bool after_init);
> +void module_enable_nx(const struct module *mod);
> +int module_enforce_rwx_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
> +				char *secstrings, struct module *mod);
> +
> +#else /* !CONFIG_STRICT_MODULE_RWX */
> +static inline void module_enable_nx(const struct module *mod) { }
> +static inline void module_enable_ro(const struct module *mod, bool after_init) {}
> +static inline int module_enforce_rwx_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
> +				       char *secstrings, struct module *mod)
> +{
> +	return 0;
> +}
> +#endif /* CONFIG_STRICT_MODULE_RWX */
> diff --git a/kernel/module/main.c b/kernel/module/main.c
> index 76b53880ad91..5cd63f14b1ef 100644
> --- a/kernel/module/main.c
> +++ b/kernel/module/main.c
> @@ -63,17 +63,6 @@
>   #define CREATE_TRACE_POINTS
>   #include <trace/events/module.h>
>   
> -/*
> - * Modules' sections will be aligned on page boundaries
> - * to ensure complete separation of code and data, but
> - * only when CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y
> - */
> -#ifdef CONFIG_ARCH_HAS_STRICT_MODULE_RWX
> -# define debug_align(X) ALIGN(X, PAGE_SIZE)
> -#else
> -# define debug_align(X) (X)
> -#endif
> -
>   /*
>    * Mutex protects:
>    * 1) List of modules (also safely readable with preempt_disable),
> @@ -1819,8 +1808,8 @@ static void mod_sysfs_teardown(struct module *mod)
>    * whether we are strict.
>    */
>   #ifdef CONFIG_ARCH_HAS_STRICT_MODULE_RWX
> -static void frob_text(const struct module_layout *layout,
> -		      int (*set_memory)(unsigned long start, int num_pages))
> +void frob_text(const struct module_layout *layout,
> +	       int (*set_memory)(unsigned long start, int num_pages))
>   {
>   	BUG_ON((unsigned long)layout->base & (PAGE_SIZE-1));
>   	BUG_ON((unsigned long)layout->text_size & (PAGE_SIZE-1));
> @@ -1837,90 +1826,6 @@ static void module_enable_x(const struct module *mod)
>   static void module_enable_x(const struct module *mod) { }
>   #endif /* CONFIG_ARCH_HAS_STRICT_MODULE_RWX */
>   
> -#ifdef CONFIG_STRICT_MODULE_RWX
> -static void frob_rodata(const struct module_layout *layout,
> -			int (*set_memory)(unsigned long start, int num_pages))
> -{
> -	BUG_ON((unsigned long)layout->base & (PAGE_SIZE-1));
> -	BUG_ON((unsigned long)layout->text_size & (PAGE_SIZE-1));
> -	BUG_ON((unsigned long)layout->ro_size & (PAGE_SIZE-1));
> -	set_memory((unsigned long)layout->base + layout->text_size,
> -		   (layout->ro_size - layout->text_size) >> PAGE_SHIFT);
> -}
> -
> -static void frob_ro_after_init(const struct module_layout *layout,
> -				int (*set_memory)(unsigned long start, int num_pages))
> -{
> -	BUG_ON((unsigned long)layout->base & (PAGE_SIZE-1));
> -	BUG_ON((unsigned long)layout->ro_size & (PAGE_SIZE-1));
> -	BUG_ON((unsigned long)layout->ro_after_init_size & (PAGE_SIZE-1));
> -	set_memory((unsigned long)layout->base + layout->ro_size,
> -		   (layout->ro_after_init_size - layout->ro_size) >> PAGE_SHIFT);
> -}
> -
> -static void frob_writable_data(const struct module_layout *layout,
> -			       int (*set_memory)(unsigned long start, int num_pages))
> -{
> -	BUG_ON((unsigned long)layout->base & (PAGE_SIZE-1));
> -	BUG_ON((unsigned long)layout->ro_after_init_size & (PAGE_SIZE-1));
> -	BUG_ON((unsigned long)layout->size & (PAGE_SIZE-1));
> -	set_memory((unsigned long)layout->base + layout->ro_after_init_size,
> -		   (layout->size - layout->ro_after_init_size) >> PAGE_SHIFT);
> -}
> -
> -static void module_enable_ro(const struct module *mod, bool after_init)
> -{
> -	if (!rodata_enabled)
> -		return;
> -
> -	set_vm_flush_reset_perms(mod->core_layout.base);
> -	set_vm_flush_reset_perms(mod->init_layout.base);
> -	frob_text(&mod->core_layout, set_memory_ro);
> -
> -	frob_rodata(&mod->core_layout, set_memory_ro);
> -	frob_text(&mod->init_layout, set_memory_ro);
> -	frob_rodata(&mod->init_layout, set_memory_ro);
> -
> -	if (after_init)
> -		frob_ro_after_init(&mod->core_layout, set_memory_ro);
> -}
> -
> -static void module_enable_nx(const struct module *mod)
> -{
> -	frob_rodata(&mod->core_layout, set_memory_nx);
> -	frob_ro_after_init(&mod->core_layout, set_memory_nx);
> -	frob_writable_data(&mod->core_layout, set_memory_nx);
> -	frob_rodata(&mod->init_layout, set_memory_nx);
> -	frob_writable_data(&mod->init_layout, set_memory_nx);
> -}
> -
> -static int module_enforce_rwx_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
> -				       char *secstrings, struct module *mod)
> -{
> -	const unsigned long shf_wx = SHF_WRITE|SHF_EXECINSTR;
> -	int i;
> -
> -	for (i = 0; i < hdr->e_shnum; i++) {
> -		if ((sechdrs[i].sh_flags & shf_wx) == shf_wx) {
> -			pr_err("%s: section %s (index %d) has invalid WRITE|EXEC flags\n",
> -				mod->name, secstrings + sechdrs[i].sh_name, i);
> -			return -ENOEXEC;
> -		}
> -	}
> -
> -	return 0;
> -}
> -
> -#else /* !CONFIG_STRICT_MODULE_RWX */
> -static void module_enable_nx(const struct module *mod) { }
> -static void module_enable_ro(const struct module *mod, bool after_init) {}
> -static int module_enforce_rwx_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
> -				       char *secstrings, struct module *mod)
> -{
> -	return 0;
> -}
> -#endif /*  CONFIG_STRICT_MODULE_RWX */
> -
>   void __weak module_memfree(void *module_region)
>   {
>   	/*
> diff --git a/kernel/module/strict_rwx.c b/kernel/module/strict_rwx.c
> new file mode 100644
> index 000000000000..7949dfd449c2
> --- /dev/null
> +++ b/kernel/module/strict_rwx.c
> @@ -0,0 +1,85 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Module strict rwx
> + *
> + * Copyright (C) 2015 Rusty Russell
> + */
> +
> +#include <linux/module.h>
> +#include <linux/mm.h>
> +#include <linux/vmalloc.h>
> +#include <linux/set_memory.h>
> +#include "internal.h"
> +
> +static void frob_rodata(const struct module_layout *layout,
> +		 int (*set_memory)(unsigned long start, int num_pages))
> +{
> +	BUG_ON(!PAGE_ALIGNED(layout->base));
> +	BUG_ON(!PAGE_ALIGNED(layout->text_size));
> +	BUG_ON(!PAGE_ALIGNED(layout->ro_size));
> +	set_memory((unsigned long)layout->base + layout->text_size,
> +		   (layout->ro_size - layout->text_size) >> PAGE_SHIFT);
> +}
> +
> +static void frob_ro_after_init(const struct module_layout *layout,
> +			int (*set_memory)(unsigned long start, int num_pages))
> +{
> +	BUG_ON(!PAGE_ALIGNED(layout->base));
> +	BUG_ON(!PAGE_ALIGNED(layout->ro_size));
> +	BUG_ON(!PAGE_ALIGNED(layout->ro_after_init_size));
> +	set_memory((unsigned long)layout->base + layout->ro_size,
> +		   (layout->ro_after_init_size - layout->ro_size) >> PAGE_SHIFT);
> +}
> +
> +static void frob_writable_data(const struct module_layout *layout,
> +			int (*set_memory)(unsigned long start, int num_pages))
> +{
> +	BUG_ON(!PAGE_ALIGNED(layout->base));
> +	BUG_ON(!PAGE_ALIGNED(layout->ro_after_init_size));
> +	BUG_ON(!PAGE_ALIGNED(layout->size));
> +	set_memory((unsigned long)layout->base + layout->ro_after_init_size,
> +		   (layout->size - layout->ro_after_init_size) >> PAGE_SHIFT);
> +}
> +
> +void module_enable_ro(const struct module *mod, bool after_init)
> +{
> +	if (!rodata_enabled)
> +		return;
> +
> +	set_vm_flush_reset_perms(mod->core_layout.base);
> +	set_vm_flush_reset_perms(mod->init_layout.base);
> +	frob_text(&mod->core_layout, set_memory_ro);
> +
> +	frob_rodata(&mod->core_layout, set_memory_ro);
> +	frob_text(&mod->init_layout, set_memory_ro);
> +	frob_rodata(&mod->init_layout, set_memory_ro);
> +
> +	if (after_init)
> +		frob_ro_after_init(&mod->core_layout, set_memory_ro);
> +}
> +
> +void module_enable_nx(const struct module *mod)
> +{
> +	frob_rodata(&mod->core_layout, set_memory_nx);
> +	frob_ro_after_init(&mod->core_layout, set_memory_nx);
> +	frob_writable_data(&mod->core_layout, set_memory_nx);
> +	frob_rodata(&mod->init_layout, set_memory_nx);
> +	frob_writable_data(&mod->init_layout, set_memory_nx);
> +}
> +
> +int module_enforce_rwx_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
> +				char *secstrings, struct module *mod)
> +{
> +	const unsigned long shf_wx = SHF_WRITE | SHF_EXECINSTR;
> +	int i;
> +
> +	for (i = 0; i < hdr->e_shnum; i++) {
> +		if ((sechdrs[i].sh_flags & shf_wx) == shf_wx) {
> +			pr_err("%s: section %s (index %d) has invalid WRITE|EXEC flags\n",
> +			       mod->name, secstrings + sechdrs[i].sh_name, i);
> +			return -ENOEXEC;
> +		}
> +	}
> +
> +	return 0;
> +}

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

* Re: [PATCH v8 07/13] module: Move extra signature support out of core code
  2022-02-22 14:12 ` [PATCH v8 07/13] module: Move extra signature support out of core code Aaron Tomlin
@ 2022-02-22 17:59   ` Christophe Leroy
  0 siblings, 0 replies; 43+ messages in thread
From: Christophe Leroy @ 2022-02-22 17:59 UTC (permalink / raw)
  To: Aaron Tomlin, mcgrof
  Cc: cl, pmladek, mbenes, akpm, jeyu, linux-kernel, linux-modules,
	void, atomlin, allen.lkml, joe, msuchanek, oleksandr



Le 22/02/2022 à 15:12, Aaron Tomlin a écrit :
> No functional change.
> 
> This patch migrates additional module signature check
> code from core module code into kernel/module/signing.c.
> 
> Signed-off-by: Aaron Tomlin <atomlin@redhat.com>

Reviewed-by: Christophe Leroy <christophe.leroy@csgroup.eu>

> ---
>   kernel/module/internal.h |  9 +++++
>   kernel/module/main.c     | 87 ----------------------------------------
>   kernel/module/signing.c  | 77 +++++++++++++++++++++++++++++++++++
>   3 files changed, 86 insertions(+), 87 deletions(-)
> 
> diff --git a/kernel/module/internal.h b/kernel/module/internal.h
> index a6895bb5598a..d6f646a5da41 100644
> --- a/kernel/module/internal.h
> +++ b/kernel/module/internal.h
> @@ -158,3 +158,12 @@ static inline int module_enforce_rwx_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
>   	return 0;
>   }
>   #endif /* CONFIG_STRICT_MODULE_RWX */
> +
> +#ifdef CONFIG_MODULE_SIG
> +int module_sig_check(struct load_info *info, int flags);
> +#else /* !CONFIG_MODULE_SIG */
> +static inline int module_sig_check(struct load_info *info, int flags)
> +{
> +	return 0;
> +}
> +#endif /* !CONFIG_MODULE_SIG */
> diff --git a/kernel/module/main.c b/kernel/module/main.c
> index 5cd63f14b1ef..c63e10c61694 100644
> --- a/kernel/module/main.c
> +++ b/kernel/module/main.c
> @@ -23,7 +23,6 @@
>   #include <linux/vmalloc.h>
>   #include <linux/elf.h>
>   #include <linux/proc_fs.h>
> -#include <linux/security.h>
>   #include <linux/seq_file.h>
>   #include <linux/syscalls.h>
>   #include <linux/fcntl.h>
> @@ -127,28 +126,6 @@ static void module_assert_mutex_or_preempt(void)
>   #endif
>   }
>   
> -#ifdef CONFIG_MODULE_SIG
> -static bool sig_enforce = IS_ENABLED(CONFIG_MODULE_SIG_FORCE);
> -module_param(sig_enforce, bool_enable_only, 0644);
> -
> -void set_module_sig_enforced(void)
> -{
> -	sig_enforce = true;
> -}
> -#else
> -#define sig_enforce false
> -#endif
> -
> -/*
> - * Export sig_enforce kernel cmdline parameter to allow other subsystems rely
> - * on that instead of directly to CONFIG_MODULE_SIG_FORCE config.
> - */
> -bool is_module_sig_enforced(void)
> -{
> -	return sig_enforce;
> -}
> -EXPORT_SYMBOL(is_module_sig_enforced);
> -
>   /* Block module loading/unloading? */
>   int modules_disabled = 0;
>   core_param(nomodule, modules_disabled, bint, 0);
> @@ -2569,70 +2546,6 @@ static inline void kmemleak_load_module(const struct module *mod,
>   }
>   #endif
>   
> -#ifdef CONFIG_MODULE_SIG
> -static int module_sig_check(struct load_info *info, int flags)
> -{
> -	int err = -ENODATA;
> -	const unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1;
> -	const char *reason;
> -	const void *mod = info->hdr;
> -	bool mangled_module = flags & (MODULE_INIT_IGNORE_MODVERSIONS |
> -				       MODULE_INIT_IGNORE_VERMAGIC);
> -	/*
> -	 * Do not allow mangled modules as a module with version information
> -	 * removed is no longer the module that was signed.
> -	 */
> -	if (!mangled_module &&
> -	    info->len > markerlen &&
> -	    memcmp(mod + info->len - markerlen, MODULE_SIG_STRING, markerlen) == 0) {
> -		/* We truncate the module to discard the signature */
> -		info->len -= markerlen;
> -		err = mod_verify_sig(mod, info);
> -		if (!err) {
> -			info->sig_ok = true;
> -			return 0;
> -		}
> -	}
> -
> -	/*
> -	 * We don't permit modules to be loaded into the trusted kernels
> -	 * without a valid signature on them, but if we're not enforcing,
> -	 * certain errors are non-fatal.
> -	 */
> -	switch (err) {
> -	case -ENODATA:
> -		reason = "unsigned module";
> -		break;
> -	case -ENOPKG:
> -		reason = "module with unsupported crypto";
> -		break;
> -	case -ENOKEY:
> -		reason = "module with unavailable key";
> -		break;
> -
> -	default:
> -		/*
> -		 * All other errors are fatal, including lack of memory,
> -		 * unparseable signatures, and signature check failures --
> -		 * even if signatures aren't required.
> -		 */
> -		return err;
> -	}
> -
> -	if (is_module_sig_enforced()) {
> -		pr_notice("Loading of %s is rejected\n", reason);
> -		return -EKEYREJECTED;
> -	}
> -
> -	return security_locked_down(LOCKDOWN_MODULE_SIGNATURE);
> -}
> -#else /* !CONFIG_MODULE_SIG */
> -static int module_sig_check(struct load_info *info, int flags)
> -{
> -	return 0;
> -}
> -#endif /* !CONFIG_MODULE_SIG */
> -
>   static int validate_section_offset(struct load_info *info, Elf_Shdr *shdr)
>   {
>   #if defined(CONFIG_64BIT)
> diff --git a/kernel/module/signing.c b/kernel/module/signing.c
> index 8aeb6d2ee94b..85c8999dfecf 100644
> --- a/kernel/module/signing.c
> +++ b/kernel/module/signing.c
> @@ -11,9 +11,29 @@
>   #include <linux/module_signature.h>
>   #include <linux/string.h>
>   #include <linux/verification.h>
> +#include <linux/security.h>
>   #include <crypto/public_key.h>
> +#include <uapi/linux/module.h>
>   #include "internal.h"
>   
> +static bool sig_enforce = IS_ENABLED(CONFIG_MODULE_SIG_FORCE);
> +module_param(sig_enforce, bool_enable_only, 0644);
> +
> +/*
> + * Export sig_enforce kernel cmdline parameter to allow other subsystems rely
> + * on that instead of directly to CONFIG_MODULE_SIG_FORCE config.
> + */
> +bool is_module_sig_enforced(void)
> +{
> +	return sig_enforce;
> +}
> +EXPORT_SYMBOL(is_module_sig_enforced);
> +
> +void set_module_sig_enforced(void)
> +{
> +	sig_enforce = true;
> +}
> +
>   /*
>    * Verify the signature on a module.
>    */
> @@ -43,3 +63,60 @@ int mod_verify_sig(const void *mod, struct load_info *info)
>   				      VERIFYING_MODULE_SIGNATURE,
>   				      NULL, NULL);
>   }
> +
> +int module_sig_check(struct load_info *info, int flags)
> +{
> +	int err = -ENODATA;
> +	const unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1;
> +	const char *reason;
> +	const void *mod = info->hdr;
> +	bool mangled_module = flags & (MODULE_INIT_IGNORE_MODVERSIONS |
> +				       MODULE_INIT_IGNORE_VERMAGIC);
> +	/*
> +	 * Do not allow mangled modules as a module with version information
> +	 * removed is no longer the module that was signed.
> +	 */
> +	if (!mangled_module &&
> +	    info->len > markerlen &&
> +	    memcmp(mod + info->len - markerlen, MODULE_SIG_STRING, markerlen) == 0) {
> +		/* We truncate the module to discard the signature */
> +		info->len -= markerlen;
> +		err = mod_verify_sig(mod, info);
> +		if (!err) {
> +			info->sig_ok = true;
> +			return 0;
> +		}
> +	}
> +
> +	/*
> +	 * We don't permit modules to be loaded into the trusted kernels
> +	 * without a valid signature on them, but if we're not enforcing,
> +	 * certain errors are non-fatal.
> +	 */
> +	switch (err) {
> +	case -ENODATA:
> +		reason = "unsigned module";
> +		break;
> +	case -ENOPKG:
> +		reason = "module with unsupported crypto";
> +		break;
> +	case -ENOKEY:
> +		reason = "module with unavailable key";
> +		break;
> +
> +	default:
> +		/*
> +		 * All other errors are fatal, including lack of memory,
> +		 * unparseable signatures, and signature check failures --
> +		 * even if signatures aren't required.
> +		 */
> +		return err;
> +	}
> +
> +	if (is_module_sig_enforced()) {
> +		pr_notice("Loading of %s is rejected\n", reason);
> +		return -EKEYREJECTED;
> +	}
> +
> +	return security_locked_down(LOCKDOWN_MODULE_SIGNATURE);
> +}

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

* Re: [PATCH v8 08/13] module: Move kmemleak support to a separate file
  2022-02-22 14:12 ` [PATCH v8 08/13] module: Move kmemleak support to a separate file Aaron Tomlin
@ 2022-02-22 17:59   ` Christophe Leroy
  0 siblings, 0 replies; 43+ messages in thread
From: Christophe Leroy @ 2022-02-22 17:59 UTC (permalink / raw)
  To: Aaron Tomlin, mcgrof
  Cc: cl, pmladek, mbenes, akpm, jeyu, linux-kernel, linux-modules,
	void, atomlin, allen.lkml, joe, msuchanek, oleksandr



Le 22/02/2022 à 15:12, Aaron Tomlin a écrit :
> No functional change.
> 
> This patch migrates kmemleak code out of core module
> code into kernel/module/debug_kmemleak.c
> 
> Signed-off-by: Aaron Tomlin <atomlin@redhat.com>

Reviewed-by: Christophe Leroy <christophe.leroy@csgroup.eu>

> ---
>   kernel/module/Makefile         |  1 +
>   kernel/module/debug_kmemleak.c | 30 ++++++++++++++++++++++++++++++
>   kernel/module/internal.h       |  7 +++++++
>   kernel/module/main.c           | 27 ---------------------------
>   4 files changed, 38 insertions(+), 27 deletions(-)
>   create mode 100644 kernel/module/debug_kmemleak.c
> 
> diff --git a/kernel/module/Makefile b/kernel/module/Makefile
> index d313c8472cb3..12388627725c 100644
> --- a/kernel/module/Makefile
> +++ b/kernel/module/Makefile
> @@ -13,3 +13,4 @@ obj-$(CONFIG_MODULE_SIG) += signing.o
>   obj-$(CONFIG_LIVEPATCH) += livepatch.o
>   obj-$(CONFIG_MODULES_TREE_LOOKUP) += tree_lookup.o
>   obj-$(CONFIG_STRICT_MODULE_RWX) += strict_rwx.o
> +obj-$(CONFIG_DEBUG_KMEMLEAK) += debug_kmemleak.o
> diff --git a/kernel/module/debug_kmemleak.c b/kernel/module/debug_kmemleak.c
> new file mode 100644
> index 000000000000..12a569d361e8
> --- /dev/null
> +++ b/kernel/module/debug_kmemleak.c
> @@ -0,0 +1,30 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Module kmemleak support
> + *
> + * Copyright (C) 2009 Catalin Marinas
> + */
> +
> +#include <linux/module.h>
> +#include <linux/kmemleak.h>
> +#include "internal.h"
> +
> +void kmemleak_load_module(const struct module *mod,
> +			  const struct load_info *info)
> +{
> +	unsigned int i;
> +
> +	/* only scan the sections containing data */
> +	kmemleak_scan_area(mod, sizeof(struct module), GFP_KERNEL);
> +
> +	for (i = 1; i < info->hdr->e_shnum; i++) {
> +		/* Scan all writable sections that's not executable */
> +		if (!(info->sechdrs[i].sh_flags & SHF_ALLOC) ||
> +		    !(info->sechdrs[i].sh_flags & SHF_WRITE) ||
> +		    (info->sechdrs[i].sh_flags & SHF_EXECINSTR))
> +			continue;
> +
> +		kmemleak_scan_area((void *)info->sechdrs[i].sh_addr,
> +				   info->sechdrs[i].sh_size, GFP_KERNEL);
> +	}
> +}
> diff --git a/kernel/module/internal.h b/kernel/module/internal.h
> index d6f646a5da41..b0c360839f63 100644
> --- a/kernel/module/internal.h
> +++ b/kernel/module/internal.h
> @@ -167,3 +167,10 @@ static inline int module_sig_check(struct load_info *info, int flags)
>   	return 0;
>   }
>   #endif /* !CONFIG_MODULE_SIG */
> +
> +#ifdef CONFIG_DEBUG_KMEMLEAK
> +void kmemleak_load_module(const struct module *mod, const struct load_info *info);
> +#else /* !CONFIG_DEBUG_KMEMLEAK */
> +static inline void kmemleak_load_module(const struct module *mod,
> +					const struct load_info *info) { }
> +#endif /* CONFIG_DEBUG_KMEMLEAK */
> diff --git a/kernel/module/main.c b/kernel/module/main.c
> index c63e10c61694..7dd283959c5c 100644
> --- a/kernel/module/main.c
> +++ b/kernel/module/main.c
> @@ -2519,33 +2519,6 @@ bool __weak module_exit_section(const char *name)
>   	return strstarts(name, ".exit");
>   }
>   
> -#ifdef CONFIG_DEBUG_KMEMLEAK
> -static void kmemleak_load_module(const struct module *mod,
> -				 const struct load_info *info)
> -{
> -	unsigned int i;
> -
> -	/* only scan the sections containing data */
> -	kmemleak_scan_area(mod, sizeof(struct module), GFP_KERNEL);
> -
> -	for (i = 1; i < info->hdr->e_shnum; i++) {
> -		/* Scan all writable sections that's not executable */
> -		if (!(info->sechdrs[i].sh_flags & SHF_ALLOC) ||
> -		    !(info->sechdrs[i].sh_flags & SHF_WRITE) ||
> -		    (info->sechdrs[i].sh_flags & SHF_EXECINSTR))
> -			continue;
> -
> -		kmemleak_scan_area((void *)info->sechdrs[i].sh_addr,
> -				   info->sechdrs[i].sh_size, GFP_KERNEL);
> -	}
> -}
> -#else
> -static inline void kmemleak_load_module(const struct module *mod,
> -					const struct load_info *info)
> -{
> -}
> -#endif
> -
>   static int validate_section_offset(struct load_info *info, Elf_Shdr *shdr)
>   {
>   #if defined(CONFIG_64BIT)

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

* Re: [PATCH v8 09/13] module: Move kallsyms support into a separate file
  2022-02-22 14:12 ` [PATCH v8 09/13] module: Move kallsyms support into " Aaron Tomlin
@ 2022-02-22 17:59   ` Christophe Leroy
  2022-02-25  9:15   ` Petr Mladek
  1 sibling, 0 replies; 43+ messages in thread
From: Christophe Leroy @ 2022-02-22 17:59 UTC (permalink / raw)
  To: Aaron Tomlin, mcgrof
  Cc: cl, pmladek, mbenes, akpm, jeyu, linux-kernel, linux-modules,
	void, atomlin, allen.lkml, joe, msuchanek, oleksandr



Le 22/02/2022 à 15:12, Aaron Tomlin a écrit :
> No functional change.
> 
> This patch migrates kallsyms code out of core module
> code kernel/module/kallsyms.c
> 
> Signed-off-by: Aaron Tomlin <atomlin@redhat.com>

Reviewed-by: Christophe Leroy <christophe.leroy@csgroup.eu>

> ---
>   kernel/module/Makefile   |   1 +
>   kernel/module/internal.h |  29 +++
>   kernel/module/kallsyms.c | 506 +++++++++++++++++++++++++++++++++++++
>   kernel/module/main.c     | 531 +--------------------------------------
>   4 files changed, 542 insertions(+), 525 deletions(-)
>   create mode 100644 kernel/module/kallsyms.c
> 
> diff --git a/kernel/module/Makefile b/kernel/module/Makefile
> index 12388627725c..9901bed3ab5b 100644
> --- a/kernel/module/Makefile
> +++ b/kernel/module/Makefile
> @@ -14,3 +14,4 @@ obj-$(CONFIG_LIVEPATCH) += livepatch.o
>   obj-$(CONFIG_MODULES_TREE_LOOKUP) += tree_lookup.o
>   obj-$(CONFIG_STRICT_MODULE_RWX) += strict_rwx.o
>   obj-$(CONFIG_DEBUG_KMEMLEAK) += debug_kmemleak.o
> +obj-$(CONFIG_KALLSYMS) += kallsyms.o
> diff --git a/kernel/module/internal.h b/kernel/module/internal.h
> index b0c360839f63..44ca05b9eb8f 100644
> --- a/kernel/module/internal.h
> +++ b/kernel/module/internal.h
> @@ -68,6 +68,19 @@ struct load_info {
>   };
>   
>   int mod_verify_sig(const void *mod, struct load_info *info);
> +struct module *find_module_all(const char *name, size_t len, bool even_unformed);
> +int cmp_name(const void *name, const void *sym);
> +long module_get_offset(struct module *mod, unsigned int *size, Elf_Shdr *sechdr,
> +		       unsigned int section);
> +
> +static inline unsigned long kernel_symbol_value(const struct kernel_symbol *sym)
> +{
> +#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
> +	return (unsigned long)offset_to_ptr(&sym->value_offset);
> +#else
> +	return sym->value;
> +#endif
> +}
>   
>   #ifdef CONFIG_LIVEPATCH
>   int copy_module_elf(struct module *mod, struct load_info *info);
> @@ -174,3 +187,19 @@ void kmemleak_load_module(const struct module *mod, const struct load_info *info
>   static inline void kmemleak_load_module(const struct module *mod,
>   					const struct load_info *info) { }
>   #endif /* CONFIG_DEBUG_KMEMLEAK */
> +
> +#ifdef CONFIG_KALLSYMS
> +void init_build_id(struct module *mod, const struct load_info *info);
> +void layout_symtab(struct module *mod, struct load_info *info);
> +void add_kallsyms(struct module *mod, const struct load_info *info);
> +unsigned long find_kallsyms_symbol_value(struct module *mod, const char *name);
> +
> +static inline bool sect_empty(const Elf_Shdr *sect)
> +{
> +	return !(sect->sh_flags & SHF_ALLOC) || sect->sh_size == 0;
> +}
> +#else /* !CONFIG_KALLSYMS */
> +static inline void init_build_id(struct module *mod, const struct load_info *info) { }
> +static inline void layout_symtab(struct module *mod, struct load_info *info) { }
> +static inline void add_kallsyms(struct module *mod, const struct load_info *info) { }
> +#endif /* CONFIG_KALLSYMS */
> diff --git a/kernel/module/kallsyms.c b/kernel/module/kallsyms.c
> new file mode 100644
> index 000000000000..b6d49bb5afed
> --- /dev/null
> +++ b/kernel/module/kallsyms.c
> @@ -0,0 +1,506 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Module kallsyms support
> + *
> + * Copyright (C) 2010 Rusty Russell
> + */
> +
> +#include <linux/module.h>
> +#include <linux/kallsyms.h>
> +#include <linux/buildid.h>
> +#include <linux/bsearch.h>
> +#include "internal.h"
> +
> +/* Lookup exported symbol in given range of kernel_symbols */
> +static const struct kernel_symbol *lookup_exported_symbol(const char *name,
> +							  const struct kernel_symbol *start,
> +							  const struct kernel_symbol *stop)
> +{
> +	return bsearch(name, start, stop - start,
> +			sizeof(struct kernel_symbol), cmp_name);
> +}
> +
> +static int is_exported(const char *name, unsigned long value,
> +		       const struct module *mod)
> +{
> +	const struct kernel_symbol *ks;
> +
> +	if (!mod)
> +		ks = lookup_exported_symbol(name, __start___ksymtab, __stop___ksymtab);
> +	else
> +		ks = lookup_exported_symbol(name, mod->syms, mod->syms + mod->num_syms);
> +
> +	return ks && kernel_symbol_value(ks) == value;
> +}
> +
> +/* As per nm */
> +static char elf_type(const Elf_Sym *sym, const struct load_info *info)
> +{
> +	const Elf_Shdr *sechdrs = info->sechdrs;
> +
> +	if (ELF_ST_BIND(sym->st_info) == STB_WEAK) {
> +		if (ELF_ST_TYPE(sym->st_info) == STT_OBJECT)
> +			return 'v';
> +		else
> +			return 'w';
> +	}
> +	if (sym->st_shndx == SHN_UNDEF)
> +		return 'U';
> +	if (sym->st_shndx == SHN_ABS || sym->st_shndx == info->index.pcpu)
> +		return 'a';
> +	if (sym->st_shndx >= SHN_LORESERVE)
> +		return '?';
> +	if (sechdrs[sym->st_shndx].sh_flags & SHF_EXECINSTR)
> +		return 't';
> +	if (sechdrs[sym->st_shndx].sh_flags & SHF_ALLOC &&
> +	    sechdrs[sym->st_shndx].sh_type != SHT_NOBITS) {
> +		if (!(sechdrs[sym->st_shndx].sh_flags & SHF_WRITE))
> +			return 'r';
> +		else if (sechdrs[sym->st_shndx].sh_flags & ARCH_SHF_SMALL)
> +			return 'g';
> +		else
> +			return 'd';
> +	}
> +	if (sechdrs[sym->st_shndx].sh_type == SHT_NOBITS) {
> +		if (sechdrs[sym->st_shndx].sh_flags & ARCH_SHF_SMALL)
> +			return 's';
> +		else
> +			return 'b';
> +	}
> +	if (strstarts(info->secstrings + sechdrs[sym->st_shndx].sh_name,
> +		      ".debug")) {
> +		return 'n';
> +	}
> +	return '?';
> +}
> +
> +static bool is_core_symbol(const Elf_Sym *src, const Elf_Shdr *sechdrs,
> +			   unsigned int shnum, unsigned int pcpundx)
> +{
> +	const Elf_Shdr *sec;
> +
> +	if (src->st_shndx == SHN_UNDEF ||
> +	    src->st_shndx >= shnum ||
> +	    !src->st_name)
> +		return false;
> +
> +#ifdef CONFIG_KALLSYMS_ALL
> +	if (src->st_shndx == pcpundx)
> +		return true;
> +#endif
> +
> +	sec = sechdrs + src->st_shndx;
> +	if (!(sec->sh_flags & SHF_ALLOC)
> +#ifndef CONFIG_KALLSYMS_ALL
> +	    || !(sec->sh_flags & SHF_EXECINSTR)
> +#endif
> +	    || (sec->sh_entsize & INIT_OFFSET_MASK))
> +		return false;
> +
> +	return true;
> +}
> +
> +/*
> + * We only allocate and copy the strings needed by the parts of symtab
> + * we keep.  This is simple, but has the effect of making multiple
> + * copies of duplicates.  We could be more sophisticated, see
> + * linux-kernel thread starting with
> + * <73defb5e4bca04a6431392cc341112b1@localhost>.
> + */
> +void layout_symtab(struct module *mod, struct load_info *info)
> +{
> +	Elf_Shdr *symsect = info->sechdrs + info->index.sym;
> +	Elf_Shdr *strsect = info->sechdrs + info->index.str;
> +	const Elf_Sym *src;
> +	unsigned int i, nsrc, ndst, strtab_size = 0;
> +
> +	/* Put symbol section at end of init part of module. */
> +	symsect->sh_flags |= SHF_ALLOC;
> +	symsect->sh_entsize = module_get_offset(mod, &mod->init_layout.size, symsect,
> +						info->index.sym) | INIT_OFFSET_MASK;
> +	pr_debug("\t%s\n", info->secstrings + symsect->sh_name);
> +
> +	src = (void *)info->hdr + symsect->sh_offset;
> +	nsrc = symsect->sh_size / sizeof(*src);
> +
> +	/* Compute total space required for the core symbols' strtab. */
> +	for (ndst = i = 0; i < nsrc; i++) {
> +		if (i == 0 || is_livepatch_module(mod) ||
> +		    is_core_symbol(src + i, info->sechdrs, info->hdr->e_shnum,
> +				   info->index.pcpu)) {
> +			strtab_size += strlen(&info->strtab[src[i].st_name]) + 1;
> +			ndst++;
> +		}
> +	}
> +
> +	/* Append room for core symbols at end of core part. */
> +	info->symoffs = ALIGN(mod->core_layout.size, symsect->sh_addralign ?: 1);
> +	info->stroffs = mod->core_layout.size = info->symoffs + ndst * sizeof(Elf_Sym);
> +	mod->core_layout.size += strtab_size;
> +	info->core_typeoffs = mod->core_layout.size;
> +	mod->core_layout.size += ndst * sizeof(char);
> +	mod->core_layout.size = debug_align(mod->core_layout.size);
> +
> +	/* Put string table section at end of init part of module. */
> +	strsect->sh_flags |= SHF_ALLOC;
> +	strsect->sh_entsize = module_get_offset(mod, &mod->init_layout.size, strsect,
> +						info->index.str) | INIT_OFFSET_MASK;
> +	pr_debug("\t%s\n", info->secstrings + strsect->sh_name);
> +
> +	/* We'll tack temporary mod_kallsyms on the end. */
> +	mod->init_layout.size = ALIGN(mod->init_layout.size,
> +				      __alignof__(struct mod_kallsyms));
> +	info->mod_kallsyms_init_off = mod->init_layout.size;
> +	mod->init_layout.size += sizeof(struct mod_kallsyms);
> +	info->init_typeoffs = mod->init_layout.size;
> +	mod->init_layout.size += nsrc * sizeof(char);
> +	mod->init_layout.size = debug_align(mod->init_layout.size);
> +}
> +
> +/*
> + * We use the full symtab and strtab which layout_symtab arranged to
> + * be appended to the init section.  Later we switch to the cut-down
> + * core-only ones.
> + */
> +void add_kallsyms(struct module *mod, const struct load_info *info)
> +{
> +	unsigned int i, ndst;
> +	const Elf_Sym *src;
> +	Elf_Sym *dst;
> +	char *s;
> +	Elf_Shdr *symsec = &info->sechdrs[info->index.sym];
> +
> +	/* Set up to point into init section. */
> +	mod->kallsyms = (void __rcu *)mod->init_layout.base +
> +		info->mod_kallsyms_init_off;
> +
> +	/* The following is safe since this pointer cannot change */
> +	rcu_dereference_sched(mod->kallsyms)->symtab = (void *)symsec->sh_addr;
> +	rcu_dereference_sched(mod->kallsyms)->num_symtab = symsec->sh_size / sizeof(Elf_Sym);
> +	/* Make sure we get permanent strtab: don't use info->strtab. */
> +	rcu_dereference_sched(mod->kallsyms)->strtab =
> +		(void *)info->sechdrs[info->index.str].sh_addr;
> +	rcu_dereference_sched(mod->kallsyms)->typetab =
> +		mod->init_layout.base + info->init_typeoffs;
> +
> +	/*
> +	 * Now populate the cut down core kallsyms for after init
> +	 * and set types up while we still have access to sections.
> +	 */
> +	mod->core_kallsyms.symtab = dst = mod->core_layout.base + info->symoffs;
> +	mod->core_kallsyms.strtab = s = mod->core_layout.base + info->stroffs;
> +	mod->core_kallsyms.typetab = mod->core_layout.base + info->core_typeoffs;
> +	src = rcu_dereference_sched(mod->kallsyms)->symtab;
> +	for (ndst = i = 0; i < rcu_dereference_sched(mod->kallsyms)->num_symtab; i++) {
> +		rcu_dereference_sched(mod->kallsyms)->typetab[i] = elf_type(src + i, info);
> +		if (i == 0 || is_livepatch_module(mod) ||
> +		    is_core_symbol(src + i, info->sechdrs, info->hdr->e_shnum,
> +				   info->index.pcpu)) {
> +			mod->core_kallsyms.typetab[ndst] =
> +			    rcu_dereference_sched(mod->kallsyms)->typetab[i];
> +			dst[ndst] = src[i];
> +			dst[ndst++].st_name = s - mod->core_kallsyms.strtab;
> +			s += strscpy(s,
> +				     &rcu_dereference_sched(mod->kallsyms)->strtab[src[i].st_name],
> +				     KSYM_NAME_LEN) + 1;
> +		}
> +	}
> +	mod->core_kallsyms.num_symtab = ndst;
> +}
> +
> +#if IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID)
> +void init_build_id(struct module *mod, const struct load_info *info)
> +{
> +	const Elf_Shdr *sechdr;
> +	unsigned int i;
> +
> +	for (i = 0; i < info->hdr->e_shnum; i++) {
> +		sechdr = &info->sechdrs[i];
> +		if (!sect_empty(sechdr) && sechdr->sh_type == SHT_NOTE &&
> +		    !build_id_parse_buf((void *)sechdr->sh_addr, mod->build_id,
> +					sechdr->sh_size))
> +			break;
> +	}
> +}
> +#else
> +void init_build_id(struct module *mod, const struct load_info *info)
> +{
> +}
> +#endif
> +
> +/*
> + * This ignores the intensely annoying "mapping symbols" found
> + * in ARM ELF files: $a, $t and $d.
> + */
> +static inline int is_arm_mapping_symbol(const char *str)
> +{
> +	if (str[0] == '.' && str[1] == 'L')
> +		return true;
> +	return str[0] == '$' && strchr("axtd", str[1]) &&
> +	       (str[2] == '\0' || str[2] == '.');
> +}
> +
> +static const char *kallsyms_symbol_name(struct mod_kallsyms *kallsyms, unsigned int symnum)
> +{
> +	return kallsyms->strtab + kallsyms->symtab[symnum].st_name;
> +}
> +
> +/*
> + * Given a module and address, find the corresponding symbol and return its name
> + * while providing its size and offset if needed.
> + */
> +static const char *find_kallsyms_symbol(struct module *mod,
> +					unsigned long addr,
> +					unsigned long *size,
> +					unsigned long *offset)
> +{
> +	unsigned int i, best = 0;
> +	unsigned long nextval, bestval;
> +	struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms);
> +
> +	/* At worse, next value is at end of module */
> +	if (within_module_init(addr, mod))
> +		nextval = (unsigned long)mod->init_layout.base + mod->init_layout.text_size;
> +	else
> +		nextval = (unsigned long)mod->core_layout.base + mod->core_layout.text_size;
> +
> +	bestval = kallsyms_symbol_value(&kallsyms->symtab[best]);
> +
> +	/*
> +	 * Scan for closest preceding symbol, and next symbol. (ELF
> +	 * starts real symbols at 1).
> +	 */
> +	for (i = 1; i < kallsyms->num_symtab; i++) {
> +		const Elf_Sym *sym = &kallsyms->symtab[i];
> +		unsigned long thisval = kallsyms_symbol_value(sym);
> +
> +		if (sym->st_shndx == SHN_UNDEF)
> +			continue;
> +
> +		/*
> +		 * We ignore unnamed symbols: they're uninformative
> +		 * and inserted at a whim.
> +		 */
> +		if (*kallsyms_symbol_name(kallsyms, i) == '\0' ||
> +		    is_arm_mapping_symbol(kallsyms_symbol_name(kallsyms, i)))
> +			continue;
> +
> +		if (thisval <= addr && thisval > bestval) {
> +			best = i;
> +			bestval = thisval;
> +		}
> +		if (thisval > addr && thisval < nextval)
> +			nextval = thisval;
> +	}
> +
> +	if (!best)
> +		return NULL;
> +
> +	if (size)
> +		*size = nextval - bestval;
> +	if (offset)
> +		*offset = addr - bestval;
> +
> +	return kallsyms_symbol_name(kallsyms, best);
> +}
> +
> +void * __weak dereference_module_function_descriptor(struct module *mod,
> +						     void *ptr)
> +{
> +	return ptr;
> +}
> +
> +/*
> + * For kallsyms to ask for address resolution.  NULL means not found.  Careful
> + * not to lock to avoid deadlock on oopses, simply disable preemption.
> + */
> +const char *module_address_lookup(unsigned long addr,
> +				  unsigned long *size,
> +			    unsigned long *offset,
> +			    char **modname,
> +			    const unsigned char **modbuildid,
> +			    char *namebuf)
> +{
> +	const char *ret = NULL;
> +	struct module *mod;
> +
> +	preempt_disable();
> +	mod = __module_address(addr);
> +	if (mod) {
> +		if (modname)
> +			*modname = mod->name;
> +		if (modbuildid) {
> +#if IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID)
> +			*modbuildid = mod->build_id;
> +#else
> +			*modbuildid = NULL;
> +#endif
> +		}
> +
> +		ret = find_kallsyms_symbol(mod, addr, size, offset);
> +	}
> +	/* Make a copy in here where it's safe */
> +	if (ret) {
> +		strncpy(namebuf, ret, KSYM_NAME_LEN - 1);
> +		ret = namebuf;
> +	}
> +	preempt_enable();
> +
> +	return ret;
> +}
> +
> +int lookup_module_symbol_name(unsigned long addr, char *symname)
> +{
> +	struct module *mod;
> +
> +	preempt_disable();
> +	list_for_each_entry_rcu(mod, &modules, list) {
> +		if (mod->state == MODULE_STATE_UNFORMED)
> +			continue;
> +		if (within_module(addr, mod)) {
> +			const char *sym;
> +
> +			sym = find_kallsyms_symbol(mod, addr, NULL, NULL);
> +			if (!sym)
> +				goto out;
> +
> +			strscpy(symname, sym, KSYM_NAME_LEN);
> +			preempt_enable();
> +			return 0;
> +		}
> +	}
> +out:
> +	preempt_enable();
> +	return -ERANGE;
> +}
> +
> +int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size,
> +			       unsigned long *offset, char *modname, char *name)
> +{
> +	struct module *mod;
> +
> +	preempt_disable();
> +	list_for_each_entry_rcu(mod, &modules, list) {
> +		if (mod->state == MODULE_STATE_UNFORMED)
> +			continue;
> +		if (within_module(addr, mod)) {
> +			const char *sym;
> +
> +			sym = find_kallsyms_symbol(mod, addr, size, offset);
> +			if (!sym)
> +				goto out;
> +			if (modname)
> +				strscpy(modname, mod->name, MODULE_NAME_LEN);
> +			if (name)
> +				strscpy(name, sym, KSYM_NAME_LEN);
> +			preempt_enable();
> +			return 0;
> +		}
> +	}
> +out:
> +	preempt_enable();
> +	return -ERANGE;
> +}
> +
> +int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
> +		       char *name, char *module_name, int *exported)
> +{
> +	struct module *mod;
> +
> +	preempt_disable();
> +	list_for_each_entry_rcu(mod, &modules, list) {
> +		struct mod_kallsyms *kallsyms;
> +
> +		if (mod->state == MODULE_STATE_UNFORMED)
> +			continue;
> +		kallsyms = rcu_dereference_sched(mod->kallsyms);
> +		if (symnum < kallsyms->num_symtab) {
> +			const Elf_Sym *sym = &kallsyms->symtab[symnum];
> +
> +			*value = kallsyms_symbol_value(sym);
> +			*type = kallsyms->typetab[symnum];
> +			strscpy(name, kallsyms_symbol_name(kallsyms, symnum), KSYM_NAME_LEN);
> +			strscpy(module_name, mod->name, MODULE_NAME_LEN);
> +			*exported = is_exported(name, *value, mod);
> +			preempt_enable();
> +			return 0;
> +		}
> +		symnum -= kallsyms->num_symtab;
> +	}
> +	preempt_enable();
> +	return -ERANGE;
> +}
> +
> +/* Given a module and name of symbol, find and return the symbol's value */
> +unsigned long find_kallsyms_symbol_value(struct module *mod, const char *name)
> +{
> +	unsigned int i;
> +	struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms);
> +
> +	for (i = 0; i < kallsyms->num_symtab; i++) {
> +		const Elf_Sym *sym = &kallsyms->symtab[i];
> +
> +		if (strcmp(name, kallsyms_symbol_name(kallsyms, i)) == 0 &&
> +		    sym->st_shndx != SHN_UNDEF)
> +			return kallsyms_symbol_value(sym);
> +	}
> +	return 0;
> +}
> +
> +/* Look for this name: can be of form module:name. */
> +unsigned long module_kallsyms_lookup_name(const char *name)
> +{
> +	struct module *mod;
> +	char *colon;
> +	unsigned long ret = 0;
> +
> +	/* Don't lock: we're in enough trouble already. */
> +	preempt_disable();
> +	if ((colon = strnchr(name, MODULE_NAME_LEN, ':')) != NULL) {
> +		if ((mod = find_module_all(name, colon - name, false)) != NULL)
> +			ret = find_kallsyms_symbol_value(mod, colon + 1);
> +	} else {
> +		list_for_each_entry_rcu(mod, &modules, list) {
> +			if (mod->state == MODULE_STATE_UNFORMED)
> +				continue;
> +			if ((ret = find_kallsyms_symbol_value(mod, name)) != 0)
> +				break;
> +		}
> +	}
> +	preempt_enable();
> +	return ret;
> +}
> +
> +#ifdef CONFIG_LIVEPATCH
> +int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *,
> +					     struct module *, unsigned long),
> +				   void *data)
> +{
> +	struct module *mod;
> +	unsigned int i;
> +	int ret = 0;
> +
> +	mutex_lock(&module_mutex);
> +	list_for_each_entry(mod, &modules, list) {
> +		/* Still use rcu_dereference_sched to remain compliant with sparse */
> +		struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms);
> +
> +		if (mod->state == MODULE_STATE_UNFORMED)
> +			continue;
> +		for (i = 0; i < kallsyms->num_symtab; i++) {
> +			const Elf_Sym *sym = &kallsyms->symtab[i];
> +
> +			if (sym->st_shndx == SHN_UNDEF)
> +				continue;
> +
> +			ret = fn(data, kallsyms_symbol_name(kallsyms, i),
> +				 mod, kallsyms_symbol_value(sym));
> +			if (ret != 0)
> +				goto out;
> +		}
> +	}
> +out:
> +	mutex_unlock(&module_mutex);
> +	return ret;
> +}
> +#endif /* CONFIG_LIVEPATCH */
> diff --git a/kernel/module/main.c b/kernel/module/main.c
> index 7dd283959c5c..952079987ea4 100644
> --- a/kernel/module/main.c
> +++ b/kernel/module/main.c
> @@ -288,15 +288,6 @@ static bool check_exported_symbol(const struct symsearch *syms,
>   	return true;
>   }
>   
> -static unsigned long kernel_symbol_value(const struct kernel_symbol *sym)
> -{
> -#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
> -	return (unsigned long)offset_to_ptr(&sym->value_offset);
> -#else
> -	return sym->value;
> -#endif
> -}
> -
>   static const char *kernel_symbol_name(const struct kernel_symbol *sym)
>   {
>   #ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
> @@ -317,7 +308,7 @@ static const char *kernel_symbol_namespace(const struct kernel_symbol *sym)
>   #endif
>   }
>   
> -static int cmp_name(const void *name, const void *sym)
> +int cmp_name(const void *name, const void *sym)
>   {
>   	return strcmp(name, kernel_symbol_name(sym));
>   }
> @@ -387,8 +378,8 @@ static bool find_symbol(struct find_symbol_arg *fsa)
>    * Search for module by name: must hold module_mutex (or preempt disabled
>    * for read-only access).
>    */
> -static struct module *find_module_all(const char *name, size_t len,
> -				      bool even_unformed)
> +struct module *find_module_all(const char *name, size_t len,
> +			       bool even_unformed)
>   {
>   	struct module *mod;
>   
> @@ -1294,13 +1285,6 @@ resolve_symbol_wait(struct module *mod,
>   	return ksym;
>   }
>   
> -#ifdef CONFIG_KALLSYMS
> -static inline bool sect_empty(const Elf_Shdr *sect)
> -{
> -	return !(sect->sh_flags & SHF_ALLOC) || sect->sh_size == 0;
> -}
> -#endif
> -
>   /*
>    * /sys/module/foo/sections stuff
>    * J. Corbet <corbet@lwn.net>
> @@ -2065,7 +2049,7 @@ unsigned int __weak arch_mod_section_prepend(struct module *mod,
>   }
>   
>   /* Update size with this section: return offset. */
> -static long get_offset(struct module *mod, unsigned int *size,
> +long module_get_offset(struct module *mod, unsigned int *size,
>   		       Elf_Shdr *sechdr, unsigned int section)
>   {
>   	long ret;
> @@ -2121,7 +2105,7 @@ static void layout_sections(struct module *mod, struct load_info *info)
>   			    || s->sh_entsize != ~0UL
>   			    || module_init_layout_section(sname))
>   				continue;
> -			s->sh_entsize = get_offset(mod, &mod->core_layout.size, s, i);
> +			s->sh_entsize = module_get_offset(mod, &mod->core_layout.size, s, i);
>   			pr_debug("\t%s\n", sname);
>   		}
>   		switch (m) {
> @@ -2154,7 +2138,7 @@ static void layout_sections(struct module *mod, struct load_info *info)
>   			    || s->sh_entsize != ~0UL
>   			    || !module_init_layout_section(sname))
>   				continue;
> -			s->sh_entsize = (get_offset(mod, &mod->init_layout.size, s, i)
> +			s->sh_entsize = (module_get_offset(mod, &mod->init_layout.size, s, i)
>   					 | INIT_OFFSET_MASK);
>   			pr_debug("\t%s\n", sname);
>   		}
> @@ -2267,228 +2251,6 @@ static void free_modinfo(struct module *mod)
>   	}
>   }
>   
> -#ifdef CONFIG_KALLSYMS
> -
> -/* Lookup exported symbol in given range of kernel_symbols */
> -static const struct kernel_symbol *lookup_exported_symbol(const char *name,
> -							  const struct kernel_symbol *start,
> -							  const struct kernel_symbol *stop)
> -{
> -	return bsearch(name, start, stop - start,
> -			sizeof(struct kernel_symbol), cmp_name);
> -}
> -
> -static int is_exported(const char *name, unsigned long value,
> -		       const struct module *mod)
> -{
> -	const struct kernel_symbol *ks;
> -	if (!mod)
> -		ks = lookup_exported_symbol(name, __start___ksymtab, __stop___ksymtab);
> -	else
> -		ks = lookup_exported_symbol(name, mod->syms, mod->syms + mod->num_syms);
> -
> -	return ks != NULL && kernel_symbol_value(ks) == value;
> -}
> -
> -/* As per nm */
> -static char elf_type(const Elf_Sym *sym, const struct load_info *info)
> -{
> -	const Elf_Shdr *sechdrs = info->sechdrs;
> -
> -	if (ELF_ST_BIND(sym->st_info) == STB_WEAK) {
> -		if (ELF_ST_TYPE(sym->st_info) == STT_OBJECT)
> -			return 'v';
> -		else
> -			return 'w';
> -	}
> -	if (sym->st_shndx == SHN_UNDEF)
> -		return 'U';
> -	if (sym->st_shndx == SHN_ABS || sym->st_shndx == info->index.pcpu)
> -		return 'a';
> -	if (sym->st_shndx >= SHN_LORESERVE)
> -		return '?';
> -	if (sechdrs[sym->st_shndx].sh_flags & SHF_EXECINSTR)
> -		return 't';
> -	if (sechdrs[sym->st_shndx].sh_flags & SHF_ALLOC
> -	    && sechdrs[sym->st_shndx].sh_type != SHT_NOBITS) {
> -		if (!(sechdrs[sym->st_shndx].sh_flags & SHF_WRITE))
> -			return 'r';
> -		else if (sechdrs[sym->st_shndx].sh_flags & ARCH_SHF_SMALL)
> -			return 'g';
> -		else
> -			return 'd';
> -	}
> -	if (sechdrs[sym->st_shndx].sh_type == SHT_NOBITS) {
> -		if (sechdrs[sym->st_shndx].sh_flags & ARCH_SHF_SMALL)
> -			return 's';
> -		else
> -			return 'b';
> -	}
> -	if (strstarts(info->secstrings + sechdrs[sym->st_shndx].sh_name,
> -		      ".debug")) {
> -		return 'n';
> -	}
> -	return '?';
> -}
> -
> -static bool is_core_symbol(const Elf_Sym *src, const Elf_Shdr *sechdrs,
> -			unsigned int shnum, unsigned int pcpundx)
> -{
> -	const Elf_Shdr *sec;
> -
> -	if (src->st_shndx == SHN_UNDEF
> -	    || src->st_shndx >= shnum
> -	    || !src->st_name)
> -		return false;
> -
> -#ifdef CONFIG_KALLSYMS_ALL
> -	if (src->st_shndx == pcpundx)
> -		return true;
> -#endif
> -
> -	sec = sechdrs + src->st_shndx;
> -	if (!(sec->sh_flags & SHF_ALLOC)
> -#ifndef CONFIG_KALLSYMS_ALL
> -	    || !(sec->sh_flags & SHF_EXECINSTR)
> -#endif
> -	    || (sec->sh_entsize & INIT_OFFSET_MASK))
> -		return false;
> -
> -	return true;
> -}
> -
> -/*
> - * We only allocate and copy the strings needed by the parts of symtab
> - * we keep.  This is simple, but has the effect of making multiple
> - * copies of duplicates.  We could be more sophisticated, see
> - * linux-kernel thread starting with
> - * <73defb5e4bca04a6431392cc341112b1@localhost>.
> - */
> -static void layout_symtab(struct module *mod, struct load_info *info)
> -{
> -	Elf_Shdr *symsect = info->sechdrs + info->index.sym;
> -	Elf_Shdr *strsect = info->sechdrs + info->index.str;
> -	const Elf_Sym *src;
> -	unsigned int i, nsrc, ndst, strtab_size = 0;
> -
> -	/* Put symbol section at end of init part of module. */
> -	symsect->sh_flags |= SHF_ALLOC;
> -	symsect->sh_entsize = get_offset(mod, &mod->init_layout.size, symsect,
> -					 info->index.sym) | INIT_OFFSET_MASK;
> -	pr_debug("\t%s\n", info->secstrings + symsect->sh_name);
> -
> -	src = (void *)info->hdr + symsect->sh_offset;
> -	nsrc = symsect->sh_size / sizeof(*src);
> -
> -	/* Compute total space required for the core symbols' strtab. */
> -	for (ndst = i = 0; i < nsrc; i++) {
> -		if (i == 0 || is_livepatch_module(mod) ||
> -		    is_core_symbol(src+i, info->sechdrs, info->hdr->e_shnum,
> -				   info->index.pcpu)) {
> -			strtab_size += strlen(&info->strtab[src[i].st_name])+1;
> -			ndst++;
> -		}
> -	}
> -
> -	/* Append room for core symbols at end of core part. */
> -	info->symoffs = ALIGN(mod->core_layout.size, symsect->sh_addralign ?: 1);
> -	info->stroffs = mod->core_layout.size = info->symoffs + ndst * sizeof(Elf_Sym);
> -	mod->core_layout.size += strtab_size;
> -	info->core_typeoffs = mod->core_layout.size;
> -	mod->core_layout.size += ndst * sizeof(char);
> -	mod->core_layout.size = debug_align(mod->core_layout.size);
> -
> -	/* Put string table section at end of init part of module. */
> -	strsect->sh_flags |= SHF_ALLOC;
> -	strsect->sh_entsize = get_offset(mod, &mod->init_layout.size, strsect,
> -					 info->index.str) | INIT_OFFSET_MASK;
> -	pr_debug("\t%s\n", info->secstrings + strsect->sh_name);
> -
> -	/* We'll tack temporary mod_kallsyms on the end. */
> -	mod->init_layout.size = ALIGN(mod->init_layout.size,
> -				      __alignof__(struct mod_kallsyms));
> -	info->mod_kallsyms_init_off = mod->init_layout.size;
> -	mod->init_layout.size += sizeof(struct mod_kallsyms);
> -	info->init_typeoffs = mod->init_layout.size;
> -	mod->init_layout.size += nsrc * sizeof(char);
> -	mod->init_layout.size = debug_align(mod->init_layout.size);
> -}
> -
> -/*
> - * We use the full symtab and strtab which layout_symtab arranged to
> - * be appended to the init section.  Later we switch to the cut-down
> - * core-only ones.
> - */
> -static void add_kallsyms(struct module *mod, const struct load_info *info)
> -{
> -	unsigned int i, ndst;
> -	const Elf_Sym *src;
> -	Elf_Sym *dst;
> -	char *s;
> -	Elf_Shdr *symsec = &info->sechdrs[info->index.sym];
> -
> -	/* Set up to point into init section. */
> -	mod->kallsyms = mod->init_layout.base + info->mod_kallsyms_init_off;
> -
> -	mod->kallsyms->symtab = (void *)symsec->sh_addr;
> -	mod->kallsyms->num_symtab = symsec->sh_size / sizeof(Elf_Sym);
> -	/* Make sure we get permanent strtab: don't use info->strtab. */
> -	mod->kallsyms->strtab = (void *)info->sechdrs[info->index.str].sh_addr;
> -	mod->kallsyms->typetab = mod->init_layout.base + info->init_typeoffs;
> -
> -	/*
> -	 * Now populate the cut down core kallsyms for after init
> -	 * and set types up while we still have access to sections.
> -	 */
> -	mod->core_kallsyms.symtab = dst = mod->core_layout.base + info->symoffs;
> -	mod->core_kallsyms.strtab = s = mod->core_layout.base + info->stroffs;
> -	mod->core_kallsyms.typetab = mod->core_layout.base + info->core_typeoffs;
> -	src = mod->kallsyms->symtab;
> -	for (ndst = i = 0; i < mod->kallsyms->num_symtab; i++) {
> -		mod->kallsyms->typetab[i] = elf_type(src + i, info);
> -		if (i == 0 || is_livepatch_module(mod) ||
> -		    is_core_symbol(src+i, info->sechdrs, info->hdr->e_shnum,
> -				   info->index.pcpu)) {
> -			mod->core_kallsyms.typetab[ndst] =
> -			    mod->kallsyms->typetab[i];
> -			dst[ndst] = src[i];
> -			dst[ndst++].st_name = s - mod->core_kallsyms.strtab;
> -			s += strlcpy(s, &mod->kallsyms->strtab[src[i].st_name],
> -				     KSYM_NAME_LEN) + 1;
> -		}
> -	}
> -	mod->core_kallsyms.num_symtab = ndst;
> -}
> -#else
> -static inline void layout_symtab(struct module *mod, struct load_info *info)
> -{
> -}
> -
> -static void add_kallsyms(struct module *mod, const struct load_info *info)
> -{
> -}
> -#endif /* CONFIG_KALLSYMS */
> -
> -#if IS_ENABLED(CONFIG_KALLSYMS) && IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID)
> -static void init_build_id(struct module *mod, const struct load_info *info)
> -{
> -	const Elf_Shdr *sechdr;
> -	unsigned int i;
> -
> -	for (i = 0; i < info->hdr->e_shnum; i++) {
> -		sechdr = &info->sechdrs[i];
> -		if (!sect_empty(sechdr) && sechdr->sh_type == SHT_NOTE &&
> -		    !build_id_parse_buf((void *)sechdr->sh_addr, mod->build_id,
> -					sechdr->sh_size))
> -			break;
> -	}
> -}
> -#else
> -static void init_build_id(struct module *mod, const struct load_info *info)
> -{
> -}
> -#endif
> -
>   static void dynamic_debug_setup(struct module *mod, struct _ddebug *debug, unsigned int num)
>   {
>   	if (!debug)
> @@ -3799,287 +3561,6 @@ static inline int within(unsigned long addr, void *start, unsigned long size)
>   	return ((void *)addr >= start && (void *)addr < start + size);
>   }
>   
> -#ifdef CONFIG_KALLSYMS
> -/*
> - * This ignores the intensely annoying "mapping symbols" found
> - * in ARM ELF files: $a, $t and $d.
> - */
> -static inline int is_arm_mapping_symbol(const char *str)
> -{
> -	if (str[0] == '.' && str[1] == 'L')
> -		return true;
> -	return str[0] == '$' && strchr("axtd", str[1])
> -	       && (str[2] == '\0' || str[2] == '.');
> -}
> -
> -static const char *kallsyms_symbol_name(struct mod_kallsyms *kallsyms, unsigned int symnum)
> -{
> -	return kallsyms->strtab + kallsyms->symtab[symnum].st_name;
> -}
> -
> -/*
> - * Given a module and address, find the corresponding symbol and return its name
> - * while providing its size and offset if needed.
> - */
> -static const char *find_kallsyms_symbol(struct module *mod,
> -					unsigned long addr,
> -					unsigned long *size,
> -					unsigned long *offset)
> -{
> -	unsigned int i, best = 0;
> -	unsigned long nextval, bestval;
> -	struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms);
> -
> -	/* At worse, next value is at end of module */
> -	if (within_module_init(addr, mod))
> -		nextval = (unsigned long)mod->init_layout.base+mod->init_layout.text_size;
> -	else
> -		nextval = (unsigned long)mod->core_layout.base+mod->core_layout.text_size;
> -
> -	bestval = kallsyms_symbol_value(&kallsyms->symtab[best]);
> -
> -	/*
> -	 * Scan for closest preceding symbol, and next symbol. (ELF
> -	 * starts real symbols at 1).
> -	 */
> -	for (i = 1; i < kallsyms->num_symtab; i++) {
> -		const Elf_Sym *sym = &kallsyms->symtab[i];
> -		unsigned long thisval = kallsyms_symbol_value(sym);
> -
> -		if (sym->st_shndx == SHN_UNDEF)
> -			continue;
> -
> -		/*
> -		 * We ignore unnamed symbols: they're uninformative
> -		 * and inserted at a whim.
> -		 */
> -		if (*kallsyms_symbol_name(kallsyms, i) == '\0'
> -		    || is_arm_mapping_symbol(kallsyms_symbol_name(kallsyms, i)))
> -			continue;
> -
> -		if (thisval <= addr && thisval > bestval) {
> -			best = i;
> -			bestval = thisval;
> -		}
> -		if (thisval > addr && thisval < nextval)
> -			nextval = thisval;
> -	}
> -
> -	if (!best)
> -		return NULL;
> -
> -	if (size)
> -		*size = nextval - bestval;
> -	if (offset)
> -		*offset = addr - bestval;
> -
> -	return kallsyms_symbol_name(kallsyms, best);
> -}
> -
> -void * __weak dereference_module_function_descriptor(struct module *mod,
> -						     void *ptr)
> -{
> -	return ptr;
> -}
> -
> -/*
> - * For kallsyms to ask for address resolution.  NULL means not found.  Careful
> - * not to lock to avoid deadlock on oopses, simply disable preemption.
> - */
> -const char *module_address_lookup(unsigned long addr,
> -			    unsigned long *size,
> -			    unsigned long *offset,
> -			    char **modname,
> -			    const unsigned char **modbuildid,
> -			    char *namebuf)
> -{
> -	const char *ret = NULL;
> -	struct module *mod;
> -
> -	preempt_disable();
> -	mod = __module_address(addr);
> -	if (mod) {
> -		if (modname)
> -			*modname = mod->name;
> -		if (modbuildid) {
> -#if IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID)
> -			*modbuildid = mod->build_id;
> -#else
> -			*modbuildid = NULL;
> -#endif
> -		}
> -
> -		ret = find_kallsyms_symbol(mod, addr, size, offset);
> -	}
> -	/* Make a copy in here where it's safe */
> -	if (ret) {
> -		strncpy(namebuf, ret, KSYM_NAME_LEN - 1);
> -		ret = namebuf;
> -	}
> -	preempt_enable();
> -
> -	return ret;
> -}
> -
> -int lookup_module_symbol_name(unsigned long addr, char *symname)
> -{
> -	struct module *mod;
> -
> -	preempt_disable();
> -	list_for_each_entry_rcu(mod, &modules, list) {
> -		if (mod->state == MODULE_STATE_UNFORMED)
> -			continue;
> -		if (within_module(addr, mod)) {
> -			const char *sym;
> -
> -			sym = find_kallsyms_symbol(mod, addr, NULL, NULL);
> -			if (!sym)
> -				goto out;
> -
> -			strlcpy(symname, sym, KSYM_NAME_LEN);
> -			preempt_enable();
> -			return 0;
> -		}
> -	}
> -out:
> -	preempt_enable();
> -	return -ERANGE;
> -}
> -
> -int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size,
> -			unsigned long *offset, char *modname, char *name)
> -{
> -	struct module *mod;
> -
> -	preempt_disable();
> -	list_for_each_entry_rcu(mod, &modules, list) {
> -		if (mod->state == MODULE_STATE_UNFORMED)
> -			continue;
> -		if (within_module(addr, mod)) {
> -			const char *sym;
> -
> -			sym = find_kallsyms_symbol(mod, addr, size, offset);
> -			if (!sym)
> -				goto out;
> -			if (modname)
> -				strlcpy(modname, mod->name, MODULE_NAME_LEN);
> -			if (name)
> -				strlcpy(name, sym, KSYM_NAME_LEN);
> -			preempt_enable();
> -			return 0;
> -		}
> -	}
> -out:
> -	preempt_enable();
> -	return -ERANGE;
> -}
> -
> -int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
> -			char *name, char *module_name, int *exported)
> -{
> -	struct module *mod;
> -
> -	preempt_disable();
> -	list_for_each_entry_rcu(mod, &modules, list) {
> -		struct mod_kallsyms *kallsyms;
> -
> -		if (mod->state == MODULE_STATE_UNFORMED)
> -			continue;
> -		kallsyms = rcu_dereference_sched(mod->kallsyms);
> -		if (symnum < kallsyms->num_symtab) {
> -			const Elf_Sym *sym = &kallsyms->symtab[symnum];
> -
> -			*value = kallsyms_symbol_value(sym);
> -			*type = kallsyms->typetab[symnum];
> -			strlcpy(name, kallsyms_symbol_name(kallsyms, symnum), KSYM_NAME_LEN);
> -			strlcpy(module_name, mod->name, MODULE_NAME_LEN);
> -			*exported = is_exported(name, *value, mod);
> -			preempt_enable();
> -			return 0;
> -		}
> -		symnum -= kallsyms->num_symtab;
> -	}
> -	preempt_enable();
> -	return -ERANGE;
> -}
> -
> -/* Given a module and name of symbol, find and return the symbol's value */
> -static unsigned long find_kallsyms_symbol_value(struct module *mod, const char *name)
> -{
> -	unsigned int i;
> -	struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms);
> -
> -	for (i = 0; i < kallsyms->num_symtab; i++) {
> -		const Elf_Sym *sym = &kallsyms->symtab[i];
> -
> -		if (strcmp(name, kallsyms_symbol_name(kallsyms, i)) == 0 &&
> -		    sym->st_shndx != SHN_UNDEF)
> -			return kallsyms_symbol_value(sym);
> -	}
> -	return 0;
> -}
> -
> -/* Look for this name: can be of form module:name. */
> -unsigned long module_kallsyms_lookup_name(const char *name)
> -{
> -	struct module *mod;
> -	char *colon;
> -	unsigned long ret = 0;
> -
> -	/* Don't lock: we're in enough trouble already. */
> -	preempt_disable();
> -	if ((colon = strnchr(name, MODULE_NAME_LEN, ':')) != NULL) {
> -		if ((mod = find_module_all(name, colon - name, false)) != NULL)
> -			ret = find_kallsyms_symbol_value(mod, colon+1);
> -	} else {
> -		list_for_each_entry_rcu(mod, &modules, list) {
> -			if (mod->state == MODULE_STATE_UNFORMED)
> -				continue;
> -			if ((ret = find_kallsyms_symbol_value(mod, name)) != 0)
> -				break;
> -		}
> -	}
> -	preempt_enable();
> -	return ret;
> -}
> -
> -#ifdef CONFIG_LIVEPATCH
> -int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *,
> -					     struct module *, unsigned long),
> -				   void *data)
> -{
> -	struct module *mod;
> -	unsigned int i;
> -	int ret = 0;
> -
> -	mutex_lock(&module_mutex);
> -	list_for_each_entry(mod, &modules, list) {
> -		/* We hold module_mutex: no need for rcu_dereference_sched */
> -		struct mod_kallsyms *kallsyms = mod->kallsyms;
> -
> -		if (mod->state == MODULE_STATE_UNFORMED)
> -			continue;
> -		for (i = 0; i < kallsyms->num_symtab; i++) {
> -			const Elf_Sym *sym = &kallsyms->symtab[i];
> -
> -			if (sym->st_shndx == SHN_UNDEF)
> -				continue;
> -
> -			ret = fn(data, kallsyms_symbol_name(kallsyms, i),
> -				 mod, kallsyms_symbol_value(sym));
> -			if (ret != 0)
> -				goto out;
> -
> -			cond_resched();
> -		}
> -	}
> -out:
> -	mutex_unlock(&module_mutex);
> -	return ret;
> -}
> -#endif /* CONFIG_LIVEPATCH */
> -#endif /* CONFIG_KALLSYMS */
> -
>   static void cfi_init(struct module *mod)
>   {
>   #ifdef CONFIG_CFI_CLANG

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

* Re: [PATCH v8 10/13] module: Move procfs support into a separate file
  2022-02-22 14:13 ` [PATCH v8 10/13] module: Move procfs " Aaron Tomlin
@ 2022-02-22 17:59   ` Christophe Leroy
  0 siblings, 0 replies; 43+ messages in thread
From: Christophe Leroy @ 2022-02-22 17:59 UTC (permalink / raw)
  To: Aaron Tomlin, mcgrof
  Cc: cl, pmladek, mbenes, akpm, jeyu, linux-kernel, linux-modules,
	void, atomlin, allen.lkml, joe, msuchanek, oleksandr



Le 22/02/2022 à 15:13, Aaron Tomlin a écrit :
> No functional change.
> 
> This patch migrates code that allows one to generate a
> list of loaded/or linked modules via /proc when procfs
> support is enabled into kernel/module/procfs.c.
> 
> Signed-off-by: Aaron Tomlin <atomlin@redhat.com>

Reviewed-by: Christophe Leroy <christophe.leroy@csgroup.eu>

> ---
>   kernel/module/Makefile   |   1 +
>   kernel/module/internal.h |   1 +
>   kernel/module/main.c     | 131 +-----------------------------------
>   kernel/module/procfs.c   | 142 +++++++++++++++++++++++++++++++++++++++
>   4 files changed, 145 insertions(+), 130 deletions(-)
>   create mode 100644 kernel/module/procfs.c
> 
> diff --git a/kernel/module/Makefile b/kernel/module/Makefile
> index 9901bed3ab5b..94296c98a67f 100644
> --- a/kernel/module/Makefile
> +++ b/kernel/module/Makefile
> @@ -15,3 +15,4 @@ obj-$(CONFIG_MODULES_TREE_LOOKUP) += tree_lookup.o
>   obj-$(CONFIG_STRICT_MODULE_RWX) += strict_rwx.o
>   obj-$(CONFIG_DEBUG_KMEMLEAK) += debug_kmemleak.o
>   obj-$(CONFIG_KALLSYMS) += kallsyms.o
> +obj-$(CONFIG_PROC_FS) += procfs.o
> diff --git a/kernel/module/internal.h b/kernel/module/internal.h
> index 44ca05b9eb8f..6af40c2d145f 100644
> --- a/kernel/module/internal.h
> +++ b/kernel/module/internal.h
> @@ -72,6 +72,7 @@ struct module *find_module_all(const char *name, size_t len, bool even_unformed)
>   int cmp_name(const void *name, const void *sym);
>   long module_get_offset(struct module *mod, unsigned int *size, Elf_Shdr *sechdr,
>   		       unsigned int section);
> +char *module_flags(struct module *mod, char *buf);
>   
>   static inline unsigned long kernel_symbol_value(const struct kernel_symbol *sym)
>   {
> diff --git a/kernel/module/main.c b/kernel/module/main.c
> index 952079987ea4..44b6fd1acc44 100644
> --- a/kernel/module/main.c
> +++ b/kernel/module/main.c
> @@ -22,7 +22,6 @@
>   #include <linux/slab.h>
>   #include <linux/vmalloc.h>
>   #include <linux/elf.h>
> -#include <linux/proc_fs.h>
>   #include <linux/seq_file.h>
>   #include <linux/syscalls.h>
>   #include <linux/fcntl.h>
> @@ -805,31 +804,6 @@ SYSCALL_DEFINE2(delete_module, const char __user *, name_user,
>   	return ret;
>   }
>   
> -static inline void print_unload_info(struct seq_file *m, struct module *mod)
> -{
> -	struct module_use *use;
> -	int printed_something = 0;
> -
> -	seq_printf(m, " %i ", module_refcount(mod));
> -
> -	/*
> -	 * Always include a trailing , so userspace can differentiate
> -	 * between this and the old multi-field proc format.
> -	 */
> -	list_for_each_entry(use, &mod->source_list, source_list) {
> -		printed_something = 1;
> -		seq_printf(m, "%s,", use->source->name);
> -	}
> -
> -	if (mod->init != NULL && mod->exit == NULL) {
> -		printed_something = 1;
> -		seq_puts(m, "[permanent],");
> -	}
> -
> -	if (!printed_something)
> -		seq_puts(m, "-");
> -}
> -
>   void __symbol_put(const char *symbol)
>   {
>   	struct find_symbol_arg fsa = {
> @@ -919,12 +893,6 @@ void module_put(struct module *module)
>   EXPORT_SYMBOL(module_put);
>   
>   #else /* !CONFIG_MODULE_UNLOAD */
> -static inline void print_unload_info(struct seq_file *m, struct module *mod)
> -{
> -	/* We don't know the usage count, or what modules are using. */
> -	seq_puts(m, " - -");
> -}
> -
>   static inline void module_unload_free(struct module *mod)
>   {
>   }
> @@ -3596,7 +3564,7 @@ static void cfi_cleanup(struct module *mod)
>   }
>   
>   /* Keep in sync with MODULE_FLAGS_BUF_SIZE !!! */
> -static char *module_flags(struct module *mod, char *buf)
> +char *module_flags(struct module *mod, char *buf)
>   {
>   	int bx = 0;
>   
> @@ -3619,103 +3587,6 @@ static char *module_flags(struct module *mod, char *buf)
>   	return buf;
>   }
>   
> -#ifdef CONFIG_PROC_FS
> -/* Called by the /proc file system to return a list of modules. */
> -static void *m_start(struct seq_file *m, loff_t *pos)
> -{
> -	mutex_lock(&module_mutex);
> -	return seq_list_start(&modules, *pos);
> -}
> -
> -static void *m_next(struct seq_file *m, void *p, loff_t *pos)
> -{
> -	return seq_list_next(p, &modules, pos);
> -}
> -
> -static void m_stop(struct seq_file *m, void *p)
> -{
> -	mutex_unlock(&module_mutex);
> -}
> -
> -static int m_show(struct seq_file *m, void *p)
> -{
> -	struct module *mod = list_entry(p, struct module, list);
> -	char buf[MODULE_FLAGS_BUF_SIZE];
> -	void *value;
> -
> -	/* We always ignore unformed modules. */
> -	if (mod->state == MODULE_STATE_UNFORMED)
> -		return 0;
> -
> -	seq_printf(m, "%s %u",
> -		   mod->name, mod->init_layout.size + mod->core_layout.size);
> -	print_unload_info(m, mod);
> -
> -	/* Informative for users. */
> -	seq_printf(m, " %s",
> -		   mod->state == MODULE_STATE_GOING ? "Unloading" :
> -		   mod->state == MODULE_STATE_COMING ? "Loading" :
> -		   "Live");
> -	/* Used by oprofile and other similar tools. */
> -	value = m->private ? NULL : mod->core_layout.base;
> -	seq_printf(m, " 0x%px", value);
> -
> -	/* Taints info */
> -	if (mod->taints)
> -		seq_printf(m, " %s", module_flags(mod, buf));
> -
> -	seq_puts(m, "\n");
> -	return 0;
> -}
> -
> -/*
> - * Format: modulename size refcount deps address
> - *
> - * Where refcount is a number or -, and deps is a comma-separated list
> - * of depends or -.
> - */
> -static const struct seq_operations modules_op = {
> -	.start	= m_start,
> -	.next	= m_next,
> -	.stop	= m_stop,
> -	.show	= m_show
> -};
> -
> -/*
> - * This also sets the "private" pointer to non-NULL if the
> - * kernel pointers should be hidden (so you can just test
> - * "m->private" to see if you should keep the values private).
> - *
> - * We use the same logic as for /proc/kallsyms.
> - */
> -static int modules_open(struct inode *inode, struct file *file)
> -{
> -	int err = seq_open(file, &modules_op);
> -
> -	if (!err) {
> -		struct seq_file *m = file->private_data;
> -		m->private = kallsyms_show_value(file->f_cred) ? NULL : (void *)8ul;
> -	}
> -
> -	return err;
> -}
> -
> -static const struct proc_ops modules_proc_ops = {
> -	.proc_flags	= PROC_ENTRY_PERMANENT,
> -	.proc_open	= modules_open,
> -	.proc_read	= seq_read,
> -	.proc_lseek	= seq_lseek,
> -	.proc_release	= seq_release,
> -};
> -
> -static int __init proc_modules_init(void)
> -{
> -	proc_create("modules", 0, NULL, &modules_proc_ops);
> -	return 0;
> -}
> -module_init(proc_modules_init);
> -#endif
> -
>   /* Given an address, look for it in the module exception tables. */
>   const struct exception_table_entry *search_module_extables(unsigned long addr)
>   {
> diff --git a/kernel/module/procfs.c b/kernel/module/procfs.c
> new file mode 100644
> index 000000000000..2717e130788e
> --- /dev/null
> +++ b/kernel/module/procfs.c
> @@ -0,0 +1,142 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Module proc support
> + *
> + * Copyright (C) 2008 Alexey Dobriyan
> + */
> +
> +#include <linux/module.h>
> +#include <linux/kallsyms.h>
> +#include <linux/mutex.h>
> +#include <linux/seq_file.h>
> +#include <linux/proc_fs.h>
> +#include "internal.h"
> +
> +#ifdef CONFIG_MODULE_UNLOAD
> +static inline void print_unload_info(struct seq_file *m, struct module *mod)
> +{
> +	struct module_use *use;
> +	int printed_something = 0;
> +
> +	seq_printf(m, " %i ", module_refcount(mod));
> +
> +	/*
> +	 * Always include a trailing , so userspace can differentiate
> +	 * between this and the old multi-field proc format.
> +	 */
> +	list_for_each_entry(use, &mod->source_list, source_list) {
> +		printed_something = 1;
> +		seq_printf(m, "%s,", use->source->name);
> +	}
> +
> +	if (mod->init && !mod->exit) {
> +		printed_something = 1;
> +		seq_puts(m, "[permanent],");
> +	}
> +
> +	if (!printed_something)
> +		seq_puts(m, "-");
> +}
> +#else /* !CONFIG_MODULE_UNLOAD */
> +static inline void print_unload_info(struct seq_file *m, struct module *mod)
> +{
> +	/* We don't know the usage count, or what modules are using. */
> +	seq_puts(m, " - -");
> +}
> +#endif /* CONFIG_MODULE_UNLOAD */
> +
> +/* Called by the /proc file system to return a list of modules. */
> +static void *m_start(struct seq_file *m, loff_t *pos)
> +{
> +	mutex_lock(&module_mutex);
> +	return seq_list_start(&modules, *pos);
> +}
> +
> +static void *m_next(struct seq_file *m, void *p, loff_t *pos)
> +{
> +	return seq_list_next(p, &modules, pos);
> +}
> +
> +static void m_stop(struct seq_file *m, void *p)
> +{
> +	mutex_unlock(&module_mutex);
> +}
> +
> +static int m_show(struct seq_file *m, void *p)
> +{
> +	struct module *mod = list_entry(p, struct module, list);
> +	char buf[MODULE_FLAGS_BUF_SIZE];
> +	void *value;
> +
> +	/* We always ignore unformed modules. */
> +	if (mod->state == MODULE_STATE_UNFORMED)
> +		return 0;
> +
> +	seq_printf(m, "%s %u",
> +		   mod->name, mod->init_layout.size + mod->core_layout.size);
> +	print_unload_info(m, mod);
> +
> +	/* Informative for users. */
> +	seq_printf(m, " %s",
> +		   mod->state == MODULE_STATE_GOING ? "Unloading" :
> +		   mod->state == MODULE_STATE_COMING ? "Loading" :
> +		   "Live");
> +	/* Used by oprofile and other similar tools. */
> +	value = m->private ? NULL : mod->core_layout.base;
> +	seq_printf(m, " 0x%px", value);
> +
> +	/* Taints info */
> +	if (mod->taints)
> +		seq_printf(m, " %s", module_flags(mod, buf));
> +
> +	seq_puts(m, "\n");
> +	return 0;
> +}
> +
> +/*
> + * Format: modulename size refcount deps address
> + *
> + * Where refcount is a number or -, and deps is a comma-separated list
> + * of depends or -.
> + */
> +static const struct seq_operations modules_op = {
> +	.start	= m_start,
> +	.next	= m_next,
> +	.stop	= m_stop,
> +	.show	= m_show
> +};
> +
> +/*
> + * This also sets the "private" pointer to non-NULL if the
> + * kernel pointers should be hidden (so you can just test
> + * "m->private" to see if you should keep the values private).
> + *
> + * We use the same logic as for /proc/kallsyms.
> + */
> +static int modules_open(struct inode *inode, struct file *file)
> +{
> +	int err = seq_open(file, &modules_op);
> +
> +	if (!err) {
> +		struct seq_file *m = file->private_data;
> +
> +		m->private = kallsyms_show_value(file->f_cred) ? NULL : (void *)8ul;
> +	}
> +
> +	return err;
> +}
> +
> +static const struct proc_ops modules_proc_ops = {
> +	.proc_flags	= PROC_ENTRY_PERMANENT,
> +	.proc_open	= modules_open,
> +	.proc_read	= seq_read,
> +	.proc_lseek	= seq_lseek,
> +	.proc_release	= seq_release,
> +};
> +
> +static int __init proc_modules_init(void)
> +{
> +	proc_create("modules", 0, NULL, &modules_proc_ops);
> +	return 0;
> +}
> +module_init(proc_modules_init);

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

* Re: [PATCH v8 11/13] module: Move sysfs support into a separate file
  2022-02-22 14:13 ` [PATCH v8 11/13] module: Move sysfs " Aaron Tomlin
@ 2022-02-22 17:59   ` Christophe Leroy
  0 siblings, 0 replies; 43+ messages in thread
From: Christophe Leroy @ 2022-02-22 17:59 UTC (permalink / raw)
  To: Aaron Tomlin, mcgrof
  Cc: cl, pmladek, mbenes, akpm, jeyu, linux-kernel, linux-modules,
	void, atomlin, allen.lkml, joe, msuchanek, oleksandr



Le 22/02/2022 à 15:13, Aaron Tomlin a écrit :
> No functional change.
> 
> This patch migrates module sysfs support out of core code into
> kernel/module/sysfs.c. In addition simple code refactoring to
> make this possible.
> 
> Signed-off-by: Aaron Tomlin <atomlin@redhat.com>

Reviewed-by: Christophe Leroy <christophe.leroy@csgroup.eu>

> ---
>   kernel/module/Makefile   |   1 +
>   kernel/module/internal.h |  21 ++
>   kernel/module/main.c     | 469 +--------------------------------------
>   kernel/module/sysfs.c    | 436 ++++++++++++++++++++++++++++++++++++
>   4 files changed, 461 insertions(+), 466 deletions(-)
>   create mode 100644 kernel/module/sysfs.c
> 
> diff --git a/kernel/module/Makefile b/kernel/module/Makefile
> index 94296c98a67f..cf8dcdc6b55f 100644
> --- a/kernel/module/Makefile
> +++ b/kernel/module/Makefile
> @@ -16,3 +16,4 @@ obj-$(CONFIG_STRICT_MODULE_RWX) += strict_rwx.o
>   obj-$(CONFIG_DEBUG_KMEMLEAK) += debug_kmemleak.o
>   obj-$(CONFIG_KALLSYMS) += kallsyms.o
>   obj-$(CONFIG_PROC_FS) += procfs.o
> +obj-$(CONFIG_SYSFS) += sysfs.o
> diff --git a/kernel/module/internal.h b/kernel/module/internal.h
> index 6af40c2d145f..62d749ef695e 100644
> --- a/kernel/module/internal.h
> +++ b/kernel/module/internal.h
> @@ -34,6 +34,9 @@
>   extern struct mutex module_mutex;
>   extern struct list_head modules;
>   
> +extern struct module_attribute *modinfo_attrs[];
> +extern size_t modinfo_attrs_count;
> +
>   /* Provided by the linker */
>   extern const struct kernel_symbol __start___ksymtab[];
>   extern const struct kernel_symbol __stop___ksymtab[];
> @@ -204,3 +207,21 @@ static inline void init_build_id(struct module *mod, const struct load_info *inf
>   static inline void layout_symtab(struct module *mod, struct load_info *info) { }
>   static inline void add_kallsyms(struct module *mod, const struct load_info *info) { }
>   #endif /* CONFIG_KALLSYMS */
> +
> +#ifdef CONFIG_SYSFS
> +int mod_sysfs_setup(struct module *mod, const struct load_info *info,
> +		    struct kernel_param *kparam, unsigned int num_params);
> +void mod_sysfs_teardown(struct module *mod);
> +void init_param_lock(struct module *mod);
> +#else /* !CONFIG_SYSFS */
> +static inline int mod_sysfs_setup(struct module *mod,
> +			   	  const struct load_info *info,
> +			   	  struct kernel_param *kparam,
> +			   	  unsigned int num_params)
> +{
> +	return 0;
> +}
> +
> +static inline void mod_sysfs_teardown(struct module *mod) { }
> +static inline void init_param_lock(struct module *mod) { }
> +#endif /* CONFIG_SYSFS */
> diff --git a/kernel/module/main.c b/kernel/module/main.c
> index 44b6fd1acc44..b8a59b5c3e3a 100644
> --- a/kernel/module/main.c
> +++ b/kernel/module/main.c
> @@ -14,9 +14,7 @@
>   #include <linux/init.h>
>   #include <linux/kallsyms.h>
>   #include <linux/buildid.h>
> -#include <linux/file.h>
>   #include <linux/fs.h>
> -#include <linux/sysfs.h>
>   #include <linux/kernel.h>
>   #include <linux/kernel_read_file.h>
>   #include <linux/slab.h>
> @@ -989,7 +987,7 @@ static ssize_t show_taint(struct module_attribute *mattr,
>   static struct module_attribute modinfo_taint =
>   	__ATTR(taint, 0444, show_taint, NULL);
>   
> -static struct module_attribute *modinfo_attrs[] = {
> +struct module_attribute *modinfo_attrs[] = {
>   	&module_uevent,
>   	&modinfo_version,
>   	&modinfo_srcversion,
> @@ -1003,6 +1001,8 @@ static struct module_attribute *modinfo_attrs[] = {
>   	NULL,
>   };
>   
> +size_t modinfo_attrs_count = ARRAY_SIZE(modinfo_attrs);
> +
>   static const char vermagic[] = VERMAGIC_STRING;
>   
>   static int try_to_force_load(struct module *mod, const char *reason)
> @@ -1253,469 +1253,6 @@ resolve_symbol_wait(struct module *mod,
>   	return ksym;
>   }
>   
> -/*
> - * /sys/module/foo/sections stuff
> - * J. Corbet <corbet@lwn.net>
> - */
> -#ifdef CONFIG_SYSFS
> -
> -#ifdef CONFIG_KALLSYMS
> -struct module_sect_attr {
> -	struct bin_attribute battr;
> -	unsigned long address;
> -};
> -
> -struct module_sect_attrs {
> -	struct attribute_group grp;
> -	unsigned int nsections;
> -	struct module_sect_attr attrs[];
> -};
> -
> -#define MODULE_SECT_READ_SIZE (3 /* "0x", "\n" */ + (BITS_PER_LONG / 4))
> -static ssize_t module_sect_read(struct file *file, struct kobject *kobj,
> -				struct bin_attribute *battr,
> -				char *buf, loff_t pos, size_t count)
> -{
> -	struct module_sect_attr *sattr =
> -		container_of(battr, struct module_sect_attr, battr);
> -	char bounce[MODULE_SECT_READ_SIZE + 1];
> -	size_t wrote;
> -
> -	if (pos != 0)
> -		return -EINVAL;
> -
> -	/*
> -	 * Since we're a binary read handler, we must account for the
> -	 * trailing NUL byte that sprintf will write: if "buf" is
> -	 * too small to hold the NUL, or the NUL is exactly the last
> -	 * byte, the read will look like it got truncated by one byte.
> -	 * Since there is no way to ask sprintf nicely to not write
> -	 * the NUL, we have to use a bounce buffer.
> -	 */
> -	wrote = scnprintf(bounce, sizeof(bounce), "0x%px\n",
> -			 kallsyms_show_value(file->f_cred)
> -				? (void *)sattr->address : NULL);
> -	count = min(count, wrote);
> -	memcpy(buf, bounce, count);
> -
> -	return count;
> -}
> -
> -static void free_sect_attrs(struct module_sect_attrs *sect_attrs)
> -{
> -	unsigned int section;
> -
> -	for (section = 0; section < sect_attrs->nsections; section++)
> -		kfree(sect_attrs->attrs[section].battr.attr.name);
> -	kfree(sect_attrs);
> -}
> -
> -static void add_sect_attrs(struct module *mod, const struct load_info *info)
> -{
> -	unsigned int nloaded = 0, i, size[2];
> -	struct module_sect_attrs *sect_attrs;
> -	struct module_sect_attr *sattr;
> -	struct bin_attribute **gattr;
> -
> -	/* Count loaded sections and allocate structures */
> -	for (i = 0; i < info->hdr->e_shnum; i++)
> -		if (!sect_empty(&info->sechdrs[i]))
> -			nloaded++;
> -	size[0] = ALIGN(struct_size(sect_attrs, attrs, nloaded),
> -			sizeof(sect_attrs->grp.bin_attrs[0]));
> -	size[1] = (nloaded + 1) * sizeof(sect_attrs->grp.bin_attrs[0]);
> -	sect_attrs = kzalloc(size[0] + size[1], GFP_KERNEL);
> -	if (sect_attrs == NULL)
> -		return;
> -
> -	/* Setup section attributes. */
> -	sect_attrs->grp.name = "sections";
> -	sect_attrs->grp.bin_attrs = (void *)sect_attrs + size[0];
> -
> -	sect_attrs->nsections = 0;
> -	sattr = &sect_attrs->attrs[0];
> -	gattr = &sect_attrs->grp.bin_attrs[0];
> -	for (i = 0; i < info->hdr->e_shnum; i++) {
> -		Elf_Shdr *sec = &info->sechdrs[i];
> -		if (sect_empty(sec))
> -			continue;
> -		sysfs_bin_attr_init(&sattr->battr);
> -		sattr->address = sec->sh_addr;
> -		sattr->battr.attr.name =
> -			kstrdup(info->secstrings + sec->sh_name, GFP_KERNEL);
> -		if (sattr->battr.attr.name == NULL)
> -			goto out;
> -		sect_attrs->nsections++;
> -		sattr->battr.read = module_sect_read;
> -		sattr->battr.size = MODULE_SECT_READ_SIZE;
> -		sattr->battr.attr.mode = 0400;
> -		*(gattr++) = &(sattr++)->battr;
> -	}
> -	*gattr = NULL;
> -
> -	if (sysfs_create_group(&mod->mkobj.kobj, &sect_attrs->grp))
> -		goto out;
> -
> -	mod->sect_attrs = sect_attrs;
> -	return;
> -  out:
> -	free_sect_attrs(sect_attrs);
> -}
> -
> -static void remove_sect_attrs(struct module *mod)
> -{
> -	if (mod->sect_attrs) {
> -		sysfs_remove_group(&mod->mkobj.kobj,
> -				   &mod->sect_attrs->grp);
> -		/*
> -		 * We are positive that no one is using any sect attrs
> -		 * at this point.  Deallocate immediately.
> -		 */
> -		free_sect_attrs(mod->sect_attrs);
> -		mod->sect_attrs = NULL;
> -	}
> -}
> -
> -/*
> - * /sys/module/foo/notes/.section.name gives contents of SHT_NOTE sections.
> - */
> -
> -struct module_notes_attrs {
> -	struct kobject *dir;
> -	unsigned int notes;
> -	struct bin_attribute attrs[];
> -};
> -
> -static ssize_t module_notes_read(struct file *filp, struct kobject *kobj,
> -				 struct bin_attribute *bin_attr,
> -				 char *buf, loff_t pos, size_t count)
> -{
> -	/*
> -	 * The caller checked the pos and count against our size.
> -	 */
> -	memcpy(buf, bin_attr->private + pos, count);
> -	return count;
> -}
> -
> -static void free_notes_attrs(struct module_notes_attrs *notes_attrs,
> -			     unsigned int i)
> -{
> -	if (notes_attrs->dir) {
> -		while (i-- > 0)
> -			sysfs_remove_bin_file(notes_attrs->dir,
> -					      &notes_attrs->attrs[i]);
> -		kobject_put(notes_attrs->dir);
> -	}
> -	kfree(notes_attrs);
> -}
> -
> -static void add_notes_attrs(struct module *mod, const struct load_info *info)
> -{
> -	unsigned int notes, loaded, i;
> -	struct module_notes_attrs *notes_attrs;
> -	struct bin_attribute *nattr;
> -
> -	/* failed to create section attributes, so can't create notes */
> -	if (!mod->sect_attrs)
> -		return;
> -
> -	/* Count notes sections and allocate structures.  */
> -	notes = 0;
> -	for (i = 0; i < info->hdr->e_shnum; i++)
> -		if (!sect_empty(&info->sechdrs[i]) &&
> -		    (info->sechdrs[i].sh_type == SHT_NOTE))
> -			++notes;
> -
> -	if (notes == 0)
> -		return;
> -
> -	notes_attrs = kzalloc(struct_size(notes_attrs, attrs, notes),
> -			      GFP_KERNEL);
> -	if (notes_attrs == NULL)
> -		return;
> -
> -	notes_attrs->notes = notes;
> -	nattr = &notes_attrs->attrs[0];
> -	for (loaded = i = 0; i < info->hdr->e_shnum; ++i) {
> -		if (sect_empty(&info->sechdrs[i]))
> -			continue;
> -		if (info->sechdrs[i].sh_type == SHT_NOTE) {
> -			sysfs_bin_attr_init(nattr);
> -			nattr->attr.name = mod->sect_attrs->attrs[loaded].battr.attr.name;
> -			nattr->attr.mode = S_IRUGO;
> -			nattr->size = info->sechdrs[i].sh_size;
> -			nattr->private = (void *) info->sechdrs[i].sh_addr;
> -			nattr->read = module_notes_read;
> -			++nattr;
> -		}
> -		++loaded;
> -	}
> -
> -	notes_attrs->dir = kobject_create_and_add("notes", &mod->mkobj.kobj);
> -	if (!notes_attrs->dir)
> -		goto out;
> -
> -	for (i = 0; i < notes; ++i)
> -		if (sysfs_create_bin_file(notes_attrs->dir,
> -					  &notes_attrs->attrs[i]))
> -			goto out;
> -
> -	mod->notes_attrs = notes_attrs;
> -	return;
> -
> -  out:
> -	free_notes_attrs(notes_attrs, i);
> -}
> -
> -static void remove_notes_attrs(struct module *mod)
> -{
> -	if (mod->notes_attrs)
> -		free_notes_attrs(mod->notes_attrs, mod->notes_attrs->notes);
> -}
> -
> -#else
> -
> -static inline void add_sect_attrs(struct module *mod,
> -				  const struct load_info *info)
> -{
> -}
> -
> -static inline void remove_sect_attrs(struct module *mod)
> -{
> -}
> -
> -static inline void add_notes_attrs(struct module *mod,
> -				   const struct load_info *info)
> -{
> -}
> -
> -static inline void remove_notes_attrs(struct module *mod)
> -{
> -}
> -#endif /* CONFIG_KALLSYMS */
> -
> -static void del_usage_links(struct module *mod)
> -{
> -#ifdef CONFIG_MODULE_UNLOAD
> -	struct module_use *use;
> -
> -	mutex_lock(&module_mutex);
> -	list_for_each_entry(use, &mod->target_list, target_list)
> -		sysfs_remove_link(use->target->holders_dir, mod->name);
> -	mutex_unlock(&module_mutex);
> -#endif
> -}
> -
> -static int add_usage_links(struct module *mod)
> -{
> -	int ret = 0;
> -#ifdef CONFIG_MODULE_UNLOAD
> -	struct module_use *use;
> -
> -	mutex_lock(&module_mutex);
> -	list_for_each_entry(use, &mod->target_list, target_list) {
> -		ret = sysfs_create_link(use->target->holders_dir,
> -					&mod->mkobj.kobj, mod->name);
> -		if (ret)
> -			break;
> -	}
> -	mutex_unlock(&module_mutex);
> -	if (ret)
> -		del_usage_links(mod);
> -#endif
> -	return ret;
> -}
> -
> -static void module_remove_modinfo_attrs(struct module *mod, int end);
> -
> -static int module_add_modinfo_attrs(struct module *mod)
> -{
> -	struct module_attribute *attr;
> -	struct module_attribute *temp_attr;
> -	int error = 0;
> -	int i;
> -
> -	mod->modinfo_attrs = kzalloc((sizeof(struct module_attribute) *
> -					(ARRAY_SIZE(modinfo_attrs) + 1)),
> -					GFP_KERNEL);
> -	if (!mod->modinfo_attrs)
> -		return -ENOMEM;
> -
> -	temp_attr = mod->modinfo_attrs;
> -	for (i = 0; (attr = modinfo_attrs[i]); i++) {
> -		if (!attr->test || attr->test(mod)) {
> -			memcpy(temp_attr, attr, sizeof(*temp_attr));
> -			sysfs_attr_init(&temp_attr->attr);
> -			error = sysfs_create_file(&mod->mkobj.kobj,
> -					&temp_attr->attr);
> -			if (error)
> -				goto error_out;
> -			++temp_attr;
> -		}
> -	}
> -
> -	return 0;
> -
> -error_out:
> -	if (i > 0)
> -		module_remove_modinfo_attrs(mod, --i);
> -	else
> -		kfree(mod->modinfo_attrs);
> -	return error;
> -}
> -
> -static void module_remove_modinfo_attrs(struct module *mod, int end)
> -{
> -	struct module_attribute *attr;
> -	int i;
> -
> -	for (i = 0; (attr = &mod->modinfo_attrs[i]); i++) {
> -		if (end >= 0 && i > end)
> -			break;
> -		/* pick a field to test for end of list */
> -		if (!attr->attr.name)
> -			break;
> -		sysfs_remove_file(&mod->mkobj.kobj, &attr->attr);
> -		if (attr->free)
> -			attr->free(mod);
> -	}
> -	kfree(mod->modinfo_attrs);
> -}
> -
> -static void mod_kobject_put(struct module *mod)
> -{
> -	DECLARE_COMPLETION_ONSTACK(c);
> -	mod->mkobj.kobj_completion = &c;
> -	kobject_put(&mod->mkobj.kobj);
> -	wait_for_completion(&c);
> -}
> -
> -static int mod_sysfs_init(struct module *mod)
> -{
> -	int err;
> -	struct kobject *kobj;
> -
> -	if (!module_sysfs_initialized) {
> -		pr_err("%s: module sysfs not initialized\n", mod->name);
> -		err = -EINVAL;
> -		goto out;
> -	}
> -
> -	kobj = kset_find_obj(module_kset, mod->name);
> -	if (kobj) {
> -		pr_err("%s: module is already loaded\n", mod->name);
> -		kobject_put(kobj);
> -		err = -EINVAL;
> -		goto out;
> -	}
> -
> -	mod->mkobj.mod = mod;
> -
> -	memset(&mod->mkobj.kobj, 0, sizeof(mod->mkobj.kobj));
> -	mod->mkobj.kobj.kset = module_kset;
> -	err = kobject_init_and_add(&mod->mkobj.kobj, &module_ktype, NULL,
> -				   "%s", mod->name);
> -	if (err)
> -		mod_kobject_put(mod);
> -
> -out:
> -	return err;
> -}
> -
> -static int mod_sysfs_setup(struct module *mod,
> -			   const struct load_info *info,
> -			   struct kernel_param *kparam,
> -			   unsigned int num_params)
> -{
> -	int err;
> -
> -	err = mod_sysfs_init(mod);
> -	if (err)
> -		goto out;
> -
> -	mod->holders_dir = kobject_create_and_add("holders", &mod->mkobj.kobj);
> -	if (!mod->holders_dir) {
> -		err = -ENOMEM;
> -		goto out_unreg;
> -	}
> -
> -	err = module_param_sysfs_setup(mod, kparam, num_params);
> -	if (err)
> -		goto out_unreg_holders;
> -
> -	err = module_add_modinfo_attrs(mod);
> -	if (err)
> -		goto out_unreg_param;
> -
> -	err = add_usage_links(mod);
> -	if (err)
> -		goto out_unreg_modinfo_attrs;
> -
> -	add_sect_attrs(mod, info);
> -	add_notes_attrs(mod, info);
> -
> -	return 0;
> -
> -out_unreg_modinfo_attrs:
> -	module_remove_modinfo_attrs(mod, -1);
> -out_unreg_param:
> -	module_param_sysfs_remove(mod);
> -out_unreg_holders:
> -	kobject_put(mod->holders_dir);
> -out_unreg:
> -	mod_kobject_put(mod);
> -out:
> -	return err;
> -}
> -
> -static void mod_sysfs_fini(struct module *mod)
> -{
> -	remove_notes_attrs(mod);
> -	remove_sect_attrs(mod);
> -	mod_kobject_put(mod);
> -}
> -
> -static void init_param_lock(struct module *mod)
> -{
> -	mutex_init(&mod->param_lock);
> -}
> -#else /* !CONFIG_SYSFS */
> -
> -static int mod_sysfs_setup(struct module *mod,
> -			   const struct load_info *info,
> -			   struct kernel_param *kparam,
> -			   unsigned int num_params)
> -{
> -	return 0;
> -}
> -
> -static void mod_sysfs_fini(struct module *mod)
> -{
> -}
> -
> -static void module_remove_modinfo_attrs(struct module *mod, int end)
> -{
> -}
> -
> -static void del_usage_links(struct module *mod)
> -{
> -}
> -
> -static void init_param_lock(struct module *mod)
> -{
> -}
> -#endif /* CONFIG_SYSFS */
> -
> -static void mod_sysfs_teardown(struct module *mod)
> -{
> -	del_usage_links(mod);
> -	module_remove_modinfo_attrs(mod, -1);
> -	module_param_sysfs_remove(mod);
> -	kobject_put(mod->mkobj.drivers_dir);
> -	kobject_put(mod->holders_dir);
> -	mod_sysfs_fini(mod);
> -}
> -
>   /*
>    * LKM RO/NX protection: protect module's text/ro-data
>    * from modification and any data from execution.
> diff --git a/kernel/module/sysfs.c b/kernel/module/sysfs.c
> new file mode 100644
> index 000000000000..ce68f821dcd1
> --- /dev/null
> +++ b/kernel/module/sysfs.c
> @@ -0,0 +1,436 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Module sysfs support
> + *
> + * Copyright (C) 2008 Rusty Russell
> + */
> +
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/fs.h>
> +#include <linux/sysfs.h>
> +#include <linux/slab.h>
> +#include <linux/kallsyms.h>
> +#include <linux/mutex.h>
> +#include "internal.h"
> +
> +/*
> + * /sys/module/foo/sections stuff
> + * J. Corbet <corbet@lwn.net>
> + */
> +#ifdef CONFIG_KALLSYMS
> +struct module_sect_attr {
> +	struct bin_attribute battr;
> +	unsigned long address;
> +};
> +
> +struct module_sect_attrs {
> +	struct attribute_group grp;
> +	unsigned int nsections;
> +	struct module_sect_attr attrs[];
> +};
> +
> +#define MODULE_SECT_READ_SIZE (3 /* "0x", "\n" */ + (BITS_PER_LONG / 4))
> +static ssize_t module_sect_read(struct file *file, struct kobject *kobj,
> +				struct bin_attribute *battr,
> +				char *buf, loff_t pos, size_t count)
> +{
> +	struct module_sect_attr *sattr =
> +		container_of(battr, struct module_sect_attr, battr);
> +	char bounce[MODULE_SECT_READ_SIZE + 1];
> +	size_t wrote;
> +
> +	if (pos != 0)
> +		return -EINVAL;
> +
> +	/*
> +	 * Since we're a binary read handler, we must account for the
> +	 * trailing NUL byte that sprintf will write: if "buf" is
> +	 * too small to hold the NUL, or the NUL is exactly the last
> +	 * byte, the read will look like it got truncated by one byte.
> +	 * Since there is no way to ask sprintf nicely to not write
> +	 * the NUL, we have to use a bounce buffer.
> +	 */
> +	wrote = scnprintf(bounce, sizeof(bounce), "0x%px\n",
> +			  kallsyms_show_value(file->f_cred)
> +				? (void *)sattr->address : NULL);
> +	count = min(count, wrote);
> +	memcpy(buf, bounce, count);
> +
> +	return count;
> +}
> +
> +static void free_sect_attrs(struct module_sect_attrs *sect_attrs)
> +{
> +	unsigned int section;
> +
> +	for (section = 0; section < sect_attrs->nsections; section++)
> +		kfree(sect_attrs->attrs[section].battr.attr.name);
> +	kfree(sect_attrs);
> +}
> +
> +static void add_sect_attrs(struct module *mod, const struct load_info *info)
> +{
> +	unsigned int nloaded = 0, i, size[2];
> +	struct module_sect_attrs *sect_attrs;
> +	struct module_sect_attr *sattr;
> +	struct bin_attribute **gattr;
> +
> +	/* Count loaded sections and allocate structures */
> +	for (i = 0; i < info->hdr->e_shnum; i++)
> +		if (!sect_empty(&info->sechdrs[i]))
> +			nloaded++;
> +	size[0] = ALIGN(struct_size(sect_attrs, attrs, nloaded),
> +			sizeof(sect_attrs->grp.bin_attrs[0]));
> +	size[1] = (nloaded + 1) * sizeof(sect_attrs->grp.bin_attrs[0]);
> +	sect_attrs = kzalloc(size[0] + size[1], GFP_KERNEL);
> +	if (!sect_attrs)
> +		return;
> +
> +	/* Setup section attributes. */
> +	sect_attrs->grp.name = "sections";
> +	sect_attrs->grp.bin_attrs = (void *)sect_attrs + size[0];
> +
> +	sect_attrs->nsections = 0;
> +	sattr = &sect_attrs->attrs[0];
> +	gattr = &sect_attrs->grp.bin_attrs[0];
> +	for (i = 0; i < info->hdr->e_shnum; i++) {
> +		Elf_Shdr *sec = &info->sechdrs[i];
> +
> +		if (sect_empty(sec))
> +			continue;
> +		sysfs_bin_attr_init(&sattr->battr);
> +		sattr->address = sec->sh_addr;
> +		sattr->battr.attr.name =
> +			kstrdup(info->secstrings + sec->sh_name, GFP_KERNEL);
> +		if (!sattr->battr.attr.name)
> +			goto out;
> +		sect_attrs->nsections++;
> +		sattr->battr.read = module_sect_read;
> +		sattr->battr.size = MODULE_SECT_READ_SIZE;
> +		sattr->battr.attr.mode = 0400;
> +		*(gattr++) = &(sattr++)->battr;
> +	}
> +	*gattr = NULL;
> +
> +	if (sysfs_create_group(&mod->mkobj.kobj, &sect_attrs->grp))
> +		goto out;
> +
> +	mod->sect_attrs = sect_attrs;
> +	return;
> +out:
> +	free_sect_attrs(sect_attrs);
> +}
> +
> +static void remove_sect_attrs(struct module *mod)
> +{
> +	if (mod->sect_attrs) {
> +		sysfs_remove_group(&mod->mkobj.kobj,
> +				   &mod->sect_attrs->grp);
> +		/*
> +		 * We are positive that no one is using any sect attrs
> +		 * at this point.  Deallocate immediately.
> +		 */
> +		free_sect_attrs(mod->sect_attrs);
> +		mod->sect_attrs = NULL;
> +	}
> +}
> +
> +/*
> + * /sys/module/foo/notes/.section.name gives contents of SHT_NOTE sections.
> + */
> +
> +struct module_notes_attrs {
> +	struct kobject *dir;
> +	unsigned int notes;
> +	struct bin_attribute attrs[];
> +};
> +
> +static ssize_t module_notes_read(struct file *filp, struct kobject *kobj,
> +				 struct bin_attribute *bin_attr,
> +				 char *buf, loff_t pos, size_t count)
> +{
> +	/*
> +	 * The caller checked the pos and count against our size.
> +	 */
> +	memcpy(buf, bin_attr->private + pos, count);
> +	return count;
> +}
> +
> +static void free_notes_attrs(struct module_notes_attrs *notes_attrs,
> +			     unsigned int i)
> +{
> +	if (notes_attrs->dir) {
> +		while (i-- > 0)
> +			sysfs_remove_bin_file(notes_attrs->dir,
> +					      &notes_attrs->attrs[i]);
> +		kobject_put(notes_attrs->dir);
> +	}
> +	kfree(notes_attrs);
> +}
> +
> +static void add_notes_attrs(struct module *mod, const struct load_info *info)
> +{
> +	unsigned int notes, loaded, i;
> +	struct module_notes_attrs *notes_attrs;
> +	struct bin_attribute *nattr;
> +
> +	/* failed to create section attributes, so can't create notes */
> +	if (!mod->sect_attrs)
> +		return;
> +
> +	/* Count notes sections and allocate structures.  */
> +	notes = 0;
> +	for (i = 0; i < info->hdr->e_shnum; i++)
> +		if (!sect_empty(&info->sechdrs[i]) &&
> +		    info->sechdrs[i].sh_type == SHT_NOTE)
> +			++notes;
> +
> +	if (notes == 0)
> +		return;
> +
> +	notes_attrs = kzalloc(struct_size(notes_attrs, attrs, notes),
> +			      GFP_KERNEL);
> +	if (!notes_attrs)
> +		return;
> +
> +	notes_attrs->notes = notes;
> +	nattr = &notes_attrs->attrs[0];
> +	for (loaded = i = 0; i < info->hdr->e_shnum; ++i) {
> +		if (sect_empty(&info->sechdrs[i]))
> +			continue;
> +		if (info->sechdrs[i].sh_type == SHT_NOTE) {
> +			sysfs_bin_attr_init(nattr);
> +			nattr->attr.name = mod->sect_attrs->attrs[loaded].battr.attr.name;
> +			nattr->attr.mode = 0444;
> +			nattr->size = info->sechdrs[i].sh_size;
> +			nattr->private = (void *)info->sechdrs[i].sh_addr;
> +			nattr->read = module_notes_read;
> +			++nattr;
> +		}
> +		++loaded;
> +	}
> +
> +	notes_attrs->dir = kobject_create_and_add("notes", &mod->mkobj.kobj);
> +	if (!notes_attrs->dir)
> +		goto out;
> +
> +	for (i = 0; i < notes; ++i)
> +		if (sysfs_create_bin_file(notes_attrs->dir,
> +					  &notes_attrs->attrs[i]))
> +			goto out;
> +
> +	mod->notes_attrs = notes_attrs;
> +	return;
> +
> +out:
> +	free_notes_attrs(notes_attrs, i);
> +}
> +
> +static void remove_notes_attrs(struct module *mod)
> +{
> +	if (mod->notes_attrs)
> +		free_notes_attrs(mod->notes_attrs, mod->notes_attrs->notes);
> +}
> +
> +#else /* !CONFIG_KALLSYMS */
> +static inline void add_sect_attrs(struct module *mod, const struct load_info *info) { }
> +static inline void remove_sect_attrs(struct module *mod) { }
> +static inline void add_notes_attrs(struct module *mod, const struct load_info *info) { }
> +static inline void remove_notes_attrs(struct module *mod) { }
> +#endif /* CONFIG_KALLSYMS */
> +
> +static void del_usage_links(struct module *mod)
> +{
> +#ifdef CONFIG_MODULE_UNLOAD
> +	struct module_use *use;
> +
> +	mutex_lock(&module_mutex);
> +	list_for_each_entry(use, &mod->target_list, target_list)
> +		sysfs_remove_link(use->target->holders_dir, mod->name);
> +	mutex_unlock(&module_mutex);
> +#endif
> +}
> +
> +static int add_usage_links(struct module *mod)
> +{
> +	int ret = 0;
> +#ifdef CONFIG_MODULE_UNLOAD
> +	struct module_use *use;
> +
> +	mutex_lock(&module_mutex);
> +	list_for_each_entry(use, &mod->target_list, target_list) {
> +		ret = sysfs_create_link(use->target->holders_dir,
> +					&mod->mkobj.kobj, mod->name);
> +		if (ret)
> +			break;
> +	}
> +	mutex_unlock(&module_mutex);
> +	if (ret)
> +		del_usage_links(mod);
> +#endif
> +	return ret;
> +}
> +
> +static void module_remove_modinfo_attrs(struct module *mod, int end)
> +{
> +	struct module_attribute *attr;
> +	int i;
> +
> +	for (i = 0; (attr = &mod->modinfo_attrs[i]); i++) {
> +		if (end >= 0 && i > end)
> +			break;
> +		/* pick a field to test for end of list */
> +		if (!attr->attr.name)
> +			break;
> +		sysfs_remove_file(&mod->mkobj.kobj, &attr->attr);
> +		if (attr->free)
> +			attr->free(mod);
> +	}
> +	kfree(mod->modinfo_attrs);
> +}
> +
> +static int module_add_modinfo_attrs(struct module *mod)
> +{
> +	struct module_attribute *attr;
> +	struct module_attribute *temp_attr;
> +	int error = 0;
> +	int i;
> +
> +	mod->modinfo_attrs = kzalloc((sizeof(struct module_attribute) *
> +					(modinfo_attrs_count + 1)),
> +					GFP_KERNEL);
> +	if (!mod->modinfo_attrs)
> +		return -ENOMEM;
> +
> +	temp_attr = mod->modinfo_attrs;
> +	for (i = 0; (attr = modinfo_attrs[i]); i++) {
> +		if (!attr->test || attr->test(mod)) {
> +			memcpy(temp_attr, attr, sizeof(*temp_attr));
> +			sysfs_attr_init(&temp_attr->attr);
> +			error = sysfs_create_file(&mod->mkobj.kobj,
> +						  &temp_attr->attr);
> +			if (error)
> +				goto error_out;
> +			++temp_attr;
> +		}
> +	}
> +
> +	return 0;
> +
> +error_out:
> +	if (i > 0)
> +		module_remove_modinfo_attrs(mod, --i);
> +	else
> +		kfree(mod->modinfo_attrs);
> +	return error;
> +}
> +
> +static void mod_kobject_put(struct module *mod)
> +{
> +	DECLARE_COMPLETION_ONSTACK(c);
> +
> +	mod->mkobj.kobj_completion = &c;
> +	kobject_put(&mod->mkobj.kobj);
> +	wait_for_completion(&c);
> +}
> +
> +static int mod_sysfs_init(struct module *mod)
> +{
> +	int err;
> +	struct kobject *kobj;
> +
> +	if (!module_sysfs_initialized) {
> +		pr_err("%s: module sysfs not initialized\n", mod->name);
> +		err = -EINVAL;
> +		goto out;
> +	}
> +
> +	kobj = kset_find_obj(module_kset, mod->name);
> +	if (kobj) {
> +		pr_err("%s: module is already loaded\n", mod->name);
> +		kobject_put(kobj);
> +		err = -EINVAL;
> +		goto out;
> +	}
> +
> +	mod->mkobj.mod = mod;
> +
> +	memset(&mod->mkobj.kobj, 0, sizeof(mod->mkobj.kobj));
> +	mod->mkobj.kobj.kset = module_kset;
> +	err = kobject_init_and_add(&mod->mkobj.kobj, &module_ktype, NULL,
> +				   "%s", mod->name);
> +	if (err)
> +		mod_kobject_put(mod);
> +
> +out:
> +	return err;
> +}
> +
> +int mod_sysfs_setup(struct module *mod,
> +		    const struct load_info *info,
> +			   struct kernel_param *kparam,
> +			   unsigned int num_params)
> +{
> +	int err;
> +
> +	err = mod_sysfs_init(mod);
> +	if (err)
> +		goto out;
> +
> +	mod->holders_dir = kobject_create_and_add("holders", &mod->mkobj.kobj);
> +	if (!mod->holders_dir) {
> +		err = -ENOMEM;
> +		goto out_unreg;
> +	}
> +
> +	err = module_param_sysfs_setup(mod, kparam, num_params);
> +	if (err)
> +		goto out_unreg_holders;
> +
> +	err = module_add_modinfo_attrs(mod);
> +	if (err)
> +		goto out_unreg_param;
> +
> +	err = add_usage_links(mod);
> +	if (err)
> +		goto out_unreg_modinfo_attrs;
> +
> +	add_sect_attrs(mod, info);
> +	add_notes_attrs(mod, info);
> +
> +	return 0;
> +
> +out_unreg_modinfo_attrs:
> +	module_remove_modinfo_attrs(mod, -1);
> +out_unreg_param:
> +	module_param_sysfs_remove(mod);
> +out_unreg_holders:
> +	kobject_put(mod->holders_dir);
> +out_unreg:
> +	mod_kobject_put(mod);
> +out:
> +	return err;
> +}
> +
> +static void mod_sysfs_fini(struct module *mod)
> +{
> +	remove_notes_attrs(mod);
> +	remove_sect_attrs(mod);
> +	mod_kobject_put(mod);
> +}
> +
> +void mod_sysfs_teardown(struct module *mod)
> +{
> +	del_usage_links(mod);
> +	module_remove_modinfo_attrs(mod, -1);
> +	module_param_sysfs_remove(mod);
> +	kobject_put(mod->mkobj.drivers_dir);
> +	kobject_put(mod->holders_dir);
> +	mod_sysfs_fini(mod);
> +}
> +
> +void init_param_lock(struct module *mod)
> +{
> +	mutex_init(&mod->param_lock);
> +}

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

* Re: [PATCH v8 12/13] module: Move kdb_modules list out of core code
  2022-02-22 14:13 ` [PATCH v8 12/13] module: Move kdb_modules list out of core code Aaron Tomlin
@ 2022-02-22 18:05   ` Christophe Leroy
  0 siblings, 0 replies; 43+ messages in thread
From: Christophe Leroy @ 2022-02-22 18:05 UTC (permalink / raw)
  To: Aaron Tomlin, mcgrof, Jason Wessel, Daniel Thompson
  Cc: cl, pmladek, mbenes, akpm, jeyu, linux-kernel, linux-modules,
	void, atomlin, allen.lkml, joe, msuchanek, oleksandr,
	kgdb-bugreport

+ Daniel and Jason.

The full series is available at 
https://patchwork.kernel.org/project/linux-modules/list/?series=616741&state=*

Le 22/02/2022 à 15:13, Aaron Tomlin a écrit :
> No functional change.
> 
> This patch migrates kdb_modules list to core kdb code
> since the list of added/or loaded modules is no longer
> private.
> 
> Signed-off-by: Aaron Tomlin <atomlin@redhat.com>

Reviewed-by: Christophe Leroy <christophe.leroy@csgroup.eu>

> ---
>   kernel/debug/kdb/kdb_main.c    | 5 +++++
>   kernel/debug/kdb/kdb_private.h | 4 ----

This patch (and the cover letter) should be copied to KDB maintainers 
and KDB list

You can use the following command to findout who they are:

[chleroy@PO20335 linux-powerpc]$ ./scripts/get_maintainer.pl -f 
kernel/debug/kdb/kdb_main.c
Jason Wessel <jason.wessel@windriver.com> (maintainer:KGDB / KDB 
/debug_core)
Daniel Thompson <daniel.thompson@linaro.org> (maintainer:KGDB / KDB 
/debug_core,commit_signer:11/14=79%)
Douglas Anderson <dianders@chromium.org> (reviewer:KGDB / KDB 
/debug_core,commit_signer:8/14=57%)
kgdb-bugreport@lists.sourceforge.net (open list:KGDB / KDB /debug_core)
linux-kernel@vger.kernel.org (open list)


>   kernel/module/main.c           | 4 ----
>   3 files changed, 5 insertions(+), 8 deletions(-)
> 
> diff --git a/kernel/debug/kdb/kdb_main.c b/kernel/debug/kdb/kdb_main.c
> index 0852a537dad4..5369bf45c5d4 100644
> --- a/kernel/debug/kdb/kdb_main.c
> +++ b/kernel/debug/kdb/kdb_main.c
> @@ -59,6 +59,11 @@ EXPORT_SYMBOL(kdb_grepping_flag);
>   int kdb_grep_leading;
>   int kdb_grep_trailing;
>   
> +#ifdef CONFIG_MODULES
> +extern struct list_head modules;
> +static struct list_head *kdb_modules = &modules; /* kdb needs the list of modules */
> +#endif /* CONFIG_MODULES */
> +
>   /*
>    * Kernel debugger state flags
>    */
> diff --git a/kernel/debug/kdb/kdb_private.h b/kernel/debug/kdb/kdb_private.h
> index 0d2f9feea0a4..1f8c519a5f81 100644
> --- a/kernel/debug/kdb/kdb_private.h
> +++ b/kernel/debug/kdb/kdb_private.h
> @@ -226,10 +226,6 @@ extern void kdb_kbd_cleanup_state(void);
>   #define kdb_kbd_cleanup_state()
>   #endif /* ! CONFIG_KDB_KEYBOARD */
>   
> -#ifdef CONFIG_MODULES
> -extern struct list_head *kdb_modules;
> -#endif /* CONFIG_MODULES */
> -
>   extern char kdb_prompt_str[];
>   
>   #define	KDB_WORD_SIZE	((int)sizeof(unsigned long))
> diff --git a/kernel/module/main.c b/kernel/module/main.c
> index b8a59b5c3e3a..bcc4f7a82649 100644
> --- a/kernel/module/main.c
> +++ b/kernel/module/main.c
> @@ -108,10 +108,6 @@ static void mod_update_bounds(struct module *mod)
>   		__mod_update_bounds(mod->init_layout.base, mod->init_layout.size);
>   }
>   
> -#ifdef CONFIG_KGDB_KDB
> -struct list_head *kdb_modules = &modules; /* kdb needs the list of modules */
> -#endif /* CONFIG_KGDB_KDB */
> -
>   static void module_assert_mutex_or_preempt(void)
>   {
>   #ifdef CONFIG_LOCKDEP

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

* Re: [PATCH v8 13/13] module: Move version support into a separate file
  2022-02-22 14:13 ` [PATCH v8 13/13] module: Move version support into a separate file Aaron Tomlin
@ 2022-02-22 18:06   ` Christophe Leroy
  0 siblings, 0 replies; 43+ messages in thread
From: Christophe Leroy @ 2022-02-22 18:06 UTC (permalink / raw)
  To: Aaron Tomlin, mcgrof
  Cc: cl, pmladek, mbenes, akpm, jeyu, linux-kernel, linux-modules,
	void, atomlin, allen.lkml, joe, msuchanek, oleksandr



Le 22/02/2022 à 15:13, Aaron Tomlin a écrit :
> No functional change.
> 
> This patch migrates module version support out of core code into
> kernel/module/version.c. In addition simple code refactoring to
> make this possible.
> 
> Signed-off-by: Aaron Tomlin <atomlin@redhat.com>

Reviewed-by: Christophe Leroy <christophe.leroy@csgroup.eu>

> ---
>   kernel/module/Makefile   |   1 +
>   kernel/module/internal.h |  48 ++++++++++++
>   kernel/module/main.c     | 156 ++-------------------------------------
>   kernel/module/version.c  | 109 +++++++++++++++++++++++++++
>   4 files changed, 166 insertions(+), 148 deletions(-)
>   create mode 100644 kernel/module/version.c
> 
> diff --git a/kernel/module/Makefile b/kernel/module/Makefile
> index cf8dcdc6b55f..a46e6361017f 100644
> --- a/kernel/module/Makefile
> +++ b/kernel/module/Makefile
> @@ -17,3 +17,4 @@ obj-$(CONFIG_DEBUG_KMEMLEAK) += debug_kmemleak.o
>   obj-$(CONFIG_KALLSYMS) += kallsyms.o
>   obj-$(CONFIG_PROC_FS) += procfs.o
>   obj-$(CONFIG_SYSFS) += sysfs.o
> +obj-$(CONFIG_MODVERSIONS) += version.o
> diff --git a/kernel/module/internal.h b/kernel/module/internal.h
> index 62d749ef695e..3fc139d5074b 100644
> --- a/kernel/module/internal.h
> +++ b/kernel/module/internal.h
> @@ -70,7 +70,27 @@ struct load_info {
>   	} index;
>   };
>   
> +enum mod_license {
> +	NOT_GPL_ONLY,
> +	GPL_ONLY,
> +};
> +
> +struct find_symbol_arg {
> +	/* Input */
> +	const char *name;
> +	bool gplok;
> +	bool warn;
> +
> +	/* Output */
> +	struct module *owner;
> +	const s32 *crc;
> +	const struct kernel_symbol *sym;
> +	enum mod_license license;
> +};
> +
>   int mod_verify_sig(const void *mod, struct load_info *info);
> +int try_to_force_load(struct module *mod, const char *reason);
> +bool find_symbol(struct find_symbol_arg *fsa);
>   struct module *find_module_all(const char *name, size_t len, bool even_unformed);
>   int cmp_name(const void *name, const void *sym);
>   long module_get_offset(struct module *mod, unsigned int *size, Elf_Shdr *sechdr,
> @@ -225,3 +245,31 @@ static inline int mod_sysfs_setup(struct module *mod,
>   static inline void mod_sysfs_teardown(struct module *mod) { }
>   static inline void init_param_lock(struct module *mod) { }
>   #endif /* CONFIG_SYSFS */
> +
> +#ifdef CONFIG_MODVERSIONS
> +int check_version(const struct load_info *info,
> +		  const char *symname, struct module *mod, const s32 *crc);
> +void module_layout(struct module *mod, struct modversion_info *ver, struct kernel_param *kp,
> +		   struct kernel_symbol *ks, struct tracepoint * const *tp);
> +int check_modstruct_version(const struct load_info *info, struct module *mod);
> +int same_magic(const char *amagic, const char *bmagic, bool has_crcs);
> +#else /* !CONFIG_MODVERSIONS */
> +static inline int check_version(const struct load_info *info,
> +				const char *symname,
> +				struct module *mod,
> +				const s32 *crc)
> +{
> +	return 1;
> +}
> +
> +static inline int check_modstruct_version(const struct load_info *info,
> +					  struct module *mod)
> +{
> +	return 1;
> +}
> +
> +static inline int same_magic(const char *amagic, const char *bmagic, bool has_crcs)
> +{
> +	return strcmp(amagic, bmagic) == 0;
> +}
> +#endif /* CONFIG_MODVERSIONS */
> diff --git a/kernel/module/main.c b/kernel/module/main.c
> index bcc4f7a82649..0749afdc34b5 100644
> --- a/kernel/module/main.c
> +++ b/kernel/module/main.c
> @@ -86,6 +86,12 @@ struct mod_tree_root mod_tree __cacheline_aligned = {
>   static unsigned long module_addr_min = -1UL, module_addr_max;
>   #endif /* CONFIG_MODULES_TREE_LOOKUP */
>   
> +struct symsearch {
> +	const struct kernel_symbol *start, *stop;
> +	const s32 *crcs;
> +	enum mod_license license;
> +};
> +
>   /*
>    * Bounds of module text, for speeding up __module_address.
>    * Protected by module_mutex.
> @@ -244,28 +250,6 @@ static __maybe_unused void *any_section_objs(const struct load_info *info,
>   #define symversion(base, idx) ((base != NULL) ? ((base) + (idx)) : NULL)
>   #endif
>   
> -struct symsearch {
> -	const struct kernel_symbol *start, *stop;
> -	const s32 *crcs;
> -	enum mod_license {
> -		NOT_GPL_ONLY,
> -		GPL_ONLY,
> -	} license;
> -};
> -
> -struct find_symbol_arg {
> -	/* Input */
> -	const char *name;
> -	bool gplok;
> -	bool warn;
> -
> -	/* Output */
> -	struct module *owner;
> -	const s32 *crc;
> -	const struct kernel_symbol *sym;
> -	enum mod_license license;
> -};
> -
>   static bool check_exported_symbol(const struct symsearch *syms,
>   				  struct module *owner,
>   				  unsigned int symnum, void *data)
> @@ -327,7 +311,7 @@ static bool find_exported_symbol_in_section(const struct symsearch *syms,
>    * Find an exported symbol and return it, along with, (optional) crc and
>    * (optional) module which owns it.  Needs preempt disabled or module_mutex.
>    */
> -static bool find_symbol(struct find_symbol_arg *fsa)
> +bool find_symbol(struct find_symbol_arg *fsa)
>   {
>   	static const struct symsearch arr[] = {
>   		{ __start___ksymtab, __stop___ksymtab, __start___kcrctab,
> @@ -1001,7 +985,7 @@ size_t modinfo_attrs_count = ARRAY_SIZE(modinfo_attrs);
>   
>   static const char vermagic[] = VERMAGIC_STRING;
>   
> -static int try_to_force_load(struct module *mod, const char *reason)
> +int try_to_force_load(struct module *mod, const char *reason)
>   {
>   #ifdef CONFIG_MODULE_FORCE_LOAD
>   	if (!test_taint(TAINT_FORCED_MODULE))
> @@ -1013,115 +997,6 @@ static int try_to_force_load(struct module *mod, const char *reason)
>   #endif
>   }
>   
> -#ifdef CONFIG_MODVERSIONS
> -
> -static u32 resolve_rel_crc(const s32 *crc)
> -{
> -	return *(u32 *)((void *)crc + *crc);
> -}
> -
> -static int check_version(const struct load_info *info,
> -			 const char *symname,
> -			 struct module *mod,
> -			 const s32 *crc)
> -{
> -	Elf_Shdr *sechdrs = info->sechdrs;
> -	unsigned int versindex = info->index.vers;
> -	unsigned int i, num_versions;
> -	struct modversion_info *versions;
> -
> -	/* Exporting module didn't supply crcs?  OK, we're already tainted. */
> -	if (!crc)
> -		return 1;
> -
> -	/* No versions at all?  modprobe --force does this. */
> -	if (versindex == 0)
> -		return try_to_force_load(mod, symname) == 0;
> -
> -	versions = (void *) sechdrs[versindex].sh_addr;
> -	num_versions = sechdrs[versindex].sh_size
> -		/ sizeof(struct modversion_info);
> -
> -	for (i = 0; i < num_versions; i++) {
> -		u32 crcval;
> -
> -		if (strcmp(versions[i].name, symname) != 0)
> -			continue;
> -
> -		if (IS_ENABLED(CONFIG_MODULE_REL_CRCS))
> -			crcval = resolve_rel_crc(crc);
> -		else
> -			crcval = *crc;
> -		if (versions[i].crc == crcval)
> -			return 1;
> -		pr_debug("Found checksum %X vs module %lX\n",
> -			 crcval, versions[i].crc);
> -		goto bad_version;
> -	}
> -
> -	/* Broken toolchain. Warn once, then let it go.. */
> -	pr_warn_once("%s: no symbol version for %s\n", info->name, symname);
> -	return 1;
> -
> -bad_version:
> -	pr_warn("%s: disagrees about version of symbol %s\n",
> -	       info->name, symname);
> -	return 0;
> -}
> -
> -static inline int check_modstruct_version(const struct load_info *info,
> -					  struct module *mod)
> -{
> -	struct find_symbol_arg fsa = {
> -		.name	= "module_layout",
> -		.gplok	= true,
> -	};
> -
> -	/*
> -	 * Since this should be found in kernel (which can't be removed), no
> -	 * locking is necessary -- use preempt_disable() to placate lockdep.
> -	 */
> -	preempt_disable();
> -	if (!find_symbol(&fsa)) {
> -		preempt_enable();
> -		BUG();
> -	}
> -	preempt_enable();
> -	return check_version(info, "module_layout", mod, fsa.crc);
> -}
> -
> -/* First part is kernel version, which we ignore if module has crcs. */
> -static inline int same_magic(const char *amagic, const char *bmagic,
> -			     bool has_crcs)
> -{
> -	if (has_crcs) {
> -		amagic += strcspn(amagic, " ");
> -		bmagic += strcspn(bmagic, " ");
> -	}
> -	return strcmp(amagic, bmagic) == 0;
> -}
> -#else
> -static inline int check_version(const struct load_info *info,
> -				const char *symname,
> -				struct module *mod,
> -				const s32 *crc)
> -{
> -	return 1;
> -}
> -
> -static inline int check_modstruct_version(const struct load_info *info,
> -					  struct module *mod)
> -{
> -	return 1;
> -}
> -
> -static inline int same_magic(const char *amagic, const char *bmagic,
> -			     bool has_crcs)
> -{
> -	return strcmp(amagic, bmagic) == 0;
> -}
> -#endif /* CONFIG_MODVERSIONS */
> -
>   static char *get_modinfo(const struct load_info *info, const char *tag);
>   static char *get_next_modinfo(const struct load_info *info, const char *tag,
>   			      char *prev);
> @@ -3247,18 +3122,3 @@ void print_modules(void)
>   		pr_cont(" [last unloaded: %s]", last_unloaded_module);
>   	pr_cont("\n");
>   }
> -
> -#ifdef CONFIG_MODVERSIONS
> -/*
> - * Generate the signature for all relevant module structures here.
> - * If these change, we don't want to try to parse the module.
> - */
> -void module_layout(struct module *mod,
> -		   struct modversion_info *ver,
> -		   struct kernel_param *kp,
> -		   struct kernel_symbol *ks,
> -		   struct tracepoint * const *tp)
> -{
> -}
> -EXPORT_SYMBOL(module_layout);
> -#endif
> diff --git a/kernel/module/version.c b/kernel/module/version.c
> new file mode 100644
> index 000000000000..adaedce1dc97
> --- /dev/null
> +++ b/kernel/module/version.c
> @@ -0,0 +1,109 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Module version support
> + *
> + * Copyright (C) 2008 Rusty Russell
> + */
> +
> +#include <linux/module.h>
> +#include <linux/string.h>
> +#include <linux/printk.h>
> +#include "internal.h"
> +
> +static u32 resolve_rel_crc(const s32 *crc)
> +{
> +	return *(u32 *)((void *)crc + *crc);
> +}
> +
> +int check_version(const struct load_info *info,
> +		  const char *symname,
> +			 struct module *mod,
> +			 const s32 *crc)
> +{
> +	Elf_Shdr *sechdrs = info->sechdrs;
> +	unsigned int versindex = info->index.vers;
> +	unsigned int i, num_versions;
> +	struct modversion_info *versions;
> +
> +	/* Exporting module didn't supply crcs?  OK, we're already tainted. */
> +	if (!crc)
> +		return 1;
> +
> +	/* No versions at all?  modprobe --force does this. */
> +	if (versindex == 0)
> +		return try_to_force_load(mod, symname) == 0;
> +
> +	versions = (void *)sechdrs[versindex].sh_addr;
> +	num_versions = sechdrs[versindex].sh_size
> +		/ sizeof(struct modversion_info);
> +
> +	for (i = 0; i < num_versions; i++) {
> +		u32 crcval;
> +
> +		if (strcmp(versions[i].name, symname) != 0)
> +			continue;
> +
> +		if (IS_ENABLED(CONFIG_MODULE_REL_CRCS))
> +			crcval = resolve_rel_crc(crc);
> +		else
> +			crcval = *crc;
> +		if (versions[i].crc == crcval)
> +			return 1;
> +		pr_debug("Found checksum %X vs module %lX\n",
> +			 crcval, versions[i].crc);
> +		goto bad_version;
> +	}
> +
> +	/* Broken toolchain. Warn once, then let it go.. */
> +	pr_warn_once("%s: no symbol version for %s\n", info->name, symname);
> +	return 1;
> +
> +bad_version:
> +	pr_warn("%s: disagrees about version of symbol %s\n", info->name, symname);
> +	return 0;
> +}
> +
> +int check_modstruct_version(const struct load_info *info,
> +			    struct module *mod)
> +{
> +	struct find_symbol_arg fsa = {
> +		.name	= "module_layout",
> +		.gplok	= true,
> +	};
> +
> +	/*
> +	 * Since this should be found in kernel (which can't be removed), no
> +	 * locking is necessary -- use preempt_disable() to placate lockdep.
> +	 */
> +	preempt_disable();
> +	if (!find_symbol(&fsa)) {
> +		preempt_enable();
> +		BUG();
> +	}
> +	preempt_enable();
> +	return check_version(info, "module_layout", mod, fsa.crc);
> +}
> +
> +/* First part is kernel version, which we ignore if module has crcs. */
> +int same_magic(const char *amagic, const char *bmagic,
> +	       bool has_crcs)
> +{
> +	if (has_crcs) {
> +		amagic += strcspn(amagic, " ");
> +		bmagic += strcspn(bmagic, " ");
> +	}
> +	return strcmp(amagic, bmagic) == 0;
> +}
> +
> +/*
> + * Generate the signature for all relevant module structures here.
> + * If these change, we don't want to try to parse the module.
> + */
> +void module_layout(struct module *mod,
> +		   struct modversion_info *ver,
> +		   struct kernel_param *kp,
> +		   struct kernel_symbol *ks,
> +		   struct tracepoint * const *tp)
> +{
> +}
> +EXPORT_SYMBOL(module_layout);

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

* Re: [PATCH v8 01/13] module: Move all into module/
  2022-02-22 14:12 ` [PATCH v8 01/13] module: Move all into module/ Aaron Tomlin
  2022-02-22 17:58   ` Christophe Leroy
@ 2022-02-22 20:00   ` Allen
  1 sibling, 0 replies; 43+ messages in thread
From: Allen @ 2022-02-22 20:00 UTC (permalink / raw)
  To: Aaron Tomlin
  Cc: Luis Chamberlain, christophe.leroy, Christoph Lameter,
	Petr Mladek, Miroslav Benes, Andrew Morton, jeyu,
	Linux Kernel Mailing List, linux-modules, void, atomlin,
	Joe Perches, msuchanek, oleksandr

 I did some testing on x86/ARM, no regressions.
Looks good so far. Will run it for little longer.

Thanks.

On Tue, Feb 22, 2022 at 6:13 AM Aaron Tomlin <atomlin@redhat.com> wrote:
>
> No functional changes.
>
> This patch moves all module related code into a separate directory,
> modifies each file name and creates a new Makefile. Note: this effort
> is in preparation to refactor core module code.
>
> Signed-off-by: Aaron Tomlin <atomlin@redhat.com>
> ---
>  MAINTAINERS                                         |  2 +-
>  kernel/Makefile                                     |  5 +----
>  kernel/module/Makefile                              | 12 ++++++++++++
>  kernel/{module_decompress.c => module/decompress.c} |  2 +-
>  kernel/{module-internal.h => module/internal.h}     |  0
>  kernel/{module.c => module/main.c}                  |  2 +-
>  kernel/{module_signing.c => module/signing.c}       |  2 +-
>  7 files changed, 17 insertions(+), 8 deletions(-)
>  create mode 100644 kernel/module/Makefile
>  rename kernel/{module_decompress.c => module/decompress.c} (99%)
>  rename kernel/{module-internal.h => module/internal.h} (100%)
>  rename kernel/{module.c => module/main.c} (99%)
>  rename kernel/{module_signing.c => module/signing.c} (97%)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index bd86ed9fbc79..463bdb829db4 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -13012,7 +13012,7 @@ L:      linux-kernel@vger.kernel.org
>  S:     Maintained
>  T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mcgrof/linux.git modules-next
>  F:     include/linux/module.h
> -F:     kernel/module.c
> +F:     kernel/module/
>
>  MONOLITHIC POWER SYSTEM PMIC DRIVER
>  M:     Saravanan Sekar <sravanhome@gmail.com>
> diff --git a/kernel/Makefile b/kernel/Makefile
> index 56f4ee97f328..717075b65deb 100644
> --- a/kernel/Makefile
> +++ b/kernel/Makefile
> @@ -29,7 +29,6 @@ KCOV_INSTRUMENT_softirq.o := n
>  KCSAN_SANITIZE_softirq.o = n
>  # These are called from save_stack_trace() on slub debug path,
>  # and produce insane amounts of uninteresting coverage.
> -KCOV_INSTRUMENT_module.o := n
>  KCOV_INSTRUMENT_extable.o := n
>  KCOV_INSTRUMENT_stacktrace.o := n
>  # Don't self-instrument.
> @@ -53,6 +52,7 @@ obj-y += rcu/
>  obj-y += livepatch/
>  obj-y += dma/
>  obj-y += entry/
> +obj-$(CONFIG_MODULES) += module/
>
>  obj-$(CONFIG_KCMP) += kcmp.o
>  obj-$(CONFIG_FREEZER) += freezer.o
> @@ -66,9 +66,6 @@ ifneq ($(CONFIG_SMP),y)
>  obj-y += up.o
>  endif
>  obj-$(CONFIG_UID16) += uid16.o
> -obj-$(CONFIG_MODULES) += module.o
> -obj-$(CONFIG_MODULE_DECOMPRESS) += module_decompress.o
> -obj-$(CONFIG_MODULE_SIG) += module_signing.o
>  obj-$(CONFIG_MODULE_SIG_FORMAT) += module_signature.o
>  obj-$(CONFIG_KALLSYMS) += kallsyms.o
>  obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
> diff --git a/kernel/module/Makefile b/kernel/module/Makefile
> new file mode 100644
> index 000000000000..cdd5c61b8c7f
> --- /dev/null
> +++ b/kernel/module/Makefile
> @@ -0,0 +1,12 @@
> +# SPDX-License-Identifier: GPL-2.0-only
> +#
> +# Makefile for linux kernel module support
> +#
> +
> +# These are called from save_stack_trace() on slub debug path,
> +# and produce insane amounts of uninteresting coverage.
> +KCOV_INSTRUMENT_module.o := n
> +
> +obj-y += main.o
> +obj-$(CONFIG_MODULE_DECOMPRESS) += decompress.o
> +obj-$(CONFIG_MODULE_SIG) += signing.o
> diff --git a/kernel/module_decompress.c b/kernel/module/decompress.c
> similarity index 99%
> rename from kernel/module_decompress.c
> rename to kernel/module/decompress.c
> index ffef98a20320..d14d6443225a 100644
> --- a/kernel/module_decompress.c
> +++ b/kernel/module/decompress.c
> @@ -12,7 +12,7 @@
>  #include <linux/sysfs.h>
>  #include <linux/vmalloc.h>
>
> -#include "module-internal.h"
> +#include "internal.h"
>
>  static int module_extend_max_pages(struct load_info *info, unsigned int extent)
>  {
> diff --git a/kernel/module-internal.h b/kernel/module/internal.h
> similarity index 100%
> rename from kernel/module-internal.h
> rename to kernel/module/internal.h
> diff --git a/kernel/module.c b/kernel/module/main.c
> similarity index 99%
> rename from kernel/module.c
> rename to kernel/module/main.c
> index 46a5c2ed1928..34a2b0cf3c3e 100644
> --- a/kernel/module.c
> +++ b/kernel/module/main.c
> @@ -58,7 +58,7 @@
>  #include <linux/dynamic_debug.h>
>  #include <linux/audit.h>
>  #include <uapi/linux/module.h>
> -#include "module-internal.h"
> +#include "internal.h"
>
>  #define CREATE_TRACE_POINTS
>  #include <trace/events/module.h>
> diff --git a/kernel/module_signing.c b/kernel/module/signing.c
> similarity index 97%
> rename from kernel/module_signing.c
> rename to kernel/module/signing.c
> index 8723ae70ea1f..8aeb6d2ee94b 100644
> --- a/kernel/module_signing.c
> +++ b/kernel/module/signing.c
> @@ -12,7 +12,7 @@
>  #include <linux/string.h>
>  #include <linux/verification.h>
>  #include <crypto/public_key.h>
> -#include "module-internal.h"
> +#include "internal.h"
>
>  /*
>   * Verify the signature on a module.
> --
> 2.34.1
>


-- 
       - Allen

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

* Re: [PATCH v8 09/13] module: Move kallsyms support into a separate file
  2022-02-22 14:12 ` [PATCH v8 09/13] module: Move kallsyms support into " Aaron Tomlin
  2022-02-22 17:59   ` Christophe Leroy
@ 2022-02-25  9:15   ` Petr Mladek
  2022-02-25  9:27     ` Christophe Leroy
  1 sibling, 1 reply; 43+ messages in thread
From: Petr Mladek @ 2022-02-25  9:15 UTC (permalink / raw)
  To: Aaron Tomlin
  Cc: mcgrof, christophe.leroy, cl, mbenes, akpm, jeyu, linux-kernel,
	linux-modules, void, atomlin, allen.lkml, joe, msuchanek,
	oleksandr

On Tue 2022-02-22 14:12:59, Aaron Tomlin wrote:
> No functional change.

The patch adds rcu_dereference_sched() into several locations.
It triggers lockdep warnings, see below.

It is good example why avoid any hidden changes when shuffling
code. The changes in the code should be done in a preparatory
patch or not at all.

This patch is even worse because these changes were not
mentioned in the commit message. It should describe what
is done and why.

I wonder how many other changes are hidden in this patchset
and if anyone really checked them.

> This patch migrates kallsyms code out of core module
> code kernel/module/kallsyms.c

> diff --git a/kernel/module/kallsyms.c b/kernel/module/kallsyms.c
> new file mode 100644
> index 000000000000..b6d49bb5afed
> --- /dev/null
> +++ b/kernel/module/kallsyms.c
[...]
> +/*
> + * We use the full symtab and strtab which layout_symtab arranged to
> + * be appended to the init section.  Later we switch to the cut-down
> + * core-only ones.
> + */
> +void add_kallsyms(struct module *mod, const struct load_info *info)
> +{
> +	unsigned int i, ndst;
> +	const Elf_Sym *src;
> +	Elf_Sym *dst;
> +	char *s;
> +	Elf_Shdr *symsec = &info->sechdrs[info->index.sym];
> +
> +	/* Set up to point into init section. */
> +	mod->kallsyms = (void __rcu *)mod->init_layout.base +
> +		info->mod_kallsyms_init_off;
> +
> +	/* The following is safe since this pointer cannot change */
> +	rcu_dereference_sched(mod->kallsyms)->symtab = (void *)symsec->sh_addr;

I have got the following warning in livepatch self-test:

[  372.740779] ===== TEST: basic function patching =====
[  372.760921] % modprobe test_klp_livepatch
[  372.766361] test_klp_livepatch: tainting kernel with TAINT_LIVEPATCH
[  372.767319] test_klp_livepatch: module verification failed: signature and/or required key missing - tainting kernel

[  372.769132] =============================
[  372.769771] WARNING: suspicious RCU usage
[  372.770392] 5.17.0-rc5-default+ #335 Tainted: G            E K  
[  372.770396] -----------------------------
[  372.770397] kernel/module/kallsyms.c:178 suspicious rcu_dereference_check() usage!
[  372.770400] 
               other info that might help us debug this:

[  372.770401] 
               rcu_scheduler_active = 2, debug_locks = 1
[  372.770403] no locks held by modprobe/1760.
[  372.770405] 
               stack backtrace:
[  372.770409] CPU: 3 PID: 1760 Comm: modprobe Tainted: G            E K   5.17.0-rc5-default+ #335
[  372.770412] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.12.0-59-gc9ba527-rebuilt.opensuse.org 04/01/2014
[  372.770413] Call Trace:
[  372.770415]  <TASK>
[  372.770417]  dump_stack_lvl+0x58/0x71
[  372.770424]  add_kallsyms+0x477/0x5c0
[  372.770434]  load_module+0x107c/0x19c0
[  372.770446]  ? kernel_read_file+0x2a3/0x2d0
[  372.782403]  ? __do_sys_finit_module+0xaf/0x120
[  372.783019]  __do_sys_finit_module+0xaf/0x120
[  372.783038]  do_syscall_64+0x37/0x80
[  372.783042]  entry_SYSCALL_64_after_hwframe+0x44/0xae
[  372.783045] RIP: 0033:0x7f13f53992a9
[  372.783048] Code: 00 f3 c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d bf 0b 2c 00 f7 d8 64 89 01 48
[  372.783050] RSP: 002b:00007ffca746bf08 EFLAGS: 00000246 ORIG_RAX: 0000000000000139
[  372.783052] RAX: ffffffffffffffda RBX: 000055bc9b8b8880 RCX: 00007f13f53992a9
[  372.783054] RDX: 0000000000000000 RSI: 000055bc99c31688 RDI: 0000000000000005
[  372.783055] RBP: 000055bc99c31688 R08: 0000000000000000 R09: 000055bc9b8b8410
[  372.783056] R10: 0000000000000005 R11: 0000000000000246 R12: 0000000000040000
[  372.783057] R13: 000055bc9b8b87a0 R14: 0000000000000000 R15: 000055bc9b8b8880
[  372.783070]  </TASK>


> +	rcu_dereference_sched(mod->kallsyms)->num_symtab = symsec->sh_size / sizeof(Elf_Sym);

[  372.793150] =============================
[  372.793151] WARNING: suspicious RCU usage
[  372.793153] 5.17.0-rc5-default+ #335 Tainted: G            E K  
[  372.793155] -----------------------------
[  372.793156] kernel/module/kallsyms.c:179 suspicious rcu_dereference_check() usage!
[  372.793158] 
               other info that might help us debug this:

[  372.797266] 
               rcu_scheduler_active = 2, debug_locks = 1
[  372.797268] no locks held by modprobe/1760.
[  372.797270] 
               stack backtrace:
[  372.797271] CPU: 3 PID: 1760 Comm: modprobe Tainted: G            E K   5.17.0-rc5-default+ #335
[  372.797274] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.12.0-59-gc9ba527-rebuilt.opensuse.org 04/01/2014
[  372.797275] Call Trace:
[  372.797277]  <TASK>
[  372.797278]  dump_stack_lvl+0x58/0x71
[  372.802579]  add_kallsyms+0x56f/0x5c0
[  372.802605]  load_module+0x107c/0x19c0
[  372.803525]  ? kernel_read_file+0x2a3/0x2d0
[  372.803538]  ? __do_sys_finit_module+0xaf/0x120
[  372.803540]  __do_sys_finit_module+0xaf/0x120
[  372.803555]  do_syscall_64+0x37/0x80
[  372.803558]  entry_SYSCALL_64_after_hwframe+0x44/0xae
[  372.803561] RIP: 0033:0x7f13f53992a9
[  372.803563] Code: 00 f3 c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d bf 0b 2c 00 f7 d8 64 89 01 48
[  372.803565] RSP: 002b:00007ffca746bf08 EFLAGS: 00000246 ORIG_RAX: 0000000000000139
[  372.803567] RAX: ffffffffffffffda RBX: 000055bc9b8b8880 RCX: 00007f13f53992a9
[  372.803568] RDX: 0000000000000000 RSI: 000055bc99c31688 RDI: 0000000000000005
[  372.811447] RBP: 000055bc99c31688 R08: 0000000000000000 R09: 000055bc9b8b8410
[  372.811465] R10: 0000000000000005 R11: 0000000000000246 R12: 0000000000040000
[  372.811467] R13: 000055bc9b8b87a0 R14: 0000000000000000 R15: 000055bc9b8b8880
[  372.811479]  </TASK>


> +	/* Make sure we get permanent strtab: don't use info->strtab. */
> +	rcu_dereference_sched(mod->kallsyms)->strtab =
> +		(void *)info->sechdrs[info->index.str].sh_addr;

[  372.814541] =============================
[  372.815091] WARNING: suspicious RCU usage
[  372.815093] 5.17.0-rc5-default+ #335 Tainted: G            E K  
[  372.815094] -----------------------------
[  372.815095] kernel/module/kallsyms.c:181 suspicious rcu_dereference_check() usage!
[  372.815096] 
               other info that might help us debug this:

[  372.815097] 
               rcu_scheduler_active = 2, debug_locks = 1
[  372.815099] no locks held by modprobe/1760.
[  372.815100] 
               stack backtrace:
[  372.815101] CPU: 3 PID: 1760 Comm: modprobe Tainted: G            E K   5.17.0-rc5-default+ #335
[  372.815102] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.12.0-59-gc9ba527-rebuilt.opensuse.org 04/01/2014
[  372.815103] Call Trace:
[  372.815105]  <TASK>
[  372.815106]  dump_stack_lvl+0x58/0x71
[  372.815111]  add_kallsyms+0x531/0x5c0
[  372.815119]  load_module+0x107c/0x19c0
[  372.815129]  ? kernel_read_file+0x2a3/0x2d0
[  372.815140]  ? __do_sys_finit_module+0xaf/0x120
[  372.815143]  __do_sys_finit_module+0xaf/0x120
[  372.815157]  do_syscall_64+0x37/0x80
[  372.815160]  entry_SYSCALL_64_after_hwframe+0x44/0xae
[  372.828879] RIP: 0033:0x7f13f53992a9
[  372.828885] Code: 00 f3 c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d bf 0b 2c 00 f7 d8 64 89 01 48
[  372.828889] RSP: 002b:00007ffca746bf08 EFLAGS: 00000246 ORIG_RAX: 0000000000000139
[  372.828892] RAX: ffffffffffffffda RBX: 000055bc9b8b8880 RCX: 00007f13f53992a9
[  372.828893] RDX: 0000000000000000 RSI: 000055bc99c31688 RDI: 0000000000000005
[  372.828894] RBP: 000055bc99c31688 R08: 0000000000000000 R09: 000055bc9b8b8410
[  372.828895] R10: 0000000000000005 R11: 0000000000000246 R12: 0000000000040000
[  372.836097] R13: 000055bc9b8b87a0 R14: 0000000000000000 R15: 000055bc9b8b8880
[  372.836115]  </TASK>


> +	rcu_dereference_sched(mod->kallsyms)->typetab =
> +		mod->init_layout.base + info->init_typeoffs;

[  372.837224] =============================
[  372.837224] WARNING: suspicious RCU usage
[  372.837225] 5.17.0-rc5-default+ #335 Tainted: G            E K  
[  372.837227] -----------------------------
[  372.837227] kernel/module/kallsyms.c:183 suspicious rcu_dereference_check() usage!
[  372.837229] 
               other info that might help us debug this:

[  372.837230] 
               rcu_scheduler_active = 2, debug_locks = 1
[  372.837231] no locks held by modprobe/1760.
[  372.837232] 
               stack backtrace:
[  372.837233] CPU: 3 PID: 1760 Comm: modprobe Tainted: G            E K   5.17.0-rc5-default+ #335
[  372.837235] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.12.0-59-gc9ba527-rebuilt.opensuse.org 04/01/2014
[  372.837236] Call Trace:
[  372.837237]  <TASK>
[  372.837239]  dump_stack_lvl+0x58/0x71
[  372.837243]  add_kallsyms+0x4f3/0x5c0
[  372.837251]  load_module+0x107c/0x19c0
[  372.849013]  ? kernel_read_file+0x2a3/0x2d0
[  372.849026]  ? __do_sys_finit_module+0xaf/0x120
[  372.849930]  __do_sys_finit_module+0xaf/0x120
[  372.849946]  do_syscall_64+0x37/0x80
[  372.850772]  entry_SYSCALL_64_after_hwframe+0x44/0xae
[  372.850775] RIP: 0033:0x7f13f53992a9
[  372.850778] Code: 00 f3 c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d bf 0b 2c 00 f7 d8 64 89 01 48
[  372.850780] RSP: 002b:00007ffca746bf08 EFLAGS: 00000246 ORIG_RAX: 0000000000000139
[  372.854028] RAX: ffffffffffffffda RBX: 000055bc9b8b8880 RCX: 00007f13f53992a9
[  372.854030] RDX: 0000000000000000 RSI: 000055bc99c31688 RDI: 0000000000000005
[  372.854031] RBP: 000055bc99c31688 R08: 0000000000000000 R09: 000055bc9b8b8410
[  372.854033] R10: 0000000000000005 R11: 0000000000000246 R12: 0000000000040000
[  372.854034] R13: 000055bc9b8b87a0 R14: 0000000000000000 R15: 000055bc9b8b8880
[  372.854048]  </TASK>

> +
> +	/*
> +	 * Now populate the cut down core kallsyms for after init
> +	 * and set types up while we still have access to sections.
> +	 */
> +	mod->core_kallsyms.symtab = dst = mod->core_layout.base + info->symoffs;
> +	mod->core_kallsyms.strtab = s = mod->core_layout.base + info->stroffs;
> +	mod->core_kallsyms.typetab = mod->core_layout.base + info->core_typeoffs;
> +	src = rcu_dereference_sched(mod->kallsyms)->symtab;

[  372.854081] =============================
[  372.854083] WARNING: suspicious RCU usage
[  372.854084] 5.17.0-rc5-default+ #335 Tainted: G            E K  
[  372.854087] -----------------------------
[  372.854089] kernel/module/kallsyms.c:193 suspicious rcu_dereference_check() usage!
[  372.854091] 
               other info that might help us debug this:

[  372.854093] 
               rcu_scheduler_active = 2, debug_locks = 1
[  372.854095] no locks held by modprobe/1760.
[  372.854097] 
               stack backtrace:
[  372.854099] CPU: 3 PID: 1760 Comm: modprobe Tainted: G            E K   5.17.0-rc5-default+ #335
[  372.854102] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.12.0-59-gc9ba527-rebuilt.opensuse.org 04/01/2014
[  372.854104] Call Trace:
[  372.854106]  <TASK>
[  372.854109]  dump_stack_lvl+0x58/0x71
[  372.854126]  add_kallsyms+0x4b5/0x5c0
[  372.854139]  load_module+0x107c/0x19c0
[  372.866967]  ? kernel_read_file+0x2a3/0x2d0
[  372.866980]  ? __do_sys_finit_module+0xaf/0x120
[  372.867921]  __do_sys_finit_module+0xaf/0x120
[  372.867937]  do_syscall_64+0x37/0x80
[  372.868823]  entry_SYSCALL_64_after_hwframe+0x44/0xae
[  372.868826] RIP: 0033:0x7f13f53992a9
[  372.868828] Code: 00 f3 c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d bf 0b 2c 00 f7 d8 64 89 01 48
[  372.868830] RSP: 002b:00007ffca746bf08 EFLAGS: 00000246 ORIG_RAX: 0000000000000139
[  372.871419] RAX: ffffffffffffffda RBX: 000055bc9b8b8880 RCX: 00007f13f53992a9
[  372.871420] RDX: 0000000000000000 RSI: 000055bc99c31688 RDI: 0000000000000005
[  372.871422] RBP: 000055bc99c31688 R08: 0000000000000000 R09: 000055bc9b8b8410
[  372.871423] R10: 0000000000000005 R11: 0000000000000246 R12: 0000000000040000
[  372.871424] R13: 000055bc9b8b87a0 R14: 0000000000000000 R15: 000055bc9b8b8880
[  372.871438]  </TASK>

> +	for (ndst = i = 0; i < rcu_dereference_sched(mod->kallsyms)->num_symtab; i++) {

[  372.871464] =============================
[  372.871466] WARNING: suspicious RCU usage
[  372.871467] 5.17.0-rc5-default+ #335 Tainted: G            E K  
[  372.871470] -----------------------------
[  372.871471] kernel/module/kallsyms.c:194 suspicious rcu_dereference_check() usage!
[  372.878748] 
               other info that might help us debug this:

[  372.878749] 
               rcu_scheduler_active = 2, debug_locks = 1
[  372.878751] no locks held by modprobe/1760.
[  372.878752] 
               stack backtrace:
[  372.878753] CPU: 3 PID: 1760 Comm: modprobe Tainted: G            E K   5.17.0-rc5-default+ #335
[  372.878756] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.12.0-59-gc9ba527-rebuilt.opensuse.org 04/01/2014
[  372.878757] Call Trace:
[  372.878758]  <TASK>
[  372.878760]  dump_stack_lvl+0x58/0x71
[  372.878765]  add_kallsyms+0x296/0x5c0
[  372.878774]  load_module+0x107c/0x19c0
[  372.878785]  ? kernel_read_file+0x2a3/0x2d0
[  372.878797]  ? __do_sys_finit_module+0xaf/0x120
[  372.878800]  __do_sys_finit_module+0xaf/0x120
[  372.878815]  do_syscall_64+0x37/0x80
[  372.886420]  entry_SYSCALL_64_after_hwframe+0x44/0xae
[  372.886423] RIP: 0033:0x7f13f53992a9
[  372.886425] Code: 00 f3 c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d bf 0b 2c 00 f7 d8 64 89 01 48
[  372.886427] RSP: 002b:00007ffca746bf08 EFLAGS: 00000246 ORIG_RAX: 0000000000000139
[  372.886429] RAX: ffffffffffffffda RBX: 000055bc9b8b8880 RCX: 00007f13f53992a9
[  372.886431] RDX: 0000000000000000 RSI: 000055bc99c31688 RDI: 0000000000000005
[  372.886432] RBP: 000055bc99c31688 R08: 0000000000000000 R09: 000055bc9b8b8410
[  372.886433] R10: 0000000000000005 R11: 0000000000000246 R12: 0000000000040000
[  372.886435] R13: 000055bc9b8b87a0 R14: 0000000000000000 R15: 000055bc9b8b8880
[  372.886448]  </TASK>

> +		rcu_dereference_sched(mod->kallsyms)->typetab[i] = elf_type(src + i, info);

[  372.886474] =============================
[  372.886476] WARNING: suspicious RCU usage
[  372.886477] 5.17.0-rc5-default+ #335 Tainted: G            E K  
[  372.886480] -----------------------------
[  372.886481] kernel/module/kallsyms.c:195 suspicious rcu_dereference_check() usage!
[  372.886484] 
               other info that might help us debug this:

[  372.886485] 
               rcu_scheduler_active = 2, debug_locks = 1
[  372.886487] no locks held by modprobe/1760.
[  372.886489] 
               stack backtrace:
[  372.886491] CPU: 3 PID: 1760 Comm: modprobe Tainted: G            E K   5.17.0-rc5-default+ #335
[  372.886494] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.12.0-59-gc9ba527-rebuilt.opensuse.org 04/01/2014
[  372.900968] Call Trace:
[  372.900970]  <TASK>
[  372.900972]  dump_stack_lvl+0x58/0x71
[  372.900977]  add_kallsyms+0x3c1/0x5c0
[  372.900986]  load_module+0x107c/0x19c0
[  372.900997]  ? kernel_read_file+0x2a3/0x2d0
[  372.901009]  ? __do_sys_finit_module+0xaf/0x120
[  372.901012]  __do_sys_finit_module+0xaf/0x120
[  372.901027]  do_syscall_64+0x37/0x80
[  372.904379]  entry_SYSCALL_64_after_hwframe+0x44/0xae
[  372.904382] RIP: 0033:0x7f13f53992a9
[  372.904384] Code: 00 f3 c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d bf 0b 2c 00 f7 d8 64 89 01 48
[  372.904386] RSP: 002b:00007ffca746bf08 EFLAGS: 00000246 ORIG_RAX: 0000000000000139
[  372.904389] RAX: ffffffffffffffda RBX: 000055bc9b8b8880 RCX: 00007f13f53992a9
[  372.904390] RDX: 0000000000000000 RSI: 000055bc99c31688 RDI: 0000000000000005
[  372.904391] RBP: 000055bc99c31688 R08: 0000000000000000 R09: 000055bc9b8b8410
[  372.904392] R10: 0000000000000005 R11: 0000000000000246 R12: 0000000000040000
[  372.904394] R13: 000055bc9b8b87a0 R14: 0000000000000000 R15: 000055bc9b8b8880
[  372.904407]  </TASK>

> +		if (i == 0 || is_livepatch_module(mod) ||
> +		    is_core_symbol(src + i, info->sechdrs, info->hdr->e_shnum,
> +				   info->index.pcpu)) {
> +			mod->core_kallsyms.typetab[ndst] =
> +			    rcu_dereference_sched(mod->kallsyms)->typetab[i];

[  372.904436] =============================
[  372.904438] WARNING: suspicious RCU usage
[  372.904440] 5.17.0-rc5-default+ #335 Tainted: G            E K  
[  372.904442] -----------------------------
[  372.904444] kernel/module/kallsyms.c:200 suspicious rcu_dereference_check() usage!
[  372.904446] 
               other info that might help us debug this:

[  372.904448] 
               rcu_scheduler_active = 2, debug_locks = 1
[  372.904450] no locks held by modprobe/1760.
[  372.904452] 
               stack backtrace:
[  372.904454] CPU: 3 PID: 1760 Comm: modprobe Tainted: G            E K   5.17.0-rc5-default+ #335
[  372.904457] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.12.0-59-gc9ba527-rebuilt.opensuse.org 04/01/2014
[  372.904459] Call Trace:
[  372.904461]  <TASK>
[  372.904464]  dump_stack_lvl+0x58/0x71
[  372.904470]  add_kallsyms+0x439/0x5c0
[  372.904485]  load_module+0x107c/0x19c0
[  372.904504]  ? kernel_read_file+0x2a3/0x2d0
[  372.921165]  ? __do_sys_finit_module+0xaf/0x120
[  372.921171]  __do_sys_finit_module+0xaf/0x120
[  372.921187]  do_syscall_64+0x37/0x80
[  372.922455]  entry_SYSCALL_64_after_hwframe+0x44/0xae
[  372.922458] RIP: 0033:0x7f13f53992a9
[  372.922461] Code: 00 f3 c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d bf 0b 2c 00 f7 d8 64 89 01 48
[  372.922463] RSP: 002b:00007ffca746bf08 EFLAGS: 00000246 ORIG_RAX: 0000000000000139
[  372.922466] RAX: ffffffffffffffda RBX: 000055bc9b8b8880 RCX: 00007f13f53992a9
[  372.922467] RDX: 0000000000000000 RSI: 000055bc99c31688 RDI: 0000000000000005
[  372.922469] RBP: 000055bc99c31688 R08: 0000000000000000 R09: 000055bc9b8b8410
[  372.922470] R10: 0000000000000005 R11: 0000000000000246 R12: 0000000000040000
[  372.922472] R13: 000055bc9b8b87a0 R14: 0000000000000000 R15: 000055bc9b8b8880
[  372.922485]  </TASK>

> +			dst[ndst] = src[i];
> +			dst[ndst++].st_name = s - mod->core_kallsyms.strtab;
> +			s += strscpy(s,
> +				     &rcu_dereference_sched(mod->kallsyms)->strtab[src[i].st_name],

[  372.929324] =============================
[  372.929325] WARNING: suspicious RCU usage
[  372.929327] 5.17.0-rc5-default+ #335 Tainted: G            E K  
[  372.929330] -----------------------------
[  372.929331] kernel/module/kallsyms.c:204 suspicious rcu_dereference_check() usage!
[  372.929334] 
               other info that might help us debug this:

[  372.929335] 
               rcu_scheduler_active = 2, debug_locks = 1
[  372.929338] no locks held by modprobe/1760.
[  372.929340] 
               stack backtrace:
[  372.929342] CPU: 3 PID: 1760 Comm: modprobe Tainted: G            E K   5.17.0-rc5-default+ #335
[  372.929345] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.12.0-59-gc9ba527-rebuilt.opensuse.org 04/01/2014
[  372.929347] Call Trace:
[  372.929349]  <TASK>
[  372.929352]  dump_stack_lvl+0x58/0x71
[  372.929360]  add_kallsyms+0x3fb/0x5c0
[  372.929374]  load_module+0x107c/0x19c0
[  372.929392]  ? kernel_read_file+0x2a3/0x2d0
[  372.939163]  ? __do_sys_finit_module+0xaf/0x120
[  372.939167]  __do_sys_finit_module+0xaf/0x120
[  372.939182]  do_syscall_64+0x37/0x80
[  372.939186]  entry_SYSCALL_64_after_hwframe+0x44/0xae
[  372.939188] RIP: 0033:0x7f13f53992a9
[  372.939190] Code: 00 f3 c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d bf 0b 2c 00 f7 d8 64 89 01 48
[  372.939192] RSP: 002b:00007ffca746bf08 EFLAGS: 00000246 ORIG_RAX: 0000000000000139
[  372.939195] RAX: ffffffffffffffda RBX: 000055bc9b8b8880 RCX: 00007f13f53992a9
[  372.939196] RDX: 0000000000000000 RSI: 000055bc99c31688 RDI: 0000000000000005
[  372.939197] RBP: 000055bc99c31688 R08: 0000000000000000 R09: 000055bc9b8b8410
[  372.939199] R10: 0000000000000005 R11: 0000000000000246 R12: 0000000000040000
[  372.939200] R13: 000055bc9b8b87a0 R14: 0000000000000000 R15: 000055bc9b8b8880
[  372.939213]  </TASK>

> +				     KSYM_NAME_LEN) + 1;
> +		}
> +	}
> +	mod->core_kallsyms.num_symtab = ndst;
> +}

[...]

> +#ifdef CONFIG_LIVEPATCH
> +int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *,
> +					     struct module *, unsigned long),
> +				   void *data)
> +{
> +	struct module *mod;
> +	unsigned int i;
> +	int ret = 0;
> +
> +	mutex_lock(&module_mutex);
> +	list_for_each_entry(mod, &modules, list) {
> +		/* Still use rcu_dereference_sched to remain compliant with sparse */
> +		struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms);

I got the following warning when running livepatch selftest:

[  403.430393] ===== TEST: multiple target modules =====
[  403.452359] % modprobe test_klp_callbacks_busy block_transition=N
[  403.458735] test_klp_callbacks_busy: test_klp_callbacks_busy_init
[  403.459544] test_klp_callbacks_busy: busymod_work_func enter
[  403.460274] test_klp_callbacks_busy: busymod_work_func exit
[  403.476999] % modprobe test_klp_callbacks_demo

[  403.483742] =============================
[  403.484446] WARNING: suspicious RCU usage
[  403.485158] 5.17.0-rc5-default+ #335 Tainted: G            E K  
[  403.486490] -----------------------------
[  403.486496] kernel/module/kallsyms.c:486 suspicious rcu_dereference_check() usage!
[  403.486499] 
               other info that might help us debug this:

[  403.486500] 
               rcu_scheduler_active = 2, debug_locks = 1
[  403.486502] 2 locks held by modprobe/2479:
[  403.486504]  #0: ffffffff94c4f770 (klp_mutex){+.+.}-{3:3}, at: klp_enable_patch.part.12+0x24/0x910
[  403.486517]  #1: ffffffff94c50a50 (module_mutex){+.+.}-{3:3}, at: module_kallsyms_on_each_symbol+0x27/0x110
[  403.486527] 
               stack backtrace:
[  403.486529] CPU: 3 PID: 2479 Comm: modprobe Tainted: G            E K   5.17.0-rc5-default+ #335
[  403.486532] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.12.0-59-gc9ba527-rebuilt.opensuse.org 04/01/2014
[  403.486535] Call Trace:
[  403.486536]  <TASK>
[  403.486539]  dump_stack_lvl+0x58/0x71
[  403.486546]  module_kallsyms_on_each_symbol+0x101/0x110
[  403.486549]  ? kobject_add_internal+0x1ca/0x2c0
[  403.501245]  klp_find_object_symbol+0x5f/0x110
[  403.501255]  klp_init_object_loaded+0xca/0x140
[  403.501261]  klp_enable_patch.part.12+0x5b6/0x910
[  403.501266]  ? pre_patch_callback+0x20/0x20 [test_klp_callbacks_demo]
[  403.501271]  ? pre_patch_callback+0x20/0x20 [test_klp_callbacks_demo]
[  403.501276]  do_one_initcall+0x58/0x300
[  403.501286]  do_init_module+0x4b/0x1f1
[  403.501291]  load_module+0x1862/0x19c0
[  403.506243]  ? __do_sys_finit_module+0xaf/0x120
[  403.506247]  __do_sys_finit_module+0xaf/0x120
[  403.506261]  do_syscall_64+0x37/0x80
[  403.506264]  entry_SYSCALL_64_after_hwframe+0x44/0xae
[  403.506267] RIP: 0033:0x7f8e5f5f12a9
[  403.506270] Code: 00 f3 c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d bf 0b 2c 00 f7 d8 64 89 01 48
[  403.510723] RSP: 002b:00007ffc725cfe48 EFLAGS: 00000246 ORIG_RAX: 0000000000000139
[  403.510727] RAX: ffffffffffffffda RBX: 000055ddd32938d0 RCX: 00007f8e5f5f12a9
[  403.510729] RDX: 0000000000000000 RSI: 000055ddd2231688 RDI: 0000000000000005
[  403.510731] RBP: 000055ddd2231688 R08: 0000000000000000 R09: 000055ddd3293410
[  403.510733] R10: 0000000000000005 R11: 0000000000000246 R12: 0000000000040000
[  403.510734] R13: 000055ddd32937a0 R14: 0000000000000000 R15: 000055ddd32938d0
[  403.510750]  </TASK>

> +
> +		if (mod->state == MODULE_STATE_UNFORMED)
> +			continue;
> +		for (i = 0; i < kallsyms->num_symtab; i++) {
> +			const Elf_Sym *sym = &kallsyms->symtab[i];
> +
> +			if (sym->st_shndx == SHN_UNDEF)
> +				continue;
> +
> +			ret = fn(data, kallsyms_symbol_name(kallsyms, i),
> +				 mod, kallsyms_symbol_value(sym));
> +			if (ret != 0)
> +				goto out;
> +		}
> +	}
> +out:
> +	mutex_unlock(&module_mutex);
> +	return ret;
> +}

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

* Re: [PATCH v8 09/13] module: Move kallsyms support into a separate file
  2022-02-25  9:15   ` Petr Mladek
@ 2022-02-25  9:27     ` Christophe Leroy
  2022-02-25 10:15       ` Petr Mladek
  0 siblings, 1 reply; 43+ messages in thread
From: Christophe Leroy @ 2022-02-25  9:27 UTC (permalink / raw)
  To: Petr Mladek, Aaron Tomlin
  Cc: mcgrof, cl, mbenes, akpm, jeyu, linux-kernel, linux-modules,
	void, atomlin, allen.lkml, joe, msuchanek, oleksandr



Le 25/02/2022 à 10:15, Petr Mladek a écrit :
> On Tue 2022-02-22 14:12:59, Aaron Tomlin wrote:
>> No functional change.
> 
> The patch adds rcu_dereference_sched() into several locations.
> It triggers lockdep warnings, see below.
> 
> It is good example why avoid any hidden changes when shuffling
> code. The changes in the code should be done in a preparatory
> patch or not at all.
> 
> This patch is even worse because these changes were not
> mentioned in the commit message. It should describe what
> is done and why.
> 
> I wonder how many other changes are hidden in this patchset
> and if anyone really checked them.

That's probably my fault, when I reviewed version v5 of the series I 
mentionned all checkpatch and sparse reports asking Aaron to make his 
series exempt of such warnings. Most warnings where related to style 
(parenthesis alignment, blank lines, spaces, etc ...) or erroneous 
casting etc....

But for that particular patch we had:

kernel/module/kallsyms.c:174:23: warning: incorrect type in assignment 
(different address spaces)
kernel/module/kallsyms.c:174:23:    expected struct mod_kallsyms 
[noderef] __rcu *kallsyms
kernel/module/kallsyms.c:174:23:    got void *
kernel/module/kallsyms.c:176:12: warning: dereference of noderef expression
kernel/module/kallsyms.c:177:12: warning: dereference of noderef expression
kernel/module/kallsyms.c:179:12: warning: dereference of noderef expression
kernel/module/kallsyms.c:180:12: warning: dereference of noderef expression
kernel/module/kallsyms.c:189:18: warning: dereference of noderef expression
kernel/module/kallsyms.c:190:35: warning: dereference of noderef expression
kernel/module/kallsyms.c:191:20: warning: dereference of noderef expression
kernel/module/kallsyms.c:196:32: warning: dereference of noderef expression
kernel/module/kallsyms.c:199:45: warning: dereference of noderef expression

Aaron used rcu_dereference_sched() in order to fix that.

How should this be fixed if using rcu_dereference_sched() is not correct ?

Thanks
Christophe

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

* Re: [PATCH v8 04/13] module: Move livepatch support to a separate file
  2022-02-22 14:12 ` [PATCH v8 04/13] module: Move livepatch support to a separate file Aaron Tomlin
  2022-02-22 17:58   ` Christophe Leroy
@ 2022-02-25  9:34   ` Petr Mladek
  2022-02-25 10:33     ` Aaron Tomlin
  2022-02-25 16:49     ` Christophe Leroy
  1 sibling, 2 replies; 43+ messages in thread
From: Petr Mladek @ 2022-02-25  9:34 UTC (permalink / raw)
  To: Aaron Tomlin
  Cc: mcgrof, christophe.leroy, cl, mbenes, akpm, jeyu, linux-kernel,
	linux-modules, void, atomlin, allen.lkml, joe, msuchanek,
	oleksandr

On Tue 2022-02-22 14:12:54, Aaron Tomlin wrote:
> No functional change.
> 
> This patch migrates livepatch support (i.e. used during module
> add/or load and remove/or deletion) from core module code into
> kernel/module/livepatch.c. At the moment it contains code to
> persist Elf information about a given livepatch module, only.
> 
> Signed-off-by: Aaron Tomlin <atomlin@redhat.com>

> diff --git a/kernel/module/livepatch.c b/kernel/module/livepatch.c
> new file mode 100644
> index 000000000000..486d4ff92719
> --- /dev/null
> +++ b/kernel/module/livepatch.c
> @@ -0,0 +1,74 @@
> + * Persist Elf information about a module. Copy the Elf header,
> + * section header table, section string table, and symtab section
> + * index from info to mod->klp_info.
> + */
> +int copy_module_elf(struct module *mod, struct load_info *info)
> +{
> +	unsigned int size, symndx;
> +	int ret;
> +
> +	size = sizeof(*mod->klp_info);
> +	mod->klp_info = kmalloc(size, GFP_KERNEL);
> +	if (!mod->klp_info)
> +		return -ENOMEM;
> +
> +	/* Elf header */
> +	size = sizeof(mod->klp_info->hdr);
> +	memcpy(&mod->klp_info->hdr, info->hdr, size);
> +
> +	/* Elf section header table */
> +	size = sizeof(*info->sechdrs) * info->hdr->e_shnum;
> +	mod->klp_info->sechdrs = kmemdup(info->sechdrs, size, GFP_KERNEL);
> +	if (!mod->klp_info->sechdrs) {
> +		ret = -ENOMEM;
> +		goto free_info;
> +	}
> +
> +	/* Elf section name string table */
> +	size = info->sechdrs[info->hdr->e_shstrndx].sh_size;
> +	mod->klp_info->secstrings = kmemdup(info->secstrings, size, GFP_KERNEL);
> +	if (!mod->klp_info->secstrings) {
> +		ret = -ENOMEM;
> +		goto free_sechdrs;
> +	}
> +
> +	/* Elf symbol section index */
> +	symndx = info->index.sym;
> +	mod->klp_info->symndx = symndx;
> +
> +	/*
> +	 * For livepatch modules, core_kallsyms.symtab is a complete
> +	 * copy of the original symbol table. Adjust sh_addr to point
> +	 * to core_kallsyms.symtab since the copy of the symtab in module
> +	 * init memory is freed at the end of do_init_module().
> +	 */
> +	mod->klp_info->sechdrs[symndx].sh_addr = (unsigned long)mod->core_kallsyms.symtab;
> +
> +	return 0;

This code include several other well hidden changes:

--- del.p	2022-02-24 16:55:26.570054922 +0100
+++ add.p	2022-02-24 16:56:04.766781394 +0100
@@ -3,14 +3,14 @@
  * section header table, section string table, and symtab section
  * index from info to mod->klp_info.
  */
-static int copy_module_elf(struct module *mod, struct load_info *info)
+int copy_module_elf(struct module *mod, struct load_info *info)
 {
 	unsigned int size, symndx;
 	int ret;
 
 	size = sizeof(*mod->klp_info);
 	mod->klp_info = kmalloc(size, GFP_KERNEL);
-	if (mod->klp_info == NULL)
+	if (!mod->klp_info)
 		return -ENOMEM;
 
 	/* Elf header */
@@ -20,7 +20,7 @@ static int copy_module_elf(struct module
 	/* Elf section header table */
 	size = sizeof(*info->sechdrs) * info->hdr->e_shnum;
 	mod->klp_info->sechdrs = kmemdup(info->sechdrs, size, GFP_KERNEL);
-	if (mod->klp_info->sechdrs == NULL) {
+	if (!mod->klp_info->sechdrs) {
 		ret = -ENOMEM;
 		goto free_info;
 	}
@@ -28,7 +28,7 @@ static int copy_module_elf(struct module
 	/* Elf section name string table */
 	size = info->sechdrs[info->hdr->e_shstrndx].sh_size;
 	mod->klp_info->secstrings = kmemdup(info->secstrings, size, GFP_KERNEL);
-	if (mod->klp_info->secstrings == NULL) {
+	if (!mod->klp_info->secstrings) {
 		ret = -ENOMEM;
 		goto free_sechdrs;
 	}
@@ -43,8 +43,7 @@ static int copy_module_elf(struct module
 	 * to core_kallsyms.symtab since the copy of the symtab in module
 	 * init memory is freed at the end of do_init_module().
 	 */
-	mod->klp_info->sechdrs[symndx].sh_addr = \
-		(unsigned long) mod->core_kallsyms.symtab;
+	mod->klp_info->sechdrs[symndx].sh_addr = (unsigned long)mod->core_kallsyms.symtab;
 
 	return 0;


Please do not do these small coding style changes. It complicates the
review and increases the risk of regressions. Different people
have different preferences. Just imagine that every half a year
someone update style of a code by his personal preferences. The
real changes will then get lost in a lot of noise.

Coding style changes might be acceptable only when the code is
reworked or when it significantly improves readability.


That said. I reviewed and tested this patch and did not find any
problem. Feel free to use:

Reviewed-by: Petr Mladek <pmladek@suse.com>
Tested-by: Petr Mladek <pmladek@suse.com>

Please, take the above as an advice for your future work.

Best Regards,
Petr

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

* Re: [PATCH v8 09/13] module: Move kallsyms support into a separate file
  2022-02-25  9:27     ` Christophe Leroy
@ 2022-02-25 10:15       ` Petr Mladek
  2022-02-25 10:27         ` Aaron Tomlin
  0 siblings, 1 reply; 43+ messages in thread
From: Petr Mladek @ 2022-02-25 10:15 UTC (permalink / raw)
  To: Christophe Leroy
  Cc: Aaron Tomlin, mcgrof, cl, mbenes, akpm, jeyu, linux-kernel,
	linux-modules, void, atomlin, allen.lkml, joe, msuchanek,
	oleksandr

On Fri 2022-02-25 09:27:33, Christophe Leroy wrote:
> 
> 
> Le 25/02/2022 à 10:15, Petr Mladek a écrit :
> > On Tue 2022-02-22 14:12:59, Aaron Tomlin wrote:
> >> No functional change.
> > 
> > The patch adds rcu_dereference_sched() into several locations.
> > It triggers lockdep warnings, see below.
> > 
> > It is good example why avoid any hidden changes when shuffling
> > code. The changes in the code should be done in a preparatory
> > patch or not at all.
> > 
> > This patch is even worse because these changes were not
> > mentioned in the commit message. It should describe what
> > is done and why.
> > 
> > I wonder how many other changes are hidden in this patchset
> > and if anyone really checked them.
> 
> That's probably my fault, when I reviewed version v5 of the series I 
> mentionned all checkpatch and sparse reports asking Aaron to make his 
> series exempt of such warnings. Most warnings where related to style 
> (parenthesis alignment, blank lines, spaces, etc ...) or erroneous 
> casting etc....
> 
> But for that particular patch we had:
> 
> kernel/module/kallsyms.c:174:23: warning: incorrect type in assignment 
> (different address spaces)
> kernel/module/kallsyms.c:174:23:    expected struct mod_kallsyms 
> [noderef] __rcu *kallsyms
> kernel/module/kallsyms.c:174:23:    got void *
> kernel/module/kallsyms.c:176:12: warning: dereference of noderef expression
> kernel/module/kallsyms.c:177:12: warning: dereference of noderef expression
> kernel/module/kallsyms.c:179:12: warning: dereference of noderef expression
> kernel/module/kallsyms.c:180:12: warning: dereference of noderef expression
> kernel/module/kallsyms.c:189:18: warning: dereference of noderef expression
> kernel/module/kallsyms.c:190:35: warning: dereference of noderef expression
> kernel/module/kallsyms.c:191:20: warning: dereference of noderef expression
> kernel/module/kallsyms.c:196:32: warning: dereference of noderef expression
> kernel/module/kallsyms.c:199:45: warning: dereference of noderef expression
> 
> Aaron used rcu_dereference_sched() in order to fix that.
> 
> How should this be fixed if using rcu_dereference_sched() is not correct ?

IMHO, sparse complains that _rcu pointer is not accessed using RCU
API.

rcu_dereference_sched() makes sparse happy. But lockdep complains
because the _rcu pointer is not accessed under:

	rcu_read_lock_sched();
	rcu_read_unlock_sched();

This is not the case here. Note that module_mutex does not
disable preemtion.

Now, the code is safe. The RCU access makes sure that "mod"
can't be freed in the meantime:

   + add_kallsyms() is called by the module loaded when the module
     is being loaded. It could not get removed in parallel
     by definition.

   + module_kallsyms_on_each_symbol() takes module_mutex.
     It means that the module could not get removed.


IMHO, we have two possibilities here:

   + Make sparse and lockdep happy by using rcu_dereference_sched()
     and calling the code under rcu_read_lock_sched().

   + Cast (struct mod_kallsyms *)mod->kallsyms when accessing
     the value.

I do not have strong preference. I am fine with both.

Anyway, such a fix should be done in a separate patch!

Best Regards,
Petr

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

* Re: [PATCH v8 09/13] module: Move kallsyms support into a separate file
  2022-02-25 10:15       ` Petr Mladek
@ 2022-02-25 10:27         ` Aaron Tomlin
  2022-02-25 12:21           ` Aaron Tomlin
  0 siblings, 1 reply; 43+ messages in thread
From: Aaron Tomlin @ 2022-02-25 10:27 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Christophe Leroy, mcgrof, cl, mbenes, akpm, jeyu, linux-kernel,
	linux-modules, void, atomlin, allen.lkml, joe, msuchanek,
	oleksandr

On Fri 2022-02-25 11:15 +0100, Petr Mladek wrote:
> rcu_dereference_sched() makes sparse happy. But lockdep complains
> because the _rcu pointer is not accessed under:
>
>     rcu_read_lock_sched();
>     rcu_read_unlock_sched();

Hi Petr,

>
> This is not the case here. Note that module_mutex does not
> disable preemtion.
>
> Now, the code is safe. The RCU access makes sure that "mod"
> can't be freed in the meantime:
>
>    + add_kallsyms() is called by the module loaded when the module
>      is being loaded. It could not get removed in parallel
>      by definition.
>
>    + module_kallsyms_on_each_symbol() takes module_mutex.
>      It means that the module could not get removed.

Indeed, which is why I did not use rcu_read_lock_sched() and
rcu_read_unlock_sched() with rcu_dereference_sched(). That being said, I
should have mentioned this in the commit message.

> IMHO, we have two possibilities here:
>
>    + Make sparse and lockdep happy by using rcu_dereference_sched()
>      and calling the code under rcu_read_lock_sched().
>
>    + Cast (struct mod_kallsyms *)mod->kallsyms when accessing
>      the value.

I prefer the first option.

> I do not have strong preference. I am fine with both.
>
> Anyway, such a fix should be done in a separate patch!

Agreed.


Kind regards,

-- 
Aaron Tomlin


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

* Re: [PATCH v8 04/13] module: Move livepatch support to a separate file
  2022-02-25  9:34   ` Petr Mladek
@ 2022-02-25 10:33     ` Aaron Tomlin
  2022-02-25 16:49     ` Christophe Leroy
  1 sibling, 0 replies; 43+ messages in thread
From: Aaron Tomlin @ 2022-02-25 10:33 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Luis R. Rodriguez, Christophe Leroy, Lameter, Christoph,
	Miroslav Benes, Andrew Morton, jeyu, linux-kernel, linux-modules,
	void, Aaron Tomlin, Allen, Joe Perches, Michal Suchanek,
	oleksandr

On Fri 2022-02-25 10:34 +0100, Petr Mladek wrote:
> This code include several other well hidden changes:
>
> --- del.p    2022-02-24 16:55:26.570054922 +0100
> +++ add.p    2022-02-24 16:56:04.766781394 +0100
> @@ -3,14 +3,14 @@
>   * section header table, section string table, and symtab section
>   * index from info to mod->klp_info.
>   */
> -static int copy_module_elf(struct module *mod, struct load_info *info)
> +int copy_module_elf(struct module *mod, struct load_info *info)
>  {
>      unsigned int size, symndx;
>      int ret;
>
>      size = sizeof(*mod->klp_info);
>      mod->klp_info = kmalloc(size, GFP_KERNEL);
> -    if (mod->klp_info == NULL)
> +    if (!mod->klp_info)
>          return -ENOMEM;
>
>      /* Elf header */
> @@ -20,7 +20,7 @@ static int copy_module_elf(struct module
>      /* Elf section header table */
>      size = sizeof(*info->sechdrs) * info->hdr->e_shnum;
>      mod->klp_info->sechdrs = kmemdup(info->sechdrs, size, GFP_KERNEL);
> -    if (mod->klp_info->sechdrs == NULL) {
> +    if (!mod->klp_info->sechdrs) {
>          ret = -ENOMEM;
>          goto free_info;
>      }
> @@ -28,7 +28,7 @@ static int copy_module_elf(struct module
>      /* Elf section name string table */
>      size = info->sechdrs[info->hdr->e_shstrndx].sh_size;
>      mod->klp_info->secstrings = kmemdup(info->secstrings, size, GFP_KERNEL);
> -    if (mod->klp_info->secstrings == NULL) {
> +    if (!mod->klp_info->secstrings) {
>          ret = -ENOMEM;
>          goto free_sechdrs;
>      }
> @@ -43,8 +43,7 @@ static int copy_module_elf(struct module
>       * to core_kallsyms.symtab since the copy of the symtab in module
>       * init memory is freed at the end of do_init_module().
>       */
> -    mod->klp_info->sechdrs[symndx].sh_addr = \
> -        (unsigned long) mod->core_kallsyms.symtab;
> +    mod->klp_info->sechdrs[symndx].sh_addr = (unsigned long)mod->core_kallsyms.symtab;
>
>      return 0;
>
>
> Please do not do these small coding style changes. It complicates the
> review and increases the risk of regressions. Different people
> have different preferences. Just imagine that every half a year
> someone update style of a code by his personal preferences. The
> real changes will then get lost in a lot of noise.
>
> Coding style changes might be acceptable only when the code is
> reworked or when it significantly improves readability.
>
>
> That said. I reviewed and tested this patch and did not find any
> problem. Feel free to use:
>
> Reviewed-by: Petr Mladek <pmladek@suse.com>
> Tested-by: Petr Mladek <pmladek@suse.com>
>
> Please, take the above as an advice for your future work.

Hi Petr,

Firstly, thank you for your feedback. Fair enough and noted.


Kind regards,

-- 
Aaron Tomlin


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

* Re: [PATCH v8 09/13] module: Move kallsyms support into a separate file
  2022-02-25 10:27         ` Aaron Tomlin
@ 2022-02-25 12:21           ` Aaron Tomlin
  2022-02-25 12:57             ` Christophe Leroy
  0 siblings, 1 reply; 43+ messages in thread
From: Aaron Tomlin @ 2022-02-25 12:21 UTC (permalink / raw)
  To: mcgrof
  Cc: Petr Mladek, Christophe Leroy, cl, mbenes, akpm, jeyu,
	linux-kernel, linux-modules, void, atomlin, allen.lkml, joe,
	msuchanek, oleksandr

On Fri 2022-02-25 10:27 +0000, Aaron Tomlin wrote:
> On Fri 2022-02-25 11:15 +0100, Petr Mladek wrote:
> > rcu_dereference_sched() makes sparse happy. But lockdep complains
> > because the _rcu pointer is not accessed under:
> >
> >     rcu_read_lock_sched();
> >     rcu_read_unlock_sched();
>
> Hi Petr,
>
> >
> > This is not the case here. Note that module_mutex does not
> > disable preemtion.
> >
> > Now, the code is safe. The RCU access makes sure that "mod"
> > can't be freed in the meantime:
> >
> >    + add_kallsyms() is called by the module loaded when the module
> >      is being loaded. It could not get removed in parallel
> >      by definition.
> >
> >    + module_kallsyms_on_each_symbol() takes module_mutex.
> >      It means that the module could not get removed.
>
> Indeed, which is why I did not use rcu_read_lock_sched() and
> rcu_read_unlock_sched() with rcu_dereference_sched(). That being said, I
> should have mentioned this in the commit message.
>
> > IMHO, we have two possibilities here:
> >
> >    + Make sparse and lockdep happy by using rcu_dereference_sched()
> >      and calling the code under rcu_read_lock_sched().
> >
> >    + Cast (struct mod_kallsyms *)mod->kallsyms when accessing
> >      the value.
>
> I prefer the first option.
>
> > I do not have strong preference. I am fine with both.
> >
> > Anyway, such a fix should be done in a separate patch!
>
> Agreed.

Luis,

If I understand correctly, it might be cleaner to resolve the above in two
separate patches for a v9 i.e. a) address the sparse and lockdep feedback
and b) refactor the code, before the latest version [1] is merged into
module-next. I assume the previous iteration will be reverted first?

Please let me know your thoughts

[1]: https://lore.kernel.org/all/20220222141303.1392190-1-atomlin@redhat.com/


Kind regards,

-- 
Aaron Tomlin


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

* Re: [PATCH v8 09/13] module: Move kallsyms support into a separate file
  2022-02-25 12:21           ` Aaron Tomlin
@ 2022-02-25 12:57             ` Christophe Leroy
  2022-02-26 20:27               ` Luis Chamberlain
  0 siblings, 1 reply; 43+ messages in thread
From: Christophe Leroy @ 2022-02-25 12:57 UTC (permalink / raw)
  To: Aaron Tomlin, mcgrof
  Cc: Petr Mladek, cl, mbenes, akpm, jeyu, linux-kernel, linux-modules,
	void, atomlin, allen.lkml, joe, msuchanek, oleksandr



Le 25/02/2022 à 13:21, Aaron Tomlin a écrit :
> On Fri 2022-02-25 10:27 +0000, Aaron Tomlin wrote:
>> On Fri 2022-02-25 11:15 +0100, Petr Mladek wrote:
>>> rcu_dereference_sched() makes sparse happy. But lockdep complains
>>> because the _rcu pointer is not accessed under:
>>>
>>>      rcu_read_lock_sched();
>>>      rcu_read_unlock_sched();
>>
>> Hi Petr,
>>
>>>
>>> This is not the case here. Note that module_mutex does not
>>> disable preemtion.
>>>
>>> Now, the code is safe. The RCU access makes sure that "mod"
>>> can't be freed in the meantime:
>>>
>>>     + add_kallsyms() is called by the module loaded when the module
>>>       is being loaded. It could not get removed in parallel
>>>       by definition.
>>>
>>>     + module_kallsyms_on_each_symbol() takes module_mutex.
>>>       It means that the module could not get removed.
>>
>> Indeed, which is why I did not use rcu_read_lock_sched() and
>> rcu_read_unlock_sched() with rcu_dereference_sched(). That being said, I
>> should have mentioned this in the commit message.
>>
>>> IMHO, we have two possibilities here:
>>>
>>>     + Make sparse and lockdep happy by using rcu_dereference_sched()
>>>       and calling the code under rcu_read_lock_sched().
>>>
>>>     + Cast (struct mod_kallsyms *)mod->kallsyms when accessing
>>>       the value.
>>
>> I prefer the first option.
>>
>>> I do not have strong preference. I am fine with both.
>>>
>>> Anyway, such a fix should be done in a separate patch!
>>
>> Agreed.
> 
> Luis,
> 
> If I understand correctly, it might be cleaner to resolve the above in two
> separate patches for a v9 i.e. a) address the sparse and lockdep feedback
> and b) refactor the code, before the latest version [1] is merged into
> module-next. I assume the previous iteration will be reverted first?
> 
> Please let me know your thoughts
> 
> [1]: https://lore.kernel.org/all/20220222141303.1392190-1-atomlin@redhat.com/
> 

I would do it the other way: first move the code into a separate file, 
and then handle the sparse __rcu feedback as a followup patch to the series.

Regarding module-next, AFAICS at the moment we still have only the 10 
first patches of v6 in the tree. I guess the way forward will be to 
rebase module-next and drop those patches and commit v9 instead.

Christophe

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

* Re: [PATCH v8 04/13] module: Move livepatch support to a separate file
  2022-02-25  9:34   ` Petr Mladek
  2022-02-25 10:33     ` Aaron Tomlin
@ 2022-02-25 16:49     ` Christophe Leroy
  2022-02-28 10:56       ` Petr Mladek
  1 sibling, 1 reply; 43+ messages in thread
From: Christophe Leroy @ 2022-02-25 16:49 UTC (permalink / raw)
  To: Petr Mladek, Aaron Tomlin
  Cc: mcgrof, cl, mbenes, akpm, jeyu, linux-kernel, linux-modules,
	void, atomlin, allen.lkml, joe, msuchanek, oleksandr



Le 25/02/2022 à 10:34, Petr Mladek a écrit :
> On Tue 2022-02-22 14:12:54, Aaron Tomlin wrote:
>> No functional change.
>>
>> This patch migrates livepatch support (i.e. used during module
>> add/or load and remove/or deletion) from core module code into
>> kernel/module/livepatch.c. At the moment it contains code to
>> persist Elf information about a given livepatch module, only.
>>
>> Signed-off-by: Aaron Tomlin <atomlin@redhat.com>
> 
>> diff --git a/kernel/module/livepatch.c b/kernel/module/livepatch.c
>> new file mode 100644
>> index 000000000000..486d4ff92719
>> --- /dev/null
>> +++ b/kernel/module/livepatch.c
>> @@ -0,0 +1,74 @@
>> + * Persist Elf information about a module. Copy the Elf header,
>> + * section header table, section string table, and symtab section
>> + * index from info to mod->klp_info.
>> + */
>> +int copy_module_elf(struct module *mod, struct load_info *info)
>> +{
>> +	unsigned int size, symndx;
>> +	int ret;
>> +
>> +	size = sizeof(*mod->klp_info);
>> +	mod->klp_info = kmalloc(size, GFP_KERNEL);
>> +	if (!mod->klp_info)
>> +		return -ENOMEM;
>> +
>> +	/* Elf header */
>> +	size = sizeof(mod->klp_info->hdr);
>> +	memcpy(&mod->klp_info->hdr, info->hdr, size);
>> +
>> +	/* Elf section header table */
>> +	size = sizeof(*info->sechdrs) * info->hdr->e_shnum;
>> +	mod->klp_info->sechdrs = kmemdup(info->sechdrs, size, GFP_KERNEL);
>> +	if (!mod->klp_info->sechdrs) {
>> +		ret = -ENOMEM;
>> +		goto free_info;
>> +	}
>> +
>> +	/* Elf section name string table */
>> +	size = info->sechdrs[info->hdr->e_shstrndx].sh_size;
>> +	mod->klp_info->secstrings = kmemdup(info->secstrings, size, GFP_KERNEL);
>> +	if (!mod->klp_info->secstrings) {
>> +		ret = -ENOMEM;
>> +		goto free_sechdrs;
>> +	}
>> +
>> +	/* Elf symbol section index */
>> +	symndx = info->index.sym;
>> +	mod->klp_info->symndx = symndx;
>> +
>> +	/*
>> +	 * For livepatch modules, core_kallsyms.symtab is a complete
>> +	 * copy of the original symbol table. Adjust sh_addr to point
>> +	 * to core_kallsyms.symtab since the copy of the symtab in module
>> +	 * init memory is freed at the end of do_init_module().
>> +	 */
>> +	mod->klp_info->sechdrs[symndx].sh_addr = (unsigned long)mod->core_kallsyms.symtab;
>> +
>> +	return 0;
> 
> This code include several other well hidden changes:
> 
> --- del.p	2022-02-24 16:55:26.570054922 +0100
> +++ add.p	2022-02-24 16:56:04.766781394 +0100
> @@ -3,14 +3,14 @@
>    * section header table, section string table, and symtab section
>    * index from info to mod->klp_info.
>    */
> -static int copy_module_elf(struct module *mod, struct load_info *info)
> +int copy_module_elf(struct module *mod, struct load_info *info)

That's not a hidden change. That's part of the move, that's required.

>   {
>   	unsigned int size, symndx;
>   	int ret;
>   
>   	size = sizeof(*mod->klp_info);
>   	mod->klp_info = kmalloc(size, GFP_KERNEL);
> -	if (mod->klp_info == NULL)
> +	if (!mod->klp_info)
>   		return -ENOMEM;
>   
>   	/* Elf header */
> @@ -20,7 +20,7 @@ static int copy_module_elf(struct module
>   	/* Elf section header table */
>   	size = sizeof(*info->sechdrs) * info->hdr->e_shnum;
>   	mod->klp_info->sechdrs = kmemdup(info->sechdrs, size, GFP_KERNEL);
> -	if (mod->klp_info->sechdrs == NULL) {
> +	if (!mod->klp_info->sechdrs) {
>   		ret = -ENOMEM;
>   		goto free_info;
>   	}
> @@ -28,7 +28,7 @@ static int copy_module_elf(struct module
>   	/* Elf section name string table */
>   	size = info->sechdrs[info->hdr->e_shstrndx].sh_size;
>   	mod->klp_info->secstrings = kmemdup(info->secstrings, size, GFP_KERNEL);
> -	if (mod->klp_info->secstrings == NULL) {
> +	if (!mod->klp_info->secstrings) {
>   		ret = -ENOMEM;
>   		goto free_sechdrs;
>   	}
> @@ -43,8 +43,7 @@ static int copy_module_elf(struct module
>   	 * to core_kallsyms.symtab since the copy of the symtab in module
>   	 * init memory is freed at the end of do_init_module().
>   	 */
> -	mod->klp_info->sechdrs[symndx].sh_addr = \
> -		(unsigned long) mod->core_kallsyms.symtab;
> +	mod->klp_info->sechdrs[symndx].sh_addr = (unsigned long)mod->core_kallsyms.symtab;
>   
>   	return 0;
> 
> 
> Please do not do these small coding style changes. It complicates the
> review and increases the risk of regressions. Different people
> have different preferences. Just imagine that every half a year
> someone update style of a code by his personal preferences. The
> real changes will then get lost in a lot of noise.

I disagree here. We are not talking about people's preference here but 
compliance with documented Linux kernel Codying Style and handling of 
official checkpatch.pl script reports.

You are right that randomly updating the style every half a year would 
be a nightmare and would kill blamability of changes.

However when moving big peaces of code like this, blamability is broken 
anyway and this is a very good opportunity to increase compliance of 
kernel code to its own codying style. But doing it in several steps 
increases code churn and has no real added value.

> 
> Coding style changes might be acceptable only when the code is
> reworked or when it significantly improves readability.

When code is moved around it is also a good opportunity.

> 
> 
> That said. I reviewed and tested this patch and did not find any
> problem. Feel free to use:
> 
> Reviewed-by: Petr Mladek <pmladek@suse.com>
> Tested-by: Petr Mladek <pmladek@suse.com>
> 
> Please, take the above as an advice for your future work.
> 

Thanks
Christophe

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

* Re: [PATCH v8 09/13] module: Move kallsyms support into a separate file
  2022-02-25 12:57             ` Christophe Leroy
@ 2022-02-26 20:27               ` Luis Chamberlain
  2022-02-28  9:02                 ` Christophe Leroy
  0 siblings, 1 reply; 43+ messages in thread
From: Luis Chamberlain @ 2022-02-26 20:27 UTC (permalink / raw)
  To: Christophe Leroy
  Cc: Aaron Tomlin, Petr Mladek, cl, mbenes, akpm, jeyu, linux-kernel,
	linux-modules, void, atomlin, allen.lkml, joe, msuchanek,
	oleksandr

On Fri, Feb 25, 2022 at 12:57:34PM +0000, Christophe Leroy wrote:
> 
> 
> Le 25/02/2022 à 13:21, Aaron Tomlin a écrit :
> > On Fri 2022-02-25 10:27 +0000, Aaron Tomlin wrote:
> >> On Fri 2022-02-25 11:15 +0100, Petr Mladek wrote:
> >>> rcu_dereference_sched() makes sparse happy. But lockdep complains
> >>> because the _rcu pointer is not accessed under:
> >>>
> >>>      rcu_read_lock_sched();
> >>>      rcu_read_unlock_sched();
> >>
> >> Hi Petr,
> >>
> >>>
> >>> This is not the case here. Note that module_mutex does not
> >>> disable preemtion.
> >>>
> >>> Now, the code is safe. The RCU access makes sure that "mod"
> >>> can't be freed in the meantime:
> >>>
> >>>     + add_kallsyms() is called by the module loaded when the module
> >>>       is being loaded. It could not get removed in parallel
> >>>       by definition.
> >>>
> >>>     + module_kallsyms_on_each_symbol() takes module_mutex.
> >>>       It means that the module could not get removed.
> >>
> >> Indeed, which is why I did not use rcu_read_lock_sched() and
> >> rcu_read_unlock_sched() with rcu_dereference_sched(). That being said, I
> >> should have mentioned this in the commit message.
> >>
> >>> IMHO, we have two possibilities here:
> >>>
> >>>     + Make sparse and lockdep happy by using rcu_dereference_sched()
> >>>       and calling the code under rcu_read_lock_sched().
> >>>
> >>>     + Cast (struct mod_kallsyms *)mod->kallsyms when accessing
> >>>       the value.
> >>
> >> I prefer the first option.
> >>
> >>> I do not have strong preference. I am fine with both.
> >>>
> >>> Anyway, such a fix should be done in a separate patch!
> >>
> >> Agreed.
> > 
> > Luis,
> > 
> > If I understand correctly, it might be cleaner to resolve the above in two
> > separate patches for a v9 i.e. a) address the sparse and lockdep feedback
> > and b) refactor the code, before the latest version [1] is merged into
> > module-next. I assume the previous iteration will be reverted first?
> > 
> > Please let me know your thoughts
> > 
> > [1]: https://lore.kernel.org/all/20220222141303.1392190-1-atomlin@redhat.com/
> > 
> 
> I would do it the other way: first move the code into a separate file, 
> and then handle the sparse __rcu feedback as a followup patch to the series.

I want to avoid any regressions and new complaints, fixes should be
submitted before so that if they are applicable to stable / etc they
can be sent there.

> Regarding module-next, AFAICS at the moment we still have only the 10 
> first patches of v6 in the tree. I guess the way forward will be to 
> rebase module-next and drop those patches and commit v9 instead.

Right, I'll just git fetch and reset to Linus' latest tree, so I'll drop
all of the stuff there now. And then the hope is to apply your new fresh new
clean v9.

Thanks for chugging on with this series!

  Luis

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

* Re: [PATCH v8 09/13] module: Move kallsyms support into a separate file
  2022-02-26 20:27               ` Luis Chamberlain
@ 2022-02-28  9:02                 ` Christophe Leroy
  2022-02-28  9:31                   ` Aaron Tomlin
  0 siblings, 1 reply; 43+ messages in thread
From: Christophe Leroy @ 2022-02-28  9:02 UTC (permalink / raw)
  To: Luis Chamberlain, Aaron Tomlin
  Cc: Petr Mladek, cl, mbenes, akpm, jeyu, linux-kernel, linux-modules,
	void, atomlin, allen.lkml, joe, msuchanek, oleksandr



Le 26/02/2022 à 21:27, Luis Chamberlain a écrit :
> On Fri, Feb 25, 2022 at 12:57:34PM +0000, Christophe Leroy wrote:
>>
>>
>> Le 25/02/2022 à 13:21, Aaron Tomlin a écrit :
>>> On Fri 2022-02-25 10:27 +0000, Aaron Tomlin wrote:
>>>> On Fri 2022-02-25 11:15 +0100, Petr Mladek wrote:
>>>>> rcu_dereference_sched() makes sparse happy. But lockdep complains
>>>>> because the _rcu pointer is not accessed under:
>>>>>
>>>>>       rcu_read_lock_sched();
>>>>>       rcu_read_unlock_sched();
>>>>
>>>> Hi Petr,
>>>>
>>>>>
>>>>> This is not the case here. Note that module_mutex does not
>>>>> disable preemtion.
>>>>>
>>>>> Now, the code is safe. The RCU access makes sure that "mod"
>>>>> can't be freed in the meantime:
>>>>>
>>>>>      + add_kallsyms() is called by the module loaded when the module
>>>>>        is being loaded. It could not get removed in parallel
>>>>>        by definition.
>>>>>
>>>>>      + module_kallsyms_on_each_symbol() takes module_mutex.
>>>>>        It means that the module could not get removed.
>>>>
>>>> Indeed, which is why I did not use rcu_read_lock_sched() and
>>>> rcu_read_unlock_sched() with rcu_dereference_sched(). That being said, I
>>>> should have mentioned this in the commit message.
>>>>
>>>>> IMHO, we have two possibilities here:
>>>>>
>>>>>      + Make sparse and lockdep happy by using rcu_dereference_sched()
>>>>>        and calling the code under rcu_read_lock_sched().
>>>>>
>>>>>      + Cast (struct mod_kallsyms *)mod->kallsyms when accessing
>>>>>        the value.
>>>>
>>>> I prefer the first option.
>>>>
>>>>> I do not have strong preference. I am fine with both.
>>>>>
>>>>> Anyway, such a fix should be done in a separate patch!
>>>>
>>>> Agreed.
>>>
>>> Luis,
>>>
>>> If I understand correctly, it might be cleaner to resolve the above in two
>>> separate patches for a v9 i.e. a) address the sparse and lockdep feedback
>>> and b) refactor the code, before the latest version [1] is merged into
>>> module-next. I assume the previous iteration will be reverted first?
>>>
>>> Please let me know your thoughts
>>>
>>> [1]: https://lore.kernel.org/all/20220222141303.1392190-1-atomlin@redhat.com/
>>>
>>
>> I would do it the other way: first move the code into a separate file,
>> and then handle the sparse __rcu feedback as a followup patch to the series.
> 
> I want to avoid any regressions and new complaints, fixes should be
> submitted before so that if they are applicable to stable / etc they
> can be sent there.

Fair enough, however here we are talking about sparse warning only, and 
the discussion around it has shown that this is not a real bug, just a 
warning that can be either fixed with a proper cast or by adding rcu 
locks which might not be necessary.

So I'm not sure this is a good candidate for -stable.

In 
https://www.kernel.org/doc/html/latest/process/stable-kernel-rules.html 
it is said "It must fix a real bug that bothers people (not a, “This 
could be a problem…” type thing)"

But up to you.

> 
>> Regarding module-next, AFAICS at the moment we still have only the 10
>> first patches of v6 in the tree. I guess the way forward will be to
>> rebase module-next and drop those patches and commit v9 instead.
> 
> Right, I'll just git fetch and reset to Linus' latest tree, so I'll drop
> all of the stuff there now. And then the hope is to apply your new fresh new
> clean v9.
> 

Aaron, do you plan to send v9 anytime soon ?

Thanks
Christophe

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

* Re: [PATCH v8 09/13] module: Move kallsyms support into a separate file
  2022-02-28  9:02                 ` Christophe Leroy
@ 2022-02-28  9:31                   ` Aaron Tomlin
  2022-02-28  9:33                     ` Christophe Leroy
  0 siblings, 1 reply; 43+ messages in thread
From: Aaron Tomlin @ 2022-02-28  9:31 UTC (permalink / raw)
  To: Christophe Leroy
  Cc: Luis Chamberlain, Aaron Tomlin, Petr Mladek, cl, mbenes, akpm,
	jeyu, linux-kernel, linux-modules, void, allen.lkml, joe,
	msuchanek, oleksandr

On Mon 2022-02-28 09:02 +0000, Christophe Leroy wrote:
> Aaron, do you plan to send v9 anytime soon ?

Hi Christophe,

Yes, today.

As discussed previously, I will resolve the Sparse warnings, in the context
of Kconfig CONFIG_KALLSYMS, with an appropriate statement in the commit
message, as a preliminary patch to the series. That being said, I believe
it makes sense to include the aforementioned patch within the series.
Any objections?


Kind regards,

-- 
Aaron Tomlin

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

* Re: [PATCH v8 09/13] module: Move kallsyms support into a separate file
  2022-02-28  9:31                   ` Aaron Tomlin
@ 2022-02-28  9:33                     ` Christophe Leroy
  0 siblings, 0 replies; 43+ messages in thread
From: Christophe Leroy @ 2022-02-28  9:33 UTC (permalink / raw)
  To: Aaron Tomlin
  Cc: Luis Chamberlain, Aaron Tomlin, Petr Mladek, cl, mbenes, akpm,
	jeyu, linux-kernel, linux-modules, void, allen.lkml, joe,
	msuchanek, oleksandr



Le 28/02/2022 à 10:31, Aaron Tomlin a écrit :
> On Mon 2022-02-28 09:02 +0000, Christophe Leroy wrote:
>> Aaron, do you plan to send v9 anytime soon ?
> 
> Hi Christophe,
> 
> Yes, today.
> 
> As discussed previously, I will resolve the Sparse warnings, in the context
> of Kconfig CONFIG_KALLSYMS, with an appropriate statement in the commit
> message, as a preliminary patch to the series. That being said, I believe
> it makes sense to include the aforementioned patch within the series.
> Any objections?
> 

No objection.

Thank you
Christophe

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

* Re: [PATCH v8 04/13] module: Move livepatch support to a separate file
  2022-02-25 16:49     ` Christophe Leroy
@ 2022-02-28 10:56       ` Petr Mladek
  2022-02-28 11:46         ` Christophe Leroy
  0 siblings, 1 reply; 43+ messages in thread
From: Petr Mladek @ 2022-02-28 10:56 UTC (permalink / raw)
  To: Christophe Leroy
  Cc: Aaron Tomlin, mcgrof, cl, mbenes, akpm, jeyu, linux-kernel,
	linux-modules, void, atomlin, allen.lkml, joe, msuchanek,
	oleksandr

On Fri 2022-02-25 16:49:31, Christophe Leroy wrote:
> 
> 
> Le 25/02/2022 à 10:34, Petr Mladek a écrit :
> > On Tue 2022-02-22 14:12:54, Aaron Tomlin wrote:
> >> No functional change.
> >>
> >> This patch migrates livepatch support (i.e. used during module
> >> add/or load and remove/or deletion) from core module code into
> >> kernel/module/livepatch.c. At the moment it contains code to
> >> persist Elf information about a given livepatch module, only.
> >>
> > --- del.p	2022-02-24 16:55:26.570054922 +0100
> > +++ add.p	2022-02-24 16:56:04.766781394 +0100
> > @@ -3,14 +3,14 @@
> >    * section header table, section string table, and symtab section
> >    * index from info to mod->klp_info.
> >    */
> > -static int copy_module_elf(struct module *mod, struct load_info *info)
> > +int copy_module_elf(struct module *mod, struct load_info *info)
> 
> That's not a hidden change. That's part of the move, that's required.

Sure. I was not talking about this line. I kept it to show the context.

> >   {
> >   	unsigned int size, symndx;
> >   	int ret;
> >   
> >   	size = sizeof(*mod->klp_info);
> >   	mod->klp_info = kmalloc(size, GFP_KERNEL);
> > -	if (mod->klp_info == NULL)
> > +	if (!mod->klp_info)
> >   		return -ENOMEM;
> >   
> >   	/* Elf header */
> > @@ -20,7 +20,7 @@ static int copy_module_elf(struct module
> >   	/* Elf section header table */
> >   	size = sizeof(*info->sechdrs) * info->hdr->e_shnum;
> >   	mod->klp_info->sechdrs = kmemdup(info->sechdrs, size, GFP_KERNEL);
> > -	if (mod->klp_info->sechdrs == NULL) {
> > +	if (!mod->klp_info->sechdrs) {
> >   		ret = -ENOMEM;
> >   		goto free_info;
> >   	}
> > @@ -28,7 +28,7 @@ static int copy_module_elf(struct module
> >   	/* Elf section name string table */
> >   	size = info->sechdrs[info->hdr->e_shstrndx].sh_size;
> >   	mod->klp_info->secstrings = kmemdup(info->secstrings, size, GFP_KERNEL);
> > -	if (mod->klp_info->secstrings == NULL) {
> > +	if (!mod->klp_info->secstrings) {
> >   		ret = -ENOMEM;
> >   		goto free_sechdrs;
> >   	}
> > @@ -43,8 +43,7 @@ static int copy_module_elf(struct module
> >   	 * to core_kallsyms.symtab since the copy of the symtab in module
> >   	 * init memory is freed at the end of do_init_module().
> >   	 */
> > -	mod->klp_info->sechdrs[symndx].sh_addr = \
> > -		(unsigned long) mod->core_kallsyms.symtab;
> > +	mod->klp_info->sechdrs[symndx].sh_addr = (unsigned long)mod->core_kallsyms.symtab;
> >   
> >   	return 0;
> > 
> > 
> > Please do not do these small coding style changes. It complicates the
> > review and increases the risk of regressions. Different people
> > have different preferences. Just imagine that every half a year
> > someone update style of a code by his personal preferences. The
> > real changes will then get lost in a lot of noise.
> 
> I disagree here. We are not talking about people's preference here but 
> compliance with documented Linux kernel Codying Style and handling of 
> official checkpatch.pl script reports.

Really?

1. I restored

	+	if (mod->klp_info->secstrings == NULL) {

   and checkpatch.pl is happy.


2. I do not see anythinkg about if (xxx == NULL) checks in
   Documentation/process/coding-style.rst

3. $> git grep "if (.* == NULL" | wc -l
   15041

4. The result of
	-	mod->klp_info->sechdrs[symndx].sh_addr = \
	-		(unsigned long) mod->core_kallsyms.symtab;
	+	mod->klp_info->sechdrs[symndx].sh_addr = (unsigned long)mod->core_kallsyms.symtab;

   is 90 characeters long and Documentation/process/coding-style.rst says:

	2) Breaking long lines and strings
	----------------------------------

	Coding style is all about readability and maintainability using commonly
	available tools.

	The preferred limit on the length of a single line is 80 columns.

	Statements longer than 80 columns should be broken into sensible chunks,
	unless exceeding 80 columns significantly increases readability and does
	not hide information.

   checkpatch.pl accepts lines up to 100 columns but 80 are still
   preferred.


> You are right that randomly updating the style every half a year would 
> be a nightmare and would kill blamability of changes.
> 
> However when moving big peaces of code like this, blamability is broken 
> anyway and this is a very good opportunity to increase compliance of 
> kernel code to its own codying style. But doing it in several steps 
> increases code churn and has no real added value.

From Documentation/process/submitting-patches.rst:

	One significant exception is when moving code from one file to
	another -- in this case you should not modify the moved code at all in
	the same patch which moves it.  This clearly delineates the act of
	moving the code and your changes.  This greatly aids review of the
	actual differences and allows tools to better track the history of
	the code itself.


> > 
> > Coding style changes might be acceptable only when the code is
> > reworked or when it significantly improves readability.
> 
> When code is moved around it is also a good opportunity.

No!

I would not have complained if it did not complicate my review.
But it did!

Best Regards,
Petr

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

* Re: [PATCH v8 04/13] module: Move livepatch support to a separate file
  2022-02-28 10:56       ` Petr Mladek
@ 2022-02-28 11:46         ` Christophe Leroy
  2022-02-28 13:05           ` Petr Mladek
  0 siblings, 1 reply; 43+ messages in thread
From: Christophe Leroy @ 2022-02-28 11:46 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Aaron Tomlin, mcgrof, cl, mbenes, akpm, jeyu, linux-kernel,
	linux-modules, void, atomlin, allen.lkml, joe, msuchanek,
	oleksandr



Le 28/02/2022 à 11:56, Petr Mladek a écrit :
> On Fri 2022-02-25 16:49:31, Christophe Leroy wrote:
>>
>>
>> Le 25/02/2022 à 10:34, Petr Mladek a écrit :
>>>
>>> Please do not do these small coding style changes. It complicates the
>>> review and increases the risk of regressions. Different people
>>> have different preferences. Just imagine that every half a year
>>> someone update style of a code by his personal preferences. The
>>> real changes will then get lost in a lot of noise.
>>
>> I disagree here. We are not talking about people's preference here but
>> compliance with documented Linux kernel Codying Style and handling of
>> official checkpatch.pl script reports.
> 
> Really?
> 
> 1. I restored
> 
> 	+	if (mod->klp_info->secstrings == NULL) {
> 
>     and checkpatch.pl is happy.

On mainline's kernel/module.c checkpatch.pl tells me:

CHECK: Comparison to NULL could be written "!mod->klp_info->secstrings"
#2092: FILE: kernel/module.c:2092:
+	if (mod->klp_info->secstrings == NULL) {



> 
> 
> 2. I do not see anythinkg about if (xxx == NULL) checks in
>     Documentation/process/coding-style.rst
> 
> 3. $> git grep "if (.* == NULL" | wc -l
>     15041

Commit b75ac618df75 ("checkpatch: add --strict "pointer comparison to 
NULL" test")

> 
> 4. The result of
> 	-	mod->klp_info->sechdrs[symndx].sh_addr = \
> 	-		(unsigned long) mod->core_kallsyms.symtab;
> 	+	mod->klp_info->sechdrs[symndx].sh_addr = (unsigned long)mod->core_kallsyms.symtab;
> 
>     is 90 characeters long and Documentation/process/coding-style.rst says:

Probably a misinterpretation of:

WARNING: Avoid unnecessary line continuations
#2107: FILE: kernel/module.c:2107:
+	mod->klp_info->sechdrs[symndx].sh_addr = \

> 
> 	2) Breaking long lines and strings
> 	----------------------------------
> 
> 	Coding style is all about readability and maintainability using commonly
> 	available tools.
> 
> 	The preferred limit on the length of a single line is 80 columns.
> 
> 	Statements longer than 80 columns should be broken into sensible chunks,
> 	unless exceeding 80 columns significantly increases readability and does
> 	not hide information.
> 
>     checkpatch.pl accepts lines up to 100 columns but 80 are still
>     preferred.
> 
> 
>> You are right that randomly updating the style every half a year would
>> be a nightmare and would kill blamability of changes.
>>
>> However when moving big peaces of code like this, blamability is broken
>> anyway and this is a very good opportunity to increase compliance of
>> kernel code to its own codying style. But doing it in several steps
>> increases code churn and has no real added value.
> 
>  From Documentation/process/submitting-patches.rst:
> 
> 	One significant exception is when moving code from one file to
> 	another -- in this case you should not modify the moved code at all in
> 	the same patch which moves it.  This clearly delineates the act of
> 	moving the code and your changes.  This greatly aids review of the
> 	actual differences and allows tools to better track the history of
> 	the code itself.
> 
> 
>>>
>>> Coding style changes might be acceptable only when the code is
>>> reworked or when it significantly improves readability.
>>
>> When code is moved around it is also a good opportunity.
> 
> No!


By the way some maintainers require checkpatch' clean patches even when 
this is only code move. I remember being requested to do that in the 
past, so now I almost always do it with my own patches.

> 
> I would not have complained if it did not complicate my review.
> But it did!
> 

Reviewing partial code move is not easy anyway, git is not very 
userfriendly with that.

Christophe

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

* Re: [PATCH v8 04/13] module: Move livepatch support to a separate file
  2022-02-28 11:46         ` Christophe Leroy
@ 2022-02-28 13:05           ` Petr Mladek
  0 siblings, 0 replies; 43+ messages in thread
From: Petr Mladek @ 2022-02-28 13:05 UTC (permalink / raw)
  To: Christophe Leroy
  Cc: Aaron Tomlin, mcgrof, cl, mbenes, akpm, jeyu, linux-kernel,
	linux-modules, void, atomlin, allen.lkml, joe, msuchanek,
	oleksandr

On Mon 2022-02-28 11:46:33, Christophe Leroy wrote:
> 
> 
> Le 28/02/2022 à 11:56, Petr Mladek a écrit :
> > On Fri 2022-02-25 16:49:31, Christophe Leroy wrote:
> >> Le 25/02/2022 à 10:34, Petr Mladek a écrit :
> >>>
> >>> Please do not do these small coding style changes. It complicates the
> >>> review and increases the risk of regressions. Different people
> >>> have different preferences. Just imagine that every half a year
> >>> someone update style of a code by his personal preferences. The
> >>> real changes will then get lost in a lot of noise.
> >>
> >> I disagree here. We are not talking about people's preference here but
> >> compliance with documented Linux kernel Codying Style and handling of
> >> official checkpatch.pl script reports.
> > 
> > Really?
> > 
> > 1. I restored
> > 
> > 	+	if (mod->klp_info->secstrings == NULL) {
> > 
> >     and checkpatch.pl is happy.
> 
> On mainline's kernel/module.c checkpatch.pl tells me:
> 
> CHECK: Comparison to NULL could be written "!mod->klp_info->secstrings"
> #2092: FILE: kernel/module.c:2092:
> +	if (mod->klp_info->secstrings == NULL) {

Only with --strict option. Alias of this option is --subjective...

> By the way some maintainers require checkpatch' clean patches even when 
> this is only code move. I remember being requested to do that in the 
> past, so now I almost always do it with my own patches.

I see.

From my POV, checkpatch is an useful tool for finding obvious mistakes.
But it is just a best effort approach. It has false positives. And
some complains are controversial.

BTW: I have never heard about --strict/--subjective option. I wonder
if some maintainer requires it.

> > I would not have complained if it did not complicate my review.
> > But it did!
> 
> Reviewing partial code move is not easy anyway, git is not very 
> userfriendly with that.

Exactly. It is a real pain to find changes in moved functions. It is
much easier when the author just shuffled the code. Anyway, the less
changes the better.

Best Regards,
Petr

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

end of thread, other threads:[~2022-02-28 13:05 UTC | newest]

Thread overview: 43+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-02-22 14:12 [PATCH v8 00/13] module: core code clean up Aaron Tomlin
2022-02-22 14:12 ` [PATCH v8 01/13] module: Move all into module/ Aaron Tomlin
2022-02-22 17:58   ` Christophe Leroy
2022-02-22 20:00   ` Allen
2022-02-22 14:12 ` [PATCH v8 02/13] module: Simple refactor in preparation for split Aaron Tomlin
2022-02-22 17:58   ` Christophe Leroy
2022-02-22 14:12 ` [PATCH v8 03/13] module: Make internal.h and decompress.c more compliant Aaron Tomlin
2022-02-22 14:12 ` [PATCH v8 04/13] module: Move livepatch support to a separate file Aaron Tomlin
2022-02-22 17:58   ` Christophe Leroy
2022-02-25  9:34   ` Petr Mladek
2022-02-25 10:33     ` Aaron Tomlin
2022-02-25 16:49     ` Christophe Leroy
2022-02-28 10:56       ` Petr Mladek
2022-02-28 11:46         ` Christophe Leroy
2022-02-28 13:05           ` Petr Mladek
2022-02-22 14:12 ` [PATCH v8 05/13] module: Move latched RB-tree " Aaron Tomlin
2022-02-22 17:58   ` Christophe Leroy
2022-02-22 14:12 ` [PATCH v8 06/13] module: Move strict rwx " Aaron Tomlin
2022-02-22 17:59   ` Christophe Leroy
2022-02-22 14:12 ` [PATCH v8 07/13] module: Move extra signature support out of core code Aaron Tomlin
2022-02-22 17:59   ` Christophe Leroy
2022-02-22 14:12 ` [PATCH v8 08/13] module: Move kmemleak support to a separate file Aaron Tomlin
2022-02-22 17:59   ` Christophe Leroy
2022-02-22 14:12 ` [PATCH v8 09/13] module: Move kallsyms support into " Aaron Tomlin
2022-02-22 17:59   ` Christophe Leroy
2022-02-25  9:15   ` Petr Mladek
2022-02-25  9:27     ` Christophe Leroy
2022-02-25 10:15       ` Petr Mladek
2022-02-25 10:27         ` Aaron Tomlin
2022-02-25 12:21           ` Aaron Tomlin
2022-02-25 12:57             ` Christophe Leroy
2022-02-26 20:27               ` Luis Chamberlain
2022-02-28  9:02                 ` Christophe Leroy
2022-02-28  9:31                   ` Aaron Tomlin
2022-02-28  9:33                     ` Christophe Leroy
2022-02-22 14:13 ` [PATCH v8 10/13] module: Move procfs " Aaron Tomlin
2022-02-22 17:59   ` Christophe Leroy
2022-02-22 14:13 ` [PATCH v8 11/13] module: Move sysfs " Aaron Tomlin
2022-02-22 17:59   ` Christophe Leroy
2022-02-22 14:13 ` [PATCH v8 12/13] module: Move kdb_modules list out of core code Aaron Tomlin
2022-02-22 18:05   ` Christophe Leroy
2022-02-22 14:13 ` [PATCH v8 13/13] module: Move version support into a separate file Aaron Tomlin
2022-02-22 18:06   ` Christophe Leroy

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).