On mer, 2014-07-16 at 13:53 +0200, Patrick Ohly wrote: > On Mon, 2014-07-14 at 13:06 +0200, Tomasz Swierczek wrote: > > 3. SAPI idea is not the way we’d like to go now > > > > a. We decided to experiment with DBus and Cynara access checks in > > DBus daemon as first step > > > > b. Most services use DBus and UDS-based services don’t usually > > interface the applications; UDS-based services are few and mostly our > > own code we’re already tampering with > > > > c. Contact points(s): Patrick Ohly (Intel, DBus modification) & > > Lukasz Wojciechowski (Cynara dev.) > > Thanks for reporting back from the meeting. When I first heard about the > meeting at the end of last week, I wasn't even sure whether this topic > had been on the agenda ;-}
Hi Patrick, Of course it was. > As D-Bus and Cynara integration now seems to have more attention in > Tizen, let me use the opportunity to give a status summary. I started > investigating what it would take to enhance dbus-daemon after TDC. So > far, I have only updated the API for obtaining a D-Bus client's Smack > label: > > https://review.tizen.org/git/?p=platform%2Fupstream%2Fdbus.git;a=shortlog;h=refs%2Fheads%2Fsandbox%2Fpohly%2Ftizen > > This is necessary because upstream rejected the current Tizen patch > (https://bugs.freedesktop.org/show_bug.cgi?id=47581). > > Further specific work on policy enforcement is blocked by the need to > clarify goals and various Cynara aspects, in particular the asynchronous > API (see the separate mails about that on the list). But prototyping without > Cynara involved is possible (see the last section of this email) and it > is useful to discuss the concept before investing a lot of work into > the implementation. > > Approaches > ========== > > We have two possible ways of securing D-Bus services: > 1. A D-Bus service calls Cynara and rejects to do things which are > not allowed. It can reply with an error or simply ignore > messages (TBD, see below). > 2. The dbus-daemon asks Cynara whether a) a client is allowed to > send a certain message and/or b) whether it is allowed to > receive one (for signals). > > Option 1 is potentially more flexible, but it cannot work in practice > without at least some rudimentary support for option 2: > A. Once we allow less privileged apps to connect to the D-Bus > buses, we need a default-deny policy enforced by the dbus-daemon > and then only selectively open up access to specific services > and/or interfaces. Expecting all D-Bus services *and* apps to be > resilient against unexpected messages is unrealistic. > B. Signal delivery with unspecified recipient can only be > controlled by dbus-daemon; all services would have to be > modified to only use unicast signals. Interesting points. > What I have in mind for option 2 is an extension of the <allow/deny> > rules with a <check privilege="foobar"> rule. This <check> rule would > have the same match criteria as the <allow/deny> rules. If it matches, a > call to cynara with > * client = Smack label of D-Bus client > * user = UID of the client process > * session_id = unique connection name (1) > * privilege = "foobar" > determines whether the rule grants access. Note that in this model, > Cynara would never be used to take away access already granted before by > some other rule. This means that if the current state is "allowed" when > evaluating a check rule, it gets skipped, because a "DENIED" would be > ignored and an "OKAY" wouldn't change the state. > > Alternatively, one could always call Cynara and change the state > accordingly, including a transition from "allowed" to "denied". I find > that model a bit harder to understand and it would be less efficient > (more Cynara checks); if it turns out to be needed, then changing the > implementation would be trivial. > > (1) As I said before, I have my concerns about such an ad-hoc choice for > the session_id. I'd prefer to have a system-wide policy for computing > the session_id that matches how the user perceives the life time of an > application. There a need to define what is THE DEFAULT SESSIONID. I'm not sure that the unique DBUS connection name is reliable. > Filtering > ========= > > With rules as outlined above, we can filter by source, destination, > interface and member. Filtering by interface and member will be > problematic in KDBus because they are part of the opaque payload that > KDBus knows nothing about. When relying on these message attributes for > filtering, a different approach will be needed if and/or when the > services switches to KDBus. > > Right now it looks like KDBus will not be a drop-in replacement anyway > and is unlikely to be in Tizen 3.0, so this shouldn't prevent us from > extending user-space routing via dbus-daemon. Canonical is also moving > ahead with their AppArmor patches for dbus-daemon. > > There is a comment in the D-Bus man page about deny rules that says: > > send_destination and receive_sender rules mean that messages may not > be sent to or received from the > *owner* of the given name, not that they may not be sent *to that > name*. That is, if a connection owns > services A, B, C, and sending to A is denied, sending to B or C will > not work either. > > This also applies to allow rules. What that means is that all well-known > names in rules and messages get resolved to the bus name before > comparison. If a client is granted the right to send a message to > org.example.service1 currently owned by client :1.10, then it is also > allowed to send to that client using the name org.example.service2, if > that name is also owned by the service. > > In practice this is not a problem, because we can and should always > include at least the interface in rules. Does this last point contradict what you said about KDBUS? In my humble understanding yes. > Existing Smack policy patches > ============================= > > We have Smack policy patches in Tizen. However, those pre-date Cynara > and rely on Smack rules being set up for each app to control what it has > access to. With the switch to Cynara, those rules will no longer be set > up (?). > > The only use that I see for these patches is to override a default deny > for processes running with "User" label without involving Cynara. If we > manage to call Cynara from dbus-daemon, we can use the Cynara daemon > also for this particular aspect. For this to work, we only need a rule > that causes cynara_check(client = "User", privilege = "dbus") > to return OK. > > My proposal is to drop these non-upstream Smack policy patches completely. IIRC, the same thing was said in security F2F last week. > Broadcasts > ========== > > Broadcasting confidential information is problematic, as explained in my > comment on AMB's security requirements. A D-Bus service cannot control > which clients receive a signal unless it explicitly specifies only a > single recipient. In the current D-Bus subscriber model, this is not > possible because the service doesn't even get to know who is interested. > > The dbus-daemon can route signals more selectively only to privileged > recipients. However, the rule matching cannot filter by message content. > The popular PropertyChanged signal cannot be filtered selectively. > > This is only relevant if these signals are part of the API which we want > exposed to less-privileged clients. For privileged clients the default > allow rule would still let the signal through. If, by the cynara meaning, an unauthorized client can subscribe to messages that it should not receive and receive them then there is a hole in the security. Is it what you write? > Specific dbus-daemon behavior > ============================= > > dbus-daemon evaluates policy rules in bus_client_policy_check_can_send() > and bus_client_policy_check_can_receive(). > > Both methods are supposed to return a response immediately without > blocking. My current thinking is that they must be extended to return a > "don't know yet" result. This must abort processing for the time being, > just like an out-of-memory error would. How this works for each call > chain varies. > > For can_send it affects the processing of the data coming from a > specific client. This data queue can be frozen while waiting for a > response from Cynara. This is an advantage over handling the Cynara > check in the recipient, because it prevents a malicious or broken client > from sending further messages while its previous message gets considered. > > can_receive is more difficult. We don't want to block the sender, > because it might have to service other clients. So we may have to > tentatively accept the message for the recipient, block the queue > delivering data to it and then later repeat the receive check. > > This can cause messages to pile up inside dbus-daemon, in particular > when we apply this to broadcasts. This behavior can also already be observed > in > normal D-Bus when a client subscribes to a signal and the stops reading > the data: memory consumption in dbus-daemon keeps going up until it > eventually hits the per-client memory limit (rather large though!) and > drops messages. Is it blocking the DBUS daemon? > Handling rejections and user interaction > ======================================== > > At the moment, dbus-daemon generates a > org.freedesktop.DBus.Error.AccessDenied error reply when a method call > gets rejected by the daemon. This is somewhat cryptic: > $ dbus-send --print-reply --dest=org.example.service1 /example/path > org.example.Echo.SayHello > Error org.freedesktop.DBus.Error.AccessDenied: Rejected send message, 1 > matched rules; type="method_call", sender=":1.8" (uid=1001 pid=13960 > comm="dbus-send --print-reply --dest=org.example.service") > interface="org.example.Echo" member="SayHello" error name="(unset)" > requested_reply="0" destination="org.example.service1" (uid=57618 pid=13950 > comm="/usr/bin/python /work/dbus/service.py ") > > It includes information about the destination (uid, pid, comm) that we > might not want leaked to the caller (?). > > It would be nicer if the AccessDenied error contained information about > all failed Cynara privilege checks, because then the app developer would > know what he needs to request in the manifest. Agreed. But is it possible? > This problem is not limited to D-Bus. When an arbitrary service does a > Cynara check and that check fails, what should it tell the caller? Yes. I was thinking that EACCES is minimalisticly enough. Doing better job would be great. > It was mentioned recently that a granted privilege may get revoked at > any time. How can an app be informed about that? Should it simply assume > that its next method call will succeed and only notify the user when > that fails? > > Likewise, under which circumstances will the Cynara daemon pop up a request to > the user to grant access? As pointed out in one of the comments on the > LWN article about Cynara, asking the users for consent is problematic: > https://lwn.net/Articles/602303/ > > In D-Bus, when an app sets up a watch, that operation itself will not > cause a check call to Cynara. It's only receiving a signal matching the > watch filter which may trigger that. So in this case, the user > interaction may happen long after the app started up, and the app cannot > know whether the watch is really having the desired result. If the check > fails, dbus-daemon drops the signal message and delivers nothing to the app. > > Prototyping D-Bus rule sets > =========================== > > It is possible to evaluate the proposed concept without patching > dbus-daemon. It is helpful (but not necessary) to recompile dbus-daemon > with --enable-developer or at least --enable-verbose-mode. > > Attached are a sessions.conf and some configs which need to go into a > session.d subdirectory relative to the session.conf. The user.conf and > app.conf must be modified to contain your main user account resp. some > second test account. > > Then run: > > DBUS_VERBOSE=1 dbus-daemon --config-file=session.conf --nofork > --print-address & > addr=unix:abstract=... (from dbus-daemon output) > DBUS_SESSION_BUS_ADDRESS=$addr ,/service.py & > DBUS_SESSION_BUS_ADDRESS=$addr dbus-send --print-reply > --dest=org.example.service1 /example/path org.example.Echo.SayHello > > When running dbus-send as less privileged test user, calling some > methods work, others get rejected. Eavesdropping with dbus-monitor works > as normal user and gets nothing as test user. > > The test user cannot own well-know bus names (and thus cannot > impersonate system services) and is protected from most (all!?) > undesirable messages that a hostile app might send to it. > > To test that selectively receiving signals works, run: > > DBUS_SESSION_BUS_ADDRESS=$addr dbus-monitor "type='signal'" > DBUS_SESSION_BUS_ADDRESS=$addr dbus-send --print-reply > --dest=org.example.service1 /example/path org.example.Echo.SayHello > DBUS_SESSION_BUS_ADDRESS=$addr dbus-send --print-reply > --dest=org.example.service1 /example/path org.example.Time.Time > > The normal user will get both signals, the test user only the Time > signal. > > Next steps > ========== > > It would be good to get feedback from other D-Bus service developers > and/or maintainers whether writing such rule sets for their service is > possible and sufficient. John and Kevron already have the AR to check > this for AMB. > > We also need to continue the Cynara API discussion. This determines what > changes are needed in dbus-daemon. Very good abstract of your research work. Thank you Best regards José > _______________________________________________ > Dev mailing list > [email protected] > https://lists.tizen.org/listinfo/dev _______________________________________________ Dev mailing list [email protected] https://lists.tizen.org/listinfo/dev
