Skip to content

Commit e7c4fb6

Browse files
committed
rand: Fix a bug acquiring a context on windows
The details can be found in the comment I wrote on the block in question, but the gist of it is that our usage of the TIB for a stack limit was causing CryptAcquireContext to fail, so we temporarily get around it by setting the stack limit to 0.
1 parent d2e99a0 commit e7c4fb6

File tree

1 file changed

+39
-1
lines changed

1 file changed

+39
-1
lines changed

src/librand/os.rs

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ mod imp {
6363
use std::cast;
6464
use std::libc::{c_ulong, DWORD, BYTE, LPCSTR, BOOL};
6565
use std::os;
66+
use std::rt::stack;
6667

6768
type HCRYPTPROV = c_ulong;
6869

@@ -82,6 +83,7 @@ mod imp {
8283
static PROV_RSA_FULL: DWORD = 1;
8384
static CRYPT_SILENT: DWORD = 64;
8485
static CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000;
86+
static NTE_BAD_SIGNATURE: DWORD = 0x80090006;
8587

8688
extern "system" {
8789
fn CryptAcquireContextA(phProv: *mut HCRYPTPROV,
@@ -99,11 +101,47 @@ mod imp {
99101
/// Create a new `OSRng`.
100102
pub fn new() -> OSRng {
101103
let mut hcp = 0;
102-
let ret = unsafe {
104+
let mut ret = unsafe {
103105
CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR,
104106
PROV_RSA_FULL,
105107
CRYPT_VERIFYCONTEXT | CRYPT_SILENT)
106108
};
109+
110+
// It turns out that if we can't acquire a context with the
111+
// NTE_BAD_SIGNATURE error code, the documentation states:
112+
//
113+
// The provider DLL signature could not be verified. Either the
114+
// DLL or the digital signature has been tampered with.
115+
//
116+
// Sounds fishy, no? As it turns out, our signature can be bad
117+
// because our Thread Information Block (TIB) isn't exactly what it
118+
// expects. As to why, I have no idea. The only data we store in the
119+
// TIB is the stack limit for each thread, but apparently that's
120+
// enough to make the signature valid.
121+
//
122+
// Furthermore, this error only happens the *first* time we call
123+
// CryptAcquireContext, so we don't have to worry about future
124+
// calls.
125+
//
126+
// Anyway, the fix employed here is that if we see this error, we
127+
// pray that we're not close to the end of the stack, temporarily
128+
// set the stack limit to 0 (what the TIB originally was), acquire a
129+
// context, and then reset the stack limit.
130+
//
131+
// Again, I'm not sure why this is the fix, nor why we're getting
132+
// this error. All I can say is that this seems to allow libnative
133+
// to progress where it otherwise would be hindered. Who knew?
134+
if ret == 0 && os::errno() as DWORD == NTE_BAD_SIGNATURE {
135+
unsafe {
136+
let limit = stack::get_sp_limit();
137+
stack::record_sp_limit(0);
138+
ret = CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR,
139+
PROV_RSA_FULL,
140+
CRYPT_VERIFYCONTEXT | CRYPT_SILENT);
141+
stack::record_sp_limit(limit);
142+
}
143+
}
144+
107145
if ret == 0 {
108146
fail!("couldn't create context: {}", os::last_os_error());
109147
}

0 commit comments

Comments
 (0)