sys_util: remove unsafe struct_util functions
Replace the uses of read_struct() and read_struct_slice() with the
safe DataInit::from_reader() implementation.
BUG=b:197263364
TEST=./test_all
TEST=Boot bzImage kernel
TEST=Boot raw ELF kernel extracted with extract_vmlinux
Change-Id: I80f98243bfb58a7ae93e1686bc4d92b0cd485cda
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/3108249
Tested-by: kokoro <noreply+kokoro@google.com>
Commit-Queue: Daniel Verkamp <dverkamp@chromium.org>
Reviewed-by: Chirantan Ekbote <chirantan@chromium.org>
diff --git a/Cargo.lock b/Cargo.lock
index 4df0e96..31be988 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -600,6 +600,7 @@
version = "0.1.0"
dependencies = [
"base",
+ "data_model",
"libc",
"tempfile",
"vm_memory",
diff --git a/kernel_loader/Cargo.toml b/kernel_loader/Cargo.toml
index 3731fa0..9b1dc13 100644
--- a/kernel_loader/Cargo.toml
+++ b/kernel_loader/Cargo.toml
@@ -4,6 +4,7 @@
edition = "2018"
[dependencies]
+data_model = { path = "../data_model" }
libc = "*"
base = { path = "../base" }
vm_memory = { path = "../vm_memory" }
diff --git a/kernel_loader/src/lib.rs b/kernel_loader/src/lib.rs
index 7f45b34..769b91e 100644
--- a/kernel_loader/src/lib.rs
+++ b/kernel_loader/src/lib.rs
@@ -8,6 +8,7 @@
use std::mem;
use base::AsRawDescriptor;
+use data_model::DataInit;
use vm_memory::{GuestAddress, GuestMemory};
#[allow(dead_code)]
@@ -17,6 +18,12 @@
#[allow(clippy::all)]
mod elf;
+// Elf64_Ehdr is plain old data with no implicit padding.
+unsafe impl data_model::DataInit for elf::Elf64_Ehdr {}
+
+// Elf64_Phdr is plain old data with no implicit padding.
+unsafe impl data_model::DataInit for elf::Elf64_Phdr {}
+
#[derive(Debug, PartialEq)]
pub enum Error {
BigEndianElfOnLittle,
@@ -73,19 +80,15 @@
pub fn load_kernel<F>(
guest_mem: &GuestMemory,
kernel_start: GuestAddress,
- kernel_image: &mut F,
+ mut kernel_image: &mut F,
) -> Result<u64>
where
F: Read + Seek + AsRawDescriptor,
{
- let mut ehdr: elf::Elf64_Ehdr = Default::default();
kernel_image
.seek(SeekFrom::Start(0))
.map_err(|_| Error::SeekElfStart)?;
- unsafe {
- // read_struct is safe when reading a POD struct. It can be used and dropped without issue.
- base::read_struct(kernel_image, &mut ehdr).map_err(|_| Error::ReadElfHeader)?;
- }
+ let ehdr = elf::Elf64_Ehdr::from_reader(&mut kernel_image).map_err(|_| Error::ReadElfHeader)?;
// Sanity checks
if ehdr.e_ident[elf::EI_MAG0 as usize] != elf::ELFMAG0 as u8
@@ -109,11 +112,12 @@
kernel_image
.seek(SeekFrom::Start(ehdr.e_phoff))
.map_err(|_| Error::SeekProgramHeader)?;
- let phdrs: Vec<elf::Elf64_Phdr> = unsafe {
- // Reading the structs is safe for a slice of POD structs.
- base::read_struct_slice(kernel_image, ehdr.e_phnum as usize)
- .map_err(|_| Error::ReadProgramHeader)?
- };
+ let phdrs = (0..ehdr.e_phnum)
+ .enumerate()
+ .map(|_| {
+ elf::Elf64_Phdr::from_reader(&mut kernel_image).map_err(|_| Error::ReadProgramHeader)
+ })
+ .collect::<Result<Vec<elf::Elf64_Phdr>>>()?;
let mut kernel_end = 0;
diff --git a/sys_util/src/lib.rs b/sys_util/src/lib.rs
index 17aa7d5..d83cca2 100644
--- a/sys_util/src/lib.rs
+++ b/sys_util/src/lib.rs
@@ -44,7 +44,6 @@
pub mod signal;
mod signalfd;
mod sock_ctrl_msg;
-mod struct_util;
mod terminal;
mod timerfd;
pub mod vsock;
@@ -70,7 +69,6 @@
pub use crate::signal::*;
pub use crate::signalfd::*;
pub use crate::sock_ctrl_msg::*;
-pub use crate::struct_util::*;
pub use crate::terminal::*;
pub use crate::timerfd::*;
pub use descriptor_reflection::{
diff --git a/sys_util/src/struct_util.rs b/sys_util/src/struct_util.rs
deleted file mode 100644
index 964b311..0000000
--- a/sys_util/src/struct_util.rs
+++ /dev/null
@@ -1,149 +0,0 @@
-// Copyright 2017 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-use std::io::Read;
-use std::mem::size_of;
-
-#[derive(Debug)]
-pub enum Error {
- ReadStruct,
-}
-pub type Result<T> = std::result::Result<T, Error>;
-
-/// Reads a struct from an input buffer.
-///
-/// # Arguments
-///
-/// * `f` - The input to read from. Often this is a file.
-/// * `out` - The struct to fill with data read from `f`.
-///
-/// # Safety
-///
-/// This is unsafe because the struct is initialized to unverified data read from the input.
-/// `read_struct` should only be called to fill plain old data structs. It is not endian safe.
-pub unsafe fn read_struct<T: Copy, F: Read>(f: &mut F, out: &mut T) -> Result<()> {
- let out_slice = std::slice::from_raw_parts_mut(out as *mut T as *mut u8, size_of::<T>());
- f.read_exact(out_slice).map_err(|_| Error::ReadStruct)?;
- Ok(())
-}
-
-/// Reads an array of structs from an input buffer. Returns a Vec of structs initialized with data
-/// from the specified input.
-///
-/// # Arguments
-///
-/// * `f` - The input to read from. Often this is a file.
-/// * `len` - The number of structs to fill with data read from `f`.
-///
-/// # Safety
-///
-/// This is unsafe because the structs are initialized to unverified data read from the input.
-/// `read_struct_slice` should only be called for plain old data structs. It is not endian safe.
-pub unsafe fn read_struct_slice<T: Copy, F: Read>(f: &mut F, len: usize) -> Result<Vec<T>> {
- let mut out: Vec<T> = Vec::with_capacity(len);
- out.set_len(len);
- let out_slice =
- std::slice::from_raw_parts_mut(out.as_ptr() as *mut T as *mut u8, size_of::<T>() * len);
- f.read_exact(out_slice).map_err(|_| Error::ReadStruct)?;
- Ok(out)
-}
-
-#[cfg(test)]
-mod test {
- use super::*;
- use std::io::Cursor;
- use std::mem;
-
- #[derive(Clone, Copy, Debug, Default, PartialEq)]
- struct TestRead {
- a: u64,
- b: u8,
- c: u8,
- d: u8,
- e: u8,
- }
-
- #[test]
- fn struct_basic_read() {
- let orig = TestRead {
- a: 0x7766554433221100,
- b: 0x88,
- c: 0x99,
- d: 0xaa,
- e: 0xbb,
- };
- let source = unsafe {
- // Don't worry it's a test
- std::slice::from_raw_parts(
- &orig as *const _ as *const u8,
- std::mem::size_of::<TestRead>(),
- )
- };
- assert_eq!(mem::size_of::<TestRead>(), mem::size_of_val(&source));
- let mut tr: TestRead = Default::default();
- unsafe {
- read_struct(&mut Cursor::new(source), &mut tr).unwrap();
- }
- assert_eq!(orig, tr);
- }
-
- #[test]
- fn struct_read_past_end() {
- let orig = TestRead {
- a: 0x7766554433221100,
- b: 0x88,
- c: 0x99,
- d: 0xaa,
- e: 0xbb,
- };
- let source = unsafe {
- // Don't worry it's a test
- std::slice::from_raw_parts(
- &orig as *const _ as *const u8,
- std::mem::size_of::<TestRead>() - 1,
- )
- };
- let mut tr: TestRead = Default::default();
- unsafe {
- assert!(read_struct(&mut Cursor::new(source), &mut tr).is_err());
- }
- }
-
- #[test]
- fn struct_slice_read() {
- let orig = vec![
- TestRead {
- a: 0x7766554433221100,
- b: 0x88,
- c: 0x99,
- d: 0xaa,
- e: 0xbb,
- },
- TestRead {
- a: 0x7867564534231201,
- b: 0x02,
- c: 0x13,
- d: 0x24,
- e: 0x35,
- },
- TestRead {
- a: 0x7a69584736251403,
- b: 0x04,
- c: 0x15,
- d: 0x26,
- e: 0x37,
- },
- ];
- let source = unsafe {
- // Don't worry it's a test
- std::slice::from_raw_parts(
- orig.as_ptr() as *const u8,
- std::mem::size_of::<TestRead>() * 3,
- )
- };
-
- let tr: Vec<TestRead> = unsafe { read_struct_slice(&mut Cursor::new(source), 3).unwrap() };
- assert_eq!(orig, tr);
- }
-}
diff --git a/x86_64/src/bzimage.rs b/x86_64/src/bzimage.rs
index 7dd3041..a756a50 100644
--- a/x86_64/src/bzimage.rs
+++ b/x86_64/src/bzimage.rs
@@ -9,6 +9,7 @@
use std::io::{Read, Seek, SeekFrom};
use base::AsRawDescriptor;
+use data_model::DataInit;
use vm_memory::{GuestAddress, GuestMemory};
use crate::bootparam::boot_params;
@@ -55,19 +56,15 @@
pub fn load_bzimage<F>(
guest_mem: &GuestMemory,
kernel_start: GuestAddress,
- kernel_image: &mut F,
+ mut kernel_image: &mut F,
) -> Result<(boot_params, u64)>
where
F: Read + Seek + AsRawDescriptor,
{
- let mut params: boot_params = Default::default();
kernel_image
.seek(SeekFrom::Start(0))
.map_err(|_| Error::SeekBootParams)?;
- unsafe {
- // read_struct is safe when reading a POD struct. It can be used and dropped without issue.
- base::read_struct(kernel_image, &mut params).map_err(|_| Error::ReadBootParams)?;
- }
+ let params = boot_params::from_reader(&mut kernel_image).map_err(|_| Error::ReadBootParams)?;
// bzImage header signature "HdrS"
if params.hdr.header != 0x53726448 {