I now have a good understanding of the problem as well as a standalone reproducer. The issue stems from the NO_REPLY_EXPECTED flag in the message header. When the sender of a message sets the NO_REPLY_EXPECTED flag, it means tells the recipient that a reply, either in the form of a method_return or an error message, is not needed even if the method normally provides a reply message. The D-Bus spec (http://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-messages) does not require that the receiver of the message honor the NO_REPLY_EXPECTED flag. Here's the text:
"... the reply can be omitted as an optimization. It is compliant with this specification to return the reply despite this flag, although doing so on a bus with a non-trivial security policy (such as the well-known system bus) may result in access denial messages being logged for the reply." The dbus-daemon code has a mechanism for tracking whether or not a reply message (method_return and error messages) is a reply that the sender of the original message actually asked for. If the reply message was not requested, the dbus-daemon code treats it as an "unrequested reply". This is important to the AppArmor mediation code in dbus-daemon because it lets reply messages that *were* requested through without requiring any sort of AppArmor policy query. The thought is that the AppArmor security policy allowed the original message to go through so surely the security policy author expects any corresponding reply message to go through. That all works great except for when the original message has the NO_REPLY_EXPECTED flag. The dbus-daemon code treats any replies to that message as an unrequested reply. That means that it is subject to the AppArmor policy and may be rejected if the process sending the reply does not have "send" permissions. The bug description for this bug mentions an AppArmor denial of pasaffe sending an UnknownMethod error message to an unconfined process: apparmor="DENIED" operation="dbus_error" bus="session" error_name="org.freedesktop.DBus.Error.UnknownMethod" mask="send" name=":1.22" pid=4993 profile="/usr/bin/pasaffe" peer_pid=3624 peer_profile="unconfined" What is happening there is that some unconfined UI component (global menus backend?) is communicating with the UI components of the confined pasaffe process over D-Bus. The confined UI components are tearing themselves down after the user enters their master password into a pasaffe modal dialog box and presses "Ok". This results in the confined UI components unregistering the D-Bus object path corresponding to the modal dialog box. After this happens, the unconfined UI components are attempting to send one last message, with the NO_REPLY_EXPECTED flag set, to the confined UI components (the "End" method call). This is an error condition since the D-Bus object has already been unregistered. The gdbus (glib) bindings notice that this is an error and send an UnknownMethod error message reply, despite the fact that the NO_REPLY_EXPECTED flag was set on the original message. This causes dbus-daemon to treat the reply as an unrequested reply and the AppArmor mediation code blocks the message and generates a denial message. Outside of the noisy denial message, there is no harm in this. The original sender of the message stated that a reply was not needed and the gdbus bindings went ahead and sent an error reply message, which is fine according to the D-Bus spec. The spec even warns that complex security policy may result in a denial message for such a reply. We could patch the gdbus bindings to not send an error reply message in this situation but I'm not sure upstream would accept such a patch and there may be other bindings or services that ignore the NO_REPLY_EXPECTED flag. In the lp1362469.tar.gz attachment, I have two example services (one written against the python-dbus bindings and the other against the gdbus bindgs) that demonstrate that these unrequested reply denials can come from a service, too. If you gunzip it, untar it, and run 'make', it'll test both services. It will result in two denials: apparmor="DENIED" operation="dbus_method_return" bus="session" mask="send" name=":1.154" pid=21732 profile="service" peer_pid=21734 peer_profile="unconfined" apparmor="DENIED" operation="dbus_error" bus="session" error_name="org.freedesktop.DBus.Error.UnknownMethod" mask="send" name=":1.154" pid=21732 profile="service" peer_pid=21734 peer_profile="unconfined" The second denial is the same sort of denial as the pasaffe denial that I described above. The first denial is an example of a service receiving a message with the NO_REPLY_EXPECTED flag set and still returning a reply message. This also results in an unrequested reply denial. I think this shows that it is unreasonable to try to fix every D-Bus binding, service, and client that ignores the NO_REPLY_EXPECTED flag in order to allow or quiet these types of denials. Our policy language doesn't allow us to easily allow or quiet the denials, either, since we cannot specify message type (method_call, signal, method_return, error) and the language has no notion of unrequested replies. This leaves us with course-grained options such as "dbus (send) peer=(label=unconfined)," to allow the two denials above. I don't even know a good way to quiet those denials without disallowing the ability to send any outgoing messages. Adjusting the policy language to allow the author to specify unrequested replies or method_return/error messages in the policy doesn't feel like the right thing to do. That clutters the already complex dbus syntax, requires changes from dbus-daemon to the kernel, and doesn't really add much other than being able to quiet denials caused by unrequested replies. Additionally, all policy authors are going to want to do the same thing: deny, without auditing, any unrequested replies. I think the most reasonable solution is to simply not audit the denials for unrequested replies. AppArmor will always block all unrequested replies. There are potentially lots of innocent unrequested replies that are allowed by the D-Bus spec they also have the potential to really litter up the audit logs. The AppArmor mediation code already knows if the message is a reply type and if the reply was requested. It is trivial to deny but not audit those messages. ** Attachment added: "lp1362469.tar.gz" https://bugs.launchpad.net/ubuntu/+source/dbus/+bug/1362469/+attachment/4313657/+files/lp1362469.tar.gz -- You received this bug notification because you are a member of Ubuntu Touch seeded packages, which is subscribed to dbus in Ubuntu. https://bugs.launchpad.net/bugs/1362469 Title: AppArmor unrequested reply protection generates unallowable denials Status in dbus package in Ubuntu: In Progress Bug description: Starting with utopic's dbus 1.8.6-1ubuntu1 package, the new AppArmor unrequested reply protections can generate some denials that can't easily be allowed in policy. For example, when running a confined pasaffe, you see these denials when starting and closing pasaffe: apparmor="DENIED" operation="dbus_error" bus="session" error_name="org.freedesktop.DBus.Error.UnknownMethod" mask="send" name=":1.22" pid=4993 profile="/usr/bin/pasaffe" peer_pid=3624 peer_profile="unconfined" It isn't obvious how to construct an AppArmor D-Bus rule to allow that operation. A bare "dbus," rule allows it but that's not acceptable for profiles implementing tight D-Bus confinement. The code that implements unrequested reply protections should be reviewed for issues and, if everything looks good there, investigations into how to allow the operation that triggers the above denial should occur. To manage notifications about this bug go to: https://bugs.launchpad.net/ubuntu/+source/dbus/+bug/1362469/+subscriptions -- Mailing list: https://launchpad.net/~touch-packages Post to : touch-packages@lists.launchpad.net Unsubscribe : https://launchpad.net/~touch-packages More help : https://help.launchpad.net/ListHelp