fix(dl-tls): TLS overallocation

* `offset` is the offset in TLS to copy initial data to NOT the segment
  size
* Only zero the region which is required to be zeroed

Signed-off-by: Anhad Singh <andypython@protonmail.com>
This commit is contained in:
Anhad Singh
2025-12-29 17:08:33 +11:00
parent be446db7c3
commit 75f6b9d64e
4 changed files with 32 additions and 19 deletions
+20 -11
View File
@@ -1,14 +1,17 @@
//! dl-tls implementation for Redox
#![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::{alloc::Layout, arch::global_asm};
use alloc::alloc::alloc_zeroed;
use alloc::alloc::alloc;
use core::{alloc::Layout, ptr};
use crate::{ld_so::tcb::Tcb, platform::types::*};
#[repr(C)]
#[allow(non_camel_case_types)]
pub struct dl_tls_index {
pub ti_module: usize,
pub ti_offset: usize,
@@ -18,7 +21,7 @@ pub struct dl_tls_index {
pub unsafe extern "C" fn __tls_get_addr(ti: *mut dl_tls_index) -> *mut c_void {
let tcb = unsafe { Tcb::current().unwrap() };
let ti = unsafe { &*ti };
let masters = unsafe { tcb.masters().unwrap() };
let masters = tcb.masters().unwrap();
trace!(
"__tls_get_addr({:p}: {:#x}, {:#x}, masters_len={}, dtv_len={})",
@@ -40,15 +43,21 @@ pub unsafe extern "C" fn __tls_get_addr(ti: *mut dl_tls_index) -> *mut c_void {
// Allocate TLS for module.
let master = &masters[dtv_index];
// FIXME(andypython): master.align
let layout = unsafe {
Layout::from_size_align_unchecked(master.offset /* aligned ph.p_memsz */, 16)
let module_tls = unsafe {
// FIXME(andypython): master.align
let layout = Layout::from_size_align_unchecked(master.segment_size, 16);
let ptr = alloc(layout);
ptr::copy_nonoverlapping(master.ptr, ptr, master.image_size);
ptr::write_bytes(
ptr.add(master.image_size),
0,
master.segment_size - master.image_size,
);
ptr
};
let module_tls = unsafe { alloc_zeroed(layout) };
unsafe { core::ptr::copy_nonoverlapping(master.ptr, module_tls, master.len) };
// Set the DTV entry.
tcb.dtv_mut()[dtv_index] = module_tls;
}
+2 -1
View File
@@ -612,7 +612,8 @@ impl DSO {
};
tcb_master = Some(Master {
ptr,
len: ph.p_filesz(endian) as usize,
image_size: ph.p_filesz(endian) as usize,
segment_size: ph.p_memsz(endian) as usize,
offset: tls_offset + ph.p_memsz(endian) as usize,
});
trace!(" tcb master {:x?}", tcb_master);
+3 -2
View File
@@ -33,7 +33,8 @@ pub use generic_rt::{ExpectTlsFree, panic_notls};
static mut STATIC_TCB_MASTER: Master = Master {
ptr: ptr::null_mut(),
len: 0,
image_size: 0,
segment_size: 0,
offset: 0,
};
@@ -112,7 +113,7 @@ pub fn static_init(
unsafe {
STATIC_TCB_MASTER.ptr = p_vaddr as *const u8;
STATIC_TCB_MASTER.len = p_filesz;
STATIC_TCB_MASTER.image_size = p_filesz;
STATIC_TCB_MASTER.offset = valign;
let tcb = Tcb::new(vsize).expect_notls("failed to allocate TCB");
+7 -5
View File
@@ -26,7 +26,8 @@ pub struct Master {
/// Pointer to initial data
pub ptr: *const u8,
/// Length of initial data in bytes
pub len: usize,
pub image_size: usize,
pub segment_size: usize,
/// Offset in TLS to copy initial data to
pub offset: usize,
}
@@ -34,7 +35,7 @@ pub struct Master {
impl Master {
/// The initial data for this TLS region
pub unsafe fn data(&self) -> &'static [u8] {
unsafe { slice::from_raw_parts(self.ptr, self.len) }
unsafe { slice::from_raw_parts(self.ptr, self.image_size) }
}
}
@@ -157,13 +158,14 @@ impl Tcb {
for master in masters
.iter()
.skip(self.num_copied_masters)
.filter(|master| master.len != 0)
.filter(|master| master.image_size != 0)
{
let range = if cfg!(any(target_arch = "x86", target_arch = "x86_64")) {
// x86{_64} TLS layout is backwards
self.tls_len - master.offset..self.tls_len - master.offset + master.len
self.tls_len - master.offset
..self.tls_len - master.offset + master.image_size
} else {
master.offset..master.offset + master.len
master.offset..master.offset + master.image_size
};
if let Some(tls_data) = tls.get_mut(range) {
let data = unsafe { master.data() };