From 36fdc389e607be2c02e09a39e6f97037485c2b29 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Mon, 22 Sep 2014 20:27:09 +0100 Subject: [PATCH] WiP: initial attempt at documenting kdbus in the D-Bus Specification --- doc/dbus-specification.xml | 869 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 869 insertions(+) diff --git a/doc/dbus-specification.xml b/doc/dbus-specification.xml index 3276f2b..a04dabb 100644 --- a/doc/dbus-specification.xml +++ b/doc/dbus-specification.xml @@ -1251,6 +1251,9 @@ match, the applications will not be able to communicate and the D-Bus connection must be disconnected. The major protocol version for this version of the specification is 1. + Major protocol version 2 is reserved for the alternative + GVariant-based serialization used with kdbus + (see ). @@ -3069,6 +3072,872 @@ + + + Linux kdbus (kernel-assisted D-Bus) + + + kdbus is an module for Linux providing kernel acceleration for D-Bus + and similar protocols. It is currently maintained outside the + main Linux kernel tree, with a reference implementation of the + user-space parts in systemd. kdbus is Linux-specific and not + intended to be portable. + + + + systemd provides a proxy, systemd-bus-proxyd, which listens on a + Unix socket and provides a unix: address to which + clients that do not support kdbus can connect. That proxy provides + normal D-Bus version 1 semantics, not those described in this + section: in other words, clients should expect these semantics + if and only if they use a kernel: address, + with the exception that any different resource limits will still + apply. + + + + Address Format + + kdbus addresses are identified by the kernel: + prefix. They are "connectable" but not "listenable", + and support the following key/value pairs: + + + + + + + Name + Values + Description + + + + + path + /dev/kdbus/UID-SUFFIX/ENDPOINT + + + Path of the bus device. ENDPOINT is typically + bus, which is a special endpoint that + is created along with the bus. The user ID that + initiated the bus may create endpoints with other names, + providing restricted access to the bus. + + + UID represents the responsible + process's numeric user ID in its appropriate user + namespace, e.g. 0 for root (whether "real" root, or root + in a container). SUFFIX is arbitrary. For uid 0, a + SUFFIX of system (i.e. + /dev/kdbus/0-system/bus) is reserved + for the well-known system bus; for all users, a SUFFIX of + user (e.g. + /dev/kdbus/1000-user/busfor uid 1000) is + reserved for the well-known user bus, which takes the place of + D-Bus' well-known session bus. + + + + + + + + + (FIXME: why isn't this more like + kernel:uid=1000,bus=user,endpoint=bus and + kernel:uid=0,bus=system,endpoint=bus?) + + + + + Differences between stream-based D-Bus and kdbus + + + The wire protocol used in kdbus is not identical to the stream-based + wire protocol used over Unix sockets, TCP sockets etc. Instead, + it is as follows: + + + + + + dbus-daemon replaced by kernel code, no peer-to-peer + connections + + + In stream-based D-Bus, there is typically a central message + bus process: the reference implementation is + dbus-daemon. Client and service processes act as clients + (in networking terms) of the message bus process, usually by + connecting to it via connect(). However, processes can also + connect directly by having one peer accept() connections, and + the other connect() to them. This is a rarely-used + feature in practice. + + + + kdbus is different: the kernel carries out the role of the + message bus, and all user-space processes that use kdbus + act as clients of that message bus. Peer-to-peer connections + are not possible: the closest equivalent is for the peers to + create a new bus and agree that they will use it for private + communication. + + + + One process, the "bus owner" that created the bus, takes on + part of the message bus's traditional role: it may configure + access-control policies. On systemd systems, this process + is systemd as process 1 for the system bus, or systemd --user + for the user bus. + + + + + Broadcast filtering is not deterministic + + + In dbus-daemon, the reference implementation of a stream-based + D-Bus message bus, the match rules used to subscribe to broadcast + messages are deterministic: a process will receive exactly those + broadcasts that it requested. However, it will additionally + receive unicast messages explicitly sent to it + Failure to account for this in dbus-glib led to an exploitable + security vulnerability in pam_fprintd, CVE-2013-0292 + , and components within a process will receive + broadcast messages requested by other components in the same + process, so in practice this cannot be relied on for correctness. + + + + In kdbus, broadcast messages are distributed based on a + bloom filter, so it is possible that a process will receive + undesired broadcast messages. + + + + + Simpler access-control language + + + dbus-daemon, the reference implementation of a stream-based D-Bus + message bus, has extensive access-control facilities. In practice, + this access-control language is too complicated to get right + consistently, and many of its features are not actually used. + kdbus has a simpler and more realistic access-control scheme. + + + + In kdbus, all match rules are in terms of whether a process + may send messages: if a unicast message may be sent, then its + intended recipient may receive it, and any recipient may + receive a broadcast message. In dbus-daemon, match rules could + in principle have also limited whether processes may receive + unicast messages addressed to them or broadcast messages, but + in practice this feature is not used. + + + + In kdbus, expected replies are always allowed: if a sender + is allowed to send a unicast message to a destination, then + the destination is allowed to send back a reply. In dbus-daemon, + it is possible (although not useful) to configure this to + not be true. + + + + In kdbus, broadcast messages are always allowed: any sender + may send broadcast messages, and the recipient is responsible + for ignoring broadcasts that are not from the sender in which + it is interested. In dbus-daemon, it is possible to configure + sending certain signals to be restricted, although in practice + this feature is not used, and recipients not filtering signals + correctly has been treated as a security vulnerability in + the recipient where appropriateCVE-2013-0292 was + one such vulnerability.. + + + + kdbus can only discriminate between unicast message recpients by + their well-known names, and between senders by their user and + group IDs and the endpoint device nodes to which they have access. + The access-control scheme does not discriminate between + messages by their interface, message type, member name or path. + + + + + + + + + + + + + Authentication handshake replaced by + KDBUS_CMD_HELLO ioctl + + + The initial nul byte (see ) + is not sent, the authentication protocol (see + ) is not used, and the + special Hello method () + is not called. Instead, the KDBUS_CMD_HELLO + ioctl combines the functionality of all three of those + things. Credentials-passing is always available, + authentication is always via those credentials (as if using + SASL EXTERNAL on the unix: transport), feature-negotiation is done + via flags fields in that ioctl, and instead of the Hello method + returning the unique bus name, the ioctl returns a numeric + unique ID, which can be converted into a unique bus name by + writing it in ASCII decimal and prepending :1.. + + + + + D-Bus message headers are secondary to the kdbus_msg + structure + + + Message fields relevant to the kernel are transferred in the + struct kdbus_msg passed to the + KDBUS_CMD_MSG_SEND ioctl. + + + + The flags field is analogous to the flags in the third byte + of the D-Bus message header, but does not use the same + numeric values. There are flags for EXPECT_REPLY + (note that this is the inverse of NO_REPLY_EXPECTED + in the D-Bus protocol), for NO_AUTO_START, and for SYNC_REPLY + to perform a synchronous call (which may violate message + ordering, but allows some optimizations). + + + + The dst_id and src_id fields encode the unique bus name of the + sender and destination: a message to :1.1234 + corresponds to dst_id being set to the integer 1234. There is + a special destination ID for broadcast messages, and a special + destination ID to represent messages sent to a well-known name. + If the latter is used, the relevant well-known name appears in + a separate KDBUS_ITEM_DST_NAME item in the message payload. + The kernel verifies that the KDBUS_ITEM_DST_NAME appears + if and only if the dst_id is KDBUS_DST_ID_NAME, so + recipients do not need to handle this condition. + + + + Senders do not need to set the src_id; it will be filled in + by the kernel during sending, and recipients may assume that + it is present and correct. There is a special source ID + to represent messages generated by the kernel. + + + + For general D-Bus messages, the kdbus payload-type field must be + set to 0x4442757344427573 (corresponding to "DBusDBus" in ASCII) + to indicate a D-Bus message. Special messages generated by the + kernel use payload type zero instead. All other values are reserved + for non-D-Bus payloads. + + + + The 64-bit cookie field corresponds to the serial number in D-Bus + on a stream. Method call messages that expect a + reply must set the EXPECT_REPLY flag, the cookie, and a timeout. + In D-Bus messages, the cookie must be nonzero, its least + significant 32 bits must match the D-Bus serial number, + and the remaining (more-significant) bits must be zero. + Similarly, the cookie_reply field corresponds to the + REPLY_SERIAL header field. + + + + There is no such thing as an infinite timeout in kdbus, + and unlike stream-based D-Bus, the timeout is enforced by + the kernel, not by the peers. Senders should map the + "infinite timeout" offered by some D-Bus APIs to a suitably + large number. + + + + + Some normally-mandatory header fields are not + mandatory in kdbus + + + The REPLY_SERIAL header field is not mandatory in messages + sent through kdbus, even in the METHOD_RETURN and ERROR + messages where it would normally be mandatory. + If present, it must match the least significant 32 bits + of the kdbus cookie_reply field, and the remaining + (more-significant) bits of the cookie_reply field must be zero. + + + + + The DESTINATION header field is not mandatory in messages sent + through kdbus. If present, it must match the dst_id, + and the KDBUS_ITEM_DST_NAME if present. + + + + + The SENDER header field is not mandatory in messages sent + through kdbus, and senders should not add it. If present, + it must match the src_id. + + + + + + "Version 2" D-Bus messages + + + The 12-byte fixed-length header at the beginning of a D-Bus + message remains present in kdbus messages. The major version + is set to 2, and the endianness is required to be native-endian + for the machine. The other fields have the same semantics as + in stream-based D-Bus. + + + + Some of the flags duplicate flags from the kdbus_msg; + so does the serial number. As discussed below, if these + contradict, the kdbus_msg has higher priority. + + + + The fixed-length header is immediately followed by the + unsigned 32-bit length in bytes for the array of header fields. + This occupies the same bytes of the message that would be + used for the length of the header-field array in a + version 1 message. + + + + Next are the header fields themselves, as an array of structs + (byte, variant), i.e. signature a(uv). Unlike in stream-based + D-Bus, they are encoded using the GVariant serialization + format. Some header fields duplicate parts of the kdbus_msg; + as in the fixed-length header, if contradictory, the kdbus_msg + has higher priority. + + + + The header fields are followed by padding to the next 8-byte + boundary (which is not included in the length value for either the + header fields or the body), then the arguments of the message, + in GVariant serialization as a single struct (tuple) encapsulating + all arguments. For instance, a message with signature iia{sv} + would be serialized as a (iia{sv}) GVariant, a message with + signature (uu) would be serialized with a second level of struct + nesting as ((uu)), and so on. Its length is given by the + body length field in bytes 4-7 of the fixed-length header. + + + + There are two ways to transmit the payload of a kdbus message: + either copying a buffer from sender to recipient + (KDBUS_ITEM_PAYLOAD_VEC), or fd-passing a "sealed" (read-only) + region of memory (KDBUS_ITEM_PAYLOAD_MEMFD). + + memfds allow for zero-copy data transfer, but in practice + this only leads to greater efficiency for messages over 512K + in size. + + The first item of one of those types must be a + KDBUS_ITEM_PAYLOAD_VEC, and must include at least the 16-byte + fixed-length header and all the header fields. It may + additionally include part or all of the body. + + + + Subsequent payload items may be of either type, except that + KDBUS_ITEM_PAYLOAD_MEMFD is not allowed in broadcast messages. + The boundaries between payload items must be immediately before + the first byte of a GVariant, and may not be inside a basic type + or inside an array of fixed-length basic types. + Item boundaries are not necessarily preserved: the kernel + implementation of kdbus may consolidate multiple payload + items into one item, preserving their order. + + + + A message with no arguments (empty signature) has an empty + body (the serialization of a GVariant of type (), which is 0 + bytes long), but padding to an 8-byte boundary is still added + before the zero-length body. + + + + As usual for D-Bus messages, the end of the message is not + padded to any particular alignment boundary. + + + + The GVariant serialization format is not documented here. + Implementors should note that, while D-Bus header fields + and bodies can be decoded based on their type and endianness + only, decoding a GVariant additionally requires knowing the + length: this is why the fixed-length header is followed + by the number of bytes of header fields, even though that + is not part of the GVariant serialization of that array. + + + + + Contradictory or malformed message payloads are not rejected + by kdbus + + + The message bus has traditionally applied strict validation + to messages, and disconnected any sender that attempts + to send an invalid message. In kdbus, the kernel treats the + message payload (fixed-length header, header fields and body) + as opaque, and does not validate it; recipients are responsible + for this. + + + + In particular, to avoid denial of service, message recipients + that can receive messages from less-trusted senders must not + respond to a malformed kdbus message by disconnecting from + the bus. + + + + The general principle is that recipients must treat the + kernel-checked kdbus message metadata as canonical. It is an + error for any duplicate information in the message payload + to contradict the kdbus message metadata; when recipients + are required to handle that error, there are several reasonable + results, but any response must be sent according to the + kdbus message metadata, and not the contradictory fixed-length + header, header fields or body. + + + + It is an error for the presence or absence of the EXPECT_REPLY + flag for a sent message to contradict the absence or + presence of the NO_REPLY_EXPECTED flag in the actual D-Bus + message. The kernel will disallow replies or impose a timeout + according to the value of the EXPECT_REPLY flag, and does + not interpret the NO_REPLY_EXPECTED flag at all. Similarly, + recipients must give higher precedence to the EXPECT_REPLY + flag; if its value contradicts the NO_REPLY_EXPECTED flag, + the recipient may either proceed as if the NO_REPLY_EXPECTED + flag had been the inverse of the EXPECT_REPLY flag, + ignore the message, or (only if EXPECT_REPLY was present) + send back an error reply indicating the contradiction. + + + + As usual, it is an error for known header fields to have types + other than those described in this specification (however, + unknown header fields must be ignored, to allow for future + additions to this specification). Recipients must either + ignore the header field, ignore the message, or send back + an error reply if appropriate. + + + + If the SENDER header field is present and contradicts the src_id, + recipients must either interpret the src_id and ignore the SENDER, + ignore the contradictory message, or (if EXPECT_REPLY + was present) send back an error reply to the src_id. + In particular, recipients must not send the error reply + to the SENDER in this case. + + + + If a recipient will use the destination of a message, and the + DESTINATION header field contradicts the combination of + dst_id and (if present) KDBUS_ITEM_DST_NAME, then recipients + must either interpret the dst_id and KDBUS_ITEM_DST_NAME + and ignore the DESTINATION, ignore the contradictory message, + or (if EXPECT_REPLY was present) send back an error reply to + the src_id. + + + + Recipients are responsible for checking that the message + header fields and body are in canonical form (UTF-8 strings, + valid object paths, zeroes in any alignment padding, etc.) + and that the GVariants in the message do not span across + more than one payload item. Recipients may ignore malformed + messages, or send back an error to the src_id if a reply + is expected. + + + + + Special message-bus messages replaced by special + kernel messages + + + The kernel does not send D-Bus messages, so several areas + of message bus functionality are replaced by messages + with payload type zero or by dedicated ioctls. + + + + The special Hello method () + is replaced as discussed in a separate section above. + + + + The NameOwnerChanged signal + () + is replaced by special NAME_ADD, + NAME_REMOVE, NAME_CHANGE, ID_ADD and ID_REMOVE messages + with payload type zero. + Client libraries may emulate the NameOwnerChanged signal + if required: they should use serial number 0xFFFFFFFF + (32 bits of all-ones) for such synthetic messages. + Not every NAME_ADD, NAME_REMOVE or NAME_CHANGE corresponds to + a NameOwnerChanged signal, because these messages are also + used to indicate that a well-known name has become + service-activatable or has ceased to be service-activatable, + which is a feature not provided by dbus-daemon. + + + + The NameLost and NameAcquired signals + (, + ) are not sent at all. + Client libraries may emulate them from the same messages + if desired. + + + + The NoReply error message sent by the message bus when a + message has not had its expected reply within the allowed time + is replaced by a REPLY_TIMEOUT message. Client libraries + should treat this as a NoReply error. + + + + The NoReply error message sent by the message bus when a + message has not had its expected reply when the connection + responsible for replying leaves the bus is replaced by a + REPLY_DEAD message. Client libraries should treat this as a + NoReply error, ideally with a different human-readable message. + + + + Instead of calling RequestName to acquire a well-known name + (see ), + clients use the KDBUS_CMD_NAME_ACQUIRE ioctl. + Its semantics are similar, but the flags differ, and are + not guaranteed to have corresponding numeric values. + In particular, the DO_NOT_QUEUE flag is replaced by + a QUEUE flag with the opposite sense. + + + + Similarly, instead of calling ReleaseName to release a + well-known name (see ), + clients send a special NAME_RELEASE message to the kernel. + + + + The KDBUS_CMD_NAME_LIST ioctl lists names, replacing + ListNames, ListActivatableNames and ListQueuedOwners + (see , + , + ). + + + + When the AddMatch and RemoveMatch methods + (, + ) + are used to opt-in to receiving broadcast messages, + that use is replaced by the KDBUS_CMD_MATCH_ADD and + KDBUS_CMD_MATCH_REMOVE ioctls. + In stream-based D-Bus, AddMatch and RemoveMatch can also + control eavesdropping, but in kdbus, they do not; see below + () + for details of how eavesdropping changes in kdbus. + + + + The KDBUS_CMD_CONN_INFO ioctl gets extensible details of a + connection, replacing NameHasOwner, GetNameOwner, + GetConnectionUnixUser, GetConnectionCredentials and all similar + methods (see , + , + , + , + , + ). + Like those methods, it returns the credentials that were + current at the time the connection was opened. + + + + + There is no direct equivalent for StartServiceByName + (). + Sending a method call to the target process, either Ping + (see ) + or some more directly relevant message for the target + process, is suggested. + + + + + Message ordering + + + In stream-based D-Bus, the messages entering the message + bus from each connection are in a particular order, + and the messages leaving the message bus for each connection + are in a particular order. In addition, the message bus + interleaves messages in a particular order (total ordering): + if two connections A and B both observe messages M1 and M2, + and A observes M1 before M2, then B cannot observe M1 before + M2. This applies equally to eavesdroppers and to the addressed + recipient. + + + + This does not guarantee that distinct connections within + the same process will send or receive messages in any particular + order relative to each other: A might receive both M1 and M2 + before B does, or vice versa, or they might be interleaved. + Also, some client-side APIs for D-Bus allow messages to + "jump the queue" and get processed out-of-order: notably, + APIs of the form "send a method call and block until the + reply is received" typically result in the reply being + processed before any signals or asynchronous method replies + that would otherwise have been received by the same thread + ahead of the reply. + + + + In kdbus, somewhat weaker ordering constraints apply to + eavesdroppers. Broadcast messages, and eavesdropped messages, + arrive in a particular consistent order chosen by the kernel, + However, if unicast messages M1, M2 originating in different + processes or threads arrive at their addressed destination in + that order, eavesdroppers might see them in the opposite order. + + + + kdbus also has APIs that allow messages to "jump the queue": + messages have a priority field, and it is possible for a + recipient to read higher-priority messages first. There is + also an API for synchronous method calls that transfer + the calling thread's timeslice to the thread implementing + the method, and these will "jump the queue" in the same + way as the equivalent client-side APIs in stream-based D-Bus. + + + + + Messages are native-endian + + + Message senders must send messages in native-endian byte + order, setting the endianness flag (the first byte) as + appropriate. + + + + Message recipients may (FIXME: should? must?) reject messages + where the endianness flag (the first byte) differs from the + recipient's endianness. + + + + FIXME: how does this interact with architectures which can run + different-endian processes on one kernel (ARM, PowerPC, + possibly mips), or with qemu-user running a big-endian ABI + on a little-endian host? + + + + + Eavesdropping is different + + + In dbus-daemon, it is possible for any process to add a match + rule that results in eavesdropping + (). + Messages received via eavesdropping are received in-band, + in the same connection as messages received without eavesdropping. + In the default configuration of the well-known system bus, + eavesdropping is forbidden, and the access-control language + makes it impossible to enable eavesdropping without compromising + system security. In the default configuration of the well-known + session bus, eavesdropping is allowed. + + + + In kdbus, eavesdropping is done by opening a special monitoring + connection, which cannot send messages. Other connections cannot + eavesdrop. Eavesdropping is allowed for processes with + administrative capabilities (specifically CAP_IPC_OWNER), + or for processes whose user ID matches the user ID that created + the bus (always uid 0 for the well-known system bus). + This is not currently configurable. + + + + + Resource limits are different + + + dbus-daemon, the reference implementation of a stream-based + D-Bus message bus, imposes various limits on the well-known + system bus to protect itself from denial-of-service. kdbus + also imposes various limits to protect the kernel from + denial of service, but its resource requirements are rather + different, so the detailed limits are correspondingly different. + + + + dbus-daemon limits the number of incoming and outgoing bytes + that it will hold on behalf of each system bus connection. + kdbus does not limit the number of bytes, since memory for + those bytes is allocated by the sender and recipient out of + their own resource-limits. + + + + kdbus allows more file descriptors per message, and + does not limit the time for which a file descriptor can + be in-flight. + + + + kdbus places a limit on the number of connections + per user per bus domain, whereas for stream-based D-Bus, + the corresponding limit is per bus. + + + + kdbus places a limit on the number of buses per user per bus + domain, whereas stream-based D-Bus can have an arbitrarily + large number of buses, limited only by process and file + descriptor limits. + + + + kdbus limits the number of queued messages from the same sending + user ID to any recipient, and makes attempts to send subsequent + messages block until earlier messages have been dealt with. + Stream-based D-Bus has no such limit. + + + + dbus-daemon imposes essentially no limits on the well-known + session bus, beyond those imposed on it by the kernel and hardware. + In kdbus, the session bus consumes the same kernel resources + as the system bus, so it is subject to similar limits. + + + + + Additional features in kdbus + + + kdbus has various features which are not portable to stream-based + D-Bus; here is an incomplete list. API designers should avoid + relying on these features in APIs intended to be portable, either + by providing slow-paths or by not using these features. + However, in software not intended to be portable, they can + improve performance or make it possible to transfer information + that cannot otherwise be obtained securely. + + + + In kdbus, a recipient can "peek" at the next message in the queue + without de-queuing the message or accepting its attached file + descriptors. In portable stream-based D-Bus, this is not possible. + + + + + kdbus messages have a priority field which may be used by + recipients to process messages out-of-order. Stream-based + D-Bus messages must be received in order. + + + + In kdbus, the credentials attached to the connection include + the monotonic time at which the process started. This can be + used to avoid confusing an old process with ID 1234 with a newer + process that recycled process ID 1234. However, it cannot be + used to distinguish between an unprivileged process, and a + process that replaced that one via exec() (even if the latter + is more privileged due to setuid or similar). + + + + In kdbus, buses are divided into domains, analogous to network + namespaces. In stream-based D-Bus, whether a container has a + different set of buses depends on implementation details of the + bus: TCP sockets and Linux abstract Unix sockets are not shared + by containers in different network namespaces, while + filesystem-backed Unix sockets are not shared by containers + that cannot see the relevant part of the filesystem. + + + + In kdbus, messages may carry additional kernel-supplied metadata, + including process ID, primary user and group IDs, auxiliary group + IDs, audit session ID, audit login user ID, cgroup membership, + process capabilities and security labels: for instance, a service + could use this to restrict execution of a particular method to + calling processes with a particular capability. In stream-based + D-Bus, there is no per-message metadata, only the per-connection + credentials (user ID if not anonymous, process ID if + platform support exists and the unix: transport is used, + and any platform-specific credentials for which race-free + platform support exists). + + + + + kdbus connections have an atomic operation for "disconnect if + there are no pending messages". In stream-based D-Bus, the common + pattern of "disconnect if not used for n seconds" has an inherent + race condition if done from the client side; in principle, it + could be implemented as a special request to the message bus, + but this is not currently specified or implemented. + + + + In kdbus, memfds allow two cooperating processes to transfer + arbitrarily large messages without exhausting message bus + resources, and messages can be more frequent than stream-based + D-Bus would allow for. + + + + + launchd -- 2.1.0