From 4e5ccbffd165bb1c0a019928ac72f2f75adfd906 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 23 Jul 2022 16:24:02 +0200 Subject: [PATCH] Allow constructors to access env vars. --- src/ld_so/linker.rs | 8 ++++++++ src/ld_so/start.rs | 16 ++++++++++++++++ src/start.rs | 33 +++++++++++++++++++++++++-------- 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/src/ld_so/linker.rs b/src/ld_so/linker.rs index e8cf6ccf..a1a517f7 100644 --- a/src/ld_so/linker.rs +++ b/src/ld_so/linker.rs @@ -472,7 +472,15 @@ impl Linker { } fn run_init(&self, objects: &Vec<DSO>) { + use crate::platform::{self, types::*}; + for obj in objects.iter().rev() { + if let Some((symbol, true)) = obj.get_sym("__relibc_init_environ") { + unsafe { + symbol.as_ptr().cast::<*mut *mut c_char>().write(platform::environ); + } + } + obj.run_init(); } } diff --git a/src/ld_so/start.rs b/src/ld_so/start.rs index 25a1f16d..e07afac1 100644 --- a/src/ld_so/start.rs +++ b/src/ld_so/start.rs @@ -167,6 +167,22 @@ pub extern "C" fn relibc_ld_so_start(sp: &'static mut Stack, ld_entry: usize) -> (argv, envs, auxv) }; + unsafe { + crate::platform::OUR_ENVIRON = envs.iter().map(|(k, v)| { + let mut var = Vec::with_capacity(k.len() + v.len() + 2); + var.extend(k.as_bytes()); + var.push(b'='); + var.extend(v.as_bytes()); + var.push(b'\0'); + let mut var = var.into_boxed_slice(); + let ptr = var.as_mut_ptr(); + core::mem::forget(var); + ptr.cast() + }).chain(core::iter::once(core::ptr::null_mut())).collect::<Vec<_>>(); + + crate::platform::environ = crate::platform::OUR_ENVIRON.as_mut_ptr(); + } + let is_manual = if let Some(img_entry) = auxv.get(&AT_ENTRY) { *img_entry == ld_entry } else { diff --git a/src/start.rs b/src/start.rs index cee25f33..9ec0eb76 100644 --- a/src/start.rs +++ b/src/start.rs @@ -67,7 +67,16 @@ static INIT_ARRAY: [extern "C" fn(); 1] = [init_array]; static mut init_complete: bool = false; +#[used] +#[no_mangle] +static mut __relibc_init_environ: *mut *mut c_char = ptr::null_mut(); + fn alloc_init() { + unsafe { + if init_complete { + return; + } + } unsafe { if let Some(tcb) = ld_so::tcb::Tcb::current() { if tcb.mspace != 0 { @@ -96,6 +105,10 @@ extern "C" fn init_array() { alloc_init(); io_init(); + unsafe { + platform::environ = __relibc_init_environ; + } + extern "C" { fn pthread_init(); } @@ -155,15 +168,19 @@ pub unsafe extern "C" fn relibc_start(sp: &'static Stack) -> ! { platform::program_invocation_name = *arg; platform::program_invocation_short_name = libgen::basename(*arg); } - - // Set up envp - let envp = sp.envp(); - let mut len = 0; - while !(*envp.add(len)).is_null() { - len += 1; + // We check for NULL here since ld.so might already have initialized it for us, and we don't + // want to overwrite it if constructors in .init_array of dependency libraries have called + // setenv. + if platform::environ.is_null() { + // Set up envp + let envp = sp.envp(); + let mut len = 0; + while !(*envp.add(len)).is_null() { + len += 1; + } + platform::OUR_ENVIRON = copy_string_array(envp, len); + platform::environ = platform::OUR_ENVIRON.as_mut_ptr(); } - platform::OUR_ENVIRON = copy_string_array(envp, len); - platform::environ = platform::OUR_ENVIRON.as_mut_ptr(); // Setup signal stack, otherwise we cannot handle any signals besides SIG_IGN/SIG_DFL behavior. setup_sigstack(); -- GitLab