From 09b24be170a74a08da67d2ce4913d15a6cfc252d Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Thu, 22 Aug 2019 15:04:19 -0500 Subject: [PATCH] deploy: Handle efi blobs We can now deploy our custom initramfs + kernel efi blobs. This will only happen when we're running in a PAYG system (ie: the kernel cmdline contains eospayg) or when we set the env var OSTREE_DEPLOY_PAYG to force PAYG deployment during image build. https://phabricator.endlessm.com/T27521 Rebase 2020.8 (T31593): Fix conflicts from upstream overlay_initrds feature and dropping flags argument to install_into_boot(). Added a couple more `!payg` to ensure other boot artifacts aren't installed. --- src/libostree/ostree-sysroot-deploy.c | 129 ++++++++++++++++++++------ 1 file changed, 99 insertions(+), 30 deletions(-) diff --git a/src/libostree/ostree-sysroot-deploy.c b/src/libostree/ostree-sysroot-deploy.c index b024b2106..61817f4e8 100644 --- a/src/libostree/ostree-sysroot-deploy.c +++ b/src/libostree/ostree-sysroot-deploy.c @@ -1055,6 +1055,8 @@ typedef struct { char *initramfs_namever; char *devicetree_srcpath; char *devicetree_namever; + char *efi_blob_srcpath; + char *efi_blob_namever; char *bootcsum; } OstreeKernelLayout; static void @@ -1069,6 +1071,8 @@ _ostree_kernel_layout_free (OstreeKernelLayout *layout) g_free (layout->initramfs_namever); g_free (layout->devicetree_srcpath); g_free (layout->devicetree_namever); + g_free (layout->efi_blob_srcpath); + g_free (layout->efi_blob_namever); g_free (layout->bootcsum); g_free (layout); } @@ -1232,6 +1236,15 @@ get_kernel_from_tree_usrlib_modules (OstreeSysroot *sysroot, g_clear_object (&in); glnx_close_fd (&fd); + if (!ot_openat_ignore_enoent (ret_layout->boot_dfd, "payg-image.efi", &fd, error)) + return FALSE; + if (fd != -1) + { + ret_layout->efi_blob_srcpath = g_strdup ("payg-image.efi"); + ret_layout->efi_blob_namever = g_strdup_printf ("payg-image-%s.efi", kver); + } + glnx_close_fd (&fd); + /* And finally, look for any HMAC file. This is needed for FIPS mode on some distros. */ if (!glnx_fstatat_allow_noent (ret_layout->boot_dfd, ".vmlinuz.hmac", NULL, 0, error)) return FALSE; @@ -1793,6 +1806,26 @@ parse_os_release (const char *contents, return ret; } +static gboolean +is_payg_deployment(GCancellable *cancellable) +{ + g_autoptr(GFile) cmdline_file = g_file_new_for_path ("/proc/cmdline"); + g_autofree char *cmdline = NULL; + gsize cmdline_len; + + if (g_getenv ("OSTREE_DEPLOY_PAYG")) + return TRUE; + + if (!g_file_load_contents (cmdline_file, cancellable, + &cmdline, &cmdline_len, NULL, NULL)) + return FALSE; + + if (g_strstr_len (cmdline, cmdline_len, "eospayg")) + return TRUE; + + return FALSE; +} + /* Given @deployment, prepare it to be booted; basically copying its * kernel/initramfs into /boot/ostree (if needed) and writing out an entry in * /boot/loader/entries. @@ -1808,6 +1841,8 @@ install_deployment_kernel (OstreeSysroot *sysroot, GError **error) { + gboolean payg; + GLNX_AUTO_PREFIX_ERROR ("Installing kernel", error); OstreeBootconfigParser *bootconfig = ostree_deployment_get_bootconfig (deployment); g_autofree char *deployment_dirpath = ostree_sysroot_get_deployment_dirpath (sysroot, deployment); @@ -1848,24 +1883,46 @@ install_deployment_kernel (OstreeSysroot *sysroot, if (!glnx_shutil_mkdir_p_at (boot_dfd, bootconfdir, 0775, cancellable, error)) return FALSE; + struct stat stbuf; + /* If this is a payg deployment, we want the efi blob and nothing else */ + payg = kernel_layout->efi_blob_srcpath && is_payg_deployment(cancellable); + /* If we're updating an old loader entry that doesn't use efi blobs + * keep it the way it was. */ + payg = payg && !ostree_bootconfig_parser_get (bootconfig, "linux"); + if (payg) + { + g_assert (kernel_layout->efi_blob_namever); + if (!glnx_fstatat_allow_noent (bootcsum_dfd, kernel_layout->efi_blob_namever, &stbuf, 0, error)) + return FALSE; + if (errno == ENOENT) + { + if (!install_into_boot (repo, sepolicy, kernel_layout->boot_dfd, kernel_layout->efi_blob_srcpath, + bootcsum_dfd, kernel_layout->efi_blob_namever, + cancellable, error)) + return FALSE; + } + } + /* Install (hardlink/copy) the kernel into /boot/ostree/osname-${bootcsum} if * it doesn't exist already. */ - struct stat stbuf; - if (!glnx_fstatat_allow_noent (bootcsum_dfd, kernel_layout->kernel_namever, &stbuf, 0, error)) - return FALSE; - if (errno == ENOENT) + if (!payg) { - if (!install_into_boot (repo, sepolicy, kernel_layout->boot_dfd, kernel_layout->kernel_srcpath, - bootcsum_dfd, kernel_layout->kernel_namever, - cancellable, error)) + if (!glnx_fstatat_allow_noent (bootcsum_dfd, kernel_layout->kernel_namever, &stbuf, 0, error)) return FALSE; + if (errno == ENOENT) + { + if (!install_into_boot (repo, sepolicy, kernel_layout->boot_dfd, kernel_layout->kernel_srcpath, + bootcsum_dfd, kernel_layout->kernel_namever, + cancellable, error)) + return FALSE; + } } /* If we have an initramfs, then install it into * /boot/ostree/osname-${bootcsum} if it doesn't exist already. */ - if (kernel_layout->initramfs_srcpath) + if (kernel_layout->initramfs_srcpath && !payg) { g_assert (kernel_layout->initramfs_namever); if (!glnx_fstatat_allow_noent (bootcsum_dfd, kernel_layout->initramfs_namever, &stbuf, 0, error)) @@ -1879,7 +1936,7 @@ install_deployment_kernel (OstreeSysroot *sysroot, } } - if (kernel_layout->devicetree_srcpath) + if (kernel_layout->devicetree_srcpath && !payg) { /* If devicetree_namever is set a single device tree is deployed */ if (kernel_layout->devicetree_namever) @@ -1902,7 +1959,7 @@ install_deployment_kernel (OstreeSysroot *sysroot, } } - if (kernel_layout->kernel_hmac_srcpath) + if (kernel_layout->kernel_hmac_srcpath && !payg) { if (!glnx_fstatat_allow_noent (bootcsum_dfd, kernel_layout->kernel_hmac_namever, &stbuf, 0, error)) return FALSE; @@ -1916,7 +1973,7 @@ install_deployment_kernel (OstreeSysroot *sysroot, } g_autoptr(GPtrArray) overlay_initrds = NULL; - for (char **it = _ostree_deployment_get_overlay_initrds (deployment); it && *it; it++) + for (char **it = _ostree_deployment_get_overlay_initrds (deployment); !payg && it && *it; it++) { char *checksum = *it; @@ -2024,39 +2081,45 @@ install_deployment_kernel (OstreeSysroot *sysroot, g_autofree char *version_key = g_strdup_printf ("%d", n_deployments - ostree_deployment_get_index (deployment)); ostree_bootconfig_parser_set (bootconfig, OSTREE_COMMIT_META_KEY_VERSION, version_key); - g_autofree char * boot_relpath = g_strconcat ("/", bootcsumdir, "/", kernel_layout->kernel_namever, NULL); - ostree_bootconfig_parser_set (bootconfig, "linux", boot_relpath); + + if (!payg) + { + g_autofree char * boot_relpath = g_strconcat ("/", bootcsumdir, "/", kernel_layout->kernel_namever, NULL); + ostree_bootconfig_parser_set (bootconfig, "linux", boot_relpath); + } val = ostree_bootconfig_parser_get (bootconfig, "options"); g_autoptr(OstreeKernelArgs) kargs = ostree_kernel_args_from_string (val); - if (kernel_layout->initramfs_namever) + if (!payg) { - g_autofree char * initrd_boot_relpath = - g_strconcat ("/", bootcsumdir, "/", kernel_layout->initramfs_namever, NULL); - ostree_bootconfig_parser_set (bootconfig, "initrd", initrd_boot_relpath); + if (kernel_layout->initramfs_namever) + { + g_autofree char * boot_relpath = g_strconcat ("/", bootcsumdir, "/", kernel_layout->initramfs_namever, NULL); + ostree_bootconfig_parser_set (bootconfig, "initrd", boot_relpath); - if (overlay_initrds) + if (overlay_initrds) + { + g_ptr_array_add (overlay_initrds, NULL); + ostree_bootconfig_parser_set_overlay_initrds (bootconfig, (char**)overlay_initrds->pdata); + } + } + else { - g_ptr_array_add (overlay_initrds, NULL); - ostree_bootconfig_parser_set_overlay_initrds (bootconfig, (char**)overlay_initrds->pdata); + g_autofree char *prepare_root_arg = NULL; + prepare_root_arg = g_strdup_printf ("init=/ostree/boot.%d/%s/%s/%d/usr/lib/ostree/ostree-prepare-root", + new_bootversion, osname, bootcsum, + ostree_deployment_get_bootserial (deployment)); + ostree_kernel_args_replace_take (kargs, g_steal_pointer (&prepare_root_arg)); } } - else - { - g_autofree char *prepare_root_arg = NULL; - prepare_root_arg = g_strdup_printf ("init=/ostree/boot.%d/%s/%s/%d/usr/lib/ostree/ostree-prepare-root", - new_bootversion, osname, bootcsum, - ostree_deployment_get_bootserial (deployment)); - ostree_kernel_args_replace_take (kargs, g_steal_pointer (&prepare_root_arg)); - } - if (kernel_layout->devicetree_namever) + if (kernel_layout->devicetree_namever && !payg) { g_autofree char * dt_boot_relpath = g_strconcat ("/", bootcsumdir, "/", kernel_layout->devicetree_namever, NULL); ostree_bootconfig_parser_set (bootconfig, "devicetree", dt_boot_relpath); } - else if (kernel_layout->devicetree_srcpath) + else if (kernel_layout->devicetree_srcpath && !payg) { /* If devicetree_srcpath is set but devicetree_namever is NULL, then we * want to point to a whole directory of device trees. @@ -2066,6 +2129,12 @@ install_deployment_kernel (OstreeSysroot *sysroot, ostree_bootconfig_parser_set (bootconfig, "fdtdir", dt_boot_relpath); } + if (payg) + { + g_autofree char * boot_relpath = g_strconcat ("/", bootcsumdir, "/", kernel_layout->efi_blob_namever, NULL); + ostree_bootconfig_parser_set (bootconfig, "efi", boot_relpath); + } + /* Note this is parsed in ostree-impl-system-generator.c */ g_autofree char *ostree_kernel_arg = g_strdup_printf ("ostree=/ostree/boot.%d/%s/%s/%d", new_bootversion, osname, bootcsum,