From patchwork Thu Feb 22 10:24:07 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andy Whitcroft X-Patchwork-Id: 876569 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) by ozlabs.org (Postfix) with ESMTP id 3zn9Sd2qq7z9sW1; Thu, 22 Feb 2018 21:24:17 +1100 (AEDT) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1eoo2t-0001hn-0N; Thu, 22 Feb 2018 10:24:11 +0000 Received: from youngberry.canonical.com ([91.189.89.112]) by huckleberry.canonical.com with esmtps (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:128) (Exim 4.86_2) (envelope-from ) id 1eoo2r-0001h2-39 for kernel-team@lists.ubuntu.com; Thu, 22 Feb 2018 10:24:09 +0000 Received: from 1.general.apw.uk.vpn ([10.172.192.78] helo=localhost) by youngberry.canonical.com with esmtpsa (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.76) (envelope-from ) id 1eoo2q-0001lv-R3; Thu, 22 Feb 2018 10:24:08 +0000 From: Andy Whitcroft To: kernel-team@lists.ubuntu.com Subject: [trusty/master-next 1/1] UBUNTU: SAUCE: x86, extable: fix uaccess fixup detection Date: Thu, 22 Feb 2018 10:24:07 +0000 Message-Id: <20180222102407.13542-2-apw@canonical.com> X-Mailer: git-send-email 2.15.1 In-Reply-To: <20180222102407.13542-1-apw@canonical.com> References: <20180222102407.13542-1-apw@canonical.com> X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Andy Whitcroft MIME-Version: 1.0 Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" The existing code intends to identify a subset of fixups which need special handling, uaccess related faults need to record the failure. This is done by adjusting the fixup code pointer by a (random) constant 0x7ffffff0. This is detected in fixup_exception by comparing the two pointers. The intent of this code is to detect the the delta between the original code and its fixup code being greater than the constant. However, the code as written triggers undefined comparison behaviour. In this kernel this prevents the condition triggering, leading to panics when jumping to the corrupted fixup address. Convert the code to better implement the intent. Convert both of the offsets to final addresses and compare the delta between those. Also add a massive comment to explain all of this including the implicit assumptions on order of the segments that this comparison implies. Fixes: 706276543b69 ("x86, extable: Switch to relative exception table entries") Signed-off-by: Andy Whitcroft Acked-by: Colin Ian King --- arch/x86/mm/extable.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/arch/x86/mm/extable.c b/arch/x86/mm/extable.c index 903ec1e9c326..a06be2f7f1bb 100644 --- a/arch/x86/mm/extable.c +++ b/arch/x86/mm/extable.c @@ -17,6 +17,7 @@ ex_fixup_addr(const struct exception_table_entry *x) int fixup_exception(struct pt_regs *regs) { const struct exception_table_entry *fixup; + unsigned long insn_ip; unsigned long new_ip; #ifdef CONFIG_PNPBIOS @@ -35,9 +36,17 @@ int fixup_exception(struct pt_regs *regs) fixup = search_exception_tables(regs->ip); if (fixup) { + insn_ip = ex_insn_addr(fixup); new_ip = ex_fixup_addr(fixup); - if (fixup->fixup - fixup->insn >= 0x7ffffff0 - 4) { + /* + * If the code and its fixup are "very far apart" then + * they are infact tagged as uaccess'es. Handle them + * specially and fix the fixup address. This relies on + * the .fixup section being at higher addresses that the + * original code. + */ + if (new_ip - insn_ip >= 0x7ffffff0) { /* Special hack for uaccess_err */ current_thread_info()->uaccess_err = 1; new_ip -= 0x7ffffff0; @@ -53,13 +62,16 @@ int fixup_exception(struct pt_regs *regs) int __init early_fixup_exception(unsigned long *ip) { const struct exception_table_entry *fixup; + unsigned long insn_ip; unsigned long new_ip; fixup = search_exception_tables(*ip); if (fixup) { + insn_ip = ex_insn_addr(fixup); new_ip = ex_fixup_addr(fixup); - if (fixup->fixup - fixup->insn >= 0x7ffffff0 - 4) { + /* See fixup_exception for details ... */ + if (new_ip - insn_ip >= 0x7ffffff0) { /* uaccess handling not supported during early boot */ return 0; }