From ee46323b493994902b04824a7dc8aae2a8117903 Mon Sep 17 00:00:00 2001 From: morluto <76467478+morluto@users.noreply.github.com> Date: Sun, 11 Oct 2026 11:51:04 +0800 Subject: [PATCH] fix(windows): preserve drive-root private runtime paths Join the admitted parent and generated child name without duplicating a drive-root separator. Reuse that name for handle-relative creation and path provenance. Add native snapshot, readback, and cleanup coverage through the Ghidra dot-prefixed temp fallback, plus a session-root contract regression. Fixes #1690 --- native/windows/src/filesystem.cc | 5 +-- scripts/verify-windows-native.mjs | 46 +++++++++++++++++++++++++++- src/ghidra/GhidraSessionRoot.test.ts | 9 ++++++ 3 files changed, 57 insertions(+), 3 deletions(-) diff --git a/native/windows/src/filesystem.cc b/native/windows/src/filesystem.cc index 4a3007623..6cfbc8e97 100644 --- a/native/windows/src/filesystem.cc +++ b/native/windows/src/filesystem.cc @@ -219,9 +219,10 @@ std::unique_ptr createRuntime(const std::wstring& parentPath, const std require(BCryptGenRandom(nullptr, random.data(), random.size(), BCRYPT_USE_SYSTEM_PREFERRED_RNG) == 0, "Generate runtime identity failed", parentPath, ERROR_GEN_FAILURE); auto result = std::make_unique(); - result->path = parent->path + L"\\" + prefix + hex(random.data(), random.size()); + const auto name = prefix + hex(random.data(), random.size()); + result->path = parent->path + (parent->path.back() == L'\\' ? L"" : L"\\") + name; Security security; - result->directory = createRelative(parent->get(), prefix + hex(random.data(), random.size()), + result->directory = createRelative(parent->get(), name, DELETE | FILE_LIST_DIRECTORY | FILE_READ_ATTRIBUTES | READ_CONTROL, true, security, result->path); try { diff --git a/scripts/verify-windows-native.mjs b/scripts/verify-windows-native.mjs index 50524475b..07252d61a 100644 --- a/scripts/verify-windows-native.mjs +++ b/scripts/verify-windows-native.mjs @@ -17,7 +17,7 @@ import { open, } from "node:fs/promises"; import { tmpdir } from "node:os"; -import { join, resolve } from "node:path"; +import { dirname, join, parse, resolve } from "node:path"; import { pathToFileURL } from "node:url"; import { verifyWindowsProtocolInput } from "./lib/windows-protocol-input.mjs"; @@ -33,6 +33,9 @@ const native = requireWindowsNativeAuthority(); const { WindowsPrivateRuntime, windowsPrivateRuntime } = await import( pathToFileURL(join(packageRoot, "dist/windows/WindowsPrivateRuntime.js")) ); +const { ghidraSessionRoot } = await import( + pathToFileURL(join(packageRoot, "dist/ghidra/GhidraSessionRoot.js")) +); const workspace = await mkdtemp(join(tmpdir(), "rea-native-conformance-")); const environment = Object.entries(process.env) .filter(([, value]) => value !== undefined) @@ -136,6 +139,47 @@ process.stdout.write(JSON.stringify({executable:basename(process.execPath),abiVe ]) assert.throws(() => native.call("open", [rejected])); report.controls.ordinaryDriveSeparatorsAndRequestedIdentity = true; + const driveRoot = parse(workspace).root; + const runtimeParent = ghidraSessionRoot({ + base: join(driveRoot, ".Tmp", "scratch"), + }); + assert.equal(runtimeParent, driveRoot); + const driveRootRuntime = native.call("runtime_create", [ + runtimeParent, + "rea-drive-root-", + ]); + try { + assert.equal(driveRootRuntime.path.startsWith(`${driveRoot}\\`), false); + assert.equal(dirname(driveRootRuntime.path), driveRoot); + const snapshot = await native.call("runtime_snapshot", [ + driveRootRuntime.handle, + source, + "probe.bin", + ]); + const sourceBytes = await readFile(source); + assert.equal( + snapshot.sha256, + createHash("sha256").update(sourceBytes).digest("hex"), + ); + assert.equal(snapshot.source.requestedPath, source); + const readback = native.call("runtime_open", [ + driveRootRuntime.handle, + "probe.bin", + ]); + try { + assert.equal(readback.size, sourceBytes.byteLength); + assert.deepEqual( + native.call("read", [readback.handle, 0, 65536]), + sourceBytes.subarray(0, 65536), + ); + } finally { + native.call("close", [readback.handle]); + } + } finally { + native.call("runtime_close", [driveRootRuntime.handle]); + } + assert.equal(await exists(driveRootRuntime.path), false); + report.controls.driveRootRuntimeParent = true; const snapshotOwner = WindowsPrivateRuntime.create( workspace.replace(/\\/u, "/"), "single-flight-", diff --git a/src/ghidra/GhidraSessionRoot.test.ts b/src/ghidra/GhidraSessionRoot.test.ts index fbfbccb6c..45cffe313 100644 --- a/src/ghidra/GhidraSessionRoot.test.ts +++ b/src/ghidra/GhidraSessionRoot.test.ts @@ -44,6 +44,15 @@ describe("ghidraSessionRoot", () => { ).toBe(posixBase("Users", "operator")); }); + it("can select a filesystem root when the inherited temp starts with a dot-prefixed element", () => { + expect( + ghidraSessionRoot({ + base: posixBase(".Tmp", "scratch"), + platform: "win32", + }), + ).toBe(resolve(sep)); + }); + it.skipIf(!POSIX)("prefers the platform temp directory by default", () => { expect( ghidraSessionRoot({ base: posixBase("home", "operator", ".cache") }),