linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] x86/boot/compressed/64: Fix boot on machines with broken E820 table
@ 2019-08-13 13:16 Kirill A. Shutemov
  2019-08-19 14:16 ` [tip:x86/urgent] " tip-bot for Kirill A. Shutemov
  0 siblings, 1 reply; 5+ messages in thread
From: Kirill A. Shutemov @ 2019-08-13 13:16 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, H. Peter Anvin
  Cc: x86, linux-kernel, Kirill A. Shutemov

BIOS on Samsung 500C Chromebook reports very rudimentary E820 table that
consists of 2 entries:

 BIOS-e820: [mem 0x0000000000000000-0x0000000000000fff] usable
 BIOS-e820: [mem 0x00000000fffff000-0x00000000ffffffff] reserved

It breaks logic in find_trampoline_placement(): bios_start lands on the
end of the first 4k page and trampoline start gets placed below 0.

Detect underflow and don't touch bios_start for such cases. It makes
kernel ignore E820 table on machines that doesn't have two usable pages
below BIOS_START_MAX.

Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Fixes: 1b3a62643660 ("x86/boot/compressed/64: Validate trampoline placement against E820")
Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=203463
---
 arch/x86/boot/compressed/pgtable_64.c | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/arch/x86/boot/compressed/pgtable_64.c b/arch/x86/boot/compressed/pgtable_64.c
index 5f2d03067ae5..2faddeb0398a 100644
--- a/arch/x86/boot/compressed/pgtable_64.c
+++ b/arch/x86/boot/compressed/pgtable_64.c
@@ -72,6 +72,8 @@ static unsigned long find_trampoline_placement(void)
 
 	/* Find the first usable memory region under bios_start. */
 	for (i = boot_params->e820_entries - 1; i >= 0; i--) {
+		unsigned long new;
+
 		entry = &boot_params->e820_table[i];
 
 		/* Skip all entries above bios_start. */
@@ -84,15 +86,20 @@ static unsigned long find_trampoline_placement(void)
 
 		/* Adjust bios_start to the end of the entry if needed. */
 		if (bios_start > entry->addr + entry->size)
-			bios_start = entry->addr + entry->size;
+			new = entry->addr + entry->size;
 
 		/* Keep bios_start page-aligned. */
-		bios_start = round_down(bios_start, PAGE_SIZE);
+		new = round_down(new, PAGE_SIZE);
 
 		/* Skip the entry if it's too small. */
-		if (bios_start - TRAMPOLINE_32BIT_SIZE < entry->addr)
+		if (new - TRAMPOLINE_32BIT_SIZE < entry->addr)
 			continue;
 
+		/* Protect against underflow. */
+		if (new - TRAMPOLINE_32BIT_SIZE > bios_start)
+			break;
+
+		bios_start = new;
 		break;
 	}
 
-- 
2.21.0


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

* [tip:x86/urgent] x86/boot/compressed/64: Fix boot on machines with broken E820 table
  2019-08-13 13:16 [PATCH] x86/boot/compressed/64: Fix boot on machines with broken E820 table Kirill A. Shutemov
@ 2019-08-19 14:16 ` tip-bot for Kirill A. Shutemov
  2019-08-26  3:33   ` Gustavo A. R. Silva
  0 siblings, 1 reply; 5+ messages in thread
From: tip-bot for Kirill A. Shutemov @ 2019-08-19 14:16 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: mingo, kirill.shutemov, x86, mingo, linux-kernel, bp, hpa, tglx, kirill

Commit-ID:  0a46fff2f9108c2c44218380a43a736cf4612541
Gitweb:     https://git.kernel.org/tip/0a46fff2f9108c2c44218380a43a736cf4612541
Author:     Kirill A. Shutemov <kirill@shutemov.name>
AuthorDate: Tue, 13 Aug 2019 16:16:54 +0300
Committer:  Borislav Petkov <bp@suse.de>
CommitDate: Mon, 19 Aug 2019 15:59:13 +0200

x86/boot/compressed/64: Fix boot on machines with broken E820 table

BIOS on Samsung 500C Chromebook reports very rudimentary E820 table that
consists of 2 entries:

  BIOS-e820: [mem 0x0000000000000000-0x0000000000000fff] usable
  BIOS-e820: [mem 0x00000000fffff000-0x00000000ffffffff] reserved

It breaks logic in find_trampoline_placement(): bios_start lands on the
end of the first 4k page and trampoline start gets placed below 0.

Detect underflow and don't touch bios_start for such cases. It makes
kernel ignore E820 table on machines that doesn't have two usable pages
below BIOS_START_MAX.

Fixes: 1b3a62643660 ("x86/boot/compressed/64: Validate trampoline placement against E820")
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Signed-off-by: Borislav Petkov <bp@suse.de>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: x86-ml <x86@kernel.org>
Link: https://bugzilla.kernel.org/show_bug.cgi?id=203463
Link: https://lkml.kernel.org/r/20190813131654.24378-1-kirill.shutemov@linux.intel.com
---
 arch/x86/boot/compressed/pgtable_64.c | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/arch/x86/boot/compressed/pgtable_64.c b/arch/x86/boot/compressed/pgtable_64.c
index 5f2d03067ae5..2faddeb0398a 100644
--- a/arch/x86/boot/compressed/pgtable_64.c
+++ b/arch/x86/boot/compressed/pgtable_64.c
@@ -72,6 +72,8 @@ static unsigned long find_trampoline_placement(void)
 
 	/* Find the first usable memory region under bios_start. */
 	for (i = boot_params->e820_entries - 1; i >= 0; i--) {
+		unsigned long new;
+
 		entry = &boot_params->e820_table[i];
 
 		/* Skip all entries above bios_start. */
@@ -84,15 +86,20 @@ static unsigned long find_trampoline_placement(void)
 
 		/* Adjust bios_start to the end of the entry if needed. */
 		if (bios_start > entry->addr + entry->size)
-			bios_start = entry->addr + entry->size;
+			new = entry->addr + entry->size;
 
 		/* Keep bios_start page-aligned. */
-		bios_start = round_down(bios_start, PAGE_SIZE);
+		new = round_down(new, PAGE_SIZE);
 
 		/* Skip the entry if it's too small. */
-		if (bios_start - TRAMPOLINE_32BIT_SIZE < entry->addr)
+		if (new - TRAMPOLINE_32BIT_SIZE < entry->addr)
 			continue;
 
+		/* Protect against underflow. */
+		if (new - TRAMPOLINE_32BIT_SIZE > bios_start)
+			break;
+
+		bios_start = new;
 		break;
 	}
 

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

* Re: [tip:x86/urgent] x86/boot/compressed/64: Fix boot on machines with broken E820 table
  2019-08-19 14:16 ` [tip:x86/urgent] " tip-bot for Kirill A. Shutemov
@ 2019-08-26  3:33   ` Gustavo A. R. Silva
  2019-08-26  7:15     ` Borislav Petkov
  0 siblings, 1 reply; 5+ messages in thread
From: Gustavo A. R. Silva @ 2019-08-26  3:33 UTC (permalink / raw)
  To: tglx, bp, hpa, linux-kernel, mingo, x86, mingo, kirill.shutemov,
	kirill, linux-tip-commits

Hi all,

On 8/19/19 9:16 AM, tip-bot for Kirill A. Shutemov wrote:
[..]
> 
> diff --git a/arch/x86/boot/compressed/pgtable_64.c b/arch/x86/boot/compressed/pgtable_64.c
> index 5f2d03067ae5..2faddeb0398a 100644
> --- a/arch/x86/boot/compressed/pgtable_64.c
> +++ b/arch/x86/boot/compressed/pgtable_64.c
> @@ -72,6 +72,8 @@ static unsigned long find_trampoline_placement(void)
>  
>  	/* Find the first usable memory region under bios_start. */
>  	for (i = boot_params->e820_entries - 1; i >= 0; i--) {
> +		unsigned long new;
> +
>  		entry = &boot_params->e820_table[i];
>  
>  		/* Skip all entries above bios_start. */
> @@ -84,15 +86,20 @@ static unsigned long find_trampoline_placement(void)
>  
>  		/* Adjust bios_start to the end of the entry if needed. */
>  		if (bios_start > entry->addr + entry->size)

Notice that if this condition happens to be false, we end up with an
uninitialized variable *new*.

What would be the right value to assign to *new* at declaration under
this condition?

> -			bios_start = entry->addr + entry->size;
> +			new = entry->addr + entry->size;
>  
>  		/* Keep bios_start page-aligned. */
> -		bios_start = round_down(bios_start, PAGE_SIZE);
> +		new = round_down(new, PAGE_SIZE);
>  
>  		/* Skip the entry if it's too small. */
> -		if (bios_start - TRAMPOLINE_32BIT_SIZE < entry->addr)
> +		if (new - TRAMPOLINE_32BIT_SIZE < entry->addr)
>  			continue;
>  
> +		/* Protect against underflow. */
> +		if (new - TRAMPOLINE_32BIT_SIZE > bios_start)
> +			break;
> +
> +		bios_start = new;
>  		break;
>  	}
>  
> 

--
Gustavo


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

* Re: [tip:x86/urgent] x86/boot/compressed/64: Fix boot on machines with broken E820 table
  2019-08-26  3:33   ` Gustavo A. R. Silva
@ 2019-08-26  7:15     ` Borislav Petkov
  2019-08-26 13:33       ` Kirill A. Shutemov
  0 siblings, 1 reply; 5+ messages in thread
From: Borislav Petkov @ 2019-08-26  7:15 UTC (permalink / raw)
  To: Gustavo A. R. Silva
  Cc: tglx, hpa, linux-kernel, mingo, x86, mingo, kirill.shutemov,
	kirill, linux-tip-commits

On Sun, Aug 25, 2019 at 10:33:15PM -0500, Gustavo A. R. Silva wrote:
> Hi all,
> 
> On 8/19/19 9:16 AM, tip-bot for Kirill A. Shutemov wrote:
> [..]
> > 
> > diff --git a/arch/x86/boot/compressed/pgtable_64.c b/arch/x86/boot/compressed/pgtable_64.c
> > index 5f2d03067ae5..2faddeb0398a 100644
> > --- a/arch/x86/boot/compressed/pgtable_64.c
> > +++ b/arch/x86/boot/compressed/pgtable_64.c
> > @@ -72,6 +72,8 @@ static unsigned long find_trampoline_placement(void)
> >  
> >  	/* Find the first usable memory region under bios_start. */
> >  	for (i = boot_params->e820_entries - 1; i >= 0; i--) {
> > +		unsigned long new;
> > +
> >  		entry = &boot_params->e820_table[i];
> >  
> >  		/* Skip all entries above bios_start. */
> > @@ -84,15 +86,20 @@ static unsigned long find_trampoline_placement(void)
> >  
> >  		/* Adjust bios_start to the end of the entry if needed. */
> >  		if (bios_start > entry->addr + entry->size)
> 
> Notice that if this condition happens to be false, we end up with an
> uninitialized variable *new*.

Yap, good catch.

> What would be the right value to assign to *new* at declaration under
> this condition?

Looking at the changed flow of the loop, how we use new instead of
bios_start and how we assign new back to bios_start, I think we should
do:

		unsigned long new = bios_start;

at the beginning...

-- 
Regards/Gruss,
    Boris.

Good mailing practices for 400: avoid top-posting and trim the reply.

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

* Re: [tip:x86/urgent] x86/boot/compressed/64: Fix boot on machines with broken E820 table
  2019-08-26  7:15     ` Borislav Petkov
@ 2019-08-26 13:33       ` Kirill A. Shutemov
  0 siblings, 0 replies; 5+ messages in thread
From: Kirill A. Shutemov @ 2019-08-26 13:33 UTC (permalink / raw)
  To: Borislav Petkov
  Cc: Gustavo A. R. Silva, tglx, hpa, linux-kernel, mingo, x86, mingo,
	kirill.shutemov, linux-tip-commits

On Mon, Aug 26, 2019 at 09:15:39AM +0200, Borislav Petkov wrote:
> On Sun, Aug 25, 2019 at 10:33:15PM -0500, Gustavo A. R. Silva wrote:
> > Hi all,
> > 
> > On 8/19/19 9:16 AM, tip-bot for Kirill A. Shutemov wrote:
> > [..]
> > > 
> > > diff --git a/arch/x86/boot/compressed/pgtable_64.c b/arch/x86/boot/compressed/pgtable_64.c
> > > index 5f2d03067ae5..2faddeb0398a 100644
> > > --- a/arch/x86/boot/compressed/pgtable_64.c
> > > +++ b/arch/x86/boot/compressed/pgtable_64.c
> > > @@ -72,6 +72,8 @@ static unsigned long find_trampoline_placement(void)
> > >  
> > >  	/* Find the first usable memory region under bios_start. */
> > >  	for (i = boot_params->e820_entries - 1; i >= 0; i--) {
> > > +		unsigned long new;
> > > +
> > >  		entry = &boot_params->e820_table[i];
> > >  
> > >  		/* Skip all entries above bios_start. */
> > > @@ -84,15 +86,20 @@ static unsigned long find_trampoline_placement(void)
> > >  
> > >  		/* Adjust bios_start to the end of the entry if needed. */
> > >  		if (bios_start > entry->addr + entry->size)
> > 
> > Notice that if this condition happens to be false, we end up with an
> > uninitialized variable *new*.
> 
> Yap, good catch.

:facepalm:

> > What would be the right value to assign to *new* at declaration under
> > this condition?
> 
> Looking at the changed flow of the loop, how we use new instead of
> bios_start and how we assign new back to bios_start, I think we should
> do:
> 
> 		unsigned long new = bios_start;
> 
> at the beginning...

Right.

What about this:

From b613c675e6690ef5608a5abf71d90e15ced31b2b Mon Sep 17 00:00:00 2001
From: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>
Date: Mon, 26 Aug 2019 16:26:01 +0300
Subject: [PATCH] x86/boot/compressed/64: Fix missining initialization in
 find_trampoline_placement()

Gustavo noticed that 'new' can be left uninitialized if 'bios_start'
happens to be less or equal to 'entry->addr + entry->size'.

Initialize the variable at the start of the iteration to current value
of 'bios_start'.

Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Reported-by: "Gustavo A. R. Silva" <gustavo@embeddedor.com>
Fixes: 0a46fff2f910 ("x86/boot/compressed/64: Fix boot on machines with broken E820 table")
---
 arch/x86/boot/compressed/pgtable_64.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/x86/boot/compressed/pgtable_64.c b/arch/x86/boot/compressed/pgtable_64.c
index 2faddeb0398a..c8862696a47b 100644
--- a/arch/x86/boot/compressed/pgtable_64.c
+++ b/arch/x86/boot/compressed/pgtable_64.c
@@ -72,7 +72,7 @@ static unsigned long find_trampoline_placement(void)
 
 	/* Find the first usable memory region under bios_start. */
 	for (i = boot_params->e820_entries - 1; i >= 0; i--) {
-		unsigned long new;
+		unsigned long new = bios_start;
 
 		entry = &boot_params->e820_table[i];
 
-- 
 Kirill A. Shutemov

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

end of thread, other threads:[~2019-08-26 13:33 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-08-13 13:16 [PATCH] x86/boot/compressed/64: Fix boot on machines with broken E820 table Kirill A. Shutemov
2019-08-19 14:16 ` [tip:x86/urgent] " tip-bot for Kirill A. Shutemov
2019-08-26  3:33   ` Gustavo A. R. Silva
2019-08-26  7:15     ` Borislav Petkov
2019-08-26 13:33       ` Kirill A. Shutemov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).