fix(core): linearize session publication

This commit is contained in:
sechmachine
2026-08-12 22:40:05 +07:00
parent 519c04e18f
commit 0723c10d9a
4 changed files with 193 additions and 24 deletions
+1
View File
@@ -742,6 +742,7 @@ fn signer_callback_rejects_every_stateful_api_across_handles() {
let other = create(&mut other_ctx);
let mut ctx = Context::default();
ctx.reentry_cancel.store(OK, Ordering::SeqCst);
ctx.reentry_target.store(other as usize, Ordering::SeqCst);
let mut cfg = config(&mut ctx);
cfg.sign_admission = Some(sign_admission_probes_global_reentry);
+64 -12
View File
@@ -204,25 +204,52 @@ pub(crate) struct Ready {
}
pub(crate) struct Oracle {
_serial: std::sync::MutexGuard<'static, ()>,
child: Child,
directory: std::path::PathBuf,
pub(crate) ready: Ready,
}
#[test]
fn production_oracles_can_run_concurrently_with_isolated_state() {
let (first_ready_tx, first_ready_rx) = std::sync::mpsc::channel();
let (release_tx, release_rx) = std::sync::mpsc::channel();
let first = thread::spawn(move || {
let oracle = Oracle::start("");
first_ready_tx.send(()).expect("first ready");
release_rx.recv().expect("release first oracle");
drop(oracle);
});
first_ready_rx
.recv_timeout(Duration::from_secs(20))
.expect("first oracle ready");
let (second_ready_tx, second_ready_rx) = std::sync::mpsc::channel();
let second = thread::spawn(move || {
let oracle = Oracle::start("");
second_ready_tx.send(()).expect("second ready");
drop(oracle);
});
let concurrent = second_ready_rx.recv_timeout(Duration::from_secs(5)).is_ok();
release_tx.send(()).expect("release first");
first.join().expect("first oracle");
second.join().expect("second oracle");
assert!(concurrent, "second isolated oracle was globally serialized");
}
impl Oracle {
pub(crate) fn start(mode: &str) -> Self {
static SERIAL: Mutex<()> = Mutex::new(());
static NEXT: AtomicUsize = AtomicUsize::new(1);
let serial = SERIAL
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
let directory = std::env::temp_dir().join(format!(
"versevdi-rust-gateway-oracle-{}-{}",
std::process::id(),
NEXT.fetch_add(1, Ordering::Relaxed)
));
fs::create_dir(&directory).expect("create oracle directory");
let directory = loop {
let candidate = std::env::temp_dir().join(format!(
"versevdi-rust-gateway-oracle-{}-{}",
std::process::id(),
NEXT.fetch_add(1, Ordering::Relaxed)
));
match fs::create_dir(&candidate) {
Ok(()) => break candidate,
Err(error) if error.kind() == std::io::ErrorKind::AlreadyExists => {}
Err(error) => panic!("create oracle directory: {error}"),
}
};
let source = directory.join("main.go");
let ready_path = directory.join("ready.json");
let stop_path = directory.join("stop");
@@ -242,7 +269,6 @@ impl Oracle {
if let Ok(bytes) = fs::read(&ready_path) {
if let Ok(ready) = serde_json::from_slice(&bytes) {
return Self {
_serial: serial,
child,
directory,
ready,
@@ -522,6 +548,8 @@ unsafe extern "C" {
struct AbiSigners {
admission: Arc<dyn SigningKey>,
tls: Arc<dyn SigningKey>,
admission_threads: Mutex<Vec<thread::ThreadId>>,
tls_threads: Mutex<Vec<thread::ThreadId>>,
}
unsafe extern "C" fn abi_admission(raw: *mut c_void, input: AbiBytes, output: *mut u8) -> u32 {
unsafe { abi_sign(raw, input, output, true) }
@@ -531,6 +559,15 @@ unsafe extern "C" fn abi_tls(raw: *mut c_void, input: AbiBytes, output: *mut u8)
}
unsafe fn abi_sign(raw: *mut c_void, input: AbiBytes, output: *mut u8, admission: bool) -> u32 {
let context = unsafe { &*raw.cast::<AbiSigners>() };
let threads = if admission {
&context.admission_threads
} else {
&context.tls_threads
};
threads
.lock()
.expect("signer threads")
.push(thread::current().id());
let bytes = unsafe { std::slice::from_raw_parts(input.data, input.length) };
let key = if admission {
&context.admission
@@ -552,6 +589,8 @@ fn real_abi_exports_connect_send_cancel_and_destroy_the_go_gateway_session() {
let mut signers = Box::new(AbiSigners {
admission: test_key(&oracle.ready.admission_key),
tls: test_key(&oracle.ready.client_key),
admission_threads: Mutex::new(Vec::new()),
tls_threads: Mutex::new(Vec::new()),
});
let config = AbiConfig {
struct_size: size_of::<AbiConfig>() as u32,
@@ -579,7 +618,20 @@ fn real_abi_exports_connect_send_cancel_and_destroy_the_go_gateway_session() {
length: oracle.ready.credential.len(),
},
};
let calling_thread = thread::current().id();
assert_eq!(unsafe { verse_core_connect_v1(core, &request) }, 0);
assert_eq!(
signers
.admission_threads
.lock()
.expect("admission threads")
.as_slice(),
[calling_thread]
);
assert_eq!(
signers.tls_threads.lock().expect("TLS threads").as_slice(),
[calling_thread]
);
let mut values = [0; 12];
values[0] = 1;
values[2] = 30;