Skip to content

Commit d0d3466

Browse files
authored
Rollup merge of rust-lang#59613 - jethrogb:jb/waitqueue-wait-unwind, r=alexcrichton
SGX target: convert a bunch of panics to aborts Fixes fortanix/rust-sgx#86, fortanix/rust-sgx#103 and in general protect preemptively against Iago attacks by aborting instead of unwinding in potentially unexpected situations.
2 parents 85a82ac + 6d96c89 commit d0d3466

File tree

12 files changed

+61
-48
lines changed

12 files changed

+61
-48
lines changed

src/libstd/sys/sgx/abi/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,9 @@ extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64
6969
}
7070

7171
// check entry is being called according to ABI
72-
assert_eq!(p3, 0);
73-
assert_eq!(p4, 0);
74-
assert_eq!(p5, 0);
72+
rtassert!(p3 == 0);
73+
rtassert!(p4 == 0);
74+
rtassert!(p5 == 0);
7575

7676
unsafe {
7777
// The actual types of these arguments are `p1: *const Arg, p2:

src/libstd/sys/sgx/abi/reloc.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ pub fn relocate_elf_rela() {
2323
};
2424
for rela in relas {
2525
if rela.info != (/*0 << 32 |*/ R_X86_64_RELATIVE as u64) {
26-
panic!("Invalid relocation");
26+
rtabort!("Invalid relocation");
2727
}
2828
unsafe { *mem::rel_ptr_mut::<*const ()>(rela.offset) = mem::rel_ptr(rela.addend) };
2929
}

src/libstd/sys/sgx/abi/tls.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -100,20 +100,24 @@ impl Tls {
100100
}
101101

102102
pub fn create(dtor: Option<unsafe extern fn(*mut u8)>) -> Key {
103-
let index = TLS_KEY_IN_USE.set().expect("TLS limit exceeded");
103+
let index = if let Some(index) = TLS_KEY_IN_USE.set() {
104+
index
105+
} else {
106+
rtabort!("TLS limit exceeded")
107+
};
104108
TLS_DESTRUCTOR[index].store(dtor.map_or(0, |f| f as usize), Ordering::Relaxed);
105109
Key::from_index(index)
106110
}
107111

108112
pub fn set(key: Key, value: *mut u8) {
109113
let index = key.to_index();
110-
assert!(TLS_KEY_IN_USE.get(index));
114+
rtassert!(TLS_KEY_IN_USE.get(index));
111115
unsafe { Self::current() }.data[index].set(value);
112116
}
113117

114118
pub fn get(key: Key) -> *mut u8 {
115119
let index = key.to_index();
116-
assert!(TLS_KEY_IN_USE.get(index));
120+
rtassert!(TLS_KEY_IN_USE.get(index));
117121
unsafe { Self::current() }.data[index].get()
118122
}
119123

src/libstd/sys/sgx/abi/usercalls/alloc.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -190,11 +190,15 @@ impl<T: ?Sized> User<T> where T: UserSafe {
190190
unsafe {
191191
// Mustn't call alloc with size 0.
192192
let ptr = if size > 0 {
193-
super::alloc(size, T::align_of()).expect("User memory allocation failed") as _
193+
rtunwrap!(Ok, super::alloc(size, T::align_of())) as _
194194
} else {
195195
T::align_of() as _ // dangling pointer ok for size 0
196196
};
197-
User(NonNull::new_userref(T::from_raw_sized(ptr, size)))
197+
if let Ok(v) = crate::panic::catch_unwind(|| T::from_raw_sized(ptr, size)) {
198+
User(NonNull::new_userref(v))
199+
} else {
200+
rtabort!("Got invalid pointer from alloc() usercall")
201+
}
198202
}
199203
}
200204

src/libstd/sys/sgx/abi/usercalls/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ pub fn close(fd: Fd) {
5252

5353
fn string_from_bytebuffer(buf: &alloc::UserRef<ByteBuffer>, usercall: &str, arg: &str) -> String {
5454
String::from_utf8(buf.copy_user_buffer())
55-
.unwrap_or_else(|_| panic!("Usercall {}: expected {} to be valid UTF-8", usercall, arg))
55+
.unwrap_or_else(|_| rtabort!("Usercall {}: expected {} to be valid UTF-8", usercall, arg))
5656
}
5757

5858
/// Usercall `bind_stream`. See the ABI documentation for more information.
@@ -176,7 +176,7 @@ fn check_os_error(err: Result) -> i32 {
176176
{
177177
err
178178
} else {
179-
panic!("Usercall: returned invalid error value {}", err)
179+
rtabort!("Usercall: returned invalid error value {}", err)
180180
}
181181
}
182182

src/libstd/sys/sgx/abi/usercalls/raw.rs

+12-17
Original file line numberDiff line numberDiff line change
@@ -131,22 +131,22 @@ impl<T: RegisterArgument> RegisterArgument for Option<NonNull<T>> {
131131

132132
impl ReturnValue for ! {
133133
fn from_registers(call: &'static str, _regs: (Register, Register)) -> Self {
134-
panic!("Usercall {}: did not expect to be re-entered", call);
134+
rtabort!("Usercall {}: did not expect to be re-entered", call);
135135
}
136136
}
137137

138138
impl ReturnValue for () {
139-
fn from_registers(call: &'static str, regs: (Register, Register)) -> Self {
140-
assert_eq!(regs.0, 0, "Usercall {}: expected {} return value to be 0", call, "1st");
141-
assert_eq!(regs.1, 0, "Usercall {}: expected {} return value to be 0", call, "2nd");
139+
fn from_registers(call: &'static str, usercall_retval: (Register, Register)) -> Self {
140+
rtassert!(usercall_retval.0 == 0);
141+
rtassert!(usercall_retval.1 == 0);
142142
()
143143
}
144144
}
145145

146146
impl<T: RegisterArgument> ReturnValue for T {
147-
fn from_registers(call: &'static str, regs: (Register, Register)) -> Self {
148-
assert_eq!(regs.1, 0, "Usercall {}: expected {} return value to be 0", call, "2nd");
149-
T::from_register(regs.0)
147+
fn from_registers(call: &'static str, usercall_retval: (Register, Register)) -> Self {
148+
rtassert!(usercall_retval.1 == 0);
149+
T::from_register(usercall_retval.0)
150150
}
151151
}
152152

@@ -174,8 +174,7 @@ macro_rules! enclave_usercalls_internal_define_usercalls {
174174
#[inline(always)]
175175
pub unsafe fn $f($n1: $t1, $n2: $t2, $n3: $t3, $n4: $t4) -> $r {
176176
ReturnValue::from_registers(stringify!($f), do_usercall(
177-
NonZeroU64::new(Usercalls::$f as Register)
178-
.expect("Usercall number must be non-zero"),
177+
rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
179178
RegisterArgument::into_register($n1),
180179
RegisterArgument::into_register($n2),
181180
RegisterArgument::into_register($n3),
@@ -191,8 +190,7 @@ macro_rules! enclave_usercalls_internal_define_usercalls {
191190
#[inline(always)]
192191
pub unsafe fn $f($n1: $t1, $n2: $t2, $n3: $t3) -> $r {
193192
ReturnValue::from_registers(stringify!($f), do_usercall(
194-
NonZeroU64::new(Usercalls::$f as Register)
195-
.expect("Usercall number must be non-zero"),
193+
rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
196194
RegisterArgument::into_register($n1),
197195
RegisterArgument::into_register($n2),
198196
RegisterArgument::into_register($n3),
@@ -208,8 +206,7 @@ macro_rules! enclave_usercalls_internal_define_usercalls {
208206
#[inline(always)]
209207
pub unsafe fn $f($n1: $t1, $n2: $t2) -> $r {
210208
ReturnValue::from_registers(stringify!($f), do_usercall(
211-
NonZeroU64::new(Usercalls::$f as Register)
212-
.expect("Usercall number must be non-zero"),
209+
rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
213210
RegisterArgument::into_register($n1),
214211
RegisterArgument::into_register($n2),
215212
0,0,
@@ -224,8 +221,7 @@ macro_rules! enclave_usercalls_internal_define_usercalls {
224221
#[inline(always)]
225222
pub unsafe fn $f($n1: $t1) -> $r {
226223
ReturnValue::from_registers(stringify!($f), do_usercall(
227-
NonZeroU64::new(Usercalls::$f as Register)
228-
.expect("Usercall number must be non-zero"),
224+
rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
229225
RegisterArgument::into_register($n1),
230226
0,0,0,
231227
return_type_is_abort!($r)
@@ -239,8 +235,7 @@ macro_rules! enclave_usercalls_internal_define_usercalls {
239235
#[inline(always)]
240236
pub unsafe fn $f() -> $r {
241237
ReturnValue::from_registers(stringify!($f), do_usercall(
242-
NonZeroU64::new(Usercalls::$f as Register)
243-
.expect("Usercall number must be non-zero"),
238+
rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
244239
0,0,0,0,
245240
return_type_is_abort!($r)
246241
))

src/libstd/sys/sgx/condvar.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,8 @@ impl Condvar {
3232
mutex.lock()
3333
}
3434

35-
pub unsafe fn wait_timeout(&self, mutex: &Mutex, _dur: Duration) -> bool {
36-
mutex.unlock(); // don't hold the lock while panicking
37-
panic!("timeout not supported in SGX");
35+
pub unsafe fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool {
36+
rtabort!("timeout not supported in SGX");
3837
}
3938

4039
#[inline]

src/libstd/sys/sgx/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ pub fn hashmap_random_keys() -> (u64, u64) {
139139
return ret;
140140
}
141141
}
142-
panic!("Failed to obtain random data");
142+
rtabort!("Failed to obtain random data");
143143
}
144144
}
145145
(rdrand64(), rdrand64())

src/libstd/sys/sgx/rwlock.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ impl RWLock {
105105
*wguard.lock_var_mut() = true;
106106
} else {
107107
// No writers were waiting, the lock is released
108-
assert!(rguard.queue_empty());
108+
rtassert!(rguard.queue_empty());
109109
}
110110
}
111111
}

src/libstd/sys/sgx/thread.rs

+6-8
Original file line numberDiff line numberDiff line change
@@ -62,25 +62,23 @@ impl Thread {
6262
}
6363

6464
pub(super) fn entry() {
65-
let mut guard = task_queue::lock();
66-
let task = guard.pop().expect("Thread started but no tasks pending");
67-
drop(guard); // make sure to not hold the task queue lock longer than necessary
65+
let mut pending_tasks = task_queue::lock();
66+
let task = rtunwrap!(Some, pending_tasks.pop());
67+
drop(pending_tasks); // make sure to not hold the task queue lock longer than necessary
6868
task.run()
6969
}
7070

7171
pub fn yield_now() {
72-
assert_eq!(
73-
usercalls::wait(0, usercalls::raw::WAIT_NO).unwrap_err().kind(),
74-
io::ErrorKind::WouldBlock
75-
);
72+
let wait_error = rtunwrap!(Err, usercalls::wait(0, usercalls::raw::WAIT_NO));
73+
rtassert!(wait_error.kind() == io::ErrorKind::WouldBlock);
7674
}
7775

7876
pub fn set_name(_name: &CStr) {
7977
// FIXME: could store this pointer in TLS somewhere
8078
}
8179

8280
pub fn sleep(_dur: Duration) {
83-
panic!("can't sleep"); // FIXME
81+
rtabort!("can't sleep"); // FIXME
8482
}
8583

8684
pub fn join(self) {

src/libstd/sys/sgx/waitqueue.rs

+11-7
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ impl<'a, T> Drop for WaitGuard<'a, T> {
121121
NotifiedTcs::Single(tcs) => Some(tcs),
122122
NotifiedTcs::All { .. } => None
123123
};
124-
usercalls::send(EV_UNPARK, target_tcs).unwrap();
124+
rtunwrap!(Ok, usercalls::send(EV_UNPARK, target_tcs));
125125
}
126126
}
127127

@@ -141,6 +141,7 @@ impl WaitQueue {
141141
///
142142
/// This function does not return until this thread has been awoken.
143143
pub fn wait<T>(mut guard: SpinMutexGuard<'_, WaitVariable<T>>) {
144+
// very unsafe: check requirements of UnsafeList::push
144145
unsafe {
145146
let mut entry = UnsafeListEntry::new(SpinMutex::new(WaitEntry {
146147
tcs: thread::current(),
@@ -149,10 +150,9 @@ impl WaitQueue {
149150
let entry = guard.queue.inner.push(&mut entry);
150151
drop(guard);
151152
while !entry.lock().wake {
152-
assert_eq!(
153-
usercalls::wait(EV_UNPARK, WAIT_INDEFINITE).unwrap() & EV_UNPARK,
154-
EV_UNPARK
155-
);
153+
// don't panic, this would invalidate `entry` during unwinding
154+
let eventset = rtunwrap!(Ok, usercalls::wait(EV_UNPARK, WAIT_INDEFINITE));
155+
rtassert!(eventset & EV_UNPARK == EV_UNPARK);
156156
}
157157
}
158158
}
@@ -269,7 +269,7 @@ mod unsafe_list {
269269
// ,-------> /---------\ next ---,
270270
// | |head_tail| |
271271
// `--- prev \---------/ <-------`
272-
assert_eq!(self.head_tail.as_ref().prev, first);
272+
rtassert!(self.head_tail.as_ref().prev == first);
273273
true
274274
} else {
275275
false
@@ -285,7 +285,9 @@ mod unsafe_list {
285285
/// # Safety
286286
///
287287
/// The entry must remain allocated until the entry is removed from the
288-
/// list AND the caller who popped is done using the entry.
288+
/// list AND the caller who popped is done using the entry. Special
289+
/// care must be taken in the caller of `push` to ensure unwinding does
290+
/// not destroy the stack frame containing the entry.
289291
pub unsafe fn push<'a>(&mut self, entry: &'a mut UnsafeListEntry<T>) -> &'a T {
290292
self.init();
291293

@@ -303,6 +305,7 @@ mod unsafe_list {
303305
entry.as_mut().prev = prev_tail;
304306
entry.as_mut().next = self.head_tail;
305307
prev_tail.as_mut().next = entry;
308+
// unwrap ok: always `Some` on non-dummy entries
306309
(*entry.as_ptr()).value.as_ref().unwrap()
307310
}
308311

@@ -333,6 +336,7 @@ mod unsafe_list {
333336
second.as_mut().prev = self.head_tail;
334337
first.as_mut().next = NonNull::dangling();
335338
first.as_mut().prev = NonNull::dangling();
339+
// unwrap ok: always `Some` on non-dummy entries
336340
Some((*first.as_ptr()).value.as_ref().unwrap())
337341
}
338342
}

src/libstd/sys_common/mod.rs

+9
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,15 @@ macro_rules! rtassert {
2828
})
2929
}
3030

31+
#[allow(unused_macros)] // not used on all platforms
32+
macro_rules! rtunwrap {
33+
($ok:ident, $e:expr) => (if let $ok(v) = $e {
34+
v
35+
} else {
36+
rtabort!(concat!("unwrap failed: ", stringify!($e)));
37+
})
38+
}
39+
3140
pub mod alloc;
3241
pub mod at_exit_imp;
3342
#[cfg(feature = "backtrace")]

0 commit comments

Comments
 (0)