Hi Lee,

On 06/09/2017 07:02 PM, The Lee-Man wrote:
> I am seriously interested in both adding an API like this (if done
> right) and in adding more/better locking so that iscsid could support
> more parallelism.

While I maintain open-iscsi for Debian, I must confess that I haven't
looked too closely at the source code. Is iscsid multithreaded at all?
Because if not, one could easily just use an event-based model and
would have no need for locks, even if one adds a public IPC mechanism,
regardless of whether that's DBus or not.

> But I know almost nothing about DBus. Why would anyone say no to
> dbus?

DBus was initially developed to replace CORBA, DCOM, and similar
approaches to inter-process communication that were used by GNOME and
KDE on the desktop. For this reason DBus tends to have a stigma
attached to it that it isn't "for servers".

Furthermore, to be fair, I see three points where DBus has some
problems:

 1. There are some inherent design decisions in the setup / protocol
    that are maybe not 100% optimal.

 2. The performance of the current DBus implementation could be
    better.

 3. DBus leaves security up to the programs themselves.

To address all three of these points in the context of iscsid:

As for (1): I think this point is a valid argument in a meta
discussion about the future of IPC systems on Linux / etc., but
when it comes to deciding whether to a) roll one's own IPC or b)
use DBus, I don't think this plays a role. If someone were to
develop a far better alternative to DBus then this argument will
be relevant IHMO, but not now. DBus is here, widely supported by
a lot of tooling and languages, and despite some flaws in its
design it does do a lot of things right.

As for (2): I don't think in the case of iscsi performance of the
IPC system is critical. For pure control commands and change
notifications DBus is by far fast enough, and that is what we're
talking about for iscsid. (If you wanted to transfer the raw
iSCSI packets then you obviously wouldn't want to use DBus, for
this very reason.)

As for (3): This is the reason for the following policy:

> I know that at SUSE we require a security analysis before we
> allow a new daemon that uses DBus,

So basically that means that instead of relying on e.g. the
kernel to protect a socket with simple access rights, you have
to do access checks yourself.

> Can you explain the DBus trade-off to me?

So let me give a very, very basic introduction to how DBus works as an
IPC system here. This is going to be simplified quite a bit, so if you
have additional questions, feel free to ask.

DBus is - as the name suggests - a bus. A so-called "client" is a
program that connects to the bus. A client can do two things:

 - access other clients over the bus

 - provide services for other clients on the bus

A client may do both at the same time. (The only reason why they are
called clients is that in practice the DBus bus is implemented via a
single server process, dbus-daemon.)

There are two types of busses in DBus: the system bus and then
session/user busses. The latter are used when people log in to the
system and are private to that specific user. Those busses are not
interesting to iscsid, so I'll ignore them.

The system bus is a global bus available on the entire machine (though
containers such as LXC have separate system busses if DBus is installed
there).

Any process on the system may connect to the system bus [1], the socket
has mode 0666. Once a process connects to the system bus, it will
automatically be assigned a "unique name" by the dbus daemon, which has
the form ":1.NNN" [2], where NNN is an increasing counter. DBus
guarantees that this name will not be reused during the runtime of
dbus-daemon.

Once connected, services may send each other messages. There are four
basic message types in DBus:

 - ERROR
 - METHOD_CALL: the sender wants to invoke a specific remote method of
   the target
 - METHOD_RETURN: the sender wants to reply to a METHOD_CALL (note that
   DBus doen't require METHOD_RETURN, some methods may have no return)
 - SIGNAL: the sender wants to send a signal (potentially as a
   broadcast) that indicates an event (such as a state change, for
   example)

To give a specific example for a potential implementation for iscsid:
METHOD_CALL would be used to tell iscsid to e.g. login to a target, and
METHOD_RETURN would be the result of that operation. SIGNAL could be
used to broadcast to all interested parties that a new target has now
been logged into, or that a session recovery has just taken place,
etc.

Only two more missing pieces, which I"ll discuss in the following:

First of all: since the unique names are not deterministic, how does
any client know which other client is actually the service it wants to
talk to? For this DBus has a concept of "well-known names". A
well-known name is a name in "reverse domain order", for iscsid this
could e.g. be "com.open-iscsi.iscsid". A client may register a
well-known name with dbus-daemon, but this is one of the few points
where dbus-daemon actually enforces an intrinsic security policy: any
well-known name on the system bus must be configured and only
sufficiently privileged processes are allowed to register that name.
This means that even though any user may connect to the system bus,
they cannot claim to be "com.open-iscsi.iscsid" themselves.

Secondly: how does a service decide if a client has the appropriate
access rights? dbus-daemon will simply forward all messages, without
any security checks. Well, what dbus-daemon does provide is a means
to determine the user / group [3] of another client that has sent a
message. This allows for simple checks such as: if user is root, then
allow, otherwise reject. That is not the end of the story, though.
There's something called PolicyKit, which is not part of DBus proper,
but extermely often used in conjuction with it. From a DBus service
point of view, it calls a PolicyKit function whether a given action
that a client wants to perform is allowed as an access check, and
PolicyKit does the rest for you by looking at a central configuration
database that allows the admin to decide which DBus method calls are
allowed for which user and which aren't. Personally I think that
PolicyKit is not the nicest piece of software, but it does provide a
standard interface for these kinds of things - and it provides things
that pure UNIX permissions can't provide: for example, one can
configure that users that are logged in locally are allowed to do
certain things, but not if they are logged in remotely. This is how
shutting down a system from the desktop works nowadays on Linux: the
desktop environment issues a DBus call on the system bus to reboot the
system, and the service processing that response will use PolicyKit to
check whether the user was allowed to make that request.

For iscsid I would suggest that if we do implement DBus, we also
use PolicyKit, and ship a default configuration that only root is
allowed to do things. This allows administrators to change that if
they want to, but the default will be secure. Alternatively we could
hard-code a check for root and not use PolicyKit at all. (Note that
in practice many daemons that run on the system will fall back to a
hard-coded root user check if PolicyKit is not installed.)




As I mentioned elsewhere in the thread, I see the following things that
speak in favor of using DBus for iscsid in general:

 - DBus is object-based, which already fits nicely with how iscsid
   thinks about things. For example, all currently logged-in sessions
   could be represented by a DBus object.

 - DBus signals may be used to signify state changes, such as that a
   session has entered the failed state and it is currently being tried
   to recover, for example.

 - PolicKit allowes the administrator to grant / revoke permissions for
   the access to services in a central place that's well established.
   And while I am not the greatest fan of PolicyKit, I do appreciate
   that I only have a single place learn where to configure these kinds
   of IPC permissions.

The major advatantages over any home-grown IPC are:

 - There is tooling for DBus specifically. For example, dbus-monitor
   is a kind of "tcpdump for DBus" and allows one to debug what's
   happening behind the scenes.

 - DBus supports introspection: you can query what methods and
   interfaces a service supports, and which objects it provides,
   dynamically at runtime. This can also be done on the command line.
   With recent enough systemd versions the 'busctl' tool is a great
   tool to do this kind of introspection, but ther are alternatives,
   such as 'qdbus' from the Qt project. (Remember to specify --system
   when calling `qdbus` if you want to access the system bus.) There
   are of course others, and there are programmatic ways to do so.

 - There are a _ton_ of language bindings for DBus ready to go. For C
   there's the reference implementation, the GLib-based gdbus as well
   as sd-bus from the systemd project. For C++ there's also QtDbus from
   the Qt project. There are native DBus implementations for Java, Go
   and JavaScript/Node.JS (written in those languages themselves).
   There are wrappers for C libraries for Python, Perl, PHP, Ruby, etc.

 - It's a standard. I don't think this can be stressed enough. In the
   past most system software has rolled their own IPC (if at all),
   which makes it much harder for any management solution to integrate
   with various system services.

The biggest complication related to iscsid I see is the folllowing:

 - iscsid must be able to cope with being started before dbus-daemon is
   up and running (especially if one is using iscsid in the initramfs
   or has the rootfs on iSCSI), but also has to cope with the fact that
   the dbus-daemon could exit at any time while it's still running.
   This is all doable (other software that is early-boot does this as
   well), but makes it a bit more complicated than just providing a
   standard DBus service.



I hope this helps. If you have further questions, feel free to ask.


Regards,
Christian



[1] Barring additional restrictions by LSMs, such as SELinux or
    AppArmor.

[2] Initially there was supposed to be additional semantics behind that
    specific syntax, but now the ":1." prefix can just be viewed as a
    fixed prefix to a counter, although anything starting with a colon
    (':') is considered to be a unique name according to the DBus spec.

[3] And e.g. SELinux security context.

-- 
You received this message because you are subscribed to the Google Groups 
"open-iscsi" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to open-iscsi+unsubscr...@googlegroups.com.
To post to this group, send email to open-iscsi@googlegroups.com.
Visit this group at https://groups.google.com/group/open-iscsi.
For more options, visit https://groups.google.com/d/optout.

Reply via email to