Compare commits

...
Author SHA1 Message Date
Mohamed Boudra dfe2f6ade0 fix(desktop): report disabled Linux sandbox
Mis-permissioned or missing Chromium helpers deliberately fail open, but the degraded launch was silent. Report the reason and stattable helper metadata before adding --no-sandbox.
2026-07-30 00:41:40 +02:00
3 changed files with 51 additions and 2 deletions
+1
View File
@@ -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),
});
@@ -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: [],
});
});
+22 -1
View File
@@ -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;
}