diff --git a/packages/desktop/src/main.ts b/packages/desktop/src/main.ts index b066e50b71..a0c1fba786 100644 --- a/packages/desktop/src/main.ts +++ b/packages/desktop/src/main.ts @@ -315,6 +315,7 @@ configureLinuxSandbox({ resourcesPath: process.resourcesPath, statSandbox: (sandboxPath) => statSync(sandboxPath), disableSandbox: () => app.commandLine.appendSwitch("no-sandbox"), + reportSandboxDisabled: (report) => log.warn("[linux-sandbox] disabling Chromium sandbox", report), reportInspectionError: (error) => log.error("[linux-sandbox] failed to inspect helper", error), }); diff --git a/packages/desktop/src/system/linux-sandbox.test.ts b/packages/desktop/src/system/linux-sandbox.test.ts index 988ac57451..2f47edc955 100644 --- a/packages/desktop/src/system/linux-sandbox.test.ts +++ b/packages/desktop/src/system/linux-sandbox.test.ts @@ -12,6 +12,7 @@ function configureWithSandbox( ) { const disabledSwitches: string[] = []; const inspectionErrors: unknown[] = []; + const disableReports: unknown[] = []; configureLinuxSandbox({ platform, @@ -23,10 +24,11 @@ function configureWithSandbox( return sandbox; }, disableSandbox: () => disabledSwitches.push("no-sandbox"), + reportSandboxDisabled: (report) => disableReports.push(report), reportInspectionError: (error) => inspectionErrors.push(error), }); - return { disabledSwitches, inspectionErrors }; + return { disabledSwitches, disableReports, inspectionErrors }; } function createFileSystemError(code: string): NodeJS.ErrnoException { @@ -39,6 +41,14 @@ describe("configureLinuxSandbox", () => { it("disables the sandbox when an AppImage mount strips SUID", () => { expect(configureWithSandbox({ uid: 1000, mode: 0o755 })).toEqual({ disabledSwitches: ["no-sandbox"], + disableReports: [ + { + reason: "wrong-owner-or-mode", + sandboxPath: "/opt/Paseo/chrome-sandbox", + observedUid: 1000, + observedMode: "0755", + }, + ], inspectionErrors: [], }); }); @@ -46,6 +56,7 @@ describe("configureLinuxSandbox", () => { it("keeps the sandbox for a root-owned 4755 helper", () => { expect(configureWithSandbox({ uid: 0, mode: 0o4755 })).toEqual({ disabledSwitches: [], + disableReports: [], inspectionErrors: [], }); }); @@ -53,6 +64,14 @@ describe("configureLinuxSandbox", () => { it("disables the sandbox when a SUID helper is not root-owned", () => { expect(configureWithSandbox({ uid: 1000, mode: 0o4755 })).toEqual({ disabledSwitches: ["no-sandbox"], + disableReports: [ + { + reason: "wrong-owner-or-mode", + sandboxPath: "/opt/Paseo/chrome-sandbox", + observedUid: 1000, + observedMode: "4755", + }, + ], inspectionErrors: [], }); }); @@ -60,6 +79,12 @@ describe("configureLinuxSandbox", () => { it("disables the sandbox when the helper is missing", () => { expect(configureWithSandbox(createFileSystemError("ENOENT"))).toEqual({ disabledSwitches: ["no-sandbox"], + disableReports: [ + { + reason: "helper-missing", + sandboxPath: "/opt/Paseo/chrome-sandbox", + }, + ], inspectionErrors: [], }); }); @@ -69,6 +94,7 @@ describe("configureLinuxSandbox", () => { expect(configureWithSandbox(permissionError)).toEqual({ disabledSwitches: [], + disableReports: [], inspectionErrors: [permissionError], }); }); @@ -76,6 +102,7 @@ describe("configureLinuxSandbox", () => { it("does not inspect or configure the sandbox outside Linux", () => { expect(configureWithSandbox(createFileSystemError("EACCES"), "darwin")).toEqual({ disabledSwitches: [], + disableReports: [], inspectionErrors: [], }); }); diff --git a/packages/desktop/src/system/linux-sandbox.ts b/packages/desktop/src/system/linux-sandbox.ts index 724195d4ef..5cb4fa4a74 100644 --- a/packages/desktop/src/system/linux-sandbox.ts +++ b/packages/desktop/src/system/linux-sandbox.ts @@ -8,11 +8,24 @@ interface SandboxMetadata { uid: number; } +type SandboxDisableReport = + | { + reason: "helper-missing"; + sandboxPath: string; + } + | { + reason: "wrong-owner-or-mode"; + sandboxPath: string; + observedUid: number; + observedMode: string; + }; + interface LinuxSandboxConfiguration { platform: NodeJS.Platform; resourcesPath: string; statSandbox: (sandboxPath: string) => SandboxMetadata; disableSandbox: () => void; + reportSandboxDisabled: (report: SandboxDisableReport) => void; reportInspectionError: (error: unknown) => void; } @@ -25,17 +38,25 @@ export function configureLinuxSandbox(input: LinuxSandboxConfiguration): void { return; } + const sandboxPath = path.join(input.resourcesPath, "..", "chrome-sandbox"); + 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.reportSandboxDisabled({ + reason: "wrong-owner-or-mode", + sandboxPath, + observedUid: sandbox.uid, + observedMode: (sandbox.mode & PERMISSION_BITS).toString(8).padStart(4, "0"), + }); input.disableSandbox(); } } catch (error) { if (isMissingSandbox(error)) { + input.reportSandboxDisabled({ reason: "helper-missing", sandboxPath }); input.disableSandbox(); return; }