lanzatool.install: init
This commit is contained in:
parent
cfff037390
commit
4356d342a2
|
@ -95,6 +95,17 @@ dependencies = [
|
||||||
"wasi",
|
"wasi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "goblin"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "572564d6cba7d09775202c8e7eebc4d534d5ae36578ab402fb21e182a0ac9505"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
"plain",
|
||||||
|
"scroll",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "heck"
|
name = "heck"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
|
@ -110,6 +121,12 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itoa"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lanztool"
|
name = "lanztool"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -117,6 +134,9 @@ dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"clap",
|
"clap",
|
||||||
"ed25519-compact",
|
"ed25519-compact",
|
||||||
|
"goblin",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -125,6 +145,15 @@ version = "0.2.137"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89"
|
checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "log"
|
||||||
|
version = "0.4.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.16.0"
|
version = "1.16.0"
|
||||||
|
@ -137,6 +166,12 @@ version = "6.4.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee"
|
checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "plain"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro-error"
|
name = "proc-macro-error"
|
||||||
version = "1.0.4"
|
version = "1.0.4"
|
||||||
|
@ -179,6 +214,63 @@ dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ryu"
|
||||||
|
version = "1.0.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "scroll"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da"
|
||||||
|
dependencies = [
|
||||||
|
"scroll_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "scroll_derive"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bdbda6ac5cd1321e724fa9cee216f3a61885889b896f073b8f82322789c5250e"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde"
|
||||||
|
version = "1.0.147"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965"
|
||||||
|
dependencies = [
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_derive"
|
||||||
|
version = "1.0.147"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_json"
|
||||||
|
version = "1.0.89"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db"
|
||||||
|
dependencies = [
|
||||||
|
"itoa",
|
||||||
|
"ryu",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.10.0"
|
version = "0.10.0"
|
||||||
|
|
|
@ -9,3 +9,6 @@ edition = "2021"
|
||||||
anyhow = "1.0.66"
|
anyhow = "1.0.66"
|
||||||
clap = { version = "4.0.26", features = ["derive"] }
|
clap = { version = "4.0.26", features = ["derive"] }
|
||||||
ed25519-compact = "2.0.2"
|
ed25519-compact = "2.0.2"
|
||||||
|
goblin = "0.6.0"
|
||||||
|
serde = { version = "1.0.147", features = ["derive"] }
|
||||||
|
serde_json = "1.0.89"
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
{
|
||||||
|
"v1": {
|
||||||
|
"init": "/nix/store/7zrsjhxi0c93m2l89rj8jdp9khm8fc6s-nixos-system-tuxedo-22.11.20221115.85d6b39/init",
|
||||||
|
"initrd": "/nix/store/7a4plccwni1sldhyra75f7m44xgsgiqw-initrd-linux-6.0.8/initrd",
|
||||||
|
"kernel": "/nix/store/nsw0422iwp4linayqx727pi4fdyja0wv-linux-6.0.8/bzImage",
|
||||||
|
"kernelParams": [
|
||||||
|
"amd_iommu=on",
|
||||||
|
"amd_iommu=pt",
|
||||||
|
"iommu=pt",
|
||||||
|
"kvm.ignore_msrs=1",
|
||||||
|
"kvm.report_ignored_msrs=0",
|
||||||
|
"udev.log_priority=3",
|
||||||
|
"systemd.unified_cgroup_hierarchy=1",
|
||||||
|
"loglevel=4"
|
||||||
|
],
|
||||||
|
"label": "NixOS 21.11.20210810.dirty (Linux 5.15.30)",
|
||||||
|
"toplevel": "/nix/store/7zrsjhxi0c93m2l89rj8jdp9khm8fc6s-nixos-system-tuxedo-22.11.20221115.85d6b39",
|
||||||
|
"extension": {
|
||||||
|
"esp": "test",
|
||||||
|
"bootctl": "/nix/store/89366aivz6v8a34yyni2m04ca9hwrl92-systemd-250.4/bin/bootctl",
|
||||||
|
"osRelease": "/nix/store/734vglb01ssz73wlihad7xa9yzvwlvx6-etc-os-release"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
|
pub struct Bootspec {
|
||||||
|
pub v1: GenerationV1,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct GenerationV1 {
|
||||||
|
/// Label for the system closure
|
||||||
|
pub label: String,
|
||||||
|
/// Path to kernel (bzImage) -- $toplevel/kernel
|
||||||
|
pub kernel: PathBuf,
|
||||||
|
/// list of kernel parameters
|
||||||
|
pub kernel_params: Vec<String>,
|
||||||
|
/// Path to the init script
|
||||||
|
pub init: PathBuf,
|
||||||
|
/// Path to initrd -- $toplevel/initrd
|
||||||
|
pub initrd: PathBuf,
|
||||||
|
/// Path to "append-initrd-secrets" script -- $toplevel/append-initrd-secrets
|
||||||
|
pub initrd_secrets: Option<PathBuf>,
|
||||||
|
/// config.system.build.toplevel path
|
||||||
|
pub toplevel: PathBuf,
|
||||||
|
pub extension: Extension,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct Extension {
|
||||||
|
pub esp: String,
|
||||||
|
pub bootctl: PathBuf,
|
||||||
|
pub os_release: PathBuf,
|
||||||
|
}
|
|
@ -4,7 +4,7 @@ use std::path::{Path, PathBuf};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
|
|
||||||
use crate::crypto;
|
use crate::{crypto, install};
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
pub struct Cli {
|
pub struct Cli {
|
||||||
|
@ -20,6 +20,10 @@ pub enum Commands {
|
||||||
Sign { file: PathBuf, private_key: PathBuf },
|
Sign { file: PathBuf, private_key: PathBuf },
|
||||||
/// Sign
|
/// Sign
|
||||||
Verify { file: PathBuf, public_key: PathBuf },
|
Verify { file: PathBuf, public_key: PathBuf },
|
||||||
|
Install {
|
||||||
|
public_key: PathBuf,
|
||||||
|
bootspec: PathBuf,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Cli {
|
impl Cli {
|
||||||
|
@ -34,6 +38,10 @@ impl Commands {
|
||||||
Commands::Generate => generate(),
|
Commands::Generate => generate(),
|
||||||
Commands::Sign { file, private_key } => sign(&file, &private_key),
|
Commands::Sign { file, private_key } => sign(&file, &private_key),
|
||||||
Commands::Verify { file, public_key } => verify(&file, &public_key),
|
Commands::Verify { file, public_key } => verify(&file, &public_key),
|
||||||
|
Commands::Install {
|
||||||
|
public_key,
|
||||||
|
bootspec,
|
||||||
|
} => install(&public_key, &bootspec),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,3 +85,8 @@ fn with_extension(path: &Path, extension: &str) -> PathBuf {
|
||||||
file_path.push(extension);
|
file_path.push(extension);
|
||||||
PathBuf::from(file_path)
|
PathBuf::from(file_path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn install(public_key: &Path, bootspec: &Path) -> Result<()> {
|
||||||
|
let lanzaboote_bin = std::env::var("LANZABOOTE")?;
|
||||||
|
install::install(public_key, bootspec, Path::new(&lanzaboote_bin))
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
pub struct EspPaths {
|
||||||
|
pub esp: PathBuf,
|
||||||
|
pub nixos: PathBuf,
|
||||||
|
pub kernel: PathBuf,
|
||||||
|
pub initrd: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EspPaths {
|
||||||
|
pub fn new(esp: &str) -> Self {
|
||||||
|
let esp = Path::new(esp);
|
||||||
|
let esp_nixos = esp.join("EFI/nixos");
|
||||||
|
|
||||||
|
Self {
|
||||||
|
esp: esp.to_owned(),
|
||||||
|
nixos: esp_nixos.clone(),
|
||||||
|
kernel: esp_nixos.join("EFI/nixos"),
|
||||||
|
initrd: esp_nixos.join("initrd"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
use std::fs;
|
||||||
|
|
||||||
|
use std::path::Path;
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
|
||||||
|
use crate::bootspec::Bootspec;
|
||||||
|
use crate::esp::EspPaths;
|
||||||
|
use crate::stub;
|
||||||
|
|
||||||
|
pub fn install(_: &Path, bootspec: &Path, lanzaboote_bin: &Path) -> Result<()> {
|
||||||
|
let bootspec_doc: Bootspec = serde_json::from_slice(&fs::read(bootspec)?)?;
|
||||||
|
|
||||||
|
let esp_paths = EspPaths::new(&bootspec_doc.v1.extension.esp);
|
||||||
|
|
||||||
|
stub::assemble(
|
||||||
|
lanzaboote_bin,
|
||||||
|
&bootspec_doc.v1.extension.os_release,
|
||||||
|
&bootspec_doc.v1.kernel_params,
|
||||||
|
&esp_paths.kernel,
|
||||||
|
&esp_paths.initrd,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Copy the files to the ESP
|
||||||
|
fs::create_dir_all(&esp_paths.nixos)?;
|
||||||
|
fs::copy(bootspec_doc.v1.kernel, esp_paths.kernel)?;
|
||||||
|
fs::copy(bootspec_doc.v1.initrd, esp_paths.initrd)?;
|
||||||
|
// install_systemd_boot(bootctl, &esp)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn install_systemd_boot(bootctl: &Path, esp: &Path) -> Result<()> {
|
||||||
|
let args = vec![
|
||||||
|
String::from("install"),
|
||||||
|
String::from("--path"),
|
||||||
|
esp.display().to_string(),
|
||||||
|
];
|
||||||
|
|
||||||
|
let status = Command::new(&bootctl).args(&args).status()?;
|
||||||
|
if !status.success() {
|
||||||
|
return Err(anyhow::anyhow!(
|
||||||
|
"Failed success run `{}` with args `{:?}`",
|
||||||
|
&bootctl.display(),
|
||||||
|
&args
|
||||||
|
)
|
||||||
|
.into());
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -1,5 +1,9 @@
|
||||||
|
mod bootspec;
|
||||||
mod cli;
|
mod cli;
|
||||||
mod crypto;
|
mod crypto;
|
||||||
|
mod esp;
|
||||||
|
mod install;
|
||||||
|
mod stub;
|
||||||
|
|
||||||
use std::process;
|
use std::process;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
use std::fs;
|
||||||
|
use std::os::unix::fs::MetadataExt;
|
||||||
|
use std::path::Path;
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use goblin;
|
||||||
|
|
||||||
|
pub fn assemble(
|
||||||
|
lanzaboote_bin: &Path,
|
||||||
|
os_release: &Path,
|
||||||
|
kernel_cmdline: &[String],
|
||||||
|
kernel_path: &Path,
|
||||||
|
initrd_path: &Path,
|
||||||
|
) -> Result<()> {
|
||||||
|
// objcopy copies files into the PE binary. That's why we have to write the contents
|
||||||
|
// of some bootspec properties to disk
|
||||||
|
let kernel_cmdline_file = Path::new("/tmp/kernel_cmdline");
|
||||||
|
fs::write(kernel_cmdline_file, kernel_cmdline.join(" "))?;
|
||||||
|
let kernel_path_file = Path::new("/tmp/kernel_path");
|
||||||
|
fs::write(kernel_path_file, kernel_path.to_str().unwrap())?;
|
||||||
|
let initrd_path_file = Path::new("/tmp/initrd_path");
|
||||||
|
fs::write(initrd_path_file, initrd_path.to_str().unwrap())?;
|
||||||
|
|
||||||
|
let pe_binary = fs::read(lanzaboote_bin)?;
|
||||||
|
let pe = goblin::pe::PE::parse(&pe_binary)?;
|
||||||
|
|
||||||
|
let os_release_offs = u64::from(
|
||||||
|
pe.sections
|
||||||
|
.iter()
|
||||||
|
.find(|s| s.name().unwrap() == ".sdmagic")
|
||||||
|
.and_then(|s| Some(s.size_of_raw_data + s.virtual_address))
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let kernel_cmdline_offs = os_release_offs + file_size(os_release)?;
|
||||||
|
let initrd_path_offs = kernel_cmdline_offs + file_size(kernel_cmdline_file)?;
|
||||||
|
let kernel_path_offs = initrd_path_offs + file_size(initrd_path_file)?;
|
||||||
|
|
||||||
|
let args = vec![
|
||||||
|
String::from("--add-section"),
|
||||||
|
format!(".osrel={}", path_to_string(os_release)),
|
||||||
|
String::from("--change-section-vma"),
|
||||||
|
format!(".osrel={:#x}", os_release_offs),
|
||||||
|
String::from("--add-section"),
|
||||||
|
format!(".cmdline={}", path_to_string(kernel_cmdline_file)),
|
||||||
|
String::from("--change-section-vma"),
|
||||||
|
format!(".cmdline={:#x}", kernel_cmdline_offs),
|
||||||
|
String::from("--add-section"),
|
||||||
|
format!(".initrdp={}", path_to_string(initrd_path_file)),
|
||||||
|
String::from("--change-section-vma"),
|
||||||
|
format!(".initrdp={:#x}", initrd_path_offs),
|
||||||
|
String::from("--add-section"),
|
||||||
|
format!(".kernelp={}", path_to_string(kernel_path_file)),
|
||||||
|
String::from("--change-section-vma"),
|
||||||
|
format!(".kernelp={:#x}", kernel_path_offs),
|
||||||
|
lanzaboote_bin.to_str().unwrap().to_owned(),
|
||||||
|
String::from("stub.efi"),
|
||||||
|
];
|
||||||
|
|
||||||
|
let status = Command::new("objcopy").args(&args).status()?;
|
||||||
|
if !status.success() {
|
||||||
|
return Err(anyhow::anyhow!("Failed to build stub with args `{:?}`", &args).into());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// All Linux file paths should be convertable to strings
|
||||||
|
fn path_to_string(path: &Path) -> String {
|
||||||
|
path.to_owned().into_os_string().into_string().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn file_size(path: &Path) -> Result<u64> {
|
||||||
|
Ok(fs::File::open(path)?.metadata()?.size())
|
||||||
|
}
|
Loading…
Reference in New Issue