Skip to main content

krun_kernel/loader/
mod.rs

1// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3//
4// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
5// Use of this source code is governed by a BSD-style license that can be
6// found in the THIRD-PARTY file.
7
8//! Helper for loading a kernel image in the guest memory.
9
10use 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
58/// Writes the command line string to the given memory slice.
59///
60/// # Arguments
61///
62/// * `guest_mem` - A u8 slice that will be partially overwritten by the command line.
63/// * `guest_addr` - The address in `guest_mem` at which to load the command line.
64/// * `cmdline` - The kernel command line as CString.
65pub 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)?; // Extra for null termination.
78
79    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}