From patchwork Tue Sep 12 00:37:18 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Konrad Rzeszutek Wilk X-Patchwork-Id: 9948219 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 5E2626038F for ; Tue, 12 Sep 2017 00:40:06 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 44A1E28D31 for ; Tue, 12 Sep 2017 00:40:06 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 392BD28D5E; Tue, 12 Sep 2017 00:40:06 +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=-3.6 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_MED,RCVD_IN_SORBS_SPAM,T_DKIM_INVALID 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 A238628D52 for ; Tue, 12 Sep 2017 00:40:03 +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 1drZDD-0000hl-U3; Tue, 12 Sep 2017 00:37:59 +0000 Received: from mail6.bemta5.messagelabs.com ([195.245.231.135]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1drZDD-0000hI-CL for xen-devel@lists.xenproject.org; Tue, 12 Sep 2017 00:37:59 +0000 Received: from [85.158.139.211] by server-2.bemta-5.messagelabs.com id 16/7F-02021-66C27B95; Tue, 12 Sep 2017 00:37:58 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFrrAIsWRWlGSWpSXmKPExsVyMfTOYd1Une2 RBvP3qVp83zKZyYHR4/CHKywBjFGsmXlJ+RUJrBlvF91lLDgeXLFjUydjA+Ny5y5GLg4hgRmM EsufbWQFcVgEPrBI3Ll8lB3EkRCYxirxb/MMpi5GTiAnTuLmvA9ANgeQnSaxrsUEIlwhMfveb XYQW0hASWLL5MeMEFMPMkk82PqOESQhLKAnMfnbbTCbTUBf4unaa8wQc9wkPl3jAqkXEWhnlJ h95RcrSA2zgKFE69ujbBC9bhLHV/Qxg9gsAqoSjxtbwWp4Bawkeq69ZoE4Ql5iYu80sPmcQPH fP+axQhxkKdGx4ArTBEbhBYwMqxg1ilOLylKLdI0M9ZKKMtMzSnITM3N0DQ1M9XJTi4sT01Nz EpOK9ZLzczcxAkO0noGBcQfj3cl+hxglOZiURHl/C2+PFOJLyk+pzEgszogvKs1JLT7EKMPBo STB+0ILKCdYlJqeWpGWmQOMFpi0BAePkghvFkiat7ggMbc4Mx0idYrRkuPCnUt/mDgO7LkFJD tu3v3DJMSSl5+XKiXO+xukQQCkIaM0D24cLKIvMcpKCfMyMjAwCPEUpBblZpagyr9iFOdgVBL mVdcGmsKTmVcCt/UV0EFMQAfxXNoCclBJIkJKqoExwiH9v7Xk8k7LvNWht1dX5Ym+PfF81/+W vlnTU96EH/1wIGzZSe19O5Vf6Vy4v3hNjsRyv+9TEmRNV1r+/7Vp69IVCVzt6W1zJlyLszX1/ vhBk2c68xQHxcmPuZvvzZylfphN3Fl1555XvsKl/Pu455qtmGadbqxnW9mwadKxDU++5q5rXP UyT4mlOCPRUIu5qDgRAEU9Ao/jAgAA X-Env-Sender: ketuzsezr@gmail.com X-Msg-Ref: server-11.tower-206.messagelabs.com!1505176676!89920289!1 X-Originating-IP: [209.85.220.195] X-SpamReason: No, hits=0.0 required=7.0 tests= X-StarScan-Received: X-StarScan-Version: 9.4.45; banners=-,-,- X-VirusChecked: Checked Received: (qmail 12327 invoked from network); 12 Sep 2017 00:37:57 -0000 Received: from mail-qk0-f195.google.com (HELO mail-qk0-f195.google.com) (209.85.220.195) by server-11.tower-206.messagelabs.com with AES128-GCM-SHA256 encrypted SMTP; 12 Sep 2017 00:37:57 -0000 Received: by mail-qk0-f195.google.com with SMTP id c69so6371744qke.5 for ; Mon, 11 Sep 2017 17:37:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=6DQnge/PPbspdDfy0SYlXU/yr1/5hHFyfnNrqGlStGE=; b=G3Tn49MlwjBac5/r65qKd7E5yk+FKuBN4TmIBevc5OVi47/tTwVHZLNK+o/u1umB6s PsDOFBJDIJnPTD2lEnNCc35KIgAD2Qo3pTvcczE9uqlNTdpJgFGkEDZWIaMGYf/4UhaZ JIVXCEEBjddTAPovtlG8zaavz1bkP8bCeAWX2sR5hVPO7LTGpam/h/DGp7OTQSnEcYIl 1Ala6guTjUZHPKzmqys8j+3AoXh0eVTDnvnSADMxdUnlIJQnUSXIfcC/Gz/nu2PvL5n5 9fr1f1gL+o2x2kRihaCozZPRc1/+LTMCRIp+IqPxCFPqDZ489PWnPgBuLr2QOip2Vb0M fR9A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references; bh=6DQnge/PPbspdDfy0SYlXU/yr1/5hHFyfnNrqGlStGE=; b=D5fXekVgVgvJlgEdL40bVhTWIDLNavx1Fbg6msBSjMdoVqBZETMwfBhGkXQGcWvTPV rgIaRRrBkGnIUy7fnsuRaSX4moIKTmHWC1z6ZJ2TsjelYFjac0VWBEdQiGLy/k9E02rm YnNJAxdxgFJ6hTIg9WOpUoun/OV8IMdvixhHM+iZzAX9jIbQpS28KdH8h6s7zrRydL3J ri3CDV4KHtgW6BiuzhNegO8XfygvoH4ym9ANj3+1UuVV6SQ9AzMFt24oLGVknihIcZ7v fHW7BYMAqM1Jqhk/leb/1IqIVPHEdS3llcLRFpEOerCi5o70Ah4XhgV4RDXIBrwp8H6m /llQ== X-Gm-Message-State: AHPjjUgkU1iHCN1KU5PMAKpN+3NlIbsyz3tUprZMi27hev/23vFRRStL y5kPFuC7G09s2qRj X-Google-Smtp-Source: AOwi7QCnqMTBwwQ2gem6K8hpkHrpjbFIS30DuYjbkynUWTFR4AI5I9lHKvcxSVlzIxCV0ESEk9ygOw== X-Received: by 10.55.20.16 with SMTP id e16mr18963904qkh.97.1505176675897; Mon, 11 Sep 2017 17:37:55 -0700 (PDT) Received: from localhost.localdomain (209-6-200-48.s4398.c3-0.smr-ubr2.sbo-smr.ma.cable.rcncustomer.com. [209.6.200.48]) by smtp.gmail.com with ESMTPSA id z75sm6771034qkb.71.2017.09.11.17.37.55 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Mon, 11 Sep 2017 17:37:55 -0700 (PDT) From: Konrad Rzeszutek Wilk X-Google-Original-From: Konrad Rzeszutek Wilk To: xen-devel@lists.xenproject.org, ross.lagerwall@citrix.com, konrad.wilk@oracle.com, julien.grall@arm.com, sstabellini@kernel.org Date: Mon, 11 Sep 2017 20:37:18 -0400 Message-Id: <20170912003726.368-10-konrad.wilk@oracle.com> X-Mailer: git-send-email 2.13.3 In-Reply-To: <20170912003726.368-1-konrad.wilk@oracle.com> References: <20170912003726.368-1-konrad.wilk@oracle.com> Cc: andrew.cooper3@citrix.com, jbeulich@suse.com Subject: [Xen-devel] [PATCH v3 09/17] livepatch/arm[32, 64]: Modify livepatch_funcs 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 This was found when porting livepatch-build-tools to ARM64/32. When livepatch-build-tools are built (and test-case thanks to: livepatch/tests: Make sure all .livepatch.funcs sections are read-only) the .livepatch.funcs are in read-only section. However the hypervisor uses the 'opaque' for its own purpose, that is stashing the original code. But the .livepatch_funcs section is in the RO vmap area so on ARM[32,64] we get a fault. On x86 the same protection is in place. In 'arch_livepatch_quiesce' we disable WP to allow changes to read-only pages (and in arch_live_resume we enable the WP protection). On ARM[32,64] we do not have the luxury of a global register that can be changed after boot. In lieu of that we use the vmap to create a temporary virtual address in which we can use instead. To do this we need to stash during livepatch: vmap of the hypervisor code, vmap of the .livepatch_funcs (vmap comes in page aligned virtual addresses), offset in the vmap (in case it is not nicely aligned), and the original first livepatch_funcs to figure out the index. Equipped with that we can patch livepatch functions which have .livepatch_funcs in rodata section. An alternative is to add the 'W' flag during loading of the .livepatch_funcs which would result the section being in writeable region from the gecko. Note that this vmap solution could be extended to x86 as well. Signed-off-by: Konrad Rzeszutek Wilk --- xen/arch/arm/arm32/livepatch.c | 11 ++++++--- xen/arch/arm/arm64/livepatch.c | 11 ++++++--- xen/arch/arm/livepatch.c | 52 ++++++++++++++++++++++++++++++++--------- xen/arch/x86/livepatch.c | 2 +- xen/common/livepatch.c | 5 ++-- xen/include/asm-arm/livepatch.h | 13 ++++++++--- xen/include/xen/livepatch.h | 2 +- 7 files changed, 71 insertions(+), 25 deletions(-) diff --git a/xen/arch/arm/arm32/livepatch.c b/xen/arch/arm/arm32/livepatch.c index 10887ace81..d793ebcaad 100644 --- a/xen/arch/arm/arm32/livepatch.c +++ b/xen/arch/arm/arm32/livepatch.c @@ -16,18 +16,23 @@ void arch_livepatch_apply(struct livepatch_func *func) uint32_t insn; uint32_t *new_ptr; unsigned int i, len; + struct livepatch_func *f; BUILD_BUG_ON(ARCH_PATCH_INSN_SIZE > sizeof(func->opaque)); BUILD_BUG_ON(ARCH_PATCH_INSN_SIZE != sizeof(insn)); - ASSERT(vmap_of_xen_text); + ASSERT(livepatch_vmap.text); len = livepatch_insn_len(func); if ( !len ) return; + /* Index in the vmap region. */ + i = livepatch_vmap.va - func; + f = (struct livepatch_func *)(livepatch_vmap.funcs + livepatch_vmap.offset) + i; + /* Save old ones. */ - memcpy(func->opaque, func->old_addr, len); + memcpy(f->opaque, func->old_addr, len); if ( func->new_addr ) { @@ -56,7 +61,7 @@ void arch_livepatch_apply(struct livepatch_func *func) else insn = 0xe1a00000; /* mov r0, r0 */ - new_ptr = func->old_addr - (void *)_start + vmap_of_xen_text; + new_ptr = func->old_addr - (void *)_start + livepatch_vmap.text; len = len / sizeof(uint32_t); /* PATCH! */ diff --git a/xen/arch/arm/arm64/livepatch.c b/xen/arch/arm/arm64/livepatch.c index 2728e2a125..662bedabc3 100644 --- a/xen/arch/arm/arm64/livepatch.c +++ b/xen/arch/arm/arm64/livepatch.c @@ -20,18 +20,23 @@ void arch_livepatch_apply(struct livepatch_func *func) uint32_t insn; uint32_t *new_ptr; unsigned int i, len; + struct livepatch_func *f; BUILD_BUG_ON(ARCH_PATCH_INSN_SIZE > sizeof(func->opaque)); BUILD_BUG_ON(ARCH_PATCH_INSN_SIZE != sizeof(insn)); - ASSERT(vmap_of_xen_text); + ASSERT(livepatch_vmap.text); len = livepatch_insn_len(func); if ( !len ) return; + /* Index in the vmap region. */ + i = livepatch_vmap.va - func; + f = (struct livepatch_func *)(livepatch_vmap.funcs + livepatch_vmap.offset) + i; + /* Save old ones. */ - memcpy(func->opaque, func->old_addr, len); + memcpy(f->opaque, func->old_addr, len); if ( func->new_addr ) insn = aarch64_insn_gen_branch_imm((unsigned long)func->old_addr, @@ -43,7 +48,7 @@ void arch_livepatch_apply(struct livepatch_func *func) /* Verified in livepatch_verify_distance. */ ASSERT(insn != AARCH64_BREAK_FAULT); - new_ptr = func->old_addr - (void *)_start + vmap_of_xen_text; + new_ptr = func->old_addr - (void *)_start + livepatch_vmap.text; len = len / sizeof(uint32_t); /* PATCH! */ diff --git a/xen/arch/arm/livepatch.c b/xen/arch/arm/livepatch.c index 3e53524365..2f9ae8e61e 100644 --- a/xen/arch/arm/livepatch.c +++ b/xen/arch/arm/livepatch.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -16,14 +17,18 @@ #undef virt_to_mfn #define virt_to_mfn(va) _mfn(__virt_to_mfn(va)) -void *vmap_of_xen_text; +struct livepatch_vmap_stash livepatch_vmap; -int arch_livepatch_quiesce(void) +int arch_livepatch_quiesce(struct livepatch_func *funcs, unsigned int nfuncs) { - mfn_t text_mfn; + mfn_t text_mfn, rodata_mfn; + void *vmap_addr; unsigned int text_order; + unsigned long va = (unsigned long)(funcs); + unsigned int offs = va & (PAGE_SIZE - 1); + unsigned int size = PFN_UP(offs + nfuncs * sizeof(*funcs)); - if ( vmap_of_xen_text ) + if ( livepatch_vmap.text || livepatch_vmap.funcs ) return -EINVAL; text_mfn = virt_to_mfn(_start); @@ -33,16 +38,33 @@ int arch_livepatch_quiesce(void) * The text section is read-only. So re-map Xen to be able to patch * the code. */ - vmap_of_xen_text = __vmap(&text_mfn, 1U << text_order, 1, 1, PAGE_HYPERVISOR, - VMAP_DEFAULT); + vmap_addr = __vmap(&text_mfn, 1U << text_order, 1, 1, PAGE_HYPERVISOR, + VMAP_DEFAULT); - if ( !vmap_of_xen_text ) + if ( !vmap_addr ) { printk(XENLOG_ERR LIVEPATCH "Failed to setup vmap of hypervisor! (order=%u)\n", text_order); return -ENOMEM; } + livepatch_vmap.text = vmap_addr; + livepatch_vmap.offset = offs; + + rodata_mfn = virt_to_mfn(va & PAGE_MASK); + vmap_addr = __vmap(&rodata_mfn, size, 1, 1, PAGE_HYPERVISOR, VMAP_DEFAULT); + if ( !vmap_addr ) + { + printk(XENLOG_ERR LIVEPATCH "Failed to setup vmap of livepatch_funcs! (mfn=%"PRI_mfn", size=%u)\n", + mfn_x(rodata_mfn), size); + vunmap(livepatch_vmap.text); + livepatch_vmap.text = NULL; + return -ENOMEM; + } + + livepatch_vmap.funcs = vmap_addr; + livepatch_vmap.va = funcs; + return 0; } @@ -54,10 +76,18 @@ void arch_livepatch_revive(void) */ invalidate_icache(); - if ( vmap_of_xen_text ) - vunmap(vmap_of_xen_text); + if ( livepatch_vmap.text ) + vunmap(livepatch_vmap.text); + + livepatch_vmap.text = NULL; + + if ( livepatch_vmap.funcs ) + vunmap(livepatch_vmap.funcs); + + livepatch_vmap.funcs = NULL; - vmap_of_xen_text = NULL; + livepatch_vmap.va = NULL; + livepatch_vmap.offset = 0; } int arch_livepatch_verify_func(const struct livepatch_func *func) @@ -78,7 +108,7 @@ void arch_livepatch_revert(const struct livepatch_func *func) uint32_t *new_ptr; unsigned int len; - new_ptr = func->old_addr - (void *)_start + vmap_of_xen_text; + new_ptr = func->old_addr - (void *)_start + livepatch_vmap.text; len = livepatch_insn_len(func); memcpy(new_ptr, func->opaque, len); diff --git a/xen/arch/x86/livepatch.c b/xen/arch/x86/livepatch.c index 48d20fdacd..8522fcbd36 100644 --- a/xen/arch/x86/livepatch.c +++ b/xen/arch/x86/livepatch.c @@ -14,7 +14,7 @@ #include #include -int arch_livepatch_quiesce(void) +int arch_livepatch_quiesce(struct livepatch_func *func, unsigned int nfuncs) { /* Disable WP to allow changes to read-only pages. */ write_cr0(read_cr0() & ~X86_CR0_WP); diff --git a/xen/common/livepatch.c b/xen/common/livepatch.c index dbab8a3f6f..e707802279 100644 --- a/xen/common/livepatch.c +++ b/xen/common/livepatch.c @@ -571,7 +571,6 @@ static int prepare_payload(struct payload *payload, if ( rc ) return rc; } - sec = livepatch_elf_sec_by_name(elf, ".livepatch.hooks.load"); if ( sec ) { @@ -1070,7 +1069,7 @@ static int apply_payload(struct payload *data) printk(XENLOG_INFO LIVEPATCH "%s: Applying %u functions\n", data->name, data->nfuncs); - rc = arch_livepatch_quiesce(); + rc = arch_livepatch_quiesce(data->funcs, data->nfuncs); if ( rc ) { printk(XENLOG_ERR LIVEPATCH "%s: unable to quiesce!\n", data->name); @@ -1111,7 +1110,7 @@ static int revert_payload(struct payload *data) printk(XENLOG_INFO LIVEPATCH "%s: Reverting\n", data->name); - rc = arch_livepatch_quiesce(); + rc = arch_livepatch_quiesce(data->funcs, data->nfuncs); if ( rc ) { printk(XENLOG_ERR LIVEPATCH "%s: unable to quiesce!\n", data->name); diff --git a/xen/include/asm-arm/livepatch.h b/xen/include/asm-arm/livepatch.h index 6bca79deb9..e030aedced 100644 --- a/xen/include/asm-arm/livepatch.h +++ b/xen/include/asm-arm/livepatch.h @@ -12,10 +12,17 @@ #define ARCH_PATCH_INSN_SIZE 4 /* - * The va of the hypervisor .text region. We need this as the - * normal va are write protected. + * The va of the hypervisor .text region and the livepatch_funcs. + * We need this as the normal va are write protected. */ -extern void *vmap_of_xen_text; +struct livepatch_vmap_stash { + void *text; /* vmap of hypervisor code. */ + void *funcs; /* vmap of the .livepatch.funcs. */ + unsigned int offset; /* Offset in 'funcs'. */ + struct livepatch_func *va; /* The original va. */ +}; + +extern struct livepatch_vmap_stash livepatch_vmap; /* These ranges are only for unconditional branches. */ #ifdef CONFIG_ARM_32 diff --git a/xen/include/xen/livepatch.h b/xen/include/xen/livepatch.h index e9bab87f28..a97afb92f9 100644 --- a/xen/include/xen/livepatch.h +++ b/xen/include/xen/livepatch.h @@ -104,7 +104,7 @@ static inline int livepatch_verify_distance(const struct livepatch_func *func) * These functions are called around the critical region patching live code, * for an architecture to take make appropratie global state adjustments. */ -int arch_livepatch_quiesce(void); +int arch_livepatch_quiesce(struct livepatch_func *func, unsigned int nfuncs); void arch_livepatch_revive(void); void arch_livepatch_apply(struct livepatch_func *func);