On 2014-07-16 13:53, 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 ;-}
Thanks Tomasz for this summary, and Patrick for this lengthy follow up. :) > 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). Third option would be to consider doing such checks transparently in binding libraries on behalf of given app/service. > 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. > > 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. Please correct me if I'm wrong but this looks like same model of operation as used by current SMACK patches. This model, I believe, was critiqued openly by at least Tomasz and Rafał for exactly that reason. Tomasz has just told me that neither Casey nor Auke were that keen on this approach so I doubt if such model shall be used together with Cynara. > 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. > > 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. While inapplicability of given idea in kdbus-like environment shouldn't be a blocker for us at this time, I do think that idea that would have no chance in landing in upstream dbus shall not be accepted lightly. kdbus might still change several times before taking final form, but it would be unwise to expect it to support use cases that were not supported by official dbus-daemon... IOW, I think it would be great if you could post this proposal to dbus mailing list rather sooner than later. Cheers, -- Karol Lewandowski, Samsung R&D Institute Poland > > 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. > > 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. > > 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. > > 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. > > 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. > > 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? > > 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. > > > > _______________________________________________ > Dev mailing list > [email protected] > https://lists.tizen.org/listinfo/dev > _______________________________________________ Dev mailing list [email protected] https://lists.tizen.org/listinfo/dev
