krun_kernel/loader/
mod.rs1use std;
11use std::ffi::CString;
12use std::fmt;
13
14use super::cmdline::Error as CmdlineError;
15use vm_memory::{Address, Bytes, GuestAddress, GuestMemory, GuestMemoryMmap};
16
17#[derive(Debug, Eq, PartialEq)]
18pub enum Error {
19 BigEndianElfOnLittle,
20 InvalidElfMagicNumber,
21 InvalidEntryAddress,
22 InvalidProgramHeaderSize,
23 InvalidProgramHeaderOffset,
24 InvalidProgramHeaderAddress,
25 ReadKernelDataStruct(&'static str),
26 ReadKernelImage,
27 SeekKernelStart,
28 SeekKernelImage,
29 SeekProgramHeader,
30}
31
32impl fmt::Display for Error {
33 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
34 write!(
35 f,
36 "{}",
37 match *self {
38 Error::BigEndianElfOnLittle => "Unsupported ELF File byte order",
39 Error::InvalidElfMagicNumber => "Invalid ELF magic number",
40 Error::InvalidEntryAddress => "Invalid entry address found in ELF header",
41 Error::InvalidProgramHeaderSize => "Invalid ELF program header size",
42 Error::InvalidProgramHeaderOffset => "Invalid ELF program header offset",
43 Error::InvalidProgramHeaderAddress => "Invalid ELF program header address",
44 Error::ReadKernelDataStruct(e) => e,
45 Error::ReadKernelImage => "Failed to write kernel image to guest memory",
46 Error::SeekKernelStart => {
47 "Failed to seek to file offset as pointed by the ELF program header"
48 }
49 Error::SeekKernelImage => "Failed to seek to offset of kernel image",
50 Error::SeekProgramHeader => "Failed to seek to ELF program header",
51 }
52 )
53 }
54}
55
56pub type Result<T> = std::result::Result<T, Error>;
57
58pub fn load_cmdline(
66 guest_mem: &GuestMemoryMmap,
67 guest_addr: GuestAddress,
68 cmdline: &CString,
69) -> std::result::Result<(), CmdlineError> {
70 let raw_cmdline = cmdline.as_bytes_with_nul();
71 if raw_cmdline.len() <= 1 {
72 return Ok(());
73 }
74
75 let cmdline_last_addr = guest_addr
76 .checked_add(raw_cmdline.len() as u64 - 1)
77 .ok_or(CmdlineError::CommandLineOverflow)?; if cmdline_last_addr > guest_mem.last_addr() {
80 return Err(CmdlineError::CommandLineOverflow);
81 }
82
83 guest_mem
84 .write_slice(raw_cmdline, guest_addr)
85 .map_err(|_| CmdlineError::CommandLineCopy)?;
86
87 Ok(())
88}
89
90#[cfg(test)]
91mod tests {
92 use super::super::cmdline::Cmdline;
93 use super::*;
94 use vm_memory::{GuestAddress, GuestMemoryMmap};
95
96 const MEM_SIZE: usize = 0x18_0000;
97
98 fn create_guest_mem() -> GuestMemoryMmap {
99 GuestMemoryMmap::from_ranges(&[(GuestAddress(0x0), MEM_SIZE)]).unwrap()
100 }
101
102 #[test]
103 fn test_cmdline_overflow() {
104 let gm = create_guest_mem();
105 let cmdline_address = GuestAddress((MEM_SIZE - 5) as u64);
106 let mut cmdline = Cmdline::new(10);
107 cmdline.insert_str("12345").unwrap();
108 let cmdline = cmdline.as_cstring().unwrap();
109 assert_eq!(
110 Err(CmdlineError::CommandLineOverflow),
111 load_cmdline(&gm, cmdline_address, &cmdline)
112 );
113 }
114
115 #[test]
116 fn test_cmdline_write_end() {
117 let gm = create_guest_mem();
118 let mut cmdline_address = GuestAddress(45);
119 let mut cmdline = Cmdline::new(10);
120 cmdline.insert_str("1234").unwrap();
121 let cmdline = cmdline.as_cstring().unwrap();
122 assert_eq!(Ok(()), load_cmdline(&gm, cmdline_address, &cmdline));
123 let val: u8 = gm.read_obj(cmdline_address).unwrap();
124 assert_eq!(val, b'1');
125 cmdline_address = cmdline_address.unchecked_add(1);
126 let val: u8 = gm.read_obj(cmdline_address).unwrap();
127 assert_eq!(val, b'2');
128 cmdline_address = cmdline_address.unchecked_add(1);
129 let val: u8 = gm.read_obj(cmdline_address).unwrap();
130 assert_eq!(val, b'3');
131 cmdline_address = cmdline_address.unchecked_add(1);
132 let val: u8 = gm.read_obj(cmdline_address).unwrap();
133 assert_eq!(val, b'4');
134 cmdline_address = cmdline_address.unchecked_add(1);
135 let val: u8 = gm.read_obj(cmdline_address).unwrap();
136 assert_eq!(val, b'\0');
137 }
138}