Pass the built-in cmdline to the kernel
Do not pass our own cmdline on to the kernel. It may have been set by a malicious boot loader specification entry, and could instruct the kernel to load an arbitrary unprotected initrd (or perform some other fun stuff). Instead, always pass the command line built into the UKI, which is properly authenticated.
This commit is contained in:
parent
3885f114a8
commit
081714cab9
|
@ -25,7 +25,7 @@ use uefi::{
|
|||
|
||||
use crate::{
|
||||
linux_loader::InitrdLoader,
|
||||
uefi_helpers::{booted_image_cmdline, booted_image_file, read_all},
|
||||
uefi_helpers::{booted_image_file, read_all},
|
||||
};
|
||||
|
||||
type Hash = sha2::digest::Output<Sha256>;
|
||||
|
@ -67,13 +67,16 @@ struct EmbeddedConfiguration {
|
|||
/// The cryptographic hash of the initrd. This hash is computed
|
||||
/// over the whole PE binary, not only the embedded initrd.
|
||||
initrd_hash: Hash,
|
||||
|
||||
/// The kernel command-line.
|
||||
cmdline: CString16,
|
||||
}
|
||||
|
||||
/// Extract a filename from a PE section. The filename is stored as UTF-8.
|
||||
fn extract_filename(file_data: &[u8], section: &str) -> Result<CString16> {
|
||||
let filename = pe_section_as_string(file_data, section).ok_or(Status::INVALID_PARAMETER)?;
|
||||
/// Extract a string, stored as UTF-8, from a PE section.
|
||||
fn extract_string(file_data: &[u8], section: &str) -> Result<CString16> {
|
||||
let string = pe_section_as_string(file_data, section).ok_or(Status::INVALID_PARAMETER)?;
|
||||
|
||||
Ok(CString16::try_from(filename.as_str()).map_err(|_| Status::INVALID_PARAMETER)?)
|
||||
Ok(CString16::try_from(string.as_str()).map_err(|_| Status::INVALID_PARAMETER)?)
|
||||
}
|
||||
|
||||
/// Extract a Blake3 hash from a PE section.
|
||||
|
@ -92,11 +95,13 @@ impl EmbeddedConfiguration {
|
|||
let file_data = read_all(file)?;
|
||||
|
||||
Ok(Self {
|
||||
kernel_filename: extract_filename(&file_data, ".kernelp")?,
|
||||
kernel_filename: extract_string(&file_data, ".kernelp")?,
|
||||
kernel_hash: extract_hash(&file_data, ".kernelh")?,
|
||||
|
||||
initrd_filename: extract_filename(&file_data, ".initrdp")?,
|
||||
initrd_filename: extract_string(&file_data, ".initrdp")?,
|
||||
initrd_hash: extract_hash(&file_data, ".initrdh")?,
|
||||
|
||||
cmdline: extract_string(&file_data, ".cmdline")?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -164,16 +169,13 @@ fn main(handle: Handle, mut system_table: SystemTable<Boot>) -> Status {
|
|||
return Status::SECURITY_VIOLATION;
|
||||
}
|
||||
|
||||
let kernel_cmdline =
|
||||
booted_image_cmdline(system_table.boot_services()).expect("Failed to fetch command line");
|
||||
|
||||
let kernel =
|
||||
Image::load(system_table.boot_services(), &kernel_data).expect("Failed to load the kernel");
|
||||
|
||||
let mut initrd_loader = InitrdLoader::new(system_table.boot_services(), handle, initrd_data)
|
||||
.expect("Failed to load the initrd. It may not be there or it is not signed");
|
||||
|
||||
let status = unsafe { kernel.start(handle, &system_table, &kernel_cmdline) };
|
||||
let status = unsafe { kernel.start(handle, &system_table, &config.cmdline) };
|
||||
|
||||
initrd_loader
|
||||
.uninstall(system_table.boot_services())
|
||||
|
|
|
@ -9,7 +9,7 @@ use uefi::{
|
|||
boot::{AllocateType, MemoryType},
|
||||
Boot, SystemTable,
|
||||
},
|
||||
Handle, Status,
|
||||
CStr16, Handle, Status,
|
||||
};
|
||||
|
||||
/// UEFI mandates 4 KiB pages.
|
||||
|
@ -124,7 +124,7 @@ impl Image {
|
|||
self,
|
||||
handle: Handle,
|
||||
system_table: &SystemTable<Boot>,
|
||||
load_options: &[u8],
|
||||
load_options: &CStr16,
|
||||
) -> Status {
|
||||
let mut loaded_image = system_table
|
||||
.boot_services()
|
||||
|
@ -146,7 +146,7 @@ impl Image {
|
|||
);
|
||||
loaded_image.set_load_options(
|
||||
load_options.as_ptr() as *const u8,
|
||||
u32::try_from(load_options.len()).unwrap(),
|
||||
u32::try_from(load_options.num_bytes()).unwrap(),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -56,15 +56,3 @@ pub fn booted_image_file(boot_services: &BootServices) -> Result<RegularFile> {
|
|||
.into_regular_file()
|
||||
.ok_or(Status::INVALID_PARAMETER)?)
|
||||
}
|
||||
|
||||
/// Return the command line of the currently executing image.
|
||||
pub fn booted_image_cmdline(boot_services: &BootServices) -> Result<Vec<u8>> {
|
||||
let loaded_image =
|
||||
boot_services.open_protocol_exclusive::<LoadedImage>(boot_services.image_handle())?;
|
||||
|
||||
Ok(loaded_image
|
||||
// If this fails, we have no load options and we return an empty string.
|
||||
.load_options_as_bytes()
|
||||
.map(|b| b.to_vec())
|
||||
.unwrap_or_default())
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue