diff --git a/alioth-cli/src/boot/boot.rs b/alioth-cli/src/boot/boot.rs index fed6b7c2..4bc5ecc8 100644 --- a/alioth-cli/src/boot/boot.rs +++ b/alioth-cli/src/boot/boot.rs @@ -15,7 +15,6 @@ mod config; use std::collections::HashMap; -use std::ffi::CString; use std::mem; use std::path::{Path, PathBuf}; @@ -94,7 +93,7 @@ pub struct BootArgs { /// Command line to pass to the kernel, e.g. `console=ttyS0`. #[arg(short, long, alias = "cmd-line", value_name = "ARGS")] - cmdline: Option, + cmdline: Option>, /// Path to an initramfs image. #[arg(short, long, value_name = "PATH")] diff --git a/alioth-cli/src/boot/boot_test.rs b/alioth-cli/src/boot/boot_test.rs index f9ef5e2b..d7076f63 100644 --- a/alioth-cli/src/boot/boot_test.rs +++ b/alioth-cli/src/boot/boot_test.rs @@ -50,7 +50,7 @@ fn test_parse_args() { let args = BootArgs { firmware: Some(Path::new("stage0.bin").into()), kernel: Some(Path::new("vmlinuz").into()), - cmdline: Some(c"console=ttyS0".into()), + cmdline: Some("console=ttyS0".into()), initramfs: Some(Path::new("initramfs.cpio").into()), cpu: Some("count=16,topology=id_topo".into()), memory: Some("size=128G,backend=anon,shared=true".into()), @@ -119,7 +119,7 @@ fn test_parse_args() { payload: Payload { executable: Some(Executable::Linux(Path::new("vmlinuz").into())), initramfs: Some(Path::new("initramfs.cpio").into()), - cmdline: Some(c"console=ttyS0".to_owned()), + cmdline: Some("console=ttyS0".into()), firmware: Some(Path::new("stage0.bin").into()), }, net: vec![ @@ -299,7 +299,7 @@ fn test_parse_mem_arg( #[case( BootArgs { kernel: Some(Path::new("vmlinuz").into()), - cmdline: Some(c"console=ttyS0".into()), + cmdline: Some("console=ttyS0".into()), initramfs: Some(Path::new("initramfs.cpio").into()), ..Default::default() }, @@ -307,13 +307,13 @@ fn test_parse_mem_arg( firmware: None, initramfs: Some(Path::new("initramfs.cpio").into()), executable: Some(Executable::Linux(Path::new("vmlinuz").into())), - cmdline: Some(c"console=ttyS0".into()), + cmdline: Some("console=ttyS0".into()), } )] #[cfg_attr(target_arch = "x86_64", case( BootArgs { pvh: Some(Path::new("vmlinux.bin").into()), - cmdline: Some(c"console=ttyS0".into()), + cmdline: Some("console=ttyS0".into()), initramfs: Some(Path::new("initramfs.cpio").into()), ..Default::default() }, @@ -321,7 +321,7 @@ fn test_parse_mem_arg( firmware: None, initramfs: Some(Path::new("initramfs.cpio").into()), executable: Some(Executable::Pvh(Path::new("vmlinux.bin").into())), - cmdline: Some(c"console=ttyS0".into()), + cmdline: Some("console=ttyS0".into()), } ))] fn test_parse_payload_arg(#[case] mut args: BootArgs, #[case] want: Payload) { diff --git a/alioth/src/board/board_aarch64.rs b/alioth/src/board/board_aarch64.rs index af0fedf6..ea0a41fe 100644 --- a/alioth/src/board/board_aarch64.rs +++ b/alioth/src/board/board_aarch64.rs @@ -157,8 +157,8 @@ where } let mut node = Node::default(); if let Some(cmdline) = &payload.cmdline { - let bytes = cmdline.as_bytes_with_nul().to_owned(); - node.props.insert("bootargs", PropVal::Bytes(bytes)); + let cmdline = cmdline.to_string(); + node.props.insert("bootargs", PropVal::String(cmdline)); } if let Some(initramfs_range) = &init_state.initramfs { node.props.insert( diff --git a/alioth/src/board/board_x86_64/board_x86_64.rs b/alioth/src/board/board_x86_64/board_x86_64.rs index e6a0d5be..22cd63b1 100644 --- a/alioth/src/board/board_x86_64/board_x86_64.rs +++ b/alioth/src/board/board_x86_64/board_x86_64.rs @@ -182,7 +182,7 @@ where dev.add_kernel_data(image).context(error::FwCfg)?; }; if let Some(cmdline) = &payload.cmdline { - dev.add_kernel_cmdline(cmdline.to_owned()); + dev.add_kernel_cmdline(cmdline).context(error::FwCfg)?; }; if let Some(initramfs) = &payload.initramfs { dev.add_initramfs_data(initramfs).context(error::FwCfg)?; diff --git a/alioth/src/device/fw_cfg/fw_cfg.rs b/alioth/src/device/fw_cfg/fw_cfg.rs index 32a93201..aa0cad25 100644 --- a/alioth/src/device/fw_cfg/fw_cfg.rs +++ b/alioth/src/device/fw_cfg/fw_cfg.rs @@ -339,11 +339,15 @@ impl FwCfg { Ok(()) } - pub fn add_kernel_cmdline(&mut self, s: CString) { - let bytes = s.into_bytes_with_nul(); + pub fn add_kernel_cmdline(&mut self, s: &str) -> Result<()> { + let Ok(c_str) = CString::new(s) else { + return Err(ErrorKind::InvalidInput.into()); + }; + let bytes = c_str.into_bytes_with_nul(); self.known_items[FW_CFG_CMDLINE_SIZE as usize] = FwCfgContent::Lu32((bytes.len() as u32).into()); self.known_items[FW_CFG_CMDLINE_DATA as usize] = FwCfgContent::Bytes(bytes); + Ok(()) } pub fn add_item(&mut self, item: FwCfgItem) -> Result<()> { diff --git a/alioth/src/loader/linux/linux_aarch64.rs b/alioth/src/loader/linux/linux_aarch64.rs index 93410d9e..3b424bb5 100644 --- a/alioth/src/loader/linux/linux_aarch64.rs +++ b/alioth/src/loader/linux/linux_aarch64.rs @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::ffi::CStr; use std::fs::File; use std::io::{BufReader, Read, Seek, SeekFrom}; use std::path::Path; @@ -47,7 +46,7 @@ pub fn load>( memory: &RamBus, mem_regions: &[(u64, MemRegionEntry)], kernel: P, - _cmdline: Option<&CStr>, + _cmdline: Option<&str>, initramfs: Option

, ) -> Result { let access_kernel = error::AccessFile { diff --git a/alioth/src/loader/linux/linux_x86_64.rs b/alioth/src/loader/linux/linux_x86_64.rs index 982ef7df..9af5fb39 100644 --- a/alioth/src/loader/linux/linux_x86_64.rs +++ b/alioth/src/loader/linux/linux_x86_64.rs @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::ffi::CStr; use std::fs::File; use std::io::{BufReader, Read, Seek, SeekFrom}; use std::mem::{size_of, size_of_val}; @@ -46,7 +45,7 @@ pub fn load>( memory: &RamBus, mem_regions: &[(u64, MemRegionEntry)], kernel: P, - cmdline: Option<&CStr>, + cmdline: Option<&str>, initramfs: Option

, ) -> Result { let mut boot_params = BootParams::new_zeroed(); @@ -104,17 +103,20 @@ pub fn load>( // load cmd line if let Some(cmdline) = cmdline { - let cmdline = cmdline.to_bytes_with_nul(); - let cmdline_limit = - std::cmp::min(boot_params.hdr.cmdline_size as u64, KERNEL_CMDLINE_LIMIT); - if cmdline.len() as u64 > cmdline_limit { + let bytes = cmdline.as_bytes(); + let cmdline_limit = std::cmp::min( + boot_params.hdr.cmdline_size as u64 + 1, + KERNEL_CMDLINE_LIMIT, + ); + if bytes.len() as u64 >= cmdline_limit { return error::CmdLineTooLong { - len: cmdline.len(), - limit: cmdline_limit, + len: bytes.len(), + limit: cmdline_limit - 1, } .fail(); } - memory.write_range(KERNEL_CMDLINE_START, cmdline.len() as u64, cmdline)?; + memory.write_range(KERNEL_CMDLINE_START, bytes.len() as u64, bytes)?; + memory.write_t(KERNEL_CMDLINE_START + bytes.len() as u64, &0u8)?; boot_params.hdr.cmdline_ptr = KERNEL_CMDLINE_START as u32; boot_params.ext_cmdline_ptr = (KERNEL_CMDLINE_START >> 32) as u32; } diff --git a/alioth/src/loader/loader.rs b/alioth/src/loader/loader.rs index bfdb753e..04f15726 100644 --- a/alioth/src/loader/loader.rs +++ b/alioth/src/loader/loader.rs @@ -21,7 +21,6 @@ pub mod linux; #[path = "xen/xen.rs"] pub mod xen; -use std::ffi::CString; use std::ops::Range; use std::path::Path; @@ -41,7 +40,7 @@ pub struct Payload { pub firmware: Option>, pub executable: Option, pub initramfs: Option>, - pub cmdline: Option, + pub cmdline: Option>, } #[derive(Debug, PartialEq, Eq, Deserialize)] diff --git a/alioth/src/loader/xen/xen.rs b/alioth/src/loader/xen/xen.rs index 00802b05..b03f7c66 100644 --- a/alioth/src/loader/xen/xen.rs +++ b/alioth/src/loader/xen/xen.rs @@ -14,7 +14,6 @@ pub mod start_info; -use std::ffi::CStr; use std::fs::File; use std::io::{BufReader, Read, Seek, SeekFrom}; use std::mem::{offset_of, size_of, size_of_val}; @@ -104,7 +103,7 @@ pub fn load>( memory: &RamBus, mem_regions: &[(u64, MemRegionEntry)], kernel: P, - cmdline: Option<&CStr>, + cmdline: Option<&str>, initramfs: Option

, ) -> Result { let access_kernel = error::AccessFile { @@ -203,15 +202,16 @@ pub fn load>( // load cmd line if let Some(cmdline) = cmdline { - let cmdline = cmdline.to_bytes_with_nul(); - if cmdline.len() as u64 > KERNEL_CMDLINE_LIMIT { + let bytes = cmdline.as_bytes(); + if bytes.len() as u64 >= KERNEL_CMDLINE_LIMIT { return error::CmdLineTooLong { - len: cmdline.len(), - limit: KERNEL_CMDLINE_LIMIT, + len: bytes.len(), + limit: KERNEL_CMDLINE_LIMIT - 1, } .fail(); } - memory.write_range(KERNEL_CMDLINE_START, cmdline.len() as u64, cmdline)?; + memory.write_range(KERNEL_CMDLINE_START, bytes.len() as u64, bytes)?; + memory.write_t(KERNEL_CMDLINE_START + bytes.len() as u64, &0u8)?; start_info_page.start_info.cmdline_paddr = KERNEL_CMDLINE_START; }