diff mbox series

[v8,01/15] x86/boot: Place kernel_info at a fixed offset

Message ID 20240214221847.2066632-2-ross.philipson@oracle.com (mailing list archive)
State New
Headers show
Series x86: Trenchboot secure dynamic launch Linux kernel support | expand

Commit Message

Ross Philipson Feb. 14, 2024, 10:18 p.m. UTC
From: Arvind Sankar <nivedita@alum.mit.edu>

There are use cases for storing the offset of a symbol in kernel_info.
For example, the trenchboot series [0] needs to store the offset of the
Measured Launch Environment header in kernel_info.

Since commit (note: commit ID from tip/master)

commit 527afc212231 ("x86/boot: Check that there are no run-time relocations")

run-time relocations are not allowed in the compressed kernel, so simply
using the symbol in kernel_info, as

	.long	symbol

will cause a linker error because this is not position-independent.

With kernel_info being a separate object file and in a different section
from startup_32, there is no way to calculate the offset of a symbol
from the start of the image in a position-independent way.

To enable such use cases, put kernel_info into its own section which is
placed at a predetermined offset (KERNEL_INFO_OFFSET) via the linker
script. This will allow calculating the symbol offset in a
position-independent way, by adding the offset from the start of
kernel_info to KERNEL_INFO_OFFSET.

Ensure that kernel_info is aligned, and use the SYM_DATA.* macros
instead of bare labels. This stores the size of the kernel_info
structure in the ELF symbol table.

Signed-off-by: Arvind Sankar <nivedita@alum.mit.edu>
Cc: Ross Philipson <ross.philipson@oracle.com>
Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
---
 arch/x86/boot/compressed/kernel_info.S | 19 +++++++++++++++----
 arch/x86/boot/compressed/kernel_info.h | 12 ++++++++++++
 arch/x86/boot/compressed/vmlinux.lds.S |  6 ++++++
 3 files changed, 33 insertions(+), 4 deletions(-)
 create mode 100644 arch/x86/boot/compressed/kernel_info.h

Comments

Ard Biesheuvel Feb. 15, 2024, 7:56 a.m. UTC | #1
On Wed, 14 Feb 2024 at 23:31, Ross Philipson <ross.philipson@oracle.com> wrote:
>
> From: Arvind Sankar <nivedita@alum.mit.edu>
>
> There are use cases for storing the offset of a symbol in kernel_info.
> For example, the trenchboot series [0] needs to store the offset of the
> Measured Launch Environment header in kernel_info.
>

Why? Is this information consumed by the bootloader?

I'd like to get away from x86 specific hacks for boot code and boot
images, so I would like to explore if we can avoid kernel_info, or at
least expose it in a generic way. We might just add a 32-bit offset
somewhere in the first 64 bytes of the bootable image: this could
co-exist with EFI bootable images, and can be implemented on arm64,
RISC-V and LoongArch as well.

> Since commit (note: commit ID from tip/master)
>
> commit 527afc212231 ("x86/boot: Check that there are no run-time relocations")
>
> run-time relocations are not allowed in the compressed kernel, so simply
> using the symbol in kernel_info, as
>
>         .long   symbol
>
> will cause a linker error because this is not position-independent.
>
> With kernel_info being a separate object file and in a different section
> from startup_32, there is no way to calculate the offset of a symbol
> from the start of the image in a position-independent way.
>
> To enable such use cases, put kernel_info into its own section which is
> placed at a predetermined offset (KERNEL_INFO_OFFSET) via the linker
> script. This will allow calculating the symbol offset in a
> position-independent way, by adding the offset from the start of
> kernel_info to KERNEL_INFO_OFFSET.
>
> Ensure that kernel_info is aligned, and use the SYM_DATA.* macros
> instead of bare labels. This stores the size of the kernel_info
> structure in the ELF symbol table.
>
> Signed-off-by: Arvind Sankar <nivedita@alum.mit.edu>
> Cc: Ross Philipson <ross.philipson@oracle.com>
> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
> ---
>  arch/x86/boot/compressed/kernel_info.S | 19 +++++++++++++++----
>  arch/x86/boot/compressed/kernel_info.h | 12 ++++++++++++
>  arch/x86/boot/compressed/vmlinux.lds.S |  6 ++++++
>  3 files changed, 33 insertions(+), 4 deletions(-)
>  create mode 100644 arch/x86/boot/compressed/kernel_info.h
>
> diff --git a/arch/x86/boot/compressed/kernel_info.S b/arch/x86/boot/compressed/kernel_info.S
> index f818ee8fba38..c18f07181dd5 100644
> --- a/arch/x86/boot/compressed/kernel_info.S
> +++ b/arch/x86/boot/compressed/kernel_info.S
> @@ -1,12 +1,23 @@
>  /* SPDX-License-Identifier: GPL-2.0 */
>
> +#include <linux/linkage.h>
>  #include <asm/bootparam.h>
> +#include "kernel_info.h"
>
> -       .section ".rodata.kernel_info", "a"
> +/*
> + * If a field needs to hold the offset of a symbol from the start
> + * of the image, use the macro below, eg
> + *     .long   rva(symbol)
> + * This will avoid creating run-time relocations, which are not
> + * allowed in the compressed kernel.
> + */
> +
> +#define rva(X) (((X) - kernel_info) + KERNEL_INFO_OFFSET)
>
> -       .global kernel_info
> +       .section ".rodata.kernel_info", "a"
>
> -kernel_info:
> +       .balign 16
> +SYM_DATA_START(kernel_info)
>         /* Header, Linux top (structure). */
>         .ascii  "LToP"
>         /* Size. */
> @@ -19,4 +30,4 @@ kernel_info:
>
>  kernel_info_var_len_data:
>         /* Empty for time being... */
> -kernel_info_end:
> +SYM_DATA_END_LABEL(kernel_info, SYM_L_LOCAL, kernel_info_end)
> diff --git a/arch/x86/boot/compressed/kernel_info.h b/arch/x86/boot/compressed/kernel_info.h
> new file mode 100644
> index 000000000000..c127f84aec63
> --- /dev/null
> +++ b/arch/x86/boot/compressed/kernel_info.h
> @@ -0,0 +1,12 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +
> +#ifndef BOOT_COMPRESSED_KERNEL_INFO_H
> +#define BOOT_COMPRESSED_KERNEL_INFO_H
> +
> +#ifdef CONFIG_X86_64
> +#define KERNEL_INFO_OFFSET 0x500
> +#else /* 32-bit */
> +#define KERNEL_INFO_OFFSET 0x100
> +#endif
> +
> +#endif /* BOOT_COMPRESSED_KERNEL_INFO_H */
> diff --git a/arch/x86/boot/compressed/vmlinux.lds.S b/arch/x86/boot/compressed/vmlinux.lds.S
> index 083ec6d7722a..718c52f3f1e6 100644
> --- a/arch/x86/boot/compressed/vmlinux.lds.S
> +++ b/arch/x86/boot/compressed/vmlinux.lds.S
> @@ -7,6 +7,7 @@ OUTPUT_FORMAT(CONFIG_OUTPUT_FORMAT)
>
>  #include <asm/cache.h>
>  #include <asm/page_types.h>
> +#include "kernel_info.h"
>
>  #ifdef CONFIG_X86_64
>  OUTPUT_ARCH(i386:x86-64)
> @@ -27,6 +28,11 @@ SECTIONS
>                 HEAD_TEXT
>                 _ehead = . ;
>         }
> +       .rodata.kernel_info KERNEL_INFO_OFFSET : {
> +               *(.rodata.kernel_info)
> +       }
> +       ASSERT(ABSOLUTE(kernel_info) == KERNEL_INFO_OFFSET, "kernel_info at bad address!")
> +
>         .rodata..compressed : {
>                 *(.rodata..compressed)
>         }
> --
> 2.39.3
>
Daniel Kiper Feb. 15, 2024, 10:56 a.m. UTC | #2
On Thu, Feb 15, 2024 at 08:56:25AM +0100, Ard Biesheuvel wrote:
> On Wed, 14 Feb 2024 at 23:31, Ross Philipson <ross.philipson@oracle.com> wrote:
> >
> > From: Arvind Sankar <nivedita@alum.mit.edu>
> >
> > There are use cases for storing the offset of a symbol in kernel_info.
> > For example, the trenchboot series [0] needs to store the offset of the
> > Measured Launch Environment header in kernel_info.
> >
>
> Why? Is this information consumed by the bootloader?

The bootloader stuffs this info, plus some offset IIRC, into special structure
and finally it is consumed by SINIT ACM after GETSEC[SENTER] call.

Sadly this data is Intel specific and it is even not compatible with AMD.
So, if I am not mistaken, we will need additional member for the AMD in
the kernel_info.

> I'd like to get away from x86 specific hacks for boot code and boot
> images, so I would like to explore if we can avoid kernel_info, or at
> least expose it in a generic way. We might just add a 32-bit offset
> somewhere in the first 64 bytes of the bootable image: this could
> co-exist with EFI bootable images, and can be implemented on arm64,
> RISC-V and LoongArch as well.

The other architectures may or may not have need for such data due to
differences in DRTM implementation. Anyway, whatever we do I want to
be sure the DRTM can be used on UEFI and non-UEFI platforms. So, I am
not entirely convinced the address/pointer to additional DRTM data
should be part of the MS-DOS and/or PE header. Though I am not against
building something generic shared among various architectures either.

Daniel
Daniel P. Smith March 21, 2024, 1:45 p.m. UTC | #3
Hi Ard!

On 2/15/24 02:56, Ard Biesheuvel wrote:
> On Wed, 14 Feb 2024 at 23:31, Ross Philipson <ross.philipson@oracle.com> wrote:
>>
>> From: Arvind Sankar <nivedita@alum.mit.edu>
>>
>> There are use cases for storing the offset of a symbol in kernel_info.
>> For example, the trenchboot series [0] needs to store the offset of the
>> Measured Launch Environment header in kernel_info.
>>
> 
> Why? Is this information consumed by the bootloader?

Yes, the bootloader needs a standardized means to find the offset of the 
MLE header, which communicates a set of meta-data needed by the DCE in 
order to set up for and start the loaded kernel. Arm will also need to 
provide a similar metadata structure and alternative entry point (or a 
complete rewrite of the existing entry point), as the current Arm entry 
point is in direct conflict with Arm DRTM specification.

> I'd like to get away from x86 specific hacks for boot code and boot
> images, so I would like to explore if we can avoid kernel_info, or at
> least expose it in a generic way. We might just add a 32-bit offset
> somewhere in the first 64 bytes of the bootable image: this could
> co-exist with EFI bootable images, and can be implemented on arm64,
> RISC-V and LoongArch as well.

With all due respect, I would not refer to boot params and the kern_info 
extension designed by the x86 maintainers as a hack. It is the 
well-defined boot protocol for x86, just as Arm has its own boot 
protocol around Device Tree.

We would gladly adopt a cross arch/cross image type, zImage and bzImage, 
means to embedded meta-data about the kernel that can be discovered by a 
bootloader. Otherwise, we are relegated to doing a per arch/per image 
type discovery mechanism. If you have any suggestions that are cross 
arch/cross image type that we could explore, we would be grateful and 
willing to investigate how to adopt such a method.

V/r,
Daniel
H. Peter Anvin March 22, 2024, 2:18 p.m. UTC | #4
On March 21, 2024 6:45:48 AM PDT, "Daniel P. Smith" <dpsmith@apertussolutions.com> wrote:
>Hi Ard!
>
>On 2/15/24 02:56, Ard Biesheuvel wrote:
>> On Wed, 14 Feb 2024 at 23:31, Ross Philipson <ross.philipson@oracle.com> wrote:
>>> 
>>> From: Arvind Sankar <nivedita@alum.mit.edu>
>>> 
>>> There are use cases for storing the offset of a symbol in kernel_info.
>>> For example, the trenchboot series [0] needs to store the offset of the
>>> Measured Launch Environment header in kernel_info.
>>> 
>> 
>> Why? Is this information consumed by the bootloader?
>
>Yes, the bootloader needs a standardized means to find the offset of the MLE header, which communicates a set of meta-data needed by the DCE in order to set up for and start the loaded kernel. Arm will also need to provide a similar metadata structure and alternative entry point (or a complete rewrite of the existing entry point), as the current Arm entry point is in direct conflict with Arm DRTM specification.
>
>> I'd like to get away from x86 specific hacks for boot code and boot
>> images, so I would like to explore if we can avoid kernel_info, or at
>> least expose it in a generic way. We might just add a 32-bit offset
>> somewhere in the first 64 bytes of the bootable image: this could
>> co-exist with EFI bootable images, and can be implemented on arm64,
>> RISC-V and LoongArch as well.
>
>With all due respect, I would not refer to boot params and the kern_info extension designed by the x86 maintainers as a hack. It is the well-defined boot protocol for x86, just as Arm has its own boot protocol around Device Tree.
>
>We would gladly adopt a cross arch/cross image type, zImage and bzImage, means to embedded meta-data about the kernel that can be discovered by a bootloader. Otherwise, we are relegated to doing a per arch/per image type discovery mechanism. If you have any suggestions that are cross arch/cross image type that we could explore, we would be grateful and willing to investigate how to adopt such a method.
>
>V/r,
>Daniel

To be fair, the way things are going UEFI, i.e. PE/COFF, is becoming the new standard format. Yes, ELF would have been better, but...
Daniel P. Smith March 23, 2024, 1:33 a.m. UTC | #5
On 3/22/24 10:18, H. Peter Anvin wrote:
> On March 21, 2024 6:45:48 AM PDT, "Daniel P. Smith" <dpsmith@apertussolutions.com> wrote:
>> Hi Ard!
>>
>> On 2/15/24 02:56, Ard Biesheuvel wrote:
>>> On Wed, 14 Feb 2024 at 23:31, Ross Philipson <ross.philipson@oracle.com> wrote:
>>>>
>>>> From: Arvind Sankar <nivedita@alum.mit.edu>
>>>>
>>>> There are use cases for storing the offset of a symbol in kernel_info.
>>>> For example, the trenchboot series [0] needs to store the offset of the
>>>> Measured Launch Environment header in kernel_info.
>>>>
>>>
>>> Why? Is this information consumed by the bootloader?
>>
>> Yes, the bootloader needs a standardized means to find the offset of the MLE header, which communicates a set of meta-data needed by the DCE in order to set up for and start the loaded kernel. Arm will also need to provide a similar metadata structure and alternative entry point (or a complete rewrite of the existing entry point), as the current Arm entry point is in direct conflict with Arm DRTM specification.
>>
>>> I'd like to get away from x86 specific hacks for boot code and boot
>>> images, so I would like to explore if we can avoid kernel_info, or at
>>> least expose it in a generic way. We might just add a 32-bit offset
>>> somewhere in the first 64 bytes of the bootable image: this could
>>> co-exist with EFI bootable images, and can be implemented on arm64,
>>> RISC-V and LoongArch as well.
>>
>> With all due respect, I would not refer to boot params and the kern_info extension designed by the x86 maintainers as a hack. It is the well-defined boot protocol for x86, just as Arm has its own boot protocol around Device Tree.
>>
>> We would gladly adopt a cross arch/cross image type, zImage and bzImage, means to embedded meta-data about the kernel that can be discovered by a bootloader. Otherwise, we are relegated to doing a per arch/per image type discovery mechanism. If you have any suggestions that are cross arch/cross image type that we could explore, we would be grateful and willing to investigate how to adopt such a method.
>>
>> V/r,
>> Daniel
> 
> To be fair, the way things are going UEFI, i.e. PE/COFF, is becoming the new standard format. Yes, ELF would have been better, but...

Fully agree with the ELF sentiment. We started looking to see if PE/COFF 
has something similar to a ELF NOTE, but figured maybe this has been 
solved for other cases. If that is not the case or there are not any 
suggestions, then we can see what we can devise.
diff mbox series

Patch

diff --git a/arch/x86/boot/compressed/kernel_info.S b/arch/x86/boot/compressed/kernel_info.S
index f818ee8fba38..c18f07181dd5 100644
--- a/arch/x86/boot/compressed/kernel_info.S
+++ b/arch/x86/boot/compressed/kernel_info.S
@@ -1,12 +1,23 @@ 
 /* SPDX-License-Identifier: GPL-2.0 */
 
+#include <linux/linkage.h>
 #include <asm/bootparam.h>
+#include "kernel_info.h"
 
-	.section ".rodata.kernel_info", "a"
+/*
+ * If a field needs to hold the offset of a symbol from the start
+ * of the image, use the macro below, eg
+ *	.long	rva(symbol)
+ * This will avoid creating run-time relocations, which are not
+ * allowed in the compressed kernel.
+ */
+
+#define rva(X) (((X) - kernel_info) + KERNEL_INFO_OFFSET)
 
-	.global kernel_info
+	.section ".rodata.kernel_info", "a"
 
-kernel_info:
+	.balign	16
+SYM_DATA_START(kernel_info)
 	/* Header, Linux top (structure). */
 	.ascii	"LToP"
 	/* Size. */
@@ -19,4 +30,4 @@  kernel_info:
 
 kernel_info_var_len_data:
 	/* Empty for time being... */
-kernel_info_end:
+SYM_DATA_END_LABEL(kernel_info, SYM_L_LOCAL, kernel_info_end)
diff --git a/arch/x86/boot/compressed/kernel_info.h b/arch/x86/boot/compressed/kernel_info.h
new file mode 100644
index 000000000000..c127f84aec63
--- /dev/null
+++ b/arch/x86/boot/compressed/kernel_info.h
@@ -0,0 +1,12 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef BOOT_COMPRESSED_KERNEL_INFO_H
+#define BOOT_COMPRESSED_KERNEL_INFO_H
+
+#ifdef CONFIG_X86_64
+#define KERNEL_INFO_OFFSET 0x500
+#else /* 32-bit */
+#define KERNEL_INFO_OFFSET 0x100
+#endif
+
+#endif /* BOOT_COMPRESSED_KERNEL_INFO_H */
diff --git a/arch/x86/boot/compressed/vmlinux.lds.S b/arch/x86/boot/compressed/vmlinux.lds.S
index 083ec6d7722a..718c52f3f1e6 100644
--- a/arch/x86/boot/compressed/vmlinux.lds.S
+++ b/arch/x86/boot/compressed/vmlinux.lds.S
@@ -7,6 +7,7 @@  OUTPUT_FORMAT(CONFIG_OUTPUT_FORMAT)
 
 #include <asm/cache.h>
 #include <asm/page_types.h>
+#include "kernel_info.h"
 
 #ifdef CONFIG_X86_64
 OUTPUT_ARCH(i386:x86-64)
@@ -27,6 +28,11 @@  SECTIONS
 		HEAD_TEXT
 		_ehead = . ;
 	}
+	.rodata.kernel_info KERNEL_INFO_OFFSET : {
+		*(.rodata.kernel_info)
+	}
+	ASSERT(ABSOLUTE(kernel_info) == KERNEL_INFO_OFFSET, "kernel_info at bad address!")
+
 	.rodata..compressed : {
 		*(.rodata..compressed)
 	}