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
This commit is contained in:
Will Deacon 2024-05-31 17:25:49 +00:00
parent 4e1776cedf
commit c991c3dbed

View file

@ -17,6 +17,7 @@
#include <ctype.h>
#include <getopt.h>
#include <stdlib.h>
#include <unistd.h>
#include <string>
@ -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;
}