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:
Ard Biesheuvel
2021-04-07 11:00:47 +02:00
committed by Ard Biesheuvel
parent 15f0fc91e1
commit 254da9ba36

View File

@@ -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