The quest towards trusted client applications: a rambling
Some of you are surely aware of my work with PolicyKit and my efforts on making privilege escalation in KDE/Linux easy and accessible. The final result of my efforts was KAuth, now part of kdelibs. Although, since quite a lot of time I have been wondering on how to improve the whole escalation/trust experience, also covering a part of our middleware which is still not quite there.
One of the main issues in a Linux system at the moment is that we are not capable of identifying and ensuring that a client application *is* actually the application we are expecting. Anyone can fake a DBus service on the session bus, same goes for the process name and much more. This is also one of the big pitfalls of Polkit – as much as the authorization is guaranteed to be unique for each client, there is no way to determine if a specific client is *actually* supposed to execute a specific action or not.
These days I am at UDS, and I have been talking about the subject with Alex (Fiestas) and others quite extensively, thinking about a potential way of fixing it. It is not an easy topic at all and the solution is anything but obvious. We came to consider the following points:
- A client application should be “signed” somehow against a central trusted entity
- This trusted entity should be managing the authorization towards both privileged and unprivileged actions
This design aims to solve several problems beyond privilege escalation – namely, API access restriction. A very good example is inhibition. At the moment, any application can decide independently to prevent suspension on your system, making your laptop fry if it persists throughout the session. In an ideal world, we would like just a set of “trusted” applications to be able to execute that API. Of course, the concept of a trusted application can either come from the distribution or the user – we don’t really care about this. What we really care about is determining that a specific application IS actually the application we expect it to be, and that it has a set of specific privileges.
So our central “trusted” entity, ideally a daemon started in a way in which it could not be easily faked (I guess systemd might help here), would take care of being a central policy handler for several userspace features and applications. The main problem in this design is how to implement the signature check for each application, and how to make sure the application only can advertise its own signature. This is the solution which seems the most sensible to us at the moment:
- The application gets installed through a package management system
- A post-installation hook creates a user named after the executable of the application itself, or in a way which is easily identifiable by the application.
- The same hook takes care of generating a key pair for the application. One key gets stored in a location accessible only by the newly created user, the other is stored in the database of the central trusted entity and is associated uniquely with the application (inside the central daemon)
- The application would be a setuid executable. This way, it can escalate back to its original user for the signature handshake process, and get back down to the caller for everything else. This should not be a treat to security as the only privilege of the “special” user would be accessing that specific directory.
- This way any malicious application without root access would not be able to fake its identity towards a “trusted” client application
- Of course, this implies that only the package management tool and a developer tool should be able to create new certificates inside the central entity. Which would be guaranteed via the very same mechanism. Of course we start from the assumption that the OS installation is not compromised, which is sensible.
- Before you complain about the bootstrapping phase, here is how it works. We assume that the package manager will be always installed first. Upon package manager’s installation, the package manager installs its own key (no need for its user, since it always runs as root anyways) into a known path. When the central trusted entity is installed, during the installation phase it self-installs the specific certificate into its database, trusting only the package manager in the first place. This way the system is ready to perform other certificate installations.
I would love to hear opinions on this before we can start working on a proof of concept approach and see if all that we said is somehow feasible. Do you see any flaws? Any obvious things we’ve missed? Any ideas for doing what we planned in a better/simpler way? Please discuss and let us know.