From 4e1776cedfaa68fab341e657e025ae31eb95f194 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 31 May 2024 15:34:18 +0000 Subject: [PATCH 1/2] Revert "Load modules from _16K dir when running on 16K kernel" This reverts commit ffdb017e7d0141d09d67c735913196a8dc166671. Overriding an explicitly-specified module path (e.g. passed via the '-d ' argument) because the kernel is using 16KiB pages is inconsistent and unexpected. Revert this change in anticipation of filtering incompatible modules instead. Bug: 343971855 Test: Verified that _16k module directory is excluded by modprobe when running in userspace fastboot with 4k pages. Change-Id: If9c6e2d26fc53b12f543d531d64ef3d288ddc179 --- toolbox/modprobe.cpp | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/toolbox/modprobe.cpp b/toolbox/modprobe.cpp index b0e76ea81..45dd9b8c1 100644 --- a/toolbox/modprobe.cpp +++ b/toolbox/modprobe.cpp @@ -15,7 +15,6 @@ */ #include -#include #include #include @@ -28,7 +27,6 @@ #include #include -#include namespace { @@ -107,11 +105,6 @@ static int KernelVersionNameFilter(const dirent* de) { return 0; } -std::string GetPageSizeSuffix() { - static const size_t page_size = sysconf(_SC_PAGE_SIZE); - return android::base::StringPrintf("_%zuk", page_size / 1024); -} - } // anonymous namespace extern "C" int modprobe_main(int argc, char** argv) { @@ -240,19 +233,6 @@ extern "C" int modprobe_main(int argc, char** argv) { // Allow modules to be directly inside /lib/modules mod_dirs.emplace_back(LIB_MODULES_PREFIX); } - if (getpagesize() != 4096) { - struct utsname uts {}; - if (uname(&uts)) { - PLOG(FATAL) << "Failed to get kernel version"; - } - const auto module_dir = android::base::StringPrintf("/lib/modules/%s%s", uts.release, - GetPageSizeSuffix().c_str()); - struct stat st {}; - if (stat(module_dir.c_str(), &st) == 0 && S_ISDIR(st.st_mode)) { - mod_dirs.clear(); - mod_dirs.emplace_back(module_dir); - } - } LOG(DEBUG) << "mode is " << mode; LOG(DEBUG) << "mod_dirs is: " << android::base::Join(mod_dirs, " "); From c991c3dbedd35d5291c68da15681b8b1efd02f9c Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 31 May 2024 17:25:49 +0000 Subject: [PATCH 2/2] toolbox/modprobe: Filter module directories based on kernel page size When modules for multiple kernels with the same major/minor versions are installed on a device, modprobe will search the module directories based on whatever order scandir() returned them. In this case, it is possible that we will try to load modules with the wrong page size for the running kernel, which can lead to obscure symbol CRC mismatches and ultimately a system crash. Adjust the scandir() filtering function so that the kernel page size is taken into account in addition to the major/minor versions returned by utsname(). The general rule is that module directories ending in "_Nk" contain modules for a page-size of N KiB, whilst the absence of such a suffix implies the default of 4 KiB. Bug: 343971855 Test: Verified that _16k module directory is excluded by modprobe when running in userspace fastboot with 4k pages. Change-Id: I78a0a249028bbb0bcdd78eb14de36e631e233be0 --- toolbox/modprobe.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/toolbox/modprobe.cpp b/toolbox/modprobe.cpp index 45dd9b8c1..7fde4915e 100644 --- a/toolbox/modprobe.cpp +++ b/toolbox/modprobe.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include @@ -85,6 +86,20 @@ void MyLogger(android::base::LogId id, android::base::LogSeverity severity, cons } } +static bool ModDirMatchesKernelPageSize(const char* mod_dir) { + static const unsigned int kernel_pgsize_kb = getpagesize() / 1024; + const char* mod_sfx = strrchr(mod_dir, '_'); + unsigned int mod_pgsize_kb; + int mod_sfx_len; + + if (mod_sfx == NULL || sscanf(mod_sfx, "_%uk%n", &mod_pgsize_kb, &mod_sfx_len) != 1 || + strlen(mod_sfx) != mod_sfx_len) { + mod_pgsize_kb = 4; + } + + return kernel_pgsize_kb == mod_pgsize_kb; +} + // Find directories in format of "/lib/modules/x.y.z-*". static int KernelVersionNameFilter(const dirent* de) { unsigned int major, minor; @@ -100,7 +115,7 @@ static int KernelVersionNameFilter(const dirent* de) { } if (android::base::StartsWith(de->d_name, kernel_version)) { - return 1; + return ModDirMatchesKernelPageSize(de->d_name); } return 0; }