fix(pi-natives): guard DeviceCheck token generation on GUI session
-[DCDevice isSupported] synchronously opens an XPC connection to the per-user DeviceCheck metadata daemon, which exists only in an interactive GUI login session. From a session without graphic access (SSH, launchd LaunchDaemon, CI runner, service account, sandbox) the connection setup hits _xpc_api_misuse and aborts the process with SIGTRAP before any completion handler runs, so the promise never rejects and every openai-codex/* OAuth model becomes unusable.
Check the caller's security session for the sessionHasGraphicAccess attribute via SessionGetInfo before touching DeviceCheck; resolve { supported: false, error } when it is absent, mirroring the non-macOS stub and letting the caller send an error-coded attestation instead of dying.
Fixes #8353
This commit is contained in:
@@ -99,6 +99,43 @@ mod platform {
|
||||
static _NSConcreteStackBlock: *const c_void;
|
||||
}
|
||||
|
||||
// `SessionGetInfo` reports the caller's login-session attributes; consulted
|
||||
// to detect a GUI/graphic session before touching the GUI-only DeviceCheck
|
||||
// daemon.
|
||||
#[link(name = "Security", kind = "framework")]
|
||||
unsafe extern "C" {
|
||||
fn SessionGetInfo(session: u32, session_id: *mut u32, attributes: *mut u32) -> i32;
|
||||
}
|
||||
|
||||
/// `callerSecuritySession` — query the session hosting the current process.
|
||||
const CALLER_SECURITY_SESSION: u32 = u32::MAX;
|
||||
/// `sessionHasGraphicAccess` attribute bit from `Security/AuthSession.h`.
|
||||
const SESSION_HAS_GRAPHIC_ACCESS: u32 = 0x0010;
|
||||
|
||||
/// Whether the caller's security session has GUI/graphic access.
|
||||
///
|
||||
/// `DCDevice.isSupported` synchronously opens an XPC connection to the
|
||||
/// per-user DeviceCheck metadata daemon, which exists only in an
|
||||
/// interactive GUI login session. From a session without graphic access
|
||||
/// (SSH, a launchd `LaunchDaemon`, a CI runner, a service account, a
|
||||
/// sandbox) the connection setup hits `_xpc_api_misuse` and aborts the
|
||||
/// whole process with `SIGTRAP` before the completion handler can run — so
|
||||
/// there is no error to return, only a dead process. Gating on the
|
||||
/// documented session attribute keeps the call out of that trapping path.
|
||||
///
|
||||
/// Returns `false` when graphic access is absent *or* the session cannot be
|
||||
/// queried: degrading to "unsupported" merely drops the attestation header
|
||||
/// (exactly as on every non-macOS host), whereas optimistically assuming
|
||||
/// "supported" risks the process-killing trap.
|
||||
fn session_has_graphic_access() -> bool {
|
||||
let mut attributes: u32 = 0;
|
||||
// SAFETY: `SessionGetInfo` writes the caller session's attribute bits
|
||||
// through the out-pointer; the session-id slot is unused, so it is null.
|
||||
let status =
|
||||
unsafe { SessionGetInfo(CALLER_SECURITY_SESSION, ptr::null_mut(), &mut attributes) };
|
||||
status == 0 && attributes & SESSION_HAS_GRAPHIC_ACCESS != 0
|
||||
}
|
||||
|
||||
/// Outcome delivered once from the completion block to the waiting worker.
|
||||
enum Completion {
|
||||
Token(String),
|
||||
@@ -289,6 +326,10 @@ mod platform {
|
||||
error: None,
|
||||
latency_ms: 0.0,
|
||||
};
|
||||
if !session_has_graphic_access() {
|
||||
result.error = Some("DeviceCheck unavailable without a GUI login session".to_owned());
|
||||
return result;
|
||||
}
|
||||
// SAFETY: `c"DCDevice"` is a valid null-terminated class name.
|
||||
let class = unsafe { objc_getClass(c"DCDevice".as_ptr()) };
|
||||
if class.is_null() {
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed `deviceCheckGenerateToken` aborting the whole process with `SIGTRAP` when called from a macOS session without GUI/graphic access (SSH, a launchd `LaunchDaemon`, a CI runner, a service account, a sandbox), which made every `openai-codex/*` OAuth model unusable for such accounts. `-[DCDevice isSupported]` synchronously opens an XPC connection to the per-user DeviceCheck metadata daemon, which exists only in an interactive GUI login session; without one the connection setup hits `_xpc_api_misuse` and traps before any completion handler runs, so the promise never rejects. The binding now checks the caller's security session for the `sessionHasGraphicAccess` attribute first and resolves `{ supported: false, error: … }` instead of touching DeviceCheck when it is absent ([#8353](https://github.com/can1357/oh-my-pi/issues/8353)).
|
||||
|
||||
## [17.2.12] - 2026-08-08
|
||||
|
||||
### Changed
|
||||
|
||||
Reference in New Issue
Block a user