From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1422773AbdEXNzH (ORCPT ); Wed, 24 May 2017 09:55:07 -0400 Received: from mail-wm0-f42.google.com ([74.125.82.42]:36268 "EHLO mail-wm0-f42.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1764834AbdEXNzE (ORCPT ); Wed, 24 May 2017 09:55:04 -0400 From: Mateusz Jurczyk To: Thomas Gleixner , Ingo Molnar , "H. Peter Anvin" , Andy Lutomirski , Borislav Petkov Cc: x86@kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v2] x86: Prevent uninitialized stack byte read in apply_alternatives() Date: Wed, 24 May 2017 15:55:00 +0200 Message-Id: <20170524135500.27223-1-mjurczyk@google.com> X-Mailer: git-send-email 2.13.0.219.gdb65acc882-goog In-Reply-To: <20170524130418.GB7275@nazgul.tnic> References: <20170524130418.GB7275@nazgul.tnic> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org In the current form of the code, if a->replacementlen is 0, the reference to *insnbuf for comparison touches potentially garbage memory. While it doesn't affect the execution flow due to the subsequent a->replacementlen comparison, it is (rightly) detected as use of uninitialized memory by a runtime instrumentation currently under my development, and could be detected as such by other tools in the future, too (e.g. KMSAN). Fix the "false-positive" by reordering the conditions to first check the replacement instruction length before referencing specific opcode bytes. Signed-off-by: Mateusz Jurczyk --- Changes in v2: - Add an explaining comment, as per Borislav Petkov's request. arch/x86/kernel/alternative.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index c5b8f760473c..32e14d137416 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -409,8 +409,13 @@ void __init_or_module noinline apply_alternatives(struct alt_instr *start, memcpy(insnbuf, replacement, a->replacementlen); insnbuf_sz = a->replacementlen; - /* 0xe8 is a relative jump; fix the offset. */ - if (*insnbuf == 0xe8 && a->replacementlen == 5) { + /* + * 0xe8 is a relative jump; fix the offset. + * + * Instruction length is checked before the opcode to avoid + * accessing uninitialized bytes for zero-length replacements. + */ + if (a->replacementlen == 5 && *insnbuf == 0xe8) { *(s32 *)(insnbuf + 1) += replacement - instr; DPRINTK("Fix CALL offset: 0x%x, CALL 0x%lx", *(s32 *)(insnbuf + 1), -- 2.13.0.219.gdb65acc882-goog