1use std::cmp::max;
9use std::io;
10use std::io::BufRead;
11use std::io::Read;
12use std::io::Seek;
13use std::io::SeekFrom;
14use std::mem::size_of_val;
15
16use base::warn;
17use base::FileGetLen;
18use base::FileReadWriteAtVolatile;
19use base::VolatileSlice;
20use data_model::Le32;
21use data_model::Le64;
22use lz4_flex::frame::FrameDecoder as Lz4FrameDecoder;
23use resources::AddressRange;
24use vm_memory::GuestAddress;
25use vm_memory::GuestMemory;
26use zerocopy::FromBytes;
27use zerocopy::FromZeros;
28use zerocopy::Immutable;
29use zerocopy::IntoBytes;
30use zerocopy::KnownLayout;
31
32use crate::ElfClass;
33use crate::Error;
34use crate::LoadedKernel;
35use crate::Result;
36
37#[derive(Copy, Clone, FromBytes, Immutable, IntoBytes, KnownLayout)]
38#[allow(unused)]
39#[repr(C)]
40struct Arm64ImageHeader {
41 code0: Le32,
42 code1: Le32,
43 text_offset: Le64,
44 image_size: Le64,
45 flags: Le64,
46 res2: Le64,
47 res3: Le64,
48 res4: Le64,
49 magic: Le32,
50 res5: Le32,
51}
52
53const ARM64_IMAGE_MAGIC: u32 = 0x644d5241; const ARM64_IMAGE_FLAG_BE_MASK: u64 = 0x1;
56
57const ARM64_TEXT_OFFSET_DEFAULT: u64 = 0x80000;
58
59impl Arm64ImageHeader {
60 fn parse_load_addr(&self, kernel_start: GuestAddress) -> Result<GuestAddress> {
61 let magic: u32 = self.magic.into();
62 if magic != ARM64_IMAGE_MAGIC {
63 return Err(Error::InvalidMagicNumber);
64 }
65
66 let flags: u64 = self.flags.into();
67 if flags & ARM64_IMAGE_FLAG_BE_MASK != 0 {
68 return Err(Error::BigEndianOnLittle);
69 }
70
71 let mut text_offset: u64 = self.text_offset.into();
72 let image_size: u64 = self.image_size.into();
73
74 if image_size == 0 {
75 warn!("arm64 Image header has an effective size of zero");
76 text_offset = ARM64_TEXT_OFFSET_DEFAULT;
79 }
80
81 kernel_start
83 .checked_add(text_offset)
84 .ok_or(Error::InvalidKernelOffset)
85 }
86}
87
88pub fn load_arm64_kernel<F>(
89 guest_mem: &GuestMemory,
90 kernel_start: GuestAddress,
91 kernel_image: &mut F,
92) -> Result<LoadedKernel>
93where
94 F: FileReadWriteAtVolatile + FileGetLen,
95{
96 let mut header = Arm64ImageHeader::new_zeroed();
97 kernel_image
98 .read_exact_at_volatile(VolatileSlice::new(header.as_mut_bytes()), 0)
99 .map_err(|_| Error::ReadHeader)?;
100 let load_addr = header.parse_load_addr(kernel_start)?;
101
102 let file_size = kernel_image.get_len().map_err(|_| Error::SeekKernelEnd)?;
103 let load_size = usize::try_from(file_size).map_err(|_| Error::InvalidKernelSize)?;
104 let range_size = max(file_size, u64::from(header.image_size));
105
106 let guest_slice = guest_mem
107 .get_slice_at_addr(load_addr, load_size)
108 .map_err(|_| Error::ReadKernelImage)?;
109 kernel_image
110 .read_exact_at_volatile(guest_slice, 0)
111 .map_err(|_| Error::ReadKernelImage)?;
112
113 Ok(LoadedKernel {
114 size: file_size,
115 address_range: AddressRange::from_start_and_size(load_addr.offset(), range_size)
116 .ok_or(Error::InvalidKernelSize)?,
117 entry: load_addr,
118 class: ElfClass::ElfClass64,
119 })
120}
121
122fn load_arm64_kernel_from_reader<F: BufRead>(
123 guest_mem: &GuestMemory,
124 kernel_start: GuestAddress,
125 mut kernel_image: F,
126) -> Result<LoadedKernel> {
127 let mut header = Arm64ImageHeader::new_zeroed();
128 let header_size = u64::try_from(size_of_val(&header)).unwrap();
129
130 kernel_image
132 .read_exact(header.as_mut_bytes())
133 .map_err(|_| Error::ReadHeader)?;
134 let load_addr = header.parse_load_addr(kernel_start)?;
135
136 guest_mem
138 .write_all_at_addr(header.as_bytes(), load_addr)
139 .map_err(|_| Error::ReadKernelImage)?;
140
141 let mut current_addr = load_addr
143 .checked_add(header_size)
144 .ok_or(Error::InvalidKernelSize)?;
145 loop {
146 let buf = match kernel_image.fill_buf() {
147 Ok([]) => break,
148 Ok(buf) => buf,
149 Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
150 Err(_) => return Err(Error::ReadKernelImage),
151 };
152
153 guest_mem
154 .write_all_at_addr(buf, current_addr)
155 .map_err(|_| Error::ReadKernelImage)?;
156
157 let consumed = buf.len();
158 kernel_image.consume(consumed);
159
160 let offset = u64::try_from(consumed).map_err(|_| Error::InvalidKernelSize)?;
161 current_addr = current_addr
162 .checked_add(offset)
163 .ok_or(Error::InvalidKernelSize)?;
164 }
165
166 let file_size = current_addr.offset_from(load_addr);
167 let range_size = max(file_size, u64::from(header.image_size));
168 Ok(LoadedKernel {
169 size: file_size,
170 address_range: AddressRange::from_start_and_size(load_addr.offset(), range_size)
171 .ok_or(Error::InvalidKernelSize)?,
172 entry: load_addr,
173 class: ElfClass::ElfClass64,
174 })
175}
176
177pub fn load_arm64_kernel_lz4<F: Read + Seek>(
178 guest_mem: &GuestMemory,
179 kernel_start: GuestAddress,
180 mut kernel_image: F,
181) -> Result<LoadedKernel> {
182 kernel_image
183 .seek(SeekFrom::Start(0))
184 .map_err(|_| Error::SeekKernelStart)?;
185 load_arm64_kernel_from_reader(
186 guest_mem,
187 kernel_start,
188 &mut Lz4FrameDecoder::new(kernel_image),
189 )
190}
191
192#[cfg(test)]
193mod test {
194 use std::fs::File;
195 use std::io::Seek;
196 use std::io::SeekFrom;
197 use std::io::Write;
198
199 use tempfile::tempfile;
200 use vm_memory::GuestAddress;
201 use vm_memory::GuestMemory;
202
203 use crate::load_arm64_kernel;
204 use crate::load_arm64_kernel_lz4;
205 use crate::Error;
206
207 const MEM_SIZE: u64 = 0x200_0000;
208
209 fn create_guest_mem() -> GuestMemory {
210 GuestMemory::new(&[(GuestAddress(0x0), MEM_SIZE)]).unwrap()
211 }
212
213 #[allow(clippy::unusual_byte_groupings)]
214 fn write_valid_kernel() -> File {
215 let mut f = tempfile().expect("failed to create tempfile");
216
217 f.write_all(&[0x00, 0xC0, 0x2E, 0x14]).unwrap(); f.write_all(&[0x00, 0x00, 0x00, 0x00]).unwrap(); f.write_all(&0x00000000_00E70000u64.to_le_bytes()).unwrap(); f.write_all(&0x00000000_0000000Au64.to_le_bytes()).unwrap(); f.write_all(&0x00000000_00000000u64.to_le_bytes()).unwrap(); f.write_all(&0x00000000_00000000u64.to_le_bytes()).unwrap(); f.write_all(&0x00000000_00000000u64.to_le_bytes()).unwrap(); f.write_all(&0x00000000_00000000u64.to_le_bytes()).unwrap(); f.write_all(&0x644D5241u32.to_le_bytes()).unwrap(); f.write_all(&0x00000000u32.to_le_bytes()).unwrap(); f.set_len(0xDC3808).unwrap();
229 f
230 }
231
232 fn mutate_file(mut f: &File, offset: u64, val: &[u8]) {
233 f.seek(SeekFrom::Start(offset))
234 .expect("failed to seek file");
235 f.write_all(val)
236 .expect("failed to write mutated value to file");
237 }
238
239 #[test]
240 fn load_arm64_valid() {
241 let gm = create_guest_mem();
242 let kernel_addr = GuestAddress(2 * 1024 * 1024);
243 let mut f = write_valid_kernel();
244 let kernel = load_arm64_kernel(&gm, kernel_addr, &mut f).unwrap();
245 assert_eq!(kernel.address_range.start, 0x107_0000);
246 assert_eq!(kernel.address_range.end, 0x1E3_3807);
247 assert_eq!(kernel.size, 0xDC_3808);
248 assert_eq!(kernel.entry, GuestAddress(0x107_0000));
249 }
250
251 #[test]
252 fn load_arm64_image_size_zero() {
253 let gm = create_guest_mem();
254 let kernel_addr = GuestAddress(2 * 1024 * 1024);
255 let mut f = write_valid_kernel();
256
257 mutate_file(&f, 16, &0u64.to_le_bytes());
259
260 let kernel = load_arm64_kernel(&gm, kernel_addr, &mut f).unwrap();
261 assert_eq!(kernel.address_range.start, 0x28_0000);
262 assert_eq!(kernel.address_range.end, 0x104_3807);
263 assert_eq!(kernel.size, 0xDC_3808);
264 assert_eq!(kernel.entry, GuestAddress(0x28_0000));
265 }
266
267 #[test]
268 fn load_arm64_bad_magic() {
269 let gm = create_guest_mem();
270 let kernel_addr = GuestAddress(2 * 1024 * 1024);
271 let mut f = write_valid_kernel();
272
273 mutate_file(&f, 56, &[0xCC, 0xCC, 0xCC, 0xCC]);
275
276 assert_eq!(
277 load_arm64_kernel(&gm, kernel_addr, &mut f),
278 Err(Error::InvalidMagicNumber)
279 );
280 }
281
282 fn write_valid_kernel_lz4() -> File {
283 let mut f = tempfile().expect("failed to create tempfile");
284
285 f.write_all(&0x184d2204u32.to_le_bytes()).unwrap(); f.write_all(&[0x44, 0x70, 0x1d]).unwrap(); f.write_all(&0x00004065u32.to_le_bytes()).unwrap();
290 f.write_all(&[
291 0x51, 0x00, 0xc0, 0x2e, 0x14, 0x00, 0x01, 0x00, 0x11, 0xe7, 0x06, 0x00, 0x11, 0x0a,
292 0x06, 0x00, 0x0f, 0x02, 0x00, 0x0f, 0x4f, 0x41, 0x52, 0x4d, 0x64, 0x26, 0x00, 0x0f,
293 0x0f, 0x02, 0x00,
294 ])
295 .unwrap();
296 f.write_all(&[0xff; 16447]).unwrap();
297
298 f.write_all(&0x000050c9u32.to_le_bytes()).unwrap();
300 f.write_all(&[
301 0x00, 0x00, 0x00, 0x4b, 0x40, 0x00, 0x00, 0x1f, 0x00, 0x01, 0x00,
302 ])
303 .unwrap();
304 f.write_all(&[0xff; 16448]).unwrap();
305
306 f.write_all(&0x00005027u32.to_le_bytes()).unwrap();
308 f.write_all(&[
309 0x00, 0x00, 0x00, 0x4b, 0x40, 0x00, 0x00, 0x1f, 0x00, 0x01, 0x00,
310 ])
311 .unwrap();
312 f.write_all(&[0xff; 16448]).unwrap();
313
314 f.write_all(&0x00005027u32.to_le_bytes()).unwrap();
316 f.write_all(&[
317 0x00, 0x00, 0x00, 0x5f, 0x1c, 0x00, 0x00, 0x1f, 0x00, 0x01, 0x00,
318 ])
319 .unwrap();
320 f.write_all(&[0xff; 7252]).unwrap();
321 f.write_all(&[0x43, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00])
322 .unwrap();
323
324 f.write_all(&0x00000000u32.to_le_bytes()).unwrap();
326
327 f.write_all(&0x22a9944cu32.to_le_bytes()).unwrap();
329
330 f
331 }
332
333 fn write_valid_kernel_lz4_legacy() -> File {
334 let mut f = tempfile().expect("failed to create tempfile");
335
336 f.write_all(&0x184c2102u32.to_le_bytes()).unwrap(); f.write_all(&0x000080a6u32.to_le_bytes()).unwrap();
340 f.write_all(&[
341 0x51, 0x00, 0xc0, 0x2e, 0x14, 0x00, 0x01, 0x00, 0x11, 0xe7, 0x06, 0x00, 0x11, 0x0a,
342 0x06, 0x00, 0x0f, 0x02, 0x00, 0x0f, 0x4f, 0x41, 0x52, 0x4d, 0x64, 0x26, 0x00, 0x0f,
343 0x0f, 0x02, 0x00,
344 ])
345 .unwrap();
346 f.write_all(&[0xff; 32896]).unwrap();
347
348 f.write_all(&0x0000500au32.to_le_bytes()).unwrap();
350 f.write_all(&[
351 0x00, 0x00, 0x00, 0x9f, 0x5c, 0x00, 0x00, 0x1f, 0x00, 0x01, 0x00,
352 ])
353 .unwrap();
354 f.write_all(&[0xff; 23700]).unwrap();
355 f.write_all(&[0x83, 0x50, 0x00]).unwrap();
356
357 f.write_all(&[0x00, 0x00, 0x00, 0x00]).unwrap();
359
360 f
361 }
362
363 #[test]
364 fn load_arm64_lz4_valid() {
365 let gm = create_guest_mem();
366 let kernel_addr = GuestAddress(2 * 1024 * 1024);
367 let mut f = write_valid_kernel_lz4();
368 let kernel = load_arm64_kernel_lz4(&gm, kernel_addr, &mut f).unwrap();
369 assert_eq!(kernel.address_range.start, 0x107_0000);
370 assert_eq!(kernel.address_range.end, 0x1E3_3807);
371 assert_eq!(kernel.size, 0xDC_3808);
372 assert_eq!(kernel.entry, GuestAddress(0x107_0000));
373 }
374
375 #[test]
376 fn load_arm64_lz4_bad_magic() {
377 let gm = create_guest_mem();
378 let kernel_addr = GuestAddress(2 * 1024 * 1024);
379 let mut f = write_valid_kernel_lz4();
380
381 mutate_file(&f, 0, &[0xCC, 0xCC, 0xCC, 0xCC]);
382
383 assert_eq!(
384 load_arm64_kernel_lz4(&gm, kernel_addr, &mut f),
385 Err(Error::ReadHeader)
386 );
387 }
388
389 #[test]
390 fn load_arm64_lz4_bad_block() {
391 let gm = create_guest_mem();
392 let kernel_addr = GuestAddress(2 * 1024 * 1024);
393 let mut f = write_valid_kernel_lz4();
394
395 mutate_file(&f, 7, &[0xCC, 0xCC, 0xCC, 0xCC]);
396
397 assert_eq!(
398 load_arm64_kernel_lz4(&gm, kernel_addr, &mut f),
399 Err(Error::ReadHeader)
400 );
401 }
402
403 #[test]
404 fn load_arm64_lz4_legacy_valid() {
405 let gm = create_guest_mem();
406 let kernel_addr = GuestAddress(2 * 1024 * 1024);
407 let mut f = write_valid_kernel_lz4_legacy();
408 let kernel = load_arm64_kernel_lz4(&gm, kernel_addr, &mut f).unwrap();
409 assert_eq!(kernel.address_range.start, 0x107_0000);
410 assert_eq!(kernel.address_range.end, 0x1E3_3807);
411 assert_eq!(kernel.size, 0xDC_3808);
412 assert_eq!(kernel.entry, GuestAddress(0x107_0000));
413 }
414
415 #[test]
416 fn load_arm64_lz4_legacy_bad_magic() {
417 let gm = create_guest_mem();
418 let kernel_addr = GuestAddress(2 * 1024 * 1024);
419 let mut f = write_valid_kernel_lz4_legacy();
420
421 mutate_file(&f, 0, &[0xCC, 0xCC, 0xCC, 0xCC]);
422
423 assert_eq!(
424 load_arm64_kernel_lz4(&gm, kernel_addr, &mut f),
425 Err(Error::ReadHeader)
426 );
427 }
428
429 #[test]
430 fn load_arm64_lz4_legacy_bad_block() {
431 let gm = create_guest_mem();
432 let kernel_addr = GuestAddress(2 * 1024 * 1024);
433 let mut f = write_valid_kernel_lz4_legacy();
434
435 mutate_file(&f, 4, &[0xCC, 0xCC, 0xCC, 0xCC]);
436
437 assert_eq!(
438 load_arm64_kernel_lz4(&gm, kernel_addr, &mut f),
439 Err(Error::ReadHeader)
440 );
441 }
442}