From 1bf5e5e70d85c8a47ae6495b095602efa1298d4c Mon Sep 17 00:00:00 2001 From: Will McVicker Date: Thu, 19 Nov 2020 13:46:37 -0800 Subject: [PATCH] ANDROID: modules: re-introduce the MODULE_SCMVERSION config Config MODULE_SCMVERSION introduces a new module attribute -- `scmversion` -- which can be used to identify a given module's SCM version. This is very useful for developers that update their kernel independently from their kernel modules or vice-versa since the SCM version provided by UTS_RELEASE (`uname -r`) will now differ from the module's vermagic attribute. For example, we have a CI setup that tests new kernel changes on the hikey960 and db845c devices without updating their kernel modules. When these tests fail, we need to be able to identify the exact device configuration the test was using. By including MODULE_SCMVERSION, we can identify the exact kernel and modules' SCM versions for debugging the failures. Additionally, by exposing the SCM version via the sysfs node /sys/module/MODULENAME/scmversion, one can also verify the SCM versions of the modules loaded from the initramfs. Currently, modinfo can only retrieve module attributes from the module's ko on disk and not from the actual module that is loaded in RAM. You can retrieve the SCM version in two ways, 1) By using modinfo: > modinfo -F scmversion MODULENAME 2) By module sysfs node: > cat /sys/module/MODULENAME/scmversion Bug: 180027765 Bug: 236871190 Link: https://lore.kernel.org/all/20210121213641.3477522-1-willmcvicker@google.com/ Signed-off-by: Will McVicker Signed-off-by: Yifan Hong Change-Id: Iad77caff63c4ddef3a3c92182cdacb0b90b124c7 --- Documentation/ABI/stable/sysfs-module | 18 ++++++++++++++++++ include/linux/module.h | 1 + kernel/module/Kconfig | 14 ++++++++++++++ kernel/module/main.c | 2 ++ scripts/Makefile.modpost | 27 +++++++++++++++++++++++++++ scripts/mod/modpost.c | 10 +++++++++- 6 files changed, 71 insertions(+), 1 deletion(-) diff --git a/Documentation/ABI/stable/sysfs-module b/Documentation/ABI/stable/sysfs-module index 41b1f16e8795..47b8fd0e196e 100644 --- a/Documentation/ABI/stable/sysfs-module +++ b/Documentation/ABI/stable/sysfs-module @@ -45,3 +45,21 @@ Date: Jun 2005 Description: If the module source has MODULE_VERSION, this file will contain the version of the source code. + +What: /sys/module/MODULENAME/scmversion +Date: November 2020 +KernelVersion: 5.12 +Contact: Will McVicker +Description: This read-only file will appear if modpost was supplied with an + SCM version for the module. It can be enabled with the config + MODULE_SCMVERSION. The SCM version is retrieved by + scripts/setlocalversion, which means that the presence of this + file depends on CONFIG_LOCALVERSION_AUTO=y. When read, the SCM + version that the module was compiled with is returned. The SCM + version is returned in the following format:: + + === + Git: g[a-f0-9]\+(-dirty)\? + Mercurial: hg[a-f0-9]\+(-dirty)\? + Subversion: svn[0-9]\+ + === diff --git a/include/linux/module.h b/include/linux/module.h index 33883dbe97c4..b991505c7f04 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -387,6 +387,7 @@ struct module { struct module_attribute *modinfo_attrs; const char *version; const char *srcversion; + const char *scmversion; struct kobject *holders_dir; /* Exported symbols */ diff --git a/kernel/module/Kconfig b/kernel/module/Kconfig index c8d4212db319..5058c2196011 100644 --- a/kernel/module/Kconfig +++ b/kernel/module/Kconfig @@ -88,6 +88,20 @@ config MODULE_SRCVERSION_ALL the version). With this option, such a "srcversion" field will be created for all modules. If unsure, say N. +config MODULE_SCMVERSION + bool "SCM version for modules" + depends on LOCALVERSION_AUTO + help + This enables the module attribute "scmversion" which can be used + by developers to identify the SCM version of a given module, e.g. + git sha1 or hg sha1. The SCM version can be queried by modinfo or + via the sysfs node: /sys/modules/MODULENAME/scmversion. This is + useful when the kernel or kernel modules are updated separately + since that causes the vermagic of the kernel and the module to + differ. + + If unsure, say N. + config MODULE_SIG bool "Module signature verification" select MODULE_SIG_FORMAT diff --git a/kernel/module/main.c b/kernel/module/main.c index e4cad7f89a68..17f0c0322f59 100644 --- a/kernel/module/main.c +++ b/kernel/module/main.c @@ -525,6 +525,7 @@ static struct module_attribute modinfo_##field = { \ MODINFO_ATTR(version); MODINFO_ATTR(srcversion); +MODINFO_ATTR(scmversion); static struct { char name[MODULE_NAME_LEN + 1]; @@ -972,6 +973,7 @@ struct module_attribute *modinfo_attrs[] = { &module_uevent, &modinfo_version, &modinfo_srcversion, + &modinfo_scmversion, &modinfo_initstate, &modinfo_coresize, #ifdef CONFIG_ARCH_WANTS_MODULES_DATA_IN_VMALLOC diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost index 931a3272a4ba..01df0bad6fa3 100644 --- a/scripts/Makefile.modpost +++ b/scripts/Makefile.modpost @@ -65,6 +65,33 @@ modpost-args += -T $(MODORDER) modpost-deps += $(MODORDER) endif +ifeq ($(CONFIG_MODULE_SCMVERSION),y) +ifeq ($(KBUILD_EXTMOD),) +module_srcpath := $(srctree) +else +# Get the external module's source path. KBUILD_EXTMOD could either be an +# absolute path or relative path from $(srctree). This makes sure that we +# aren't using a relative path from a separate working directory (O= or +# KBUILD_OUTPUT) since that may not be the actual module's SCM project path. So +# check the path relative to $(srctree) first. +ifneq ($(realpath $(srctree)/$(KBUILD_EXTMOD) 2>/dev/null),) + module_srcpath := $(srctree)/$(KBUILD_EXTMOD) +else + module_srcpath := $(KBUILD_EXTMOD) +endif +endif + +# Get the SCM version of the module. Sed verifies setlocalversion returns +# a proper revision based on the SCM type, e.g. git, mercurial, or svn. +# Note: relative M= paths are not supported when building the kernel out of the +# srctree since setlocalversion won't be able to find the module srctree. +module_scmversion := $(shell $(srctree)/scripts/setlocalversion $(module_srcpath) | \ + sed -n 's/.*-\(\(g\|hg\)[a-fA-F0-9]\+\(-dirty\)\?\|svn[0-9]\+\).*/\1/p') +ifneq ($(module_scmversion),) +modpost-args += -v $(module_scmversion) +endif +endif + ifeq ($(KBUILD_EXTMOD),) # Generate the list of in-tree objects in vmlinux diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 9466b6a2abae..f043dbe7f751 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -29,6 +29,8 @@ static bool modversions; static bool all_versions; /* If we are modposting external module set to 1 */ static bool external_module; +#define MODULE_SCMVERSION_SIZE 64 +static char module_scmversion[MODULE_SCMVERSION_SIZE]; /* Only warn about unresolved symbols */ static bool warn_unresolved; @@ -2006,6 +2008,9 @@ static void add_header(struct buffer *b, struct module *mod) if (!external_module) buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n"); + if (module_scmversion[0] != '\0') + buf_printf(b, "\nMODULE_INFO(scmversion, \"%s\");\n", module_scmversion); + buf_printf(b, "\n" "#ifdef CONFIG_RETPOLINE\n" @@ -2334,7 +2339,7 @@ int main(int argc, char **argv) LIST_HEAD(dump_lists); struct dump_list *dl, *dl2; - while ((opt = getopt(argc, argv, "ei:mnT:o:awENd:")) != -1) { + while ((opt = getopt(argc, argv, "ei:mnT:o:awENd:v:")) != -1) { switch (opt) { case 'e': external_module = true; @@ -2371,6 +2376,9 @@ int main(int argc, char **argv) case 'd': missing_namespace_deps = optarg; break; + case 'v': + strncpy(module_scmversion, optarg, sizeof(module_scmversion) - 1); + break; default: exit(1); }