mirror of
https://github.com/morluto/rea.git
synced 2026-11-07 05:56:19 -10:00
fix(ghidra): preserve project access failures
This commit is contained in:
1 parent
6734dee6a8
commit
6979c589b0
2 files changed
+68
-11
No files matched your search
@@ -63,18 +63,24 @@ const selectionFailure = (
|
||||
new ConfigurationError(message, {
|
||||
settings: [{ setting, constraint: message }],
|
||||
});
|
||||
const entriesFor = (name: string) => [`${name}.gpr`, `${name}.rep`];
|
||||
const entriesFor = (name: string) => [`${name}.gpr`, `${name}.rep`] as const;
|
||||
|
||||
const absentProjectEntry = (cause: unknown): undefined => {
|
||||
if (cause instanceof Error && "code" in cause && cause.code === "ENOENT")
|
||||
return undefined;
|
||||
throw cause;
|
||||
};
|
||||
|
||||
const validateProject = async (root: string, name: string): Promise<void> => {
|
||||
if (!(await lstat(root)).isDirectory())
|
||||
if (!(await lstat(root).catch(absentProjectEntry))?.isDirectory())
|
||||
throw selectionFailure(
|
||||
`Existing Ghidra project directory does not exist: ${root}`,
|
||||
);
|
||||
const [marker, data] = await Promise.all(
|
||||
entriesFor(name).map((entry) =>
|
||||
lstat(join(root, entry)).catch(() => undefined),
|
||||
),
|
||||
);
|
||||
// Inspect both entries even when one is missing; a physical failure of the
|
||||
// other entry must not be mistaken for an invalid project selection.
|
||||
const [markerName, dataName] = entriesFor(name);
|
||||
const marker = await lstat(join(root, markerName)).catch(absentProjectEntry);
|
||||
const data = await lstat(join(root, dataName)).catch(absentProjectEntry);
|
||||
if (!marker?.isFile() || !data?.isDirectory())
|
||||
throw selectionFailure(
|
||||
`Existing Ghidra project requires a regular ${name}.gpr marker and ${name}.rep directory; restore saved .grez archives before selecting the project: ${root}`,
|
||||
@@ -233,10 +239,10 @@ export const copyExistingGhidraProject = async (
|
||||
resources,
|
||||
} = options;
|
||||
assertArtifactReadActive(signal);
|
||||
const source = await realpath(sourcePath).catch(() => undefined);
|
||||
const runtime = await realpath(dirname(destinationRoot)).catch(() =>
|
||||
resolve(dirname(destinationRoot)),
|
||||
);
|
||||
const source = await realpath(sourcePath).catch(absentProjectEntry);
|
||||
const runtime =
|
||||
(await realpath(dirname(destinationRoot)).catch(absentProjectEntry)) ??
|
||||
resolve(dirname(destinationRoot));
|
||||
if (
|
||||
source !== undefined &&
|
||||
entriesFor(projectName).some((entry) =>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import {
|
||||
chmod,
|
||||
rm,
|
||||
mkdir,
|
||||
readFile,
|
||||
readdir,
|
||||
@@ -222,3 +224,52 @@ it.skipIf(process.platform === "win32")(
|
||||
).rejects.toMatchObject({ diagnostics: { system_code: "ENOENT" } });
|
||||
},
|
||||
);
|
||||
|
||||
it.skipIf(process.platform === "win32" || process.getuid?.() === 0)(
|
||||
"preserves denied access between profile resolution and snapshot copying",
|
||||
async () => {
|
||||
const { source, destination } = await fixture();
|
||||
const project = await resolveGhidraProject(
|
||||
{ path: join(source, "selected.gpr") },
|
||||
{ path: "/tmp/target" },
|
||||
resources,
|
||||
);
|
||||
try {
|
||||
await chmod(source, 0);
|
||||
await expect(
|
||||
copyExistingGhidraProject(project.project_path, destination, {
|
||||
projectName: project.project_name,
|
||||
expectedSha256: project.sha256,
|
||||
resources,
|
||||
}),
|
||||
).rejects.toMatchObject({
|
||||
_tag: "AnalysisAccessDeniedError",
|
||||
operation: "open_binary",
|
||||
systemCode: "EACCES",
|
||||
path: join(project.project_path, "selected.gpr"),
|
||||
});
|
||||
} finally {
|
||||
await chmod(source, 0o700);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
it.skipIf(process.platform === "win32")(
|
||||
"keeps missing entries and symbolic links classified as invalid selections",
|
||||
async () => {
|
||||
const { source, destination } = await fixture();
|
||||
await rm(join(source, "selected.gpr"));
|
||||
await expect(
|
||||
copyExistingGhidraProject(source, destination, {
|
||||
projectName: "selected",
|
||||
}),
|
||||
).rejects.toMatchObject({ _tag: "ConfigurationError" });
|
||||
await writeFile(join(source, "other.gpr"), "marker");
|
||||
await symlink("other.gpr", join(source, "selected.gpr"));
|
||||
await expect(
|
||||
copyExistingGhidraProject(source, destination, {
|
||||
projectName: "selected",
|
||||
}),
|
||||
).rejects.toMatchObject({ _tag: "ConfigurationError" });
|
||||
},
|
||||
);
|
||||
Reference in new issue
Block a user