From 83d4c135e80862e1de9f8c0961ef24e06b5cdd22 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Mon, 30 Sep 2024 13:42:23 +0200 Subject: [PATCH 1/3] ukify: Drop unused size() method --- src/ukify/ukify.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/ukify/ukify.py b/src/ukify/ukify.py index cd1dedffca..fc391995c4 100755 --- a/src/ukify/ukify.py +++ b/src/ukify/ukify.py @@ -363,9 +363,6 @@ class Section: return cls.create(name, out, output_mode=ttype) - def size(self): - return self.content.stat().st_size - def check_name(self): # PE section names with more than 8 characters are legal, but our stub does # not support them. From 2188c759f97e40b97ebe3e94e82239f36b525b10 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Mon, 30 Sep 2024 13:42:50 +0200 Subject: [PATCH 2/3] ukify: Use SizeOfImage from linux image as virtual size of .linux section The SizeOfImage is bigger than the image itself so that space is guaranteed to be available for in place execution of the linux image. Let's make sure we take this into account and use SizeOfImage as the section's virtual size instead of the size of the image itself. Fixes #34578 --- src/ukify/ukify.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/ukify/ukify.py b/src/ukify/ukify.py index fc391995c4..86117cd563 100755 --- a/src/ukify/ukify.py +++ b/src/ukify/ukify.py @@ -323,6 +323,7 @@ class Section: tmpfile: Optional[IO] = None measure: bool = False output_mode: Optional[str] = None + virtual_size: Optional[int] = None @classmethod def create(cls, name, contents, **kwargs): @@ -709,7 +710,10 @@ def pe_add_sections(uki: UKI, output: str): new_section.set_file_offset(offset) new_section.Name = section.name.encode() - new_section.Misc_VirtualSize = len(data) + if section.virtual_size is not None: + new_section.Misc_VirtualSize = section.virtual_size + else: + new_section.Misc_VirtualSize = len(data) # Non-stripped stubs might still have an unaligned symbol table at the end, making their size # unaligned, so we make sure to explicitly pad the pointer to new sections to an aligned offset. new_section.PointerToRawData = round_up(len(pe.__data__), pe.OPTIONAL_HEADER.FileAlignment) @@ -988,7 +992,13 @@ uki-addon,1,UKI Addon,addon,1,https://www.freedesktop.org/software/systemd/man/l # UKI creation if linux is not None: - uki.add_section(Section.create('.linux', linux, measure=True)) + try: + virtual_size = pefile.PE(linux, fast_load=True).OPTIONAL_HEADER.SizeOfImage + except pefile.PEFormatError: + print(f"{f} is not a valid PE file, not using SizeOfImage.") + virtual_size = None + + uki.add_section(Section.create('.linux', linux, measure=True, virtual_size=virtual_size)) if sign_args_present: unsigned = tempfile.NamedTemporaryFile(prefix='uki') From 7af304d3b6c8a20020cb00f1399612c5281cc2e3 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Mon, 30 Sep 2024 13:50:27 +0200 Subject: [PATCH 3/3] ukify: Remove special casing for .linux section Now that we properly leave sufficient space for inline execution of the .linux section, let's remove the special casing of the .linux section as it doesn't need to be the last section anymore now. --- src/ukify/ukify.py | 32 +++++++++++--------------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/src/ukify/ukify.py b/src/ukify/ukify.py index 86117cd563..55c40164ae 100755 --- a/src/ukify/ukify.py +++ b/src/ukify/ukify.py @@ -502,7 +502,7 @@ def pe_strip_section_name(name): return name.rstrip(b"\x00").decode() -def call_systemd_measure(uki, linux, opts): +def call_systemd_measure(uki, opts): if not opts.measure and not opts.pcr_private_keys: return @@ -528,14 +528,10 @@ def call_systemd_measure(uki, linux, opts): continue if s.content is not None: - assert(s.name != ".linux" or linux is None) to_measure.append(f"--{s.name.removeprefix('.')}={s.content}") else: raise ValueError(f"Don't know how to measure section {s.name}"); - if linux is not None: - to_measure.append(f'--linux={linux}') - # And now iterate through the base profile and measure what we haven't measured above if opts.measure_base is not None: pe = pefile.PE(opts.measure_base, fast_load=True) @@ -952,9 +948,6 @@ def make_uki(opts): ('.pcrpkey', pcrpkey, True ), ('.initrd', initrd, True ), ('.ucode', opts.microcode, True ), - - # linux shall be last to leave breathing room for decompression. - # We'll add it later. ] for name, content, measure in sections: @@ -965,6 +958,15 @@ def make_uki(opts): for section in opts.sections: uki.add_section(section) + if linux is not None: + try: + virtual_size = pefile.PE(linux, fast_load=True).OPTIONAL_HEADER.SizeOfImage + except pefile.PEFormatError: + print(f"{linux} is not a valid PE file, not using SizeOfImage.") + virtual_size = None + + uki.add_section(Section.create('.linux', linux, measure=True, virtual_size=virtual_size)) + if opts.extend is None: if linux is not None: # Merge the .sbat sections from stub, kernel and parameter, so that revocation can be done on either. @@ -984,22 +986,10 @@ uki-addon,1,UKI Addon,addon,1,https://www.freedesktop.org/software/systemd/man/l # PCR measurement and signing - # We pass in the contents for .linux separately because we need them to do the measurement but can't add - # the section yet because we want .linux to be the last section. Make sure any other sections are added - # before this function is called. - call_systemd_measure(uki, linux, opts=opts) + call_systemd_measure(uki, opts=opts) # UKI creation - if linux is not None: - try: - virtual_size = pefile.PE(linux, fast_load=True).OPTIONAL_HEADER.SizeOfImage - except pefile.PEFormatError: - print(f"{f} is not a valid PE file, not using SizeOfImage.") - virtual_size = None - - uki.add_section(Section.create('.linux', linux, measure=True, virtual_size=virtual_size)) - if sign_args_present: unsigned = tempfile.NamedTemporaryFile(prefix='uki') unsigned_output = unsigned.name