Optimize the loading process of the ELF file

1. Load ld.so according to the executable automatically
2. Add the position-independent check for ELF file
This commit is contained in:
LI Qing 2020-12-01 14:00:04 +08:00 committed by Zongmin.Gu
parent 318f1e6a4f
commit 1a00884e1c
2 changed files with 33 additions and 8 deletions

@ -3,7 +3,7 @@ use std::path::Path;
use self::aux_vec::{AuxKey, AuxVec};
use self::exec_loader::{load_exec_file_to_vec, load_file_to_vec};
use super::elf_file::{ElfFile, ElfHeader, ProgramHeader, ProgramHeaderExt};
use super::elf_file::{ElfFile, ElfHeader, ProgramHeader, ProgramHeaderExt, SegmentData};
use super::process::ProcessBuilder;
use super::task::Task;
use super::thread::ThreadName;
@ -117,12 +117,22 @@ fn new_process(
file_path.to_string()
};
let ldso_path = "/lib/ld-musl-x86_64.so.1";
let ldso_elf_buf = load_file_to_vec(ldso_path, current_ref)
.cause_err(|e| errno!(e.errno(), "cannot load ld.so"))?;
let exec_elf_file =
ElfFile::new(&elf_buf).cause_err(|e| errno!(e.errno(), "invalid executable"))?;
// Get the ldso_path of the executable
let exec_interp_segment = exec_elf_file
.program_headers()
.find(|segment| segment.is_interpreter())
.ok_or_else(|| errno!(EINVAL, "cannot find the interpreter segment"))?;
let ldso_path = match exec_interp_segment.get_content(&exec_elf_file) {
SegmentData::Undefined(bytes) => std::ffi::CStr::from_bytes_with_nul(bytes)
.unwrap()
.to_str()
.unwrap(),
_ => return_errno!(EINVAL, "cannot get ldso_path from executable"),
};
let ldso_elf_buf = load_file_to_vec(ldso_path, current_ref)
.cause_err(|e| errno!(e.errno(), "cannot load ld.so"))?;
let ldso_elf_file =
ElfFile::new(&ldso_elf_buf).cause_err(|e| errno!(e.errno(), "invalid ld.so"))?;

@ -4,7 +4,7 @@ use xmas_elf::{header, program, sections};
use crate::prelude::*;
pub use xmas_elf::header::HeaderPt2 as ElfHeader;
pub use xmas_elf::program::{ProgramHeader, ProgramIter};
pub use xmas_elf::program::{ProgramHeader, ProgramIter, SegmentData};
#[derive(Debug)]
pub struct ElfFile<'a> {
@ -37,6 +37,10 @@ impl<'a> ElfFile<'a> {
// Validate the ELF header
xmas_elf::header::sanity_check(elf_inner)
.map_err(|e| errno!(ENOEXEC, "invalid ELF header"))?;
// Validate ELF type
if elf_inner.header.pt2.type_().as_type() != xmas_elf::header::Type::SharedObject {
return_errno!(ENOEXEC, "ELF is not position-independent");
}
// Validate the segments
for segment in elf_inner.program_iter() {
segment.validate()?;
@ -45,18 +49,29 @@ impl<'a> ElfFile<'a> {
}
}
pub trait ProgramHeaderExt {
pub trait ProgramHeaderExt<'a> {
fn loadable(&self) -> bool;
fn is_interpreter(&self) -> bool;
fn validate(&self) -> Result<()>;
fn get_content(&self, elf_file: &ElfFile<'a>) -> SegmentData<'a>;
}
impl<'a> ProgramHeaderExt for ProgramHeader<'a> {
impl<'a> ProgramHeaderExt<'a> for ProgramHeader<'a> {
/// Is the segment loadable?
fn loadable(&self) -> bool {
let type_ = self.get_type().unwrap();
type_ == xmas_elf::program::Type::Load
}
fn is_interpreter(&self) -> bool {
let type_ = self.get_type().unwrap();
type_ == xmas_elf::program::Type::Interp
}
fn get_content(&self, elf_file: &ElfFile<'a>) -> SegmentData<'a> {
self.get_data(&elf_file.elf_inner).unwrap()
}
/// Do some basic sanity checks in case the ELF is corrupted somehow
fn validate(&self) -> Result<()> {
let ph64 = match self {