Public bug reported:

Say, we are running on a classic distribution in a confined mode:

https://github.com/snapcore/snapd/blob/master/cmd/snap-confine/mount-
support.c#L531

That means that the following mounts are set up for a process after creating a 
new mount ns and changing its rootfs to a different fs via pivot_root:
        if (on_classic) {
                const struct sc_mount mounts[] = {
                        {"/dev"},       // because it contains devices on host 
OS
                        {"/etc"},       // because that's where 
/etc/resolv.conf lives, perhaps a bad idea
                        {"/home"},      // to support /home/*/snap and home 
interface
                        {"/root"},      // because that is $HOME for services
                        {"/proc"},      // fundamental filesystem
                        {"/sys"},       // fundamental filesystem
                        {"/tmp"},       // to get writable tmp
                        {"/var/snap"},  // to get access to global snap data
                        {"/var/lib/snapd"},     // to get access to snapd state 
and seccomp profiles
                        {"/var/tmp"},   // to get access to the other temporary 
directory
                        {"/run"},       // to get /run with sockets and what not
                        {"/lib/modules"},       // access to the modules of the 
running kernel
                        {"/usr/src"},   // FIXME: move to SecurityMounts in 
system-trace interface
                        {"/var/log"},   // FIXME: move to SecurityMounts in 
log-observe interface
#ifdef MERGED_USR
                        {"/run/media", true},   // access to the users 
removable devices
#else
                        {"/media", true},       // access to the users 
removable devices
#endif                          // MERGED_USR
                        {"/run/netns", true},   // access to the 'ip netns' 
network namespaces
                        {},
                };
---

One example of two applications communicating securely via POSIX IPC is
when a directory with a unix socket is shared from one snap to another
via the content interface (have to provide read-write access since
sockets are bidirectional).

Provider:
...
apps:                                                                           
                                                                                
                                                                       
  consul:                                                                       
                                                                                
                                                                       
    command: consul-snap                                                        
                                                                                
                                                                       
    plugs: [network, network-bind, network-observe]                             
                                                                                
                                                                       
    slots: [consul-tmp]                                                         
                                                                                
                                                                       

slots:                                                                          
                                                                                
                                                                       
  consul-tmp:                                                                   
                                                                                
                                                                       
    interface: content                                                          
                                                                                
                                                                       
    content: consul-tmp                                                         
                                                                                
                                                                       
    # read-write access to the consul socket for                                
                                                                                
                                                                       
    # HTTP communication with the consul agent                                  
                                                                                
                                                                       
    write: [/tmp] 
...

Consumer:

apps:                                                                           
                                                                                
                                                                       
  vault:                                                                        
                                                                                
                                                                       
    command: vault-snap
    plugs: [network, network-bind, consul-tmp]                                  
                                                                                
                                                                                
                                     
plugs:
  consul-tmp:
    interface: content                                                          
                                                                                
                                                                       
    content: consul-tmp
    target: $SNAP/consul                                                        
                                                                                
                                                                        
    default-provider: consul-dmitriis:consul-tmp
...
  consul-dir:
     plugin: dump
     prime:
      - vault-snap
      - consul

➜  snap-consul git:(master) ✗ sudo snap install consul-
dmitriis_0.8.0_amd64.snap --dangerous

➜  snap-vault git:(bug-1681068) ✗ sudo snap install vault-
dmitriis_0.6.5_amd64.snap --dangerous

➜  snap-vault git:(bug-1681068) ✗ sudo snap connect vault-dmitriis
:consul-tmp consul-dmitriis:consul-tmp

# in a provider (consul) a directory is shared using 'write: [/tmp]'
# on the receiving side there's 'target: $SNAP/consul' and consul directory is 
primed during build time

➜  snap-consul git:(master) ✗ sudo snap run --shell consul-dmitriis.consul
root@blade:/home/dima/src/canonical/snap-consul# cd /tmp
root@blade:/tmp# touch testfile

➜  snap-vault git:(bug-1681068) ✗ sudo snap run --shell vault-
dmitriis.vault

# in this case $SNAP/consul dir exists so the effect is that we don't
see anything propagated

root@blade:/home/dima/src/canonical/snap-vault# cd $SNAP/consul/

root@blade:/snap/vault-dmitriis/x1/consul# ls -l
total 0
 
Looking at the interface's code, I can clearly see that if an absolute path is 
provided, then, actually, $SNAP is prepended so bind mounting is not done as 
one would expect - $SNAP/<your-abs-dir> is used:

https://github.com/snapcore/snapd/blob/master/interfaces/builtin/content.go#L116

// resolveSpecialVariable resolves one of the three $SNAP* variables at the
// beginning of a given path.  The variables are $SNAP, $SNAP_DATA and
// $SNAP_COMMON. If there are no variables then $SNAP is implicitly assumed
// (this is the behavior that was used before the variables were supporter).

...
        // NOTE: assume $SNAP by default if nothing else is provided, for 
compatibility
        return filepath.Join(snapInfo.MountDir(), path)
}

The note says that it is for compatibility, but how am I supposed to
share a snap-local /tmp directory (or a directory under it)?

The rationale behind using /tmp is that on reboots /tmp will be cleared
(by the virtue of rules used by systemd at /usr/lib/tmpfiles.d/), so if
a particular application doesn't cleanup its own unix sockets, they will
be deleted automatically. Or, if you pull a power cord, you won't have
that socket file after reboot (see https://github.com/nextcloud
/nextcloud-snap/issues/151 for what might happen if a non-tmp directory
is used and unix sockets are not deleted).

https://www.freedesktop.org/software/systemd/man/systemd-tmpfiles.html
https://www.freedesktop.org/software/systemd/man/tmpfiles.d.html#

The systemd's tmpfiles mechanism works for snapped applications as the
snap-specific directories are located under /tmp of the pid 1's rootfs
and are bind mounted later:

https://github.com/snapcore/snapd/blob/master/cmd/snap-confine/mount-
support.c#L90

        // Under that basedir, we put a 1777 /tmp dir that is then bind
        // mounted for the applications to use
        sc_must_snprintf(tmpdir, sizeof(tmpdir), "/tmp/snap.%d_%s_XXXXXX", uid,


Is it possible to revise the decision to prepend $SNAP?

I realize there might be some reasons for not doing so besides
compatibility.

Also, it is good that this is documented in the source code but it would
be nice to have in the docs for that interface as it is not intuitive at
all and hard to debug: originally, I noticed what was wrong by somehow
generating:

cannot mount /snap/consul-dmitriis/x4/tmp at /snap/vault-
dmitriis/x1/consul with options bind: No such file or directory

which revealed that $SNAP is prepended.

In other words, instead of spending minutes on setting up something like
that people might spend hours.

** Affects: snapd (Ubuntu)
     Importance: Undecided
         Status: New

** Summary changed:

- Absolute paths used with content interface are actually relative to $SNAP
+ Absolute paths used with the 'content' interface are actually relative to 
$SNAP

-- 
You received this bug notification because you are a member of Ubuntu
Bugs, which is subscribed to Ubuntu.
https://bugs.launchpad.net/bugs/1681130

Title:
  Absolute paths used with the 'content' interface are actually relative
  to $SNAP

To manage notifications about this bug go to:
https://bugs.launchpad.net/ubuntu/+source/snapd/+bug/1681130/+subscriptions

-- 
ubuntu-bugs mailing list
ubuntu-bugs@lists.ubuntu.com
https://lists.ubuntu.com/mailman/listinfo/ubuntu-bugs

Reply via email to