Trying to post Beeper to snapstore - need allow-sandbox: true

Hi Snap team!

We are very excited to launch Beeper on Snapcraft. @popey was extremely helpful and connected us to a fantastic Snap contractor (@diddledan) who helped us get our app compiled.

We have built a multi-network chat client called Beeper - www.beeperhq.com. We use a variety of interesting methods in order to display and send chat messages on 15+ different chat networks. The client is a React + Electron app. We’re using electron-builder to build the snap.

I submitted the app to Snapcraft but it was rejected for using the allow-sandbox:true. I tried removing this permission and tried switching to browser-support rather than browser-sandbox but our app no longer worked. We’re doing some browser-like things in order to get this to work, that’s probably why it no longer works if we do not use sandbox.

Can we get approved to post our Snap?

Thanks,

Eric

1 Like

Have you tried launching it with --no-sandbox as a parameter? Assuming this works you can make this default behaviour and it’s generally how most Electron apps are configured in the Snap Store.

1 Like

Hmm just tried that as well. App does not boot correctly when I launch with --no-sandbox. I just get a white screen (react app never launches)

/usr/share/libdrm/amdgpu.ids: No such file or directory
[3652594:0222/101807.684531:FATAL:platform_shared_memory_region_posix.cc(255)] This is frequently caused by incorrect permissions on /dev/shm.  Try 'sudo chmod 1777 /dev/shm' to fix.

That’s unfortunate, there was a similar error a few weeks back also with Electron Builder, but debugging it didn’t get anything concrete

There’s also the --disable-dev-shm-usage flag, but this isn’t expected to be default in snaps and didn’t improve the scenario in the thread above, though it’s worth a go.

It could be worth trying to do a build with the snapcraft build tool itself rather than Electron Build to see if that improves the situation, otherwise given this thread is a request for an interface declaration and it presumably works fine with that declaration, maybe it’ll be granted and not end up a problem for you, but it looks like there’s something funny going on with Electron lately that is worth looking more into.

ok! When I start beeper-beta --disable-dev-shm-usage it starts and seems to work. But when I launch it with beeper-beta --disable-dev-shm-usage --no-sandbox it does not work.

What should be my next step to get this app on Snapcraft? I’m open to all options!

If it can’t be made to work with --no-sandbox, wait around until the reviewer team takes a look here and they’ll consider the relevant factors, in the event the request is denied we’d have to debug why --no-sandbox refuses to work, it would appear that it’s not a problem unique to Beeper, but the vast majority of Electron snaps are using --no-sandbox.

There’s an overview of the requests process here if you’re curious, basically all you should do now is wait a while for the reviewer team to see if you can get approval and it takes about a week.

2 Likes

Just pitching in: working on this snap, I have tried both with and without the sandbox. I can only get the app to launch completely (it shows a blank white screen when it fails) with the sandbox enabled along with the allow-sandbox feature of the browser-support interface.

With the sandbox disabled, there are no relevant denials, but the app itself reports:

[424357:0222/191054.337271:FATAL:platform_shared_memory_region_posix.cc(254)] This is frequently caused by incorrect permissions on /dev/shm.  Try 'sudo chmod 1777 /dev/shm' to fix.

It seems that electron is somehow checking for access to /dev/shm without actually reading or writing anything to the directory.

For completeness, here’s the snappy-debug messages:

= AppArmor =
Time: Feb 22 19:10:40
Log: apparmor="DENIED" operation="capable" profile="/usr/lib/snapd/snap-confine" pid=424078 comm="snap-confine" capability=4  capname="fsetid"
Capability: fsetid
Suggestions:
* adjust program to not require 'CAP_FSETID' (see 'man 7 capabilities')
* add one of 'account-control' to 'plugs'
* do nothing if program otherwise works properly

= AppArmor =
Time: Feb 22 19:10:40
Log: apparmor="DENIED" operation="open" profile="snap.beeper.beeper" name="/snap/core/10823/usr/share/locale/en_GB/LC_MESSAGES/snappy.mo" pid=424078 comm="snap-exec" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0
File: /snap/core/10823/usr/share/locale/en_GB/LC_MESSAGES/snappy.mo (read)
Suggestion:
* adjust program to read necessary files from $SNAP, $SNAP_DATA, $SNAP_COMMON, $SNAP_USER_DATA or $SNAP_USER_COMMON

= AppArmor =
Time: Feb 22 19:10:40
Log: apparmor="DENIED" operation="open" profile="snap.beeper.beeper" name="/home/dllewellyn/Nextcloud/Documents/" pid=424134 comm="head" requested_mask="r" denied_mask="r" fsuid=1000 ouid=1000
File: /home/dllewellyn/Nextcloud/Documents/ (read)
Suggestion:
* add 'home' to 'plugs'

= AppArmor =
Time: Feb 22 19:10:47
Log: apparmor="DENIED" operation="dbus_method_call"  bus="system" path="/" interface="org.freedesktop.DBus.ObjectManager" member="GetManagedObjects" mask="send" name="org.bluez" pid=424078 label="snap.beeper.beeper" peer_pid=2486 peer_label="unconfined"
DBus access

As you see, they’re all fairly benign, with the only really interesting one being the first message about snap-confine though that might be unrelated.

1 Like

this is benign and not related

FWIW, we looked at this a bit internally and could not figure out what the issue is with another snap, the wordpress-desktop snap in the edge channel, and we could not get it to work with --no-sandbox no matter what confinement we use, i.e. devmode or allow-sandbox: true, etc. so I think there is something more fundamental broken with new electron snaps and the sandboxing as it pertains to snaps. I think it needs more investigation from someone who has good electron/chromium knowledge

1 Like

also as an antecdote, I tried to reproduce this by running the same system call (access()) on the same dir that chromium is trying from a Go program like this:

package main

import (
    "fmt"
    "os"

    "golang.org/x/sys/unix"
)

func main() {
    fmt.Println(unix.Access(os.Args[1], unix.W_OK|unix.X_OK))
}

but my Go program works and chromium apparently doesn’t work which leads me to believe that the /dev/shm problem is not confinement related but somehow configuration or a code bug in chromium.

1 Like

Here’s the code path that fails in Chromium:

  FilePath path;
  ScopedFD fd = CreateAndOpenFdForTemporaryFileInDir(directory, &path);
  File shm_file(fd.release());
  if (!shm_file.IsValid()) {
    PLOG(ERROR) << "Creating shared memory in " << path.value() << " failed";
    FilePath dir = path.DirName();
    if (access(dir.value().c_str(), W_OK | X_OK) < 0) {
      PLOG(ERROR) << "Unable to access(W_OK|X_OK) " << dir.value();
      if (dir.value() == "/dev/shm") {
        LOG(FATAL) << "This is frequently caused by incorrect permissions on "
                   << "/dev/shm.  Try 'sudo chmod 1777 /dev/shm' to fix.";
      }
    }
    return {};
  }

c.f. https://chromium.googlesource.com/chromium/src/+/master/base/memory/platform_shared_memory_region_posix.cc#255

right this is what is failing, but why is the question to me, we allow the access syscall unconditionally with any arguments and the dir it is checking here is $XDG_RUNTIME_DIR which the snap has access to via AppArmor

it’s trying /dev/shm:

https://source.chromium.org/chromium/chromium/src/+/master:base/files/file_util_posix.cc;l=1101

But if you specify --disable-dev-shm-usage then it’s not doing that and uses $XDG_RUNTIME_DIR and it still displays a white window and complains about /dev/shm. Though I could try using my Go program in the snap confinement with /dev/shm and see what happens

1 Like

I don’t think this is correct. (edit, no, I’m wrong here sorry :-)) The only reference I can figure out from the chromium source is to find that it calls the function PlatformSharedMemoryRegion::Create with executable set to true. When executable = true you get to the following code which will always attempt to use /dev/shm if the permission on the filesystem include executable access:

#if !defined(OS_ANDROID)
// This is implemented in file_util_android.cc for that platform.
bool GetShmemTempDir(bool executable, FilePath* path) {
#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_AIX)
  bool disable_dev_shm = false;
#if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS)
  disable_dev_shm = CommandLine::ForCurrentProcess()->HasSwitch(
      switches::kDisableDevShmUsage);
#endif
  bool use_dev_shm = true;
  if (executable) {
    static const bool s_dev_shm_executable =
        IsPathExecutable(FilePath("/dev/shm"));
    use_dev_shm = s_dev_shm_executable;
  }
  if (use_dev_shm && !disable_dev_shm) {
    *path = FilePath("/dev/shm");
    return true;
  }
#endif  // defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_AIX)
  return GetTempDir(path);
}
#endif  // !defined(OS_ANDROID)

Edit: wait, I’m wrong - I see the relevant command line bit in the above code that overrides the default behaviour.

On a different track, here’s some strace… (running with --no-sandbox and --disable-dev-shm-usage)

[pid 518352] openat(AT_FDCWD, "/dev/shm/.org.chromium.Chromium.ZoYzIO", O_RDWR|O_CREAT|O_EXCL, 0600 <unfinished ...>
[pid 518352] <... openat resumed>)      = -1 EPERM (Operation not permitted)
...
[pid 518352] access("/dev/shm", W_OK|X_OK <unfinished ...>
[pid 518352] <... access resumed>)      = -1 EPERM (Operation not permitted)
...
[pid 518352] socketpair(AF_UNIX, SOCK_SEQPACKET, 0 <unfinished ...>
[pid 518352] <... socketpair resumed>, [29, 30]) = 0
...
[pid 518352] close(30 <unfinished ...>
[pid 518352] <... close resumed>)       = 0
...
[pid 518352] close(29 <unfinished ...>
[pid 518352] <... close resumed>)       = 0
...
[pid 518352] write(2, "[518352:0222/231315.188400:FATAL"..., 182 <unfinished ...>
[pid 518352] <... write resumed>)       = 182
...
[pid 518352] --- SIGTRAP {si_signo=SIGTRAP, si_code=SI_KERNEL} ---

While there is a chromium switch --disable-dev-shm-usage, I can’t find any implementation for it in electron. They do have an explicit --no-sandbox thing in their repository so I am tentatively thinking that electron does not honor the --disable-dev-shm-usage flag at all.

Don’t electron flags get passed onto chromium directly? If not that feels like a bug in electron

I think they get first passed to electron and only “electron supported” switches get handed through:

https://www.electronjs.org/docs/api/command-line-switches

but there is a way to forcefully create additional switches that get handed through from within your app code:

https://www.electronjs.org/docs/api/command-line

1 Like

That was how I was reading things, too. I’m glad I’m not going too crazy :wink:

@ijohnson not sure if you know anyone on the app review team, but it would be good to get an update about whether we can get this app approved soon. I’d like to make this available to our linux users vs distributing appimages. Snap is so much better!