From ecf6173869ebaa899dd5a03bdb1c1b385f5cda83 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Fri, 30 May 2014 09:24:38 -0500 Subject: [PATCH] kmod/core: validate dynrela destination address Ensure that dynrela destination addresses are within the patch module's memory. Also, use the module address ranges to check whether set_memory_rw() is needed. --- kmod/core/core.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/kmod/core/core.c b/kmod/core/core.c index 8d09d20..b22b40f 100644 --- a/kmod/core/core.c +++ b/kmod/core/core.c @@ -462,8 +462,9 @@ static int kpatch_write_relocations(struct kpatch_module *kpmod) int ret, i, size, readonly = 0; struct kpatch_dynrela *dynrela; u64 loc, val; - pte_t *pte; - unsigned int level; + unsigned long core = (unsigned long)kpmod->mod->module_core; + unsigned long core_ro_size = kpmod->mod->core_ro_size; + unsigned long core_size = kpmod->mod->core_size; for (i = 0; i < kpmod->dynrelas_nr; i++) { dynrela = &kpmod->dynrelas[i]; @@ -492,19 +493,29 @@ static int kpatch_write_relocations(struct kpatch_module *kpmod) return -EINVAL; } - pte = lookup_address(loc, &level); - if (!pte_write(*pte)) { + if (loc >= core && loc < core + core_ro_size) readonly = 1; - set_memory_rw(loc & PAGE_MASK, 1); + else if (loc >= core + core_ro_size && loc < core + core_size) + readonly = 0; + else { + pr_err("bad dynrela location 0x%llx for symbol %s\n", + loc, dynrela->name); + return -EINVAL; } + if (readonly) + set_memory_rw(loc & PAGE_MASK, 1); + ret = probe_kernel_write((void *)loc, &val, size); if (readonly) set_memory_ro(loc & PAGE_MASK, 1); - if (ret) + if (ret) { + pr_err("write to 0x%llx failed for symbol %s\n", + loc, dynrela->name); return ret; + } } return 0;