From: Daan De Meyer Date: Tue, 28 Jan 2025 08:38:26 +0000 (+0100) Subject: ukify: Add --sign-profile X-Git-Tag: v258-rc1~1463 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=b61efe6591944d05adfb1c5e567454096b6da2f0;p=thirdparty%2Fsystemd.git ukify: Add --sign-profile Let's allow configuring which UKI profiles we generate signed PCR measurements for since there are various types of profiles for which we do not want to generate signed PCR measurements so that they can not unlock the encrypted rootfs. Fixes #36173. --- diff --git a/man/ukify.xml b/man/ukify.xml index 0a0ee4390c8..d6a46bc8438 100644 --- a/man/ukify.xml +++ b/man/ukify.xml @@ -258,6 +258,17 @@ + + + + Takes a profile ID for which signed PCR measurements should be generated by ukify. + This option can be used together with when building the final + unified kernel image. If not specified, signed PCR measurements will be added for all profiles. + + + + + diff --git a/src/ukify/ukify.py b/src/ukify/ukify.py index 5b4f20aeda5..5f821297c12 100755 --- a/src/ukify/ukify.py +++ b/src/ukify/ukify.py @@ -141,6 +141,25 @@ def try_import(modname: str, name: Optional[str] = None) -> ModuleType: raise ValueError(f'Kernel is compressed with {name or modname}, but module unavailable') from e +def read_env_file(text: str) -> dict[str, str]: + result = {} + + for line in text.splitlines(): + line = line.rstrip() + if not line or line.startswith('#'): + continue + if m := re.match(r'([A-Z][A-Z_0-9]+)=(.*)', line): + name, val = m.groups() + if val and val[0] in '"\'': + val = next(shlex.shlex(val, posix=True)) + + result[name] = val + else: + print(f'bad line {line!r}', file=sys.stderr) + + return result + + def get_zboot_kernel(f: IO[bytes]) -> bytes: """Decompress zboot efistub kernel if compressed. Return contents.""" # See linux/drivers/firmware/efi/libstub/Makefile.zboot @@ -244,6 +263,7 @@ class UkifyConfig: hwids: Path initrd: list[Path] join_profiles: list[Path] + sign_profiles: list[str] json: Union[Literal['pretty'], Literal['short'], Literal['off']] linux: Optional[Path] measure: bool @@ -1249,7 +1269,10 @@ def make_uki(opts: UkifyConfig) -> None: # PCR measurement and signing - call_systemd_measure(uki, opts=opts) + if (opts.join_profiles or not opts.profile) and ( + not opts.sign_profiles or opts.profile in opts.sign_profiles + ): + call_systemd_measure(uki, opts=opts) # UKI profiles @@ -1298,6 +1321,13 @@ def make_uki(opts: UkifyConfig) -> None: Section.create(n, pesection.get_data(length=pesection.Misc_VirtualSize), measure=True) ) + if opts.sign_profiles: + pesection = next(s for s in pe.sections if pe_strip_section_name(s.Name) == '.profile') + id = read_env_file(pesection.get_data(length=pesection.Misc_VirtualSize).decode()).get('ID') + if not id or id not in opts.sign_profiles: + print(f'Not signing expected PCR measurements for "{id}" profile') + continue + call_systemd_measure(uki, opts=opts, profile_start=prev_len) # UKI creation @@ -1807,6 +1837,14 @@ CONFIG_ITEMS = [ default=[], help='A PE binary containing an additional profile to add to the UKI', ), + ConfigItem( + '--sign-profile', + dest='sign_profiles', + metavar='ID', + action='append', + default=[], + help='Which profiles to sign expected PCR measurements for', + ), ConfigItem( '--efi-arch', metavar='ARCH',