Presently ima_get_kexec_buffer() doesn't check if the previous kernel's
ima-kexec-buffer lies outside the addressable memory range. This can result
in a kernel panic if the new kernel is booted with 'mem=X' arg and the
ima-kexec-buffer was allocated beyond that range by the previous kernel.
The panic is usually of the form below:
$ sudo kexec --initrd initrd vmlinux --append='mem=16G'
<snip>
BUG: Unable to handle kernel data access on read at 0xc000c01fff7f0000
Faulting instruction address: 0xc000000000837974
Oops: Kernel access of bad area, sig: 11 [#1]
<snip>
NIP [c000000000837974] ima_restore_measurement_list+0x94/0x6c0
LR [c00000000083b55c] ima_load_kexec_buffer+0xac/0x160
Call Trace:
[c00000000371fa80] [c00000000083b55c] ima_load_kexec_buffer+0xac/0x160
[c00000000371fb00] [c0000000020512c4] ima_init+0x80/0x108
[c00000000371fb70] [c0000000020514dc] init_ima+0x4c/0x120
[c00000000371fbf0] [c000000000012240] do_one_initcall+0x60/0x2c0
[c00000000371fcc0] [c000000002004ad0] kernel_init_freeable+0x344/0x3ec
[c00000000371fda0] [c0000000000128a4] kernel_init+0x34/0x1b0
[c00000000371fe10] [c00000000000ce64] ret_from_kernel_thread+0x5c/0x64
Instruction dump:
f92100b8 f92100c0 90e10090 910100a0 4182050c 282a0017 3bc00000 40810330
7c0802a6 fb610198 7c9b2378 f80101d0 <a1240000> 2c090001 40820614 e9240010
---[ end trace 0000000000000000 ]---
Fix this issue by checking returned PFN range of previous kernel's
ima-kexec-buffer with pfn_valid to ensure correct memory bounds.
Fixes: 467d27824920 ("powerpc: ima: get the kexec buffer passed by the previous kernel")
Cc: Frank Rowand <[email protected]>
Cc: Prakhar Srivastava <[email protected]>
Cc: Lakshmi Ramasubramanian <[email protected]>
Cc: Thiago Jung Bauermann <[email protected]>
Cc: Rob Herring <[email protected]>
Signed-off-by: Vaibhav Jain <[email protected]>
---
Changelog
==========
v2:
* Instead of using memblock to determine the valid bounds use pfn_valid() to do
so since memblock may not be available late after the kernel init. [ Mpe ]
* Changed the patch prefix from 'powerpc' to 'of' [ Mpe ]
* Updated the 'Fixes' tag to point to correct commit that introduced this
function. [ Rob ]
* Fixed some whitespace/tab issues in the patch description [ Rob ]
* Added another check for checking ig 'tmp_size' for ima-kexec-buffer is > 0
---
drivers/of/kexec.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/drivers/of/kexec.c b/drivers/of/kexec.c
index 8d374cc552be..879e984fe901 100644
--- a/drivers/of/kexec.c
+++ b/drivers/of/kexec.c
@@ -126,6 +126,7 @@ int ima_get_kexec_buffer(void **addr, size_t *size)
{
int ret, len;
unsigned long tmp_addr;
+ unsigned int start_pfn, end_pfn;
size_t tmp_size;
const void *prop;
@@ -140,6 +141,22 @@ int ima_get_kexec_buffer(void **addr, size_t *size)
if (ret)
return ret;
+ /* Do some sanity on the returned size for the ima-kexec buffer */
+ if (!tmp_size)
+ return -ENOENT;
+
+ /*
+ * Calculate the PFNs for the buffer and ensure
+ * they are with in addressable memory.
+ */
+ start_pfn = PHYS_PFN(tmp_addr);
+ end_pfn = PHYS_PFN(tmp_addr + tmp_size - 1);
+ if (!pfn_valid(start_pfn) || !pfn_valid(end_pfn)) {
+ pr_warn("IMA buffer at 0x%lx, size = 0x%zx beyond memory\n",
+ tmp_addr, tmp_size);
+ return -EINVAL;
+ }
+
*addr = __va(tmp_addr);
*size = tmp_size;
--
2.35.1
Hi Ritesh,
thanks for looking into this patch,
Ritesh Harjani <[email protected]> writes:
> Just a minor nit which I noticed.
>
> On 22/05/24 11:20AM, Vaibhav Jain wrote:
>> Presently ima_get_kexec_buffer() doesn't check if the previous kernel's
>> ima-kexec-buffer lies outside the addressable memory range. This can result
>> in a kernel panic if the new kernel is booted with 'mem=X' arg and the
>> ima-kexec-buffer was allocated beyond that range by the previous kernel.
>> The panic is usually of the form below:
>>
>> $ sudo kexec --initrd initrd vmlinux --append='mem=16G'
>>
>> <snip>
>> BUG: Unable to handle kernel data access on read at 0xc000c01fff7f0000
>> Faulting instruction address: 0xc000000000837974
>> Oops: Kernel access of bad area, sig: 11 [#1]
>> <snip>
>> NIP [c000000000837974] ima_restore_measurement_list+0x94/0x6c0
>> LR [c00000000083b55c] ima_load_kexec_buffer+0xac/0x160
>> Call Trace:
>> [c00000000371fa80] [c00000000083b55c] ima_load_kexec_buffer+0xac/0x160
>> [c00000000371fb00] [c0000000020512c4] ima_init+0x80/0x108
>> [c00000000371fb70] [c0000000020514dc] init_ima+0x4c/0x120
>> [c00000000371fbf0] [c000000000012240] do_one_initcall+0x60/0x2c0
>> [c00000000371fcc0] [c000000002004ad0] kernel_init_freeable+0x344/0x3ec
>> [c00000000371fda0] [c0000000000128a4] kernel_init+0x34/0x1b0
>> [c00000000371fe10] [c00000000000ce64] ret_from_kernel_thread+0x5c/0x64
>> Instruction dump:
>> f92100b8 f92100c0 90e10090 910100a0 4182050c 282a0017 3bc00000 40810330
>> 7c0802a6 fb610198 7c9b2378 f80101d0 <a1240000> 2c090001 40820614 e9240010
>> ---[ end trace 0000000000000000 ]---
>>
>> Fix this issue by checking returned PFN range of previous kernel's
>> ima-kexec-buffer with pfn_valid to ensure correct memory bounds.
>>
>> Fixes: 467d27824920 ("powerpc: ima: get the kexec buffer passed by the previous kernel")
>> Cc: Frank Rowand <[email protected]>
>> Cc: Prakhar Srivastava <[email protected]>
>> Cc: Lakshmi Ramasubramanian <[email protected]>
>> Cc: Thiago Jung Bauermann <[email protected]>
>> Cc: Rob Herring <[email protected]>
>> Signed-off-by: Vaibhav Jain <[email protected]>
>>
>> ---
>> Changelog
>> ==========
>>
>> v2:
>> * Instead of using memblock to determine the valid bounds use pfn_valid() to do
>> so since memblock may not be available late after the kernel init. [ Mpe ]
>> * Changed the patch prefix from 'powerpc' to 'of' [ Mpe ]
>> * Updated the 'Fixes' tag to point to correct commit that introduced this
>> function. [ Rob ]
>> * Fixed some whitespace/tab issues in the patch description [ Rob ]
>> * Added another check for checking ig 'tmp_size' for ima-kexec-buffer is > 0
>> ---
>> drivers/of/kexec.c | 17 +++++++++++++++++
>> 1 file changed, 17 insertions(+)
>>
>> diff --git a/drivers/of/kexec.c b/drivers/of/kexec.c
>> index 8d374cc552be..879e984fe901 100644
>> --- a/drivers/of/kexec.c
>> +++ b/drivers/of/kexec.c
>> @@ -126,6 +126,7 @@ int ima_get_kexec_buffer(void **addr, size_t *size)
>> {
>> int ret, len;
>> unsigned long tmp_addr;
>> + unsigned int start_pfn, end_pfn;
>
> ^^^ Shouldn't this be unsigned long?
Thanks for catching this. Yes that should be 'unsigned long'. Will
resend the patch with this fixed.
>
> -ritesh
>
>> size_t tmp_size;
>> const void *prop;
>>
>> @@ -140,6 +141,22 @@ int ima_get_kexec_buffer(void **addr, size_t *size)
>> if (ret)
>> return ret;
>>
>> + /* Do some sanity on the returned size for the ima-kexec buffer */
>> + if (!tmp_size)
>> + return -ENOENT;
>> +
>> + /*
>> + * Calculate the PFNs for the buffer and ensure
>> + * they are with in addressable memory.
>> + */
>> + start_pfn = PHYS_PFN(tmp_addr);
>> + end_pfn = PHYS_PFN(tmp_addr + tmp_size - 1);
>> + if (!pfn_valid(start_pfn) || !pfn_valid(end_pfn)) {
>> + pr_warn("IMA buffer at 0x%lx, size = 0x%zx beyond memory\n",
>> + tmp_addr, tmp_size);
>> + return -EINVAL;
>> + }
>> +
>> *addr = __va(tmp_addr);
>> *size = tmp_size;
>>
>> --
>> 2.35.1
>>
--
Cheers
~ Vaibhav
Just a minor nit which I noticed.
On 22/05/24 11:20AM, Vaibhav Jain wrote:
> Presently ima_get_kexec_buffer() doesn't check if the previous kernel's
> ima-kexec-buffer lies outside the addressable memory range. This can result
> in a kernel panic if the new kernel is booted with 'mem=X' arg and the
> ima-kexec-buffer was allocated beyond that range by the previous kernel.
> The panic is usually of the form below:
>
> $ sudo kexec --initrd initrd vmlinux --append='mem=16G'
>
> <snip>
> BUG: Unable to handle kernel data access on read at 0xc000c01fff7f0000
> Faulting instruction address: 0xc000000000837974
> Oops: Kernel access of bad area, sig: 11 [#1]
> <snip>
> NIP [c000000000837974] ima_restore_measurement_list+0x94/0x6c0
> LR [c00000000083b55c] ima_load_kexec_buffer+0xac/0x160
> Call Trace:
> [c00000000371fa80] [c00000000083b55c] ima_load_kexec_buffer+0xac/0x160
> [c00000000371fb00] [c0000000020512c4] ima_init+0x80/0x108
> [c00000000371fb70] [c0000000020514dc] init_ima+0x4c/0x120
> [c00000000371fbf0] [c000000000012240] do_one_initcall+0x60/0x2c0
> [c00000000371fcc0] [c000000002004ad0] kernel_init_freeable+0x344/0x3ec
> [c00000000371fda0] [c0000000000128a4] kernel_init+0x34/0x1b0
> [c00000000371fe10] [c00000000000ce64] ret_from_kernel_thread+0x5c/0x64
> Instruction dump:
> f92100b8 f92100c0 90e10090 910100a0 4182050c 282a0017 3bc00000 40810330
> 7c0802a6 fb610198 7c9b2378 f80101d0 <a1240000> 2c090001 40820614 e9240010
> ---[ end trace 0000000000000000 ]---
>
> Fix this issue by checking returned PFN range of previous kernel's
> ima-kexec-buffer with pfn_valid to ensure correct memory bounds.
>
> Fixes: 467d27824920 ("powerpc: ima: get the kexec buffer passed by the previous kernel")
> Cc: Frank Rowand <[email protected]>
> Cc: Prakhar Srivastava <[email protected]>
> Cc: Lakshmi Ramasubramanian <[email protected]>
> Cc: Thiago Jung Bauermann <[email protected]>
> Cc: Rob Herring <[email protected]>
> Signed-off-by: Vaibhav Jain <[email protected]>
>
> ---
> Changelog
> ==========
>
> v2:
> * Instead of using memblock to determine the valid bounds use pfn_valid() to do
> so since memblock may not be available late after the kernel init. [ Mpe ]
> * Changed the patch prefix from 'powerpc' to 'of' [ Mpe ]
> * Updated the 'Fixes' tag to point to correct commit that introduced this
> function. [ Rob ]
> * Fixed some whitespace/tab issues in the patch description [ Rob ]
> * Added another check for checking ig 'tmp_size' for ima-kexec-buffer is > 0
> ---
> drivers/of/kexec.c | 17 +++++++++++++++++
> 1 file changed, 17 insertions(+)
>
> diff --git a/drivers/of/kexec.c b/drivers/of/kexec.c
> index 8d374cc552be..879e984fe901 100644
> --- a/drivers/of/kexec.c
> +++ b/drivers/of/kexec.c
> @@ -126,6 +126,7 @@ int ima_get_kexec_buffer(void **addr, size_t *size)
> {
> int ret, len;
> unsigned long tmp_addr;
> + unsigned int start_pfn, end_pfn;
^^^ Shouldn't this be unsigned long?
-ritesh
> size_t tmp_size;
> const void *prop;
>
> @@ -140,6 +141,22 @@ int ima_get_kexec_buffer(void **addr, size_t *size)
> if (ret)
> return ret;
>
> + /* Do some sanity on the returned size for the ima-kexec buffer */
> + if (!tmp_size)
> + return -ENOENT;
> +
> + /*
> + * Calculate the PFNs for the buffer and ensure
> + * they are with in addressable memory.
> + */
> + start_pfn = PHYS_PFN(tmp_addr);
> + end_pfn = PHYS_PFN(tmp_addr + tmp_size - 1);
> + if (!pfn_valid(start_pfn) || !pfn_valid(end_pfn)) {
> + pr_warn("IMA buffer at 0x%lx, size = 0x%zx beyond memory\n",
> + tmp_addr, tmp_size);
> + return -EINVAL;
> + }
> +
> *addr = __va(tmp_addr);
> *size = tmp_size;
>
> --
> 2.35.1
>
On Tue, May 24, 2022 at 11:20:42AM +0530, Vaibhav Jain wrote:
> Presently ima_get_kexec_buffer() doesn't check if the previous kernel's
> ima-kexec-buffer lies outside the addressable memory range. This can result
> in a kernel panic if the new kernel is booted with 'mem=X' arg and the
> ima-kexec-buffer was allocated beyond that range by the previous kernel.
> The panic is usually of the form below:
>
> $ sudo kexec --initrd initrd vmlinux --append='mem=16G'
>
> <snip>
> BUG: Unable to handle kernel data access on read at 0xc000c01fff7f0000
> Faulting instruction address: 0xc000000000837974
> Oops: Kernel access of bad area, sig: 11 [#1]
> <snip>
> NIP [c000000000837974] ima_restore_measurement_list+0x94/0x6c0
> LR [c00000000083b55c] ima_load_kexec_buffer+0xac/0x160
> Call Trace:
> [c00000000371fa80] [c00000000083b55c] ima_load_kexec_buffer+0xac/0x160
> [c00000000371fb00] [c0000000020512c4] ima_init+0x80/0x108
> [c00000000371fb70] [c0000000020514dc] init_ima+0x4c/0x120
> [c00000000371fbf0] [c000000000012240] do_one_initcall+0x60/0x2c0
> [c00000000371fcc0] [c000000002004ad0] kernel_init_freeable+0x344/0x3ec
> [c00000000371fda0] [c0000000000128a4] kernel_init+0x34/0x1b0
> [c00000000371fe10] [c00000000000ce64] ret_from_kernel_thread+0x5c/0x64
> Instruction dump:
> f92100b8 f92100c0 90e10090 910100a0 4182050c 282a0017 3bc00000 40810330
> 7c0802a6 fb610198 7c9b2378 f80101d0 <a1240000> 2c090001 40820614 e9240010
> ---[ end trace 0000000000000000 ]---
>
> Fix this issue by checking returned PFN range of previous kernel's
> ima-kexec-buffer with pfn_valid to ensure correct memory bounds.
>
> Fixes: 467d27824920 ("powerpc: ima: get the kexec buffer passed by the previous kernel")
> Cc: Frank Rowand <[email protected]>
> Cc: Prakhar Srivastava <[email protected]>
> Cc: Lakshmi Ramasubramanian <[email protected]>
> Cc: Thiago Jung Bauermann <[email protected]>
> Cc: Rob Herring <[email protected]>
> Signed-off-by: Vaibhav Jain <[email protected]>
>
> ---
> Changelog
> ==========
>
> v2:
> * Instead of using memblock to determine the valid bounds use pfn_valid() to do
> so since memblock may not be available late after the kernel init. [ Mpe ]
> * Changed the patch prefix from 'powerpc' to 'of' [ Mpe ]
> * Updated the 'Fixes' tag to point to correct commit that introduced this
> function. [ Rob ]
> * Fixed some whitespace/tab issues in the patch description [ Rob ]
> * Added another check for checking ig 'tmp_size' for ima-kexec-buffer is > 0
> ---
> drivers/of/kexec.c | 17 +++++++++++++++++
> 1 file changed, 17 insertions(+)
>
> diff --git a/drivers/of/kexec.c b/drivers/of/kexec.c
> index 8d374cc552be..879e984fe901 100644
> --- a/drivers/of/kexec.c
> +++ b/drivers/of/kexec.c
> @@ -126,6 +126,7 @@ int ima_get_kexec_buffer(void **addr, size_t *size)
> {
> int ret, len;
> unsigned long tmp_addr;
> + unsigned int start_pfn, end_pfn;
> size_t tmp_size;
> const void *prop;
>
> @@ -140,6 +141,22 @@ int ima_get_kexec_buffer(void **addr, size_t *size)
> if (ret)
> return ret;
>
> + /* Do some sanity on the returned size for the ima-kexec buffer */
> + if (!tmp_size)
> + return -ENOENT;
> +
> + /*
> + * Calculate the PFNs for the buffer and ensure
> + * they are with in addressable memory.
> + */
> + start_pfn = PHYS_PFN(tmp_addr);
> + end_pfn = PHYS_PFN(tmp_addr + tmp_size - 1);
> + if (!pfn_valid(start_pfn) || !pfn_valid(end_pfn)) {
pfn_valid() isn't necessarily RAM, only that you have a struct page
AIUI. Maybe page_is_ram() instead?
Thanks to Robin for this.
Rob
Thanks for looking into this patch Rob,
I have addressed your review comment in v3 of the patch posted at
https://lore.kernel.org/all/[email protected]/
<snip>
--
Cheers
~ Vaibhav