linux_loader/loader/bzimage/
mod.rs1#![cfg(all(feature = "bzimage", any(target_arch = "x86", target_arch = "x86_64")))]
13
14use std::fmt;
15use std::io::{Seek, SeekFrom};
16
17use vm_memory::{Address, ByteValued, GuestAddress, GuestMemory, GuestUsize, ReadVolatile};
18
19use crate::loader::{
20 bootparam, Error as KernelLoaderError, KernelLoader, KernelLoaderResult, Result,
21};
22
23#[derive(Debug, PartialEq, Eq)]
24pub enum Error {
26 InvalidBzImage,
28 Overflow,
30 ReadBzImageHeader,
32 ReadBzImageCompressedKernel,
34 SeekBzImageEnd,
36 SeekBzImageHeader,
38 SeekBzImageCompressedKernel,
40 Underflow,
42}
43
44impl fmt::Display for Error {
45 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46 let desc = match self {
47 Error::InvalidBzImage => "Invalid bzImage",
48 Error::Overflow => "Overflow occurred during an arithmetic operation",
49 Error::ReadBzImageHeader => "Unable to read bzImage header",
50 Error::ReadBzImageCompressedKernel => "Unable to read bzImage compressed kernel",
51 Error::SeekBzImageEnd => "Unable to seek bzImage end",
52 Error::SeekBzImageHeader => "Unable to seek bzImage header",
53 Error::SeekBzImageCompressedKernel => "Unable to seek bzImage compressed kernel",
54 Error::Underflow => "Underflow occurred during an arithmetic operation",
55 };
56
57 write!(f, "Kernel Loader: {}", desc)
58 }
59}
60
61impl std::error::Error for Error {}
62
63pub struct BzImage;
65
66impl KernelLoader for BzImage {
67 fn load<F, M: GuestMemory>(
104 guest_mem: &M,
105 kernel_offset: Option<GuestAddress>,
106 kernel_image: &mut F,
107 highmem_start_address: Option<GuestAddress>,
108 ) -> Result<KernelLoaderResult>
109 where
110 F: ReadVolatile + Seek,
111 {
112 let mut kernel_size = kernel_image
113 .seek(SeekFrom::End(0))
114 .map_err(|_| Error::SeekBzImageEnd)? as usize;
115 kernel_image
116 .seek(SeekFrom::Start(0x1F1))
117 .map_err(|_| Error::SeekBzImageHeader)?;
118
119 let mut boot_header = bootparam::setup_header::default();
120 kernel_image
121 .read_volatile(&mut boot_header.as_bytes())
122 .map_err(|_| Error::ReadBzImageHeader)?;
123
124 if boot_header.header != 0x5372_6448 {
127 return Err(Error::InvalidBzImage.into());
128 }
129
130 if (boot_header.version < 0x0200) || ((boot_header.loadflags & 0x1) == 0x0) {
132 return Err(Error::InvalidBzImage.into());
133 }
134
135 let mut setup_size = boot_header.setup_sects as usize;
136 if setup_size == 0 {
137 setup_size = 4;
138 }
139 setup_size = setup_size
140 .checked_add(1)
141 .and_then(|setup_size| setup_size.checked_mul(512))
142 .ok_or(Error::Overflow)?;
143 kernel_size = kernel_size
144 .checked_sub(setup_size)
145 .ok_or(Error::Underflow)?;
146
147 if (highmem_start_address.is_some())
150 && (u64::from(boot_header.code32_start) < highmem_start_address.unwrap().raw_value())
151 {
152 return Err(KernelLoaderError::InvalidKernelStartAddress);
153 }
154
155 let mem_offset = match kernel_offset {
156 Some(start) => start,
157 None => GuestAddress(u64::from(boot_header.code32_start)),
158 };
159
160 boot_header.code32_start = mem_offset.raw_value() as u32;
161
162 let mut loader_result = KernelLoaderResult {
163 setup_header: Some(boot_header),
164 kernel_load: mem_offset,
165 ..Default::default()
166 };
167
168 kernel_image
170 .seek(SeekFrom::Start(setup_size as u64))
171 .map_err(|_| Error::SeekBzImageCompressedKernel)?;
172 guest_mem
173 .read_exact_volatile_from(mem_offset, kernel_image, kernel_size)
174 .map_err(|_| Error::ReadBzImageCompressedKernel)?;
175
176 loader_result.kernel_end = mem_offset
177 .raw_value()
178 .checked_add(kernel_size as GuestUsize)
179 .ok_or(KernelLoaderError::MemoryOverflow)?;
180
181 Ok(loader_result)
182 }
183}
184
185#[cfg(test)]
186mod tests {
187 use super::*;
188
189 use std::fs::File;
190 use std::io::{Cursor, Read};
191 use std::process::Command;
192 use vm_memory::{Address, GuestAddress};
193 type GuestMemoryMmap = vm_memory::GuestMemoryMmap<()>;
194
195 const MEM_SIZE: u64 = 0x100_0000;
196
197 fn create_guest_mem() -> GuestMemoryMmap {
198 GuestMemoryMmap::from_ranges(&[(GuestAddress(0x0), (MEM_SIZE as usize))]).unwrap()
199 }
200
201 fn download_resources() {
202 let command = "./.buildkite/download_resources.sh";
203 let status = Command::new(command).status().unwrap();
204 if !status.success() {
205 panic!("Cannot run build script");
206 }
207 }
208
209 fn make_bzimage() -> Vec<u8> {
210 download_resources();
211 let mut v = Vec::new();
212 let path = concat!(env!("CARGO_MANIFEST_DIR"), "/src/loader/bzimage/bzimage");
213 let mut f = File::open(path).unwrap();
214 f.read_to_end(&mut v).unwrap();
215
216 v
217 }
218
219 #[allow(non_snake_case)]
220 #[test]
221 fn test_load_bzImage() {
222 let gm = create_guest_mem();
223 let image = make_bzimage();
224 let mut kernel_offset = GuestAddress(0x200000);
225 let mut highmem_start_address = GuestAddress(0x0);
226
227 let mut loader_result = BzImage::load(
229 &gm,
230 Some(kernel_offset),
231 &mut Cursor::new(&image),
232 Some(highmem_start_address),
233 )
234 .unwrap();
235 let setup_header = loader_result.setup_header.unwrap();
236
237 assert_eq!(loader_result.kernel_load.raw_value(), 0x200000);
238 assert_eq!(
239 unsafe { std::ptr::addr_of!(setup_header.header).read_unaligned() },
243 0x53726448
244 );
245 assert_eq!(
246 unsafe { std::ptr::addr_of!(setup_header.version).read_unaligned() },
250 0x20f
251 );
252 assert_eq!(loader_result.setup_header.unwrap().loadflags, 1);
253 assert_eq!(loader_result.kernel_end, 0x8b5e40);
254
255 loader_result = BzImage::load(
257 &gm,
258 None,
259 &mut Cursor::new(&image),
260 Some(highmem_start_address),
261 )
262 .unwrap();
263 let setup_header = loader_result.setup_header.unwrap();
264
265 assert_eq!(loader_result.kernel_load.raw_value(), 0x100000);
266
267 loader_result = BzImage::load(&gm, None, &mut Cursor::new(&image), None).unwrap();
269 assert_eq!(
271 0x53726448,
272 unsafe { std::ptr::addr_of!(setup_header.header).read_unaligned() }
276 );
277 assert_eq!(loader_result.kernel_load.raw_value(), 0x100000);
278
279 kernel_offset = GuestAddress(0x1000);
281 highmem_start_address = GuestAddress(0x200000);
282
283 assert_eq!(
284 Some(KernelLoaderError::InvalidKernelStartAddress),
285 BzImage::load(
286 &gm,
287 Some(kernel_offset),
288 &mut Cursor::new(&image),
289 Some(highmem_start_address),
290 )
291 .err()
292 );
293 }
294
295 #[test]
296 fn test_invalid_bzimage_underflow() {
297 use crate::loader::Error as LoaderError;
298
299 let path = concat!(
300 env!("CARGO_MANIFEST_DIR"),
301 "/src/loader/bzimage/fuzz_invalid_bzimage.bin"
302 );
303
304 let gm = create_guest_mem();
305 let mut image = File::open(path).unwrap();
306 let kernel_offset = GuestAddress(0x200000);
307 let highmem_start_address = GuestAddress(0x0);
308
309 let loader_result = BzImage::load(
311 &gm,
312 Some(kernel_offset),
313 &mut image,
314 Some(highmem_start_address),
315 );
316
317 assert_eq!(
318 loader_result.unwrap_err(),
319 LoaderError::Bzimage(Error::Underflow)
320 );
321 }
322}