From patchwork Sun Sep 11 20:35:14 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: 9325595 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 23D696048B for ; Sun, 11 Sep 2016 20:38:40 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 13AF0284EF for ; Sun, 11 Sep 2016 20:38:40 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 0844F28AB7; Sun, 11 Sep 2016 20:38:40 +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 48850284EF for ; Sun, 11 Sep 2016 20:38:39 +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 1bjBTm-0001xn-US; Sun, 11 Sep 2016 20:35:54 +0000 Received: from mail6.bemta5.messagelabs.com ([195.245.231.135]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1bjBTl-0001wO-F1 for xen-devel@lists.xenproject.org; Sun, 11 Sep 2016 20:35:53 +0000 Received: from [85.158.139.211] by server-9.bemta-5.messagelabs.com id 49/B9-13924-820C5D75; Sun, 11 Sep 2016 20:35:52 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFvrFLMWRWlGSWpSXmKPExsXSO6nOVVfjwNV wg/8r2S2+b5nM5MDocfjDFZYAxijWzLyk/IoE1ozrJ5qZC9abVyxbOpetgXGBXhcjF4eQwGQm iSvdK5ggnN+MEicPPmaEcDYySjxrnMoK4UxglOidfAeojIODTcBE4s0qR5C4iEAbo8S3E1vZu xg5OZgFyiQeLn7CCmILC0RKPO5+yAZiswioSny7+5AJxOYVcJN4/LSJFWSOhIC8xLPb9SBhTg F3iY1z3rOAhIWASk70GIOEJQSMJdrfXmSbwMi3gJFhFaN6cWpRWWqRrqleUlFmekZJbmJmjq6 hgalebmpxcWJ6ak5iUrFecn7uJkZgmDAAwQ7GL/3OhxglOZiURHn9F1wNF+JLyk+pzEgszogv Ks1JLT7EKMPBoSTBe3ofUE6wKDU9tSItMwcYsDBpCQ4eJRHevyBp3uKCxNzizHSI1ClGRSlxX lmQhABIIqM0D64NFiWXGGWlhHkZgQ4R4ilILcrNLEGVf8UozsGoJMzLsR9oCk9mXgnc9FdAi5 mAFj/dehlkcUkiQkqqgdHf2/lowuLLTs5Beqt/KkrmTfGv+PLD7JpX81npqLCUizePhnHem79 87/Lrz/waTfU/HXz8NW7H7wuapgllx/M+b57zt+nBrpwHmnrJDDn3Lp0v9W5/tVzE6akIo0Gj tM3WDZ+SJ8m7O9f8vGFwad3ksxe3T4ldsfPb0ksH60PmrHh1XezNqfX/lFiKMxINtZiLihMBd NOud40CAAA= X-Env-Sender: konrad.wilk@oracle.com X-Msg-Ref: server-3.tower-206.messagelabs.com!1473626150!55320035!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 45580 invoked from network); 11 Sep 2016 20:35:51 -0000 Received: from aserp1040.oracle.com (HELO aserp1040.oracle.com) (141.146.126.69) by server-3.tower-206.messagelabs.com with DHE-RSA-AES256-GCM-SHA384 encrypted SMTP; 11 Sep 2016 20:35:51 -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 u8BKZggX004818 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Sun, 11 Sep 2016 20:35:42 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 u8BKZf4Q014216 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Sun, 11 Sep 2016 20:35:42 GMT Received: from abhmp0016.oracle.com (abhmp0016.oracle.com [141.146.116.22]) by userv0122.oracle.com (8.14.4/8.14.4) with ESMTP id u8BKZeHb015943; Sun, 11 Sep 2016 20:35:41 GMT Received: from localhost.localdomain.com (/209.6.196.81) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Sun, 11 Sep 2016 13:35:40 -0700 From: Konrad Rzeszutek Wilk To: xen-devel@lists.xenproject.org, konrad@kernel.org, julien.grall@arm.com, sstabellini@kernel.org, ross.lagerwall@citrix.com Date: Sun, 11 Sep 2016 16:35:14 -0400 Message-Id: <1473626125-13683-8-git-send-email-konrad.wilk@oracle.com> X-Mailer: git-send-email 2.4.11 In-Reply-To: <1473626125-13683-1-git-send-email-konrad.wilk@oracle.com> References: <1473626125-13683-1-git-send-email-konrad.wilk@oracle.com> X-Source-IP: aserv0022.oracle.com [141.146.126.234] Cc: andrew.cooper3@citrix.com, Jan Beulich , Konrad Rzeszutek Wilk Subject: [Xen-devel] [PATCH v3 07/18] livepatch: ARM/x86: Check displacement of old_addr and new_addr 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 If the distance is too great we are in trouble - as our relocation distance can surely be clipped, or still have a valid width - but cause an overflow of distance. On various architectures the maximum displacement for a unconditional branch/jump varies. ARM32 is +/- 32MB, ARM64 is +/- 128MB while x86 for 32-bit relocations is +/- 2G. Note: On x86 we could use the 64-bit jmpq instruction which would provide much bigger displacement to do a jump, but we would still have issues with the new function not being able to reach any of the old functions (as all the relocations would assume 32-bit displacement). On ARM the conditional branch supports even a smaller displacement but fortunatly we are not using that. Signed-off-by: Konrad Rzeszutek Wilk --- Cc: Andrew Cooper Cc: Jan Beulich Cc: Stefano Stabellini Cc: Julien Grall v3: New submission. --- docs/misc/livepatch.markdown | 14 +++++++++++++- xen/arch/arm/arm64/livepatch.c | 1 + xen/arch/x86/livepatch.c | 2 +- xen/common/livepatch.c | 4 ++++ xen/include/asm-arm/livepatch.h | 11 +++++++++++ xen/include/asm-x86/livepatch.h | 3 +++ xen/include/xen/livepatch.h | 22 +++++++++++++++++++--- 7 files changed, 52 insertions(+), 5 deletions(-) diff --git a/docs/misc/livepatch.markdown b/docs/misc/livepatch.markdown index 53b5371..52c281d 100644 --- a/docs/misc/livepatch.markdown +++ b/docs/misc/livepatch.markdown @@ -1099,7 +1099,7 @@ can be changed during payload application. The hypervisor should verify that the in-place patching would fit within the code or data. -### Trampoline (e9 opcode) +### Trampoline (e9 opcode), x86 The e9 opcode used for jmpq uses a 32-bit signed displacement. That means we are limited to up to 2GB of virtual address to place the new code @@ -1133,3 +1133,15 @@ that in the hypervisor is advised. The tool for generating payloads currently does perform a compile-time check to ensure that the function to be replaced is large enough. +The hypervisor also checks the displacement during loading of the payload. + +#### Trampoline (ea opcode), ARM + +The 0xea000000 instruction (with proper offset) is used for an unconditional +branch to the new code. This means we are limited on ARM32 to +/- 32MB +displacement and on ARM64 to +/- 128MB displacement. + +The new code is placed in the 8M - 10M virtual address space while the +Xen code is in 2M - 4M. That gives us enough space. + +The hypervisor also checks the displacement during loading of the payload. diff --git a/xen/arch/arm/arm64/livepatch.c b/xen/arch/arm/arm64/livepatch.c index ecaf3f6..f072671 100644 --- a/xen/arch/arm/arm64/livepatch.c +++ b/xen/arch/arm/arm64/livepatch.c @@ -40,6 +40,7 @@ void arch_livepatch_apply_jmp(struct livepatch_func *func) else insn = aarch64_insn_gen_nop(); + /* Verified in arch_livepatch_verify_distance. */ ASSERT(insn != AARCH64_BREAK_FAULT); new_ptr = func->old_addr - (void *)_start + vmap_of_xen_text; diff --git a/xen/arch/x86/livepatch.c b/xen/arch/x86/livepatch.c index c4d4b4d..cf3eb22 100644 --- a/xen/arch/x86/livepatch.c +++ b/xen/arch/x86/livepatch.c @@ -44,7 +44,7 @@ void arch_livepatch_apply_jmp(struct livepatch_func *func) { uint8_t *old_ptr; uint8_t insn[sizeof(func->opaque)]; - size_t len; + unsigned int len; old_ptr = func->old_addr; len = arch_livepatch_insn_len(func); diff --git a/xen/common/livepatch.c b/xen/common/livepatch.c index 5baa418..4f156c2 100644 --- a/xen/common/livepatch.c +++ b/xen/common/livepatch.c @@ -530,6 +530,10 @@ static int prepare_payload(struct payload *payload, rc = resolve_old_address(f, elf); if ( rc ) return rc; + + rc = arch_livepatch_verify_distance(f); + if ( rc ) + return rc; } sec = livepatch_elf_sec_by_name(elf, ".livepatch.hooks.load"); diff --git a/xen/include/asm-arm/livepatch.h b/xen/include/asm-arm/livepatch.h index 8c8d625..a632cfa 100644 --- a/xen/include/asm-arm/livepatch.h +++ b/xen/include/asm-arm/livepatch.h @@ -6,6 +6,8 @@ #ifndef __XEN_ARM_LIVEPATCH_H__ #define __XEN_ARM_LIVEPATCH_H__ +#include /* For SZ_* macros. */ + /* On ARM32,64 instructions are always 4 bytes long. */ #define PATCH_INSN_SIZE 4 @@ -15,6 +17,15 @@ */ extern void *vmap_of_xen_text; +/* These ranges are only for unconditional branches. */ +#ifdef CONFIG_ARM_32 +/* ARM32: A4.3 IN ARM DDI 0406C.j - we are using only ARM instructions in Xen.*/ +#define LIVEPATCH_ARCH_RANGE SZ_32M +#else +/* ARM64: C1.3.2 in ARM DDI 0487A.j */ +#define LIVEPATCH_ARCH_RANGE SZ_128M +#endif + #endif /* __XEN_ARM_LIVEPATCH_H__ */ /* diff --git a/xen/include/asm-x86/livepatch.h b/xen/include/asm-x86/livepatch.h index 63ea079..0cae242 100644 --- a/xen/include/asm-x86/livepatch.h +++ b/xen/include/asm-x86/livepatch.h @@ -6,7 +6,10 @@ #ifndef __XEN_X86_LIVEPATCH_H__ #define __XEN_X86_LIVEPATCH_H__ +#include /* For SZ_* macros. */ + #define PATCH_INSN_SIZE 5 +#define LIVEPATCH_ARCH_RANGE SZ_2G #endif /* __XEN_X86_LIVEPATCH_H__ */ diff --git a/xen/include/xen/livepatch.h b/xen/include/xen/livepatch.h index 8258e02..904785a 100644 --- a/xen/include/xen/livepatch.h +++ b/xen/include/xen/livepatch.h @@ -12,6 +12,7 @@ struct livepatch_elf_sym; struct xen_sysctl_livepatch_op; #include +#include /* For -ENOSYS or -EOVERFLOW */ #ifdef CONFIG_LIVEPATCH /* @@ -66,16 +67,32 @@ int arch_livepatch_secure(const void *va, unsigned int pages, enum va_type types void arch_livepatch_init(void); #include /* For struct livepatch_func. */ -#include /* For PATCH_INSN_SIZE. */ +#include /* For LIVEPATCH_ARCH_RANGE and PATCH_INSN_SIZE */ int arch_livepatch_verify_func(const struct livepatch_func *func); -static inline size_t arch_livepatch_insn_len(const struct livepatch_func *func) +static inline +unsigned int arch_livepatch_insn_len(const struct livepatch_func *func) { if ( !func->new_addr ) return func->new_size; return PATCH_INSN_SIZE; } + +static inline int arch_livepatch_verify_distance(const struct livepatch_func *func) +{ + long offset; + long range = (long)LIVEPATCH_ARCH_RANGE; + + if ( !func->new_addr ) /* Ignore NOPs. */ + return 0; + + offset = ((long)func->old_addr - (long)func->new_addr); + if ( offset < -range || offset >= range ) + return -EOVERFLOW; + + return 0; +} /* * These functions are called around the critical region patching live code, * for an architecture to take make appropratie global state adjustments. @@ -100,7 +117,6 @@ void arch_livepatch_unmask(void); #define init_or_livepatch_data __initdata #define init_or_livepatch __init -#include /* For -ENOSYS */ static inline int livepatch_op(struct xen_sysctl_livepatch_op *op) { return -ENOSYS;