From 838be737a818253a7f48f6b21ac0699bf51dee5f Mon Sep 17 00:00:00 2001 From: Nikita Dubrovskii Date: Thu, 16 Nov 2023 17:17:13 +0100 Subject: [PATCH] s390x: add zVM Secure IPL support --- data/example-config.yaml | 2 + docs/cmd/install.md | 3 + docs/customizing-install.md | 2 + docs/release-notes.md | 1 + man/coreos-installer-install.8 | 5 +- scripts/coreos-installer-service | 5 ++ src/cmdline/install.rs | 7 ++ src/install.rs | 3 + src/s390x/mod.rs | 1 + src/s390x/zipl.rs | 68 ++++++++++++++++++- systemd/coreos-installer-generator | 5 ++ systemd/coreos-installer-post.target | 1 + .../coreos-installer-reboot-loaddev.service | 16 +++++ 13 files changed, 116 insertions(+), 3 deletions(-) create mode 100644 systemd/coreos-installer-reboot-loaddev.service diff --git a/data/example-config.yaml b/data/example-config.yaml index 640a1dd91..1d48fde75 100644 --- a/data/example-config.yaml +++ b/data/example-config.yaml @@ -43,5 +43,7 @@ stream-base-url: URL preserve-on-error: true # Fetch retries, or string "infinite" fetch-retries: N +# Enable IBM Secure IPL +secure-ipl: true # Destination device dest-device: path diff --git a/docs/cmd/install.md b/docs/cmd/install.md index be4a55fa8..240e55edf 100644 --- a/docs/cmd/install.md +++ b/docs/cmd/install.md @@ -163,4 +163,7 @@ Advanced Options: indefinitely. [default: 0] + + --secure-ipl + Enable IBM Secure IPL ``` diff --git a/docs/customizing-install.md b/docs/customizing-install.md index 6ae305ddb..a8cf73cac 100644 --- a/docs/customizing-install.md +++ b/docs/customizing-install.md @@ -168,6 +168,8 @@ stream-base-url: URL preserve-on-error: true # Fetch retries, or string "infinite" fetch-retries: N +# Enable IBM Secure IPL +secure-ipl: true # Destination device dest-device: path ``` diff --git a/docs/release-notes.md b/docs/release-notes.md index 7696a3f7d..cac10aafb 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -8,6 +8,7 @@ nav_order: 8 Major changes: +- install: Add zVM Secure IPL support Minor changes: diff --git a/man/coreos-installer-install.8 b/man/coreos-installer-install.8 index 721196e4f..1d76f4c1d 100644 --- a/man/coreos-installer-install.8 +++ b/man/coreos-installer-install.8 @@ -4,7 +4,7 @@ .SH NAME coreos\-installer\-install \- Install Fedora CoreOS or RHEL CoreOS .SH SYNOPSIS -\fBcoreos\-installer\-install\fR [\fB\-c\fR|\fB\-\-config\-file\fR] [\fB\-s\fR|\fB\-\-stream\fR] [\fB\-u\fR|\fB\-\-image\-url\fR] [\fB\-f\fR|\fB\-\-image\-file\fR] [\fB\-i\fR|\fB\-\-ignition\-file\fR] [\fB\-I\fR|\fB\-\-ignition\-url\fR] [\fB\-\-ignition\-hash\fR] [\fB\-a\fR|\fB\-\-architecture\fR] [\fB\-p\fR|\fB\-\-platform\fR] [\fB\-\-console\fR] [\fB\-\-append\-karg\fR] [\fB\-\-delete\-karg\fR] [\fB\-n\fR|\fB\-\-copy\-network\fR] [\fB\-\-network\-dir\fR] [\fB\-\-save\-partlabel\fR] [\fB\-\-save\-partindex\fR] [\fB\-\-offline\fR] [\fB\-\-insecure\fR] [\fB\-\-insecure\-ignition\fR] [\fB\-\-stream\-base\-url\fR] [\fB\-\-preserve\-on\-error\fR] [\fB\-\-fetch\-retries\fR] [\fB\-h\fR|\fB\-\-help\fR] [\fB\-V\fR|\fB\-\-version\fR] [\fIDEST_DEVICE\fR] +\fBcoreos\-installer\-install\fR [\fB\-c\fR|\fB\-\-config\-file\fR] [\fB\-s\fR|\fB\-\-stream\fR] [\fB\-u\fR|\fB\-\-image\-url\fR] [\fB\-f\fR|\fB\-\-image\-file\fR] [\fB\-i\fR|\fB\-\-ignition\-file\fR] [\fB\-I\fR|\fB\-\-ignition\-url\fR] [\fB\-\-ignition\-hash\fR] [\fB\-a\fR|\fB\-\-architecture\fR] [\fB\-p\fR|\fB\-\-platform\fR] [\fB\-\-console\fR] [\fB\-\-append\-karg\fR] [\fB\-\-delete\-karg\fR] [\fB\-n\fR|\fB\-\-copy\-network\fR] [\fB\-\-network\-dir\fR] [\fB\-\-save\-partlabel\fR] [\fB\-\-save\-partindex\fR] [\fB\-\-offline\fR] [\fB\-\-insecure\fR] [\fB\-\-insecure\-ignition\fR] [\fB\-\-stream\-base\-url\fR] [\fB\-\-preserve\-on\-error\fR] [\fB\-\-fetch\-retries\fR] [\fB\-\-secure\-ipl\fR] [\fB\-h\fR|\fB\-\-help\fR] [\fB\-V\fR|\fB\-\-version\fR] [\fIDEST_DEVICE\fR] .SH DESCRIPTION Install Fedora CoreOS or RHEL CoreOS .SH OPTIONS @@ -123,6 +123,9 @@ Fetch retries, or "infinite" Number of times to retry network fetches, or the string "infinite" to retry indefinitely. .TP +\fB\-\-secure\-ipl\fR +Enable IBM Secure IPL +.TP \fB\-h\fR, \fB\-\-help\fR Print help (see a summary with \*(Aq\-h\*(Aq) .TP diff --git a/scripts/coreos-installer-service b/scripts/coreos-installer-service index 71c636a5c..aaa452f4b 100755 --- a/scripts/coreos-installer-service +++ b/scripts/coreos-installer-service @@ -121,6 +121,11 @@ if karg_bool coreos.inst.insecure; then args+=("--insecure") fi +# zVM Secure IPL support +if karg_bool coreos.inst.secure_ipl; then + args+=("--secure-ipl") +fi + # Always retry HTTP requests; we've got nothing to lose since we fail anyway. args+=("--fetch-retries" "infinite") diff --git a/src/cmdline/install.rs b/src/cmdline/install.rs index 000479f69..885ca73db 100644 --- a/src/cmdline/install.rs +++ b/src/cmdline/install.rs @@ -252,6 +252,10 @@ pub struct InstallConfig { #[serde(skip_serializing_if = "is_default")] #[arg(long, value_name = "N", default_value_t, help_heading = ADVANCED)] pub fetch_retries: FetchRetries, + /// Enable IBM Secure IPL + #[serde(skip_serializing_if = "is_default")] + #[arg(long, help_heading = ADVANCED)] + pub secure_ipl: bool, // positional args /// Destination device @@ -361,6 +365,7 @@ mod test { stream_base_url: Some(Url::parse("http://example.com/t").unwrap()), preserve_on_error: true, fetch_retries: FetchRetries::from_str("3").unwrap(), + secure_ipl: true, dest_device: Some("u".into()), }; let expected = vec![ @@ -412,6 +417,7 @@ mod test { "--preserve-on-error", "--fetch-retries", "3", + "--secure-ipl", "u", ]; assert_eq!(config.to_args().unwrap(), expected); @@ -484,6 +490,7 @@ dest-device: u stream_base_url: Some(Url::parse("http://example.com/t").unwrap()), preserve_on_error: true, fetch_retries: FetchRetries::from_str("3").unwrap(), + secure_ipl: false, dest_device: Some("u".into()), }; let config = InstallConfig::from_args(&["--config-file", f.path().to_str().unwrap()]) diff --git a/src/install.rs b/src/install.rs index 71c116e75..c2a8cc56b 100644 --- a/src/install.rs +++ b/src/install.rs @@ -454,6 +454,9 @@ fn write_disk( None, )?; s390x::chreipl(device)?; + if config.secure_ipl { + s390x::set_loaddev(device)?; + } } } diff --git a/src/s390x/mod.rs b/src/s390x/mod.rs index 8f39c4c75..7a707637f 100644 --- a/src/s390x/mod.rs +++ b/src/s390x/mod.rs @@ -19,6 +19,7 @@ pub mod zipl; pub use dasd::{dasd_try_get_sector_size, image_copy_s390x, prepare_dasd}; pub use zipl::chreipl; +pub use zipl::set_loaddev; pub use zipl::zipl; mod eckd; mod fba; diff --git a/src/s390x/zipl.rs b/src/s390x/zipl.rs index 4b3d8064e..2b6f657e3 100644 --- a/src/s390x/zipl.rs +++ b/src/s390x/zipl.rs @@ -14,10 +14,11 @@ use crate::blockdev::Mount; use crate::io::{visit_bls_entry, visit_bls_entry_options, Initrd, KargsEditor}; -use crate::runcmd; use crate::s390x::ZiplSecexMode; use crate::util::cmd_output; -use anyhow::{anyhow, Context, Result}; +use crate::{runcmd, runcmd_output}; +use anyhow::{anyhow, bail, Context, Result}; +use lazy_static::lazy_static; use nix::mount::MsFlags; use regex::Regex; use std::fs::{copy, create_dir_all, read_dir, DirEntry, File}; @@ -33,6 +34,69 @@ pub fn chreipl>(dev: P) -> Result<()> { Ok(()) } +/// Sets zVM secure loaddev to `dev`. +pub fn set_loaddev>(dev: P) -> Result<()> { + eprintln!("Setting LOADDEV"); + let output = runcmd_output!( + "lszdev", + "-n", + "--columns", + "TYPE,ID", + "--by-node", + dev.as_ref() + )?; + let (devtype, id) = output + .trim() + .split_once(' ') + .with_context(|| format!("parsing {output}"))?; + + let mut cmd = Command::new("vmcp"); + cmd.arg("set").arg("loaddev"); + match devtype { + "dasd-eckd" => { + lazy_static! { + static ref REGEX: Regex = + Regex::new(r#"[[:digit:]].[[:digit:]].([[:xdigit:]]+)"#).unwrap(); + } + for cap in REGEX.captures_iter(id) { + cmd.arg("eckd").arg("dev").arg(&cap[1]); + } + } + "zfcp-lun" => { + lazy_static! { + static ref REGEX: Regex = Regex::new( + r#"[[:digit:]].[[:digit:]].([[:xdigit:]]+):0x([[:xdigit:]]+):0x([[:xdigit:]]+)"# + ) + .unwrap(); + } + // CP tool wants portname/lun to be splitted at 8th character: + // $ vmcp set loaddev dev 8007 portname 500507630400d1e3 lun 4001404c00000000 secure + // HCPZPM002E Invalid operand - 500507630400D1E3 + + // $ vmcp set loaddev dev 8007 portname 50050763 0400d1e3 lun 4001404c 00000000 secure + // $ vmcp q loaddev + // SCSI DEVICE 8007 SECURE + // PORTNAME 50050763 0400D1E3 LUN 4001404C 00000000 BOOTPROG 0 + // BR_LBA 00000000 00000000 + + for cap in REGEX.captures_iter(id) { + cmd.arg("dev") + .arg(&cap[1]) + .arg("portname") + .arg(&cap[2][0..8]) + .arg(&cap[2][8..]) + .arg("lun") + .arg(&cap[3][0..8]) + .arg(&cap[3][8..]); + } + } + _ => bail!("unsupported device: {} id: {}", devtype, id), + }; + cmd.arg("secure"); + cmd_output(&mut cmd)?; + Ok(()) +} + fn secure_execution_is_enabled() -> Result { let sysfs_flag = "/sys/firmware/uv/prot_virt_guest"; match File::open(sysfs_flag) { diff --git a/systemd/coreos-installer-generator b/systemd/coreos-installer-generator index 8611da24d..ba7e893ce 100755 --- a/systemd/coreos-installer-generator +++ b/systemd/coreos-installer-generator @@ -38,4 +38,9 @@ if [ -n "$(karg coreos.inst.install_dev)" -o \ if ! karg_bool coreos.inst.skip_reboot; then touch /run/coreos-installer-reboot fi + + # Create precondition for coreos-installer-reboot-loaddev.service if requested + if karg_bool coreos.inst.secure_ipl; then + touch /run/coreos-installer-loaddev + fi fi diff --git a/systemd/coreos-installer-post.target b/systemd/coreos-installer-post.target index 8013eb6f8..7773cc134 100644 --- a/systemd/coreos-installer-post.target +++ b/systemd/coreos-installer-post.target @@ -5,3 +5,4 @@ AllowIsolate=yes Requires=coreos-installer.target Requires=coreos-installer-reboot.service Requires=coreos-installer-noreboot.service +Requires=coreos-installer-reboot-loaddev.service diff --git a/systemd/coreos-installer-reboot-loaddev.service b/systemd/coreos-installer-reboot-loaddev.service new file mode 100644 index 000000000..3ff474ba3 --- /dev/null +++ b/systemd/coreos-installer-reboot-loaddev.service @@ -0,0 +1,16 @@ +[Unit] +Description=Reboot from zVM LOADDEV after CoreOS Installer +ConditionVirtualization=zvm +ConditionPathExists=/run/coreos-installer-loaddev + +Requires=coreos-installer.target +After=coreos-installer.target +After=coreos-installer-reboot.service +OnFailure=emergency.target +OnFailureJobMode=replace-irreversibly + +[Service] +Type=simple +ExecStart=/usr/sbin/vmcp ipl loaddev +StandardOutput=kmsg+console +StandardError=kmsg+console