]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
ukify: Add --sign-profile
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Tue, 28 Jan 2025 08:38:26 +0000 (09:38 +0100)
committerLuca Boccassi <luca.boccassi@gmail.com>
Tue, 28 Jan 2025 17:20:46 +0000 (17:20 +0000)
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.

man/ukify.xml
src/ukify/ukify.py

index 0a0ee4390c88341b1f483214acb30943df7cf975..d6a46bc8438b7b7cfdad7a09ce9d360b9c3397e4 100644 (file)
           <xi:include href="version-info.xml" xpointer="v257"/></listitem>
         </varlistentry>
 
+        <varlistentry>
+          <term><option>--sign-profile=<replaceable>ID</replaceable></option></term>
+
+          <listitem><para>Takes a profile ID for which signed PCR measurements should be generated by ukify.
+          This option can be used together with <option>--join-profile=</option> when building the final
+          unified kernel image. If not specified, signed PCR measurements will be added for all profiles.
+          </para>
+
+          <xi:include href="version-info.xml" xpointer="v258"/></listitem>
+        </varlistentry>
+
         <varlistentry>
           <term><option>--tools=<replaceable>DIRS</replaceable></option></term>
 
index 5b4f20aeda5b8a8b456a79e8bd3c5b812f6a6adc..5f821297c128516d2764d7d286a90a037668a1d8 100755 (executable)
@@ -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',