Promote the FIFA17 SBC dispatch repair: armed by the build, not by env
Retail Gates A-G passed on the pinned CardsDLL build (4706a881), and the repair has been live-proven repeatedly, so it is now a promoted feature. Arming it from OPENFUT_SBC_DISPATCH meant any launch that did not export it (Steam, the launcher Launch button, a bare umu-run) silently lost the SBC screen to the known response-to-deserializer dispatch defect, leaving a harness script as the only working entry point. REPAIR_PROMOTED is now a build constant with a compile-time contract, and both install sites derive from it: sbc_dispatch::install always arms, and sbc_trace::install derives the parser/notifier/controller-registration traces from it because those traces ARE the repair decision inputs, not optional diagnostics. Promotion weakens no check. Safety stays in the runtime evidence gate rather than a flag: the worker still validates the exact CardsDLL signatures before installing a detour, and decide() still requires the transport sentinel status, the pinned category-response vtable captured while the response object was provably live, balanced parser counts on the one parser thread, this generation notifier having entered AND returned, the captured controller/model identity, and one repair per deserializer generation. An unrecognised build leaves native execution untouched. Rollback is a file swap (restore the previous version.dll via the hook harness backup), the documented client rollback path, deliberately not an env kill-switch. fmt clean, strict clippy clean on default and fifa17 features, 22 tests pass, release cross-build to x86_64-pc-windows-gnu produces artifact 3641d581.
This commit is contained in:
@@ -79,7 +79,9 @@ unsafe extern "system" fn worker(_: *mut core::ffi::c_void) -> u32 {
|
||||
));
|
||||
dump_modules();
|
||||
write_log("fifa17: worker complete (injection healthy)\n");
|
||||
// Every SBC detour is deferred and inert unless its exact environment gate is `1`.
|
||||
// The promoted SBC dispatch repair (and the evidence traces it decides on) arms
|
||||
// itself from the build; its safety is the runtime signature/evidence gate. The
|
||||
// remaining legacy experiment modules stay inert unless their env gate is `1`.
|
||||
crate::sbc_hook::install();
|
||||
crate::sbc_trace::install();
|
||||
crate::sbc_dispatch::install();
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
//! Guarded FIFA 17 SBC completion dispatch and passive event tracing.
|
||||
//!
|
||||
//! `OPENFUT_SBC_DISPATCH=1` permits one narrowly-scoped repair per native
|
||||
//! deserializer generation. The default and `OPENFUT_SBC_DISPATCH_TRACE=1` paths
|
||||
//! are behavior-preserving.
|
||||
//! The repair is a PROMOTED feature: it is armed by the build itself, never by an
|
||||
//! environment variable (see [`REPAIR_PROMOTED`]). Safety lives in the runtime
|
||||
//! evidence gate, not in a flag.
|
||||
|
||||
use core::ffi::c_void;
|
||||
use core::sync::atomic::{AtomicBool, AtomicU64, AtomicUsize, Ordering};
|
||||
@@ -44,6 +44,30 @@ const EVENT_SIGNATURE: [u8; EVENT_COPY_LEN] = [
|
||||
type CompletionFn = unsafe extern "system" fn(*mut c_void, *mut c_void) -> usize;
|
||||
type EventDispatchFn = unsafe extern "system" fn(*mut c_void, u32, *mut c_void) -> usize;
|
||||
|
||||
/// The guarded native dispatch repair is PROMOTED: armed by the build, never by an
|
||||
/// environment variable. Retail Gates A–G passed on the pinned CardsDLL build, so a
|
||||
/// deployed hook must repair the SBC completion on every launch path (Steam, the
|
||||
/// launcher, or a bare `umu-run`) with nothing to export.
|
||||
///
|
||||
/// Promotion does NOT weaken any check — every guard stays in the runtime evidence
|
||||
/// gate rather than in a flag. `worker` still validates the exact CardsDLL
|
||||
/// signatures before installing a detour, and [`decide`] still requires the
|
||||
/// transport sentinel status, the pinned category-response vtable captured while
|
||||
/// the response object was provably live, balanced parser counts on the one parser
|
||||
/// thread, this generation's notifier having entered AND returned, the captured
|
||||
/// controller/model identity, and one repair per deserializer generation. Anything
|
||||
/// unrecognised leaves native execution untouched.
|
||||
///
|
||||
/// Rollback is a file swap (restore the previous `version.dll`) — the documented
|
||||
/// client rollback path — deliberately not an env kill-switch.
|
||||
pub(crate) const REPAIR_PROMOTED: bool = true;
|
||||
|
||||
/// Compile-time contract: the repair stays armed by the build. Flipping this back to
|
||||
/// an env gate would silently cost a normal launch (Steam or the launcher) its SBC
|
||||
/// screen, which is exactly the regression promotion removed — so it must be a
|
||||
/// deliberate, visible change here rather than a missing variable at runtime.
|
||||
const _: () = assert!(REPAIR_PROMOTED);
|
||||
|
||||
static REPAIR_ENABLED: AtomicBool = AtomicBool::new(false);
|
||||
static COMPLETION_TRAMPOLINE: AtomicUsize = AtomicUsize::new(0);
|
||||
static EVENT_TRAMPOLINE: AtomicUsize = AtomicUsize::new(0);
|
||||
@@ -691,22 +715,12 @@ unsafe fn worker() {
|
||||
}
|
||||
|
||||
pub(crate) fn install() {
|
||||
let repair =
|
||||
crate::sbc_trace::env_enabled(std::env::var("OPENFUT_SBC_DISPATCH").ok().as_deref());
|
||||
let trace = repair
|
||||
|| crate::sbc_trace::env_enabled(
|
||||
std::env::var("OPENFUT_SBC_DISPATCH_TRACE").ok().as_deref(),
|
||||
);
|
||||
REPAIR_ENABLED.store(repair, Ordering::Release);
|
||||
if !trace {
|
||||
crate::write_log("SBC_DISPATCH: disabled\n");
|
||||
return;
|
||||
}
|
||||
crate::write_log(if repair {
|
||||
"SBC_DISPATCH: repair ARMED; strict native evidence gate enabled\n"
|
||||
} else {
|
||||
"SBC_DISPATCH: passive trace requested; repair disabled\n"
|
||||
});
|
||||
// Promoted: armed by the build. No environment variable participates in the
|
||||
// decision, so every launch path behaves identically.
|
||||
REPAIR_ENABLED.store(REPAIR_PROMOTED, Ordering::Release);
|
||||
crate::write_log(
|
||||
"SBC_DISPATCH: repair ARMED (promoted); strict native evidence gate enabled\n",
|
||||
);
|
||||
std::thread::spawn(|| unsafe { worker() });
|
||||
}
|
||||
|
||||
|
||||
@@ -1148,7 +1148,9 @@ fn install_notifier(enabled: bool) {
|
||||
}
|
||||
|
||||
pub(crate) fn install() {
|
||||
let dispatch_repair = env_enabled(std::env::var("OPENFUT_SBC_DISPATCH").ok().as_deref());
|
||||
// The repair's evidence traces (parser, notifier, controller registration) are
|
||||
// its decision inputs, so they follow the promoted repair, not an env var.
|
||||
let dispatch_repair = crate::sbc_dispatch::REPAIR_PROMOTED;
|
||||
let dispatch_trace =
|
||||
dispatch_repair || env_enabled(std::env::var("OPENFUT_SBC_DISPATCH_TRACE").ok().as_deref());
|
||||
let enabled =
|
||||
|
||||
Reference in New Issue
Block a user