Skip to content

Commit 3e3eabe

Browse files
ardbiesheuvelIngo Molnar
authored and
Ingo Molnar
committed
x86/boot: Increase section and file alignment to 4k/512
Align x86 with other EFI architectures, and increase the section alignment to the EFI page size (4k), so that firmware is able to honour the section permission attributes and map code read-only and data non-executable. There are a number of requirements that have to be taken into account: - the sign tools get cranky when there are gaps between sections in the file view of the image - the virtual offset of each section must be aligned to the image's section alignment - the file offset *and size* of each section must be aligned to the image's file alignment - the image size must be aligned to the section alignment - each section's virtual offset must be greater than or equal to the size of the headers. In order to meet all these requirements, while avoiding the need for lots of padding to accommodate the .compat section, the latter is placed at an arbitrary offset towards the end of the image, but aligned to the minimum file alignment (512 bytes). The space before the .text section is therefore distributed between the PE header, the .setup section and the .compat section, leaving no gaps in the file coverage, making the signing tools happy. Signed-off-by: Ard Biesheuvel <ardb@kernel.org> Signed-off-by: Ingo Molnar <mingo@kernel.org> Link: https://lore.kernel.org/r/20230915171623.655440-18-ardb@google.com
1 parent 34951f3 commit 3e3eabe

File tree

4 files changed

+51
-125
lines changed

4 files changed

+51
-125
lines changed

arch/x86/boot/compressed/vmlinux.lds.S

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,13 @@ SECTIONS
4343
*(.rodata.*)
4444
_erodata = . ;
4545
}
46-
.data : {
46+
.data : ALIGN(0x1000) {
4747
_data = . ;
4848
*(.data)
4949
*(.data.*)
5050

5151
/* Add 4 bytes of extra space for a CRC-32 checksum */
52-
. = ALIGN(. + 4, 0x20);
52+
. = ALIGN(. + 4, 0x200);
5353
_edata = . ;
5454
}
5555
. = ALIGN(L1_CACHE_BYTES);

arch/x86/boot/header.S

Lines changed: 43 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ SYSSEG = 0x1000 /* historical load address >> 4 */
3636
#define ROOT_RDONLY 1
3737
#endif
3838

39+
.set salign, 0x1000
40+
.set falign, 0x200
41+
3942
.code16
4043
.section ".bstext", "ax"
4144
#ifdef CONFIG_EFI_STUB
@@ -82,7 +85,7 @@ optional_header:
8285

8386
.long setup_size + ZO_efi_pe_entry # AddressOfEntryPoint
8487

85-
.long 0x0200 # BaseOfCode
88+
.long setup_size # BaseOfCode
8689
#ifdef CONFIG_X86_32
8790
.long 0 # data
8891
#endif
@@ -93,8 +96,8 @@ extra_header_fields:
9396
#else
9497
.quad 0 # ImageBase
9598
#endif
96-
.long 0x20 # SectionAlignment
97-
.long 0x20 # FileAlignment
99+
.long salign # SectionAlignment
100+
.long falign # FileAlignment
98101
.word 0 # MajorOperatingSystemVersion
99102
.word 0 # MinorOperatingSystemVersion
100103
.word LINUX_EFISTUB_MAJOR_VERSION # MajorImageVersion
@@ -103,9 +106,10 @@ extra_header_fields:
103106
.word 0 # MinorSubsystemVersion
104107
.long 0 # Win32VersionValue
105108

106-
.long setup_size + ZO__end # SizeOfImage
109+
.long setup_size + ZO__end + pecompat_vsize
110+
# SizeOfImage
107111

108-
.long 0x200 # SizeOfHeaders
112+
.long salign # SizeOfHeaders
109113
.long 0 # CheckSum
110114
.word IMAGE_SUBSYSTEM_EFI_APPLICATION # Subsystem (EFI application)
111115
#ifdef CONFIG_EFI_DXE_MEM_ATTRIBUTES
@@ -136,44 +140,51 @@ extra_header_fields:
136140

137141
# Section table
138142
section_table:
139-
#
140-
# The offset & size fields are filled in by build.c.
141-
#
142143
.ascii ".setup"
143144
.byte 0
144145
.byte 0
145-
.long 0
146-
.long 0x0 # startup_{32,64}
147-
.long 0 # Size of initialized data
148-
# on disk
149-
.long 0x0 # startup_{32,64}
150-
.long 0 # PointerToRelocations
151-
.long 0 # PointerToLineNumbers
152-
.word 0 # NumberOfRelocations
153-
.word 0 # NumberOfLineNumbers
154-
.long IMAGE_SCN_CNT_CODE | \
146+
.long setup_size - salign # VirtualSize
147+
.long salign # VirtualAddress
148+
.long pecompat_fstart - salign # SizeOfRawData
149+
.long salign # PointerToRawData
150+
151+
.long 0, 0, 0
152+
.long IMAGE_SCN_CNT_INITIALIZED_DATA | \
155153
IMAGE_SCN_MEM_READ | \
156-
IMAGE_SCN_MEM_EXECUTE # Characteristics
154+
IMAGE_SCN_MEM_DISCARDABLE # Characteristics
157155

158156
#ifdef CONFIG_EFI_MIXED
159-
#
160-
# The offset & size fields are filled in by build.c.
161-
#
162157
.asciz ".compat"
163-
.long 0
164-
.long 0x0
165-
.long 0 # Size of initialized data
166-
# on disk
167-
.long 0x0
168-
.long 0 # PointerToRelocations
169-
.long 0 # PointerToLineNumbers
170-
.word 0 # NumberOfRelocations
171-
.word 0 # NumberOfLineNumbers
158+
159+
.long 8 # VirtualSize
160+
.long setup_size + ZO__end # VirtualAddress
161+
.long pecompat_fsize # SizeOfRawData
162+
.long pecompat_fstart # PointerToRawData
163+
164+
.long 0, 0, 0
172165
.long IMAGE_SCN_CNT_INITIALIZED_DATA | \
173166
IMAGE_SCN_MEM_READ | \
174167
IMAGE_SCN_MEM_DISCARDABLE # Characteristics
175-
#endif
176168

169+
/*
170+
* Put the IA-32 machine type and the associated entry point address in
171+
* the .compat section, so loaders can figure out which other execution
172+
* modes this image supports.
173+
*/
174+
.pushsection ".pecompat", "a", @progbits
175+
.balign falign
176+
.set pecompat_vsize, salign
177+
.globl pecompat_fstart
178+
pecompat_fstart:
179+
.byte 0x1 # Version
180+
.byte 8 # Size
181+
.word IMAGE_FILE_MACHINE_I386 # PE machine type
182+
.long setup_size + ZO_efi32_pe_entry # Entrypoint
183+
.popsection
184+
#else
185+
.set pecompat_vsize, 0
186+
.set pecompat_fstart, setup_size
187+
#endif
177188
.ascii ".text"
178189
.byte 0
179190
.byte 0

arch/x86/boot/setup.ld

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,17 @@ SECTIONS
3636
. = ALIGN(16);
3737
.data : { *(.data*) }
3838

39+
.pecompat : { *(.pecompat) }
40+
PROVIDE(pecompat_fsize = setup_size - pecompat_fstart);
41+
3942
.signature : {
4043
setup_sig = .;
4144
LONG(0x5a5aaa55)
4245

43-
/* Reserve some extra space for the compat section */
44-
setup_size = ALIGN(ABSOLUTE(.) + 32, 512);
46+
setup_size = ALIGN(ABSOLUTE(.), 4096);
4547
setup_sects = ABSOLUTE(setup_size / 512);
4648
}
4749

48-
4950
. = ALIGN(16);
5051
.bss :
5152
{

arch/x86/boot/tools/build.c

Lines changed: 2 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,6 @@ typedef unsigned int u32;
4747
/* This must be large enough to hold the entire setup */
4848
u8 buf[SETUP_SECT_MAX*512];
4949

50-
#define PECOFF_COMPAT_RESERVE 0x20
51-
52-
static unsigned long efi32_pe_entry;
5350
static unsigned long _edata;
5451

5552
/*----------------------------------------------------------------------*/
@@ -136,85 +133,6 @@ static void usage(void)
136133
die("Usage: build setup system zoffset.h image");
137134
}
138135

139-
#ifdef CONFIG_EFI_STUB
140-
141-
static void update_pecoff_section_header_fields(char *section_name, u32 vma, u32 size, u32 datasz, u32 offset)
142-
{
143-
unsigned int pe_header;
144-
unsigned short num_sections;
145-
u8 *section;
146-
147-
pe_header = get_unaligned_le32(&buf[0x3c]);
148-
num_sections = get_unaligned_le16(&buf[pe_header + 6]);
149-
150-
#ifdef CONFIG_X86_32
151-
section = &buf[pe_header + 0xa8];
152-
#else
153-
section = &buf[pe_header + 0xb8];
154-
#endif
155-
156-
while (num_sections > 0) {
157-
if (strncmp((char*)section, section_name, 8) == 0) {
158-
/* section header size field */
159-
put_unaligned_le32(size, section + 0x8);
160-
161-
/* section header vma field */
162-
put_unaligned_le32(vma, section + 0xc);
163-
164-
/* section header 'size of initialised data' field */
165-
put_unaligned_le32(datasz, section + 0x10);
166-
167-
/* section header 'file offset' field */
168-
put_unaligned_le32(offset, section + 0x14);
169-
170-
break;
171-
}
172-
section += 0x28;
173-
num_sections--;
174-
}
175-
}
176-
177-
static void update_pecoff_section_header(char *section_name, u32 offset, u32 size)
178-
{
179-
update_pecoff_section_header_fields(section_name, offset, size, size, offset);
180-
}
181-
182-
static void update_pecoff_setup(unsigned int size)
183-
{
184-
u32 setup_offset = 0x200;
185-
u32 compat_offset = size - PECOFF_COMPAT_RESERVE;
186-
u32 setup_size = compat_offset - setup_offset;
187-
188-
update_pecoff_section_header(".setup", setup_offset, setup_size);
189-
190-
#ifdef CONFIG_EFI_MIXED
191-
update_pecoff_section_header(".compat", compat_offset, PECOFF_COMPAT_RESERVE);
192-
193-
/*
194-
* Put the IA-32 machine type (0x14c) and the associated entry point
195-
* address in the .compat section, so loaders can figure out which other
196-
* execution modes this image supports.
197-
*/
198-
buf[compat_offset] = 0x1;
199-
buf[compat_offset + 1] = 0x8;
200-
put_unaligned_le16(0x14c, &buf[compat_offset + 2]);
201-
put_unaligned_le32(efi32_pe_entry + size, &buf[compat_offset + 4]);
202-
#endif
203-
}
204-
205-
#else
206-
207-
static inline void update_pecoff_setup(unsigned int size) {}
208-
209-
#endif /* CONFIG_EFI_STUB */
210-
211-
static int reserve_pecoff_compat_section(int c)
212-
{
213-
/* Reserve 0x20 bytes for .compat section */
214-
memset(buf+c, 0, PECOFF_COMPAT_RESERVE);
215-
return PECOFF_COMPAT_RESERVE;
216-
}
217-
218136
/*
219137
* Parse zoffset.h and find the entry points. We could just #include zoffset.h
220138
* but that would mean tools/build would have to be rebuilt every time. It's
@@ -243,7 +161,6 @@ static void parse_zoffset(char *fname)
243161
p = (char *)buf;
244162

245163
while (p && *p) {
246-
PARSE_ZOFS(p, efi32_pe_entry);
247164
PARSE_ZOFS(p, _edata);
248165

249166
p = strchr(p, '\n');
@@ -283,17 +200,14 @@ int main(int argc, char ** argv)
283200
die("Boot block hasn't got boot flag (0xAA55)");
284201
fclose(file);
285202

286-
c += reserve_pecoff_compat_section(c);
287-
288203
/* Pad unused space with zeros */
289-
setup_sectors = (c + 511) / 512;
204+
setup_sectors = (c + 4095) / 4096;
205+
setup_sectors *= 8;
290206
if (setup_sectors < SETUP_SECT_MIN)
291207
setup_sectors = SETUP_SECT_MIN;
292208
i = setup_sectors*512;
293209
memset(buf+c, 0, i-c);
294210

295-
update_pecoff_setup(i);
296-
297211
/* Open and stat the kernel file */
298212
fd = open(argv[2], O_RDONLY);
299213
if (fd < 0)

0 commit comments

Comments
 (0)