Merge branch 'patch5' into 'master'
fix(ld.so): errors UB See merge request redox-os/relibc!595
This commit is contained in:
+18
-11
@@ -1,19 +1,19 @@
|
||||
//! dlfcn implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/dlfcn.h.html
|
||||
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
// FIXME(andypython): remove this when #![allow(warnings, unused_variables)] is
|
||||
// dropped from src/lib.rs.
|
||||
#![warn(warnings, unused_variables)]
|
||||
|
||||
use core::{
|
||||
ptr::{self, NonNull},
|
||||
str,
|
||||
ptr, str,
|
||||
sync::atomic::{AtomicUsize, Ordering},
|
||||
};
|
||||
|
||||
use alloc::sync::Arc;
|
||||
|
||||
use crate::{
|
||||
c_str::CStr,
|
||||
ld_so::{
|
||||
linker::{ObjectHandle, ObjectScope, Resolve},
|
||||
linker::{DlError, ObjectHandle, ObjectScope, Resolve},
|
||||
tcb::Tcb,
|
||||
},
|
||||
platform::types::*,
|
||||
@@ -32,7 +32,12 @@ static ERROR_NOT_SUPPORTED: CStr = c_str!("dlfcn not supported");
|
||||
#[thread_local]
|
||||
static ERROR: AtomicUsize = AtomicUsize::new(0);
|
||||
|
||||
fn set_last_error(error: DlError) {
|
||||
ERROR.store(error.repr().as_ptr() as usize, Ordering::SeqCst);
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub struct Dl_info {
|
||||
dli_fname: *const c_char,
|
||||
dli_fbase: *mut c_void,
|
||||
@@ -41,7 +46,7 @@ pub struct Dl_info {
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dladdr(addr: *mut c_void, info: *mut Dl_info) -> c_int {
|
||||
pub unsafe extern "C" fn dladdr(_addr: *mut c_void, info: *mut Dl_info) -> c_int {
|
||||
//TODO
|
||||
unsafe {
|
||||
(*info).dli_fname = ptr::null();
|
||||
@@ -86,11 +91,13 @@ pub unsafe extern "C" fn dlopen(cfilename: *const c_char, flags: c_int) -> *mut
|
||||
return ptr::null_mut();
|
||||
}
|
||||
};
|
||||
|
||||
if tcb.linker_ptr.is_null() {
|
||||
ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
|
||||
return ptr::null_mut();
|
||||
}
|
||||
let mut linker = unsafe { (&*tcb.linker_ptr).lock() };
|
||||
|
||||
let mut linker = unsafe { (*tcb.linker_ptr).lock() };
|
||||
|
||||
let cbs_c = linker.cbs.clone();
|
||||
let cbs = cbs_c.borrow();
|
||||
@@ -98,7 +105,7 @@ pub unsafe extern "C" fn dlopen(cfilename: *const c_char, flags: c_int) -> *mut
|
||||
match (cbs.load_library)(&mut linker, filename, resolve, scope, noload) {
|
||||
Ok(handle) => handle.as_ptr().cast_mut(),
|
||||
Err(error) => {
|
||||
ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
|
||||
set_last_error(error);
|
||||
ptr::null_mut()
|
||||
}
|
||||
}
|
||||
@@ -131,7 +138,7 @@ pub unsafe extern "C" fn dlsym(handle: *mut c_void, symbol: *const c_char) -> *m
|
||||
return ptr::null_mut();
|
||||
}
|
||||
|
||||
let linker = unsafe { (&*tcb.linker_ptr).lock() };
|
||||
let linker = unsafe { (*tcb.linker_ptr).lock() };
|
||||
let cbs_c = linker.cbs.clone();
|
||||
let cbs = cbs_c.borrow();
|
||||
match (cbs.get_sym)(&linker, handle, symbol_str) {
|
||||
@@ -159,11 +166,11 @@ pub unsafe extern "C" fn dlclose(handle: *mut c_void) -> c_int {
|
||||
};
|
||||
|
||||
let Some(handle) = ObjectHandle::from_ptr(handle) else {
|
||||
ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
|
||||
set_last_error(DlError::InvalidHandle);
|
||||
return -1;
|
||||
};
|
||||
|
||||
let mut linker = unsafe { (&*tcb.linker_ptr).lock() };
|
||||
let mut linker = unsafe { (*tcb.linker_ptr).lock() };
|
||||
let cbs_c = linker.cbs.clone();
|
||||
let cbs = cbs_c.borrow();
|
||||
(cbs.unload)(&mut linker, handle);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use super::linker::{Linker, ObjectHandle, ObjectScope, Resolve};
|
||||
use super::linker::{Linker, ObjectHandle, ObjectScope, Resolve, Result};
|
||||
use crate::platform::types::c_void;
|
||||
use alloc::boxed::Box;
|
||||
use goblin::error::Result;
|
||||
|
||||
pub struct LinkerCallbacks {
|
||||
pub unload: Box<dyn Fn(&mut Linker, ObjectHandle)>,
|
||||
|
||||
+4
-5
@@ -1,5 +1,6 @@
|
||||
use crate::{c_str::CString, platform::types::*};
|
||||
use alloc::boxed::Box;
|
||||
use core::ptr;
|
||||
|
||||
#[repr(C)]
|
||||
pub enum RTLDState {
|
||||
@@ -50,7 +51,6 @@ impl RTLDDebug {
|
||||
} else {
|
||||
unsafe { (*self.r_map).add_object(l_addr, name, l_ld) };
|
||||
}
|
||||
return;
|
||||
}
|
||||
pub fn insert_first(&mut self, l_addr: usize, name: &str, l_ld: usize) {
|
||||
if self.r_map.is_null() {
|
||||
@@ -60,7 +60,6 @@ impl RTLDDebug {
|
||||
self.r_map = LinkMap::new_with_args(l_addr, name, l_ld);
|
||||
unsafe { (*self.r_map).link(&mut *tmp) };
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,10 +82,10 @@ impl LinkMap {
|
||||
fn new() -> *mut Self {
|
||||
let map = Box::new(LinkMap {
|
||||
l_addr: 0,
|
||||
l_name: 0 as *const c_char,
|
||||
l_name: ptr::null(),
|
||||
l_ld: 0,
|
||||
l_next: 0 as *mut LinkMap,
|
||||
l_prev: 0 as *mut LinkMap,
|
||||
l_next: ptr::null_mut(),
|
||||
l_prev: ptr::null_mut(),
|
||||
});
|
||||
Box::into_raw(map)
|
||||
}
|
||||
|
||||
+33
-30
@@ -93,7 +93,7 @@ pub struct DSO {
|
||||
impl DSO {
|
||||
pub fn new(
|
||||
path: &str,
|
||||
data: &Vec<u8>,
|
||||
data: &[u8],
|
||||
base_addr: Option<usize>,
|
||||
dlopened: bool,
|
||||
id: usize,
|
||||
@@ -101,13 +101,13 @@ impl DSO {
|
||||
tls_offset: usize,
|
||||
) -> Result<(DSO, Option<Master>)> {
|
||||
let elf = Elf::parse(data)?;
|
||||
let (mmap, tcb_master) = DSO::mmap_and_copy(&path, &elf, &data, base_addr, tls_offset)?;
|
||||
let (global_syms, weak_syms) = DSO::collect_syms(&elf, &mmap)?;
|
||||
let (mmap, tcb_master) = DSO::mmap_and_copy(path, &elf, data, base_addr, tls_offset)?;
|
||||
let (global_syms, weak_syms) = DSO::collect_syms(&elf, mmap)?;
|
||||
let (init_array, fini_array) = DSO::init_fini_arrays(&elf, mmap.as_ptr() as usize);
|
||||
|
||||
let name = match elf.soname {
|
||||
Some(soname) => soname.to_string(),
|
||||
_ => basename(&path),
|
||||
_ => basename(path),
|
||||
};
|
||||
let tls_offset = match tcb_master {
|
||||
Some(ref master) => master.offset,
|
||||
@@ -123,7 +123,7 @@ impl DSO {
|
||||
id,
|
||||
dlopened,
|
||||
entry_point,
|
||||
runpath: DSO::get_runpath(&path, &elf)?,
|
||||
runpath: DSO::get_runpath(path, &elf)?,
|
||||
mmap,
|
||||
global_syms,
|
||||
weak_syms,
|
||||
@@ -138,7 +138,7 @@ impl DSO {
|
||||
tls_offset,
|
||||
|
||||
pie: is_pie_enabled(&elf),
|
||||
dynamic: elf.dynamic.map(|dynamic| dynamic),
|
||||
dynamic: elf.dynamic,
|
||||
dynsyms: elf.dynsyms.iter().collect(),
|
||||
|
||||
scope: Scope::local(),
|
||||
@@ -149,10 +149,7 @@ impl DSO {
|
||||
|
||||
/// Global Offset Table
|
||||
pub(super) fn got(&self) -> Option<NonNull<usize>> {
|
||||
let Some(dynamic) = self.dynamic.as_ref() else {
|
||||
return None;
|
||||
};
|
||||
|
||||
let dynamic = self.dynamic.as_ref()?;
|
||||
let object_base_addr = self.mmap.as_ptr() as u64;
|
||||
|
||||
let got = if let Some(ptr) = {
|
||||
@@ -178,10 +175,10 @@ impl DSO {
|
||||
pub fn get_sym(&self, name: &str) -> Option<(Symbol, SymbolBinding)> {
|
||||
if let Some(value) = self.global_syms.get(name) {
|
||||
Some((*value, SymbolBinding::Global))
|
||||
} else if let Some(value) = self.weak_syms.get(name) {
|
||||
Some((*value, SymbolBinding::Weak))
|
||||
} else {
|
||||
None
|
||||
self.weak_syms
|
||||
.get(name)
|
||||
.map(|value| (*value, SymbolBinding::Weak))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,7 +187,9 @@ impl DSO {
|
||||
let (addr, size) = self.init_array;
|
||||
for i in (0..size).step_by(8) {
|
||||
let func = transmute::<usize, *const Option<extern "C" fn()>>(addr + i);
|
||||
(*func).map(|x| x());
|
||||
if let Some(f) = *func {
|
||||
f();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -200,7 +199,9 @@ impl DSO {
|
||||
let (addr, size) = self.fini_array;
|
||||
for i in (0..size).step_by(8).rev() {
|
||||
let func = transmute::<usize, *const Option<extern "C" fn()>>(addr + i);
|
||||
(*func).map(|x| x());
|
||||
if let Some(f) = *func {
|
||||
f();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -220,13 +221,14 @@ impl DSO {
|
||||
_ => return Ok(None),
|
||||
}
|
||||
}
|
||||
return Ok(None);
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn mmap_and_copy(
|
||||
path: &str,
|
||||
elf: &Elf,
|
||||
data: &Vec<u8>,
|
||||
data: &[u8],
|
||||
base_addr: Option<usize>,
|
||||
tls_offset: usize,
|
||||
) -> Result<(&'static mut [u8], Option<Master>)> {
|
||||
@@ -269,12 +271,12 @@ impl DSO {
|
||||
// Allocate memory
|
||||
let mmap = unsafe {
|
||||
if let Some(addr) = base_addr {
|
||||
let size = if is_pie_enabled(&elf) {
|
||||
let size = if is_pie_enabled(elf) {
|
||||
bounds.1
|
||||
} else {
|
||||
bounds.1 - bounds.0
|
||||
};
|
||||
_r_debug.insert_first(addr as usize, path, addr + l_ld as usize);
|
||||
_r_debug.insert_first(addr, path, addr + l_ld as usize);
|
||||
slice::from_raw_parts_mut(addr as *mut u8, size)
|
||||
} else {
|
||||
let (start, end) = bounds;
|
||||
@@ -371,7 +373,7 @@ impl DSO {
|
||||
}
|
||||
};
|
||||
tcb_master = Some(Master {
|
||||
ptr: ptr,
|
||||
ptr,
|
||||
len: ph.p_filesz as usize,
|
||||
offset: tls_offset + vsize,
|
||||
});
|
||||
@@ -384,13 +386,11 @@ impl DSO {
|
||||
let mut debug_start = None;
|
||||
// next we identify the location of DT_DEBUG in .dynamic section
|
||||
if let Some(dynamic) = elf.dynamic.as_ref() {
|
||||
let mut i = 0;
|
||||
for entry in &dynamic.dyns {
|
||||
for (i, entry) in dynamic.dyns.iter().enumerate() {
|
||||
if entry.d_tag == DT_DEBUG {
|
||||
debug_start = Some(i as usize);
|
||||
debug_start = Some(i);
|
||||
break;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
if let Some(i) = debug_start {
|
||||
@@ -408,7 +408,8 @@ impl DSO {
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
return Ok((mmap, tcb_master));
|
||||
|
||||
Ok((mmap, tcb_master))
|
||||
}
|
||||
|
||||
fn collect_syms(
|
||||
@@ -458,7 +459,8 @@ impl DSO {
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
return Ok((globals, weak_syms));
|
||||
|
||||
Ok((globals, weak_syms))
|
||||
}
|
||||
|
||||
fn init_fini_arrays(elf: &Elf, mmap_addr: usize) -> ((usize, usize), (usize, usize)) {
|
||||
@@ -480,7 +482,8 @@ impl DSO {
|
||||
fini_array = (addr, section.sh_size as usize);
|
||||
}
|
||||
}
|
||||
return (init_array, fini_array);
|
||||
|
||||
(init_array, fini_array)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -492,15 +495,15 @@ impl Drop for DSO {
|
||||
}
|
||||
|
||||
pub fn is_pie_enabled(elf: &Elf) -> bool {
|
||||
return elf.header.e_type == ET_DYN;
|
||||
elf.header.e_type == ET_DYN
|
||||
}
|
||||
|
||||
fn basename(path: &str) -> String {
|
||||
return path.split("/").last().unwrap_or(path).to_string();
|
||||
path.split("/").last().unwrap_or(path).to_string()
|
||||
}
|
||||
|
||||
fn dirname(path: &str) -> String {
|
||||
let mut parts: Vec<&str> = path.split("/").collect();
|
||||
parts.truncate(parts.len() - 1);
|
||||
return parts.join("/");
|
||||
parts.join("/")
|
||||
}
|
||||
|
||||
+126
-60
@@ -10,10 +10,7 @@ use core::{
|
||||
mem::transmute,
|
||||
ptr::{self, NonNull},
|
||||
};
|
||||
use goblin::{
|
||||
elf::{dynamic::DT_STRTAB, program_header, reloc, sym::STT_TLS, Elf},
|
||||
error::{Error, Result},
|
||||
};
|
||||
use goblin::elf::{dynamic::DT_STRTAB, program_header, reloc, sym::STT_TLS, Elf};
|
||||
|
||||
use crate::{
|
||||
c_str::{CStr, CString},
|
||||
@@ -41,14 +38,37 @@ use super::{
|
||||
PATH_SEP,
|
||||
};
|
||||
|
||||
// FIXME: ERROR HANDLING IS WRONG!
|
||||
// load_library may return an error which may have some variants heap allocated.
|
||||
// eg Error::Malformed(String::from("failed to locate 'libfoo.so'"))
|
||||
// therefore dropping it in dlopen would cause heap corruption as it was allocated
|
||||
// by the dynamic linker's and was freed by the program.
|
||||
// do better errors than just goblin::Error::Malformed
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum DlError {
|
||||
/// Failed to locate the requested DSO.
|
||||
NotFound,
|
||||
/// The DSO is malformed somehow.
|
||||
Malformed,
|
||||
/// Invalid DSO handle.
|
||||
InvalidHandle,
|
||||
}
|
||||
|
||||
impl DlError {
|
||||
/// Returns a human-readable, null-terminated C string describing the error.
|
||||
pub fn repr(&self) -> CStr<'static> {
|
||||
match self {
|
||||
DlError::NotFound => c_str!(
|
||||
"Failed to locate the requested DSO. Set `LD_DEBUG=all` for more information."
|
||||
),
|
||||
|
||||
DlError::Malformed => {
|
||||
c_str!("The DSO is malformed somehow. Set `LD_DEBUG=all` for more information.")
|
||||
}
|
||||
|
||||
DlError::InvalidHandle => {
|
||||
c_str!("Invalid DSO handle. Set `LD_DEBUG=all` for more information.")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type Result<T> = core::result::Result<T, DlError>;
|
||||
|
||||
// TODO: rwlock?
|
||||
static GLOBAL_SCOPE: RwLock<Scope> = RwLock::new(Scope::global());
|
||||
|
||||
/// Same as [`crate::fs::File`], but does not touch [`crate::platform::ERRNO`] as the dynamic
|
||||
@@ -139,9 +159,9 @@ impl Scope {
|
||||
fn add(&mut self, target: &Arc<DSO>) {
|
||||
match self {
|
||||
Self::Global { objs } => {
|
||||
let target = Arc::downgrade(&target);
|
||||
let target = Arc::downgrade(target);
|
||||
for obj in objs.iter() {
|
||||
if Weak::ptr_eq(&obj, &target) {
|
||||
if Weak::ptr_eq(obj, &target) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -151,7 +171,7 @@ impl Scope {
|
||||
|
||||
Self::Local { objs, .. } => {
|
||||
for obj in objs.iter() {
|
||||
if Arc::ptr_eq(obj, &target) {
|
||||
if Arc::ptr_eq(obj, target) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -190,7 +210,7 @@ impl Scope {
|
||||
.find_map(get_sym)
|
||||
}
|
||||
}
|
||||
.or_else(|| res)
|
||||
.or(res)
|
||||
}
|
||||
|
||||
fn move_into(&self, other: &mut Self) {
|
||||
@@ -199,7 +219,7 @@ impl Scope {
|
||||
(Self::Local { owner, objs }, Self::Global { objs: other_objs }) => {
|
||||
let owner = owner.as_ref().expect("local scope without owner");
|
||||
other_objs.push(owner.clone());
|
||||
other_objs.extend(objs.iter().map(|o| Arc::downgrade(o)));
|
||||
other_objs.extend(objs.iter().map(Arc::downgrade));
|
||||
}
|
||||
|
||||
_ => unreachable!(),
|
||||
@@ -220,7 +240,7 @@ impl ObjectHandle {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn into_inner(&self) -> Arc<DSO> {
|
||||
fn into_inner(self) -> Arc<DSO> {
|
||||
unsafe { Arc::from_raw(self.0) }
|
||||
}
|
||||
|
||||
@@ -246,7 +266,7 @@ bitflags::bitflags! {
|
||||
#[derive(Debug, Default)]
|
||||
pub struct DebugFlags: u32 {
|
||||
/// Display what objects and where they are being loaded.
|
||||
const BASE_ADDRESS = 1 << 1;
|
||||
const LOAD = 1 << 1;
|
||||
/// Display library search paths.
|
||||
const SEARCH = 1 << 2;
|
||||
/// Display scope information.
|
||||
@@ -270,9 +290,10 @@ impl Config {
|
||||
let mut flags = DebugFlags::empty();
|
||||
for opt in value.split(',') {
|
||||
flags |= match opt {
|
||||
"baseaddr" => DebugFlags::BASE_ADDRESS,
|
||||
"load" => DebugFlags::LOAD,
|
||||
"search" => DebugFlags::SEARCH,
|
||||
"scopes" => DebugFlags::SCOPES,
|
||||
"all" => DebugFlags::all(),
|
||||
_ => {
|
||||
eprintln!("[ld.so]: unknown debug flag '{}'", opt);
|
||||
DebugFlags::empty()
|
||||
@@ -526,7 +547,7 @@ impl Linker {
|
||||
use redox_rt::signal::tmp_disable_signals;
|
||||
|
||||
let old_tcb = Tcb::current().expect("failed to get bootstrap TCB");
|
||||
let new_tcb = Tcb::new(self.tls_size)?; // This actually allocates TCB, TLS and ABI page.
|
||||
let new_tcb = Tcb::new(self.tls_size).map_err(|_| DlError::Malformed)?; // This actually allocates TCB, TLS and ABI page.
|
||||
|
||||
// Stash
|
||||
let new_tls_end = new_tcb.generic.tls_end;
|
||||
@@ -567,7 +588,7 @@ impl Linker {
|
||||
};
|
||||
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
let tcb = Tcb::new(self.tls_size)?;
|
||||
let tcb = Tcb::new(self.tls_size).map_err(|_| DlError::Malformed)?;
|
||||
|
||||
// We are now loading the main program or its dependencies. The TLS for all initially
|
||||
// loaded objects reside in the static TLS block. Depending on the architecture, the
|
||||
@@ -601,7 +622,7 @@ impl Linker {
|
||||
|
||||
tcb.append_masters(tcb_masters);
|
||||
// Copy the master data into the static TLS block.
|
||||
tcb.copy_masters()?;
|
||||
tcb.copy_masters().map_err(|_| DlError::Malformed)?;
|
||||
tcb.activate();
|
||||
|
||||
#[cfg(target_os = "redox")]
|
||||
@@ -657,8 +678,10 @@ impl Linker {
|
||||
return Ok(obj.clone());
|
||||
}
|
||||
|
||||
let debug = self.config.debug_flags.contains(DebugFlags::LOAD);
|
||||
|
||||
let path = self.search_object(name, parent_runpath)?;
|
||||
let data = Linker::read_file(&path)?;
|
||||
let data = self.read_file(&path)?;
|
||||
let (mut obj, tcb_master) = DSO::new(
|
||||
&path,
|
||||
&data,
|
||||
@@ -667,9 +690,16 @@ impl Linker {
|
||||
self.next_object_id,
|
||||
self.next_tls_module_id,
|
||||
self.tls_size,
|
||||
)?;
|
||||
)
|
||||
.map_err(|err| {
|
||||
if debug {
|
||||
eprintln!("[ld.so]: failed to load '{}': {}", name, err)
|
||||
}
|
||||
|
||||
if self.config.debug_flags.contains(DebugFlags::BASE_ADDRESS) {
|
||||
DlError::Malformed
|
||||
})?;
|
||||
|
||||
if debug {
|
||||
eprintln!(
|
||||
"[ld.so]: loading object: {} at {:#x}",
|
||||
name,
|
||||
@@ -760,18 +790,41 @@ impl Linker {
|
||||
}
|
||||
}
|
||||
|
||||
Err(Error::Malformed(format!("failed to locate '{}'", name)))
|
||||
if debug {
|
||||
eprintln!("[ld.so]: failed to locate '{}'", name);
|
||||
}
|
||||
|
||||
Err(DlError::NotFound)
|
||||
}
|
||||
|
||||
fn read_file(path: &str) -> Result<Vec<u8>> {
|
||||
fn read_file(&self, path: &str) -> Result<Vec<u8>> {
|
||||
let debug = self.config.debug_flags.contains(DebugFlags::SEARCH);
|
||||
|
||||
let mut data = Vec::new();
|
||||
let path_c = CString::new(path)
|
||||
.map_err(|err| Error::Malformed(format!("invalid path '{}': {}", path, err)))?;
|
||||
let path_c = CString::new(path).map_err(|err| {
|
||||
if debug {
|
||||
eprintln!("[ld.so]: invalid path '{}': {}", path, err)
|
||||
}
|
||||
|
||||
DlError::NotFound
|
||||
})?;
|
||||
|
||||
let flags = fcntl::O_RDONLY | fcntl::O_CLOEXEC;
|
||||
let mut file = File::open(CStr::borrow(&path_c), flags)
|
||||
.map_err(|err| Error::Malformed(format!("failed to open '{}': {}", path, err)))?;
|
||||
file.read_to_end(&mut data)
|
||||
.map_err(|err| Error::Malformed(format!("failed to read '{}': {}", path, err)))?;
|
||||
let mut file = File::open(CStr::borrow(&path_c), flags).map_err(|err| {
|
||||
if debug {
|
||||
eprintln!("[ld.so]: failed to open '{}': {}", path, err)
|
||||
}
|
||||
|
||||
DlError::NotFound
|
||||
})?;
|
||||
|
||||
file.read_to_end(&mut data).map_err(|err| {
|
||||
if debug {
|
||||
eprintln!("[ld.so]: failed to read '{}': {}", path, err)
|
||||
}
|
||||
|
||||
DlError::NotFound
|
||||
})?;
|
||||
|
||||
Ok(data)
|
||||
}
|
||||
@@ -780,6 +833,7 @@ impl Linker {
|
||||
fn lazy_relocate(&self, obj: &Arc<DSO>, elf: &Elf, resolve: Resolve) -> Result<()> {
|
||||
let Some(got) = obj.got() else { return Ok(()) };
|
||||
let object_base_addr = obj.mmap.as_ptr() as u64;
|
||||
let debug = self.config.debug_flags.contains(DebugFlags::LOAD);
|
||||
|
||||
unsafe {
|
||||
got.add(1).write(Arc::as_ptr(obj) as usize);
|
||||
@@ -803,18 +857,21 @@ impl Linker {
|
||||
}
|
||||
|
||||
(reloc::R_X86_64_JUMP_SLOT, Resolve::Now) => {
|
||||
let sym = elf.dynsyms.get(rel.r_sym).ok_or(Error::Malformed(format!(
|
||||
"missing symbol for relocation {:?}",
|
||||
rel
|
||||
)))?;
|
||||
let sym = elf.dynsyms.get(rel.r_sym).ok_or_else(|| {
|
||||
if debug {
|
||||
eprintln!("missing symbol for relocation {:?}", rel)
|
||||
}
|
||||
|
||||
let name =
|
||||
elf.dynstrtab
|
||||
.get_at(sym.st_name)
|
||||
.ok_or(Error::Malformed(format!(
|
||||
"missing name for symbol {:?}",
|
||||
sym
|
||||
)))?;
|
||||
DlError::Malformed
|
||||
})?;
|
||||
|
||||
let name = elf.dynstrtab.get_at(sym.st_name).ok_or_else(|| {
|
||||
if debug {
|
||||
eprintln!("missing name for symbol {:?}", sym)
|
||||
}
|
||||
|
||||
DlError::Malformed
|
||||
})?;
|
||||
|
||||
let resolved = GLOBAL_SCOPE
|
||||
.read()
|
||||
@@ -839,7 +896,8 @@ impl Linker {
|
||||
|
||||
fn relocate(&self, obj: &Arc<DSO>, object_data: &[u8], resolve: Resolve) -> Result<()> {
|
||||
// Perform static relocations.
|
||||
let elf = Elf::parse(object_data)?;
|
||||
let elf = Elf::parse(object_data).or(Err(DlError::Malformed))?;
|
||||
let debug = self.config.debug_flags.contains(DebugFlags::LOAD); // FIXME
|
||||
|
||||
trace!("link {}", obj.name);
|
||||
|
||||
@@ -855,18 +913,21 @@ impl Linker {
|
||||
);
|
||||
|
||||
let symbol = if rel.r_sym > 0 {
|
||||
let sym = elf.dynsyms.get(rel.r_sym).ok_or(Error::Malformed(format!(
|
||||
"missing symbol for relocation {:?}",
|
||||
rel
|
||||
)))?;
|
||||
let sym = elf.dynsyms.get(rel.r_sym).ok_or_else(|| {
|
||||
if debug {
|
||||
eprintln!("[ld.so]: missing symbol for relocation {:?}", rel)
|
||||
}
|
||||
|
||||
let name = elf
|
||||
.dynstrtab
|
||||
.get_at(sym.st_name)
|
||||
.ok_or(Error::Malformed(format!(
|
||||
"missing name for symbol {:?}",
|
||||
sym
|
||||
)))?;
|
||||
DlError::Malformed
|
||||
})?;
|
||||
|
||||
let name = elf.dynstrtab.get_at(sym.st_name).ok_or_else(|| {
|
||||
if debug {
|
||||
eprintln!("[ld.so]: missing name for symbol {:?}", sym)
|
||||
}
|
||||
|
||||
DlError::Malformed
|
||||
})?;
|
||||
|
||||
let symbol = GLOBAL_SCOPE
|
||||
.read()
|
||||
@@ -992,8 +1053,13 @@ impl Linker {
|
||||
vaddr as *const u8
|
||||
};
|
||||
trace!(" prot {:#x}, {:#x}: {:p}, {:#x}", vaddr, vsize, ptr, prot);
|
||||
Sys::mprotect(ptr as *mut c_void, vsize, prot)
|
||||
.map_err(|_| Error::Malformed(format!("failed to mprotect {}", obj.name)))?;
|
||||
Sys::mprotect(ptr as *mut c_void, vsize, prot).map_err(|err| {
|
||||
if debug {
|
||||
eprintln!("[ld.so]: failed to mprotect: {}", err)
|
||||
}
|
||||
|
||||
DlError::Malformed
|
||||
})?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1036,7 +1102,7 @@ extern "C" fn __plt_resolve_inner(obj: *const DSO, relocation_index: c_uint) ->
|
||||
let obj = unsafe { &*obj };
|
||||
let obj_base = obj.mmap.as_ptr() as usize;
|
||||
let dynamic = obj.dynamic.as_ref().unwrap();
|
||||
let jmprel = dynamic.info.jmprel as usize;
|
||||
let jmprel = dynamic.info.jmprel;
|
||||
|
||||
let rela = unsafe {
|
||||
&*((obj_base + jmprel) as *const reloc::reloc64::Rela).add(relocation_index as usize)
|
||||
@@ -1068,7 +1134,7 @@ extern "C" fn __plt_resolve_inner(obj: *const DSO, relocation_index: c_uint) ->
|
||||
};
|
||||
|
||||
let resolved = resolve_sym(name.to_str().unwrap(), &[&GLOBAL_SCOPE.read(), &obj.scope])
|
||||
.expect(&format!("symbol '{}' not found", name.to_str().unwrap()))
|
||||
.unwrap_or_else(|| panic!("symbol '{}' not found", name.to_str().unwrap()))
|
||||
.as_ptr();
|
||||
|
||||
trace!(
|
||||
|
||||
+6
-3
@@ -42,7 +42,8 @@ unsafe fn get_argv(mut ptr: *const usize) -> (Vec<String>, *const usize) {
|
||||
}
|
||||
ptr = ptr.add(1);
|
||||
}
|
||||
return (argv, ptr);
|
||||
|
||||
(argv, ptr)
|
||||
}
|
||||
|
||||
unsafe fn get_env(mut ptr: *const usize) -> (BTreeMap<String, String>, *const usize) {
|
||||
@@ -60,7 +61,8 @@ unsafe fn get_env(mut ptr: *const usize) -> (BTreeMap<String, String>, *const us
|
||||
}
|
||||
ptr = ptr.add(1);
|
||||
}
|
||||
return (envs, ptr);
|
||||
|
||||
(envs, ptr)
|
||||
}
|
||||
|
||||
unsafe fn adjust_stack(sp: &'static mut Stack) {
|
||||
@@ -236,7 +238,8 @@ pub extern "C" fn relibc_ld_so_start(sp: &'static mut Stack, ld_entry: usize) ->
|
||||
let entry = match linker.load_program(&path, base_addr) {
|
||||
Ok(entry) => entry,
|
||||
Err(err) => {
|
||||
eprintln!("ld.so: failed to link '{}': {}", path, err);
|
||||
eprintln!("ld.so: failed to link '{}': {:?}", path, err);
|
||||
eprintln!("ld.so: enable debug output with `LD_DEBUG=all` for more information");
|
||||
unistd::_exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
use alloc::vec::Vec;
|
||||
use alloc::{string::ToString, vec::Vec};
|
||||
use core::{
|
||||
cell::UnsafeCell,
|
||||
mem,
|
||||
@@ -247,7 +247,7 @@ impl Tcb {
|
||||
-1,
|
||||
0,
|
||||
)
|
||||
.map_err(|_| Error::Malformed(format!("failed to map tls")))?;
|
||||
.map_err(|_| Error::Malformed("failed to map tls".to_string()))?;
|
||||
|
||||
ptr::write_bytes(ptr as *mut u8, 0, size);
|
||||
Ok(slice::from_raw_parts_mut(ptr as *mut u8, size))
|
||||
|
||||
Reference in New Issue
Block a user