From patchwork Sat Sep 28 15:12:59 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Wieczorkiewicz, Pawel" X-Patchwork-Id: 11165435 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E6423912 for ; Sat, 28 Sep 2019 15:16:23 +0000 (UTC) Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id B582E20863 for ; Sat, 28 Sep 2019 15:16:23 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=amazon.de header.i=@amazon.de header.b="ff/ADLC7" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org B582E20863 Authentication-Results: mail.kernel.org; dmarc=fail (p=quarantine dis=none) header.from=amazon.de Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=xen-devel-bounces@lists.xenproject.org Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1iEERC-00014q-Bl; Sat, 28 Sep 2019 15:15:10 +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 1iEERA-00014F-TN for xen-devel@lists.xenproject.org; Sat, 28 Sep 2019 15:15:08 +0000 X-Inumbo-ID: c186eeb2-e202-11e9-969c-12813bfff9fa Received: from smtp-fw-9102.amazon.com (unknown [207.171.184.29]) by localhost (Halon) with ESMTPS id c186eeb2-e202-11e9-969c-12813bfff9fa; Sat, 28 Sep 2019 15:15:08 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amazon.de; i=@amazon.de; q=dns/txt; s=amazon201209; t=1569683708; x=1601219708; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version; bh=oArMHyT/16A8vc/tCtslc/4R/RbLonnB9l9ieNolArw=; b=ff/ADLC70Ef/R3zVzphyLfmvU8590uwSGMqFN4pg+1rVVctAchDnJQ4F wreQBVyMo5J0YqfrzyF9tKCPOidi8AAUecrtWWYbwS74FY732I/xMcgG2 873yTLv9sNS0aJgDpeJWSHt8vhxudoy668MpyYPUMk8+GUsMzwxFoYeuH s=; X-IronPort-AV: E=Sophos;i="5.64,559,1559520000"; d="scan'208";a="705176527" Received: from sea3-co-svc-lb6-vlan3.sea.amazon.com (HELO email-inbound-relay-1d-9ec21598.us-east-1.amazon.com) ([10.47.22.38]) by smtp-border-fw-out-9102.sea19.amazon.com with ESMTP; 28 Sep 2019 15:14:13 +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-9ec21598.us-east-1.amazon.com (Postfix) with ESMTPS id C54F9A1D6B; Sat, 28 Sep 2019 15:13:55 +0000 (UTC) Received: from EX13D05EUB001.ant.amazon.com (10.43.166.87) by EX13MTAUEA001.ant.amazon.com (10.43.61.243) with Microsoft SMTP Server (TLS) id 15.0.1367.3; Sat, 28 Sep 2019 15:13:46 +0000 Received: from EX13MTAUWB001.ant.amazon.com (10.43.161.207) by EX13D05EUB001.ant.amazon.com (10.43.166.87) with Microsoft SMTP Server (TLS) id 15.0.1367.3; Sat, 28 Sep 2019 15:13:45 +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; Sat, 28 Sep 2019 15:13:42 +0000 From: Pawel Wieczorkiewicz To: Date: Sat, 28 Sep 2019 15:12:59 +0000 Message-ID: <20190928151305.127380-7-wipawel@amazon.de> X-Mailer: git-send-email 2.16.5 In-Reply-To: <20190928151305.127380-1-wipawel@amazon.de> References: <20190928151305.127380-1-wipawel@amazon.de> MIME-Version: 1.0 Precedence: Bulk Subject: [Xen-devel] [PATCH v4 06/12] 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: Pawel Wieczorkiewicz , wipawel@amazon.com, Ross Lagerwall , mpohlack@amazon.com, Konrad Rzeszutek Wilk Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" With default implementation the ELF_LIVEPATCH_FUNC section containing all functions to be replaced or added must be part of the livepatch payload, otherwise the payload is rejected (with -EINVAL). However, with the extended hooks implementation, a livepatch 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 Signed-off-by: Konrad Rzeszutek Wilk Reviewed-by: Ross Lagerwall --- Changed since v3: * fix indent Changed since v1: * always print XENLOG_ERR messages * remove ASSERT from build_symbol_table() * added corresponding documentation * added tests xen/common/livepatch.c | 147 +++++++++++++++++++-------- xen/include/xen/livepatch.h | 8 ++ xen/test/livepatch/Makefile | 9 +- xen/test/livepatch/xen_action_hooks_nofunc.c | 86 ++++++++++++++++ 4 files changed, 206 insertions(+), 44 deletions(-) create mode 100644 xen/test/livepatch/xen_action_hooks_nofunc.c diff --git a/xen/common/livepatch.c b/xen/common/livepatch.c index 38b1e3519d..c70fd5f600 100644 --- a/xen/common/livepatch.c +++ b/xen/common/livepatch.c @@ -467,8 +467,7 @@ static int xen_build_id_dep(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_DEBUG, LIVEPATCH "%s: %s is missing\n", + elf->name, names[i]); + continue; /* This section is optional */ + } + + if ( !sec->sec->sh_size ) + { + printk(XENLOG_ERR LIVEPATCH "%s: %s is empty\n", + elf->name, names[i]); + return -EINVAL; + } + + if ( test_and_set_bit(i, found) ) + { + printk(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++ ) { - printk(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 ) - { - printk(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 ) + { + printk(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 ) + { + printk(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 ) @@ -786,8 +845,6 @@ static int build_symbol_table(struct payload *payload, struct livepatch_symbol *symtab; char *strtab; - ASSERT(payload->nfuncs); - /* Recall that section @0 is always NULL. */ for ( i = 1; i < elf->nsym; i++ ) { @@ -904,6 +961,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) diff --git a/xen/test/livepatch/Makefile b/xen/test/livepatch/Makefile index 116e52e774..bbc6bdaf64 100644 --- a/xen/test/livepatch/Makefile +++ b/xen/test/livepatch/Makefile @@ -23,6 +23,7 @@ LIVEPATCH_NO_XEN_BUILDID := xen_no_xen_buildid.livepatch LIVEPATCH_PREPOST_HOOKS := xen_prepost_hooks.livepatch LIVEPATCH_PREPOST_HOOKS_FAIL := xen_prepost_hooks_fail.livepatch LIVEPATCH_ACTION_HOOKS := xen_action_hooks.livepatch +LIVEPATCH_ACTION_HOOKS_NOFUNC := xen_action_hooks_nofunc.livepatch LIVEPATCHES += $(LIVEPATCH) LIVEPATCHES += $(LIVEPATCH_BYE) @@ -32,6 +33,7 @@ LIVEPATCHES += $(LIVEPATCH_NO_XEN_BUILDID) LIVEPATCHES += $(LIVEPATCH_PREPOST_HOOKS) LIVEPATCHES += $(LIVEPATCH_PREPOST_HOOKS_FAIL) LIVEPATCHES += $(LIVEPATCH_ACTION_HOOKS) +LIVEPATCHES += $(LIVEPATCH_ACTION_HOOKS_NOFUNC) LIVEPATCH_DEBUG_DIR ?= $(DEBUG_DIR)/xen-livepatch @@ -152,6 +154,11 @@ xen_actions_hooks.o: config.h $(LIVEPATCH_ACTION_HOOKS): xen_action_hooks.o xen_hello_world_func.o note.o xen_note.o $(LD) $(LDFLAGS) $(build_id_linker) -r -o $(LIVEPATCH_ACTION_HOOKS) $^ +.PHONY: $(LIVEPATCH_ACTION_HOOKS_NOFUNC) +$(LIVEPATCH_ACTION_HOOKS_NOFUNC): xen_action_hooks_nofunc.o note.o xen_note.o + $(LD) $(LDFLAGS) $(build_id_linker) -r -o $(LIVEPATCH_ACTION_HOOKS_NOFUNC) $^ + .PHONY: livepatch livepatch: $(LIVEPATCH) $(LIVEPATCH_BYE) $(LIVEPATCH_REPLACE) $(LIVEPATCH_NOP) $(LIVEPATCH_NO_XEN_BUILDID) \ - $(LIVEPATCH_PREPOST_HOOKS) $(LIVEPATCH_PREPOST_HOOKS_FAIL) $(LIVEPATCH_ACTION_HOOKS) + $(LIVEPATCH_PREPOST_HOOKS) $(LIVEPATCH_PREPOST_HOOKS_FAIL) $(LIVEPATCH_ACTION_HOOKS) \ + $(LIVEPATCH_ACTION_HOOKS_NOFUNC) diff --git a/xen/test/livepatch/xen_action_hooks_nofunc.c b/xen/test/livepatch/xen_action_hooks_nofunc.c new file mode 100644 index 0000000000..2b4e90436f --- /dev/null +++ b/xen/test/livepatch/xen_action_hooks_nofunc.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2019 Amazon.com, Inc. or its affiliates. All rights reserved. + * + */ + +#include "config.h" +#include +#include +#include +#include +#include + +#include + +static unsigned int apply_cnt; +static unsigned int revert_cnt; + +static int apply_hook(livepatch_payload_t *payload) +{ + int i; + + printk(KERN_DEBUG "%s: Hook starting.\n", __func__); + + for (i = 0; i < payload->nfuncs; i++) + { + struct livepatch_func *func = &payload->funcs[i]; + + apply_cnt++; + printk(KERN_DEBUG "%s: applying: %s\n", __func__, func->name); + } + + printk(KERN_DEBUG "%s: Hook done.\n", __func__); + + return 0; +} + +static int revert_hook(livepatch_payload_t *payload) +{ + int i; + + printk(KERN_DEBUG "%s: Hook starting.\n", __func__); + + for (i = 0; i < payload->nfuncs; i++) + { + struct livepatch_func *func = &payload->funcs[i]; + + revert_cnt++; + printk(KERN_DEBUG "%s: reverting: %s\n", __func__, func->name); + } + + printk(KERN_DEBUG "%s: Hook done.\n", __func__); + + return 0; +} + +static void post_revert_hook(livepatch_payload_t *payload) +{ + int i; + + printk(KERN_DEBUG "%s: Hook starting.\n", __func__); + + for (i = 0; i < payload->nfuncs; i++) + { + struct livepatch_func *func = &payload->funcs[i]; + + printk(KERN_DEBUG "%s: reverted: %s\n", __func__, func->name); + } + + BUG_ON(apply_cnt > 0 || revert_cnt > 0); + printk(KERN_DEBUG "%s: Hook done.\n", __func__); +} + +LIVEPATCH_APPLY_HOOK(apply_hook); +LIVEPATCH_REVERT_HOOK(revert_hook); + +LIVEPATCH_POSTREVERT_HOOK(post_revert_hook); + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */