One request that has come up a few times is the ability for snapped daemons to make use of polkit authorisation. This essentially lets the daemon consult a system policy to decide whether to allow a non-root user to perform a particular action. When the polkitd daemon is absent, such applications typically fall back to requiring that the user be root.
I’ve been doing some analysis to see what needs to be exposed to enable this feature, and what some of the potential security concerns are.
Communicating with polkitd
polkitd daemon resides on the D-Bus system bus under the name
org.freedesktop.PolicyKit1 and exposes a number of methods on the
org.freedesktop.PolicyKit1.Authority interface. This is a mix of methods intended for use by daemons, user-side authentication agents, and potentially a control panel type UI.
Of particular concern, the
EnumerateActions method could potentially be used to determine the list of all polkit enabled daemons on the system.
Granting access to only
CancelCheckAuthorization should be mostly safe, but it could probably be used to probe for the presence of well known action IDs (e.g. request non-interactive auth of an action ID, and check what error is returned).
Determining the authorisation subject
The first argument to
CheckAuthorization is a “subject” structure identifying the client the daemon wants to check. The
PolkitSubject struct can take a number of forms:
PolkitSystemBusName: system bus unique name
PolkitUnixProcess: pid, process start time, uid
PolkitUnixSession: ConsoleKit session ID (is this deprecated?)
In the first case, no additional permissions should be needed: the D-Bus daemon passes the client’s unique bus name in the message.
The UNIX process subject type is needed when the client communicates with the daemon over something other than the D-Bus system bus. Snapd is an example, where we use polkit to authorise commands sent over a UNIX domain socket.
To handle this case, the daemon needs to be able to read the
SO_PEERCRED socket option for the pid and uid, and read
/proc/$pid/stat for the process start time. This last one is used to detect pid reuse attacks. This effectively means that the daemon needs to be given read access to
/proc/*/stat, which grants access to far more information than just the start time of one particular process.
Given the size of this hole, it might make sense to leave
ProcessUnixProcess support out initially, or hide it behind an interface option that review-tools can gate access to. Supporting D-Bus system daemons alone would be a decent improvement.
Installing action descriptions
CheckAuthorization method takes an “action ID” string as an argument. These action IDs take the form of Java-style reversed DNS names and are chosen by the daemon author. In order to be usable though, it is necessary to publish a
.policy file describing those actions. These are XML files that provide human readable descriptions of the actions (for use in prompt dialogs) and the default policy for the actions. The files need to live in
So we need some way for a snap to install new policy files. This should only be done after validating the files to ensure it’s not something that will cause
polkitd to misbehave.
One concern I have is snaps attempting to provide default policy for a second daemon’s action IDs. I still need to check what polkit does in a situation like this, but the worst case scenario would be a snap changing the default policy for an action from
auth_admin to a simple
yes. If polkit does guard against duplicate default policy, it might simply turn into a denial of service for that action ID. Neither option is particularly appealing.
Requiring that actions contain the snap name is one approach, but since actions IDs are generally hard coded into daemons this would likely require code modification in most cases. I’m not sure if there is a better solution though.
I don’t think there is any need to restrict what the default policy actually is: if a client is allowed to talk to a daemon, then the daemon could easily act without consulting polkitd. So there isn’t any real security benefit to e.g. rejecting a default permissive policy for an action ID.
- add a new
polkitinterface whose slot is implicitly provided by
systemon classic distros. Snaps that plug this interface are allowed to connect to the D-Bus system bus and issue the
CancelCheckAuthorizationmethod calls to
- snaps can provide a
meta/polkit-1.policyfile. On snap installation, this file will be validated to ensure it is valid XML and only provides actions named
snap.$SNAP_NAME.*, and then installed to
I think it should be safe to have these two parts operate independently: installing policy files for unused actions should effectively be a no-op. And if we don’t initially include support for
PolkitUnixProcess subjects, then it is probably safe to allow auto-connection.