From patchwork Thu Aug 4 15:49:22 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Konrad Rzeszutek Wilk X-Patchwork-Id: 9263867 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 630996048F for ; Thu, 4 Aug 2016 15:52:20 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 51E8D28409 for ; Thu, 4 Aug 2016 15:52:20 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 467AC2840D; Thu, 4 Aug 2016 15:52:20 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 27B7828409 for ; Thu, 4 Aug 2016 15:52:19 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1bVKtx-0002AX-4q; Thu, 04 Aug 2016 15:49:41 +0000 Received: from mail6.bemta3.messagelabs.com ([195.245.230.39]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1bVKtv-0002AK-Uq for xen-devel@lists.xenproject.org; Thu, 04 Aug 2016 15:49:40 +0000 Received: from [85.158.137.68] by server-1.bemta-3.messagelabs.com id 13/D8-17152-31463A75; Thu, 04 Aug 2016 15:49:39 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFmplkeJIrShJLcpLzFFi42LpnVTnqiuUsjj cYMo1GYvvWyYzOTB6HP5whSWAMYo1My8pvyKBNaP/ZAd7wRaPigerHBsY71l3MXJxCAm0M0ls eneLuYuRE8j5yijxqZ0LIrGBUeLXgTmMEE43o8T3TWvZuxg5gJwiie6GehCTTcBE4s0qR5BeE QFTiYU7JzGBlDMLzGOW+HtoMRNIQljAT+LGrldsIDaLgKrE+u99rCA2r4CbxPl/L8BsCQE5iW 1b9jCC2JwC7hIH1u5hhTjITeLI9i4miBpjifa3F9kmMPIvYGRYxahenFpUllqka6KXVJSZnlG Sm5iZo2toYKyXm1pcnJiempOYVKyXnJ+7iREYPAxAsIOx8YvTIUZJDiYlUd4ZAYvDhfiS8lMq MxKLM+KLSnNSiw8xynBwKEnwdiUB5QSLUtNTK9Iyc4BhDJOW4OBREuHdBZLmLS5IzC3OTIdIn WJUlBLnvQ2SEABJZJTmwbXBYucSo6yUMC8j0CFCPAWpRbmZJajyrxjFORiVhHlbQabwZOaVwE 1/BbSYCWjxCYMFIItLEhFSUg2MbRvblNqOplq+DpI75Xt+n5Qxz1bbJVKPNz4U+5cUodlys6v wx6foTz9Sz2XtWL3CZl3vqctPZ/yR7ZjRfWPbdNWpug8FtYvVu05IyO7+0xAQkPEhP+CZuIDr g3WSsv/mNSg/OHZM1OWpQa3op6dxn8Xm3whMMrT4P3e/itkCo4380d+33Z+tosRSnJFoqMVcV JwIAJOvVTGYAgAA X-Env-Sender: konrad@char.us.oracle.com X-Msg-Ref: server-2.tower-31.messagelabs.com!1470325776!54007537!1 X-Originating-IP: [141.146.126.69] X-SpamReason: No, hits=0.0 required=7.0 tests=sa_preprocessor: VHJ1c3RlZCBJUDogMTQxLjE0Ni4xMjYuNjkgPT4gMjc3MjE4\n X-StarScan-Received: X-StarScan-Version: 8.77; banners=-,-,- X-VirusChecked: Checked Received: (qmail 57670 invoked from network); 4 Aug 2016 15:49:38 -0000 Received: from aserp1040.oracle.com (HELO aserp1040.oracle.com) (141.146.126.69) by server-2.tower-31.messagelabs.com with DHE-RSA-AES256-GCM-SHA384 encrypted SMTP; 4 Aug 2016 15:49:38 -0000 Received: from aserv0022.oracle.com (aserv0022.oracle.com [141.146.126.234]) by aserp1040.oracle.com (Sentrion-MTA-4.3.2/Sentrion-MTA-4.3.2) with ESMTP id u74FnSQD025049 (version=TLSv1 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Thu, 4 Aug 2016 15:49:28 GMT Received: from aserv0121.oracle.com (aserv0121.oracle.com [141.146.126.235]) by aserv0022.oracle.com (8.13.8/8.13.8) with ESMTP id u74FnRK3025498 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Thu, 4 Aug 2016 15:49:27 GMT Received: from abhmp0010.oracle.com (abhmp0010.oracle.com [141.146.116.16]) by aserv0121.oracle.com (8.13.8/8.13.8) with ESMTP id u74FnRj4029246; Thu, 4 Aug 2016 15:49:27 GMT Received: from char.us.oracle.com (/10.137.176.158) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Thu, 04 Aug 2016 08:49:26 -0700 Received: by char.us.oracle.com (Postfix, from userid 1000) id 9AFF06A013F; Thu, 4 Aug 2016 11:49:25 -0400 (EDT) From: Konrad Rzeszutek Wilk To: konrad@kernel.org, xen-devel@lists.xenproject.org Date: Thu, 4 Aug 2016 11:49:22 -0400 Message-Id: <1470325764-12566-2-git-send-email-konrad.wilk@oracle.com> X-Mailer: git-send-email 2.5.5 In-Reply-To: <1470325764-12566-1-git-send-email-konrad.wilk@oracle.com> References: <1470325764-12566-1-git-send-email-konrad.wilk@oracle.com> X-Source-IP: aserv0022.oracle.com [141.146.126.234] Cc: Stefano Stabellini , Wei Liu , Konrad Rzeszutek Wilk , George Dunlap , Andrew Cooper , Ian Jackson , Tim Deegan , Ross Lagerwall , Jan Beulich Subject: [Xen-devel] [PATCH v2 1/3] livepach: Add .livepatch.hooks functions and test-case X-BeenThere: xen-devel@lists.xen.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: xen-devel-bounces@lists.xen.org Sender: "Xen-devel" X-Virus-Scanned: ClamAV using ClamSMTP From: Ross Lagerwall Add hook functions which run during patch apply and patch revert. Hook functions are used by livepatch payloads to manipulate data structures during patching, etc. One use case is the XSA91. As Martin mentions it: "If we have shadow variables, we also need an unload hook to garbage collect all the variables introduced by a hotpatch to prevent memory leaks. Potentially, we also want to pre-reserve memory for static or existing dynamic objects in the load-hook instead of on the fly. For testing and debugging, various applications are possible. In general, the hooks provide flexibility when having to deal with unforeseen cases, but their application should be rarely required (< 10%)." Furthermore include a test-case for it. Signed-off-by: Ross Lagerwall Signed-off-by: Konrad Rzeszutek Wilk --- v12: s/xsplice/livepatch/ Cc: Andrew Cooper Cc: George Dunlap Cc: Ian Jackson Cc: Jan Beulich Cc: Stefano Stabellini Cc: Tim Deegan Cc: Wei Liu --- docs/misc/livepatch.markdown | 23 +++++++++++++++++ xen/arch/x86/test/xen_hello_world.c | 36 ++++++++++++++++++++++++++ xen/common/livepatch.c | 50 ++++++++++++++++++++++++++++++++++++- xen/include/xen/livepatch_payload.h | 49 ++++++++++++++++++++++++++++++++++++ 4 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 xen/include/xen/livepatch_payload.h diff --git a/docs/misc/livepatch.markdown b/docs/misc/livepatch.markdown index 89c1050..e0fc5e4 100644 --- a/docs/misc/livepatch.markdown +++ b/docs/misc/livepatch.markdown @@ -340,6 +340,13 @@ When reverting a patch, the hypervisor iterates over each `livepatch_func` and the core code copies the data from the undo buffer (private internal copy) to `old_addr`. +It optionally may contain the address of functions to be called right before +being applied and after being reverted: + + * `.livepatch.hooks.load` - an array of function pointers. + * `.livepatch.hooks.unload` - an array of function pointers. + + ### Example of .livepatch.funcs A simple example of what a payload file can be: @@ -377,6 +384,22 @@ struct livepatch_func livepatch_hello_world = { Code must be compiled with -fPIC. +### .livepatch.hooks.load and .livepatch.hooks.unload + +This section contains an array of function pointers to be executed +before payload is being applied (.livepatch.funcs) or after reverting +the payload. This is useful to prepare data structures that need to +be modified patching. + +Each entry in this array is eight bytes. + +The type definition of the function are as follow: + +
+typedef void (*livepatch_loadcall_t)(void);  
+typedef void (*livepatch_unloadcall_t)(void);   
+
+ ### .livepatch.depends and .note.gnu.build-id To support dependencies checking and safe loading (to load the diff --git a/xen/arch/x86/test/xen_hello_world.c b/xen/arch/x86/test/xen_hello_world.c index 422bdf1..e6a095b 100644 --- a/xen/arch/x86/test/xen_hello_world.c +++ b/xen/arch/x86/test/xen_hello_world.c @@ -4,14 +4,50 @@ */ #include "config.h" +#include #include #include #include +#include #include static char hello_world_patch_this_fnc[] = "xen_extra_version"; extern const char *xen_hello_world(void); +static unsigned int cnt; + +static void apply_hook(void) +{ + printk(KERN_DEBUG "Hook executing.\n"); +} + +static void revert_hook(void) +{ + printk(KERN_DEBUG "Hook unloaded.\n"); +} + +static void hi_func(void) +{ + printk(KERN_DEBUG "%s: Hi! (called %u times)\n", __func__, ++cnt); +}; + +/* If we are sorted we _MUST_ be the last .livepatch.hook section. */ +static void Z_check_fnc(void) +{ + printk(KERN_DEBUG "%s: Hi func called %u times\n", __func__, cnt); + BUG_ON(cnt == 0 || cnt > 2); + cnt = 0; /* Otherwise if you revert, apply, revert the value will be 4! */ +} + +LIVEPATCH_LOAD_HOOK(apply_hook); +LIVEPATCH_UNLOAD_HOOK(revert_hook); + +/* Imbalance here. Two load and three unload. */ + +LIVEPATCH_LOAD_HOOK(hi_func); +LIVEPATCH_UNLOAD_HOOK(hi_func); + +LIVEPATCH_UNLOAD_HOOK(Z_check_fnc); struct livepatch_func __section(".livepatch.funcs") livepatch_xen_hello_world = { .version = LIVEPATCH_PAYLOAD_VERSION, diff --git a/xen/common/livepatch.c b/xen/common/livepatch.c index 5da28a3..f6dbd51 100644 --- a/xen/common/livepatch.c +++ b/xen/common/livepatch.c @@ -23,6 +23,7 @@ #include #include #include +#include #include @@ -70,7 +71,11 @@ struct payload { unsigned int nsyms; /* Nr of entries in .strtab and symbols. */ struct livepatch_build_id id; /* ELFNOTE_DESC(.note.gnu.build-id) of the payload. */ struct livepatch_build_id dep; /* ELFNOTE_DESC(.livepatch.depends). */ - char name[XEN_LIVEPATCH_NAME_SIZE]; /* Name of it. */ + livepatch_loadcall_t **load_funcs; /* The array of funcs to call after */ + livepatch_unloadcall_t **unload_funcs;/* load and unload of the payload. */ + unsigned int n_load_funcs; /* Nr of the funcs to load and execute. */ + unsigned int n_unload_funcs; /* Nr of funcs to call durung unload. */ + char name[XEN_LIVEPATCH_NAME_SIZE]; /* Name of it. */ }; /* Defines an outstanding patching action. */ @@ -515,6 +520,27 @@ static int prepare_payload(struct payload *payload, } } + sec = livepatch_elf_sec_by_name(elf, ".livepatch.hooks.load"); + if ( sec ) + { + if ( !sec->sec->sh_size || + (sec->sec->sh_size % sizeof(*payload->load_funcs)) ) + return -EINVAL; + + payload->load_funcs = sec->load_addr; + payload->n_load_funcs = sec->sec->sh_size / sizeof(*payload->load_funcs); + } + + sec = livepatch_elf_sec_by_name(elf, ".livepatch.hooks.unload"); + if ( sec ) + { + if ( !sec->sec->sh_size || + (sec->sec->sh_size % sizeof(*payload->unload_funcs)) ) + return -EINVAL; + + payload->unload_funcs = sec->load_addr; + payload->n_unload_funcs = sec->sec->sh_size / sizeof(*payload->unload_funcs); + } sec = livepatch_elf_sec_by_name(elf, ELF_BUILD_ID_NOTE); if ( sec ) { @@ -999,6 +1025,17 @@ static int apply_payload(struct payload *data) arch_livepatch_quiesce(); + /* + * The hooks may call common code which expects spinlocks to be certain + * type, as such disable this temporarily. + */ + spin_debug_disable(); + for ( i = 0; i < data->n_load_funcs; i++ ) + data->load_funcs[i](); + spin_debug_enable(); + + ASSERT(!local_irq_is_enabled()); + for ( i = 0; i < data->nfuncs; i++ ) arch_livepatch_apply_jmp(&data->funcs[i]); @@ -1025,6 +1062,17 @@ static int revert_payload(struct payload *data) for ( i = 0; i < data->nfuncs; i++ ) arch_livepatch_revert_jmp(&data->funcs[i]); + /* + * The hooks may call common code which expects spinlocks to be certain + * type, as such disable this temporarily. + */ + spin_debug_disable(); + for ( i = 0; i < data->n_unload_funcs; i++ ) + data->unload_funcs[i](); + spin_debug_enable(); + + ASSERT(!local_irq_is_enabled()); + arch_livepatch_revive(); /* diff --git a/xen/include/xen/livepatch_payload.h b/xen/include/xen/livepatch_payload.h new file mode 100644 index 0000000..cebf568 --- /dev/null +++ b/xen/include/xen/livepatch_payload.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2016 Citrix Systems R&D Ltd. + */ + +#ifndef __XEN_LIVEPATCH_PAYLOAD_H__ +#define __XEN_LIVEPATCH_PAYLOAD_H__ + +/* + * The following definitions are to be used in patches. They are taken + * from kpatch. + */ +typedef void livepatch_loadcall_t(void); +typedef void livepatch_unloadcall_t(void); + +/* + * LIVEPATCH_LOAD_HOOK macro + * + * Declares a function pointer to be allocated in a new + * .livepatch.hook.load section. This livepatch_load_data symbol is later + * stripped by create-diff-object so that it can be declared in multiple + * objects that are later linked together, avoiding global symbol + * collision. Since multiple hooks can be registered, the + * .livepatch.hook.load section is a table of functions that will be + * executed in series by the livepatch infrastructure at patch load time. + */ +#define LIVEPATCH_LOAD_HOOK(_fn) \ + livepatch_loadcall_t *__attribute__((weak)) \ + livepatch_load_data_##_fn __section(".livepatch.hooks.load") = _fn; + +/* + * LIVEPATCH_UNLOAD_HOOK macro + * + * Same as LOAD hook with s/load/unload/ + */ +#define LIVEPATCH_UNLOAD_HOOK(_fn) \ + livepatch_unloadcall_t *__attribute__((weak)) \ + livepatch_unload_data_##_fn __section(".livepatch.hooks.unload") = _fn; + +#endif /* __XEN_LIVEPATCH_PAYLOAD_H__ */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */