electron-userland/electron-builder

How to pass --no-sandbox Debian appImage?

Closed this issue · 20 comments

In order to run electron on Debian I have to start it with the --no-sandbox option. How can I have this automatically done for my appImage generated by electron-builder? I don't want my users to have to run the app from the command line and enter --no-sandbox everytime.

Thanks.

I'm having the exact same problem, any solutions or workarounds yet?

stale commented

Is this still relevant? If so, what is blocking it? Is there anything you can do to help move it forward?

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.

Yes, still relevant for Debian 10+

Sharing my solution for other folks who stumble across this issue.

In my package.json I run a script after packaging the app:

 "build": {
    "afterPack": "./appimage-fix.js",

This script renames the executable that usually gets launched to <app-name>.bin and creates a shell script with the old name of the executable: <app-name>. So that when you launch the app-image the shell script gets executed.

The shell script then opens the <app-name>.bin file with the --no-sandbox option.

appimage-fix.js

Just swap out the appName variable with the one specified in your package.json and you're good to go.

const child_process = require('child_process'),
    fs = require('fs'),
    path = require('path');
    
const appName = "youtube-dl-gui";    

function isLinux (targets) {
    const re = /AppImage|snap|deb|rpm|freebsd|pacman/i;
    return !!targets.find ( target => re.test (target.name));
}

async function afterPack ({targets, appOutDir}) {
    if ( !isLinux ( targets ) ) return;
    const scriptPath = path.join(appOutDir, appName),
        script = '#!/bin/bash\n"${BASH_SOURCE%/*}"/' + appName + '.bin "$@" --no-sandbox';
    new Promise((resolve) => {
        const child = child_process.exec(`mv ${appName} ${appName}.bin`, {cwd: appOutDir});  
        child.on('exit', () => {
            resolve();
        });    
    }).then(() => {
        fs.writeFileSync (scriptPath, script);
        child_process.exec(`chmod +x ${appName}`, {cwd: appOutDir});
    });
}

module.exports = afterPack;

Thanks a lot @jely2002, this is a good workaround.

Based on your solution I have taken the same approach for jitsi/jitsi-meet-electron#550, only difference is that it takes the executable name from the packager context and the renames and file writing is done via the async promises nodejs api: https://github.com/csett86/jitsi-meet-electron/blob/fix-231/linux-sandbox-fix.js

stale commented

Is this still relevant? If so, what is blocking it? Is there anything you can do to help move it forward?

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.

Yes, this is still relevant for Debian 10+

stale commented

Is this still relevant? If so, what is blocking it? Is there anything you can do to help move it forward?

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.

AppImages based on Electron require the kernel to be configured in a certain way to allow for its sandboxing to work as intended (specifically, the kernel needs to be allowed to provide “unprivileged namespaces”). Many distributions come with this configured out of the box (like Ubuntu for instance), but some do not (for example Debian).

To temporarily enable unprivileged namespaces, you can run this command:

sudo sysctl -w kernel.unprivileged_userns_clone=1

This command will take effect immediately but will not survive a reboot. To permanently enable unprivileged namespaces, run:

echo kernel.unprivileged_userns_clone = 1 | sudo tee /etc/sysctl.d/00-local-userns.conf

This command will take effect only on the next reboot.

Please see https://docs.appimage.org/user-guide/troubleshooting.html#i-have-issues-with-electron-based-appimages-and-their-sandboxing for more information.

If you think that Debian should enable unprivileged namespaces by default (like most other desktop distributions do), then please file an issue with Debian.

stale commented

Is this still relevant? If so, what is blocking it? Is there anything you can do to help move it forward?

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.

Please reopen.

This is the only information I could locate on your request, but I don't know what AppRun is.
https://discourse.appimage.org/t/command-line-parameter-transfer/1537

AFAICT, this is not a feature that can be built by electron-builder. AppImage creation is handled by an upstream project https://github.com/develar/app-builder, so any feature request will need to be opened there.

@probonopd I found this PR that might serve what you need for AppImages?
https://github.com/electron-userland/electron-builder/pull/6429/files
Way to pass --no-sandbox for linux is via executableArgs in electron-builder config, but it's already considered default if no other args provided

Alternatively, in my project, I noticed previous logic for just adding it in main/index.ts

app.commandLine.appendSwitch("--no-sandbox");

Thanks @mmaietta. This will help a lot of people.
It should be made the default.

I have made a tool that automatically applies the --no-sandbox flag when the unprivileged_userns_clone kernel feature is not enabled: https://www.npmjs.com/package/electron-builder-sandbox-fix

Cool! We should add this to the AppImage (and Electron?) docs.

Even better, this should be made the default in Electron for AppImages.

I would not make this the default, as Debian 11 also no longer requires the --no-sandbox. Since Debian 11 unprivileged processes can create namespaces by default: https://www.debian.org/releases/bullseye/amd64/release-notes/ch-information.en.html#linux-user-namespaces

@probonopd AppImage target already applies --no-sandbox by default (added Oct 16th, 2020 in ede6d50) if no custom executableArgs are passed in via the electron-builder config

this.desktopEntry = new Lazy<string>(() => {
const args = this.options.executableArgs?.join(" ") || "--no-sandbox"

I am getting "[1109/191656.470723:FATAL:electron_main_delegate.cc(298)] Running as root without --no-sandbox is not supported. See https://crbug.com/638180.". passing --no-sandbox will fix it. but none of the executableArgs and the app.commandLine.appendSwitch("--no-sandbox") worked. (electron v21.2.2, electron-builder v23.6.0 FWIW)