Re: Sharing credentials in general (Re: [GIT PULL] kdbus for 4.1-rc1)
From: Havoc Pennington
Date: Sun May 03 2015 - 15:44:16 EST
On Fri, May 1, 2015 at 9:48 PM, Andy Lutomirski <luto@xxxxxxxxxxxxxx> wrote:
> Havoc, am I missing something here? If I'm right about this aspect of
> D-Bus, then I'm a bit surprised.
>
I'm not well-informed about Binder, though from reading about it, it
seems to be modeled on and comparable to COM.
>From what I can tell Binder cannot be implemented in userspace, it
depends on a kernel piece for its semantics, so that's one reason we
wouldn't have made some of its design decisions. Should we make some
of them now if kernel is on the table - I don't know enough about
binder and kdbus to say, but interesting question.
When we did dbus, Android didn't exist so Binder was (I guess) just a
weird BeOS thing, I don't think I had ever looked at it.
COM however was top-of-mind. Mozilla had XPCOM, and GNOME's ORBit and
Bonobo stuff was COM-inspired.
The original idea of COM as far as I know wasn't IPC but more solving
a C++ ABI problem. C++ objects didn't have a fixed ABI (dependent on
compiler, which wasn't stable then) and C++ objects don't define
refcounting, introspection, and stuff like that. So COM provided a
more stable and complete C++ object model, and this evolved to (for
example) allow a COM interface to be used from multiple languages such
as Visual Basic. It makes C++ objects more like java.lang.Object or
GObject or other languages with more complete runtimes.
A COM object can be implemented by an in-proc dll or by a separate
process: http://blogs.msdn.com/b/larryosterman/archive/2004/10/12/241420.aspx
When you instantiate a COM object it's analogous to a C++ "new", it
isn't analogous to a dbus "service activation" - COM doesn't help you
with having a race-free singleton provider of a service, according to
http://stackoverflow.com/questions/6252334/singleton-com-object-required
anyway (and the one time I did win32 programming I remember getting a
singleton by creating a hidden window with a certain class name on it
or some hack like that, while on Linux for the same app we just used
dbus).
I don't think COM addresses the "multicast" thing either.
Anyway, if COM starts from "fancy C++ objects" and then happens to
have out-of-process mode, dbus starts from "singleton service
directory and multicasting" and then happens to have some
convention-only ways to map that onto native language objects.
dbus here was like X11 and KDE's DCOP, and moved away from GNOME's
ORBit and Mozilla's XPCOM.
To fill the COM-like role, GNOME ended up just extending GObject (such
as by adding full introspection).
I'm trying to remember the full rationale here, but some things I remember:
* each language or framework already had the COM-like thing for
in-process: java.lang.Object, GObject, python object, etc. These
define refcounting or GC, introspection, and all that stuff already.
App developers generally want to work with their "native" object
runtime.
* the abstraction where objects could be either in or out of process
wasn't that useful; in practice each object was always one or the
other, and had to be treated differently depending on which.
Philosophically, "network transparent objects" as promised by CORBA
were not working for us.
* multicast and singleton services were really useful, while
random-object-happens-to-be-out-of-process really wasn't. The usual
reason to go out of process is because there's some sort of shared
resource (like "the user's task bar" or "the wifi connection"), so
singleton is the default case. There are two common singleton
"scopes," per-machine (system bus) and per-session (user bus).
* cross-process reference counting made a big mess; without the
hub-and-spoke as in dbus, it's either unreliable or wastes a lot of
file descriptors as every process tracks every other process via an
open connection. (binder solves this presumably via the kernel, but we
were looking at userspace-only options.)
* recursion never had a satisfactory solution; you'd call some
innocuous-looking method on what turned out to be, or use, a remote
object and suddenly code from some completely unrelated part of your
app might end up running. so you call foo_ref() and while that ref is
going to another process you get an incoming unref on another object
you were using... needless to say these bugs were always heisenbugs...
essentially it was multithreaded programming but without locks. The
idea with dbus is to make explicitly asynchronous remote calls kind of
the default, or at least well-supported, though language bindings can
always choose otherwise. In dbus if you make a blocking remote call,
traditionally it is truly blocking (though it's up to the language
binding). The thread making the blocking call will not process any
incoming recursive calls. If you get a deadlock, you need to make your
code nonblocking, which you probably should have done in the first
place.
http://lists.freedesktop.org/archives/dbus/2007-March/007381.html and
http://lists.freedesktop.org/archives/dbus/2006-March/004362.html are
some sample discussions of this topic if anyone is super curious.
* from the X11 experience we felt the most important performance
issue was to avoid blocking round trips, so this is another reason to
write nonblocking code always - you can fire off a lot of requests
without waiting to get back each reply as you're going along.
* because dbus uses the same system for service location/activation,
unicast messages, and multicast, it can keep ordering between
lifecycle events on the bus, multicast events, and unicast method
calls.
Anyhow... so the big picture is this different design emphasis. dbus
is solving multicast/singleton/multi-process first, and then making it
look sort of OO-ish in the language binding library. COM is solving
"C++ has an impoverished runtime with a fragile ABI" first, and then
bolting on "hey we could make these fancied-up objects be out of
process sometimes."
I don't know how to characterize Binder here, I guess it is COM-like
but I don't know if it has in-process mode, or what they do about
singletons or locating/activating services.
dbus is exposing more implementation detail than COM - it explicitly
is always about processes (ok, technically bus connections, but the
point is: not objects). You can track the processes themselves (via
the bus names). dbus encourages writing async code, again exposing
that we're dealing with remote objects. dbus encourages you to just
use your language's native runtime for in-proc objects.
dbus has an "objects-with-methods mapping" but it's pretty much just
convention. Object paths are free-form strings. Either language
bindings or apps can decide what to do with these paths in order to
route method calls within the process.
For example a spreadsheet could own the name
"org.freedesktop.Spreadsheet" and then it could decide to have objects
like "/documents/foo/cells/E5" - the "object" could be completely
virtual, maybe there really isn't an object instance allocated in the
spreadsheet process for every cell (could mean millions of objects),
instead it just parses the path and makes it look like there is. But
another program could have object paths that are just a number, and
keep a hash table from the numbers to object instances. It's up to the
app, or the binding library, to decide how it wants to do it. Apps can
also choose to implement reference counting if they want (and they can
auto-release references by tracking the lifetime of the peer process).
So dbus is punting a lot more to the bindings than COM does; it
doesn't require that an object even exists as a distinct allocation,
let alone require anything about its vtable layout.
On the language binding level, though, you can make COM-like
decisions; you could choose to allow incoming recursion during
apparently-blocking calls, you could choose to export Ref and Unref
methods on all your objects, stuff like that. You could even make a
COM binding to dbus I suppose.
I guess you're really asking how all this relates to capabilities and
I don't know - dbus only looks at processes, not objects, for security
purposes, as far as I know. Objects are just a convention, the dbus
daemon doesn't actually care how a process interprets the object path
(or interface or method name, for that matter).
Havoc
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/