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.