From patchwork Tue May 7 08:50:06 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Po-Hsu Lin X-Patchwork-Id: 1096217 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=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=canonical.com Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 44ytc90qJpz9sB3; Tue, 7 May 2019 18:50:47 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1hNvo9-00064A-Ik; Tue, 07 May 2019 08:50:41 +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 1hNvo7-00061z-S4 for kernel-team@lists.ubuntu.com; Tue, 07 May 2019 08:50:39 +0000 Received: from mail-pl1-f200.google.com ([209.85.214.200]) by youngberry.canonical.com with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.76) (envelope-from ) id 1hNvo7-0003X9-9g for kernel-team@lists.ubuntu.com; Tue, 07 May 2019 08:50:39 +0000 Received: by mail-pl1-f200.google.com with SMTP id d10so8915153plo.12 for ; Tue, 07 May 2019 01:50:39 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=Mcajk+dLi28D0KCNlYofP3ZmjfkBWCvTfNZJ5Msi0HM=; b=PLH+TrfpdqxW5It6EJNnu0ae6CzUQgqMVWva58gg0VSMmMh6YJ9Yhn+zjlGLOI+VjT 0JywZPcQU4sJL1qxSo5+jsDZ6F5v8LkHiEJlEITmfz2IUbeIMFv8r4hT33m6HElj1nok WeFUVYkxpaP98uKdtlYaHyHOewYB0ucXpmqcB5k+yzwCmYZEUwgo9Ototmuq4RLKiOm0 JUT3WxM6Mn6dMSi/zivyeQEZMXZw3CihnLAIvLXUtmUw8rs8+sEGT/hscBw6S1BEX6+X QScaOb2YQOwyd8EG5lCoLDQ9clsO+F66F0RvkqxAx+YpPMVviWgsu5haofWZ356Pgx3f swzw== X-Gm-Message-State: APjAAAXt8IfL2xcetLDZ9Rv56lOC1eRmeOdxO113ihP9WuDrKoTwKshI fKtIc91HELPZkRBe1FNvju0zpHeY8v4SYGRX7smtpwvN/SockywPZvEm9UBxAJSr33WG1MxYLxp ScS1V8TuS3gm1iYXeklOSCK0VbD2S/Bk4awZMm2Ax X-Received: by 2002:a17:902:8f84:: with SMTP id z4mr36912126plo.124.1557219037823; Tue, 07 May 2019 01:50:37 -0700 (PDT) X-Google-Smtp-Source: APXvYqxQt0suiB7ZFZ0xdnNvY2dixHE9tY8p8/h+HgjJM/ZudWGcGLaNdYf2E09e1mmwujz3GAfiTg== X-Received: by 2002:a17:902:8f84:: with SMTP id z4mr36912105plo.124.1557219037615; Tue, 07 May 2019 01:50:37 -0700 (PDT) Received: from Leggiero.taipei.internal (61-220-137-37.HINET-IP.hinet.net. [61.220.137.37]) by smtp.gmail.com with ESMTPSA id e8sm23383525pfc.47.2019.05.07.01.50.36 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 07 May 2019 01:50:36 -0700 (PDT) From: Po-Hsu Lin To: kernel-team@lists.ubuntu.com Subject: [B][C][SRU][PATCH 1/1] kprobes/x86: Fix instruction patching corruption when copying more than one RIP-relative instruction Date: Tue, 7 May 2019 16:50:06 +0800 Message-Id: <20190507085006.17500-2-po-hsu.lin@canonical.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190507085006.17500-1-po-hsu.lin@canonical.com> References: <20190507085006.17500-1-po-hsu.lin@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: , MIME-Version: 1.0 Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" From: Masami Hiramatsu BugLink: https://bugs.launchpad.net/bugs/1826385 After copy_optimized_instructions() copies several instructions to the working buffer it tries to fix up the real RIP address, but it adjusts the RIP-relative instruction with an incorrect RIP address for the 2nd and subsequent instructions due to a bug in the logic. This will break the kernel pretty badly (with likely outcomes such as a kernel freeze, a crash, or worse) because probed instructions can refer to the wrong data. For example putting kprobes on cpumask_next() typically hits this bug. cpumask_next() is normally like below if CONFIG_CPUMASK_OFFSTACK=y (in this case nr_cpumask_bits is an alias of nr_cpu_ids): : 48 89 f0 mov %rsi,%rax 8b 35 7b fb e2 00 mov 0xe2fb7b(%rip),%esi # ffffffff82db9e64 55 push %rbp ... If we put a kprobe on it and it gets jump-optimized, it gets patched by the kprobes code like this: : e9 95 7d 07 1e jmpq 0xffffffffa000207a 7b fb jnp 0xffffffff81f8a2e2 e2 00 loop 0xffffffff81f8a2e9 55 push %rbp This shows that the first two MOV instructions were copied to a trampoline buffer at 0xffffffffa000207a. Here is the disassembled result of the trampoline, skipping the optprobe template instructions: # Dump of assembly code from 0xffffffffa000207a to 0xffffffffa00020ea: 54 push %rsp ... 48 83 c4 08 add $0x8,%rsp 9d popfq 48 89 f0 mov %rsi,%rax 8b 35 82 7d db e2 mov -0x1d24827e(%rip),%esi # 0xffffffff82db9e67 This dump shows that the second MOV accesses *(nr_cpu_ids+3) instead of the original *nr_cpu_ids. This leads to a kernel freeze because cpumask_next() always returns 0 and for_each_cpu() never ends. Fix this by adding 'len' correctly to the real RIP address while copying. [ mingo: Improved the changelog. ] Reported-by: Michael Rodin Signed-off-by: Masami Hiramatsu Reviewed-by: Steven Rostedt (VMware) Cc: Arnaldo Carvalho de Melo Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Steven Rostedt Cc: Thomas Gleixner Cc: stable@vger.kernel.org # v4.15+ Fixes: 63fef14fc98a ("kprobes/x86: Make insn buffer always ROX and use text_poke()") Link: http://lkml.kernel.org/r/153504457253.22602.1314289671019919596.stgit@devbox Signed-off-by: Ingo Molnar (cherry picked from commit 43a1b0cb4cd6dbfd3cd9c10da663368394d299d8) Signed-off-by: Po-Hsu Lin Acked-by: Kleber Sacilotto de Souza Acked-by: Connor Kuehl --- arch/x86/kernel/kprobes/opt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/kprobes/opt.c b/arch/x86/kernel/kprobes/opt.c index 1467f96..72e1286 100644 --- a/arch/x86/kernel/kprobes/opt.c +++ b/arch/x86/kernel/kprobes/opt.c @@ -189,7 +189,7 @@ static int copy_optimized_instructions(u8 *dest, u8 *src, u8 *real) int len = 0, ret; while (len < RELATIVEJUMP_SIZE) { - ret = __copy_instruction(dest + len, src + len, real, &insn); + ret = __copy_instruction(dest + len, src + len, real + len, &insn); if (!ret || !can_boost(&insn, src + len)) return -EINVAL; len += ret;