ilya-zlobintsev / LACT

Linux GPU Configuration Tool
MIT License
1.45k stars 34 forks source link

Enable systemd service hardening features for the daemon #341

Closed zenofile closed 2 months ago

zenofile commented 5 months ago

Since LACT runs the daemon as root, it would be desirable to restrict the processes permissions utilizing systemd's sandboxing capabilities to only permit access to necessary system components.

Currently, I run the daemon with these overrides and didn't experience any problems so far:

[Service]
KeyringMode=private
LockPersonality=yes
MemoryDenyWriteExecute=yes
NoNewPrivileges=yes
PrivateDevices=no
DeviceAllow=char-drm
ProtectKernelTunables=no
PrivateTmp=yes
ProtectClock=yes
ProtectControlGroups=yes
# Allow creation of /root/.cache for shader cache inside tmpfs
ProtectHome=tmpfs
ProtectHostname=yes
ProtectKernelLogs=yes
ProtectKernelModules=yes
ProtectProc=invisible
ProtectSystem=strict
ReadWritePaths=/etc/lact
RemoveIPC=yes
RestrictAddressFamilies=AF_UNIX AF_LOCAL AF_NETLINK
RestrictRealtime=yes
RestrictNamespaces=yes
RestrictSUIDSGID=yes
PrivateNetwork=yes
SystemCallArchitectures=native
SystemCallFilter=@system-service
CapabilityBoundingSet=CAP_DAC_OVERRIDE CAP_CHOWN

This results in a systemd-analyze score of 2.3 OK as opposed to 9.6 UNSAFE.

There are however two issues I see with this restrictive configuration:

1) Accessing a generated debug snapshots is now more complicated due to PrivateTmp=yes; however it can still be accessed by joining the mount namespace:

`sudo nsenter --target $(systemctl show --property=MainPID --value lactd.service) --mount sh -c 'cat /tmp/LACT-sysfs-snapshot-*.tar.gz' > snapshot.tar.gz`

…which is probably not ideal for collecting debug information from users.

2) Enabling overclocking support won't be possible using the GUI: /etc/modprobe.d/99-amdgpu-overdrive.conf could be added to ReadWritePaths, but regenerating the initrd would not be possible due to child processes inheriting the parent's restrictions. For example dracut would have insufficient permissions for writing to /boot.

Not using PrivateTmp is of course an option, but allowing proper execution of dracut et al. would result in dropping quite a few restrictions.

Maybe there could be an alternative service file bundled that launches the daemon in hardened mode, since I assume you probably do not want to separate the initrd– and debug info generation into a separate binary or cli subcommand for the user to execute.

This is of course just a suggestion, I personally am fine with overriding the settings.

ilya-zlobintsev commented 5 months ago

Enabling many of the hardening features makes sense (for example there's no need for network access). However I wouldn't want to break any functionality. Like you listed:

It's also worth noting that the hardening isn't as necessary for the lact daemon as it is for something like a web server. The API is only accessible to a whitelisted admin via unix socket permissions (this admin would already most likely have access to everything that's being limited here), and the functionality exposed has a pretty limited surface compared to some general purpose internet-facing service... but I understand the concern since the service runs as root.

zenofile commented 5 months ago

I agree that the example settings are a bit restrictive. They can certainly be relaxed and still provide some form of protection without altering the codebase to support them.

D-Bus access should still be possible, but I did not test that.

This does not fix the initramfs generation though. For that ProtectSystem, SystemCallFilter, DeviceAllow and CapabilityBoundingSet need to be relaxed or dropped completely in order to allow access to /boot, /efi as well as mknod, ioctl (ffreeze), chroot system calls etc. – at that point there is no real benefit in trying to restrict access since most settings can be undone by the privileged process I suppose.

But I think disabling networking with something like this might still be worth it without losing any functionality lact has right now:

[Service]
MemoryDenyWriteExecute=yes
PrivateNetwork=yes
RestrictAddressFamilies=AF_UNIX AF_LOCAL AF_NETLINK
SystemCallArchitectures=native
SystemCallFilter=~@debug
CapabilityBoundingSet=~CAP_NET_ADMIN CAP_NET_RAW CAP_BPF CAP_SYS_PTRACE