Interface for communicating to host services via DBus

I currently work on tailscale snap and get the following errors:

= AppArmor =
Time: Jul 25 15:52:14
Log: apparmor="DENIED" operation="dbus_method_call"  bus="system" path="/org/freedesktop/resolve1" interface="org.freedesktop.DBus.Peer" member="Ping" mask="send" name="org.freedesktop.resolve1" pid=44870 label="snap.tailscale.service" peer_pid=1024 peer_label="unconfined"
DBus access

As far as I can understand, I cannot communicate with host services via DBus and there has to be an interface specificially implemented for this purpose. Should I wait for such an implementation? Is there a workaround?

did you check if snappy-debug gives you any suggestions ?

There are examples of using dbus here - but I noticed at the bottom it states these features aren’t supported.

Have you considered using another form of IPC? perhaps a unix socket, named pipe or virtual network interface could be used to reflect traffic between dbus and your snap.

For example tailscale uses godbus; which, has examples of dbus over tls among others. Since snaps have network interface access, I imagine you could set up a simple (local) tcp server that reflects (proxies) traffic between your snap and the actual dbus socket.

Just a thought, though.

This is infact the output of snappy-debug. Unfortunetely it doesn’t offer anything for this one.

1 Like

That’d be fairly complex imo. I’m not really familiar with what protocols dbus use at what port. Also I’m not sure (yet) why these pings are needed by the application. For now, I left them out of scope for the snap until it causes some problems.

Looks like the reason tailscale requires access to DBus is to check whether resolved is managing the DNS or not… As far as I understand, it also has checks via /etc/resolv.conf file.

I’m not really familiar with what protocols dbus use at what port.

Ah yes, dbus uses the wire protocol - worth looking into a bit in my opinion if you’ve never heard of it.

It transmits that protocol over unix domain sockets to local processes, given that part of it’s job is to be a centralized system bus for processes, and all.

If you want to talk directly to dbus, you’ll need to at some point talk to that socket - this means getting the permissions and caps required to do so. Snap has rules are security and what not so your best bet may be to have a chat with them.

Also I’m not sure (yet) why these pings are needed by the application. For now, I left them out of scope for the snap until it causes some problems.

I like your approach haha - I mean these sound pretty standard, I’d say they are likely an attestation on your behalf to the network, simply put you’re making others (dbus mainly) aware of your (desire) to participate in the “network”; Secondly they are a health check for you, implemented by some developer who likely wanted to be knowledgable should, well, this happen.

Yup, that makes sense – considering dbus facilitates a “local distributed system of processes” (or at least that’s how I think of it, in a sense) it needs some means to, well, find memebers of the network.

You can see in the code you shared they:

  1. Make a connection to that local resolver (not sure where you see resolv.conf though)
  2. Used the ping interface org.freedesktop.DBus.Peer to see if that connection is alive, as is the standard interface for doing so with dbus.

Well, you’re right. I’m not very familiar with Go but I tried to read the source code. To my understanding, they try to read /etc/resolv.conf and do some verifications for determining what manages system DNS.

I currently can’t make the snap read /etc/resolv.conf despite I’ve added system-files interface to the snap. (I’m not sure why but I suspect that this error occurs because it’s a symlink to another file) When it cannot read that file, it tries to replace it (while creating a backup). If it can, it tries to search for patterns and for systemd-resolved it tries to verify the stub-resolver by pinging 127.0.0.53 to see if it really exists.

DNS configuration of tailscale seems to be failing when these can’t work properly. So I’ve to fix both issues. (reading the file and communicating DBus)

Btw, I’m not sure whether your suggestion (to directly talk to the service via RPC, unix socket etc.) would work. Snap confinement prevents me from communicating to host services via DBus. It’d probably prevent me from communicating it in any other way as well?

I commited latest changes for strict confinement just in case someone may want to look at it: https://github.com/tunix/tailscale-snap/tree/strict

I’m not sure whether your suggestion (to directly talk to the service via RPC, unix socket etc.) would work.

I mean, of course it would work, if you get the appropriate permissions and Capabilities.

You may need to reach out to folks at snapcraft to gets those required privileges.

Snap confinement prevents me from communicating to host services via DBus. It’d probably prevent me from communicating it in any other way as well?

Well I wouldn’t go as far to say that they prevent you from communicating in any other way; I mean for your vpns sake I’d sure hope so LOL.

I would like to have a good answer to your question; it would answer some of my own questions as well, but I don’t.

My best advice is try to reach out to folks on here.

have you taken a look at the interfaces in the snapd source ?
looks like the network-manager plug might help with the dbus access (if send is enough at least):

2 Likes

I actually did but it didn’t work and led me to think that I was misinterpreting the code. I’ll do a clean build and report back. Thanks!

I clean built a new package with network-manager plug but unfortunetely I still can’t alter host’s DNS configuration. To be more precise:

  • snap remove --purge tailscale
  • Add network-manager to plugs of tailscale service (app)
  • snapcraft clean
  • snapcraft --debug
  • sudo snap install tailscale_1.10.2_amd64.snap --dangerous
  • Manually connect all plugs:
sudo snap connect tailscale:firewall-control
sudo snap connect tailscale:network-control
sudo snap connect tailscale:network-manager
sudo snap connect tailscale:system-backup
sudo snap connect tailscale:hostfs-etc-resolv-conf
sudo snap connect tailscale:system-observe
  • Restart service and tail both syslog & snappy-debug logs:
# syslog
snap logs -f tailscale.service

# snappy-debug
sudo snappy-debug -r --only-snap=tailscale

snappy-debug reports DBus related errors when the service is restarted:

INFO: Following '/var/log/syslog'. If have dropped messages, use:
INFO: $ sudo journalctl --output=short --follow --all | sudo snappy-debug
kernel.printk_ratelimit = 0
= AppArmor =
Time: Jul 28 01:13:09
Log: apparmor="DENIED" operation="dbus_method_call"  bus="system" path="/org/freedesktop/resolve1" interface="org.freedesktop.DBus.Peer" member="Ping" mask="send" name="org.freedesktop.resolve1" pid=21779 label="snap.tailscale.service" peer_pid=1186 peer_label="unconfined"
DBus access

= AppArmor =
Time: Jul 28 01:13:10
Log: apparmor="DENIED" operation="dbus_method_call"  bus="system" path="/org/freedesktop/resolve1" interface="org.freedesktop.DBus.Peer" member="Ping" mask="send" name="org.freedesktop.resolve1" pid=21879 label="snap.tailscale.service" peer_pid=1186 peer_label="unconfined"
DBus access

= AppArmor =
Time: Jul 28 01:13:11
Log: apparmor="DENIED" operation="dbus_method_call"  bus="system" path="/org/freedesktop/resolve1" interface="org.freedesktop.DBus.Peer" member="Ping" mask="send" name="org.freedesktop.resolve1" pid=21910 label="snap.tailscale.service" peer_pid=1186 peer_label="unconfined"
DBus access

Additionally, once tailscale up is triggered, the following logs are written:

= AppArmor =
Time: Jul 28 01:13:52
Log: apparmor="DENIED" operation="open" profile="snap.tailscale.tailscale" name="/etc/pop-os/os-release" pid=21979 comm="snap-exec" requested_mask="r" denied_mask="r" fsuid=0 ouid=0
File: /etc/pop-os/os-release (read)
Suggestions:
* adjust program to read necessary files from $SNAP, $SNAP_DATA, $SNAP_COMMON, $SNAP_USER_DATA or $SNAP_USER_COMMON
* adjust snap to use snap layouts (https://forum.snapcraft.io/t/snap-layouts/7207)
* add 'system-files (see https://forum.snapcraft.io/t/the-system-files-interface for acceptance criteria)' to 'plugs'

= AppArmor =
Time: Jul 28 01:14:03
Log: apparmor="DENIED" operation="rename_dest" profile="snap.tailscale.service" name="/etc/resolv.pre-tailscale-backup.conf" pid=21910 comm="tailscaled" requested_mask="wc" denied_mask="wc" fsuid=0 ouid=0
File: /etc/resolv.pre-tailscale-backup.conf (write)
Suggestions:
* adjust program to write to $SNAP_DATA, $SNAP_COMMON, $SNAP_USER_DATA or $SNAP_USER_COMMON
* adjust snap to use snap layouts (https://forum.snapcraft.io/t/snap-layouts/7207)
* add 'system-files (see https://forum.snapcraft.io/t/the-system-files-interface for acceptance criteria)' to 'plugs'

General tailscale functionality seems to be working. I’m able to ping other hosts within the private network. But since the host’s DNS configuration cannot be altered, they cannot be accessed by their hostnames.

I think the daemon tries to determine what manages the DNS configuration on the host at its init phase. In my case, I suspect it cannot determine so it falls back to direct management of /etc/resolv.conf by replacing it. It seems to have access to that file (because I see no complaints) but I see no modifications to the file (it usually places a search param). According to snappy-debug logs, it tries to place a backup file but it can’t due to permission issues.

Is it possible to use system-files interface with wildcard file patterns? Looks like tailscale tries to write random files (/etc/resolv.conf.tmp829392107) before it replaces /etc/resolv.conf