From patchwork Wed Sep 21 16:57:10 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: 9343957 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 5E4CC607D4 for ; Wed, 21 Sep 2016 16:59:55 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 5F2AF2A80C for ; Wed, 21 Sep 2016 16:59:55 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 53D872A80E; Wed, 21 Sep 2016 16:59:55 +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 880A72A80C for ; Wed, 21 Sep 2016 16:59:54 +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 1bmkq4-0000Jv-2q; Wed, 21 Sep 2016 16:57:40 +0000 Received: from mail6.bemta3.messagelabs.com ([195.245.230.39]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1bmkq2-0000Ii-JW for xen-devel@lists.xenproject.org; Wed, 21 Sep 2016 16:57:38 +0000 Received: from [85.158.137.68] by server-6.bemta-3.messagelabs.com id F9/9C-28813-10CB2E75; Wed, 21 Sep 2016 16:57:37 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFvrOLMWRWlGSWpSXmKPExsXSO6nOVZdxz6N wg/PtrBbft0xmcmD0OPzhCksAYxRrZl5SfkUCa8aesy2sBdt8K1YfUWhgvGnfxcjFISQwmUni y9tdjBDOb0aJRQ1L2SCcjYwS5+/sYYdwZjFK3OntYO1i5OBgEzCReLPKsYuRk0NEIEKib+prR hCbWeASk8TdczIgtrCAn8SXi/eYQcpZBFQlfjWkg4R5Bdwkfq5dxA4SlhCQl3h2ux4kzCngLv Hx3XYWkLAQUMmCH6kgYQkBY4n2txfZJjDyLWBkWMWoXpxaVJZapGuhl1SUmZ5RkpuYmaNraGC sl5taXJyYnpqTmFSsl5yfu4kRGCAMQLCD8UK78yFGSQ4mJVHe7i2PwoX4kvJTKjMSizPii0pz UosPMcpwcChJ8NbuAsoJFqWmp1akZeYAQxUmLcHBoyTC6wuS5i0uSMwtzkyHSJ1iVJQS590Ok hAASWSU5sG1weLjEqOslDAvI9AhQjwFqUW5mSWo8q8YxTkYlYR5dXcDTeHJzCuBm/4KaDET0O ItPx+ALC5JREhJNTBOW7ZnSvEu/yVHbadc3Dqz8tmZi9lrfwXO/nvV6OQuj0/L3hUXFEuEhhx /Llh9sNslU93uUk3c0RQOjnvzH8Rv+nXOy8k8e5end03LI97eeaZbsmwfl4md4Fslt9pH563W AsVdxevtt1iVrH7EcO2we/CmD7vaNpYYBUj9aHffXLF1J2POlD2uSizFGYmGWsxFxYkAfTVu0 4oCAAA= X-Env-Sender: konrad.wilk@oracle.com X-Msg-Ref: server-8.tower-31.messagelabs.com!1474477055!62024762!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.84; banners=-,-,- X-VirusChecked: Checked Received: (qmail 15236 invoked from network); 21 Sep 2016 16:57:36 -0000 Received: from aserp1040.oracle.com (HELO aserp1040.oracle.com) (141.146.126.69) by server-8.tower-31.messagelabs.com with DHE-RSA-AES256-GCM-SHA384 encrypted SMTP; 21 Sep 2016 16:57:36 -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 u8LGvQAb003304 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Wed, 21 Sep 2016 16:57:27 GMT Received: from userv0122.oracle.com (userv0122.oracle.com [156.151.31.75]) by aserv0022.oracle.com (8.14.4/8.14.4) with ESMTP id u8LGvQ5h011109 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Wed, 21 Sep 2016 16:57:26 GMT Received: from abhmp0007.oracle.com (abhmp0007.oracle.com [141.146.116.13]) by userv0122.oracle.com (8.14.4/8.14.4) with ESMTP id u8LGvP8l016883; Wed, 21 Sep 2016 16:57:25 GMT Received: from localhost.localdomain.localdomain (/172.58.216.202) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Wed, 21 Sep 2016 09:57:25 -0700 From: Konrad Rzeszutek Wilk To: konrad@kernel.org, xen-devel@lists.xenproject.org, ross.lagerwall@citrix.com Date: Wed, 21 Sep 2016 12:57:10 -0400 Message-Id: <1474477030-10722-6-git-send-email-konrad.wilk@oracle.com> X-Mailer: git-send-email 2.4.11 In-Reply-To: <1474477030-10722-1-git-send-email-konrad.wilk@oracle.com> References: <1474477030-10722-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.cooper3@citrix.com, Ian Jackson , Tim Deegan , Jan Beulich Subject: [Xen-devel] [PATCH v7 5/5] 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. Reviewed-by: Andrew Cooper Signed-off-by: Ross Lagerwall Signed-off-by: Konrad Rzeszutek Wilk --- Cc: Andrew Cooper Cc: George Dunlap Cc: Ian Jackson Cc: Jan Beulich Cc: Stefano Stabellini Cc: Tim Deegan Cc: Wei Liu v0.4..v0.11: Defered for v4.8 v0.12: s/xsplice/livepatch/ v3: Clarify the comments about spin_debug_enable Rename one of the hooks to lower-case (Z->z) to guarantee it being called last. Learned a lot of about 'const' v4: Do the actual const of the hooks. Remove the requirement for the tests-case hooks to be sorted (they never were to start with). Fix up the comment about spin_debug_enable so more. v5: Added Reviewed-by from Andrew. Dropped the check_fnc hook Added the check_fnc hook back again as "livepatch: Disallow applying after an revert" guarantees we won't hit the BUG_ON check. --- docs/misc/livepatch.markdown | 23 +++++++++++++++++ xen/arch/x86/test/xen_hello_world.c | 34 +++++++++++++++++++++++++ xen/common/livepatch.c | 50 ++++++++++++++++++++++++++++++++++++- xen/include/xen/livepatch_payload.h | 49 ++++++++++++++++++++++++++++++++++++ 4 files changed, 155 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 37a0860..f2ae52a 100644 --- a/docs/misc/livepatch.markdown +++ b/docs/misc/livepatch.markdown @@ -351,6 +351,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: @@ -388,6 +395,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 d80963e..02f3f85 100644 --- a/xen/arch/x86/test/xen_hello_world.c +++ b/xen/arch/x86/test/xen_hello_world.c @@ -4,14 +4,48 @@ */ #include "config.h" +#include #include #include #include +#include #include static const 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); +}; + +static void check_fnc(void) +{ + printk(KERN_DEBUG "%s: Hi func called %u times\n", __func__, cnt); + BUG_ON(cnt == 0 || cnt > 2); +} + +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(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 9d2e86d..5f9986d 100644 --- a/xen/common/livepatch.c +++ b/xen/common/livepatch.c @@ -23,6 +23,7 @@ #include #include #include +#include #include @@ -72,7 +73,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 *const *load_funcs; /* The array of funcs to call after */ + livepatch_unloadcall_t *const *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. */ @@ -542,6 +547,25 @@ static int prepare_payload(struct payload *payload, return rc; } + sec = livepatch_elf_sec_by_name(elf, ".livepatch.hooks.load"); + if ( sec ) + { + if ( 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 % 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 ) { @@ -1032,6 +1056,18 @@ static int apply_payload(struct payload *data) return rc; } + /* + * Since we are running with IRQs disabled and the hooks may call common + * code - which expects certain spinlocks to run with IRQs enabled - we + * temporarily disable the spin locks IRQ state checks. + */ + 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(&data->funcs[i]); @@ -1064,6 +1100,18 @@ static int revert_payload(struct payload *data) for ( i = 0; i < data->nfuncs; i++ ) arch_livepatch_revert(&data->funcs[i]); + /* + * Since we are running with IRQs disabled and the hooks may call common + * code - which expects certain spinlocks to run with IRQs enabled - we + * temporarily disable the spin locks IRQ state checks. + */ + 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..8f38cc2 --- /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)) \ + const 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)) \ + const 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: + */