From b345e53a9b7a6ea15c9edb4f94da30def9660f24 Mon Sep 17 00:00:00 2001 From: Cafe Babe <41276330+Neumannzc@users.noreply.github.com> Date: Thu, 30 Jul 2026 18:32:44 +0800 Subject: [PATCH] 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 --- packages/desktop/src/main.ts | 16 ++-- .../desktop/src/system/linux-sandbox.test.ts | 82 ------------------- packages/desktop/src/system/linux-sandbox.ts | 45 ---------- 3 files changed, 7 insertions(+), 136 deletions(-) delete mode 100644 packages/desktop/src/system/linux-sandbox.test.ts delete mode 100644 packages/desktop/src/system/linux-sandbox.ts diff --git a/packages/desktop/src/main.ts b/packages/desktop/src/main.ts index b066e50b7..5509fdd0e 100644 --- a/packages/desktop/src/main.ts +++ b/packages/desktop/src/main.ts @@ -8,7 +8,7 @@ import { inheritLoginShellEnv } from "./login-shell-env.js"; import path from "node:path"; import { pathToFileURL } from "node:url"; -import { existsSync, statSync } from "node:fs"; +import { existsSync } from "node:fs"; import { execFileSync } from "node:child_process"; import { app, @@ -40,7 +40,6 @@ import { buildStandardContextMenuItems, } from "./window/window-manager.js"; import { setupDarwinCompositorWatchdog } from "./window/compositor-watchdog/index.js"; -import { configureLinuxSandbox } from "./system/linux-sandbox.js"; import { registerDialogHandlers } from "./features/dialogs.js"; import { registerNotificationHandlers, @@ -310,13 +309,12 @@ if (forcedUserDataDir) { } } -configureLinuxSandbox({ - platform: process.platform, - resourcesPath: process.resourcesPath, - statSandbox: (sandboxPath) => statSync(sandboxPath), - disableSandbox: () => app.commandLine.appendSwitch("no-sandbox"), - reportInspectionError: (error) => log.error("[linux-sandbox] failed to inspect helper", error), -}); +// AppImage runtimes mount the app from /tmp under the user's UID, so the SUID +// chrome-sandbox helper we ship in .deb/.rpm cannot work there. Disable the +// sandbox only in that case; .deb/.rpm keep the sandbox on, matching VS Code. +if (process.platform === "linux" && process.env.APPIMAGE) { + app.commandLine.appendSwitch("no-sandbox"); +} // Allow users to pass Chromium flags via PASEO_ELECTRON_FLAGS for debugging // rendering issues (e.g. "--disable-gpu --ozone-platform=x11"). diff --git a/packages/desktop/src/system/linux-sandbox.test.ts b/packages/desktop/src/system/linux-sandbox.test.ts deleted file mode 100644 index 988ac5745..000000000 --- a/packages/desktop/src/system/linux-sandbox.test.ts +++ /dev/null @@ -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: [], - }); - }); -}); diff --git a/packages/desktop/src/system/linux-sandbox.ts b/packages/desktop/src/system/linux-sandbox.ts deleted file mode 100644 index 724195d4e..000000000 --- a/packages/desktop/src/system/linux-sandbox.ts +++ /dev/null @@ -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); - } -}