All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] x86: Prevent uninitialized stack byte read in apply_alternatives()
@ 2017-05-24 12:51 Mateusz Jurczyk
  2017-05-24 13:04 ` Borislav Petkov
  0 siblings, 1 reply; 5+ messages in thread
From: Mateusz Jurczyk @ 2017-05-24 12:51 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Andy Lutomirski,
	Borislav Petkov
  Cc: x86, linux-kernel

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 <mjurczyk@google.com>
---
 arch/x86/kernel/alternative.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index c5b8f760473c..d03ba6bc97d8 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -410,7 +410,7 @@ void __init_or_module noinline apply_alternatives(struct alt_instr *start,
 		insnbuf_sz = a->replacementlen;
 
 		/* 0xe8 is a relative jump; fix the offset. */
-		if (*insnbuf == 0xe8 && a->replacementlen == 5) {
+		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

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH] x86: Prevent uninitialized stack byte read in apply_alternatives()
  2017-05-24 12:51 [PATCH] x86: Prevent uninitialized stack byte read in apply_alternatives() Mateusz Jurczyk
@ 2017-05-24 13:04 ` Borislav Petkov
  2017-05-24 13:55   ` [PATCH v2] " Mateusz Jurczyk
  0 siblings, 1 reply; 5+ messages in thread
From: Borislav Petkov @ 2017-05-24 13:04 UTC (permalink / raw)
  To: Mateusz Jurczyk
  Cc: Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Andy Lutomirski,
	x86, linux-kernel

On Wed, May 24, 2017 at 02:51:20PM +0200, Mateusz Jurczyk wrote:
> 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 <mjurczyk@google.com>
> ---
>  arch/x86/kernel/alternative.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
> index c5b8f760473c..d03ba6bc97d8 100644
> --- a/arch/x86/kernel/alternative.c
> +++ b/arch/x86/kernel/alternative.c
> @@ -410,7 +410,7 @@ void __init_or_module noinline apply_alternatives(struct alt_instr *start,
>  		insnbuf_sz = a->replacementlen;
>  
>  		/* 0xe8 is a relative jump; fix the offset. */

Sure but put in short the reason to look at the instruction length first
in the comment above so that it is clear why we're doing it this way.

> -		if (*insnbuf == 0xe8 && a->replacementlen == 5) {
> +		if (a->replacementlen == 5 && *insnbuf == 0xe8) {
>  			*(s32 *)(insnbuf + 1) += replacement - instr;
>  			DPRINTK("Fix CALL offset: 0x%x, CALL 0x%lx",
>  				*(s32 *)(insnbuf + 1),
> -- 

Thanks.

-- 
Regards/Gruss,
    Boris.

SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nürnberg)
-- 

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH v2] x86: Prevent uninitialized stack byte read in apply_alternatives()
  2017-05-24 13:04 ` Borislav Petkov
@ 2017-05-24 13:55   ` Mateusz Jurczyk
  2017-05-24 14:02     ` Borislav Petkov
  2017-05-24 14:25     ` [tip:x86/urgent] x86/alternatives: " tip-bot for Mateusz Jurczyk
  0 siblings, 2 replies; 5+ messages in thread
From: Mateusz Jurczyk @ 2017-05-24 13:55 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Andy Lutomirski,
	Borislav Petkov
  Cc: x86, linux-kernel

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 <mjurczyk@google.com>
---
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

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH v2] x86: Prevent uninitialized stack byte read in apply_alternatives()
  2017-05-24 13:55   ` [PATCH v2] " Mateusz Jurczyk
@ 2017-05-24 14:02     ` Borislav Petkov
  2017-05-24 14:25     ` [tip:x86/urgent] x86/alternatives: " tip-bot for Mateusz Jurczyk
  1 sibling, 0 replies; 5+ messages in thread
From: Borislav Petkov @ 2017-05-24 14:02 UTC (permalink / raw)
  To: Mateusz Jurczyk
  Cc: Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Andy Lutomirski,
	x86, linux-kernel

On Wed, May 24, 2017 at 03:55:00PM +0200, Mateusz Jurczyk wrote:
> 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 <mjurczyk@google.com>
> ---
> 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),
> -- 

Reviewed-by: Borislav Petkov <bp@suse.de>

-- 
Regards/Gruss,
    Boris.

SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nürnberg)
-- 

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [tip:x86/urgent] x86/alternatives: Prevent uninitialized stack byte read in apply_alternatives()
  2017-05-24 13:55   ` [PATCH v2] " Mateusz Jurczyk
  2017-05-24 14:02     ` Borislav Petkov
@ 2017-05-24 14:25     ` tip-bot for Mateusz Jurczyk
  1 sibling, 0 replies; 5+ messages in thread
From: tip-bot for Mateusz Jurczyk @ 2017-05-24 14:25 UTC (permalink / raw)
  To: linux-tip-commits; +Cc: mjurczyk, linux-kernel, hpa, bp, luto, mingo, tglx

Commit-ID:  fc152d22d6e9fac95a9a990e6c29510bdf1b9425
Gitweb:     http://git.kernel.org/tip/fc152d22d6e9fac95a9a990e6c29510bdf1b9425
Author:     Mateusz Jurczyk <mjurczyk@google.com>
AuthorDate: Wed, 24 May 2017 15:55:00 +0200
Committer:  Thomas Gleixner <tglx@linutronix.de>
CommitDate: Wed, 24 May 2017 16:18:12 +0200

x86/alternatives: Prevent uninitialized stack byte read in apply_alternatives()

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 <mjurczyk@google.com>
Reviewed-by: Borislav Petkov <bp@suse.de>
Cc: Andy Lutomirski <luto@kernel.org>
Link: http://lkml.kernel.org/r/20170524135500.27223-1-mjurczyk@google.com
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 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 c5b8f76..32e14d1 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),

^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2017-05-24 14:27 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-05-24 12:51 [PATCH] x86: Prevent uninitialized stack byte read in apply_alternatives() Mateusz Jurczyk
2017-05-24 13:04 ` Borislav Petkov
2017-05-24 13:55   ` [PATCH v2] " Mateusz Jurczyk
2017-05-24 14:02     ` Borislav Petkov
2017-05-24 14:25     ` [tip:x86/urgent] x86/alternatives: " tip-bot for Mateusz Jurczyk

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.