[PATCH v3 1/2] x86/mm: rename the confusing local variable in early_memremap_is_setup_data()

Baoquan He posted 2 patches 2 months, 2 weeks ago
[PATCH v3 1/2] x86/mm: rename the confusing local variable in early_memremap_is_setup_data()
Posted by Baoquan He 2 months, 2 weeks ago
In function early_memremap_is_setup_data(), parameter 'size' passed has
the same name as the local variable inside the while loop. That
confuses people who sometime mix up them when reading code.

Here rename the local variable 'size' inside while loop to 'sd_size'.

And also add one local variable 'sd_size' likewise in function
memremap_is_setup_data() to simplify code. In later patch, this can also
be used.

Signed-off-by: Baoquan He <bhe@redhat.com>
Acked-by: Tom Lendacky <thomas.lendacky@amd.com>
---
 arch/x86/mm/ioremap.c | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c
index aa7d279321ea..f1ee8822ddf1 100644
--- a/arch/x86/mm/ioremap.c
+++ b/arch/x86/mm/ioremap.c
@@ -640,7 +640,7 @@ static bool memremap_is_setup_data(resource_size_t phys_addr,
 
 	paddr = boot_params.hdr.setup_data;
 	while (paddr) {
-		unsigned int len;
+		unsigned int len, sd_size;
 
 		if (phys_addr == paddr)
 			return true;
@@ -652,6 +652,8 @@ static bool memremap_is_setup_data(resource_size_t phys_addr,
 			return false;
 		}
 
+		sd_size = sizeof(*data);
+
 		paddr_next = data->next;
 		len = data->len;
 
@@ -662,7 +664,9 @@ static bool memremap_is_setup_data(resource_size_t phys_addr,
 
 		if (data->type == SETUP_INDIRECT) {
 			memunmap(data);
-			data = memremap(paddr, sizeof(*data) + len,
+
+			sd_size += len;
+			data = memremap(paddr, sd_size,
 					MEMREMAP_WB | MEMREMAP_DEC);
 			if (!data) {
 				pr_warn("failed to memremap indirect setup_data\n");
@@ -701,7 +705,7 @@ static bool __init early_memremap_is_setup_data(resource_size_t phys_addr,
 
 	paddr = boot_params.hdr.setup_data;
 	while (paddr) {
-		unsigned int len, size;
+		unsigned int len, sd_size;
 
 		if (phys_addr == paddr)
 			return true;
@@ -712,7 +716,7 @@ static bool __init early_memremap_is_setup_data(resource_size_t phys_addr,
 			return false;
 		}
 
-		size = sizeof(*data);
+		sd_size = sizeof(*data);
 
 		paddr_next = data->next;
 		len = data->len;
@@ -723,9 +727,9 @@ static bool __init early_memremap_is_setup_data(resource_size_t phys_addr,
 		}
 
 		if (data->type == SETUP_INDIRECT) {
-			size += len;
+			sd_size += len;
 			early_memunmap(data, sizeof(*data));
-			data = early_memremap_decrypted(paddr, size);
+			data = early_memremap_decrypted(paddr, sd_size);
 			if (!data) {
 				pr_warn("failed to early memremap indirect setup_data\n");
 				return false;
@@ -739,7 +743,7 @@ static bool __init early_memremap_is_setup_data(resource_size_t phys_addr,
 			}
 		}
 
-		early_memunmap(data, size);
+		early_memunmap(data, sd_size);
 
 		if ((phys_addr > paddr) && (phys_addr < (paddr + len)))
 			return true;
-- 
2.41.0
Re: [PATCH v3 1/2] x86/mm: rename the confusing local variable in early_memremap_is_setup_data()
Posted by Borislav Petkov 1 month ago
On Wed, Sep 11, 2024 at 04:16:14PM +0800, Baoquan He wrote:
> In function early_memremap_is_setup_data(), parameter 'size' passed has
> the same name as the local variable inside the while loop. That
> confuses people who sometime mix up them when reading code.
> 
> Here rename the local variable 'size' inside while loop to 'sd_size'.
> 
> And also add one local variable 'sd_size' likewise in function
> memremap_is_setup_data() to simplify code. In later patch, this can also
> be used.
> 
> Signed-off-by: Baoquan He <bhe@redhat.com>
> Acked-by: Tom Lendacky <thomas.lendacky@amd.com>
> ---
>  arch/x86/mm/ioremap.c | 18 +++++++++++-------
>  1 file changed, 11 insertions(+), 7 deletions(-)
> 
> diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c
> index aa7d279321ea..f1ee8822ddf1 100644
> --- a/arch/x86/mm/ioremap.c
> +++ b/arch/x86/mm/ioremap.c
> @@ -640,7 +640,7 @@ static bool memremap_is_setup_data(resource_size_t phys_addr,

Huh?

---
diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c
index 70b02fc61d93..e461d8e26871 100644
--- a/arch/x86/mm/ioremap.c
+++ b/arch/x86/mm/ioremap.c
@@ -632,8 +632,7 @@ static bool memremap_is_efi_data(resource_size_t phys_addr,
  * Examine the physical address to determine if it is boot data by checking
  * it against the boot params setup_data chain.
  */
-static bool memremap_is_setup_data(resource_size_t phys_addr,
-				   unsigned long size)
+static bool memremap_is_setup_data(resource_size_t phys_addr)
 {
 	struct setup_indirect *indirect;
 	struct setup_data *data;
@@ -769,7 +768,7 @@ bool arch_memremap_can_ram_remap(resource_size_t phys_addr, unsigned long size,
 		return false;
 
 	if (cc_platform_has(CC_ATTR_HOST_MEM_ENCRYPT)) {
-		if (memremap_is_setup_data(phys_addr, size) ||
+		if (memremap_is_setup_data(phys_addr) ||
 		    memremap_is_efi_data(phys_addr, size))
 			return false;
 	}

-- 
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette
Re: [PATCH v3 1/2] x86/mm: rename the confusing local variable in early_memremap_is_setup_data()
Posted by Baoquan He 1 month ago
On 10/29/24 at 07:11pm, Borislav Petkov wrote:
> On Wed, Sep 11, 2024 at 04:16:14PM +0800, Baoquan He wrote:
> > In function early_memremap_is_setup_data(), parameter 'size' passed has
> > the same name as the local variable inside the while loop. That
> > confuses people who sometime mix up them when reading code.
> > 
> > Here rename the local variable 'size' inside while loop to 'sd_size'.
> > 
> > And also add one local variable 'sd_size' likewise in function
> > memremap_is_setup_data() to simplify code. In later patch, this can also
> > be used.
> > 
> > Signed-off-by: Baoquan He <bhe@redhat.com>
> > Acked-by: Tom Lendacky <thomas.lendacky@amd.com>
> > ---
> >  arch/x86/mm/ioremap.c | 18 +++++++++++-------
> >  1 file changed, 11 insertions(+), 7 deletions(-)
> > 
> > diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c
> > index aa7d279321ea..f1ee8822ddf1 100644
> > --- a/arch/x86/mm/ioremap.c
> > +++ b/arch/x86/mm/ioremap.c
> > @@ -640,7 +640,7 @@ static bool memremap_is_setup_data(resource_size_t phys_addr,
> 
> Huh?

Thanks for looking into this.

I ever doubted this, guess it could use the unused 'size' to avoid
warning? Noticed Tom introduced it at the beginning. It's better idea to
remove it if it's useless.

commit 8f716c9b5febf6ed0f5fedb7c9407cd0c25b2796
Author: Tom Lendacky <thomas.lendacky@amd.com>
Date:   Mon Jul 17 16:10:16 2017 -0500

    x86/mm: Add support to access boot related data in the clear

Hi Tom,

Can you help check and tell your intention why the argument 'size' is
added into early_memremap_is_setup_data() and memremap_is_setup_data().

Thanks
Baoquan

> 
> ---
> diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c
> index 70b02fc61d93..e461d8e26871 100644
> --- a/arch/x86/mm/ioremap.c
> +++ b/arch/x86/mm/ioremap.c
> @@ -632,8 +632,7 @@ static bool memremap_is_efi_data(resource_size_t phys_addr,
>   * Examine the physical address to determine if it is boot data by checking
>   * it against the boot params setup_data chain.
>   */
> -static bool memremap_is_setup_data(resource_size_t phys_addr,
> -				   unsigned long size)
> +static bool memremap_is_setup_data(resource_size_t phys_addr)
>  {
>  	struct setup_indirect *indirect;
>  	struct setup_data *data;
> @@ -769,7 +768,7 @@ bool arch_memremap_can_ram_remap(resource_size_t phys_addr, unsigned long size,
>  		return false;
>  
>  	if (cc_platform_has(CC_ATTR_HOST_MEM_ENCRYPT)) {
> -		if (memremap_is_setup_data(phys_addr, size) ||
> +		if (memremap_is_setup_data(phys_addr) ||
>  		    memremap_is_efi_data(phys_addr, size))
>  			return false;
>  	}
> 
> -- 
> Regards/Gruss,
>     Boris.
> 
> https://people.kernel.org/tglx/notes-about-netiquette
>
Re: [PATCH v3 1/2] x86/mm: rename the confusing local variable in early_memremap_is_setup_data()
Posted by Tom Lendacky 1 month ago
On 10/29/24 19:53, Baoquan He wrote:
> On 10/29/24 at 07:11pm, Borislav Petkov wrote:
>> On Wed, Sep 11, 2024 at 04:16:14PM +0800, Baoquan He wrote:
>>> In function early_memremap_is_setup_data(), parameter 'size' passed has
>>> the same name as the local variable inside the while loop. That
>>> confuses people who sometime mix up them when reading code.
>>>
>>> Here rename the local variable 'size' inside while loop to 'sd_size'.
>>>
>>> And also add one local variable 'sd_size' likewise in function
>>> memremap_is_setup_data() to simplify code. In later patch, this can also
>>> be used.
>>>
>>> Signed-off-by: Baoquan He <bhe@redhat.com>
>>> Acked-by: Tom Lendacky <thomas.lendacky@amd.com>
>>> ---
>>>  arch/x86/mm/ioremap.c | 18 +++++++++++-------
>>>  1 file changed, 11 insertions(+), 7 deletions(-)
>>>
>>> diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c
>>> index aa7d279321ea..f1ee8822ddf1 100644
>>> --- a/arch/x86/mm/ioremap.c
>>> +++ b/arch/x86/mm/ioremap.c
>>> @@ -640,7 +640,7 @@ static bool memremap_is_setup_data(resource_size_t phys_addr,
>>
>> Huh?
> 
> Thanks for looking into this.
> 
> I ever doubted this, guess it could use the unused 'size' to avoid
> warning? Noticed Tom introduced it at the beginning. It's better idea to
> remove it if it's useless.
> 
> commit 8f716c9b5febf6ed0f5fedb7c9407cd0c25b2796
> Author: Tom Lendacky <thomas.lendacky@amd.com>
> Date:   Mon Jul 17 16:10:16 2017 -0500
> 
>     x86/mm: Add support to access boot related data in the clear
> 
> Hi Tom,
> 
> Can you help check and tell your intention why the argument 'size' is
> added into early_memremap_is_setup_data() and memremap_is_setup_data().

That was a long time ago... I probably used it while I was developing the
support and then never removed it in the final version where it wasn't used.

Thanks,
Tom

> 
> Thanks
> Baoquan
> 
>>
>> ---
>> diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c
>> index 70b02fc61d93..e461d8e26871 100644
>> --- a/arch/x86/mm/ioremap.c
>> +++ b/arch/x86/mm/ioremap.c
>> @@ -632,8 +632,7 @@ static bool memremap_is_efi_data(resource_size_t phys_addr,
>>   * Examine the physical address to determine if it is boot data by checking
>>   * it against the boot params setup_data chain.
>>   */
>> -static bool memremap_is_setup_data(resource_size_t phys_addr,
>> -				   unsigned long size)
>> +static bool memremap_is_setup_data(resource_size_t phys_addr)
>>  {
>>  	struct setup_indirect *indirect;
>>  	struct setup_data *data;
>> @@ -769,7 +768,7 @@ bool arch_memremap_can_ram_remap(resource_size_t phys_addr, unsigned long size,
>>  		return false;
>>  
>>  	if (cc_platform_has(CC_ATTR_HOST_MEM_ENCRYPT)) {
>> -		if (memremap_is_setup_data(phys_addr, size) ||
>> +		if (memremap_is_setup_data(phys_addr) ||
>>  		    memremap_is_efi_data(phys_addr, size))
>>  			return false;
>>  	}
>>
>> -- 
>> Regards/Gruss,
>>     Boris.
>>
>> https://people.kernel.org/tglx/notes-about-netiquette
>>
> 
>
Re: [PATCH v3 1/2] x86/mm: rename the confusing local variable in early_memremap_is_setup_data()
Posted by Baoquan He 1 month ago
On 10/30/24 at 07:49am, Tom Lendacky wrote:
> On 10/29/24 19:53, Baoquan He wrote:
> > On 10/29/24 at 07:11pm, Borislav Petkov wrote:
> >> On Wed, Sep 11, 2024 at 04:16:14PM +0800, Baoquan He wrote:
> >>> In function early_memremap_is_setup_data(), parameter 'size' passed has
> >>> the same name as the local variable inside the while loop. That
> >>> confuses people who sometime mix up them when reading code.
> >>>
> >>> Here rename the local variable 'size' inside while loop to 'sd_size'.
> >>>
> >>> And also add one local variable 'sd_size' likewise in function
> >>> memremap_is_setup_data() to simplify code. In later patch, this can also
> >>> be used.
> >>>
> >>> Signed-off-by: Baoquan He <bhe@redhat.com>
> >>> Acked-by: Tom Lendacky <thomas.lendacky@amd.com>
> >>> ---
> >>>  arch/x86/mm/ioremap.c | 18 +++++++++++-------
> >>>  1 file changed, 11 insertions(+), 7 deletions(-)
> >>>
> >>> diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c
> >>> index aa7d279321ea..f1ee8822ddf1 100644
> >>> --- a/arch/x86/mm/ioremap.c
> >>> +++ b/arch/x86/mm/ioremap.c
> >>> @@ -640,7 +640,7 @@ static bool memremap_is_setup_data(resource_size_t phys_addr,
> >>
> >> Huh?
> > 
> > Thanks for looking into this.
> > 
> > I ever doubted this, guess it could use the unused 'size' to avoid
> > warning? Noticed Tom introduced it at the beginning. It's better idea to
> > remove it if it's useless.
> > 
> > commit 8f716c9b5febf6ed0f5fedb7c9407cd0c25b2796
> > Author: Tom Lendacky <thomas.lendacky@amd.com>
> > Date:   Mon Jul 17 16:10:16 2017 -0500
> > 
> >     x86/mm: Add support to access boot related data in the clear
> > 
> > Hi Tom,
> > 
> > Can you help check and tell your intention why the argument 'size' is
> > added into early_memremap_is_setup_data() and memremap_is_setup_data().
> 
> That was a long time ago... I probably used it while I was developing the
> support and then never removed it in the final version where it wasn't used.

Thanks for confirming. Then we can remove it to avoid confusion.

Hi Boris,

Should I send the fixing patch alone and clean up the useless argument
'size' later, or squash them into one patch?

Thanks
Baoquan
Re: [PATCH v3 1/2] x86/mm: rename the confusing local variable in early_memremap_is_setup_data()
Posted by Borislav Petkov 4 weeks ago
On Thu, Oct 31, 2024 at 11:41:12AM +0800, Baoquan He wrote:
> Should I send the fixing patch alone and clean up the useless argument
> 'size' later, or squash them into one patch?

First the fix, then the cleanup.

Btw, that fix wants to go to stable no? Seeing how it breaks certain machines
with IMA and kdump and SMe...

Thx.

-- 
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette
Re: [PATCH v3 1/2] x86/mm: rename the confusing local variable in early_memremap_is_setup_data()
Posted by Baoquan He 4 weeks ago
On 11/01/24 at 05:18pm, Borislav Petkov wrote:
> On Thu, Oct 31, 2024 at 11:41:12AM +0800, Baoquan He wrote:
> > Should I send the fixing patch alone and clean up the useless argument
> > 'size' later, or squash them into one patch?
> 
> First the fix, then the cleanup.

Sure, will do. Thanks a lot.

> 
> Btw, that fix wants to go to stable no? Seeing how it breaks certain machines
> with IMA and kdump and SMe...

Yeah, it should be added to stable. Distros may get both SME/IMA set not
as early as the bug introduced, while anyone doing so in an earlier kernel
will see the problem.
Re: [PATCH v3 1/2] x86/mm: rename the confusing local variable in early_memremap_is_setup_data()
Posted by Borislav Petkov 3 weeks, 6 days ago
On Sat, Nov 02, 2024 at 08:23:33AM +0800, Baoquan He wrote:
> Yeah, it should be added to stable. Distros may get both SME/IMA set not
> as early as the bug introduced, while anyone doing so in an earlier kernel
> will see the problem.

Ok, I'll take your 2/2 next week and you can then send the cleanup ontop.

Thx.

-- 
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette
Re: [PATCH v3 1/2] x86/mm: rename the confusing local variable in early_memremap_is_setup_data()
Posted by Borislav Petkov 3 weeks, 2 days ago
On Sat, Nov 02, 2024 at 12:06:18PM +0100, Borislav Petkov wrote:
> Ok, I'll take your 2/2 next week and you can then send the cleanup ontop.

OMG what a mess this is. Please test the below before I apply it.

Then, when you do the cleanup, do the following:

- merge early_memremap_is_setup_data() with memremap_is_setup_data() into
  a common __memremap_is_setup_data() and then add a bool early which
  determines which memremap variant is called.

- unify the @size argument by dropping it and using a function local size.
  What we have there now is the definition of bitrot. :-\

- replace all sizeof(*data), sizeof(struct setup_data) with a macro definition
  above the functions to unify it properly.

What an ugly mess... :-\

---
From: Baoquan He <bhe@redhat.com>
Date: Wed, 11 Sep 2024 16:16:15 +0800
Subject: [PATCH] x86/mm: Fix a kdump kernel failure on SME system when
 CONFIG_IMA_KEXEC=y
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

The kdump kernel is broken on SME systems with CONFIG_IMA_KEXEC=y enabled.
Debugging traced the issue back to

  b69a2afd5afc ("x86/kexec: Carry forward IMA measurement log on kexec").

Testing was previously not conducted on SME systems with CONFIG_IMA_KEXEC
enabled, which led to the oversight, with the following incarnation:

...
  ima: No TPM chip found, activating TPM-bypass!
  Loading compiled-in module X.509 certificates
  Loaded X.509 cert 'Build time autogenerated kernel key: 18ae0bc7e79b64700122bb1d6a904b070fef2656'
  ima: Allocated hash algorithm: sha256
  Oops: general protection fault, probably for non-canonical address 0xcfacfdfe6660003e: 0000 [#1] PREEMPT SMP NOPTI
  CPU: 0 UID: 0 PID: 1 Comm: swapper/0 Not tainted 6.11.0-rc2+ #14
  Hardware name: Dell Inc. PowerEdge R7425/02MJ3T, BIOS 1.20.0 05/03/2023
  RIP: 0010:ima_restore_measurement_list
  Call Trace:
   <TASK>
   ? show_trace_log_lvl
   ? show_trace_log_lvl
   ? ima_load_kexec_buffer
   ? __die_body.cold
   ? die_addr
   ? exc_general_protection
   ? asm_exc_general_protection
   ? ima_restore_measurement_list
   ? vprintk_emit
   ? ima_load_kexec_buffer
   ima_load_kexec_buffer
   ima_init
   ? __pfx_init_ima
   init_ima
   ? __pfx_init_ima
   do_one_initcall
   do_initcalls
   ? __pfx_kernel_init
   kernel_init_freeable
   kernel_init
   ret_from_fork
   ? __pfx_kernel_init
   ret_from_fork_asm
   </TASK>
  Modules linked in:
  ---[ end trace 0000000000000000 ]---
  ...
  Kernel panic - not syncing: Fatal exception
  Kernel Offset: disabled
  Rebooting in 10 seconds..

Adding debug printks showed that the stored addr and size of ima_kexec buffer
are not decrypted correctly like:

  ima: ima_load_kexec_buffer, buffer:0xcfacfdfe6660003e, size:0xe48066052d5df359

Three types of setup_data info

  — SETUP_EFI,
  - SETUP_IMA, and
  - SETUP_RNG_SEED

are passed to the kexec/kdump kernel. Only the ima_kexec buffer
experienced incorrect decryption. Debugging identified a bug in
early_memremap_is_setup_data(), where an incorrect range calculation
occurred due to the len variable in struct setup_data ended up only
representing the length of the data field, excluding the struct's size,
and thus leading to miscalculation.

Address a similar issue in memremap_is_setup_data() while at it.

  [ bp: Heavily massage. ]

Fixes: b3c72fc9a78e ("x86/boot: Introduce setup_indirect")
Signed-off-by: Baoquan He <bhe@redhat.com>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Acked-by: Tom Lendacky <thomas.lendacky@amd.com>
Cc: <stable@kernel.org>
Link: https://lore.kernel.org/r/20240911081615.262202-3-bhe@redhat.com
---
 arch/x86/mm/ioremap.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c
index 70b02fc61d93..8d29163568a7 100644
--- a/arch/x86/mm/ioremap.c
+++ b/arch/x86/mm/ioremap.c
@@ -656,7 +656,8 @@ static bool memremap_is_setup_data(resource_size_t phys_addr,
 		paddr_next = data->next;
 		len = data->len;
 
-		if ((phys_addr > paddr) && (phys_addr < (paddr + len))) {
+		if ((phys_addr > paddr) &&
+		    (phys_addr < (paddr + sizeof(struct setup_data) + len))) {
 			memunmap(data);
 			return true;
 		}
@@ -718,7 +719,8 @@ static bool __init early_memremap_is_setup_data(resource_size_t phys_addr,
 		paddr_next = data->next;
 		len = data->len;
 
-		if ((phys_addr > paddr) && (phys_addr < (paddr + len))) {
+		if ((phys_addr > paddr) &&
+		    (phys_addr < (paddr + sizeof(struct setup_data) + len))) {
 			early_memunmap(data, sizeof(*data));
 			return true;
 		}
-- 
2.43.0


-- 
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette
Re: [PATCH v3 1/2] x86/mm: rename the confusing local variable in early_memremap_is_setup_data()
Posted by Baoquan He 2 weeks, 2 days ago
On 11/06/24 at 12:20pm, Borislav Petkov wrote:
> On Sat, Nov 02, 2024 at 12:06:18PM +0100, Borislav Petkov wrote:
> > Ok, I'll take your 2/2 next week and you can then send the cleanup ontop.
> 
> OMG what a mess this is. Please test the below before I apply it.

I finally got an available machine to test below patch, I can confirm
that without it the breakage can be reproduced stably; with below patch
applied the breakage is gone and vmcore dumping is successful.

> 
> Then, when you do the cleanup, do the following:

Will post cleanup patch later. Thanks.

> 
> - merge early_memremap_is_setup_data() with memremap_is_setup_data() into
>   a common __memremap_is_setup_data() and then add a bool early which
>   determines which memremap variant is called.
> 
> - unify the @size argument by dropping it and using a function local size.
>   What we have there now is the definition of bitrot. :-\
> 
> - replace all sizeof(*data), sizeof(struct setup_data) with a macro definition
>   above the functions to unify it properly.
> 
> What an ugly mess... :-\
> 
> ---
> From: Baoquan He <bhe@redhat.com>
> Date: Wed, 11 Sep 2024 16:16:15 +0800
> Subject: [PATCH] x86/mm: Fix a kdump kernel failure on SME system when
>  CONFIG_IMA_KEXEC=y
> MIME-Version: 1.0
> Content-Type: text/plain; charset=UTF-8
> Content-Transfer-Encoding: 8bit
> 
> The kdump kernel is broken on SME systems with CONFIG_IMA_KEXEC=y enabled.
> Debugging traced the issue back to
> 
>   b69a2afd5afc ("x86/kexec: Carry forward IMA measurement log on kexec").
> 
> Testing was previously not conducted on SME systems with CONFIG_IMA_KEXEC
> enabled, which led to the oversight, with the following incarnation:
> 
> ...
>   ima: No TPM chip found, activating TPM-bypass!
>   Loading compiled-in module X.509 certificates
>   Loaded X.509 cert 'Build time autogenerated kernel key: 18ae0bc7e79b64700122bb1d6a904b070fef2656'
>   ima: Allocated hash algorithm: sha256
>   Oops: general protection fault, probably for non-canonical address 0xcfacfdfe6660003e: 0000 [#1] PREEMPT SMP NOPTI
>   CPU: 0 UID: 0 PID: 1 Comm: swapper/0 Not tainted 6.11.0-rc2+ #14
>   Hardware name: Dell Inc. PowerEdge R7425/02MJ3T, BIOS 1.20.0 05/03/2023
>   RIP: 0010:ima_restore_measurement_list
>   Call Trace:
>    <TASK>
>    ? show_trace_log_lvl
>    ? show_trace_log_lvl
>    ? ima_load_kexec_buffer
>    ? __die_body.cold
>    ? die_addr
>    ? exc_general_protection
>    ? asm_exc_general_protection
>    ? ima_restore_measurement_list
>    ? vprintk_emit
>    ? ima_load_kexec_buffer
>    ima_load_kexec_buffer
>    ima_init
>    ? __pfx_init_ima
>    init_ima
>    ? __pfx_init_ima
>    do_one_initcall
>    do_initcalls
>    ? __pfx_kernel_init
>    kernel_init_freeable
>    kernel_init
>    ret_from_fork
>    ? __pfx_kernel_init
>    ret_from_fork_asm
>    </TASK>
>   Modules linked in:
>   ---[ end trace 0000000000000000 ]---
>   ...
>   Kernel panic - not syncing: Fatal exception
>   Kernel Offset: disabled
>   Rebooting in 10 seconds..
> 
> Adding debug printks showed that the stored addr and size of ima_kexec buffer
> are not decrypted correctly like:
> 
>   ima: ima_load_kexec_buffer, buffer:0xcfacfdfe6660003e, size:0xe48066052d5df359
> 
> Three types of setup_data info
> 
>   — SETUP_EFI,
>   - SETUP_IMA, and
>   - SETUP_RNG_SEED
> 
> are passed to the kexec/kdump kernel. Only the ima_kexec buffer
> experienced incorrect decryption. Debugging identified a bug in
> early_memremap_is_setup_data(), where an incorrect range calculation
> occurred due to the len variable in struct setup_data ended up only
> representing the length of the data field, excluding the struct's size,
> and thus leading to miscalculation.
> 
> Address a similar issue in memremap_is_setup_data() while at it.
> 
>   [ bp: Heavily massage. ]
> 
> Fixes: b3c72fc9a78e ("x86/boot: Introduce setup_indirect")
> Signed-off-by: Baoquan He <bhe@redhat.com>
> Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
> Acked-by: Tom Lendacky <thomas.lendacky@amd.com>
> Cc: <stable@kernel.org>
> Link: https://lore.kernel.org/r/20240911081615.262202-3-bhe@redhat.com
> ---
>  arch/x86/mm/ioremap.c | 6 ++++--
>  1 file changed, 4 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c
> index 70b02fc61d93..8d29163568a7 100644
> --- a/arch/x86/mm/ioremap.c
> +++ b/arch/x86/mm/ioremap.c
> @@ -656,7 +656,8 @@ static bool memremap_is_setup_data(resource_size_t phys_addr,
>  		paddr_next = data->next;
>  		len = data->len;
>  
> -		if ((phys_addr > paddr) && (phys_addr < (paddr + len))) {
> +		if ((phys_addr > paddr) &&
> +		    (phys_addr < (paddr + sizeof(struct setup_data) + len))) {
>  			memunmap(data);
>  			return true;
>  		}
> @@ -718,7 +719,8 @@ static bool __init early_memremap_is_setup_data(resource_size_t phys_addr,
>  		paddr_next = data->next;
>  		len = data->len;
>  
> -		if ((phys_addr > paddr) && (phys_addr < (paddr + len))) {
> +		if ((phys_addr > paddr) &&
> +		    (phys_addr < (paddr + sizeof(struct setup_data) + len))) {
>  			early_memunmap(data, sizeof(*data));
>  			return true;
>  		}
> -- 
> 2.43.0
> 
> 
> -- 
> Regards/Gruss,
>     Boris.
> 
> https://people.kernel.org/tglx/notes-about-netiquette
> 

Re: [PATCH v3 1/2] x86/mm: rename the confusing local variable in early_memremap_is_setup_data()
Posted by Borislav Petkov 2 weeks, 2 days ago
On Wed, Nov 13, 2024 at 08:55:47PM +0800, Baoquan He wrote:
> I finally got an available machine to test below patch, I can confirm
> that without it the breakage can be reproduced stably; with below patch
> applied the breakage is gone and vmcore dumping is successful.

Thanks, lemme queue it.

> Will post cleanup patch later. Thanks.

Thx.

-- 
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette
Re: [PATCH v3 1/2] x86/mm: rename the confusing local variable in early_memremap_is_setup_data()
Posted by Baoquan He 3 weeks, 1 day ago
On 11/06/24 at 12:20pm, Borislav Petkov wrote:
> On Sat, Nov 02, 2024 at 12:06:18PM +0100, Borislav Petkov wrote:
> > Ok, I'll take your 2/2 next week and you can then send the cleanup ontop.
> 
> OMG what a mess this is. Please test the below before I apply it.

Just got a machine and building kernel, will report here when testing is
done.

> 
> Then, when you do the cleanup, do the following:
> 
> - merge early_memremap_is_setup_data() with memremap_is_setup_data() into
>   a common __memremap_is_setup_data() and then add a bool early which
>   determines which memremap variant is called.
> 
> - unify the @size argument by dropping it and using a function local size.
>   What we have there now is the definition of bitrot. :-\
> 
> - replace all sizeof(*data), sizeof(struct setup_data) with a macro definition
>   above the functions to unify it properly.
> 
> What an ugly mess... :-\

Will clean them all up as suggested. Thanks.