Skip to content

Commit 2b21649

Browse files
authored
Add stack-smashing protector support. (#95)
Add a canary field to the thread metadata, and add a `__stack_chk_guard` global variable.
1 parent ce014d1 commit 2b21649

2 files changed

Lines changed: 43 additions & 13 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ include = ["src", "Cargo.toml", "COPYRIGHT", "LICENSE*", "/*.md"]
1515

1616
[dependencies]
1717
linux-raw-sys = { version = "0.4.9", default-features = false, features = ["general", "no_std", "elf"] }
18-
rustix = { version = "0.38.17", default-features = false }
18+
rustix = { version = "0.38.26", default-features = false }
1919
bitflags = { version = "2.4.0", default-features = false }
2020
memoffset = { version = "0.9.0", optional = true }
2121
log = { version = "0.4.14", default-features = false, optional = true }

src/thread/linux_raw.rs

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,13 @@ struct Metadata {
119119
#[repr(C)]
120120
#[cfg_attr(target_arch = "arm", repr(align(8)))]
121121
struct Abi {
122-
/// Aarch64 has an ABI-exposed `dtv` field (though we don't yet implement
123-
/// dynamic linking).
124-
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
122+
/// The ABI-exposed `canary` field.
123+
#[cfg(any(target_arch = "aarch64", target_arch = "arm", target_arch = "riscv64"))]
124+
canary: usize,
125+
126+
/// The ABI-exposed `dtv` field (though we don't yet implement dynamic
127+
/// linking).
128+
#[cfg(any(target_arch = "aarch64", target_arch = "arm", target_arch = "riscv64"))]
125129
dtv: *const c_void,
126130

127131
/// x86 and x86-64 put a copy of the thread-pointer register at the memory
@@ -130,9 +134,25 @@ struct Abi {
130134
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
131135
this: *mut Abi,
132136

137+
/// The ABI-exposed `dtv` field (though we don't yet implement dynamic
138+
/// linking).
139+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
140+
dtv: *const c_void,
141+
142+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
143+
_pad: [usize; 3],
144+
145+
/// The ABI-exposed `canary` field.
146+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
147+
canary: usize,
148+
133149
/// Padding to put the TLS data which follows at its known offset.
134150
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
135-
pad: [usize; 1],
151+
_pad: [usize; 1],
152+
153+
/// Padding to put the TLS data which follows at its known offset.
154+
#[cfg(target_arch = "riscv64")]
155+
_pad: [usize; 0],
136156
}
137157

138158
/// Information obtained from the `DT_TLS` segment of the executable.
@@ -331,15 +351,19 @@ pub(super) unsafe fn initialize_main_thread(mem: *mut c_void) {
331351
let thread_id_ptr = (*metadata).thread.thread_id.as_ptr();
332352
let tid = rustix::runtime::set_tid_address(thread_id_ptr.cast());
333353

354+
// Initialize the canary value from the OS-provided random bytes.
355+
let random_ptr = rustix::runtime::random().cast::<usize>();
356+
let canary = random_ptr.read_unaligned();
357+
__stack_chk_guard = canary;
358+
334359
// Initialize the thread metadata.
335360
metadata.write(Metadata {
336361
abi: Abi {
362+
canary,
363+
dtv: null(),
337364
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
338365
this: newtls,
339-
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
340-
dtv: null(),
341-
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
342-
pad: [0_usize; 1],
366+
_pad: Default::default(),
343367
},
344368
thread: ThreadData::new(
345369
Some(tid),
@@ -464,15 +488,17 @@ pub unsafe fn create_thread(
464488
let metadata: *mut Metadata = map.add(header).cast();
465489
let newtls: *mut Abi = &mut (*metadata).abi;
466490

491+
// Copy the current thread's canary to the new thread.
492+
let canary = (*current_metadata()).abi.canary;
493+
467494
// Initialize the thread metadata.
468495
metadata.write(Metadata {
469496
abi: Abi {
497+
canary,
498+
dtv: null(),
470499
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
471500
this: newtls,
472-
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
473-
dtv: null(),
474-
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
475-
pad: [0_usize; 1],
501+
_pad: Default::default(),
476502
},
477503
thread: ThreadData::new(
478504
None, // the real tid will be written by `clone`.
@@ -1031,6 +1057,10 @@ extern "C" fn __aeabi_read_tp() -> *mut c_void {
10311057
thread_pointer()
10321058
}
10331059

1060+
/// Some targets use this global variable instead of the TLS `canary` field.
1061+
#[no_mangle]
1062+
static mut __stack_chk_guard: usize = 0;
1063+
10341064
const fn round_up(addr: usize, boundary: usize) -> usize {
10351065
(addr + (boundary - 1)) & boundary.wrapping_neg()
10361066
}

0 commit comments

Comments
 (0)