From patchwork Wed Aug 14 12:10:53 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Wieczorkiewicz, Pawel" X-Patchwork-Id: 11093815 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 1C6186C5 for ; Wed, 14 Aug 2019 12:13:00 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 082132849D for ; Wed, 14 Aug 2019 12:13:00 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id F036628756; Wed, 14 Aug 2019 12:12:59 +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 3E7DF2849D for ; Wed, 14 Aug 2019 12:12:59 +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 1hxs7R-00085w-OQ; Wed, 14 Aug 2019 12:11:09 +0000 Received: from us1-rack-iad1.inumbo.com ([172.99.69.81]) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1hxs7Q-00085p-1Y for xen-devel@lists.xen.org; Wed, 14 Aug 2019 12:11:08 +0000 X-Inumbo-ID: 98805024-be8c-11e9-ade6-bbb71cb4c8ed Received: from smtp-fw-4101.amazon.com (unknown [72.21.198.25]) by us1-rack-iad1.inumbo.com (Halon) with ESMTPS id 98805024-be8c-11e9-ade6-bbb71cb4c8ed; Wed, 14 Aug 2019 12:11:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amazon.de; i=@amazon.de; q=dns/txt; s=amazon201209; t=1565784667; x=1597320667; h=from:to:cc:subject:date:message-id:mime-version; bh=SPD4A6bGMHPNjqLPvW3NJnbKE2CQOSt/oG6jsD3Ek3s=; b=gw2h9qc8qA/rVwJxa6NwhFoyRRY+QnHvgJaODRFqKzDZABeofg7FtvQA HEGnunrhK2jzl/XieEVr4b1L802xwdL6XAcv0vxEmjcIo6wF3LgHV/fKD yCwuXzsIlfevy74vow0wftPP57fyO2ScOYFf1roNRU+sDarx696cq7qe6 s=; X-IronPort-AV: E=Sophos;i="5.64,385,1559520000"; d="scan'208";a="779221121" Received: from iad6-co-svc-p1-lb1-vlan3.amazon.com (HELO email-inbound-relay-1a-af6a10df.us-east-1.amazon.com) ([10.124.125.6]) by smtp-border-fw-out-4101.iad4.amazon.com with ESMTP; 14 Aug 2019 12:11:04 +0000 Received: from EX13MTAUEA001.ant.amazon.com (iad55-ws-svc-p15-lb9-vlan3.iad.amazon.com [10.40.159.166]) by email-inbound-relay-1a-af6a10df.us-east-1.amazon.com (Postfix) with ESMTPS id 4AEC0A27F2; Wed, 14 Aug 2019 12:11:03 +0000 (UTC) Received: from EX13D03EUA003.ant.amazon.com (10.43.165.89) by EX13MTAUEA001.ant.amazon.com (10.43.61.82) with Microsoft SMTP Server (TLS) id 15.0.1367.3; Wed, 14 Aug 2019 12:11:02 +0000 Received: from EX13MTAUWB001.ant.amazon.com (10.43.161.207) by EX13D03EUA003.ant.amazon.com (10.43.165.89) with Microsoft SMTP Server (TLS) id 15.0.1367.3; Wed, 14 Aug 2019 12:11:01 +0000 Received: from dev-dsk-wipawel-1a-0c4e6d58.eu-west-1.amazon.com (10.4.134.33) by mail-relay.amazon.com (10.43.161.249) with Microsoft SMTP Server id 15.0.1367.3 via Frontend Transport; Wed, 14 Aug 2019 12:10:59 +0000 From: Pawel Wieczorkiewicz To: Date: Wed, 14 Aug 2019 12:10:53 +0000 Message-ID: <20190814121053.16524-1-wipawel@amazon.de> X-Mailer: git-send-email 2.16.5 MIME-Version: 1.0 Precedence: Bulk Subject: [Xen-devel] [PATCH livepatch-hooks-3 1/1] livepatch: Do not enforce ELF_LIVEPATCH_FUNC section presence 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 With default implementation the ELF_LIVEPATCH_FUNC section containing all functions to be replaced or added must be part of the hotpatch payload, otherwise the payload is rejected (with -EINVAL). However, with the extended hooks implementation, a hotpatch may be constructed of only hooks to perform certain actions without any code to be added or replaced. Therefore, do not always expect the functions section and allow it to be missing, provided there is at least one section containing hooks present. The functions section, when present in a payload, must be a single, non-empty section. Check also all extended hooks sections if they are a single, non-empty sections each. At least one of the functions or hooks section must be present in a valid payload. Signed-off-by: Pawel Wieczorkiewicz Reviewed-by: Andra-Irina Paraschiv Reviewed-by: Bjoern Doebel Reviewed-by: Martin Pohlack --- xen/common/livepatch.c | 145 +++++++++++++++++++++++++++++++------------- xen/include/xen/livepatch.h | 8 +++ 2 files changed, 112 insertions(+), 41 deletions(-) diff --git a/xen/common/livepatch.c b/xen/common/livepatch.c index 38fab8b240..c4a107d91c 100644 --- a/xen/common/livepatch.c +++ b/xen/common/livepatch.c @@ -467,8 +467,7 @@ static int check_xen_build_id(const struct payload *payload) static int check_special_sections(const struct livepatch_elf *elf) { unsigned int i; - static const char *const names[] = { ELF_LIVEPATCH_FUNC, - ELF_LIVEPATCH_DEPENDS, + static const char *const names[] = { ELF_LIVEPATCH_DEPENDS, ELF_LIVEPATCH_XEN_DEPENDS, ELF_BUILD_ID_NOTE}; DECLARE_BITMAP(found, ARRAY_SIZE(names)) = { 0 }; @@ -503,6 +502,64 @@ static int check_special_sections(const struct livepatch_elf *elf) return 0; } +static int check_patching_sections(const struct livepatch_elf *elf) +{ + unsigned int i; + static const char *const names[] = { ELF_LIVEPATCH_FUNC, + ELF_LIVEPATCH_LOAD_HOOKS, + ELF_LIVEPATCH_UNLOAD_HOOKS, + ELF_LIVEPATCH_PREAPPLY_HOOK, + ELF_LIVEPATCH_APPLY_HOOK, + ELF_LIVEPATCH_POSTAPPLY_HOOK, + ELF_LIVEPATCH_PREREVERT_HOOK, + ELF_LIVEPATCH_REVERT_HOOK, + ELF_LIVEPATCH_POSTREVERT_HOOK}; + DECLARE_BITMAP(found, ARRAY_SIZE(names)) = { 0 }; + + /* + * The patching sections are optional, but at least one + * must be present. Otherwise, there is nothing to do. + * All the existing sections must not be empty and must + * be present at most once. + */ + for ( i = 0; i < ARRAY_SIZE(names); i++ ) + { + const struct livepatch_elf_sec *sec; + + sec = livepatch_elf_sec_by_name(elf, names[i]); + if ( !sec ) + { + dprintk(XENLOG_INFO, LIVEPATCH "%s: %s is missing!\n", + elf->name, names[i]); + continue; /* This section is optional */ + } + + if ( !sec->sec->sh_size ) + { + dprintk(XENLOG_ERR, LIVEPATCH "%s: %s is empty!\n", + elf->name, names[i]); + return -EINVAL; + } + + if ( test_and_set_bit(i, found) ) + { + dprintk(XENLOG_ERR, LIVEPATCH "%s: %s was seen more than once!\n", + elf->name, names[i]); + return -EINVAL; + } + } + + /* Checking if at least one section is present. */ + if ( bitmap_empty(found, ARRAY_SIZE(names)) ) + { + printk(XENLOG_ERR LIVEPATCH "%s: Nothing to patch. Aborting...\n", + elf->name); + return -EINVAL; + } + + 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 @@ -542,57 +599,59 @@ static int prepare_payload(struct payload *payload, const Elf_Note *n; sec = livepatch_elf_sec_by_name(elf, ELF_LIVEPATCH_FUNC); - ASSERT(sec); - if ( !section_ok(elf, sec, sizeof(*payload->funcs)) ) - return -EINVAL; - - payload->funcs = sec->load_addr; - payload->nfuncs = sec->sec->sh_size / sizeof(*payload->funcs); - - for ( i = 0; i < payload->nfuncs; i++ ) + if ( sec ) { - int rc; + if ( !section_ok(elf, sec, sizeof(*payload->funcs)) ) + return -EINVAL; - f = &(payload->funcs[i]); + payload->funcs = sec->load_addr; + payload->nfuncs = sec->sec->sh_size / sizeof(*payload->funcs); - if ( f->version != LIVEPATCH_PAYLOAD_VERSION ) + for ( i = 0; i < payload->nfuncs; i++ ) { - dprintk(XENLOG_ERR, LIVEPATCH "%s: Wrong version (%u). Expected %d!\n", - elf->name, f->version, LIVEPATCH_PAYLOAD_VERSION); - return -EOPNOTSUPP; - } + int rc; - /* 'old_addr', 'new_addr', 'new_size' can all be zero. */ - if ( !f->old_size ) - { - dprintk(XENLOG_ERR, LIVEPATCH "%s: Address or size fields are zero!\n", - elf->name); - return -EINVAL; - } + f = &(payload->funcs[i]); - rc = arch_livepatch_verify_func(f); - if ( rc ) - return rc; + if ( f->version != LIVEPATCH_PAYLOAD_VERSION ) + { + dprintk(XENLOG_ERR, LIVEPATCH "%s: Wrong version (%u). Expected %d!\n", + elf->name, f->version, LIVEPATCH_PAYLOAD_VERSION); + return -EOPNOTSUPP; + } - rc = resolve_old_address(f, elf); - if ( rc ) - return rc; + /* 'old_addr', 'new_addr', 'new_size' can all be zero. */ + if ( !f->old_size ) + { + dprintk(XENLOG_ERR, LIVEPATCH "%s: Address or size fields are zero!\n", + elf->name); + return -EINVAL; + } - rc = livepatch_verify_distance(f); - if ( rc ) - return rc; + rc = arch_livepatch_verify_func(f); + if ( rc ) + return rc; + + rc = resolve_old_address(f, elf); + if ( rc ) + return rc; + + rc = livepatch_verify_distance(f); + if ( rc ) + return rc; + } } - 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"); + LIVEPATCH_ASSIGN_MULTI_HOOK(elf, payload->load_funcs, payload->n_load_funcs, ELF_LIVEPATCH_LOAD_HOOKS); + LIVEPATCH_ASSIGN_MULTI_HOOK(elf, payload->unload_funcs, payload->n_unload_funcs, ELF_LIVEPATCH_UNLOAD_HOOKS); - LIVEPATCH_ASSIGN_SINGLE_HOOK(elf, payload->hooks.apply.pre, ".livepatch.hooks.preapply"); - LIVEPATCH_ASSIGN_SINGLE_HOOK(elf, payload->hooks.apply.action, ".livepatch.hooks.apply"); - LIVEPATCH_ASSIGN_SINGLE_HOOK(elf, payload->hooks.apply.post, ".livepatch.hooks.postapply"); + LIVEPATCH_ASSIGN_SINGLE_HOOK(elf, payload->hooks.apply.pre, ELF_LIVEPATCH_PREAPPLY_HOOK); + LIVEPATCH_ASSIGN_SINGLE_HOOK(elf, payload->hooks.apply.action, ELF_LIVEPATCH_APPLY_HOOK); + LIVEPATCH_ASSIGN_SINGLE_HOOK(elf, payload->hooks.apply.post, ELF_LIVEPATCH_POSTAPPLY_HOOK); - LIVEPATCH_ASSIGN_SINGLE_HOOK(elf, payload->hooks.revert.pre, ".livepatch.hooks.prerevert"); - LIVEPATCH_ASSIGN_SINGLE_HOOK(elf, payload->hooks.revert.action, ".livepatch.hooks.revert"); - LIVEPATCH_ASSIGN_SINGLE_HOOK(elf, payload->hooks.revert.post, ".livepatch.hooks.postrevert"); + LIVEPATCH_ASSIGN_SINGLE_HOOK(elf, payload->hooks.revert.pre, ELF_LIVEPATCH_PREREVERT_HOOK); + LIVEPATCH_ASSIGN_SINGLE_HOOK(elf, payload->hooks.revert.action, ELF_LIVEPATCH_REVERT_HOOK); + LIVEPATCH_ASSIGN_SINGLE_HOOK(elf, payload->hooks.revert.post, ELF_LIVEPATCH_POSTREVERT_HOOK); sec = livepatch_elf_sec_by_name(elf, ELF_BUILD_ID_NOTE); if ( sec ) @@ -904,6 +963,10 @@ static int load_payload_data(struct payload *payload, void *raw, size_t len) if ( rc ) goto out; + rc = check_patching_sections(&elf); + if ( rc ) + goto out; + rc = prepare_payload(payload, &elf); if ( rc ) goto out; diff --git a/xen/include/xen/livepatch.h b/xen/include/xen/livepatch.h index ed997aa4cc..2aec532ee2 100644 --- a/xen/include/xen/livepatch.h +++ b/xen/include/xen/livepatch.h @@ -33,6 +33,14 @@ struct xen_sysctl_livepatch_op; #define ELF_LIVEPATCH_DEPENDS ".livepatch.depends" #define ELF_LIVEPATCH_XEN_DEPENDS ".livepatch.xen_depends" #define ELF_BUILD_ID_NOTE ".note.gnu.build-id" +#define ELF_LIVEPATCH_LOAD_HOOKS ".livepatch.hooks.load" +#define ELF_LIVEPATCH_UNLOAD_HOOKS ".livepatch.hooks.unload" +#define ELF_LIVEPATCH_PREAPPLY_HOOK ".livepatch.hooks.preapply" +#define ELF_LIVEPATCH_APPLY_HOOK ".livepatch.hooks.apply" +#define ELF_LIVEPATCH_POSTAPPLY_HOOK ".livepatch.hooks.postapply" +#define ELF_LIVEPATCH_PREREVERT_HOOK ".livepatch.hooks.prerevert" +#define ELF_LIVEPATCH_REVERT_HOOK ".livepatch.hooks.revert" +#define ELF_LIVEPATCH_POSTREVERT_HOOK ".livepatch.hooks.postrevert" /* Arbitrary limit for payload size and .bss section size. */ #define LIVEPATCH_MAX_SIZE MB(2)