Access to /var/run for confined snap

I’ve created a snap of WireGuard’s userspace implementation, which appears to work well in devmode. But after confinement, I get an error as soon as the engine starts up and tries to write to /var/run:

mkdir /var/run/wireguard: permission denied

This is not surprising of course, as the snap doesn’t have write access to that path. What options to I have to get this to run?

To be clear, the program itself doesn’t appear to have an option flag that would make it save its runtime socket file elsewhere (though I also haven’t looked way too hard). I could patch the codebase of course, but I’d rather look for another solution first.

Specifically, I’ve considered:

  • Any interface that would give access to /var/run?
  • Maybe I should set up a layout? (Snap layouts)
  • Some other way I’m missing

Any pointers would be appreciated!

1 Like

I’d go with layouts, that’s the easiest way to get this out of the way, my suggestion for your snapcraft.yaml file:

      type: tmpfs

Please give this a try and report back!

1 Like

Thanks for the advice @zyga-snapd! I like the idea, but I’m not quite getting there.

First off, trying this out with results in the following:

The build process is actually successful - it just looks like a glitch that’s causing the snap to not be published.

Anyway, local build works fine, and I can install the snap. But when I try to run a command I get

cannot update snap namespace: cannot open directory "/var/run": not a directory
snap-update-ns failed with code 1: No such file or directory

I tried setting

      type: tmpfs
      type: tmpfs

but that didn’t help. I also tried

      bind: $SNAP_COMMON

just to make sure it’s not an issue with tmpfs, but still got the same error about not being able to open /var/run/. Of course there are a few other permutations I could try, but I thought I’d see if you have any ideas.

By the way this is the snapcraft file:

I wanted to tick off some potential causes of the above:

  • I’m running the command with sudo
  • /var/run does exist
  • /var/run/wireguard doesn’t exist

But…it appears that /var/run is actually a symlink to /run. Could that be the problem? Also /run itself is a tmpfs, though I assume that should be fine. I’m running this on a pretty standard Ubuntu 18.04 install

Hey. I will investigate this today. Note that to see what really happens you cannot just look at the files on your host and on the initial mount namespace. Snapd does a lot of tricks to let apps run.

Thanks a lot for taking a look! And yes, appreciate there’s a lot happening under the hood. I mainly wanted to do some basic sanity checks, at least against the prerequisites you set out in the layout documentation thread.

Do let me know if there’s something else I should try (or logs I should look at, etc) in the meantime.

I will look at this now. I will add a spread test to ensure this functionality is explicitly tested with every pull request and release of snapd.

EDIT: so, quick test aside, with /var/run being a symlink to /run we are in risky waters. Snapd rightfully refuses to mount through a symbolic link of /var/run -> /run.

In addition snapd performs layout validation and refuses allow changing /run because some of the places there are sensitive.

I think that right now we need a new interface for Wireshark that would allow it to write to /run/wireshark for real.

CC: @jdstrand for opinion?

Just picking this up again. Thanks for the pointers @zyga-snapd!

To recap:

  • I can’t have a layout bind under /run/wireguard since that’s restricted. Indeed, I get the following upon trying to install with such a layout:
error: cannot perform the following tasks:
- Mount snap "wireguard-ammp" (36) (layout "/run/wireguard" in an off-limits area)
  • I also cannot have a layout that binds to /var/run/wireguard since /var/run is a symlink.

So the upshot is that this can’t be made to work with layouts. The options on the table then, I guess, are:

  1. Patch the upstream codebase so that the path under which WireGuard’s socket file is not hardcoded, and can e.g. be set via an environment variable
  2. Have an interface created that allows writing to /var/run/wireguard

What’s the likelihood of #2 being a viable way forward? Or should I just plough ahead with #1?

For reference, the requirements/behavior of WireGuard with respect to access are described here

FWIW, I gave patching a go. The socket file is now successfully created under $SNAP_DATA/socket/ - but…I promptly get

ERROR: (wg0) 2018/11/11 04:19:29 UAPI listen error: listen unix /var/snap/wireguard-ammp/43/socket/wg0.sock: listen: operation not permitted

Some casual googling (e.g. leads me to believe that this error is due to the fact that the socket file is not in an appropriate/allowable location. So it seems I’m back to square one. Any ideas?

do you have network-bind in your plugs section (IIRC that is needed for socket communication) ?

1 Like

Thanks for the tip @ogra. I was hoping that would be it but after adding and connecting the interface I get the same behavior. The following is what I get in the log:

Nov 11 15:20:07 ubuntu-vm systemd-udevd[81075]: link_config: autonegotiation is unset or enabled, the speed and duplex are not writable.
Nov 11 15:20:07 ubuntu-vm kernel: [55513.384117] audit: type=1326 audit(1541946007.299:810): auid=1000 uid=0 gid=0 ses=38 pid=81038 comm="wireguard-go" exe="/snap/wireguard-ammp/49/usr/bin/wireguard-go" sig=0 arch=c000003e syscall=50 compat=0 ip=0x48a550 code=0x50000
Nov 11 15:20:07 ubuntu-vm networkd-dispatcher[30172]: WARNING:Unknown index 18 seen, reloading interface list
Nov 11 15:20:07 ubuntu-vm systemd-udevd[81075]: Process '/bin/sh -c 'echo 180 >/sys$DEVPATH/timeout'' failed with exit code 2.
Nov 11 15:20:07 ubuntu-vm networkd-dispatcher[30172]: ERROR:Unknown interface index 18 seen even after reload
Nov 11 15:20:07 ubuntu-vm systemd-udevd[81075]: Process '/bin/sh -c 'echo 180 >/sys$DEVPATH/timeout'' failed with exit code 2.
Nov 11 15:20:07 ubuntu-vm systemd-udevd[81079]: Process '/bin/sh -c 'echo 180 >/sys$DEVPATH/timeout'' failed with exit code 2.

well, the audit message talks about syscall=50 … which is listen() on x86 … you now made me check network-bind and it clearly defines the listen syscall, which is weird:

is your snapcraft.yaml on GH up to date ? i dont see network-bind defined for wireguard-go…

1 Like

:man_facepalming: …yes, that’s because I had accidentally mis-assigned the interface in the snapcraft.yaml. Thanks @ogra for going the extra mile to figure that out.

With the network-bind interface correctly associated with wireguard-go, the whole thing appears to work 100% now!

I’ll leave this open for now since the original question regarding access to /var/run remains. In the meantime, if anyone’s looking for a functioning WireGuard snap it’s here: Install WireGuard on Linux | Snap Store

Great work @svet! Just a note in case you didn’t know, the patch you made in can be part of the snap, so you don’t have to maintain a fork.

We used this in the nextcloud snap for a mysql patch:

1 Like

Yup, good point @pachulo! Having a patch was my original vision for how to do it also - and I agree is a better long-term solution. The fork+edit seemed more straightforward for a proof-of-concept. Ideally of course I would be able to get the upstream developers to make the change (or something like it), which is sensible from a functionality perspective anyway

1 Like

Great point! Go for it then! :grinning:

Better yet, upstream it in a generic way and then just use it from your snap :slight_smile:

I think having a dedicated interface is sensible.

Has there been any update on getting an interface to allow a strict mode snap to access files in /var/run? I also have an application that needs to talk to a closed source driver that places socket files and such in /var/run.

@olympionex - fyi, these days snapd allows snaps to create/use a snap-specific directory in /run/snap.<snap name>/ and any commands within the snap are able to access those files. That should cover many use cases. For snap-to-snap communication, that can either be done via the content interface or implementing an application specific interface, like with mir, udisks2, etc. It really depends on the situation. You may want to start a new topic if this doesn’t meet your needs and can discuss paths forward.

/me notes that /var/run is typically a symlink to /run these days