livepatch-patch-hook: ensure compatibility with kernels < 4.7 and >= 4.7

Use dynrelas when kernel version is < 4.7 and klp relas otherwise.
This commit is contained in:
Jessica Yu 2017-01-23 12:43:39 -08:00
parent 0cc693ba36
commit 355996e366

View File

@ -35,6 +35,10 @@
#define UTS_UBUNTU_RELEASE_ABI 0
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0)
#define NEED_KLP_RELOCS
#endif
/*
* There are quite a few similar structures at play in this file:
* - livepatch.h structs prefixed with klp_*
@ -83,7 +87,9 @@ static struct patch_object *patch_alloc_new_object(const char *name)
if (!object)
return NULL;
INIT_LIST_HEAD(&object->funcs);
#ifdef NEED_KLP_RELOCS
INIT_LIST_HEAD(&object->relocs);
#endif
if (strcmp(name, "vmlinux"))
object->name = name;
list_add(&object->list, &patch_objects);
@ -123,6 +129,7 @@ static int patch_add_func_to_object(struct kpatch_patch_func *kfunc)
return 0;
}
#ifdef NEED_KLP_RELOCS
static int patch_add_reloc_to_object(struct kpatch_patch_dynrela *kdynrela)
{
struct patch_reloc *reloc;
@ -143,11 +150,14 @@ static int patch_add_reloc_to_object(struct kpatch_patch_dynrela *kdynrela)
object->relocs_nr++;
return 0;
}
#endif
static void patch_free_scaffold(void) {
struct patch_func *func, *safefunc;
struct patch_reloc *reloc, *safereloc;
struct patch_object *object, *safeobject;
#ifdef NEED_KLP_RELOCS
struct patch_reloc *reloc, *safereloc;
#endif
list_for_each_entry_safe(object, safeobject, &patch_objects, list) {
list_for_each_entry_safe(func, safefunc,
@ -155,11 +165,13 @@ static void patch_free_scaffold(void) {
list_del(&func->list);
kfree(func);
}
#ifdef NEED_KLP_RELOCS
list_for_each_entry_safe(reloc, safereloc,
&object->relocs, list) {
list_del(&reloc->list);
kfree(reloc);
}
#endif
list_del(&object->list);
kfree(object);
}
@ -173,8 +185,10 @@ static void patch_free_livepatch(struct klp_patch *patch)
for (object = patch->objs; object && object->funcs; object++) {
if (object->funcs)
kfree(object->funcs);
#ifdef NEED_KLP_RELOCS
if (object->relocs)
kfree(object->relocs);
#endif
}
if (patch->objs)
kfree(patch->objs);
@ -183,19 +197,23 @@ static void patch_free_livepatch(struct klp_patch *patch)
}
extern struct kpatch_patch_func __kpatch_funcs[], __kpatch_funcs_end[];
#ifdef NEED_KLP_RELOCS
extern struct kpatch_patch_dynrela __kpatch_dynrelas[], __kpatch_dynrelas_end[];
#endif
static int __init patch_init(void)
{
struct kpatch_patch_func *kfunc;
struct kpatch_patch_dynrela *kdynrela;
struct klp_object *lobjects, *lobject;
struct klp_func *lfuncs, *lfunc;
struct klp_reloc *lrelocs, *lreloc;
struct patch_object *object;
struct patch_func *func;
struct patch_reloc *reloc;
int ret = 0, i, j;
#ifdef NEED_KLP_RELOCS
struct kpatch_patch_dynrela *kdynrela;
struct patch_reloc *reloc;
struct klp_reloc *lrelocs, *lreloc;
#endif
/* organize functions and relocs by object in scaffold */
for (kfunc = __kpatch_funcs;
@ -206,6 +224,7 @@ static int __init patch_init(void)
goto out;
}
#ifdef NEED_KLP_RELOCS
for (kdynrela = __kpatch_dynrelas;
kdynrela != __kpatch_dynrelas_end;
kdynrela++) {
@ -213,6 +232,7 @@ static int __init patch_init(void)
if (ret)
goto out;
}
#endif
/* past this point, only possible return code is -ENOMEM */
ret = -ENOMEM;
@ -254,6 +274,7 @@ static int __init patch_init(void)
j++;
}
#ifdef NEED_KLP_RELOCS
lrelocs = kzalloc(sizeof(struct klp_reloc) *
(object->relocs_nr+1), GFP_KERNEL);
if (!lrelocs)
@ -270,13 +291,14 @@ static int __init patch_init(void)
lreloc->sympos = reloc->kdynrela->sympos;
#else
lreloc->val = reloc->kdynrela->src;
#endif
#endif /* 4.5.0 */
lreloc->type = reloc->kdynrela->type;
lreloc->name = reloc->kdynrela->name;
lreloc->addend = reloc->kdynrela->addend;
lreloc->external = reloc->kdynrela->external;
j++;
}
#endif /* 4.7.0 */
i++;
}