Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752898AbbEDLlQ (ORCPT ); Mon, 4 May 2015 07:41:16 -0400 Received: from ip4-83-240-67-251.cust.nbox.cz ([83.240.67.251]:50909 "EHLO ip4-83-240-18-248.cust.nbox.cz" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1751922AbbEDLk2 (ORCPT ); Mon, 4 May 2015 07:40:28 -0400 From: Jiri Slaby To: live-patching@vger.kernel.org Cc: jpoimboe@redhat.com, sjenning@redhat.com, jkosina@suse.cz, vojtech@suse.cz, mingo@redhat.com, linux-kernel@vger.kernel.org, Jiri Slaby Subject: [RFC kgr on klp 5/9] livepatch: teach klp about consistency models Date: Mon, 4 May 2015 13:40:21 +0200 Message-Id: <1430739625-4658-5-git-send-email-jslaby@suse.cz> X-Mailer: git-send-email 2.3.5 In-Reply-To: <1430739625-4658-1-git-send-email-jslaby@suse.cz> References: <1430739625-4658-1-git-send-email-jslaby@suse.cz> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 8660 Lines: 287 We want more concise consistency models than simple is. This is a preparation for other, more complex ones. It moves the simple handling out of ftrace handler and is called as newly introduced struct klp_cmodel->stub. This way, every model can implement its own handler. On the top of that, I assume the structure will be extended over time. For example, kGraft-like patching will need pre-patch and post-patch hooks and more. We store the models in a list and all have its ID, specified in every patch. The ID is then looked up in the list and appropriate cmodel used. Signed-off-by: Jiri Slaby --- include/linux/livepatch.h | 35 ++++++++++++++++++++++++++++++++ kernel/livepatch/Makefile | 2 +- kernel/livepatch/cmodel-simple.c | 39 ++++++++++++++++++++++++++++++++++++ kernel/livepatch/core.c | 37 ++++++++++++++++++++++++++++++---- samples/livepatch/livepatch-sample.c | 1 + 5 files changed, 109 insertions(+), 5 deletions(-) create mode 100644 kernel/livepatch/cmodel-simple.c diff --git a/include/linux/livepatch.h b/include/linux/livepatch.h index fabb067a3f1d..009f308ff756 100644 --- a/include/linux/livepatch.h +++ b/include/linux/livepatch.h @@ -23,11 +23,36 @@ #include #include +#include #if IS_ENABLED(CONFIG_LIVEPATCH) #include +struct klp_func; + +/** + * enum klp_cmodel_id - possible consistency models + */ +enum klp_cmodel_id { + KLP_CM_INVALID = 0, + KLP_CM_SIMPLE, /* LEAVE_FUNCTION and SWITCH_FUNCTION */ +}; + +/** + * struct klp_cmodel - implementation of a consistency model + * @id: id of this model (from enum klp_cmodel_id) + * @list: member of klp_cmodel_list + * @stub: what to use as an ftrace handler (annotate with notrace!) + */ +struct klp_cmodel { + const enum klp_cmodel_id id; + struct list_head list; + + void (*stub)(struct list_head *func_stack, struct klp_func *func, + struct pt_regs *regs); +}; + enum klp_state { KLP_DISABLED, KLP_ENABLED @@ -42,6 +67,7 @@ enum klp_state { * @kobj: kobject for sysfs resources * @state: tracks function-level patch application state * @stack_node: list node for klp_ops func_stack list + * @stub: cache of klp_patch.cmodel.stub */ struct klp_func { /* external */ @@ -61,6 +87,8 @@ struct klp_func { struct kobject kobj; enum klp_state state; struct list_head stack_node; + void (*stub)(struct list_head *func_stack, struct klp_func *func, + struct pt_regs *regs); }; /** @@ -108,19 +136,23 @@ struct klp_object { * struct klp_patch - patch structure for live patching * @mod: reference to the live patch module * @objs: object entries for kernel objects to be patched + * @cmodel_id: consistency model used to apply this patch * @list: list node for global list of registered patches * @kobj: kobject for sysfs resources * @state: tracks patch-level application state + * @cmodel: cmodel_id's implementation */ struct klp_patch { /* external */ struct module *mod; struct klp_object *objs; + const enum klp_cmodel_id cmodel_id; /* internal */ struct list_head list; struct kobject kobj; enum klp_state state; + struct klp_cmodel *cmodel; }; #define klp_for_each_object(patch, obj) \ @@ -144,6 +176,9 @@ int klp_unregister_patch(struct klp_patch *); int klp_enable_patch(struct klp_patch *); int klp_disable_patch(struct klp_patch *); +void klp_init_cmodel_simple(void); +void klp_register_cmodel(struct klp_cmodel *); + #endif /* CONFIG_LIVEPATCH */ #endif /* _LINUX_LIVEPATCH_H_ */ diff --git a/kernel/livepatch/Makefile b/kernel/livepatch/Makefile index e8780c0901d9..926533777247 100644 --- a/kernel/livepatch/Makefile +++ b/kernel/livepatch/Makefile @@ -1,3 +1,3 @@ obj-$(CONFIG_LIVEPATCH) += livepatch.o -livepatch-objs := core.o +livepatch-objs := core.o cmodel-simple.o diff --git a/kernel/livepatch/cmodel-simple.c b/kernel/livepatch/cmodel-simple.c new file mode 100644 index 000000000000..d4e430ff40c0 --- /dev/null +++ b/kernel/livepatch/cmodel-simple.c @@ -0,0 +1,39 @@ +/* + * cmodel-simple.c - KLP Simple Consistency Model + * + * Copyright (C) 2015 Seth Jennings + * Copyright (C) 2015 SUSE + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include +#include +#include + +static void notrace klp_simple_stub(struct list_head *func_stack, + struct klp_func *func, struct pt_regs *regs) +{ + klp_arch_set_pc(regs, (unsigned long)func->new_func); +} + +static struct klp_cmodel klp_simple_model = { + .id = KLP_CM_SIMPLE, + .stub = klp_simple_stub, +}; + +void klp_init_cmodel_simple(void) +{ + klp_register_cmodel(&klp_simple_model); +} diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c index 2da42be84452..ab6a36688c93 100644 --- a/kernel/livepatch/core.c +++ b/kernel/livepatch/core.c @@ -58,6 +58,7 @@ static DEFINE_MUTEX(klp_mutex); static LIST_HEAD(klp_patches); static LIST_HEAD(klp_ops); +static LIST_HEAD(klp_cmodel_list); static struct kobject *klp_root_kobj; @@ -319,18 +320,16 @@ static void notrace klp_ftrace_handler(unsigned long ip, struct ftrace_ops *fops, struct pt_regs *regs) { - struct klp_ops *ops; + struct klp_ops *ops = container_of(fops, struct klp_ops, fops); struct klp_func *func; - ops = container_of(fops, struct klp_ops, fops); - rcu_read_lock(); func = list_first_or_null_rcu(&ops->func_stack, struct klp_func, stack_node); if (WARN_ON_ONCE(!func)) goto unlock; - klp_arch_set_pc(regs, (unsigned long)func->new_func); + func->stub(&ops->func_stack, func, regs); unlock: rcu_read_unlock(); } @@ -720,6 +719,7 @@ static int klp_init_func(struct klp_object *obj, struct klp_func *func) { INIT_LIST_HEAD(&func->stack_node); func->state = KLP_DISABLED; + func->stub = klp_object_to_patch(obj)->cmodel->stub; return kobject_init_and_add(&func->kobj, &klp_ktype_func, &obj->kobj, "%s", func->old_name); @@ -790,13 +790,28 @@ free: static int klp_init_patch(struct klp_patch *patch) { struct klp_object *obj; + struct klp_cmodel *cm, *cmodel = NULL; int ret; if (!patch->objs) return -EINVAL; + list_for_each_entry(cm, &klp_cmodel_list, list) { + if (patch->cmodel_id == cm->id) { + cmodel = cm; + break; + } + } + + if (!cmodel) { + pr_err("%s: patch '%ps' requires unknown consistency model %d\n", + __func__, patch, patch->cmodel_id); + return -EINVAL; + } + mutex_lock(&klp_mutex); + patch->cmodel = cmodel; patch->state = KLP_DISABLED; ret = kobject_init_and_add(&patch->kobj, &klp_ktype_patch, @@ -893,6 +908,18 @@ int klp_register_patch(struct klp_patch *patch) } EXPORT_SYMBOL_GPL(klp_register_patch); +/** + * klp_register_cmodel - register a consistency model + * @model: model to register + * + * This functions has to be synchronously called before klp_root_kobj is + * created in klp_init since we use no locking. + */ +void klp_register_cmodel(struct klp_cmodel *model) +{ + list_add_tail(&model->list, &klp_cmodel_list); +} + static void klp_module_notify_coming(struct klp_patch *patch, struct klp_object *obj) { @@ -993,6 +1020,8 @@ static int klp_init(void) return -EINVAL; } + klp_init_cmodel_simple(); + ret = register_module_notifier(&klp_module_nb); if (ret) return ret; diff --git a/samples/livepatch/livepatch-sample.c b/samples/livepatch/livepatch-sample.c index fb8c8614e728..48621de040db 100644 --- a/samples/livepatch/livepatch-sample.c +++ b/samples/livepatch/livepatch-sample.c @@ -63,6 +63,7 @@ static struct klp_object objs[] = { static struct klp_patch patch = { .mod = THIS_MODULE, .objs = objs, + .cmodel_id = KLP_CM_SIMPLE, }; static int livepatch_init(void) -- 2.3.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/