mirror of
https://github.com/dynup/kpatch
synced 2024-12-11 16:04:40 +00:00
Merge pull request #217 from jpoimboe/check-page-rw
kmod/core: ensure page is RO before changing its permissions
This commit is contained in:
commit
52c0cd108d
@ -457,15 +457,64 @@ static int kpatch_verify_symbol_match(char *name, unsigned long addr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
for (i = 0; i < kpmod->dynrelas_nr; i++) {
|
||||
dynrela = &kpmod->dynrelas[i];
|
||||
|
||||
ret = kpatch_verify_symbol_match(dynrela->name, dynrela->src);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (dynrela->type) {
|
||||
case R_X86_64_PC32:
|
||||
loc = dynrela->dest;
|
||||
val = (u32)(dynrela->src + dynrela->addend -
|
||||
dynrela->dest);
|
||||
size = 4;
|
||||
break;
|
||||
case R_X86_64_32S:
|
||||
loc = dynrela->dest;
|
||||
val = (s32)dynrela->src + dynrela->addend;
|
||||
size = 4;
|
||||
break;
|
||||
default:
|
||||
printk("unsupported rela type %ld for "
|
||||
"0x%lx <- 0x%lx at index %d\n",
|
||||
dynrela->type, dynrela->dest,
|
||||
dynrela->src, i);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pte = lookup_address(loc, &level);
|
||||
if (!pte_write(*pte)) {
|
||||
readonly = 1;
|
||||
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)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kpatch_register(struct kpatch_module *kpmod, bool replace)
|
||||
{
|
||||
int ret, i;
|
||||
struct kpatch_func *funcs, *func;
|
||||
int num_funcs = kpmod->patches_nr;
|
||||
struct kpatch_dynrela *dynrela;
|
||||
void *loc;
|
||||
u64 val;
|
||||
int size;
|
||||
|
||||
if (!kpmod->mod || !kpmod->patches || !num_funcs)
|
||||
return -EINVAL;
|
||||
@ -490,37 +539,9 @@ int kpatch_register(struct kpatch_module *kpmod, bool replace)
|
||||
goto err_up;
|
||||
}
|
||||
|
||||
for (i = 0; i < kpmod->dynrelas_nr; i++) {
|
||||
dynrela = &kpmod->dynrelas[i];
|
||||
ret = kpatch_verify_symbol_match(dynrela->name, dynrela->src);
|
||||
if (ret)
|
||||
goto err_put;
|
||||
switch (dynrela->type) {
|
||||
case R_X86_64_PC32:
|
||||
loc = (void *)dynrela->dest;
|
||||
val = (u32)(dynrela->src + dynrela->addend -
|
||||
dynrela->dest);
|
||||
size = 4;
|
||||
break;
|
||||
case R_X86_64_32S:
|
||||
loc = (void *)dynrela->dest;
|
||||
val = (s32)dynrela->src + dynrela->addend;
|
||||
size = 4;
|
||||
break;
|
||||
default:
|
||||
printk("unsupported rela type %ld for "
|
||||
"0x%lx <- 0x%lx at index %d\n",
|
||||
dynrela->type, dynrela->dest,
|
||||
dynrela->src, i);
|
||||
ret = -EINVAL;
|
||||
goto err_put;
|
||||
}
|
||||
set_memory_rw((unsigned long)loc & PAGE_MASK, 1);
|
||||
ret = probe_kernel_write(loc, &val, size);
|
||||
set_memory_ro((unsigned long)loc & PAGE_MASK, 1);
|
||||
if (ret)
|
||||
goto err_put;
|
||||
}
|
||||
ret = kpatch_write_relocations(kpmod);
|
||||
if (ret)
|
||||
goto err_put;
|
||||
|
||||
for (i = 0; i < num_funcs; i++) {
|
||||
func = &funcs[i];
|
||||
|
Loading…
Reference in New Issue
Block a user