Permission denied for calling system calls from snap app

I am using below calls in my snap for which I get “Permission denied” on executing the app from snap:

system ("df -kh ./");
system ("free -h");
system ("snap connections");
system("snap get core watchdog");

But invocation of following works fine

system("date");
system("uptime");

App in snapcraft.yaml:
device-status:
command: bin/dev_stat
plugs: [system-files, system-observe, hardware-observe]

On building snap I get:

snap “platform” has bad plugs or slots: system-files (cannot add system-files plug: needs valid “read” or “write” attribute)

Snap connections:
iotadmin@localhost:~$ snap connections platform
Interface Plug Slot Notes
content[libraries] platform:lib core:lib gadget
content[writable-data] platform:share core:share gadget
hardware-observe platform:hardware-observe :hardware-observe gadget
network platform:network :network -
network-bind platform:network-bind :network-bind -
process-control platform:process-control - -
system-observe platform:system-observe :system-observe manual
iotadmin@localhost:~$

Am I using right plugs?

try to use snappy-debug to get suggestions for missing interfaces:

$ sudo snap install snappy-debug
$ sudo journalctl --output=short --follow --all | sudo snappy-debug -r

now run your snap from a second terminal and snappy-debug should give suggestions about missing plugs.

regarding the system-files interface … you are holding it wrong :wink:

system-files needs at least a read: entry defining the file or subdir you want to allow read access to. see an example at:

https://snapcraft.io/docs/system-files-interface

1 Like

I get an error while installing snappy-debug

iotadmin@localhost:~$ sudo snap install snappy-debug
error: snap “snappy-debug” not found
iotadmin@localhost:~$

can you install any other snaps ? i.e. try: snap install htop also, whats the output of snap version ?

I can install htop. No issues there.

iotadmin@localhost:~$ snap version
snap 2.44+git1737.g603d46a
snapd 2.44+git1737.g603d46a
series 16
kernel 4.15.18+
iotadmin@localhost:~$

hmm, this is weird, snappy debug should be available for all architectures in the global store …

do you see any errors in the system journal when trying to install snappy-debug ?

Can you download the snappy-debug snap and install it manually with:

$ snap download snappy-debug
$ snap ack snappy-debug*.assert
$ snap install snappy-debug*.snap
1 Like

This worked. Thx.

Following are the errors I see for using system(“df -kh ./”) in my snap.

= AppArmor =
Time: Mar 18 11:16:45
Log: apparmor=“DENIED” operation=“exec” profile=“snap.platform.device-status” name="/bin/df" pid=9364 comm=“sh” requested_mask=“x” denied_mask=“x” fsuid=1000 ouid=0
File: /bin/df (exec)
Suggestions:

  • adjust snap to ship ‘df’
  • adjust program to use relative paths if the snap already ships ‘df’

This works fine in devmode. For testing I released the app to beta channel and I see this issue.
Not sure, how with devmode path to ‘df’ system binary / utility but not when on beta channel.

in strict mode access to the df binary from the core snap is not allowed (–devmode drops all restrictions but prints ALLOWED messages in your journal for each access that would normally be forbidden) … so you need to ship df via a stage-packages: entry, then you can call it from inside the snap ($SNAP/bin and $SNAP/usr/bin are transparently added to your PATH when running a snap) df is in the coreutils deb, just add it to your stage-packages:

Thanks will add and check.
I am using following in my snap to check device health:

system (“df -kh ./”);
system (“free -h”);
system (“snap connections”);
system (“getent group | cut -d: -f1 | grep ggc”);
system(“snap get core watchdog”);
system(“date”);
system(“uptime”);
stream = popen(“sudo platform.dmidecode -t bios -q”, “r”);
stream = popen(“sudo platform.dmidecode -t processor -q”, “r”);

I wonder, why ‘snap connections’, ‘snap get core watchdog’ and ‘sudo platform.dmidecode’ are also failing.

= AppArmor =
Time: Mar 18 11:40:49
Log: apparmor=“DENIED” operation=“exec” profile=“snap.platform.device-status” name="/usr/bin/sudo" pid=9998 comm=“sh” requested_mask=“x” denied_mask=“x” fsuid=1000 ouid=0
File: /usr/bin/sudo (exec)
Suggestions:

  • adjust snap to ship ‘sudo’
  • adjust program to use relative paths if the snap already ships ‘sudo’

= AppArmor =
Time: Mar 18 11:40:49
Log: apparmor=“DENIED” operation=“exec” profile=“snap.platform.device-status” name="/snap/snapd/6870/usr/bin/snap" pid=10000 comm=“sh” requested_mask=“x” denied_mask=“x” fsuid=1000 ouid=0
File: /snap/snapd/6870/usr/bin/snap (exec)
Suggestions:

  • adjust snap to ship ‘snap’
  • adjust program to use relative paths if the snap already ships ‘snap’

because they need highly privileged interfaces … snap commands can not be executed at all … you need the snapd-control interface that grants you access to the snapd REST API which is not available via the global store, this requires a brand store …

for dmidecode you need:

  • the dmidecode binary insde your snap

  • the hardware-observe interface that grants read access to /sys/firmware/dmi/tables

  • the actual file permissions to access the above dir (which is why i assume you call sudo in the command … which does not really work inside snaps (no access to /etc/sudoers and the like))

obviously C) isnt easily solvable, you could create a service (daemon: simple) for this and talk to it through a socket (or dbus if you like it more complex) from your userspace program so the userspace part does not need to elevate privileges itself.

Thanks. Will try and see how I can tackle this for different utilities that I am using.

You don’t need to ship ‘df’, the ‘mount-observe’ interface allows access to it. It is a bug in snappy-debug that it isn’t suggesting it (for which I’ve taken a TODO to fix).

If doing this, please perform some sort of permissions check otherwise your snap provides privilege escalation for all users on any system it is installed on (the permissions are what they are for a reason :). One way to do this is if using the socket, look up the PEERCRED (man unix) to get the uid, then you can use id <uid> to see the group membership for the user. You might, for example, see if the user is in the ‘sudo’ group. This isn’t perfect since, of course, there is no password prompt, but it is something.