ANDROID: arm64: module: preserve RELA sections for FIPS140 integrity selfcheck
The FIPS 140-2 integrity check compares the runtime code with a digest that was created at build time. Given that the module's placement in virtual memory is an a priori unknown, we cannot account for this at build time, and so we need to do so at runtime instead. In order to revert the code to the build time state, we need to know which changes the module loader applied to it. These changes are based on the RELA ELF section that describes the changes that the module loader must apply, and so to unapply these changes, we need to preserve the RELA section when loading the module. So add a special case for a module called 'fips140' in the module loader, and copy the RELA sections applying to .text and .rodata to a temporary buffer that the fips140.ko init code can access. Bug: 153614920 Bug: 188620248 Change-Id: I97d69053c6657b104a3a9ea10af78a53ce52c6e5 Signed-off-by: Ard Biesheuvel <ardb@google.com>
This commit is contained in:

committed by
Ard Biesheuvel

parent
15f0fc91e1
commit
254da9ba36
@@ -7,6 +7,7 @@
|
||||
#include <linux/ftrace.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sort.h>
|
||||
|
||||
static struct plt_entry __get_adrp_add_pair(u64 dst, u64 pc,
|
||||
@@ -290,6 +291,7 @@ static int partition_branch_plt_relas(Elf64_Sym *syms, Elf64_Rela *rela,
|
||||
int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
|
||||
char *secstrings, struct module *mod)
|
||||
{
|
||||
bool copy_rela_for_fips140 = false;
|
||||
unsigned long core_plts = 0;
|
||||
unsigned long init_plts = 0;
|
||||
Elf64_Sym *syms = NULL;
|
||||
@@ -321,6 +323,10 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_CRYPTO_FIPS140) &&
|
||||
!strcmp(mod->name, "fips140"))
|
||||
copy_rela_for_fips140 = true;
|
||||
|
||||
for (i = 0; i < ehdr->e_shnum; i++) {
|
||||
Elf64_Rela *rels = (void *)ehdr + sechdrs[i].sh_offset;
|
||||
int nents, numrels = sechdrs[i].sh_size / sizeof(Elf64_Rela);
|
||||
@@ -329,10 +335,38 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
|
||||
if (sechdrs[i].sh_type != SHT_RELA)
|
||||
continue;
|
||||
|
||||
#ifdef CONFIG_CRYPTO_FIPS140
|
||||
if (copy_rela_for_fips140 &&
|
||||
!strcmp(secstrings + dstsec->sh_name, ".rodata")) {
|
||||
void *p = kmemdup(rels, numrels * sizeof(Elf64_Rela),
|
||||
GFP_KERNEL);
|
||||
if (!p) {
|
||||
pr_err("fips140: failed to allocate .rodata RELA buffer\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
mod->arch.rodata_relocations = p;
|
||||
mod->arch.num_rodata_relocations = numrels;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ignore relocations that operate on non-exec sections */
|
||||
if (!(dstsec->sh_flags & SHF_EXECINSTR))
|
||||
continue;
|
||||
|
||||
#ifdef CONFIG_CRYPTO_FIPS140
|
||||
if (copy_rela_for_fips140 &&
|
||||
!strcmp(secstrings + dstsec->sh_name, ".text")) {
|
||||
void *p = kmemdup(rels, numrels * sizeof(Elf64_Rela),
|
||||
GFP_KERNEL);
|
||||
if (!p) {
|
||||
pr_err("fips140: failed to allocate .text RELA buffer\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
mod->arch.text_relocations = p;
|
||||
mod->arch.num_text_relocations = numrels;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* sort branch relocations requiring a PLT by type, symbol index
|
||||
* and addend
|
||||
|
Reference in New Issue
Block a user