From e067e96da26111e446c5deadefd839a6451dd6d1 Mon Sep 17 00:00:00 2001 From: Will McVicker Date: Thu, 25 May 2023 16:43:31 -0700 Subject: [PATCH] toolbox/modprobe: Fix fallback path when mod_dirs is empty Due to GKI, the kernel UTS release string will not always (if ever) match the vendor's UTS release string that is used to create the initramfs file structure -- /lib/modules/. This causes module load failures when `-d DIR` is omitted. To fix this, we can include all of the versions under /lib/modules that match the kernel's major and minor version instead of directly using the value of uname(). In addition, we can also support modules being loaded directly from /lib/modules. Test: verify GKI kernel + initramfs with different UTS strings Test: verify GKI kernel + initramfs with modules directly in /lib/modules Fixes: 83207784251c ("toolbox/modprobe: Fallback to /lib/modules/ ") Bug: 282917063 Bug: 254835242 Merged-In: I5368f5cff139ba3165323a6a91066be38bfa0736 Change-Id: I5368f5cff139ba3165323a6a91066be38bfa0736 --- toolbox/modprobe.cpp | 44 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/toolbox/modprobe.cpp b/toolbox/modprobe.cpp index 17f815697..17d4e319b 100644 --- a/toolbox/modprobe.cpp +++ b/toolbox/modprobe.cpp @@ -85,6 +85,26 @@ void MyLogger(android::base::LogId id, android::base::LogSeverity severity, cons } } +// Find directories in format of "/lib/modules/x.y.z-*". +static int KernelVersionNameFilter(const dirent* de) { + unsigned int major, minor; + static std::string kernel_version; + utsname uts; + + if (kernel_version.empty()) { + if ((uname(&uts) != 0) || (sscanf(uts.release, "%u.%u", &major, &minor) != 2)) { + LOG(ERROR) << "Could not parse the kernel version from uname"; + return 0; + } + kernel_version = android::base::StringPrintf("%u.%u", major, minor); + } + + if (android::base::StartsWith(de->d_name, kernel_version)) { + return 1; + } + return 0; +} + } // anonymous namespace extern "C" int modprobe_main(int argc, char** argv) { @@ -192,9 +212,22 @@ extern "C" int modprobe_main(int argc, char** argv) { } if (mod_dirs.empty()) { - utsname uts; - uname(&uts); - mod_dirs.emplace_back(android::base::StringPrintf("/lib/modules/%s", uts.release)); + static constexpr auto LIB_MODULES_PREFIX = "/lib/modules/"; + dirent** kernel_dirs = NULL; + + int n = scandir(LIB_MODULES_PREFIX, &kernel_dirs, KernelVersionNameFilter, NULL); + if (n == -1) { + PLOG(ERROR) << "Failed to scan dir " << LIB_MODULES_PREFIX; + return EXIT_FAILURE; + } else if (n > 0) { + while (n--) { + mod_dirs.emplace_back(LIB_MODULES_PREFIX + std::string(kernel_dirs[n]->d_name)); + } + } + free(kernel_dirs); + + // Allow modules to be directly inside /lib/modules + mod_dirs.emplace_back(LIB_MODULES_PREFIX); } LOG(DEBUG) << "mode is " << mode; @@ -212,11 +245,6 @@ extern "C" int modprobe_main(int argc, char** argv) { return EXIT_FAILURE; } } - if (mod_dirs.empty()) { - LOG(ERROR) << "No module configuration directories given."; - print_usage(); - return EXIT_FAILURE; - } if (parameter_count && modules.size() > 1) { LOG(ERROR) << "Only one module may be loaded when specifying module parameters."; print_usage();