mirror of
https://github.com/morluto/rea.git
synced 2026-11-13 18:22:42 +00:00
fix(desktop): preserve literal directories in ELF origin expansion (#10215)
fix(desktop): expand ELF origin paths as literal directory names
This commit is contained in:
1 parent
966bde3780
commit
c19d319929
3 files changed
+77
-4
No files matched your search
@@ -10,6 +10,50 @@ import { inspectLibraryPackages } from "./LibraryPackageInventory.js";
|
||||
import { elfImage } from "../domain/desktop/elfImage.fixture.js";
|
||||
import { createTestTempDirectory } from "../../tests/fixtures/temporaryDirectory.js";
|
||||
|
||||
describe.skipIf(process.platform === "win32")(
|
||||
"literal ELF origin paths",
|
||||
() => {
|
||||
it.each(["rpath", "runpath"] as const)(
|
||||
"resolves %s libraries when the executable's directory contains dollars",
|
||||
async (tag) => {
|
||||
const root = await createTestTempDirectory("rea-library-origin-");
|
||||
const bin = join(root, "$build-$&", "bin");
|
||||
const lib = join(root, "$build-$&", "lib");
|
||||
await Promise.all([
|
||||
mkdir(bin, { recursive: true }),
|
||||
mkdir(lib, { recursive: true }),
|
||||
]);
|
||||
const executable = join(bin, "app");
|
||||
const library = join(lib, "liborigin.so");
|
||||
await Promise.all([
|
||||
writeFile(
|
||||
executable,
|
||||
elfImage({ needed: ["liborigin.so"], [tag]: "${ORIGIN}/../lib" }),
|
||||
),
|
||||
writeFile(library, elfImage({})),
|
||||
]);
|
||||
const queried: string[] = [];
|
||||
const result = await inspectLibraryPackages(
|
||||
executable,
|
||||
"app",
|
||||
async (command, args) => {
|
||||
if (command === "ldconfig") return { stdout: "", exitCode: 0 };
|
||||
queried.push(...args.slice(1));
|
||||
return { stdout: `origin-owner: ${library}`, exitCode: 0 };
|
||||
},
|
||||
undefined,
|
||||
);
|
||||
expect(result).toEqual({
|
||||
library_packages: ["origin-owner"],
|
||||
missing_libraries: [],
|
||||
unpackaged_libraries: [],
|
||||
});
|
||||
expect(queried).toContain(library);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
it.skipIf(process.platform === "win32")(
|
||||
"retains a compatible candidate's package when its declared header size is invalid",
|
||||
async () => {
|
||||
|
||||
@@ -325,6 +325,33 @@ describe("libraryClosure unresolved candidates", () => {
|
||||
});
|
||||
|
||||
describe("libraryClosure search paths", () => {
|
||||
it("expands ORIGIN literally while leaving unsupported source tokens unresolved", async () => {
|
||||
const closure = await libraryClosure(
|
||||
{
|
||||
path: "/opt/$build-$&/bin/app",
|
||||
dependencies: elf(
|
||||
["liborigin.so", "libunsupported.so"],
|
||||
["$ORIGIN/../lib", "$ORIGIN/$LIB", "$ORIGIN_SUFFIX", "relative"],
|
||||
),
|
||||
},
|
||||
[],
|
||||
host({
|
||||
"/opt/$build-$&/lib/liborigin.so": elf([]),
|
||||
"/opt/$build-$&/bin/$LIB/libunsupported.so": elf([]),
|
||||
"/opt/$build-$&/bin_SUFFIX/libunsupported.so": elf([]),
|
||||
}),
|
||||
10,
|
||||
);
|
||||
expect(closure).toEqual({
|
||||
libraries: [
|
||||
{ soname: "liborigin.so", path: "/opt/$build-$&/lib/liborigin.so" },
|
||||
],
|
||||
missing: ["libunsupported.so"],
|
||||
unreadable: [],
|
||||
truncated: false,
|
||||
});
|
||||
});
|
||||
|
||||
it("normalizes $ORIGIN/.. before telling the app's own folder from system libraries", async () => {
|
||||
const closure = await libraryClosure(
|
||||
{
|
||||
|
||||
@@ -66,16 +66,18 @@ interface LoadedObject {
|
||||
readonly loader: LoadedObject | undefined;
|
||||
}
|
||||
|
||||
const ORIGIN_TOKEN = /\$(?:ORIGIN(?![A-Za-z0-9_])|\{ORIGIN\})/gu;
|
||||
|
||||
/** Absolute directories with `$ORIGIN` expanded to the owner's folder; relative and other dynamic-token paths are left out. */
|
||||
const expanded = (
|
||||
owner: string,
|
||||
directories: readonly string[],
|
||||
): readonly string[] =>
|
||||
directories
|
||||
.map((path) =>
|
||||
path.replace(/\$(?:ORIGIN|\{ORIGIN\})/gu, posix.dirname(owner)),
|
||||
)
|
||||
.filter((path) => path.startsWith("/") && !path.includes("$"))
|
||||
// Check tokens before expansion: dollars in the owner's directory are data.
|
||||
.filter((path) => !path.replace(ORIGIN_TOKEN, "").includes("$"))
|
||||
.map((path) => path.replace(ORIGIN_TOKEN, () => posix.dirname(owner)))
|
||||
.filter((path) => path.startsWith("/"))
|
||||
.map((path) => posix.normalize(path));
|
||||
|
||||
/**
|
||||
|
||||
Reference in new issue
Block a user