Security and PackageKit This document is a brief overview of security policies and notes about security in the PackageKit project. It has been written by the PackageKit authors, and should not be treated as independent analysis. This document has been written as packagekitd is a system activated daemon running as the root user (uid 0), which means the package management system is run as root also. The daemon receives untrusted input from the client, which means the daemon is security sensitive. First, a high level overview, in this case using the yum backend as an example: gpk-update-icon gpk-application | ___/ [D-Bus] __[D-Bus]__/ | / packagekitd -- [D-Bus] -- polkitd-1 | [pipe] | yumBackend.py (using yum) packagekitd does not expose itself remotely over XMLRPC or other remote interface, and so a remote denial of service or exploit is impossible without a serious exploit of other services such as D-Bus. It advertises a simple interface that can be queried by clients in unprivileged and privileged modes. The privileged modes are controlled using PolicyKit, and policy and the authentication mechanism is deferred to the polkitd-1 service. When a privileged method is executed, the daemon checks with polkitd-1 daemon for whether the client is authorized for the action it wants to perform. This may involve the user authenticating that they are either the user (by typing their password) or that they are an administrative user (by typing the root password or the password of a user designated as an administrative user). The authorization check can take some time, but the daemon can process other requests whilst waiting for user input. Please see the the PolicyKit-1 man page for more information. The packagekitd daemon is started using D-Bus system activation, which means it is started without any environment (no PATH, etc) and therefore is impossible to exploit by preloading other libraries. It is also running as uid 0, and so requires root privileges to inject code into it. A typical transaction would be for the client to request a TID (transaction ID) to which the server responds by creating a transaction instance and exposing this on the system bus. The client then connects to this interface, and executes the chosen method. This method will emit signals such as ::Package(), then ::Finished() and then after a number of seconds ::Destroy() which will remove the interface from the bus. There is a concern that a session service can be written to automatically authenticate methods, and replace the native client, but this is not possible. When authenticating, polkitd-1 passes a cookie to the authentication agent. If the user enters the right password, the authentication agent calls AuthenticationAgentResponse on the Authority with the cookie for the authentication request. If the caller of AuthenticationAgentResponse is not uid 0, then it is ignored. The authentication setuid root polkit-agent-helper-1 only decides to invoke this method if the user actually successfully authenticated. This of course relies on polkit-agent-helper-1 being a secure program. This is easy to verify since this is just over 300 lines of code and only depends on PAM (which is supposed to be secure) up until we have decided that the user successfully authenticated. Only when that is done, we initialize other libraries to send the message. Possible attack vectors: * A client could cause a local DoS (denial of service) by repeatedly calling CreateTransaction without then calling a method to use this TID. This is mitigated by timing out Tid request after a present number of seconds, and the effect can be limited with a config variable (SimultaneousTransactionsForUid). * Local DoS by repeatedly calling non-privileged methods such as Resolve and SearchName. This could be mitigated by limiting the number of requests per second for a certain seat, although no code has been written to do this at present. * A privileged method could be requested and then ignored or hidden by the window manager. This is mitigated by not blocking the daemon when processing authentication, and timing-out the authentication after a number of seconds if authentication credentials are not supplied. * Passing untrusted input to the backend which could be used to crash and exploit the underlying package system. This is mitigated by rejecting invalid input to methods, and testing filenames for existence before they are passed to the backend. * Issuing a large amount of data to a method to cause a local denial of service, for instance calling Resolve with millions of parameters. This is mitigated in the daemon by checking for a sane number of requests (MaximumPackagesToProcess) for each method, and also limiting the total length of the data. * The HTTP and FTP proxies that are sent by the session may contain embedded usernames and passwords. Whilst these are sent in plain text over the system D-Bus (FIXME?), the database is not be readable by users (mode 0640). * The matching of UID and session to proxies assumes that the user cannot modify the login UID, and cannot spoof a session in ConsoleKit. If a user were able to change the apparent UID, then this would allow them to use proxy settings set from another user. This is manifested when a graphical application is run using sudo (which you should never do, but I digress) and different proxy settings may be used from the user settings. It also allows applications run using sudo to use the proxy specified by root, which may be different. * We save the UID and session to a database to get the proxy state for each transaction. If the user is able to create a large number of different sessions then this will add many entries to the database. Some rate-limiting could be added to ConsoleKit or PackageKit to solve this, but has not been done at this time.