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