From patchwork Wed Aug 14 07:55:25 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Wieczorkiewicz, Pawel" X-Patchwork-Id: 11093463 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 681BF6C5 for ; Wed, 14 Aug 2019 07:57:13 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 560A128737 for ; Wed, 14 Aug 2019 07:57:13 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 4772328797; Wed, 14 Aug 2019 07:57:13 +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,DKIM_ADSP_ALL, DKIM_INVALID,DKIM_SIGNED,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 97F1428737 for ; Wed, 14 Aug 2019 07:57:12 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1hxo8K-0001EI-Hc; Wed, 14 Aug 2019 07:55:48 +0000 Received: from us1-rack-iad1.inumbo.com ([172.99.69.81]) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1hxo8J-0001EC-Td for xen-devel@lists.xen.org; Wed, 14 Aug 2019 07:55:47 +0000 X-Inumbo-ID: eca4b358-be68-11e9-aac1-bf0143fad4e2 Received: from smtp-fw-4101.amazon.com (unknown [72.21.198.25]) by us1-rack-iad1.inumbo.com (Halon) with ESMTPS id eca4b358-be68-11e9-aac1-bf0143fad4e2; Wed, 14 Aug 2019 07:55:46 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amazon.de; i=@amazon.de; q=dns/txt; s=amazon201209; t=1565769346; x=1597305346; h=from:to:cc:subject:date:message-id:mime-version; bh=A170r0IWzzOpIg/PBJzQr4TMLCLBtpdSJyiI6Mxk8Ak=; b=jaCIa3Ou1uQDjJws741o7gjj0pHdJQ/yPMLizZh9Kij66v/2vC6SIMHs 5iQnHtcAS3xfIvXEV/ARNIvAP2j0Icnp89ZsAGqN1WLd0c9TOcHDj90Ql tZJKNMUvPG8ZEPQX5hNDFi3nBvDaOEeWIZn1qKvMdBSGhuNxiFkDolxs9 8=; X-IronPort-AV: E=Sophos;i="5.64,384,1559520000"; d="scan'208";a="779187480" Received: from iad6-co-svc-p1-lb1-vlan3.amazon.com (HELO email-inbound-relay-2a-69849ee2.us-west-2.amazon.com) ([10.124.125.6]) by smtp-border-fw-out-4101.iad4.amazon.com with ESMTP; 14 Aug 2019 07:55:45 +0000 Received: from EX13MTAUEA001.ant.amazon.com (pdx4-ws-svc-p6-lb7-vlan2.pdx.amazon.com [10.170.41.162]) by email-inbound-relay-2a-69849ee2.us-west-2.amazon.com (Postfix) with ESMTPS id E5343A250F; Wed, 14 Aug 2019 07:55:44 +0000 (UTC) Received: from EX13D03EUA003.ant.amazon.com (10.43.165.89) by EX13MTAUEA001.ant.amazon.com (10.43.61.243) with Microsoft SMTP Server (TLS) id 15.0.1367.3; Wed, 14 Aug 2019 07:55:44 +0000 Received: from EX13MTAUWC001.ant.amazon.com (10.43.162.135) by EX13D03EUA003.ant.amazon.com (10.43.165.89) with Microsoft SMTP Server (TLS) id 15.0.1367.3; Wed, 14 Aug 2019 07:55:43 +0000 Received: from dev-dsk-wipawel-1a-0c4e6d58.eu-west-1.amazon.com (10.4.134.33) by mail-relay.amazon.com (10.43.162.232) with Microsoft SMTP Server id 15.0.1367.3 via Frontend Transport; Wed, 14 Aug 2019 07:55:41 +0000 From: Pawel Wieczorkiewicz To: Date: Wed, 14 Aug 2019 07:55:25 +0000 Message-ID: <20190814075525.83191-1-wipawel@amazon.de> X-Mailer: git-send-email 2.16.5 MIME-Version: 1.0 Precedence: Bulk Subject: [Xen-devel] [livepatch-hooks-1 PATCH 1/3] create-diff-object: Handle extra pre-|post- hooks X-BeenThere: xen-devel@lists.xenproject.org X-Mailman-Version: 2.1.23 List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Cc: mpohlack@amazon.de, ross.lagerwall@citrix.com, wipawel@amazon.de, konrad.wilk@oracle.com Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" X-Virus-Scanned: ClamAV using ClamSMTP Include new sections containing optional pre-, post- action hooks. The following new section names are supported: - .livepatch.hooks.preapply - .livepatch.hooks.postapply - .livepatch.hooks.prerevert - .livepatch.hooks.postrevert Signed-off-by: Pawel Wieczorkiewicz Reviewed-by: Ross Lagerwall --- create-diff-object.c | 67 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 54 insertions(+), 13 deletions(-) diff --git a/create-diff-object.c b/create-diff-object.c index f352704..3493fe1 100644 --- a/create-diff-object.c +++ b/create-diff-object.c @@ -1102,6 +1102,22 @@ static struct special_section special_sections[] = { .name = ".livepatch.hooks.unload", .group_size = livepatch_hooks_group_size, }, + { + .name = ".livepatch.hooks.preapply", + .group_size = livepatch_hooks_group_size, + }, + { + .name = ".livepatch.hooks.postapply", + .group_size = livepatch_hooks_group_size, + }, + { + .name = ".livepatch.hooks.prerevert", + .group_size = livepatch_hooks_group_size, + }, + { + .name = ".livepatch.hooks.postrevert", + .group_size = livepatch_hooks_group_size, + }, {}, }; @@ -1460,23 +1476,44 @@ static void kpatch_include_debug_sections(struct kpatch_elf *kelf) } } -static void kpatch_include_hook_elements(struct kpatch_elf *kelf) +#define IS_HOOK_SECTION(section, hook) ({ \ + !strcmp(((section))->name, ".livepatch.hooks." hook) || \ + !strcmp(((section))->name, ".rela.livepatch.hooks." hook); \ +}) + +#define IS_ACTION_HOOK_SECTION(section, action) ({ \ + IS_HOOK_SECTION(section, "pre" action) || \ + IS_HOOK_SECTION(section, "post" action); \ +}) + +#define IS_HOOK_SYM_NAME(symbol, hook) ({ \ + !strcmp(((symbol))->name, "livepatch_" hook "_data"); \ +}) + +#define IS_ACTION_HOOK_SYM_NAME(symbol, action) ({ \ + IS_HOOK_SYM_NAME(symbol, "pre" action) || \ + IS_HOOK_SYM_NAME(symbol, "post" action); \ +}) + +static int kpatch_include_hook_elements(struct kpatch_elf *kelf) { struct section *sec; struct symbol *sym; struct rela *rela; + int num_new_functions = 0; - /* include load/unload sections */ + /* include all supported hooks sections */ list_for_each_entry(sec, &kelf->sections, list) { - if (!strcmp(sec->name, ".livepatch.hooks.load") || - !strcmp(sec->name, ".livepatch.hooks.unload") || - !strcmp(sec->name, ".rela.livepatch.hooks.load") || - !strcmp(sec->name, ".rela.livepatch.hooks.unload")) { + if (IS_HOOK_SECTION(sec, "load") || + IS_HOOK_SECTION(sec, "unload") || + IS_ACTION_HOOK_SECTION(sec, "apply") || + IS_ACTION_HOOK_SECTION(sec, "revert")) { sec->include = 1; + num_new_functions++; if (is_rela_section(sec)) { /* include hook dependencies */ rela = list_entry(sec->relas.next, - struct rela, list); + struct rela, list); sym = rela->sym; log_normal("found hook: %s\n",sym->name); kpatch_include_symbol(sym, 0); @@ -1492,13 +1529,17 @@ static void kpatch_include_hook_elements(struct kpatch_elf *kelf) } /* - * Strip temporary global load/unload function pointer objects - * used by the kpatch_[load|unload]() macros. + * Strip temporary global function pointer objects for all + * supported hooks, used by the kpatch_[load|unload]() macros. */ list_for_each_entry(sym, &kelf->symbols, list) - if (!strcmp(sym->name, "livepatch_load_data") || - !strcmp(sym->name, "livepatch_unload_data")) + if (IS_HOOK_SYM_NAME(sym, "load") || + IS_HOOK_SYM_NAME(sym, "unload") || + IS_ACTION_HOOK_SYM_NAME(sym, "apply") || + IS_ACTION_HOOK_SYM_NAME(sym, "revert")) sym->include = 0; + + return num_new_functions; } static int kpatch_include_new_globals(struct kpatch_elf *kelf) @@ -2287,11 +2328,11 @@ int main(int argc, char *argv[]) kpatch_include_standard_elements(kelf_patched); log_debug("Include changed functions\n"); num_changed = kpatch_include_changed_functions(kelf_patched); - log_debug("num_changed = %d\n", num_changed); log_debug("Include debug sections\n"); kpatch_include_debug_sections(kelf_patched); log_debug("Include hook elements\n"); - kpatch_include_hook_elements(kelf_patched); + num_changed += kpatch_include_hook_elements(kelf_patched); + log_debug("num_changed = %d\n", num_changed); log_debug("Include standard string elements\n"); kpatch_include_standard_string_elements(kelf_patched); log_debug("Include new globals\n"); From patchwork Wed Aug 14 07:57:24 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Wieczorkiewicz, Pawel" X-Patchwork-Id: 11093465 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C02B86C5 for ; Wed, 14 Aug 2019 07:59:25 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id AC5E328737 for ; Wed, 14 Aug 2019 07:59:25 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A0C0F28797; Wed, 14 Aug 2019 07:59:25 +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,DKIM_ADSP_ALL, DKIM_INVALID,DKIM_SIGNED,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 1ABEF28737 for ; Wed, 14 Aug 2019 07:59:25 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1hxoAA-0001L6-6v; Wed, 14 Aug 2019 07:57:42 +0000 Received: from all-amaz-eas1.inumbo.com ([34.197.232.57] helo=us1-amaz-eas2.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1hxoA8-0001Ku-VV for xen-devel@lists.xen.org; Wed, 14 Aug 2019 07:57:41 +0000 X-Inumbo-ID: 2dc3973c-be69-11e9-9f17-d3be2b170e32 Received: from smtp-fw-33001.amazon.com (unknown [207.171.190.10]) by us1-amaz-eas2.inumbo.com (Halon) with ESMTPS id 2dc3973c-be69-11e9-9f17-d3be2b170e32; Wed, 14 Aug 2019 07:57:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amazon.de; i=@amazon.de; q=dns/txt; s=amazon201209; t=1565769456; x=1597305456; h=from:to:cc:subject:date:message-id:mime-version; bh=kNDa4im2hmOVkZDy522gHdmdFnkiMSjMqHjoHiFJ4L4=; b=NKhnltyo1YOe0DHfaBNC+Ye6PX/5eg9+lX3HEgSkKhtg2q6xtivFXSKG qOGlQ9enZF1AN9LEHCMdQPOahqNFeR2MqA2/m9BY/Ml8NLCWGg//XAvcS 7Gr5WRo1FfbnAY5JzVwq9QG5UrjFE398qaaTRKXruWv2Frkzf+3JrWajj w=; X-IronPort-AV: E=Sophos;i="5.64,384,1559520000"; d="scan'208";a="819712246" Received: from sea3-co-svc-lb6-vlan2.sea.amazon.com (HELO email-inbound-relay-1d-98acfc19.us-east-1.amazon.com) ([10.47.22.34]) by smtp-border-fw-out-33001.sea14.amazon.com with ESMTP; 14 Aug 2019 07:57:33 +0000 Received: from EX13MTAUEA001.ant.amazon.com (iad55-ws-svc-p15-lb9-vlan3.iad.amazon.com [10.40.159.166]) by email-inbound-relay-1d-98acfc19.us-east-1.amazon.com (Postfix) with ESMTPS id 64F0FA234A; Wed, 14 Aug 2019 07:57:32 +0000 (UTC) Received: from EX13D03EUC002.ant.amazon.com (10.43.164.60) by EX13MTAUEA001.ant.amazon.com (10.43.61.82) with Microsoft SMTP Server (TLS) id 15.0.1367.3; Wed, 14 Aug 2019 07:57:31 +0000 Received: from EX13MTAUWA001.ant.amazon.com (10.43.160.58) by EX13D03EUC002.ant.amazon.com (10.43.164.60) with Microsoft SMTP Server (TLS) id 15.0.1367.3; Wed, 14 Aug 2019 07:57:30 +0000 Received: from dev-dsk-wipawel-1a-0c4e6d58.eu-west-1.amazon.com (10.4.134.33) by mail-relay.amazon.com (10.43.160.118) with Microsoft SMTP Server id 15.0.1367.3 via Frontend Transport; Wed, 14 Aug 2019 07:57:28 +0000 From: Pawel Wieczorkiewicz To: Date: Wed, 14 Aug 2019 07:57:24 +0000 Message-ID: <20190814075724.83645-1-wipawel@amazon.de> X-Mailer: git-send-email 2.16.5 MIME-Version: 1.0 Precedence: Bulk Subject: [Xen-devel] [livepatch-hooks-1 PATCH 2/3] livepatch: Export payload structure via livepatch_payload.h X-BeenThere: xen-devel@lists.xenproject.org X-Mailman-Version: 2.1.23 List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Cc: mpohlack@amazon.de, ross.lagerwall@citrix.com, wipawel@amazon.de, konrad.wilk@oracle.com Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" X-Virus-Scanned: ClamAV using ClamSMTP The payload structure will be used by the new hooks implementation and therefore its definition has to be exported via the livepatch_payload header. The new hooks will make use of the payload structure fields and the hooks' pointers will also be defined in the payload structure, so the structure along with all field definitions needs to be available to the code being patched in. Signed-off-by: Pawel Wieczorkiewicz Reviewed-by: Andra-Irina Paraschiv Reviewed-by: Eslam Elnikety Reviewed-by: Leonard Foerster Reviewed-by: Martin Pohlack Reviewed-by: Ross Lagerwall --- xen/common/livepatch.c | 37 ---------------------------------- xen/include/xen/livepatch_payload.h | 40 +++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 37 deletions(-) diff --git a/xen/common/livepatch.c b/xen/common/livepatch.c index fb91d5095c..ed5756a032 100644 --- a/xen/common/livepatch.c +++ b/xen/common/livepatch.c @@ -45,43 +45,6 @@ static LIST_HEAD(applied_list); static unsigned int payload_cnt; static unsigned int payload_version = 1; -/* To contain the ELF Note header. */ -struct livepatch_build_id { - const void *p; - unsigned int len; -}; - -struct payload { - uint32_t state; /* One of the LIVEPATCH_STATE_*. */ - int32_t rc; /* 0 or -XEN_EXX. */ - bool reverted; /* Whether it was reverted. */ - bool safe_to_reapply; /* Can apply safely after revert. */ - struct list_head list; /* Linked to 'payload_list'. */ - const void *text_addr; /* Virtual address of .text. */ - size_t text_size; /* .. and its size. */ - const void *rw_addr; /* Virtual address of .data. */ - size_t rw_size; /* .. and its size (if any). */ - const void *ro_addr; /* Virtual address of .rodata. */ - size_t ro_size; /* .. and its size (if any). */ - unsigned int pages; /* Total pages for [text,rw,ro]_addr */ - struct list_head applied_list; /* Linked to 'applied_list'. */ - struct livepatch_func *funcs; /* The array of functions to patch. */ - unsigned int nfuncs; /* Nr of functions to patch. */ - const struct livepatch_symbol *symtab; /* All symbols. */ - const char *strtab; /* Pointer to .strtab. */ - struct virtual_region region; /* symbol, bug.frame patching and - exception table (x86). */ - 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). */ - struct livepatch_build_id xen_dep; /* ELFNOTE_DESC(.livepatch.xen_depends). */ - 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. */ struct livepatch_work { diff --git a/xen/include/xen/livepatch_payload.h b/xen/include/xen/livepatch_payload.h index 4a1a96d054..99613af2db 100644 --- a/xen/include/xen/livepatch_payload.h +++ b/xen/include/xen/livepatch_payload.h @@ -4,6 +4,15 @@ #ifndef __XEN_LIVEPATCH_PAYLOAD_H__ #define __XEN_LIVEPATCH_PAYLOAD_H__ +#include + +/* To contain the ELF Note header. */ +struct livepatch_build_id { + const void *p; + unsigned int len; +}; + +typedef struct payload livepatch_payload_t; /* * The following definitions are to be used in patches. They are taken @@ -12,6 +21,37 @@ typedef void livepatch_loadcall_t(void); typedef void livepatch_unloadcall_t(void); +struct payload { + uint32_t state; /* One of the LIVEPATCH_STATE_*. */ + int32_t rc; /* 0 or -XEN_EXX. */ + bool reverted; /* Whether it was reverted. */ + bool safe_to_reapply; /* Can apply safely after revert. */ + struct list_head list; /* Linked to 'payload_list'. */ + const void *text_addr; /* Virtual address of .text. */ + size_t text_size; /* .. and its size. */ + const void *rw_addr; /* Virtual address of .data. */ + size_t rw_size; /* .. and its size (if any). */ + const void *ro_addr; /* Virtual address of .rodata. */ + size_t ro_size; /* .. and its size (if any). */ + unsigned int pages; /* Total pages for [text,rw,ro]_addr */ + struct list_head applied_list; /* Linked to 'applied_list'. */ + struct livepatch_func *funcs; /* The array of functions to patch. */ + unsigned int nfuncs; /* Nr of functions to patch. */ + const struct livepatch_symbol *symtab; /* All symbols. */ + const char *strtab; /* Pointer to .strtab. */ + struct virtual_region region; /* symbol, bug.frame patching and + exception table (x86). */ + 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). */ + struct livepatch_build_id xen_dep; /* ELFNOTE_DESC(.livepatch.xen_depends). */ + 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. */ +}; + /* * LIVEPATCH_LOAD_HOOK macro * From patchwork Wed Aug 14 07:58:54 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Wieczorkiewicz, Pawel" X-Patchwork-Id: 11093487 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 5FE9F6C5 for ; Wed, 14 Aug 2019 08:00:24 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4B23F22B1F for ; Wed, 14 Aug 2019 08:00:24 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 3EC76287A4; Wed, 14 Aug 2019 08:00:24 +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,DKIM_ADSP_ALL, DKIM_INVALID,DKIM_SIGNED,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 0848522B1F for ; Wed, 14 Aug 2019 08:00:23 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1hxoBU-0001Tw-Ik; Wed, 14 Aug 2019 07:59:04 +0000 Received: from us1-rack-iad1.inumbo.com ([172.99.69.81]) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1hxoBU-0001Tq-4a for xen-devel@lists.xen.org; Wed, 14 Aug 2019 07:59:04 +0000 X-Inumbo-ID: 6198f11a-be69-11e9-ac16-5beba594774b Received: from smtp-fw-6002.amazon.com (unknown [52.95.49.90]) by us1-rack-iad1.inumbo.com (Halon) with ESMTPS id 6198f11a-be69-11e9-ac16-5beba594774b; Wed, 14 Aug 2019 07:59:02 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amazon.de; i=@amazon.de; q=dns/txt; s=amazon201209; t=1565769542; x=1597305542; h=from:to:cc:subject:date:message-id:mime-version; bh=N0Xjb44SoXY229XZ17xnLZJpdqrjLArGLuQOpbMphsw=; b=kYw5r1X8bqRJS23fJ+kILgRWC+XbZBtzl7Af6Ne6e9gPyzpMCAb8zRbg svlm7gy/C3SkyfovMkghr3N2/kJ2vsgpDZzSfigd613b1EQ/iPRvlS3/b esTcHRPSyAlDt2dB9s2h13DtTX4/6GMwdn735hmT0JLxCYAFLlpZLbglO k=; X-IronPort-AV: E=Sophos;i="5.64,384,1559520000"; d="scan'208";a="415358383" Received: from iad6-co-svc-p1-lb1-vlan3.amazon.com (HELO email-inbound-relay-1e-303d0b0e.us-east-1.amazon.com) ([10.124.125.6]) by smtp-border-fw-out-6002.iad6.amazon.com with ESMTP; 14 Aug 2019 07:59:02 +0000 Received: from EX13MTAUEA001.ant.amazon.com (iad55-ws-svc-p15-lb9-vlan3.iad.amazon.com [10.40.159.166]) by email-inbound-relay-1e-303d0b0e.us-east-1.amazon.com (Postfix) with ESMTPS id EC84BA2120; Wed, 14 Aug 2019 07:59:01 +0000 (UTC) Received: from EX13D05EUB002.ant.amazon.com (10.43.166.45) by EX13MTAUEA001.ant.amazon.com (10.43.61.243) with Microsoft SMTP Server (TLS) id 15.0.1367.3; Wed, 14 Aug 2019 07:59:01 +0000 Received: from EX13MTAUWA001.ant.amazon.com (10.43.160.58) by EX13D05EUB002.ant.amazon.com (10.43.166.45) with Microsoft SMTP Server (TLS) id 15.0.1367.3; Wed, 14 Aug 2019 07:58:59 +0000 Received: from dev-dsk-wipawel-1a-0c4e6d58.eu-west-1.amazon.com (10.4.134.33) by mail-relay.amazon.com (10.43.160.118) with Microsoft SMTP Server id 15.0.1367.3 via Frontend Transport; Wed, 14 Aug 2019 07:58:58 +0000 From: Pawel Wieczorkiewicz To: Date: Wed, 14 Aug 2019 07:58:54 +0000 Message-ID: <20190814075854.83923-1-wipawel@amazon.de> X-Mailer: git-send-email 2.16.5 MIME-Version: 1.0 Precedence: Bulk Subject: [Xen-devel] [livepatch-hooks-1 PATCH 3/3] livepatch: Implement pre-|post- apply|revert hooks X-BeenThere: xen-devel@lists.xenproject.org X-Mailman-Version: 2.1.23 List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Cc: mpohlack@amazon.de, ross.lagerwall@citrix.com, wipawel@amazon.de, konrad.wilk@oracle.com Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" X-Virus-Scanned: ClamAV using ClamSMTP This is an implementation of 4 new livepatch module vetoing hooks, that can be optionally supplied along with modules. Hooks that currently exists in the livepatch mechanism aren't agile enough and have various limitations: * run only from within a quiescing zone * cannot conditionally prevent applying or reverting * do not have access to the module context To address these limitations the following has been implemented: 1) pre-apply hook runs before the apply action is scheduled for execution. Its main purpose is to prevent from applying a hotpatch when certain expected conditions aren't met or when mutating actions implemented in the hook fail or cannot be executed. 2) post-apply hook runs after the apply action has been executed and quiescing zone exited. Its main purpose is to provide an ability to follow-up on actions performed by the pre- hook, when module application was successful or undo certain preparation steps of the pre- hook in case of a failure. The success/failure error code is proviVded to the post- hooks via the rc field of the payload structure. 3) pre-revert hook runs before the revert action is scheduled for execution. Its main purpose is to prevent from reverting a hotpatch when certain expected conditions aren't met or when mutating actions implemented in the hook fail or cannot be executed. 4) post-revert hook runs after the revert action has been executed and quiescing zone exited. Its main purpose is to perform cleanup of all previously executed mutating actions in order to restore the original system state from before the current module application. The success/failure error code is provided to the post- hooks via the rc field of the payload structure. The replace action performs atomically the following actions: - revert all applied modules - apply a single replacement module. With the vetoing hooks in place various inter-hook dependencies may arise. Also, during the revert part of the operation certain vetoing hooks may detect failing conditions that previously were satisfied. That could in turn lead to situation when the revert part must be rolled back with all the pre- and post- hooks re-applied, which again can't be guaranteed to always succeed. The simplest response to this complication is to disallow the replace action completely on modules with vetoing hooks. Signed-off-by: Pawel Wieczorkiewicz Reviewed-by: Andra-Irina Paraschiv Reviewed-by: Petre Eftime Reviewed-by: Martin Pohlack Reviewed-by: Norbert Manthey --- xen/common/livepatch.c | 179 ++++++++++++++++++++++++++++++++---- xen/include/xen/livepatch_payload.h | 27 ++++++ 2 files changed, 189 insertions(+), 17 deletions(-) diff --git a/xen/common/livepatch.c b/xen/common/livepatch.c index ed5756a032..464c07ad28 100644 --- a/xen/common/livepatch.c +++ b/xen/common/livepatch.c @@ -28,6 +28,8 @@ #include #include +#define is_hook_enabled(hook) ({ (hook) && *(hook); }) + /* * Protects against payload_list operations and also allows only one * caller in schedule_work. @@ -501,6 +503,35 @@ static int check_special_sections(const struct livepatch_elf *elf) return 0; } +/* + * Lookup specified section and when exists assign its address to a specified hook. + * Perform section pointer and size validation: single hook sections must contain a + * single pointer only. + */ +#define LIVEPATCH_ASSIGN_SINGLE_HOOK(elf, hook, section_name) do { \ + const struct livepatch_elf_sec *__sec = livepatch_elf_sec_by_name(elf, section_name); \ + if ( !__sec ) \ + break; \ + if ( !section_ok(elf, __sec, sizeof(*hook)) || __sec->sec->sh_size != sizeof(*hook) ) \ + return -EINVAL; \ + hook = __sec->load_addr; \ +} while (0) + +/* + * Lookup specified section and when exists assign its address to a specified hook. + * Perform section pointer and size validation: multi hook sections must contain an + * array whose size must be a multiple of the array's items size. + */ +#define LIVEPATCH_ASSIGN_MULTI_HOOK(elf, hook, nhooks, section_name) do { \ + const struct livepatch_elf_sec *__sec = livepatch_elf_sec_by_name(elf, section_name); \ + if ( !__sec ) \ + break; \ + if ( !section_ok(elf, __sec, sizeof(*hook)) ) \ + return -EINVAL; \ + hook = __sec->load_addr; \ + nhooks = __sec->sec->sh_size / sizeof(*hook); \ +} while (0) + static int prepare_payload(struct payload *payload, struct livepatch_elf *elf) { @@ -552,25 +583,14 @@ static int prepare_payload(struct payload *payload, return rc; } - sec = livepatch_elf_sec_by_name(elf, ".livepatch.hooks.load"); - if ( sec ) - { - if ( !section_ok(elf, sec, sizeof(*payload->load_funcs)) ) - return -EINVAL; - - payload->load_funcs = sec->load_addr; - payload->n_load_funcs = sec->sec->sh_size / sizeof(*payload->load_funcs); - } + LIVEPATCH_ASSIGN_MULTI_HOOK(elf, payload->load_funcs, payload->n_load_funcs, ".livepatch.hooks.load"); + LIVEPATCH_ASSIGN_MULTI_HOOK(elf, payload->unload_funcs, payload->n_unload_funcs, ".livepatch.hooks.unload"); - sec = livepatch_elf_sec_by_name(elf, ".livepatch.hooks.unload"); - if ( sec ) - { - if ( !section_ok(elf, sec, sizeof(*payload->unload_funcs)) ) - return -EINVAL; + LIVEPATCH_ASSIGN_SINGLE_HOOK(elf, payload->hooks.apply.pre, ".livepatch.hooks.preapply"); + LIVEPATCH_ASSIGN_SINGLE_HOOK(elf, payload->hooks.apply.post, ".livepatch.hooks.postapply"); + LIVEPATCH_ASSIGN_SINGLE_HOOK(elf, payload->hooks.revert.pre, ".livepatch.hooks.prerevert"); + LIVEPATCH_ASSIGN_SINGLE_HOOK(elf, payload->hooks.revert.post, ".livepatch.hooks.postrevert"); - 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 ) { @@ -1217,6 +1237,39 @@ static bool_t is_work_scheduled(const struct payload *data) return livepatch_work.do_work && livepatch_work.data == data; } +/* + * Check if payload has any of the vetoing, non-atomic hooks assigned. + * A vetoing, non-atmic hook may perform an operation that changes the + * hypervisor state and may not be guaranteed to succeed. Result of + * such operation may be returned and may change the livepatch workflow. + * Such hooks may require additional cleanup actions performed by other + * hooks. Thus they are not suitable for replace action. + */ +static inline bool_t has_payload_any_vetoing_hooks(const struct payload *payload) +{ + return is_hook_enabled(payload->hooks.apply.pre) || + is_hook_enabled(payload->hooks.apply.post) || + is_hook_enabled(payload->hooks.revert.pre) || + is_hook_enabled(payload->hooks.revert.post); +} + +/* + * Checks if any of the already applied hotpatches has any vetoing, + * non-atomic hooks assigned. + */ +static inline bool_t livepatch_applied_have_vetoing_hooks(void) +{ + struct payload *p; + + list_for_each_entry ( p, &applied_list, applied_list ) + { + if ( has_payload_any_vetoing_hooks(p) ) + return true; + } + + return false; +} + static int schedule_work(struct payload *data, uint32_t cmd, uint32_t timeout) { ASSERT(spin_is_locked(&payload_lock)); @@ -1317,6 +1370,7 @@ void check_for_livepatch_work(void) { struct payload *p; unsigned int cpus; + bool_t action_done = false; p = livepatch_work.data; if ( !get_cpu_maps() ) @@ -1369,6 +1423,7 @@ void check_for_livepatch_work(void) livepatch_do_action(); /* Serialize and flush out the CPU via CPUID instruction (on x86). */ arch_livepatch_post_action(); + action_done = true; local_irq_restore(flags); } @@ -1381,6 +1436,43 @@ void check_for_livepatch_work(void) /* put_cpu_maps has an barrier(). */ put_cpu_maps(); + if ( action_done ) + { + switch ( livepatch_work.cmd ) + { + case LIVEPATCH_ACTION_REVERT: + if ( is_hook_enabled(p->hooks.revert.post) ) + { + printk(XENLOG_INFO LIVEPATCH "%s: Calling post-revert hook function with rc=%d\n", + p->name, p->rc); + + (*p->hooks.revert.post)(p); + } + break; + + case LIVEPATCH_ACTION_APPLY: + if ( is_hook_enabled(p->hooks.apply.post) ) + { + printk(XENLOG_INFO LIVEPATCH "%s: Calling post-apply hook function with rc=%d\n", + p->name, p->rc); + + (*p->hooks.apply.post)(p); + } + break; + + case LIVEPATCH_ACTION_REPLACE: + if ( has_payload_any_vetoing_hooks(p) ) + { + /* It should be impossible to get here since livepatch_action() guards against that. */ + panic(LIVEPATCH "%s: REPLACE action is not supported on hotpatches with vetoing hooks!\n", + p->name); + ASSERT_UNREACHABLE(); + } + default: + break; + } + } + printk(XENLOG_INFO LIVEPATCH "%s finished %s with rc=%d\n", p->name, names[livepatch_work.cmd], p->rc); } @@ -1516,6 +1608,21 @@ static int livepatch_action(struct xen_sysctl_livepatch_action *action) rc = -EBUSY; break; } + + if ( is_hook_enabled(data->hooks.revert.pre) ) + { + printk(XENLOG_INFO LIVEPATCH "%s: Calling pre-revert hook function\n", data->name); + + rc = (*data->hooks.revert.pre)(data); + if ( rc ) + { + printk(XENLOG_ERR LIVEPATCH "%s: pre-revert hook failed (rc=%d), aborting!\n", + data->name, rc); + data->rc = rc; + break; + } + } + data->rc = -EAGAIN; rc = schedule_work(data, action->cmd, action->timeout); } @@ -1549,6 +1656,20 @@ static int livepatch_action(struct xen_sysctl_livepatch_action *action) break; } + if ( is_hook_enabled(data->hooks.apply.pre) ) + { + printk(XENLOG_INFO LIVEPATCH "%s: Calling pre-apply hook function\n", data->name); + + rc = (*data->hooks.apply.pre)(data); + if ( rc ) + { + printk(XENLOG_ERR LIVEPATCH "%s: pre-apply hook failed (rc=%d), aborting!\n", + data->name, rc); + data->rc = rc; + break; + } + } + data->rc = -EAGAIN; rc = schedule_work(data, action->cmd, action->timeout); } @@ -1560,6 +1681,30 @@ static int livepatch_action(struct xen_sysctl_livepatch_action *action) rc = build_id_dep(data, 1 /* against hypervisor. */); if ( rc ) break; + + /* + * REPLACE action is not supported on hotpatches with vetoing hooks. + * Vetoing hooks usually perform mutating actions on the system and + * typically exist in pairs (pre- hook doing an action and post- hook + * undoing the action). Coalescing all hooks from all applied modules + * cannot be performed without inspecting potential dependencies between + * the mutating hooks and hence cannot be performed automatically by + * the replace action. Also, the replace action cannot safely assume a + * successful revert of all the module with vetoing hooks. When one + * of the hooks fails due to not meeting certain conditions the whole + * replace operation must have been reverted with all previous pre- and + * post- hooks re-executed (which cannot be guaranteed to succeed). + * The simplest response to this complication is disallow replace + * action on modules with vetoing hooks. + */ + if ( has_payload_any_vetoing_hooks(data) || livepatch_applied_have_vetoing_hooks() ) + { + printk(XENLOG_ERR LIVEPATCH "%s: REPLACE action is not supported on hotpatches with vetoing hooks!\n", + data->name); + rc = -EOPNOTSUPP; + break; + } + data->rc = -EAGAIN; rc = schedule_work(data, action->cmd, action->timeout); } diff --git a/xen/include/xen/livepatch_payload.h b/xen/include/xen/livepatch_payload.h index 99613af2db..cd20944cc4 100644 --- a/xen/include/xen/livepatch_payload.h +++ b/xen/include/xen/livepatch_payload.h @@ -21,6 +21,16 @@ typedef struct payload livepatch_payload_t; typedef void livepatch_loadcall_t(void); typedef void livepatch_unloadcall_t(void); +typedef int livepatch_precall_t(livepatch_payload_t *arg); +typedef void livepatch_postcall_t(livepatch_payload_t *arg); + +struct livepatch_hooks { + struct { + livepatch_precall_t *const *pre; + livepatch_postcall_t *const *post; + } apply, revert; +}; + struct payload { uint32_t state; /* One of the LIVEPATCH_STATE_*. */ int32_t rc; /* 0 or -XEN_EXX. */ @@ -47,6 +57,7 @@ struct payload { struct livepatch_build_id xen_dep; /* ELFNOTE_DESC(.livepatch.xen_depends). */ 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. */ + struct livepatch_hooks hooks; /* Pre and post hooks for apply and revert */ 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. */ @@ -76,6 +87,22 @@ struct payload { livepatch_unloadcall_t *__weak \ const livepatch_unload_data_##_fn __section(".livepatch.hooks.unload") = _fn; +#define LIVEPATCH_PREAPPLY_HOOK(_fn) \ + livepatch_precall_t *__attribute__((weak, used)) \ + const livepatch_preapply_data_##_fn __section(".livepatch.hooks.preapply") = _fn; + +#define LIVEPATCH_POSTAPPLY_HOOK(_fn) \ + livepatch_postcall_t *__attribute__((weak, used)) \ + const livepatch_postapply_data_##_fn __section(".livepatch.hooks.postapply") = _fn; + +#define LIVEPATCH_PREREVERT_HOOK(_fn) \ + livepatch_precall_t *__attribute__((weak, used)) \ + const livepatch_prerevert_data_##_fn __section(".livepatch.hooks.prerevert") = _fn; + +#define LIVEPATCH_POSTREVERT_HOOK(_fn) \ + livepatch_postcall_t *__attribute__((weak, used)) \ + const livepatch_postrevert_data_##_fn __section(".livepatch.hooks.postrevert") = _fn; + #endif /* __XEN_LIVEPATCH_PAYLOAD_H__ */ /*