Re: kdbus: to merge or not to merge?

Alexander Larsson
2015-06-24T17:11:21Z

On Wed, Jun 24, 2015 at 5:38 PM, Andy Lutomirski <luto@amacapital.net> wrote:
> Was this intentionally off-list?

Nah, that was a mistake, adding back the list.

> On Wed, Jun 24, 2015 at 8:10 AM, Alexander Larsson

>> The way i did it in the userspace proxy is to allow peer exited
>> messages from services that talked to you at some point, as this is
>> the core requirement (you must be able to limit things to the lifetime
>> of clients). However, i can see how tracking that in the kernel is a
>> bit painful, so just allowing all is probably a reasonable choice.
>>
>
> Hmm. I guess this is an ugliness of dbus in general. Since dbus
> doesn't really have a concept of objects (AIUI) you can't really get a
> notification that a particular object that you have a reference to is
> gone, so you have to ask for notification that the peer providing the
> object is gone, but there was never any concept of having a reference
> to a peer, so here we are :(

You keep using works like ugly and stupid, which isn't super
impressive. My name is on the dbus specification, and I am (and was
then) well aware of systems with object references. In fact, both
previous ipc systems (Corba ORBs) that Gnome used before we designed
dbus uses object references, and they had a lot of problems which dbus
solved for us. I'm not saying dbus is perfect, but it has its reasons
for the way it works.

So, dbus-the-system has some kind of notion of an object reference
(peer + object path), but the *bus* is fundamentally a way to
communicate between peers, and the object path is merely some
uninterpreted metadata. Once the message reaches the destination
process it is essentially free to interpret the object path however
they want. If something needs a long lasting "reference" to an object
you can implement that by e.g. using a Subscribe method, and you can
guarantee cleanup because the bus will tell you if the peer died.

This also means that the bus itself is vastly simplified. It only has
to track peers, not every object in every peer. And clients are more
flexible with how objects are handled. They can be instantiated
lazily, or even created algorithmically from the object path if
needed.

You wish that the kernel controlled access to a particular object in a
peer, but once the message is dispatched into the target process all
bets are off anyway. It will be running some code parsing your message
in the process with no real separation from the other objects. Any bug
there could give you wider access. I don't see how this fundamentally
makes the whole system much more secure. On the other hand, I *do*
remember having to track down cross-process leaks from circular
references between processes using Corba...

>> The desktop file lists the icon, name and whatnot which is displayed
>> by the desktop environment. If DBusActivatable is true, then the app
>> is started by sending dbus messages to the same name as the desktop
>> file, to the org.freedesktop.Application interface, this way we can
>> ensure a singleton app and you can do more things than just spawning
>> it.
>
> How do I install apps as an unprivileged user? What about running
> sandboxed apps that aren't installed at all? What about downloading
> one app and running three instances of it that are all isolated from
> each other?

Users install desktop files in a file in their home directory
(~/.local/share/applications/ typically).

xdg-app apps require some form of installation before running.

You can run three instances of an app, but only one of them can own
the bus name. This works out fine if your app does not use dbus, but
it may be a problem if it uses dbus activation.

>> Well, your "other than" part kinda breaks things like launching the
>> application. So, we need to be on the real bus.
>> Could you then *also* have a bus per app for talking to the portal? I
>> guess so, but I don't quite see the point. Just having the portals
>> trying to find all new buses that come and go will be all kinds of
>> painful.
>
> How many portals will there be? It seems like, if you want multiple
> portals programs (in the org.freedesktop.portal.* sense), then you'd
> have some awkwardness if each app were on its own bus and you didn't
> want a proxy, but I think you'll also have prevented yourself from
> meaningfully sandboxing the portals themselves.

You can sandbox the portals to some extent, but fundamentally they are
meant to run in some kind of "higher privileges" mode, so they have to
have access to things normal apps would not. For instance, they have
to be able to activate other dbus names.

> Android, on the other hand, sandboxes most of its service providers,
> and Binder provides a nice way to selectively grant capabilities
> between sandboxes. (The privacy and security disaster that's built on
> top of Binder is another story, but that's not Binder's fault.)

Well, the service providers are not the same as the portals. Say you
have a twitter client that you want to register to be able to share
some selected text. The twitter client can be fully sandboxed. The
portal is just the link between the requesting app and the list of
registered share providers.

> For launching the application, couldn't you just say "hey, portal,
> launch this application please?" Using custom endpoints with shared
> namespaces just for this purpose sounds unnecessary.

Well, that is essentially what a portal like the share one does.
Although it shows a user controlled UI inbetween to avoid the app
being able to start any other app it wants.

> Semi-shameless plug [1]: Sandstorm is inventing something quite
> similar to what you're doing, but they're doing it with a single proxy
> per sandbox instance and a capability model. There are no special
> portal services -- instead, there's a general and *very* clean
> mechanism for allowing other sandboxed applications to supply
> interfaces that can be requested from any sandbox (with appropriate
> user confirmation). It could be worth comparing notes. I'll try to
> see if they have a nice summary of how the pieces fit together.

That sounds similar to the portal idea, would be cool to read about.

>> I don't think that is really a problem. People can do stupid things on
>> the non-sandboxed side in all kinds of ways. You just can't protect
>> against that.
>
> But you can prevent people on the non-sandboxed side from being
> invoked *at all* from the sandbox without explicit user opt-in, which
> makes the scope for screwing things up much smaller. If you combine
> that with sandboxing the portal providers too, you end up in decent
> shape.

The non-sandboxed side can scribble all over your application. Trying
to protect against it doing something wrong is imho fruitless.

>> Basically, the app id is linked to the dbus names that the app may
>> own. So, the only way it could take over org.gnome.gedit is if you
>> actually install the app called "org.gnome.gedit". Of course if you
>> trust some random untrusted repo and install something called that you
>> get what you want...
>
> Um.
>
> Have you ever noticed that friendly android app names like "Yelp" have
> nothing whatsoever to do with the app ids? Heck, it's hard to find an
> app id shown in the UI at all when installing an Android app.
> Nevertheless, you're supposed to be safe if you install random apps,
> as long as you don't grant them dangerous permissions.
>
> So, yes, users really ought to be protected against apps that
> partially break the sandbox because their names are malicious.

Yeah. I'm aware of this. Anything that allows free text and icon to
describe the app will be able to impersonate another app (to the user,
if not the system). The only solution to this is manual verification
and trust. The limitations above make it possible for a reviewer to
check the app id and the exported files (such as the desktop file and
the dbus service file) and will be able to catch such impersonation.
So, if you trust an upstream to do such verifications you register
their public gpg key for the repo.

That obviously doesn't scale super well, as you don't want every user
to have to trust every upstream. So, what I want to do is have
repositories that only have references to other repositories + local
signatures. That way e.g. gnome could run an app store, which
essentially collects a set of upstream repositories, does some manual
verification of each new release and then slaps a signature on it. The
user could them chose to trust this middle-man instead of each
individual upstream. This is basically how android solves this. They
have people looking at submitted apps. Only with this approach you are
not tied to the google appstore only. The whole system is distributed.

>> I understand that you think this is weird, but it is how dbus works,
>> and it is important that it keeps working like this, as this is how
>> you keep talking to the same service if a new one is taking over an
>> old name.
>
> In an object-capability system, the client asks some broker for a
> capability representing some service or name. The broker gives the
> client that capability (if policy says it's okay). If a new service
> takes over the name, the client keeps talking to the old one. If a
> service offers two names, then they'll be represented by two different
> capabilities, and everything works fine.

In dbus this is optional. You can either use the peer id + object path
to keep referencing the old object, or you can use the name + the
object path to always (race-free) go to the latest version.

> Dbus got this wrong, full stop.

Your opinion has been noted.

>>> If you use per-sandbox busses or sockets, you completely avoid needing
>>> to muck with cgroups names. You know a priori which request comes
>>> from which sandboxed app because it could only have come from one
>>> place.
>>
>> That would only be true for the app talking to the portals, not for
>> other peers talking to your app on the regular bus (such as during
>> activation).
>
> Other than activation, when would a non-portal app talk to a sandboxed app?

Well, it would mostly happen indirectly via portals, yeah. Although I
can think of other extension points to the shell an app could install.
For instance, the gnome-shell search provider system works by the app
installing some file that tells the shell its bus name.

> Honestly, given that all of the portal interfaces are new, I find
> myself wondering whether dbus is a good thing to build them on or
> whether it might actually make sense to use something that can pass
> object references (i.e. capabilities) around for real.

You're free to design such a system and write a desktop to use it.
However, in Gnome (and in the other desktops as well), dbus is already
used for all ipc like this and all the freedesktop specs,
infrastructure, type systems, interfaces, code and frameworks are
built around that. There has to be a *massive* advantage for us to use
something else, and I'm not at all convinced by the issues you bring
up.