]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
stub: add support for dtb addons
authorLuca Boccassi <bluca@debian.org>
Mon, 7 Aug 2023 00:05:18 +0000 (01:05 +0100)
committerLuca Boccassi <bluca@debian.org>
Mon, 9 Oct 2023 21:22:09 +0000 (22:22 +0100)
Same as kernel command line addons.

docs/TPM2_PCR_MEASUREMENTS.md
man/systemd-stub.xml
src/boot/bootctl-status.c
src/boot/efi/stub.c
src/fundamental/efivars-fundamental.h

index dffe2baaa02ac6e7153c8202818abb59cc8a0f0d..f2893f1344542a8f53d8c5801b50bf35b5af0b9e 100644 (file)
@@ -90,6 +90,16 @@ UTF-16.
 → **Measured hash** covers the literal kernel command line in UTF-16 (without any
 trailing NUL bytes).
 
+### PCR 12, `EV_EVENT_TAG`, "Devicetrees"
+
+Devicetree addons are measured individually as a tagged event.
+
+→ **Event Tag** `0x6c46f751`
+
+→ **Description** the addon filename.
+
+→ **Measured hash** covers the content of the Devicetree.
+
 ### PCR 12, `EV_IPL`, "Per-UKI Credentials initrd"
 
 → **Description** in the event log record is the constant string "Credentials
index 1173db572b50afe5796a2a88b92893eeca72cd7e..5650c53f0218b15ff92e176d07b42f9786c2d017 100644 (file)
       <citerefentry><refentrytitle>ukify</refentrytitle><manvolnum>1</manvolnum></citerefentry> tool will
       add a SBAT policy by default if none is passed when building addons. For more information on SBAT see
       <ulink url="https://github.com/rhboot/shim/blob/main/SBAT.md">Shim's documentation</ulink>.
-      Addons are supposed to be used to pass additional kernel command line parameters, regardless of the
-      kernel image being booted, for example to allow platform vendors to ship platform-specific
-      configuration. The loaded command line addon files are sorted, loaded, measured into TPM PCR 12 (if a
-      TPM is present) and appended to the kernel command line. UKI command line options are listed first,
-      then options from addons in <filename>/loader/addons/*.addon.efi</filename> are appended next, and
-      finally UKI-specific addons are appended last. Addons are always loaded in the same order based on the
-      filename, so that, given the same set of addons, the same set of measurements can be expected in
-      PCR12, however note that the filename is not protected by the PE signature, and as such an attacker
-      with write access to the ESP could potentially rename these files to change the order in which they
-      are loaded, in a way that could alter the functionality of the kernel, as some options might be order
-      dependent. If you sign such addons, you should pay attention to the PCR12 values and make use of an
-      attestation service so that improper use of your signed addons can be detected and dealt with using
-      one of the aforementioned revocation mechanisms.</para></listitem>
+      Addons are supposed to be used to pass additional kernel command line parameters or Devicetree blobs,
+      regardless of the kernel image being booted, for example to allow platform vendors to ship
+      platform-specific configuration. The loaded command line addon files are sorted, loaded, and measured
+      into TPM PCR 12 (if a TPM is present) and appended to the kernel command line. UKI command line options
+      are listed first, then options from addons in <filename>/loader/addons/*.addon.efi</filename>, and
+      finally UKI-specific addons. Device tree blobs are loaded and measured following the same algorithm.
+      Addons are always loaded in the same order based on the filename, so that, given the same set of
+      addons, the same set of measurements can be expected in PCR12. However, note that the filename is not
+      protected by the PE signature, and as such an attacker with write access to the ESP could potentially
+      rename these files to change the order in which they are loaded, in a way that could alter the
+      functionality of the kernel, as some options might be order dependent. If you sign such addons, you
+      should pay attention to the PCR12 values and make use of an attestation service so that improper use
+      of your signed addons can be detected and dealt with using one of the aforementioned revocation
+      mechanisms.</para></listitem>
 
       <listitem><para>Files <filename>/loader/credentials/*.cred</filename> are packed up in a
       <command>cpio</command> archive and placed in the <filename>/.extra/global_credentials/</filename>
       measured into TPM PCR 12 (if a TPM is present).</para></listitem>
 
       <listitem><para>Additionally, files <filename>/loader/addons/*.addon.efi</filename> are loaded and
-      verified as PE binaries, and a <literal>.cmdline</literal> section is parsed from them. This is
-      supposed to be used to pass additional command line parameters to the kernel, regardless of the kernel
-      being booted.</para></listitem>
+      verified as PE binaries, and <literal>.cmdline</literal> and/or <literal>.dtb</literal> sections are
+      parsed from them. This is supposed to be used to pass additional command line parameters or Devicetree
+      blobs to the kernel, regardless of the kernel being booted.</para></listitem>
     </itemizedlist>
 
     <para>These mechanisms may be used to parameterize and extend trusted (i.e. signed), immutable initrd
index 033abb056657ad46866c68c520830a36ed798f79..a1fe3364331b93216a6d6ea5b0851ee164e2e1f3 100644 (file)
@@ -384,6 +384,7 @@ int verb_status(int argc, char *argv[], void *userdata) {
                         { EFI_STUB_FEATURE_RANDOM_SEED,               "Support for passing random seed to OS"                },
                         { EFI_STUB_FEATURE_CMDLINE_ADDONS,            "Pick up .cmdline from addons"                         },
                         { EFI_STUB_FEATURE_CMDLINE_SMBIOS,            "Pick up .cmdline from SMBIOS Type 11"                 },
+                        { EFI_STUB_FEATURE_DEVICETREE_ADDONS,         "Pick up .dtb from addons"                             },
                 };
                 _cleanup_free_ char *fw_type = NULL, *fw_info = NULL, *loader = NULL, *loader_path = NULL, *stub = NULL;
                 sd_id128_t loader_part_uuid = SD_ID128_NULL;
index 0f30f13d9215f7fdca43e585738d8553348001fb..dd3d017cce89351333f4090d960379a4a3788804 100644 (file)
@@ -26,6 +26,8 @@ DECLARE_NOALLOC_SECTION(".sdmagic", "#### LoaderInfo: systemd-stub " GIT_VERSION
 
 DECLARE_SBAT(SBAT_STUB_SECTION_TEXT);
 
+#define ADDON_FILENAME_EVENT_TAG_ID UINT32_C(0x6c46f751)
+
 static EFI_STATUS combine_initrd(
                 EFI_PHYSICAL_ADDRESS initrd_base, size_t initrd_size,
                 const void * const extra_initrds[], const size_t extra_initrd_sizes[], size_t n_extra_initrds,
@@ -95,6 +97,7 @@ static void export_variables(EFI_LOADED_IMAGE_PROTOCOL *loaded_image) {
                 EFI_STUB_FEATURE_RANDOM_SEED |              /* We pass a random seed to the kernel */
                 EFI_STUB_FEATURE_CMDLINE_ADDONS |           /* We pick up .cmdline addons */
                 EFI_STUB_FEATURE_CMDLINE_SMBIOS |           /* We support extending kernel cmdline from SMBIOS Type #11 */
+                EFI_STUB_FEATURE_DEVICETREE_ADDONS |        /* We pick up .dtb addons */
                 0;
 
         assert(loaded_image);
@@ -253,29 +256,123 @@ static EFI_STATUS load_addons_from_dir(
         return EFI_SUCCESS;
 }
 
-static EFI_STATUS cmdline_append_and_measure_addons(
+static void cmdline_append_and_measure_addons(
+                char16_t *cmdline,
+                char16_t **cmdline_append,
+                bool *ret_parameters_measured) {
+
+        _cleanup_free_ char16_t *tmp = NULL;
+        bool m = false;
+
+        assert(cmdline_append);
+        assert(ret_parameters_measured);
+
+        mangle_stub_cmdline(cmdline);
+
+        if (isempty(cmdline))
+                return;
+
+        (void) tpm_log_load_options(cmdline, &m);
+        *ret_parameters_measured = m;
+
+        tmp = TAKE_PTR(*cmdline_append);
+        *cmdline_append = xasprintf("%ls%ls%ls", strempty(tmp), isempty(tmp) ? u"" : u" ", cmdline);
+}
+
+static void dtb_install_addons(
+                struct devicetree_state *dt_state,
+                void **dt_bases,
+                size_t *dt_sizes,
+                char16_t **dt_filenames,
+                size_t n_dts,
+                bool *ret_parameters_measured) {
+
+        int parameters_measured = -1;
+        EFI_STATUS err;
+
+        assert(dt_state);
+        assert(n_dts == 0 || (dt_bases && dt_sizes && dt_filenames));
+        assert(ret_parameters_measured);
+
+        for (size_t i = 0; i < n_dts; ++i) {
+                err = devicetree_install_from_memory(dt_state, dt_bases[i], dt_sizes[i]);
+                if (err != EFI_SUCCESS)
+                        log_error_status(err, "Error loading addon devicetree, ignoring: %m");
+                else {
+                        bool m = false;
+
+                        err = tpm_log_tagged_event(
+                                        TPM2_PCR_KERNEL_CONFIG,
+                                        POINTER_TO_PHYSICAL_ADDRESS(dt_bases[i]),
+                                        dt_sizes[i],
+                                        ADDON_FILENAME_EVENT_TAG_ID,
+                                        dt_filenames[i],
+                                        &m);
+                        if (err != EFI_SUCCESS)
+                                return (void) log_error_status(
+                                                err,
+                                                "Unable to add measurement of DTB addon #%zu to PCR %i: %m",
+                                                i,
+                                                TPM2_PCR_KERNEL_CONFIG);
+
+                        parameters_measured = parameters_measured < 0 ? m : (parameters_measured && m);
+                }
+        }
+
+        *ret_parameters_measured = parameters_measured;
+}
+
+static void dt_bases_free(void **dt_bases, size_t n_dt) {
+        assert(dt_bases || n_dt == 0);
+
+        for (size_t i = 0; i < n_dt; ++i)
+                free(dt_bases[i]);
+
+        free(dt_bases);
+}
+
+static void dt_filenames_free(char16_t **dt_filenames, size_t n_dt) {
+        assert(dt_filenames || n_dt == 0);
+
+        for (size_t i = 0; i < n_dt; ++i)
+                free(dt_filenames[i]);
+
+        free(dt_filenames);
+}
+
+static EFI_STATUS load_addons(
                 EFI_HANDLE stub_image,
                 EFI_LOADED_IMAGE_PROTOCOL *loaded_image,
                 const char16_t *prefix,
                 const char *uname,
-                bool *ret_parameters_measured,
-                char16_t **cmdline_append) {
+                char16_t **ret_cmdline,
+                void ***ret_dt_bases,
+                size_t **ret_dt_sizes,
+                char16_t ***ret_dt_filenames,
+                size_t *ret_n_dt) {
 
+        _cleanup_free_ size_t *dt_sizes = NULL;
         _cleanup_(strv_freep) char16_t **items = NULL;
         _cleanup_(file_closep) EFI_FILE *root = NULL;
-        _cleanup_free_ char16_t *buffer = NULL;
-        size_t n_items = 0, n_allocated = 0;
+        _cleanup_free_ char16_t *cmdline = NULL;
+        size_t n_items = 0, n_allocated = 0, n_dt = 0;
+        char16_t **dt_filenames = NULL;
+        void **dt_bases = NULL;
         EFI_STATUS err;
 
         assert(stub_image);
         assert(loaded_image);
         assert(prefix);
-        assert(ret_parameters_measured);
-        assert(cmdline_append);
+        assert(!!ret_dt_bases == !!ret_dt_sizes);
+        assert(!!ret_dt_bases == !!ret_n_dt);
+        assert(!!ret_dt_filenames == !!ret_n_dt);
 
         if (!loaded_image->DeviceHandle)
                 return EFI_SUCCESS;
 
+        CLEANUP_ARRAY(dt_bases, n_dt, dt_bases_free);
+        CLEANUP_ARRAY(dt_filenames, n_dt, dt_filenames_free);
+
         err = open_volume(loaded_image->DeviceHandle, &root);
         if (err == EFI_UNSUPPORTED)
                 /* Error will be unsupported if the bootloader doesn't implement the file system protocol on
@@ -325,11 +422,12 @@ static EFI_STATUS cmdline_append_and_measure_addons(
                         return log_error_status(err, "Failed to find protocol in %ls: %m", items[i]);
 
                 err = pe_memory_locate_sections(loaded_addon->ImageBase, unified_sections, addrs, szs);
-                if (err != EFI_SUCCESS || szs[UNIFIED_SECTION_CMDLINE] == 0) {
+                if (err != EFI_SUCCESS ||
+                    (szs[UNIFIED_SECTION_CMDLINE] == 0 && szs[UNIFIED_SECTION_DTB] == 0)) {
                         if (err == EFI_SUCCESS)
                                 err = EFI_NOT_FOUND;
                         log_error_status(err,
-                                         "Unable to locate embedded .cmdline section in %ls, ignoring: %m",
+                                         "Unable to locate embedded .cmdline/.dtb sections in %ls, ignoring: %m",
                                          items[i]);
                         continue;
                 }
@@ -350,22 +448,42 @@ static EFI_STATUS cmdline_append_and_measure_addons(
                         continue;
                 }
 
-                _cleanup_free_ char16_t *tmp = TAKE_PTR(buffer),
-                                        *extra16 = xstrn8_to_16((char *)loaded_addon->ImageBase + addrs[UNIFIED_SECTION_CMDLINE],
-                                                                szs[UNIFIED_SECTION_CMDLINE]);
-                buffer = xasprintf("%ls%ls%ls", strempty(tmp), isempty(tmp) ? u"" : u" ", extra16);
-        }
+                if (ret_cmdline && szs[UNIFIED_SECTION_CMDLINE] > 0) {
+                        _cleanup_free_ char16_t *tmp = TAKE_PTR(cmdline),
+                                                *extra16 = xstrn8_to_16((char *)loaded_addon->ImageBase + addrs[UNIFIED_SECTION_CMDLINE],
+                                                                        szs[UNIFIED_SECTION_CMDLINE]);
+                        cmdline = xasprintf("%ls%ls%ls", strempty(tmp), isempty(tmp) ? u"" : u" ", extra16);
+                }
+
+                if (ret_dt_bases && szs[UNIFIED_SECTION_DTB] > 0) {
+                        dt_sizes = xrealloc(dt_sizes,
+                                            n_dt * sizeof(size_t),
+                                            (n_dt + 1)  * sizeof(size_t));
+                        dt_sizes[n_dt] = szs[UNIFIED_SECTION_DTB];
 
-        mangle_stub_cmdline(buffer);
+                        dt_bases = xrealloc(dt_bases,
+                                            n_dt * sizeof(void *),
+                                            (n_dt + 1) * sizeof(void *));
+                        dt_bases[n_dt] = xmemdup((uint8_t*)loaded_addon->ImageBase + addrs[UNIFIED_SECTION_DTB],
+                                                 dt_sizes[n_dt]);
 
-        if (!isempty(buffer)) {
-                _cleanup_free_ char16_t *tmp = TAKE_PTR(*cmdline_append);
-                bool m = false;
+                        dt_filenames = xrealloc(dt_filenames,
+                                                n_dt * sizeof(char16_t *),
+                                                (n_dt + 1) * sizeof(char16_t *));
+                        dt_filenames[n_dt] = xstrdup16(items[i]);
+
+                        ++n_dt;
+                }
+        }
 
-                (void) tpm_log_load_options(buffer, &m);
-                *ret_parameters_measured = m;
+        if (ret_cmdline && !isempty(cmdline))
+                *ret_cmdline = TAKE_PTR(cmdline);
 
-                *cmdline_append = xasprintf("%ls%ls%ls", strempty(tmp), isempty(tmp) ? u"" : u" ", buffer);
+        if (ret_n_dt && n_dt > 0) {
+                *ret_dt_filenames = TAKE_PTR(dt_filenames);
+                *ret_dt_bases = TAKE_PTR(dt_bases);
+                *ret_dt_sizes = TAKE_PTR(dt_sizes);
+                *ret_n_dt = n_dt;
         }
 
         return EFI_SUCCESS;
@@ -374,12 +492,15 @@ static EFI_STATUS cmdline_append_and_measure_addons(
 static EFI_STATUS run(EFI_HANDLE image) {
         _cleanup_free_ void *credential_initrd = NULL, *global_credential_initrd = NULL, *sysext_initrd = NULL, *pcrsig_initrd = NULL, *pcrpkey_initrd = NULL;
         size_t credential_initrd_size = 0, global_credential_initrd_size = 0, sysext_initrd_size = 0, pcrsig_initrd_size = 0, pcrpkey_initrd_size = 0;
-        size_t linux_size, initrd_size, dt_size;
+        void **dt_bases_addons_global = NULL, **dt_bases_addons_uki = NULL;
+        char16_t **dt_filenames_addons_global = NULL, **dt_filenames_addons_uki = NULL;
+        _cleanup_free_ size_t *dt_sizes_addons_global = NULL, *dt_sizes_addons_uki = NULL;
+        size_t linux_size, initrd_size, dt_size, n_dts_addons_global = 0, n_dts_addons_uki = 0;
         EFI_PHYSICAL_ADDRESS linux_base, initrd_base, dt_base;
         _cleanup_(devicetree_cleanup) struct devicetree_state dt_state = {};
         EFI_LOADED_IMAGE_PROTOCOL *loaded_image;
         size_t addrs[_UNIFIED_SECTION_MAX] = {}, szs[_UNIFIED_SECTION_MAX] = {};
-        _cleanup_free_ char16_t *cmdline = NULL;
+        _cleanup_free_ char16_t *cmdline = NULL, *cmdline_addons_global = NULL, *cmdline_addons_uki = NULL;
         int sections_measured = -1, parameters_measured = -1;
         _cleanup_free_ char *uname = NULL;
         bool sysext_measured = false, m;
@@ -406,6 +527,40 @@ static EFI_STATUS run(EFI_HANDLE image) {
                 return log_error_status(err, "Unable to locate embedded .linux section: %m");
         }
 
+        CLEANUP_ARRAY(dt_bases_addons_global, n_dts_addons_global, dt_bases_free);
+        CLEANUP_ARRAY(dt_bases_addons_uki, n_dts_addons_uki, dt_bases_free);
+        CLEANUP_ARRAY(dt_filenames_addons_global, n_dts_addons_global, dt_filenames_free);
+        CLEANUP_ARRAY(dt_filenames_addons_uki, n_dts_addons_uki, dt_filenames_free);
+
+        /* Now that we have the UKI sections loaded, also load global first and then local (per-UKI)
+         * addons. The data is loaded at once, and then used later. */
+        err = load_addons(
+                        image,
+                        loaded_image,
+                        u"\\loader\\addons",
+                        uname,
+                        &cmdline_addons_global,
+                        &dt_bases_addons_global,
+                        &dt_sizes_addons_global,
+                        &dt_filenames_addons_global,
+                        &n_dts_addons_global);
+        if (err != EFI_SUCCESS)
+                log_error_status(err, "Error loading global addons, ignoring: %m");
+
+        _cleanup_free_ char16_t *dropin_dir = get_extra_dir(loaded_image->FilePath);
+        err = load_addons(
+                        image,
+                        loaded_image,
+                        dropin_dir,
+                        uname,
+                        &cmdline_addons_uki,
+                        &dt_bases_addons_uki,
+                        &dt_sizes_addons_uki,
+                        &dt_filenames_addons_uki,
+                        &n_dts_addons_uki);
+        if (err != EFI_SUCCESS)
+                log_error_status(err, "Error loading UKI-specific addons, ignoring: %m");
+
         /* Measure all "payload" of this PE image into a separate PCR (i.e. where nothing else is written
          * into so far), so that we have one PCR that we can nicely write policies against because it
          * contains all static data of this image, and thus can be easily be pre-calculated. */
@@ -471,27 +626,10 @@ static EFI_STATUS run(EFI_HANDLE image) {
          * measure the additions separately, after the embedded options, but before the smbios ones,
          * so that the order is reversed from "most hardcoded" to "most dynamic". The global addons are
          * loaded first, and the image-specific ones later, for the same reason. */
-        err = cmdline_append_and_measure_addons(
-                        image,
-                        loaded_image,
-                        u"\\loader\\addons",
-                        uname,
-                        &m,
-                        &cmdline);
-        if (err != EFI_SUCCESS)
-                log_error_status(err, "Error loading global addons, ignoring: %m");
+        cmdline_append_and_measure_addons(cmdline_addons_global, &cmdline, &m);
         parameters_measured = parameters_measured < 0 ? m : (parameters_measured && m);
 
-        _cleanup_free_ char16_t *dropin_dir = get_extra_dir(loaded_image->FilePath);
-        err = cmdline_append_and_measure_addons(
-                        image,
-                        loaded_image,
-                        dropin_dir,
-                        uname,
-                        &m,
-                        &cmdline);
-        if (err != EFI_SUCCESS)
-                log_error_status(err, "Error loading UKI-specific addons, ignoring: %m");
+        cmdline_append_and_measure_addons(cmdline_addons_uki, &cmdline, &m);
         parameters_measured = parameters_measured < 0 ? m : (parameters_measured && m);
 
         /* SMBIOS OEM Strings data is controlled by the host admin and not covered
@@ -552,6 +690,32 @@ static EFI_STATUS run(EFI_HANDLE image) {
                       &m) == EFI_SUCCESS)
                 sysext_measured = m;
 
+        dt_size = szs[UNIFIED_SECTION_DTB];
+        dt_base = dt_size != 0 ? POINTER_TO_PHYSICAL_ADDRESS(loaded_image->ImageBase) + addrs[UNIFIED_SECTION_DTB] : 0;
+
+        /* First load the base device tree, then fix it up using addons - global first, then per-UKI. */
+        if (dt_size > 0) {
+                err = devicetree_install_from_memory(
+                                &dt_state, PHYSICAL_ADDRESS_TO_POINTER(dt_base), dt_size);
+                if (err != EFI_SUCCESS)
+                        log_error_status(err, "Error loading embedded devicetree: %m");
+        }
+
+        dtb_install_addons(&dt_state,
+                           dt_bases_addons_global,
+                           dt_sizes_addons_global,
+                           dt_filenames_addons_global,
+                           n_dts_addons_global,
+                           &m);
+        parameters_measured = parameters_measured < 0 ? m : (parameters_measured && m);
+        dtb_install_addons(&dt_state,
+                           dt_bases_addons_uki,
+                           dt_sizes_addons_uki,
+                           dt_filenames_addons_uki,
+                           n_dts_addons_uki,
+                           &m);
+        parameters_measured = parameters_measured < 0 ? m : (parameters_measured && m);
+
         if (parameters_measured > 0)
                 (void) efivar_set_uint_string(MAKE_GUID_PTR(LOADER), u"StubPcrKernelParameters", TPM2_PCR_KERNEL_CONFIG, 0);
         if (sysext_measured)
@@ -600,9 +764,6 @@ static EFI_STATUS run(EFI_HANDLE image) {
         initrd_size = szs[UNIFIED_SECTION_INITRD];
         initrd_base = initrd_size != 0 ? POINTER_TO_PHYSICAL_ADDRESS(loaded_image->ImageBase) + addrs[UNIFIED_SECTION_INITRD] : 0;
 
-        dt_size = szs[UNIFIED_SECTION_DTB];
-        dt_base = dt_size != 0 ? POINTER_TO_PHYSICAL_ADDRESS(loaded_image->ImageBase) + addrs[UNIFIED_SECTION_DTB] : 0;
-
         _cleanup_pages_ Pages initrd_pages = {};
         if (credential_initrd || global_credential_initrd || sysext_initrd || pcrsig_initrd || pcrpkey_initrd) {
                 /* If we have generated initrds dynamically, let's combine them with the built-in initrd. */
@@ -637,13 +798,6 @@ static EFI_STATUS run(EFI_HANDLE image) {
                 pcrpkey_initrd = mfree(pcrpkey_initrd);
         }
 
-        if (dt_size > 0) {
-                err = devicetree_install_from_memory(
-                                &dt_state, PHYSICAL_ADDRESS_TO_POINTER(dt_base), dt_size);
-                if (err != EFI_SUCCESS)
-                        log_error_status(err, "Error loading embedded devicetree: %m");
-        }
-
         err = linux_exec(image, cmdline,
                          PHYSICAL_ADDRESS_TO_POINTER(linux_base), linux_size,
                          PHYSICAL_ADDRESS_TO_POINTER(initrd_base), initrd_size);
index 569f5eeceb1f9144de4179a2bf01086b2f991b10..8c9e7ddef287818f87b04b56f783423aeab1b2e5 100644 (file)
@@ -31,6 +31,7 @@
 #define EFI_STUB_FEATURE_RANDOM_SEED               (UINT64_C(1) << 4)
 #define EFI_STUB_FEATURE_CMDLINE_ADDONS            (UINT64_C(1) << 5)
 #define EFI_STUB_FEATURE_CMDLINE_SMBIOS            (UINT64_C(1) << 6)
+#define EFI_STUB_FEATURE_DEVICETREE_ADDONS         (UINT64_C(1) << 7)
 
 typedef enum SecureBootMode {
         SECURE_BOOT_UNSUPPORTED,