Fix Linux desktop package startup (#2654)
Restore the Linux startup behavior that shipped in 0.2.3 by reverting the generalized sandbox detection from #2439. Co-authored-by: tang <tang@tang-zai>
This commit is contained in:
@@ -8,7 +8,7 @@ import { inheritLoginShellEnv } from "./login-shell-env.js";
|
|||||||
|
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import { pathToFileURL } from "node:url";
|
import { pathToFileURL } from "node:url";
|
||||||
import { existsSync, statSync } from "node:fs";
|
import { existsSync } from "node:fs";
|
||||||
import { execFileSync } from "node:child_process";
|
import { execFileSync } from "node:child_process";
|
||||||
import {
|
import {
|
||||||
app,
|
app,
|
||||||
@@ -40,7 +40,6 @@ import {
|
|||||||
buildStandardContextMenuItems,
|
buildStandardContextMenuItems,
|
||||||
} from "./window/window-manager.js";
|
} from "./window/window-manager.js";
|
||||||
import { setupDarwinCompositorWatchdog } from "./window/compositor-watchdog/index.js";
|
import { setupDarwinCompositorWatchdog } from "./window/compositor-watchdog/index.js";
|
||||||
import { configureLinuxSandbox } from "./system/linux-sandbox.js";
|
|
||||||
import { registerDialogHandlers } from "./features/dialogs.js";
|
import { registerDialogHandlers } from "./features/dialogs.js";
|
||||||
import {
|
import {
|
||||||
registerNotificationHandlers,
|
registerNotificationHandlers,
|
||||||
@@ -310,13 +309,12 @@ if (forcedUserDataDir) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
configureLinuxSandbox({
|
// AppImage runtimes mount the app from /tmp under the user's UID, so the SUID
|
||||||
platform: process.platform,
|
// chrome-sandbox helper we ship in .deb/.rpm cannot work there. Disable the
|
||||||
resourcesPath: process.resourcesPath,
|
// sandbox only in that case; .deb/.rpm keep the sandbox on, matching VS Code.
|
||||||
statSandbox: (sandboxPath) => statSync(sandboxPath),
|
if (process.platform === "linux" && process.env.APPIMAGE) {
|
||||||
disableSandbox: () => app.commandLine.appendSwitch("no-sandbox"),
|
app.commandLine.appendSwitch("no-sandbox");
|
||||||
reportInspectionError: (error) => log.error("[linux-sandbox] failed to inspect helper", error),
|
}
|
||||||
});
|
|
||||||
|
|
||||||
// Allow users to pass Chromium flags via PASEO_ELECTRON_FLAGS for debugging
|
// Allow users to pass Chromium flags via PASEO_ELECTRON_FLAGS for debugging
|
||||||
// rendering issues (e.g. "--disable-gpu --ozone-platform=x11").
|
// rendering issues (e.g. "--disable-gpu --ozone-platform=x11").
|
||||||
|
|||||||
@@ -1,82 +0,0 @@
|
|||||||
import { describe, expect, it } from "vitest";
|
|
||||||
import { configureLinuxSandbox } from "./linux-sandbox";
|
|
||||||
|
|
||||||
interface SandboxMetadata {
|
|
||||||
mode: number;
|
|
||||||
uid: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
function configureWithSandbox(
|
|
||||||
sandbox: SandboxMetadata | Error,
|
|
||||||
platform: NodeJS.Platform = "linux",
|
|
||||||
) {
|
|
||||||
const disabledSwitches: string[] = [];
|
|
||||||
const inspectionErrors: unknown[] = [];
|
|
||||||
|
|
||||||
configureLinuxSandbox({
|
|
||||||
platform,
|
|
||||||
resourcesPath: "/opt/Paseo/resources",
|
|
||||||
statSandbox: () => {
|
|
||||||
if (sandbox instanceof Error) {
|
|
||||||
throw sandbox;
|
|
||||||
}
|
|
||||||
return sandbox;
|
|
||||||
},
|
|
||||||
disableSandbox: () => disabledSwitches.push("no-sandbox"),
|
|
||||||
reportInspectionError: (error) => inspectionErrors.push(error),
|
|
||||||
});
|
|
||||||
|
|
||||||
return { disabledSwitches, inspectionErrors };
|
|
||||||
}
|
|
||||||
|
|
||||||
function createFileSystemError(code: string): NodeJS.ErrnoException {
|
|
||||||
const error: NodeJS.ErrnoException = new Error(code);
|
|
||||||
error.code = code;
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
describe("configureLinuxSandbox", () => {
|
|
||||||
it("disables the sandbox when an AppImage mount strips SUID", () => {
|
|
||||||
expect(configureWithSandbox({ uid: 1000, mode: 0o755 })).toEqual({
|
|
||||||
disabledSwitches: ["no-sandbox"],
|
|
||||||
inspectionErrors: [],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("keeps the sandbox for a root-owned 4755 helper", () => {
|
|
||||||
expect(configureWithSandbox({ uid: 0, mode: 0o4755 })).toEqual({
|
|
||||||
disabledSwitches: [],
|
|
||||||
inspectionErrors: [],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("disables the sandbox when a SUID helper is not root-owned", () => {
|
|
||||||
expect(configureWithSandbox({ uid: 1000, mode: 0o4755 })).toEqual({
|
|
||||||
disabledSwitches: ["no-sandbox"],
|
|
||||||
inspectionErrors: [],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("disables the sandbox when the helper is missing", () => {
|
|
||||||
expect(configureWithSandbox(createFileSystemError("ENOENT"))).toEqual({
|
|
||||||
disabledSwitches: ["no-sandbox"],
|
|
||||||
inspectionErrors: [],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("keeps the sandbox and reports unexpected inspection failures", () => {
|
|
||||||
const permissionError = createFileSystemError("EACCES");
|
|
||||||
|
|
||||||
expect(configureWithSandbox(permissionError)).toEqual({
|
|
||||||
disabledSwitches: [],
|
|
||||||
inspectionErrors: [permissionError],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("does not inspect or configure the sandbox outside Linux", () => {
|
|
||||||
expect(configureWithSandbox(createFileSystemError("EACCES"), "darwin")).toEqual({
|
|
||||||
disabledSwitches: [],
|
|
||||||
inspectionErrors: [],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
import path from "node:path";
|
|
||||||
|
|
||||||
const REQUIRED_SANDBOX_MODE = 0o4755;
|
|
||||||
const PERMISSION_BITS = 0o7777;
|
|
||||||
|
|
||||||
interface SandboxMetadata {
|
|
||||||
mode: number;
|
|
||||||
uid: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface LinuxSandboxConfiguration {
|
|
||||||
platform: NodeJS.Platform;
|
|
||||||
resourcesPath: string;
|
|
||||||
statSandbox: (sandboxPath: string) => SandboxMetadata;
|
|
||||||
disableSandbox: () => void;
|
|
||||||
reportInspectionError: (error: unknown) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isMissingSandbox(error: unknown): boolean {
|
|
||||||
return error instanceof Error && "code" in error && error.code === "ENOENT";
|
|
||||||
}
|
|
||||||
|
|
||||||
export function configureLinuxSandbox(input: LinuxSandboxConfiguration): void {
|
|
||||||
if (input.platform !== "linux") {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const sandboxPath = path.join(input.resourcesPath, "..", "chrome-sandbox");
|
|
||||||
const sandbox = input.statSandbox(sandboxPath);
|
|
||||||
const hasUsableSandbox =
|
|
||||||
sandbox.uid === 0 && (sandbox.mode & PERMISSION_BITS) === REQUIRED_SANDBOX_MODE;
|
|
||||||
|
|
||||||
if (!hasUsableSandbox) {
|
|
||||||
input.disableSandbox();
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
if (isMissingSandbox(error)) {
|
|
||||||
input.disableSandbox();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
input.reportInspectionError(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user