Skip to contentSkip to conversation

Add kdbus implementation

PATCH Superseded Greg Kroah-Hartman 8 participants 48 messages Nov 21, 2014 – Jan 20, 2015

Subsystems (3)

v2 of 4 Superseded Latest is v4 →

lore
Share & tools
lore
#0 lore raw

v2 cover Add kdbus implementation

kdbus is a kernel-level IPC implementation that aims for resemblance to the the protocol layer with the existing userspace D-Bus daemon while enabling some features that couldn't be implemented before in userspace.

The documentation in the first patch in this series explains the protocol and the API details.

This version has changed a lot since the first submission, based on the review comments received, many thanks to everyone who took the time to review the code and make suggestions. Full details are below:

Reasons why this should be done in the kernel, instead of userspace as it is currently done today include the following:

- performance: fewer process context switches, fewer copies, fewer syscalls, larger memory chunks via memfd. This is really important for a whole class of userspace programs that are ported from other operating systems that are run on tiny ARM systems that rely on hundreds of thousands of messages passed at boot time, and at "critical" times in their user interaction loops.
- security: the peers which communicate do not have to trust each other, as the only trustworthy compoenent in the game is the kernel which adds metadata and ensures that all data passed as payload is either copied or sealed, so that the receiver can parse the data without having to protect against changing memory while parsing buffers. Also, all the data transfer is controlled by the kernel, so that LSMs can track and control what is going on, without involving userspace. Because of the LSM issue, security people are much happier with this model than the current scheme of having to hook into dbus to mediate things.
- more metadata can be attached to messages than in userspace
- semantics for apps with heavy data payloads (media apps, for instance) with optinal priority message dequeuing, and global message ordering. Some "crazy" people are playing with using kdbus for audio data in the system. I'm not saying that this is the best model for this, but until now, there wasn't any other way to do this without having to create custom "busses", one for each application library.
- being in the kernle closes a lot of races which can't be fixed with the current userspace solutions. For example, with kdbus, there is a way a client can disconnect from a bus, but do so only if no further messages present in its queue, which is crucial for implementing race-free "exit-on-idle" services
- eavesdropping on the kernel level, so privileged users can hook into the message stream without hacking support for that into their userspace processes
- a number of smaller benefits: for example kdbus learned a way to peek full messages without dequeing them, which is really useful for logging metadata when handling bus-activation requests.

Of course, some of the bits above could be implemented in userspace alone, for example with more sophisticated memory management APIs, but this is usually done by losing out on the other details. For example, for many of the memory management APIs, it's hard to not require the communicating peers to fully trust each other. And we _really_ don't want peers to have to trust each other.

Another benefit of having this in the kernel, rather than as a userspace daemon, is that you can now easily use the bus from the initrd, or up to the very end when the system shuts down. On current userspace D-Bus, this is not really possible, as this requires passing the bus instance around between initrd and the "real" system. Such a transition of all fds also requires keeping full state of what has already been read from the connection fds. kdbus makes this much simpler, as we can change the ownership of the bus, just by passing one fd over from one part to the other.

Regarding binder: binder and kdbus follow very different design concepts. Binder implies the use of thread-pools to dispatch incoming method calls. This is a very efficient scheme, and completely natural in programming languages like Java. On most Linux programs, however, there's a much stronger focus on central poll() loops that dispatch all sources a program cares about. kdbus is much more usable in such environments, as it doesn't enforce a threading model, and it is happy with serialized dispatching. In fact, this major difference had an effect on much of the design decisions: binder does not guarantee global message ordering due to the parallel dispatching in the thread-pools, but kdbus does. Moreover, there's also a difference in the way message handling. In kdbus, every message is basically taken and dispatched as one blob, while in binder, continious connections to other peers are created, which are then used to send messages on. Hence, the models are quite different, and they serve different needs. I believe that the D-Bus/kdbus model is more compatible and friendly with how Linux programs are usually implemented.

This can also be found in a git tree, the kdbus branch of char-misc.git at:
https://git.kernel.org/cgit/linux/kernel/git/gregkh/char-misc.git/

Changes since RFC v1:

* Most notably, kdbus exposes its control files, buses and endpoints via an own file system now, called kdbusfs.

* Each time a file system of this type is mounted, a new kdbus domain is created.

* By default, kdbus is expected to be mounted in /sys/fs/kdbus

* The layout inside each mount point is the same as before, except that domains are not hierarchically nested anymore.

* Domains are therefore also unnamed now.

* Unmounting a kdbusfs will automatically also destroy the associated domain.

* Hence, the action of creating a kdbus domain is now as privileged as mounting a file system.

* This way, we can get around creating dev nodes for everything, which is last but not least something that is not limited by 20-bit minor numbers.

* Rework the metadata attachment logic to address concerns raised by Andy Lutomirsky and Alan Cox:

* Split the attach_flags in kdbus_cmd_hello into two parts, attach_flags_send and attach_flags_recv. Also, split the existing KDBUS_ITEM_ATTACH_FLAGS into KDBUS_ITEM_ATTACH_FLAGS_SEND and KDBUS_ITEM_ATTACH_FLAGS_RECV, and allow updating both connection details through KDBUS_CMD_CONN_UPDATE.

* Only attach metadata to the final message in the receiver's pool if both the sender's attach_flags_send and the receiver's attach_flags_recv bit are set.

* Add an optional metadata mask to the bus during its creation, so bus owners can denote their minimal requirements of metadata to be attached by connections of the bus.

* Namespaces are now pinned by a domain at its creation time, and metadata items are automatically translated into these namespaces. Unless that cannot be done (currently only capabilities), in which case the items are dropped. For hide_pid enabled domains, drop all items except for such not revealing anything about the task.

* Capabilities are now only checked at open() time, and the information is cached for the lifetime of a file descriptor. Reported by Eric W. Biederman, Andy Lutomirski and Thomas Gleixner.

* Make functions that create new objects return the newly allocated memory directly, rather than in a referenced function arguments. That implies using ERR_PTR/PTR_ERR logic in many areas. Requested by Al Viro.

* Rename two details in kdbus.h to not overload the term 'name' too much:

KDBUS_ITEM_CONN_NAME → KDBUS_ITEM_CONN_DESCRIPTION
KDBUS_ATTACH_CONN_NAME → KDBUS_ATTACH_CONN_DESCRIPTION

* Documentation fixes, by Peter Meerwald and others.

* Some memory leaks plugged, and another match test added, by Rui Miguel Silva

* Per-user message count quota logic fixed, and new test added. By John de la Garza.

* More test code for CONN_INFO ioctl

* Added a kdbus_node object embedded by domains, endpoints and buses to track children in a generic way. A kdbus_node is always exposed as inode in kdbusfs.

* Add a new attach flags constant called _KDBUS_ATTACH_ANY (~0) which automatically degrades to _KDBUS_ATTACH_ALL in the kernel. That way, old clients can opt-in for whethever newer kernels might offer to send.

* Use #defines rather than an enum for the ioctl signatures, so when new ones are added, usespace can use #ifdeffery to determine the function set at compile time. Suggested by Arnd Bergmann.

* Moved the driver to ipc/kdbus, as suggested by Arnd Bergmann.

Daniel Mack (13):
kdbus: add documentation
kdbus: add header file
kdbus: add driver skeleton, ioctl entry points and utility functions
kdbus: add connection pool implementation
kdbus: add connection, queue handling and message validation code
kdbus: add node and filesystem implementation
kdbus: add code to gather metadata
kdbus: add code for notifications and matches
kdbus: add code for buses, domains and endpoints
kdbus: add name registry implementation
kdbus: add policy database implementation
kdbus: add Makefile, Kconfig and MAINTAINERS entry
kdbus: add selftests

 Documentation/ioctl/ioctl-number.txt             |    1 +
 Documentation/kdbus.txt                          | 1837 +++++++++++++++++++++
 MAINTAINERS                                      |   12 +
 include/uapi/linux/Kbuild                        |    1 +
 include/uapi/linux/kdbus.h                       |  933 +++++++++++
 include/uapi/linux/magic.h                       |    1 +
 init/Kconfig                                     |   12 +
 ipc/Makefile                                     |    2 +-
 ipc/kdbus/Makefile                               |   21 +
 ipc/kdbus/bus.c                                  |  459 ++++++
 ipc/kdbus/bus.h                                  |   98 ++
 ipc/kdbus/connection.c                           | 1838 ++++++++++++++++++++++
 ipc/kdbus/connection.h                           |  188 +++
 ipc/kdbus/domain.c                               |  349 ++++
 ipc/kdbus/domain.h                               |   84 +
 ipc/kdbus/endpoint.c                             |  497 ++++++
 ipc/kdbus/endpoint.h                             |   91 ++
 ipc/kdbus/fs.c                                   |  417 +++++
 ipc/kdbus/fs.h                                   |   22 +
 ipc/kdbus/handle.c                               |  993 ++++++++++++
 ipc/kdbus/handle.h                               |   20 +
 ipc/kdbus/item.c                                 |  258 +++
 ipc/kdbus/item.h                                 |   41 +
 ipc/kdbus/limits.h                               |   77 +
 ipc/kdbus/main.c                                 |   59 +
 ipc/kdbus/match.c                                |  524 ++++++
 ipc/kdbus/match.h                                |   31 +
 ipc/kdbus/message.c                              |  444 ++++++
 ipc/kdbus/message.h                              |   75 +
 ipc/kdbus/metadata.c                             |  698 ++++++++
 ipc/kdbus/metadata.h                             |   38 +
 ipc/kdbus/names.c                                |  921 +++++++++++
 ipc/kdbus/names.h                                |   81 +
 ipc/kdbus/node.c                                 |  872 ++++++++++
 ipc/kdbus/node.h                                 |   86 +
 ipc/kdbus/notify.c                               |  235 +++
 ipc/kdbus/notify.h                               |   29 +
 ipc/kdbus/policy.c                               |  629 ++++++++
 ipc/kdbus/policy.h                               |   61 +
 ipc/kdbus/pool.c                                 |  722 +++++++++
 ipc/kdbus/pool.h                                 |   44 +
 ipc/kdbus/queue.c                                |  608 +++++++
 ipc/kdbus/queue.h                                |   93 ++
 ipc/kdbus/util.c                                 |  166 ++
 ipc/kdbus/util.h                                 |  103 ++
 tools/testing/selftests/Makefile                 |    1 +
 tools/testing/selftests/kdbus/.gitignore         |   11 +
 tools/testing/selftests/kdbus/Makefile           |   45 +
 tools/testing/selftests/kdbus/kdbus-enum.c       |   94 ++
 tools/testing/selftests/kdbus/kdbus-enum.h       |   14 +
 tools/testing/selftests/kdbus/kdbus-test.c       |  546 +++++++
 tools/testing/selftests/kdbus/kdbus-test.h       |   81 +
 tools/testing/selftests/kdbus/kdbus-util.c       | 1240 +++++++++++++++
 tools/testing/selftests/kdbus/kdbus-util.h       |  143 ++
 tools/testing/selftests/kdbus/test-activator.c   |  317 ++++
 tools/testing/selftests/kdbus/test-benchmark.c   |  409 +++++
 tools/testing/selftests/kdbus/test-bus.c         |  130 ++
 tools/testing/selftests/kdbus/test-chat.c        |  123 ++
 tools/testing/selftests/kdbus/test-connection.c  |  501 ++++++
 tools/testing/selftests/kdbus/test-daemon.c      |   66 +
 tools/testing/selftests/kdbus/test-endpoint.c    |  221 +++
 tools/testing/selftests/kdbus/test-fd.c          |  664 ++++++++
 tools/testing/selftests/kdbus/test-free.c        |   34 +
 tools/testing/selftests/kdbus/test-match.c       |  437 +++++
 tools/testing/selftests/kdbus/test-message.c     |  371 +++++
 tools/testing/selftests/kdbus/test-metadata-ns.c |  258 +++
 tools/testing/selftests/kdbus/test-monitor.c     |  156 ++
 tools/testing/selftests/kdbus/test-names.c       |  184 +++
 tools/testing/selftests/kdbus/test-policy-ns.c   |  622 ++++++++
 tools/testing/selftests/kdbus/test-policy-priv.c | 1168 ++++++++++++++
 tools/testing/selftests/kdbus/test-policy.c      |   81 +
 tools/testing/selftests/kdbus/test-race.c        |  313 ++++
 tools/testing/selftests/kdbus/test-sync.c        |  241 +++
 tools/testing/selftests/kdbus/test-timeout.c     |   97 ++
 74 files changed, 23338 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/kdbus.txt
 create mode 100644 include/uapi/linux/kdbus.h
 create mode 100644 ipc/kdbus/Makefile
 create mode 100644 ipc/kdbus/bus.c
 create mode 100644 ipc/kdbus/bus.h
 create mode 100644 ipc/kdbus/connection.c
 create mode 100644 ipc/kdbus/connection.h
 create mode 100644 ipc/kdbus/domain.c
 create mode 100644 ipc/kdbus/domain.h
 create mode 100644 ipc/kdbus/endpoint.c
 create mode 100644 ipc/kdbus/endpoint.h
 create mode 100644 ipc/kdbus/fs.c
 create mode 100644 ipc/kdbus/fs.h
 create mode 100644 ipc/kdbus/handle.c
 create mode 100644 ipc/kdbus/handle.h
 create mode 100644 ipc/kdbus/item.c
 create mode 100644 ipc/kdbus/item.h
 create mode 100644 ipc/kdbus/limits.h
 create mode 100644 ipc/kdbus/main.c
 create mode 100644 ipc/kdbus/match.c
 create mode 100644 ipc/kdbus/match.h
 create mode 100644 ipc/kdbus/message.c
 create mode 100644 ipc/kdbus/message.h
 create mode 100644 ipc/kdbus/metadata.c
 create mode 100644 ipc/kdbus/metadata.h
 create mode 100644 ipc/kdbus/names.c
 create mode 100644 ipc/kdbus/names.h
 create mode 100644 ipc/kdbus/node.c
 create mode 100644 ipc/kdbus/node.h
 create mode 100644 ipc/kdbus/notify.c
 create mode 100644 ipc/kdbus/notify.h
 create mode 100644 ipc/kdbus/policy.c
 create mode 100644 ipc/kdbus/policy.h
 create mode 100644 ipc/kdbus/pool.c
 create mode 100644 ipc/kdbus/pool.h
 create mode 100644 ipc/kdbus/queue.c
 create mode 100644 ipc/kdbus/queue.h
 create mode 100644 ipc/kdbus/util.c
 create mode 100644 ipc/kdbus/util.h
 create mode 100644 tools/testing/selftests/kdbus/.gitignore
 create mode 100644 tools/testing/selftests/kdbus/Makefile
 create mode 100644 tools/testing/selftests/kdbus/kdbus-enum.c
 create mode 100644 tools/testing/selftests/kdbus/kdbus-enum.h
 create mode 100644 tools/testing/selftests/kdbus/kdbus-test.c
 create mode 100644 tools/testing/selftests/kdbus/kdbus-test.h
 create mode 100644 tools/testing/selftests/kdbus/kdbus-util.c
 create mode 100644 tools/testing/selftests/kdbus/kdbus-util.h
 create mode 100644 tools/testing/selftests/kdbus/test-activator.c
 create mode 100644 tools/testing/selftests/kdbus/test-benchmark.c
 create mode 100644 tools/testing/selftests/kdbus/test-bus.c
 create mode 100644 tools/testing/selftests/kdbus/test-chat.c
 create mode 100644 tools/testing/selftests/kdbus/test-connection.c
 create mode 100644 tools/testing/selftests/kdbus/test-daemon.c
 create mode 100644 tools/testing/selftests/kdbus/test-endpoint.c
 create mode 100644 tools/testing/selftests/kdbus/test-fd.c
 create mode 100644 tools/testing/selftests/kdbus/test-free.c
 create mode 100644 tools/testing/selftests/kdbus/test-match.c
 create mode 100644 tools/testing/selftests/kdbus/test-message.c
 create mode 100644 tools/testing/selftests/kdbus/test-metadata-ns.c
 create mode 100644 tools/testing/selftests/kdbus/test-monitor.c
 create mode 100644 tools/testing/selftests/kdbus/test-names.c
 create mode 100644 tools/testing/selftests/kdbus/test-policy-ns.c
 create mode 100644 tools/testing/selftests/kdbus/test-policy-priv.c
 create mode 100644 tools/testing/selftests/kdbus/test-policy.c
 create mode 100644 tools/testing/selftests/kdbus/test-race.c
 create mode 100644 tools/testing/selftests/kdbus/test-sync.c
 create mode 100644 tools/testing/selftests/kdbus/test-timeout.c
#1 lore raw

kdbus: add documentation

From: Daniel Mack <[email protected]>

kdbus is a system for low-latency, low-overhead, easy to use interprocess communication (IPC).

The interface to all functions in this driver is implemented through ioctls on files exposed through the mount point of a kdbusfs. This patch adds detailed documentation about the kernel level API design.

---
 Documentation/kdbus.txt | 1837 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 1837 insertions(+)
 create mode 100644 Documentation/kdbus.txt
Documentation/kdbus.txt new file +1837 -0
new file mode 100644
index 000000000000..2bd7277ef179
@@ -0,0 +1,1837 @@
+D-Bus is a system for powerful, easy to use interprocess communication (IPC).
+
+The focus of this document is an overview of the low-level, native kernel D-Bus
+transport called kdbus. Kdbus exposes its functionality via files in a
+filesystem called 'kdbusfs'. All communication between processes takes place
+via ioctls on files exposed through the mount point of a kdbusfs. The default
+mount point of kdbusfs is /sys/fs/kdbus.
+
+For the general D-Bus protocol specification, the payload format, the
+marshaling, and the communication semantics, please refer to:
+  http://dbus.freedesktop.org/doc/dbus-specification.html
+
+For a kdbus specific userspace library implementation please refer to:
+  http://cgit.freedesktop.org/systemd/systemd/tree/src/systemd/sd-bus.h
+
+Articles about D-Bus and kdbus:
+  http://lwn.net/Articles/580194/
+
+
+1. Terminology
+===============================================================================
+
+  Domain:
+    A domain is created each time a kdbusfs is mounted. Each process that is
+    capable to mount a new instance of a kdbusfs will have its own kdbus
+    hierarchy. Each domain (ie, each mount point) offers its own "control"
+    file to create new buses. Domains have no connection to each other and
+    cannot see nor talk to each other. See section 5 for more details.
+
+  Bus:
+    A bus is a named object inside a domain. Clients exchange messages
+    over a bus. Multiple buses themselves have no connection to each other;
+    messages can only be exchanged on the same bus. The default entry point to
+    a bus, where clients establish the connection to, is the "bus" file
+    /sys/fs/kdbus/<bus name>/bus.
+    Common operating system setups create one "system bus" per system, and one
+    "user bus" for every logged-in user. Applications or services may create
+    their own private named buses. See section 5 for more details.
+
+  Endpoint:
+    An endpoint provides the file to talk to a bus. Opening an endpoint
+    creates a new connection to the bus to which the endpoint belongs.
+    Inside the directory of the bus, every bus has a default endpoint
+    called "bus". A bus can optionally offer additional endpoints with
+    custom names to provide restricted access to the bus. Custom endpoints
+    carry additional policy which can be used to create sandboxes with a
+    locked-down, limited, filtered access to a bus.  See section 5 for
+    more details.
+
+  Connection:
+    A connection to a bus is created by opening an endpoint file of inside a
+    bus' folder and becoming an active client with the HELLO exchange. Every
+    connected client connection has a unique identifier on the bus and can
+    address messages to every other connection on the same bus by using
+    the peer's connection id as the destination.
+    See section 6 for more details.
+
+  Pool:
+    Each connection allocates a piece of shmem-backed memory that is used
+    to receive messages and answers to ioctl command from the kernel. It is
+    never used to send anything to the kernel. In order to access that memory,
+    userspace must mmap() it into its task.
+    See section 12 for more details.
+
+  Well-known Name:
+    A connection can, in addition to its implicit unique connection id, request
+    the ownership of a textual well-known name. Well-known names are noted in
+    reverse-domain notation, such as com.example.service1. Connections offering
+    a service on a bus are usually reached by its well-known name. The analogy
+    of connection id and well-known name is an IP address and a DNS name
+    associated with that address.
+
+  Message:
+    Connections can exchange messages with other connections by addressing
+    the peers with their connection id or well-known name. A message consists
+    of a message header with kernel-specific information on how to route the
+    message, and the message payload, which is a logical byte stream of
+    arbitrary size. Messages can carry additional file descriptors to be passed
+    from one connection to another. Every connection can specify which set of
+    metadata the kernel should attach to the message when it is delivered
+    to the receiving connection. Metadata contains information like: system
+    timestamps, uid, gid, tid, proc-starttime, well-known-names, process comm,
+    process exe, process argv, cgroup, capabilities, seclabel, audit session,
+    loginuid and the connection's human-readable name.
+    See section 7 and 13 for more details.
+
+  Item:
+    The API of kdbus implements a notion of items, submitted through and
+    returned by most ioctls, and stored inside data structures in the
+    connection's pool. See section 4 for more details.
+
+  Broadcast and Match:
+    Broadcast messages are potentially sent to all connections of a bus. By
+    default, the connections will not actually receive any of the sent
+    broadcast messages; only after installing a match for specific message
+    properties, a broadcast message passes this filter.
+    See section 10 for more details.
+
+  Policy:
+    A policy is a set of rules that define which connections can see, talk to,
+    or register a well-know name on the bus. A policy is attached to buses and
+    custom endpoints, and modified by policy holder connection or owners of
+    custom endpoints. See section 11 for more details.
+
+    Access rules to allow who can see a name on the bus are only checked on
+    custom endpoints. Policies may be defined with names that end with '.*'.
+    When matching a well-known name against such a wildcard entry, the last
+    part of the name is ignored and checked against the wildcard name without
+    the trailing '.*'. See section 11 for more details.
+
+  Privileged bus users:
+    A user connecting to the bus is considered privileged if it is either the
+    creator of the bus, or if it has the CAP_IPC_OWNER capability flag set.
+
+
+2. Control Files Layout
+===============================================================================
+
+The kdbus interface is exposed through files in its kdbusfs mount point
+(defaults to /sys/fs/kdbus):
+
+  /sys/fs/kdbus
+  |-- control
+  |-- 0-system
+  |   |-- bus
+  |   `-- ep.apache
+  |-- 1000-user
+  |   `-- bus
+  `-- 2702-user
+      |-- bus
+      `-- ep.app
+
+
+3. Data Structures and flags
+===============================================================================
+
+3.1 Data structures and interconnections
+----------------------------------------
+
+  +--------------------------------------------------------------------------+
+  | Domain (Mount Point)                                                     |
+  | /sys/fs/kdbus/control                                                    |
+  | +----------------------------------------------------------------------+ |
+  | | Bus (System Bus)                                                     | |
+  | | /sys/fs/kdbus/0-system/                                              | |
+  | | +-------------------------------+ +--------------------------------+ | |
+  | | | Endpoint                      | | Endpoint                       | | |
+  | | | /sys/fs/kdbus/0-system/bus    | | /sys/fs/kdbus/0-system/ep.app  | | |
+  | | +-------------------------------+ +--------------------------------+ | |
+  | | +--------------+ +--------------+ +--------------+ +---------------+ | |
+  | | | Connection   | | Connection   | | Connection   | | Connection    | | |
+  | | | :1.22        | | :1.25        | | :1.55        | | :1.81         | | |
+  | | +--------------+ +--------------+ +--------------+ +---------------+ | |
+  | +----------------------------------------------------------------------+ |
+  |                                                                          |
+  | +----------------------------------------------------------------------+ |
+  | | Bus (User Bus for UID 2702)                                          | |
+  | | /sys/fs/kdbus/2702-user/                                             | |
+  | | +-------------------------------+ +--------------------------------+ | |
+  | | | Endpoint                      | | Endpoint                       | | |
+  | | | /sys/fs/kdbus/2702-user/bus   | | /sys/fs/kdbus/2702-user/ep.app | | |
+  | | +-------------------------------+ +--------------------------------+ | |
+  | | +--------------+ +--------------+ +--------------+ +---------------+ | |
+  | | | Connection   | | Connection   | | Connection   | | Connection    | | |
+  | | | :1.22        | | :1.25        | | :1.55        | | :1.81         | | |
+  | | +--------------+ +--------------+ +--------------------------------+ | |
+  | +----------------------------------------------------------------------+ |
+  +--------------------------------------------------------------------------+
+
+The above description uses the D-Bus notation of unique connection names that
+adds a ":1." prefix to the connection's unique ID. kdbus itself doesn't
+use that notation, neither internally nor externally. However, libraries and
+other usespace code that aims for compatibility to D-Bus might.
+
+3.2 Flags
+---------
+
+All ioctls used in the communication with the driver contain two 64-bit fields,
+'flags' and 'kernel_flags'. In 'flags', the behavior of the command can be
+tweaked, whereas in 'kernel_flags', the kernel driver writes back the mask of
+supported bits upon each call, and sets the KDBUS_FLAGS_KERNEL bit. This is a
+way to probe possible kernel features and make code forward and backward
+compatible.
+
+All bits that are not recognized by the kernel in 'flags' are rejected, and the
+ioctl fails with -EINVAL.
+
+
+4. Items
+===============================================================================
+
+To flexibly augment transport structures used by kdbus, data blobs of type
+struct kdbus_item are used. An item has a fixed-sized header that only stores
+the type of the item and the overall size. The total size is variable and is
+in some cases defined by the item type, in other cases, they can be of
+arbitrary length (for instance, a string).
+
+In the external kernel API, items are used for many ioctls to transport
+optional information from userspace to kernelspace. They are also used for
+information stored in a connection's pool, such as messages, name lists or
+requested connection information.
+
+In all such occasions where items are used as part of the kdbus kernel API,
+they are embedded in structs that have an overall size of their own, so there
+can be many of them.
+
+The kernel expects all items to be aligned to 8-byte boundaries.
+
+A simple iterator in userspace would iterate over the items until the items
+have reached the embedding structure's overall size. An example implementation
+of such an iterator can be found in tools/testing/selftests/kdbus/kdbus-util.h.
+
+
+5. Creation of new domains, buses and endpoints
+===============================================================================
+
+The initial kdbus domain is unconditionally created by the kernel module. A
+domain contains a "control" file which allows to create a new bus. New domains
+(mount points) do not have any buses created by default.
+
+
+5.1 Buses
+---------
+
+Opening the control file returns a file descriptor which accepts the
+KDBUS_CMD_BUS_MAKE ioctl to create a new bus. The control file descriptor needs
+to be kept open for the entire life-time of the created bus, closing it will
+immediately cleanup the entire bus and all its associated resources and
+endpoints. Every control file descriptor can only be used once
+to create a new bus; from that point, it is not used for any further
+communication until the final close().
+
+Each bus will generate a random, 128-bit UUID upon creation. It will be
+returned to the creators of connections through kdbus_cmd_hello.id128 and can
+be used by userspace to uniquely identify buses, even across different machines
+or containers. The UUID will have its its variant bits set to 'DCE', and denote
+version 4 (random).
+
+Optionally, an item of type KDBUS_ITEM_ATTACH_FLAGS_RECV can be attached to
+KDBUS_CMD_BUS_MAKE. In that, a set of required attach flags can be passed,
+which is used as negotiation measure during connection creation.
+
+
+5.2 Endpoints
+-------------
+
+Endpoints are entry points to a bus. By default, each bus has a default
+endpoint called 'bus'. The bus owner has the ability to create custom
+endpoints with specific names, permissions, and policy databases (see below).
+
+To create a custom endpoint, use the KDBUS_CMD_ENDPOINT_MAKE ioctl with struct
+kdbus_cmd_make. Custom endpoints always have a policy database that, by
+default, does not allow anything. Everything that users of this new endpoint
+should be able to do has to be explicitly specified through KDBUS_ITEM_NAME and
+KDBUS_ITEM_POLICY_ACCESS items.
+
+
+5.3 Domains
+-----------
+
+Each time a kdbusfs is mounted, a new kdbus domain is created, with its own
+'control' file only. The lifetime of the domain ends once the user has
+unmounted the kdbusfs.
+
+
+5.4 Creating buses and endpoints
+--------------------------------
+
+KDBUS_CMD_BUS_MAKE, and KDBUS_CMD_ENDPOINT_MAKE take a
+struct kdbus_cmd_make argument.
+
+struct kdbus_cmd_make {
+  __u64 size;
+    The overall size of the struct, including its items.
+
+  __u64 flags;
+    The flags for creation.
+
+    KDBUS_MAKE_ACCESS_GROUP
+      Make the device file group-accessible
+
+    KDBUS_MAKE_ACCESS_WORLD
+      Make the device file world-accessible
+
+  __u64 kernel_flags;
+    Valid flags for this command, returned by the kernel upon each call.
+
+  struct kdbus_item items[0];
+    A list of items, only used for creating custom endpoints. Has specific
+    meanings for KDBUS_CMD_BUS_MAKE and KDBUS_CMD_ENDPOINT_MAKE (see above).
+};
+
+
+6. Connections
+===============================================================================
+
+
+6.1 Connection IDs and well-known connection names
+--------------------------------------------------
+
+Connections are identified by their connection id, internally implemented as a
+uint64_t counter. The IDs of every newly created bus start at 1, and every new
+connection will increment the counter by 1. The ids are not reused.
+
+In higher level tools, the user visible representation of a connection is
+defined by the D-Bus protocol specification as ":1.<id>".
+
+Messages with a specific uint64_t destination id are directly delivered to
+the connection with the corresponding id. Messages with the special destination
+id KDBUS_DST_ID_BROADCAST are broadcast messages and are potentially delivered
+to all known connections on the bus; clients interested in broadcast messages
+need to subscribe to the specific messages they are interested, though before
+any broadcast message reaches them.
+
+Messages synthesized and sent directly by the kernel will carry the special
+source id KDBUS_SRC_ID_KERNEL (0).
+
+In addition to the unique uint64_t connection id, established connections can
+request the ownership of well-known names, under which they can be found and
+addressed by other bus clients. A well-known name is associated with one and
+only one connection at a time. See section 8 on name acquisition and the
+name registry, and the validity of names.
+
+Messages can specify the special destination id 0 and carry a well-known name
+in the message data. Such a message is delivered to the destination connection
+which owns that well-known name.
+
+  +-------------------------------------------------------------------------+
+  | +---------------+     +---------------------------+                     |
+  | | Connection    |     | Message                   | -----------------+  |
+  | | :1.22         | --> | src: 22                   |                  |  |
+  | |               |     | dst: 25                   |                  |  |
+  | |               |     |                           |                  |  |
+  | |               |     |                           |                  |  |
+  | |               |     +---------------------------+                  |  |
+  | |               |                                                    |  |
+  | |               | <--------------------------------------+           |  |
+  | +---------------+                                        |           |  |
+  |                                                          |           |  |
+  | +---------------+     +---------------------------+      |           |  |
+  | | Connection    |     | Message                   | -----+           |  |
+  | | :1.25         | --> | src: 25                   |                  |  |
+  | |               |     | dst: 0xffffffffffffffff   | -------------+   |  |
+  | |               |     |  (KDBUS_DST_ID_BROADCAST) |              |   |  |
+  | |               |     |                           | ---------+   |   |  |
+  | |               |     +---------------------------+          |   |   |  |
+  | |               |                                            |   |   |  |
+  | |               | <--------------------------------------------------+  |
+  | +---------------+                                            |   |      |
+  |                                                              |   |      |
+  | +---------------+     +---------------------------+          |   |      |
+  | | Connection    |     | Message                   | --+      |   |      |
+  | | :1.55         | --> | src: 55                   |   |      |   |      |
+  | |               |     | dst: 0 / org.foo.bar      |   |      |   |      |
+  | |               |     |                           |   |      |   |      |
+  | |               |     |                           |   |      |   |      |
+  | |               |     +---------------------------+   |      |   |      |
+  | |               |                                     |      |   |      |
+  | |               | <------------------------------------------+   |      |
+  | +---------------+                                     |          |      |
+  |                                                       |          |      |
+  | +---------------+                                     |          |      |
+  | | Connection    |                                     |          |      |
+  | | :1.81         |                                     |          |      |
+  | | org.foo.bar   |                                     |          |      |
+  | |               |                                     |          |      |
+  | |               |                                     |          |      |
+  | |               | <-----------------------------------+          |      |
+  | |               |                                                |      |
+  | |               | <----------------------------------------------+      |
+  | +---------------+                                                       |
+  +-------------------------------------------------------------------------+
+
+
+6.2 Creating connections
+------------------------
+
+A connection to a bus is created by opening an endpoint file of a bus and
+becoming an active client with the KDBUS_CMD_HELLO ioctl. Every connected client
+connection has a unique identifier on the bus and can address messages to every
+other connection on the same bus by using the peer's connection id as the
+destination.
+
+The KDBUS_CMD_HELLO ioctl takes the following struct as argument.
+
+struct kdbus_cmd_hello {
+  __u64 size;
+    The overall size of the struct, including all attached items.
+
+  __u64 conn_flags;
+    Flags to apply to this connection:
+
+    KDBUS_HELLO_ACCEPT_FD
+      When this flag is set, the connection can be sent file descriptors
+      as message payload. If it's not set, any attempt of doing so will
+      result in -ECOMM on the sender's side.
+
+    KDBUS_HELLO_ACTIVATOR
+      Make this connection an activator (see below). With this bit set,
+      an item of type KDBUS_ITEM_NAME has to be attached which describes
+      the well-known name this connection should be an activator for.
+
+    KDBUS_HELLO_POLICY_HOLDER
+      Make this connection a policy holder (see below). With this bit set,
+      an item of type KDBUS_ITEM_NAME has to be attached which describes
+      the well-known name this connection should hold a policy for.
+
+    KDBUS_HELLO_MONITOR
+      Make this connection an eaves-dropping connection that receives all
+      unicast messages sent on the bus. To also receive broadcast messages,
+      the connection has to upload appropriate matches as well.
+      This flag is only valid for privileged bus connections.
+
+  __u64 attach_flags_send;
+      Set the bits for metadata this connection permits to be sent to the
+      receiving peer. Only metadata items that are both allowed to be sent by
+      the sender and that are requested by the receiver will effectively be
+      attached to the message eventually. Note, however, that the bus may
+      optionally enforce some of those bits to be set. If the match fails,
+      -ECONNREFUSED will be returned. In either case, this field will be set
+      to the mask of metadata items that are enforced by the bus. The
+      KDBUS_FLAGS_KERNEL bit will as well be set.
+
+  __u64 attach_flags_recv;
+      Request the attachment of metadata for each message received by this
+      connection. The metadata actually attached may actually augment the list
+      of requested items. See section 13 for more details.
+
+  __u64 bus_flags;
+      Upon successful completion of the ioctl, this member will contain the
+      flags of the bus it connected to.
+
+  __u64 id;
+      Upon successful completion of the ioctl, this member will contain the
+      id of the new connection.
+
+  __u64 pool_size;
+      The size of the communication pool, in bytes. The pool can be accessed
+      by calling mmap() on the file descriptor that was used to issue the
+      KDBUS_CMD_HELLO ioctl.
+
+  struct kdbus_bloom_parameter bloom;
+      Bloom filter parameter (see below).
+
+  __u8 id128[16];
+      Upon successful completion of the ioctl, this member will contain the
+      128 bit wide UUID of the connected bus.
+
+  struct kdbus_item items[0];
+      Variable list of items to add optional additional information. The
+      following items are currently expected/valid:
+
+      KDBUS_ITEM_CONN_DESCRIPTION
+        Contains a string to describes this connection's name, so it can be
+        identified later.
+
+      KDBUS_ITEM_NAME
+      KDBUS_ITEM_POLICY_ACCESS
+        For activators and policy holders only, combinations of these two
+        items describe policy access entries (see section about policy).
+
+      KDBUS_ITEM_CREDS
+      KDBUS_ITEM_SECLABEL
+        Privileged bus users may submit these types in order to create
+        connections with faked credentials. The only real use case for this
+        is a proxy service which acts on behalf of some other tasks. For a
+        connection that runs in that mode, the message's metadata items will
+        be limited to what's specified here. See section 13 for more
+        information.
+
+      Items of other types are silently ignored.
+};
+
+
+6.3 Activator and policy holder connection
+------------------------------------------
+
+An activator connection is a placeholder for a well-known name. Messages sent
+to such a connection can be used by userspace to start an implementor
+connection, which will then get all the messages from the activator copied
+over. An activator connection cannot be used to send any message.
+
+A policy holder connection only installs a policy for one or more names.
+These policy entries are kept active as long as the connection is alive, and
+are removed once it terminates. Such a policy connection type can be used to
+deploy restrictions for names that are not yet active on the bus. A policy
+holder connection cannot be used to send any message.
+
+The creation of activator, policy holder or monitor connections is an operation
+restricted to privileged users on the bus (see section "Terminology").
+
+
+6.4 Retrieving information on a connection
+------------------------------------------
+
+The KDBUS_CMD_CONN_INFO ioctl can be used to retrieve credentials and
+properties of the initial creator of a connection. This ioctl uses the
+following struct:
+
+struct kdbus_cmd_info {
+  __u64 size;
+    The overall size of the struct, including the name with its 0-byte string
+    terminator.
+
+  __u64 flags;
+    Specify which metadata items should be attached to the answer.
+    See section 13 for more details.
+
+    After the ioctl returns, this field will contain the current metadata
+    attach flags of the connection.
+
+  __u64 kernel_flags;
+    Valid flags for this command, returned by the kernel upon each call.
+
+  __u64 id;
+    The connection's numerical ID to retrieve information for. If set to
+    non-zero value, the 'name' field is ignored.
+
+  __u64 offset;
+    When the ioctl returns, this value will yield the offset of the connection
+    information inside the caller's pool.
+
+  struct kdbus_item items[0];
+    The optional item list, containing the well-known name to look up as
+    a KDBUS_ITEM_OWNED_NAME. Only required if the 'id' field is set to 0.
+    All other items are currently ignored.
+};
+
+After the ioctl returns, the following struct will be stored in the caller's
+pool at 'offset'.
+
+struct kdbus_info {
+  __u64 size;
+    The overall size of the struct, including all its items.
+
+  __u64 id;
+    The connection's unique ID.
+
+  __u64 flags;
+    The connection's flags as specified when it was created.
+
+  __u64 kernel_flags;
+    Valid flags for this command, returned by the kernel upon each call.
+
+  struct kdbus_item items[0];
+    Depending on the 'flags' field in struct kdbus_cmd_info, items of
+    types KDBUS_ITEM_OWNED_NAME and KDBUS_ITEM_CONN_DESCRIPTION are followed
+    here.
+};
+
+Once the caller is finished with parsing the return buffer, it needs to call
+KDBUS_CMD_FREE for the offset.
+
+
+6.5 Getting information about a connection's bus creator
+--------------------------------------------------------
+
+The KDBUS_CMD_BUS_CREATOR_INFO ioctl takes the same struct as
+KDBUS_CMD_CONN_INFO but is used to retrieve information about the creator of
+the bus the connection is attached to. The metadata returned by this call is
+collected during the creation of the bus and is never altered afterwards, so
+it provides pristine information on the task that created the bus, at the
+moment when it did so.
+
+In response to this call, a slice in the connection's pool is allocated and
+filled with an object of type struct kdbus_info, pointed to by the ioctl's
+'offset' field.
+
+struct kdbus_info {
+  __u64 size;
+    The overall size of the struct, including all its items.
+
+  __u64 id;
+    The bus' ID
+
+  __u64 flags;
+    The bus' flags as specified when it was created.
+
+  __u64 kernel_flags;
+    Valid flags for this command, returned by the kernel upon each call.
+
+  struct kdbus_item items[0];
+    Metadata information is stored in items here.
+};
+
+Once the caller is finished with parsing the return buffer, it needs to call
+KDBUS_CMD_FREE for the offset.
+
+
+6.6 Updating connection details
+-------------------------------
+
+Some of a connection's details can be updated with the KDBUS_CMD_CONN_UPDATE
+ioctl, using the file descriptor that was used to create the connection.
+The update command uses the following struct.
+
+struct kdbus_cmd_update {
+  __u64 size;
+    The overall size of the struct, including all its items.
+
+  struct kdbus_item items[0];
+    Items to describe the connection details to be updated. The following item
+    types are supported:
+
+    KDBUS_ITEM_ATTACH_FLAGS_SEND
+      Supply a new set of items that this connection permits to be sent along
+      with messages.
+
+    KDBUS_ITEM_ATTACH_FLAGS_RECV
+      Supply a new set of items to be attached to each message.
+
+    KDBUS_ITEM_NAME
+    KDBUS_ITEM_POLICY_ACCESS
+      Policy holder connections may supply a new set of policy information
+      with these items. For other connection types, -EOPNOTSUPP is returned.
+};
+
+
+6.6 Termination
+---------------
+
+A connection can be terminated by simply closing the file descriptor that was
+used to start the connection. All pending incoming messages will be discarded,
+and the memory in the pool will be freed.
+
+An alternative way of closing down a connection is calling the KDBUS_CMD_BYEBYE
+ioctl on it, which will only succeed if the message queue of the connection is
+empty at the time of closing, otherwise, -EBUSY is returned.
+
+When this ioctl returns successfully, the connection has been terminated and
+won't accept any new messages from remote peers. This way, a connection can
+be terminated race-free, without losing any messages.
+
+
+7. Messages
+===============================================================================
+
+Messages consist of a fixed-size header followed directly by a list of
+variable-sized data 'items'. The overall message size is specified in the
+header of the message. The chain of data items can contain well-defined
+message metadata fields, raw data, references to data, or file descriptors.
+
+
+7.1 Sending messages
+--------------------
+
+Messages are passed to the kernel with the KDBUS_CMD_MSG_SEND ioctl. Depending
+on the destination address of the message, the kernel delivers the message to
+the specific destination connection or to all connections on the same bus.
+Sending messages across buses is not possible. Messages are always queued in
+the memory pool of the destination connection (see below).
+
+The KDBUS_CMD_MSG_SEND ioctl uses struct kdbus_msg to describe the message to
+be sent.
+
+struct kdbus_msg {
+  __u64 size;
+    The overall size of the struct, including the attached items.
+
+  __u64 flags;
+    Flags for message delivery:
+
+    KDBUS_MSG_FLAGS_EXPECT_REPLY
+      Expect a reply from the remote peer to this message. With this bit set,
+      the timeout_ns field must be set to a non-zero number of nanoseconds in
+      which the receiving peer is expected to reply. If such a reply is not
+      received in time, the sender will be notified with a timeout message
+      (see below). The value must be an absolute value, in nanoseconds and
+      based on CLOCK_MONOTONIC.
+
+      For a message to be accepted as reply, it must be a direct message to
+      the original sender (not a broadcast), and its kdbus_msg.reply_cookie
+      must match the previous message's kdbus_msg.cookie.
+
+      Expected replies also temporarily open the policy of the sending
+      connection, so the other peer is allowed to respond within the given
+      time window.
+
+    KDBUS_MSG_FLAGS_SYNC_REPLY
+      By default, all calls to kdbus are considered asynchronous,
+      non-blocking. However, as there are many use cases that need to wait
+      for a remote peer to answer a method call, there's a way to send a
+      message and wait for a reply in a synchronous fashion. This is what
+      the KDBUS_MSG_FLAGS_SYNC_REPLY controls. The KDBUS_CMD_MSG_SEND ioctl
+      will block until the reply has arrived, the timeout limit is reached,
+      in case the remote connection was shut down, or if interrupted by
+      a signal before any reply; see signal(7).
+
+      The offset of the reply message in the sender's pool is stored in
+      in 'offset_reply' when the ioctl has returned without error. Hence,
+      there is no need for another KDBUS_CMD_MSG_RECV ioctl or anything else
+      to receive the reply.
+
+    KDBUS_MSG_FLAGS_NO_AUTO_START
+      By default, when a message is sent to an activator connection, the
+      activator notified and will start an implementor. This flag inhibits
+      that behavior. With this bit set, and the remote being an activator,
+      -EADDRNOTAVAIL is returned from the ioctl.
+
+  __u64 kernel_flags;
+    Valid flags for this command, returned by the kernel upon each call of
+    KDBUS_MSG_SEND.
+
+  __s64 priority;
+    The priority of this message. Receiving messages (see below) may
+    optionally be constrained to messages of a minimal priority. This
+    allows for use cases where timing critical data is interleaved with
+    control data on the same connection. If unused, the priority should be
+    set to zero.
+
+  __u64 dst_id;
+    The numeric ID of the destination connection, or KDBUS_DST_ID_BROADCAST
+    (~0ULL) to address every peer on the bus, or KDBUS_DST_ID_NAME (0) to look
+    it up dynamically from the bus' name registry. In the latter case, an item
+    of type KDBUS_ITEM_DST_NAME is mandatory.
+
+  __u64 src_id;
+    Upon return of the ioctl, this member will contain the sending
+    connection's numerical ID. Should be 0 at send time.
+
+  __u64 payload_type;
+    Type of the payload in the actual data records. Currently, only
+    KDBUS_PAYLOAD_DBUS is accepted as input value of this field. When
+    receiving messages that are generated by the kernel (notifications),
+    this field will yield KDBUS_PAYLOAD_KERNEL.
+
+  __u64 cookie;
+    Cookie of this message, for later recognition. Also, when replying
+    to a message (see above), the cookie_reply field must match this value.
+
+  __u64 timeout_ns;
+    If the message sent requires a reply from the remote peer (see above),
+    this field contains the timeout in absolute nanoseconds based on
+    CLOCK_MONOTONIC.
+
+  __u64 cookie_reply;
+    If the message sent is a reply to another message, this field must
+    match the cookie of the formerly received message.
+
+  __u64 offset_reply;
+    If the message successfully got a synchronous reply (see above), this
+    field will yield the offset of the reply message in the sender's pool.
+    Is is what KDBUS_CMD_MSG_RECV usually does for asynchronous messages.
+
+  struct kdbus_item items[0];
+    A dynamically sized list of items to contain additional information.
+    The following items are expected/valid:
+
+    KDBUS_ITEM_PAYLOAD_VEC
+    KDBUS_ITEM_PAYLOAD_MEMFD
+    KDBUS_ITEM_FDS
+      Actual data records containing the payload. See section "Passing of
+      Payload Data".
+
+    KDBUS_ITEM_BLOOM_FILTER
+      Bloom filter for matches (see below).
+
+    KDBUS_ITEM_DST_NAME
+      Well-known name to send this message to. Required if dst_id is set
+      to KDBUS_DST_ID_NAME. If a connection holding the given name can't
+      be found, -ESRCH is returned.
+      For messages to a unique name (ID), this item is optional. If present,
+      the kernel will make sure the name owner matches the given unique name.
+      This allows userspace tie the message sending to the condition that a
+      name is currently owned by a certain unique name.
+};
+
+The message will be augmented by the requested metadata items when queued into
+the receiver's pool. See also section 13.1 ("Metadata and namespaces").
+
+
+7.2 Message layout
+------------------
+
+The layout of a message is shown below.
+
+  +-------------------------------------------------------------------------+
+  | Message                                                                 |
+  | +---------------------------------------------------------------------+ |
+  | | Header                                                              | |
+  | | size: overall message size, including the data records              | |
+  | | destination: connection id of the receiver                          | |
+  | | source: connection id of the sender (set by kernel)                 | |
+  | | payload_type: "DBusDBus" textual identifier stored as uint64_t      | |
+  | +---------------------------------------------------------------------+ |
+  | +---------------------------------------------------------------------+ |
+  | | Data Record                                                         | |
+  | | size: overall record size (without padding)                         | |
+  | | type: type of data                                                  | |
+  | | data: reference to data (address or file descriptor)                | |
+  | +---------------------------------------------------------------------+ |
+  | +---------------------------------------------------------------------+ |
+  | | padding bytes to the next 8 byte alignment                          | |
+  | +---------------------------------------------------------------------+ |
+  | +---------------------------------------------------------------------+ |
+  | | Data Record                                                         | |
+  | | size: overall record size (without padding)                         | |
+  | | ...                                                                 | |
+  | +---------------------------------------------------------------------+ |
+  | +---------------------------------------------------------------------+ |
+  | | padding bytes to the next 8 byte alignment                          | |
+  | +---------------------------------------------------------------------+ |
+  | +---------------------------------------------------------------------+ |
+  | | Data Record                                                         | |
+  | | size: overall record size                                           | |
+  | | ...                                                                 | |
+  | +---------------------------------------------------------------------+ |
+  | +---------------------------------------------------------------------+ |
+  | | padding bytes to the next 8 byte alignment                          | |
+  | +---------------------------------------------------------------------+ |
+  +-------------------------------------------------------------------------+
+
+
+7.3 Passing of Payload Data
+---------------------------
+
+When connecting to the bus, receivers request a memory pool of a given size,
+large enough to carry all backlog of data enqueued for the connection. The
+pool is internally backed by a shared memory file which can be mmap()ed by
+the receiver.
+
+KDBUS_MSG_PAYLOAD_VEC:
+  Messages are directly copied by the sending process into the receiver's pool,
+  that way two peers can exchange data by effectively doing a single-copy from
+  one process to another, the kernel will not buffer the data anywhere else.
+
+KDBUS_MSG_PAYLOAD_MEMFD:
+  Messages can reference memfd files which contain the data.
+  memfd files are tmpfs-backed files that allow sealing of the content of the
+  file, which prevents all writable access to the file content.
+  Only sealed memfd files are accepted as payload data, which enforces
+  reliable passing of data; the receiver can assume that neither the sender nor
+  anyone else can alter the content after the message is sent.
+
+Apart from the sender filling-in the content into memfd files, the data will
+be passed as zero-copy from one process to another, read-only, shared between
+the peers.
+
+
+7.4 Receiving messages
+----------------------
+
+Messages are received by the client with the KDBUS_CMD_MSG_RECV ioctl. The
+endpoint file of the bus supports poll() to wake up the receiving process when
+new messages are queued up to be received.
+
+With the KDBUS_CMD_MSG_RECV ioctl, a struct kdbus_cmd_recv is used.
+
+struct kdbus_cmd_recv {
+  __u64 flags;
+    Flags to control the receive command.
+
+    KDBUS_RECV_PEEK
+      Just return the location of the next message. Do not install file
+      descriptors or anything else. This is usually used to determine the
+      sender of the next queued message.
+
+    KDBUS_RECV_DROP
+      Drop the next message without doing anything else with it, and free the
+      pool slice. This a short-cut for KDBUS_RECV_PEEK and KDBUS_CMD_FREE.
+
+    KDBUS_RECV_USE_PRIORITY
+      Use the priority field (see below).
+
+  __u64 kernel_flags;
+    Valid flags for this command, returned by the kernel upon each call.
+
+  __s64 priority;
+      With KDBUS_RECV_USE_PRIORITY set in flags, receive the next message in
+      the queue with at least the given priority. If no such message is waiting
+      in the queue, -ENOMSG is returned.
+
+  __u64 offset;
+      Upon return of the ioctl, this field contains the offset in the
+      receiver's memory pool.
+};
+
+Unless KDBUS_RECV_DROP was passed, and given that the ioctl succeeded, the
+offset field contains the location of the new message inside the receiver's
+pool. The message is stored as struct kdbus_msg at this offset, and can be
+interpreted with the semantics described above.
+
+Also, if the connection allowed for file descriptor to be passed
+(KDBUS_HELLO_ACCEPT_FD), and if the message contained any, they will be
+installed into the receiving process after the KDBUS_CMD_MSG_RECV ioctl
+returns. The receiving task is obliged to close all of them appropriately.
+
+The caller is obliged to call KDBUS_CMD_FREE with the returned offset when
+the memory is no longer needed.
+
+
+7.5 Canceling messages synchronously waiting for replies
+--------------------------------------------------------
+
+When a connection sends a message with KDBUS_MSG_FLAGS_SYNC_REPLY and
+blocks while waiting for the reply, the KDBUS_CMD_MSG_CANCEL ioctl can be
+used on the same file descriptor to cancel the message, based on its cookie.
+If there are multiple messages with the same cookie that are all synchronously
+waiting for a reply, all of them will be canceled. Obviously, this is only
+possible in multi-threaded applications.
+
+
+8. Name registry
+===============================================================================
+
+Each bus instantiates a name registry to resolve well-known names into unique
+connection IDs for message delivery. The registry will be queried when a
+message is sent with kdbus_msg.dst_id set to KDBUS_DST_ID_NAME, or when a
+registry dump is requested.
+
+All of the below is subject to policy rules for SEE and OWN permissions.
+
+
+8.1 Name validity
+-----------------
+
+A name has to comply to the following rules to be considered valid:
+
+ - The name has two or more elements separated by a period ('.') character
+ - All elements must contain at least one character
+ - Each element must only contain the ASCII characters "[A-Z][a-z][0-9]_"
+   and must not begin with a digit
+ - The name must contain at least one '.' (period) character
+   (and thus at least two elements)
+ - The name must not begin with a '.' (period) character
+ - The name must not exceed KDBUS_NAME_MAX_LEN (255)
+
+
+8.2 Acquiring a name
+--------------------
+
+To acquire a name, a client uses the KDBUS_CMD_NAME_ACQUIRE ioctl with the
+following data structure.
+
+struct kdbus_cmd_name {
+  __u64 size;
+    The overall size of this struct, including the name with its 0-byte string
+    terminator.
+
+  __u64 flags;
+    Flags to control details in the name acquisition.
+
+    KDBUS_NAME_REPLACE_EXISTING
+      Acquiring a name that is already present usually fails, unless this flag
+      is set in the call, and KDBUS_NAME_ALLOW_REPLACEMENT or (see below) was
+      set when the current owner of the name acquired it, or if the current
+      owner is an activator connection (see below).
+
+    KDBUS_NAME_ALLOW_REPLACEMENT
+      Allow other connections to take over this name. When this happens, the
+      former owner of the connection will be notified of the name loss.
+
+    KDBUS_NAME_QUEUE (acquire)
+      A name that is already acquired by a connection, and which wasn't
+      requested with the KDBUS_NAME_ALLOW_REPLACEMENT flag set can not be
+      acquired again. However, a connection can put itself in a queue of
+      connections waiting for the name to be released. Once that happens, the
+      first connection in that queue becomes the new owner and is notified
+      accordingly.
+
+  __u64 kernel_flags;
+    Valid flags for this command, returned by the kernel upon each call.
+
+  struct kdbus_item items[0];
+    Items to submit the name. Currently, one item of type KDBUS_ITEM_NAME is
+    expected and allowed, and the contained string must be a valid bus name.
+};
+
+
+8.3 Releasing a name
+--------------------
+
+A connection may release a name explicitly with the KDBUS_CMD_NAME_RELEASE
+ioctl. If the connection was an implementor of an activatable name, its
+pending messages are moved back to the activator. If there are any connections
+queued up as waiters for the name, the oldest one of them will become the new
+owner. The same happens implicitly for all names once a connection terminates.
+
+The KDBUS_CMD_NAME_RELEASE ioctl uses the same data structure as the
+acquisition call, but with slightly different field usage.
+
+struct kdbus_cmd_name {
+  __u64 size;
+    The overall size of this struct, including the name with its 0-byte string
+    terminator.
+
+  __u64 flags;
+
+  struct kdbus_item items[0];
+    Items to submit the name. Currently, one item of type KDBUS_ITEM_NAME is
+    expected and allowed, and the contained string must be a valid bus name.
+};
+
+
+8.4 Dumping the name registry
+-----------------------------
+
+A connection may request a complete or filtered dump of currently active bus
+names with the KDBUS_CMD_NAME_LIST ioctl, which takes a struct
+kdbus_cmd_name_list as argument.
+
+struct kdbus_cmd_name_list {
+  __u64 flags;
+    Any combination of flags to specify which names should be dumped.
+
+    KDBUS_NAME_LIST_UNIQUE
+      List the unique (numeric) IDs of the connection, whether it owns a name
+      or not.
+
+    KDBUS_NAME_LIST_NAMES
+      List well-known names stored in the database which are actively owned by
+      a real connection (not an activator).
+
+    KDBUS_NAME_LIST_ACTIVATORS
+      List names that are owned by an activator.
+
+    KDBUS_NAME_LIST_QUEUED
+      List connections that are not yet owning a name but are waiting for it
+      to become available.
+
+  __u64 offset;
+    When the ioctl returns successfully, the offset to the name registry dump
+    inside the connection's pool will be stored in this field.
+};
+
+The returned list of names is stored in a struct kdbus_name_list that in turn
+contains a dynamic number of struct kdbus_cmd_name that carry the actual
+information. The fields inside that struct kdbus_cmd_name is described next.
+
+struct kdbus_name_info {
+  __u64 size;
+    The overall size of this struct, including the name with its 0-byte string
+    terminator.
+
+  __u64 owner_id;
+    The owning connection's unique ID.
+
+  __u64 conn_flags;
+    The flags of the owning connection.
+
+  struct kdbus_item items[0];
+    Items containing the actual name. Currently, one item of type
+    KDBUS_ITEM_OWNED_NAME will be attached, including the name's flags. In that
+    item, the flags field of the name may carry the following bits:
+
+    KDBUS_NAME_ALLOW_REPLACEMENT
+      Other connections are allowed to take over this name from the
+      connection that owns it.
+
+    KDBUS_NAME_IN_QUEUE (list)
+      When retrieving a list of currently acquired name in the registry, this
+      flag indicates whether the connection actually owns the name or is
+      currently waiting for it to become available.
+
+    KDBUS_NAME_ACTIVATOR (list)
+      An activator connection owns a name as a placeholder for an implementor,
+      which is started on demand as soon as the first message arrives. There's
+      some more information on this topic below. In contrast to
+      KDBUS_NAME_REPLACE_EXISTING, when a name is taken over from an activator
+      connection, all the messages that have been queued in the activator
+      connection will be moved over to the new owner. The activator connection
+      will still be tracked for the name and will take control again if the
+      implementor connection terminates.
+      This flag can not be used when acquiring a name, but is implicitly set
+      through KDBUS_CMD_HELLO with KDBUS_HELLO_ACTIVATOR set in
+      kdbus_cmd_hello.conn_flags.
+};
+
+The returned buffer must be freed with the KDBUS_CMD_FREE ioctl when the user
+is finished with it.
+
+
+9. Notifications
+===============================================================================
+
+The kernel will notify its users of the following events.
+
+  * When connection A is terminated while connection B is waiting for a reply
+    from it, connection B is notified with a message with an item of type
+    KDBUS_ITEM_REPLY_DEAD.
+
+  * When connection A does not receive a reply from connection B within the
+    specified timeout window, connection A will receive a message with an item
+    of type KDBUS_ITEM_REPLY_TIMEOUT.
+
+  * When a connection is created on or removed from a bus, messages with an
+    item of type KDBUS_ITEM_ID_ADD or KDBUS_ITEM_ID_REMOVE, respectively, are
+    sent to all bus members that match these messages through their match
+    database.
+
+  * When a connection owns or loses a name, or a name is moved from one
+    connection to another, messages with an item of type KDBUS_ITEM_NAME_ADD,
+    KDBUS_ITEM_NAME_REMOVE or KDBUS_ITEM_NAME_CHANGE are sent to all bus
+    members that match these messages through their match database.
+
+A kernel notification is a regular kdbus message with the following details.
+
+  * kdbus_msg.src_id == KDBUS_SRC_ID_KERNEL
+  * kdbus_msg.dst_id == KDBUS_DST_ID_BROADCAST
+  * kdbus_msg.payload_type == KDBUS_PAYLOAD_KERNEL
+  * Has exactly one of the aforementioned items attached
+
+
+10. Message Matching, Bloom filters
+===============================================================================
+
+10.1 Matches for broadcast messages from other connections
+----------------------------------------------------------
+
+A message addressed at the connection ID KDBUS_DST_ID_BROADCAST (~0ULL) is a
+broadcast message, delivered to all connected peers which installed a rule to
+match certain properties of the message. Without any rules installed in the
+connection, no broadcast message or kernel-side notifications will be delivered
+to the connection. Broadcast messages are subject to policy rules and TALK
+access checks.
+
+See section 11 for details on policies, and section 11.5 for more
+details on implicit policies.
+
+Matches for messages from other connections (not kernel notifications) are
+implemented as bloom filters. The sender adds certain properties of the message
+as elements to a bloom filter bit field, and sends that along with the
+broadcast message.
+
+The connection adds the message properties it is interested as elements to a
+bloom mask bit field, and uploads the mask to the match rules of the
+connection.
+
+The kernel will match the broadcast message's bloom filter against the
+connections bloom mask (simply by &-ing it), and decide whether the message
+should be delivered to the connection.
+
+The kernel has no notion of any specific properties of the message, all it
+sees are the bit fields of the bloom filter and mask to match against. The
+use of bloom filters allows simple and efficient matching, without exposing
+any message properties or internals to the kernel side. Clients need to deal
+with the fact that they might receive broadcasts which they did not subscribe
+to, as the bloom filter might allow false-positives to pass the filter.
+
+To allow the future extension of the set of elements in the bloom filter, the
+filter specifies a "generation" number. A later generation must always contain
+all elements of the set of the previous generation, but can add new elements
+to the set. The match rules mask can carry an array with all previous
+generations of masks individually stored. When the filter and mask are matched
+by the kernel, the mask with the closest matching "generation" is selected
+as the index into the mask array.
+
+
+10.2 Matches for kernel notifications
+------------------------------------
+
+To receive kernel generated notifications (see section 9), a connection must
+install special match rules that are different from the bloom filter matches
+described in the section above. They can be filtered by a sender connection's
+ID, by one of the name the sender connection owns at the time of sending the
+message, or by type of the notification (id/name add/remove/change).
+
+10.3 Adding a match
+-------------------
+
+To add a match, the KDBUS_CMD_MATCH_ADD ioctl is used, which takes a struct
+of the struct described below.
+
+Note that each of the items attached to this command will internally create
+one match 'rule', and the collection of them, which is submitted as one block
+via the ioctl is called a 'match'. To allow a message to pass, all rules of a
+match have to be satisfied. Hence, adding more items to the command will only
+narrow the possibility of a match to effectively let the message pass, and will
+cause the connection's user space process to wake up less likely.
+
+Multiple matches can be installed per connection. As long as one of it has a
+set of rules which allows the message to pass, this one will be decisive.
+
+struct kdbus_cmd_match {
+  __u64 size;
+    The overall size of the struct, including its items.
+
+  __u64 cookie;
+    A cookie which identifies the match, so it can be referred to at removal
+    time.
+
+  __u64 flags;
+    Flags to control the behavior of the ioctl.
+
+    KDBUS_MATCH_REPLACE:
+      Remove all entries with the given cookie before installing the new one.
+      This allows for race-free replacement of matches.
+
+  struct kdbus_item items[0];
+    Items to define the actual rules of the matches. The following item types
+    are expected. Each item will cause one new match rule to be created.
+
+    KDBUS_ITEM_BLOOM_MASK
+      An item that carries the bloom filter mask to match against in its
+      data field. The payload size must match the bloom filter size that
+      was specified when the bus was created.
+      See section 10.4 for more information.
+
+    KDBUS_ITEM_NAME
+      Specify a name that a sending connection must own at a time of sending
+      a broadcast message in order to match this rule.
+
+    KDBUS_ITEM_ID
+      Specify a sender connection's ID that will match this rule.
+
+    KDBUS_ITEM_NAME_ADD
+    KDBUS_ITEM_NAME_REMOVE
+    KDBUS_ITEM_NAME_CHANGE
+      These items request delivery of broadcast messages that describe a name
+      acquisition, loss, or change. The details are stored in the item's
+      kdbus_notify_name_change member. All information specified must be
+      matched in order to make the message pass. Use KDBUS_MATCH_ID_ANY to
+      match against any unique connection ID.
+
+    KDBUS_ITEM_ID_ADD
+    KDBUS_ITEM_ID_REMOVE
+      These items request delivery of broadcast messages that are generated
+      when a connection is created or terminated. struct kdbus_notify_id_change
+      is used to store the actual match information. This item can be used to
+      monitor one particular connection ID, or, when the id field is set to
+      KDBUS_MATCH_ID_ANY, all of them.
+
+    Other item types are ignored.
+};
+
+
+10.4 Bloom filters
+------------------
+
+Bloom filters allow checking whether a given word is present in a dictionary.
+This allows connections to set up a mask for information it is interested in,
+and will be delivered broadcast messages that have a matching filter.
+
+For general information on bloom filters, see
+
+  https://en.wikipedia.org/wiki/Bloom_filter
+
+The size of the bloom filter is defined per bus when it is created, in
+kdbus_bloom_parameter.size. All bloom filters attached to broadcast messages
+on the bus must match this size, and all bloom filter matches uploaded by
+connections must also match the size, or a multiple thereof (see below).
+
+The calculation of the mask has to be done on the userspace side. The kernel
+just checks the bitmasks to decide whether or not to let the message pass. All
+bits in the mask must match the filter in and bit-wise AND logic, but the
+mask may have more bits set than the filter. Consequently, false positive
+matches are expected to happen, and userspace must deal with that fact.
+
+Masks are entities that are always passed to the kernel as part of a match
+(with an item of type KDBUS_ITEM_BLOOM_MASK), and filters can be attached to
+broadcast messages (with an item of type KDBUS_ITEM_BLOOM_FILTER).
+
+For a broadcast to match, all set bits in the filter have to be set in the
+installed match mask as well. For example, consider a bus has a bloom size
+of 8 bytes, and the following mask/filter combinations:
+
+    filter  0x0101010101010101
+    mask    0x0101010101010101
+            -> matches
+
+    filter  0x0303030303030303
+    mask    0x0101010101010101
+            -> doesn't match
+
+    filter  0x0101010101010101
+    mask    0x0303030303030303
+            -> matches
+
+Hence, in order to catch all messages, a mask filled with 0xff bytes can be
+installed as a wildcard match rule.
+
+Uploaded matches may contain multiple masks, each of which in the size of the
+bloom size defined by the bus. Each block of a mask is called a 'generation',
+starting at index 0.
+
+At match time, when a broadcast message is about to be delivered, a bloom
+mask generation is passed, which denotes which of the bloom masks the filter
+should be matched against. This allows userspace to provide backward compatible
+masks at upload time, while older clients can still match against older
+versions of filters.
+
+
+10.5 Removing a match
+--------------------
+
+Matches can be removed through the KDBUS_CMD_MATCH_REMOVE ioctl, which again
+takes struct kdbus_cmd_match as argument, but its fields are used slightly
+differently.
+
+struct kdbus_cmd_match {
+  __u64 size;
+    The overall size of the struct. As it has no items in this use case, the
+    value should yield 16.
+
+  __u64 cookie;
+    The cookie of the match, as it was passed when the match was added.
+    All matches that have this cookie will be removed.
+
+  __u64 flags;
+    Unused for this use case,
+
+  __u64 kernel_flags;
+    Valid flags for this command, returned by the kernel upon each call.
+
+  struct kdbus_item items[0];
+    Unused for this use case.
+};
+
+
+11. Policy
+===============================================================================
+
+A policy databases restrict the possibilities of connections to own, see and
+talk to well-known names. It can be associated with a bus (through a policy
+holder connection) or a custom endpoint.
+
+See section 8.1 for more details on the validity of well-known names.
+
+Default endpoints of buses always have a policy database. The default
+policy is to deny all operations except for operations that are covered by
+implicit policies. Custom endpoints always have a policy, and by default,
+a policy database is empty. Therefore, unless policy rules are added, all
+operations will also be denied by default.
+
+See section 11.5 for more details on implicit policies.
+
+A set of policy rules is described by a name and multiple access rules, defined
+by the following struct.
+
+struct kdbus_policy_access {
+  __u64 type;	/* USER, GROUP, WORLD */
+    One of the following.
+
+    KDBUS_POLICY_ACCESS_USER
+      Grant access to a user with the uid stored in the 'id' field.
+
+    KDBUS_POLICY_ACCESS_GROUP
+      Grant access to a user with the gid stored in the 'id' field.
+
+    KDBUS_POLICY_ACCESS_WORLD
+      Grant access to everyone. The 'id' field is ignored.
+
+  __u64 access;	/* OWN, TALK, SEE */
+    The access to grant.
+
+    KDBUS_POLICY_SEE
+      Allow the name to be seen.
+
+    KDBUS_POLICY_TALK
+      Allow the name to be talked to.
+
+    KDBUS_POLICY_OWN
+      Allow the name to be owned.
+
+  __u64 id;
+    For KDBUS_POLICY_ACCESS_USER, stores the uid.
+    For KDBUS_POLICY_ACCESS_GROUP, stores the gid.
+};
+
+Policies are set through KDBUS_CMD_HELLO (when creating a policy holder
+connection), KDBUS_CMD_CONN_UPDATE (when updating a policy holder connection),
+KDBUS_CMD_ENDPOINT_MAKE (creating a custom endpoint) or
+KDBUS_CMD_ENDPOINT_UPDATE (updating a custom endpoint). In all cases, the name
+and policy access information is stored in items of type KDBUS_ITEM_NAME and
+KDBUS_ITEM_POLICY_ACCESS. For this transport, the following rules apply.
+
+  * An item of type KDBUS_ITEM_NAME must be followed by at least one
+    KDBUS_ITEM_POLICY_ACCESS item
+  * An item of type KDBUS_ITEM_NAME can be followed by an arbitrary number of
+    KDBUS_ITEM_POLICY_ACCESS items
+  * An arbitrary number of groups of names and access levels can be passed
+
+uids and gids are internally always stored in the kernel's view of global ids,
+and are translated back and forth on the ioctl level accordingly.
+
+
+11.2 Wildcard names
+-------------------
+
+Policy holder connections may upload names that contain the wildcard suffix
+(".*"). That way, a policy can be uploaded that is effective for every
+well-kwown name that extends the provided name by exactly one more level.
+
+For example, if an item of a set up uploaded policy rules contains the name
+"foo.bar.*", both "foo.bar.baz" and "foo.bar.bazbaz" are valid, but
+"foo.bar.baz.baz" is not.
+
+This allows connections to take control over multiple names that the policy
+holder doesn't need to know about when uploading the policy.
+
+Such wildcard entries are not allowed for custom endpoints.
+
+
+11.3 Policy example
+-------------------
+
+For example, a set of policy rules may look like this:
+
+  KDBUS_ITEM_NAME: str='org.foo.bar'
+  KDBUS_ITEM_POLICY_ACCESS: type=USER, access=OWN, id=1000
+  KDBUS_ITEM_POLICY_ACCESS: type=USER, access=TALK, id=1001
+  KDBUS_ITEM_POLICY_ACCESS: type=WORLD, access=SEE
+  KDBUS_ITEM_NAME: str='org.blah.baz'
+  KDBUS_ITEM_POLICY_ACCESS: type=USER, access=OWN, id=0
+  KDBUS_ITEM_POLICY_ACCESS: type=WORLD, access=TALK
+
+That means that 'org.foo.bar' may only be owned by uid 1000, but every user on
+the bus is allowed to see the name. However, only uid 1001 may actually send
+a message to the connection and receive a reply from it.
+
+The second rule allows 'org.blah.baz' to be owned by uid 0 only, but every user
+may talk to it.
+
+
+11.4 TALK access and multiple well-known names per connection
+-------------------------------------------------------------
+
+Note that TALK access is checked against all names of a connection.
+For example, if a connection owns both 'org.foo.bar' and 'org.blah.baz', and
+the policy database allows 'org.blah.baz' to be talked to by WORLD, then this
+permission is also granted to 'org.foo.bar'. That might sound illogical, but
+after all, we allow messages to be directed to either the name or a well-known
+name, and policy is applied to the connection, not the name. In other words,
+the effective TALK policy for a connection is the most permissive of all names
+the connection owns.
+
+If a policy database exists for a bus (because a policy holder created one on
+demand) or for a custom endpoint (which always has one), each one is consulted
+during name registry listing, name owning or message delivery. If either one
+fails, the operation is failed with -EPERM.
+
+For best practices, connections that own names with a restricted TALK
+access should not install matches. This avoids cases where the sent
+message may pass the bloom filter due to false-positives and may also
+satisfy the policy rules.
+
+
+11.5 Implicit policies
+----------------------
+
+Depending on the type of the endpoint, a set of implicit rules might be
+enforced. On default endpoints, the following set is enforced:
+
+  * Privileged connections always override any installed policy. Those
+    connections could easily install their own policies, so there is no
+    reason to enforce installed policies.
+  * Connections can always talk to connections of the same user. This
+    includes broadcast messages.
+  * Connections that own names might send broadcast messages to other
+    connections that belong to a different user, but only if that
+    destination connection does not own any name.
+
+Custom endpoints have stricter policies. The following rules apply:
+
+  * Policy rules are always enforced, even if the connection is a privileged
+    connection.
+  * Policy rules are always enforced for TALK access, even if both ends are
+    running under the same user. This includes broadcast messages.
+  * To restrict the set of names that can be seen, endpoint policies can
+    install "SEE" policies.
+
+
+12. Pool
+===============================================================================
+
+A pool for data received from the kernel is installed for every connection of
+the bus, and is sized according to kdbus_cmd_hello.pool_size. It is accessed
+when one of the following ioctls is issued:
+
+  * KDBUS_CMD_MSG_RECV, to receive a message
+  * KDBUS_CMD_NAME_LIST, to dump the name registry
+  * KDBUS_CMD_CONN_INFO, to retrieve information on a connection
+
+Internally, the pool is organized in slices, stored in an rb-tree. The offsets
+returned by either one of the aforementioned ioctls describe offsets inside the
+pool. In order to make the slice available for subsequent calls, KDBUS_CMD_FREE
+has to be called on the offset.
+
+To access the memory, the caller is expected to mmap() it to its task, like
+this:
+
+  /*
+   * POOL_SIZE has to be a multiple of PAGE_SIZE, and it must match the
+   * value that was previously passed in the .pool_size field of struct
+   * kdbus_cmd_hello.
+   */
+
+  buf = mmap(NULL, POOL_SIZE, PROT_READ, MAP_PRIVATE, conn_fd, 0);
+
+
+13. Metadata
+===============================================================================
+
+When a message is delivered to a receiver connection, it is augmented by
+metadata items in accordance to the destination's current attach flags. The
+information stored in those metadata items refer to the sender task at the
+time of sending the message, so even if any detail of the sender task has
+already changed upon message reception (or if the sender task does not exist
+anymore), the information is still preserved and won't be modfied until the
+message is freed.
+
+Note that there are two exceptions to the above rules:
+
+  a) Kernel generated messages don't have a source connection, so they won't be
+     augmented.
+
+  b) If a connection was created with faked credentials (see section 6.2),
+     the only attached metadata items are the ones provided by the connection
+     itself. Other bits in the destination's attach_flags_recv won't have any
+     effect in such cases.
+
+Also, there are two things to be considered by userspace programs regarding
+those metadata items:
+
+  a) Userspace must cope with the fact that it might get more metadata than
+     they requested. That happens, for example, when a broadcast message is
+     sent and receivers have different attach flags. Items that haven't been
+     requested should hence be silently ignored.
+
+  b) Userspace might not always get all requested metadata items that it
+     requested. That is because some of those items are only added if a
+     corresponding kernel feature has been enabled. Also, the two exceptions
+     described above will as well lead to less items be attached than
+     requested.
+
+
+13.1 Known item types
+---------------------
+
+The following attach flags are currently supported.
+
+  KDBUS_ATTACH_TIMESTAMP
+    Attaches an item of type KDBUS_ITEM_TIMESTAMP which contains both the
+    monotonic and the realtime timestamp, taken when the message was
+    processed on the kernel side.
+
+  KDBUS_ATTACH_CREDS
+    Attaches an item of type KDBUS_ITEM_CREDS, containing credentials as
+    described in kdbus_creds: the uid, gid, pid, tid and starttime of the task.
+
+  KDBUS_ATTACH_AUXGROUPS
+    Attaches an item of type KDBUS_ITEM_AUXGROUPS, containing a dynamic
+    number of auxiliary groups the sending task was a member of.
+
+  KDBUS_ATTACH_NAMES
+    Attaches items of type KDBUS_ITEM_OWNED_NAME, one for each name the sending
+    connection currently owns. The name and flags are stored in kdbus_item.name
+    for each of them.
+
+  KDBUS_ATTACH_TID_COMM
+    Attaches an items of type KDBUS_ITEM_TID_COMM, transporting the sending
+    task's 'comm', for the tid.  The string is stored in kdbus_item.str.
+
+  KDBUS_ATTACH_PID_COMM
+    Attaches an items of type KDBUS_ITEM_PID_COMM, transporting the sending
+    task's 'comm', for the pid.  The string is stored in kdbus_item.str.
+
+  KDBUS_ATTACH_EXE
+    Attaches an item of type KDBUS_ITEM_EXE, containing the path to the
+    executable of the sending task, stored in kdbus_item.str.
+
+  KDBUS_ATTACH_CMDLINE
+    Attaches an item of type KDBUS_ITEM_CMDLINE, containing the command line
+    arguments of the sending task, as an array of strings, stored in
+    kdbus_item.str.
+
+  KDBUS_ATTACH_CGROUP
+    Attaches an item of type KDBUS_ITEM_CGROUP with the task's cgroup path.
+
+  KDBUS_ATTACH_CAPS
+    Attaches an item of type KDBUS_ITEM_CAPS, carrying sets of capabilities
+    that should be accessed via kdbus_item.caps.caps. Also, userspace should
+    be written in a way that it takes kdbus_item.caps.last_cap into account,
+    and derive the number of sets and rows from the item size and the reported
+    number of valid capability bits.
+
+  KDBUS_ATTACH_SECLABEL
+    Attaches an item of type KDBUS_ITEM_SECLABEL, which contains the SELinux
+    security label of the sending task. Access via kdbus_item->str.
+
+  KDBUS_ATTACH_AUDIT
+    Attaches an item of type KDBUS_ITEM_AUDIT, which contains the audio label
+    of the sending taskj. Access via kdbus_item->str.
+
+  KDBUS_ATTACH_CONN_DESCRIPTION
+    Attaches an item of type KDBUS_ITEM_CONN_DESCRIPTION that contains the
+    sender connection's current name in kdbus_item.str.
+
+
+13.1 Metadata and namespaces
+----------------------------
+
+Metadata such as PIDs, UIDs or GIDs are automatically translated to the
+namespaces of the domain that is used to send a message over. The namespaces
+of a domain are pinned at creation time, which is when the filesystem has been
+mounted.
+
+Metadata items that cannot be translated are dropped.
+
+
+14. Error codes
+===============================================================================
+
+Below is a list of error codes that might be returned by the individual
+ioctl commands. The list focuses on the return values from kdbus code itself,
+and might not cover those of all kernel internal functions.
+
+For all ioctls:
+
+  -ENOMEM	The kernel memory is exhausted
+  -ENOTTY	Illegal ioctl command issued for the file descriptor
+  -ENOSYS	The requested functionality is not available
+
+For all ioctls that carry a struct as payload:
+
+  -EFAULT	The supplied data pointer was not 64-bit aligned, or was
+		inaccessible from the kernel side.
+  -EINVAL	The size inside the supplied struct was smaller than expected
+  -EMSGSIZE	The size inside the supplied struct was bigger than expected
+  -ENAMETOOLONG	A supplied name is larger than the allowed maximum size
+
+For KDBUS_CMD_BUS_MAKE:
+
+  -EINVAL	The flags supplied in the kdbus_cmd_make struct are invalid or
+		the supplied name does not start with the current uid and a '-'
+  -EEXIST	A bus of that name already exists
+  -ESHUTDOWN	The domain for the bus is already shut down
+  -EMFILE	The maximum number of buses for the current user is exhausted
+
+For KDBUS_CMD_ENDPOINT_MAKE:
+
+  -EPERM	The calling user is not privileged (see Terminology)
+  -EINVAL	The flags supplied in the kdbus_cmd_make struct are invalid
+  -EEXIST	An endpoint of that name already exists
+
+For KDBUS_CMD_HELLO:
+
+  -EFAULT	The supplied pool size was 0 or not a multiple of the page size
+  -EINVAL	The flags supplied in the kdbus_cmd_make struct are invalid, or
+		an illegal combination of KDBUS_HELLO_MONITOR,
+		KDBUS_HELLO_ACTIVATOR and KDBUS_HELLO_POLICY_HOLDER was passed
+		in the flags, or an invalid set of items was supplied
+  -ECONNREFUSED	The attach_flags_send field did not satisfy the requirements of
+		the bus
+  -EPERM	An KDBUS_ITEM_CREDS items was supplied, but the current user is
+		not privileged
+  -ESHUTDOWN	The bus has already been shut down
+  -EMFILE	The maximum number of connection on the bus has been reached
+
+For KDBUS_CMD_BYEBYE:
+
+  -EALREADY	The connection has already been shut down
+  -EBUSY	There are still messages queued up in the connection's pool
+
+For KDBUS_CMD_MSG_SEND:
+
+  -EOPNOTSUPP	The connection is not an ordinary connection, or the passed
+		file descriptors are either kdbus handles or unix domain
+		sockets. Both are currently unsupported
+  -EINVAL	The submitted payload type is KDBUS_PAYLOAD_KERNEL,
+		KDBUS_MSG_FLAGS_EXPECT_REPLY was set without a timeout value,
+		KDBUS_MSG_FLAGS_SYNC_REPLY was set without
+		KDBUS_MSG_FLAGS_EXPECT_REPLY, an invalid item was supplied,
+		src_id was != 0 and different from the current connection's ID,
+		a supplied memfd had a size of 0, a string was not properly
+		nul-terminated
+  -ENOTUNIQ	The supplied destination is KDBUS_DST_ID_BROADCAST, a file
+		descriptor was passed, KDBUS_MSG_FLAGS_EXPECT_REPLY was set,
+		or a timeout was given for a broadcast message
+  -E2BIG	Too many items
+  -EMSGSIZE	The size of the message header and items or the payload vector
+		is too big.
+  -EEXIST	Multiple KDBUS_ITEM_FDS, KDBUS_ITEM_BLOOM_FILTER or
+		KDBUS_ITEM_DST_NAME items were supplied
+  -EBADF	The supplied KDBUS_ITEM_FDS or KDBUS_MSG_PAYLOAD_MEMFD items
+		contained an illegal file descriptor
+  -EMEDIUMTYPE	The supplied memfd is not a sealed kdbus memfd
+  -EMFILE	Too many file descriptors inside a KDBUS_ITEM_FDS
+  -EBADMSG	An item had illegal size, both a dst_id and a
+		KDBUS_ITEM_DST_NAME was given, or both a name and a bloom
+		filter was given
+  -ETXTBSY	The supplied kdbus memfd file cannot be sealed or the seal
+		was removed, because it is shared with other processes or
+		still mmap()ed
+  -ECOMM	A peer does not accept the file descriptors addressed to it
+  -EFAULT	The supplied bloom filter size was not 64-bit aligned
+  -EDOM		The supplied bloom filter size did not match the bloom filter
+		size of the bus
+  -EDESTADDRREQ	dst_id was set to KDBUS_DST_ID_NAME, but no KDBUS_ITEM_DST_NAME
+		was attached
+  -ESRCH	The name to look up was not found in the name registry
+  -EADDRNOTAVAIL KDBUS_MSG_FLAGS_NO_AUTO_START was given but the destination
+		 connection is an activator.
+  -ENXIO	The passed numeric destination connection ID couldn't be found,
+		or is not connected
+  -ECONNRESET	The destination connection is no longer active
+  -ETIMEDOUT	Timeout while synchronously waiting for a reply
+  -EINTR	System call interrupted while synchronously waiting for a reply
+  -EPIPE	When sending a message, a synchronous reply from the receiving
+		connection was expected but the connection died before
+		answering
+  -ECANCELED	A synchronous message sending was cancelled
+  -ENOBUFS	Too many pending messages on the receiver side
+  -EREMCHG	Both a well-known name and a unique name (ID) was given, but
+		the name is not currently owned by that connection.
+  -EXFULL	The memory pool of the receiver is full
+  -EREMOTEIO	While synchronously waiting for a reply, the remote peer
+		failed with an I/O error.
+
+For KDBUS_CMD_MSG_RECV:
+
+  -EINVAL	Invalid flags or offset
+  -EAGAIN	No message found in the queue
+  -ENOMSG	No message of the requested priority found
+  -EOVERFLOW	Broadcast messages have been lost
+
+For KDBUS_CMD_MSG_CANCEL:
+
+  -EINVAL	Invalid flags
+  -ENOENT	Pending message with the supplied cookie not found
+
+For KDBUS_CMD_FREE:
+
+  -ENXIO	No pool slice found at given offset
+  -EINVAL	Invalid flags provided, the offset is valid, but the user is
+		not allowed to free the slice. This happens, for example, if
+		the offset was retrieved with KDBUS_RECV_PEEK.
+
+For KDBUS_CMD_NAME_ACQUIRE:
+
+  -EINVAL	Illegal command flags, illegal name provided, or an activator
+		tried to acquire a second name
+  -EPERM	Policy prohibited name ownership
+  -EALREADY	Connection already owns that name
+  -EEXIST	The name already exists and can not be taken over
+  -E2BIG	The maximum number of well-known names per connection
+		is exhausted
+  -ECONNRESET	The connection was reset during the call
+
+For KDBUS_CMD_NAME_RELEASE:
+
+  -EINVAL	Invalid command flags, or invalid name provided
+  -ESRCH	Name is not found found in the registry
+  -EADDRINUSE	Name is owned by a different connection and can't be released
+
+For KDBUS_CMD_NAME_LIST:
+
+  -EINVAL	Invalid flags
+  -ENOBUFS	No available memory in the connection's pool.
+
+For KDBUS_CMD_CONN_INFO:
+
+  -EINVAL	Invalid flags, or neither an ID nor a name was provided,
+		or the name is invalid.
+  -ESRCH	Connection lookup by name failed
+  -ENXIO	No connection with the provided number connection ID found
+
+For KDBUS_CMD_CONN_UPDATE:
+
+  -EINVAL	Illegal flags or items
+  -EOPNOTSUPP	Operation not supported by connection.
+  -E2BIG	Too many policy items attached
+  -EINVAL	Wildcards submitted in policy entries, or illegal sequence
+		of policy items
+
+For KDBUS_CMD_ENDPOINT_UPDATE:
+
+  -E2BIG	Too many policy items attached
+  -EINVAL	Invalid flags, or wildcards submitted in policy entries,
+		or illegal sequence of policy items
+
+For KDBUS_CMD_MATCH_ADD:
+
+  -EINVAL	Illegal flags or items
+  -EDOM		Illegal bloom filter size
+  -EMFILE	Too many matches for this connection
+
+For KDBUS_CMD_MATCH_REMOVE:
+
+  -EINVAL	Illegal flags
+  -ENOENT	A match entry with the given cookie could not be found.
+
+
+15. Internal object relations
+===============================================================================
+
+This is a simplified outline of the internal kdbus object relations, for
+those interested in the inner life of the driver implementation.
+
+From the a mount point's (domain's) perspective:
+
+struct kdbus_domain
+  |» struct kdbus_domain_user *user (many, owned)
+  '» struct kdbus_node node (embedded)
+      |» struct kdbus_node children (many, referenced)
+      |» struct kdbus_node *parent (pinned)
+      '» struct kdbus_bus (many, pinned)
+          |» struct kdbus_node node (embedded)
+          '» struct kdbus_ep (many, pinned)
+              |» struct kdbus_node node (embedded)
+              |» struct kdbus_bus *bus (pinned)
+              |» struct kdbus_conn conn_list (many, pinned)
+              |   |» struct kdbus_ep *ep (pinned)
+              |   |» struct kdbus_name_entry *activator_of (owned)
+              |   |» struct kdbus_match_db *match_db (owned)
+              |   |» struct kdbus_meta *meta (owned)
+              |   |» struct kdbus_match_db *match_db (owned)
+              |   |    '» struct kdbus_match_entry (many, owned)
+              |   |
+              |   |» struct kdbus_pool *pool (owned)
+              |   |    '» struct kdbus_pool_slice *slices (many, owned)
+              |   |       '» struct kdbus_pool *pool (pinned)
+              |   |
+              |   |» struct kdbus_domain_user *user (pinned)
+              |   `» struct kdbus_queue_entry entries (many, embedded)
+              |        |» struct kdbus_pool_slice *slice (pinned)
+              |        |» struct kdbus_conn_reply *reply (owned)
+              |        '» struct kdbus_domain_user *user (pinned)
+              |
+              '» struct kdbus_domain_user *user (pinned)
+                  '» struct kdbus_policy_db policy_db (embedded)
+                       |» struct kdbus_policy_db_entry (many, owned)
+                       |   |» struct kdbus_conn (pinned)
+                       |   '» struct kdbus_ep (pinned)
+                       |
+                       '» struct kdbus_policy_db_cache_entry (many, owned)
+                           '» struct kdbus_conn (pinned)
+
+
+For the life-time of a file descriptor derived from calling open() on a file
+inside the mount point:
+
+struct kdbus_handle
+  |» struct kdbus_meta *meta (owned)
+  |» struct kdbus_ep *ep (pinned)
+  |» struct kdbus_conn *conn (owned)
+  '» struct kdbus_ep *ep (owned)
Signature · 1 line
2.1.3
#2 lore raw

Re: kdbus: add documentation

Quoted 8 lines · Greg Kroah-Hartman

From: Daniel Mack <[email protected]>
…

+5.4 Creating buses and endpoints
+--------------------------------

Documentation/kdbus.txt new file +3 -0
+
+KDBUS_CMD_BUS_MAKE, and KDBUS_CMD_ENDPOINT_MAKE take a
+struct kdbus_cmd_make argument.

Documentation/kdbus.txt line 280

Quoted 10 lines
Documentation/kdbus.txt new file +10 -0
+
+struct kdbus_cmd_make {
+  __u64 size;
+    The overall size of the struct, including its items.
+
+  __u64 flags;
+    The flags for creation.
+
+    KDBUS_MAKE_ACCESS_GROUP
+      Make the device file group-accessible

device?

Documentation/kdbus.txt line 283

Quoted 3 lines
Documentation/kdbus.txt new file +3 -0
+
+    KDBUS_MAKE_ACCESS_WORLD
+      Make the device file world-accessible

device?

Quoted 9 lines
Documentation/kdbus.txt new file +8 -0
+
+  __u64 kernel_flags;
+    Valid flags for this command, returned by the kernel upon each call.
+
+  struct kdbus_item items[0];
+    A list of items, only used for creating custom endpoints. Has specific
+    meanings for KDBUS_CMD_BUS_MAKE and KDBUS_CMD_ENDPOINT_MAKE (see above).
+};
…
#3 lore raw

Re: kdbus: add documentation

In reply to Greg Kroah-Hartman
Quoted 15 lines · Greg Kroah-Hartman

From: Daniel Mack <[email protected]>

kdbus is a system for low-latency, low-overhead, easy to use interprocess communication (IPC).

The interface to all functions in this driver is implemented through ioctls on files exposed through the mount point of a kdbusfs. This patch adds detailed documentation about the kernel level API design.

---

Documentation/kdbus.txt line 63

Quoted 6 lines
Documentation/kdbus.txt new file +6 -0
+  Pool:
+    Each connection allocates a piece of shmem-backed memory that is used
+    to receive messages and answers to ioctl command from the kernel. It is
+    never used to send anything to the kernel. In order to access that memory,
+    userspace must mmap() it into its task.
+    See section 12 for more details.

At the risk of opening a can of worms, wouldn't this be much more useful if you could share a pool between multiple connections?

Quoted 15 lines
Documentation/kdbus.txt new file +15 -0
+
+
+4. Items
+===============================================================================
+
+To flexibly augment transport structures used by kdbus, data blobs of type
+struct kdbus_item are used. An item has a fixed-sized header that only stores
+the type of the item and the overall size. The total size is variable and is
+in some cases defined by the item type, in other cases, they can be of
+arbitrary length (for instance, a string).
+
+In the external kernel API, items are used for many ioctls to transport
+optional information from userspace to kernelspace. They are also used for
+information stored in a connection's pool, such as messages, name lists or
+requested connection information.

Documentation/kdbus.txt line 211

Quoted 10 lines
Documentation/kdbus.txt new file +10 -0
+
+In all such occasions where items are used as part of the kdbus kernel API,
+they are embedded in structs that have an overall size of their own, so there
+can be many of them.
+
+The kernel expects all items to be aligned to 8-byte boundaries.
+
+A simple iterator in userspace would iterate over the items until the items
+have reached the embedding structure's overall size. An example implementation
+of such an iterator can be found in tools/testing/selftests/kdbus/kdbus-util.h.

It looks like many (all?) item consumers ignore unknown items. This seems like a compatbility problem.

Would it be better to have a bit in each item that toggles between "ignore me if you don't recognize me" and "error out if you don't recognize me"?

Quoted 5 lines
Documentation/kdbus.txt new file +5 -0
+KDBUS_CMD_BUS_MAKE, and KDBUS_CMD_ENDPOINT_MAKE take a
+struct kdbus_cmd_make argument.
+
+struct kdbus_cmd_make {
+  __u64 size;

Documentation/kdbus.txt line 283

Quoted 10 lines
Documentation/kdbus.txt new file +10 -0
+    The overall size of the struct, including its items.
+
+  __u64 flags;
+    The flags for creation.
+
+    KDBUS_MAKE_ACCESS_GROUP
+      Make the device file group-accessible
+
+    KDBUS_MAKE_ACCESS_WORLD
+      Make the device file world-accessible

This thing is a file. What's wrong with using a normal POSIX mode? (And what to the read, write, and exec modes do?)

Quoted 87 lines
Documentation/kdbus.txt new file +87 -0
+
+
+6.2 Creating connections
+------------------------
+
+A connection to a bus is created by opening an endpoint file of a bus and
+becoming an active client with the KDBUS_CMD_HELLO ioctl. Every connected client
+connection has a unique identifier on the bus and can address messages to every
+other connection on the same bus by using the peer's connection id as the
+destination.
+
+The KDBUS_CMD_HELLO ioctl takes the following struct as argument.
+
+struct kdbus_cmd_hello {
+  __u64 size;
+    The overall size of the struct, including all attached items.
+
+  __u64 conn_flags;
+    Flags to apply to this connection:
+
+    KDBUS_HELLO_ACCEPT_FD
+      When this flag is set, the connection can be sent file descriptors
+      as message payload. If it's not set, any attempt of doing so will
+      result in -ECOMM on the sender's side.
+
+    KDBUS_HELLO_ACTIVATOR
+      Make this connection an activator (see below). With this bit set,
+      an item of type KDBUS_ITEM_NAME has to be attached which describes
+      the well-known name this connection should be an activator for.
+
+    KDBUS_HELLO_POLICY_HOLDER
+      Make this connection a policy holder (see below). With this bit set,
+      an item of type KDBUS_ITEM_NAME has to be attached which describes
+      the well-known name this connection should hold a policy for.
+
+    KDBUS_HELLO_MONITOR
+      Make this connection an eaves-dropping connection that receives all
+      unicast messages sent on the bus. To also receive broadcast messages,
+      the connection has to upload appropriate matches as well.
+      This flag is only valid for privileged bus connections.
+
+  __u64 attach_flags_send;
+      Set the bits for metadata this connection permits to be sent to the
+      receiving peer. Only metadata items that are both allowed to be sent by
+      the sender and that are requested by the receiver will effectively be
+      attached to the message eventually. Note, however, that the bus may
+      optionally enforce some of those bits to be set. If the match fails,
+      -ECONNREFUSED will be returned. In either case, this field will be set
+      to the mask of metadata items that are enforced by the bus. The
+      KDBUS_FLAGS_KERNEL bit will as well be set.
+
+  __u64 attach_flags_recv;
+      Request the attachment of metadata for each message received by this
+      connection. The metadata actually attached may actually augment the list
+      of requested items. See section 13 for more details.
+
+  __u64 bus_flags;
+      Upon successful completion of the ioctl, this member will contain the
+      flags of the bus it connected to.
+
+  __u64 id;
+      Upon successful completion of the ioctl, this member will contain the
+      id of the new connection.
+
+  __u64 pool_size;
+      The size of the communication pool, in bytes. The pool can be accessed
+      by calling mmap() on the file descriptor that was used to issue the
+      KDBUS_CMD_HELLO ioctl.
+
+  struct kdbus_bloom_parameter bloom;
+      Bloom filter parameter (see below).
+
+  __u8 id128[16];
+      Upon successful completion of the ioctl, this member will contain the
+      128 bit wide UUID of the connected bus.
+
+  struct kdbus_item items[0];
+      Variable list of items to add optional additional information. The
+      following items are currently expected/valid:
+
+      KDBUS_ITEM_CONN_DESCRIPTION
+        Contains a string to describes this connection's name, so it can be
+        identified later.
+
+      KDBUS_ITEM_NAME
+      KDBUS_ITEM_POLICY_ACCESS
+        For activators and policy holders only, combinations of these two

Documentation/kdbus.txt line 469

Quoted 10 lines
Documentation/kdbus.txt new file +10 -0
+        items describe policy access entries (see section about policy).
+
+      KDBUS_ITEM_CREDS
+      KDBUS_ITEM_SECLABEL
+        Privileged bus users may submit these types in order to create
+        connections with faked credentials. The only real use case for this
+        is a proxy service which acts on behalf of some other tasks. For a
+        connection that runs in that mode, the message's metadata items will
+        be limited to what's specified here. See section 13 for more
+        information.

This is still confusing. There are multiple places in which metadata is attached. Which does this apply to? And why are only creds and seclabel listed?

Quoted 62 lines
Documentation/kdbus.txt new file +62 -0
+
+6.4 Retrieving information on a connection
+------------------------------------------
+
+The KDBUS_CMD_CONN_INFO ioctl can be used to retrieve credentials and
+properties of the initial creator of a connection. This ioctl uses the
+following struct:
+
+struct kdbus_cmd_info {
+  __u64 size;
+    The overall size of the struct, including the name with its 0-byte string
+    terminator.
+
+  __u64 flags;
+    Specify which metadata items should be attached to the answer.
+    See section 13 for more details.
+
+    After the ioctl returns, this field will contain the current metadata
+    attach flags of the connection.
+
+  __u64 kernel_flags;
+    Valid flags for this command, returned by the kernel upon each call.
+
+  __u64 id;
+    The connection's numerical ID to retrieve information for. If set to
+    non-zero value, the 'name' field is ignored.
+
+  __u64 offset;
+    When the ioctl returns, this value will yield the offset of the connection
+    information inside the caller's pool.
+
+  struct kdbus_item items[0];
+    The optional item list, containing the well-known name to look up as
+    a KDBUS_ITEM_OWNED_NAME. Only required if the 'id' field is set to 0.
+    All other items are currently ignored.
+};
+
+After the ioctl returns, the following struct will be stored in the caller's
+pool at 'offset'.
+
+struct kdbus_info {
+  __u64 size;
+    The overall size of the struct, including all its items.
+
+  __u64 id;
+    The connection's unique ID.
+
+  __u64 flags;
+    The connection's flags as specified when it was created.
+
+  __u64 kernel_flags;
+    Valid flags for this command, returned by the kernel upon each call.
+
+  struct kdbus_item items[0];
+    Depending on the 'flags' field in struct kdbus_cmd_info, items of
+    types KDBUS_ITEM_OWNED_NAME and KDBUS_ITEM_CONN_DESCRIPTION are followed
+    here.
+};
+
+Once the caller is finished with parsing the return buffer, it needs to call
+KDBUS_CMD_FREE for the offset.
+

Documentation/kdbus.txt line 563

Quoted 10 lines
Documentation/kdbus.txt new file +10 -0
+
+6.5 Getting information about a connection's bus creator
+--------------------------------------------------------
+
+The KDBUS_CMD_BUS_CREATOR_INFO ioctl takes the same struct as
+KDBUS_CMD_CONN_INFO but is used to retrieve information about the creator of
+the bus the connection is attached to. The metadata returned by this call is
+collected during the creation of the bus and is never altered afterwards, so
+it provides pristine information on the task that created the bus, at the
+moment when it did so.

What's this for? I understand the need for the creator of busses to be authenticated, but doing it like this mean that anyone who will *fail* authentication can DoS the authentic creator.

Quoted 11 lines
Documentation/kdbus.txt new file +11 -0
+
+7.3 Passing of Payload Data
+---------------------------
+
+When connecting to the bus, receivers request a memory pool of a given size,
+large enough to carry all backlog of data enqueued for the connection. The
+pool is internally backed by a shared memory file which can be mmap()ed by
+the receiver.
+
+KDBUS_MSG_PAYLOAD_VEC:
+  Messages are directly copied by the sending process into the receiver's pool,

Documentation/kdbus.txt line 833

Quoted 10 lines
Documentation/kdbus.txt new file +10 -0
+  that way two peers can exchange data by effectively doing a single-copy from
+  one process to another, the kernel will not buffer the data anywhere else.
+
+KDBUS_MSG_PAYLOAD_MEMFD:
+  Messages can reference memfd files which contain the data.
+  memfd files are tmpfs-backed files that allow sealing of the content of the
+  file, which prevents all writable access to the file content.
+  Only sealed memfd files are accepted as payload data, which enforces
+  reliable passing of data; the receiver can assume that neither the sender nor
+  anyone else can alter the content after the message is sent.

This should specify *which* seals are checked.

Quoted 38 lines
Documentation/kdbus.txt new file +38 -0
+
+Apart from the sender filling-in the content into memfd files, the data will
+be passed as zero-copy from one process to another, read-only, shared between
+the peers.
+
+
+7.4 Receiving messages
+----------------------
+
+Messages are received by the client with the KDBUS_CMD_MSG_RECV ioctl. The
+endpoint file of the bus supports poll() to wake up the receiving process when
+new messages are queued up to be received.
+
+With the KDBUS_CMD_MSG_RECV ioctl, a struct kdbus_cmd_recv is used.
+
+struct kdbus_cmd_recv {
+  __u64 flags;
+    Flags to control the receive command.
+
+    KDBUS_RECV_PEEK
+      Just return the location of the next message. Do not install file
+      descriptors or anything else. This is usually used to determine the
+      sender of the next queued message.
+
+    KDBUS_RECV_DROP
+      Drop the next message without doing anything else with it, and free the
+      pool slice. This a short-cut for KDBUS_RECV_PEEK and KDBUS_CMD_FREE.
+
+    KDBUS_RECV_USE_PRIORITY
+      Use the priority field (see below).
+
+  __u64 kernel_flags;
+    Valid flags for this command, returned by the kernel upon each call.
+
+  __s64 priority;
+      With KDBUS_RECV_USE_PRIORITY set in flags, receive the next message in
+      the queue with at least the given priority. If no such message is waiting
+      in the queue, -ENOMSG is returned.

Documentation/kdbus.txt line 881

Quoted 10 lines
Documentation/kdbus.txt new file +10 -0
+
+  __u64 offset;
+      Upon return of the ioctl, this field contains the offset in the
+      receiver's memory pool.
+};
+
+Unless KDBUS_RECV_DROP was passed, and given that the ioctl succeeded, the
+offset field contains the location of the new message inside the receiver's
+pool. The message is stored as struct kdbus_msg at this offset, and can be
+interpreted with the semantics described above.

I'm confused here. Is sent data written to the pool when send is called or when recv is called?

If the former, what prevents DoS, especially DoS due to sending too many fds?

If the latter, where is the data buffered in the mean time?

Documentation/kdbus.txt line 886

Quoted 5 lines
Documentation/kdbus.txt new file +5 -0
+
+Also, if the connection allowed for file descriptor to be passed
+(KDBUS_HELLO_ACCEPT_FD), and if the message contained any, they will be
+installed into the receiving process after the KDBUS_CMD_MSG_RECV ioctl
+returns. The receiving task is obliged to close all of them appropriately.

This makes it sound like fds are installed at receive time. What prevents resource exhaustion due to having excessive numbers of fds in transit (that are presumably not accounted to anyone)?

Documentation/kdbus.txt line 900

Quoted 10 lines
Documentation/kdbus.txt new file +10 -0
+
+7.5 Canceling messages synchronously waiting for replies
+--------------------------------------------------------
+
+When a connection sends a message with KDBUS_MSG_FLAGS_SYNC_REPLY and
+blocks while waiting for the reply, the KDBUS_CMD_MSG_CANCEL ioctl can be
+used on the same file descriptor to cancel the message, based on its cookie.
+If there are multiple messages with the same cookie that are all synchronously
+waiting for a reply, all of them will be canceled. Obviously, this is only
+possible in multi-threaded applications.

What does "cancel the message" mean? Does it just mean that the wait for the reply is cancelled?

Documentation/kdbus.txt line 1315

Quoted 6 lines

+11. Policy
+===============================================================================

Documentation/kdbus.txt new file +4 -0
+
+A policy databases restrict the possibilities of connections to own, see and
+talk to well-known names. It can be associated with a bus (through a policy
+holder connection) or a custom endpoint.

ISTM metadata items on bus names should be replaced with policy that applies to the domain as a whole and governs bus creation.

Quoted 22 lines
Documentation/kdbus.txt new file +22 -0
+A set of policy rules is described by a name and multiple access rules, defined
+by the following struct.
+
+struct kdbus_policy_access {
+  __u64 type;  /* USER, GROUP, WORLD */
+    One of the following.
+
+    KDBUS_POLICY_ACCESS_USER
+      Grant access to a user with the uid stored in the 'id' field.
+
+    KDBUS_POLICY_ACCESS_GROUP
+      Grant access to a user with the gid stored in the 'id' field.
+
+    KDBUS_POLICY_ACCESS_WORLD
+      Grant access to everyone. The 'id' field is ignored.
+
+  __u64 access;        /* OWN, TALK, SEE */
+    The access to grant.
+
+    KDBUS_POLICY_SEE
+      Allow the name to be seen.
+

Documentation/kdbus.txt line 1358

Quoted 10 lines
Documentation/kdbus.txt new file +10 -0
+    KDBUS_POLICY_TALK
+      Allow the name to be talked to.
+
+    KDBUS_POLICY_OWN
+      Allow the name to be owned.
+
+  __u64 id;
+    For KDBUS_POLICY_ACCESS_USER, stores the uid.
+    For KDBUS_POLICY_ACCESS_GROUP, stores the gid.
+};

What happens if there are multiple matches?

Documentation/kdbus.txt line 1425

Quoted 12 lines
Documentation/kdbus.txt new file +12 -0
+
+11.4 TALK access and multiple well-known names per connection
+-------------------------------------------------------------
+
+Note that TALK access is checked against all names of a connection.
+For example, if a connection owns both 'org.foo.bar' and 'org.blah.baz', and
+the policy database allows 'org.blah.baz' to be talked to by WORLD, then this
+permission is also granted to 'org.foo.bar'. That might sound illogical, but
+after all, we allow messages to be directed to either the name or a well-known
+name, and policy is applied to the connection, not the name. In other words,
+the effective TALK policy for a connection is the most permissive of all names
+the connection owns.

This does seem illogical. Does the recipient at least know which well-known name was addressed?

Documentation/kdbus.txt line 1443

Quoted 6 lines

+11.5 Implicit policies
+----------------------

Documentation/kdbus.txt new file +4 -0
+
+Depending on the type of the endpoint, a set of implicit rules might be
+enforced. On default endpoints, the following set is enforced:
+

How do these rules interact with installed policy?

Documentation/kdbus.txt line 1448

Quoted 5 lines
Documentation/kdbus.txt new file +5 -0
+  * Privileged connections always override any installed policy. Those
+    connections could easily install their own policies, so there is no
+    reason to enforce installed policies.
+  * Connections can always talk to connections of the same user. This
+    includes broadcast messages.

Why? If anyone ever strengthens the concept of identity to include things other than users (hmm -- there are already groups), this could be very limiting.

Documentation/kdbus.txt line 1452

Quoted 4 lines
Documentation/kdbus.txt new file +4 -0
+  * Connections that own names might send broadcast messages to other
+    connections that belong to a different user, but only if that
+    destination connection does not own any name.
+

This is weird. It is also differently illogical than the "illogical" thing above.

How about restricting access per name and making sure that the receivers check what name was addressed before taking any action?

Quoted 5 lines

+12. Pool
+===============================================================================

Documentation/kdbus.txt new file +3 -0
+
+A pool for data received from the kernel is installed for every connection of
+the bus, and is sized according to kdbus_cmd_hello.pool_size. It is accessed

Documentation/kdbus.txt line 1477

Quoted 10 lines
Documentation/kdbus.txt new file +10 -0
+when one of the following ioctls is issued:
+
+  * KDBUS_CMD_MSG_RECV, to receive a message
+  * KDBUS_CMD_NAME_LIST, to dump the name registry
+  * KDBUS_CMD_CONN_INFO, to retrieve information on a connection
+
+Internally, the pool is organized in slices, stored in an rb-tree. The offsets
+returned by either one of the aforementioned ioctls describe offsets inside the
+pool. In order to make the slice available for subsequent calls, KDBUS_CMD_FREE
+has to be called on the offset.

Why are you documenting that the slices are stored in an rb-tree? That's just an implementation details, right?

Documentation/kdbus.txt line 1489

Quoted 12 lines
Documentation/kdbus.txt new file +12 -0
+
+To access the memory, the caller is expected to mmap() it to its task, like
+this:
+
+  /*
+   * POOL_SIZE has to be a multiple of PAGE_SIZE, and it must match the
+   * value that was previously passed in the .pool_size field of struct
+   * kdbus_cmd_hello.
+   */
+
+  buf = mmap(NULL, POOL_SIZE, PROT_READ, MAP_PRIVATE, conn_fd, 0);
+

Will mapping with PROT_WRITE fail? What about MAP_SHARED?

And why are you suggesting MAP_PRIVATE? That's just strange.

Quoted 41 lines
Documentation/kdbus.txt new file +41 -0
+
+13. Metadata
+===============================================================================
+
+When a message is delivered to a receiver connection, it is augmented by
+metadata items in accordance to the destination's current attach flags. The
+information stored in those metadata items refer to the sender task at the
+time of sending the message, so even if any detail of the sender task has
+already changed upon message reception (or if the sender task does not exist
+anymore), the information is still preserved and won't be modfied until the
+message is freed.
+
+Note that there are two exceptions to the above rules:
+
+  a) Kernel generated messages don't have a source connection, so they won't be
+     augmented.
+
+  b) If a connection was created with faked credentials (see section 6.2),
+     the only attached metadata items are the ones provided by the connection
+     itself. Other bits in the destination's attach_flags_recv won't have any
+     effect in such cases.
+
+Also, there are two things to be considered by userspace programs regarding
+those metadata items:
+
+  a) Userspace must cope with the fact that it might get more metadata than
+     they requested. That happens, for example, when a broadcast message is
+     sent and receivers have different attach flags. Items that haven't been
+     requested should hence be silently ignored.
+
+  b) Userspace might not always get all requested metadata items that it
+     requested. That is because some of those items are only added if a
+     corresponding kernel feature has been enabled. Also, the two exceptions
+     described above will as well lead to less items be attached than
+     requested.
+
+
+13.1 Known item types
+---------------------
+
+The following attach flags are currently supported.

Documentation/kdbus.txt line 1540

Quoted 10 lines
Documentation/kdbus.txt new file +10 -0
+
+  KDBUS_ATTACH_TIMESTAMP
+    Attaches an item of type KDBUS_ITEM_TIMESTAMP which contains both the
+    monotonic and the realtime timestamp, taken when the message was
+    processed on the kernel side.
+
+  KDBUS_ATTACH_CREDS
+    Attaches an item of type KDBUS_ITEM_CREDS, containing credentials as
+    described in kdbus_creds: the uid, gid, pid, tid and starttime of the task.
+

As mentioned last time, please remove or justify starttime.

Documentation/kdbus.txt line 1549

Quoted 9 lines
Documentation/kdbus.txt new file +9 -0
+  KDBUS_ATTACH_AUXGROUPS
+    Attaches an item of type KDBUS_ITEM_AUXGROUPS, containing a dynamic
+    number of auxiliary groups the sending task was a member of.
+
+  KDBUS_ATTACH_NAMES
+    Attaches items of type KDBUS_ITEM_OWNED_NAME, one for each name the sending
+    connection currently owns. The name and flags are stored in kdbus_item.name
+    for each of them.
+

That's interesting. What's it for?

Quoted 6 lines
Documentation/kdbus.txt new file +6 -0
+  KDBUS_ATTACH_TID_COMM
+    Attaches an items of type KDBUS_ITEM_TID_COMM, transporting the sending
+    task's 'comm', for the tid.  The string is stored in kdbus_item.str.
+
+  KDBUS_ATTACH_PID_COMM
+    Attaches an items of type KDBUS_ITEM_PID_COMM, transporting the sending

Documentation/kdbus.txt line 1565

Quoted 10 lines
Documentation/kdbus.txt new file +10 -0
+    task's 'comm', for the pid.  The string is stored in kdbus_item.str.
+
+  KDBUS_ATTACH_EXE
+    Attaches an item of type KDBUS_ITEM_EXE, containing the path to the
+    executable of the sending task, stored in kdbus_item.str.
+
+  KDBUS_ATTACH_CMDLINE
+    Attaches an item of type KDBUS_ITEM_CMDLINE, containing the command line
+    arguments of the sending task, as an array of strings, stored in
+    kdbus_item.str.

Please remove these four items. They are genuinely useless. Anything that uses them for anything is either buggy or should have asked the sender to put the value in the payload (and immediately wondered why it was doing that).

Documentation/kdbus.txt line 1576

Quoted 11 lines
Documentation/kdbus.txt new file +11 -0
+
+  KDBUS_ATTACH_CGROUP
+    Attaches an item of type KDBUS_ITEM_CGROUP with the task's cgroup path.
+
+  KDBUS_ATTACH_CAPS
+    Attaches an item of type KDBUS_ITEM_CAPS, carrying sets of capabilities
+    that should be accessed via kdbus_item.caps.caps. Also, userspace should
+    be written in a way that it takes kdbus_item.caps.last_cap into account,
+    and derive the number of sets and rows from the item size and the reported
+    number of valid capability bits.
+

Please remove this, too, or justify its use.

Documentation/kdbus.txt line 1580

Quoted 4 lines
Documentation/kdbus.txt new file +4 -0
+  KDBUS_ATTACH_SECLABEL
+    Attaches an item of type KDBUS_ITEM_SECLABEL, which contains the SELinux
+    security label of the sending task. Access via kdbus_item->str.
+

This one, too, and please justify why code that uses it will work in containers an on non-selinux systems.

Documentation/kdbus.txt line 1584

Quoted 4 lines
Documentation/kdbus.txt new file +4 -0
+  KDBUS_ATTACH_AUDIT
+    Attaches an item of type KDBUS_ITEM_AUDIT, which contains the audio label
+    of the sending taskj. Access via kdbus_item->str.
+

I will NAK the hell out of this until, at the very least, someone documents what this means, how to parse it, what its stability rules are, who is allowed to see the value it contains, why that value will never evolve to become *more* security sensitive than it is now, etc.

Audit gets to do crazy sh*t because it's restricted to privileged receivers. This isn't restricted like that, so it doesn't deserve the same dispensation. (And, honestly, I'm not sure that audit really deserves its free pass on making sense.)

Documentation/kdbus.txt line 1588

Quoted 4 lines
Documentation/kdbus.txt new file +4 -0
+  KDBUS_ATTACH_CONN_DESCRIPTION
+    Attaches an item of type KDBUS_ITEM_CONN_DESCRIPTION that contains the
+    sender connection's current name in kdbus_item.str.
+

Which name? Can't there be several?

Documentation/kdbus.txt line 1598

Quoted 10 lines
Documentation/kdbus.txt new file +10 -0
+
+13.1 Metadata and namespaces
+----------------------------
+
+Metadata such as PIDs, UIDs or GIDs are automatically translated to the
+namespaces of the domain that is used to send a message over. The namespaces
+of a domain are pinned at creation time, which is when the filesystem has been
+mounted.
+
+Metadata items that cannot be translated are dropped.

What if the receiver said that the item was mandatory?

Thanks,
Andy

#4 lore raw

Re: kdbus: add documentation

Hi Andy!

Quoted 24 lines · Andy Lutomirski
Quoted 15 lines · Greg Kroah-Hartman

From: Daniel Mack <[email protected]>

kdbus is a system for low-latency, low-overhead, easy to use interprocess communication (IPC).

The interface to all functions in this driver is implemented through ioctls on files exposed through the mount point of a kdbusfs. This patch adds detailed documentation about the kernel level API design.

---

Documentation/kdbus.txt line 63

Quoted 6 lines
Documentation/kdbus.txt new file +6 -0
+  Pool:
+    Each connection allocates a piece of shmem-backed memory that is used
+    to receive messages and answers to ioctl command from the kernel. It is
+    never used to send anything to the kernel. In order to access that memory,
+    userspace must mmap() it into its task.
+    See section 12 for more details.
Quoted 2 lines

At the risk of opening a can of worms, wouldn't this be much more useful if you could share a pool between multiple connections?

Within a process it could theoretically be possible to share the same memory pool between multiple connections made by the process. However, note that normally a process only has a single connection to the bus open (possibly two, if it opens a connection to both the system and the user bus). Now, sharing the receiver buffer could certainly be considered an optimization, but it would have no effect on "usefulness", though, as just allocating space from a single shared per-process receiver won't give you any new possibilities...

We have thought about this, but decided to delay it for now. Shared pools can easily be added as an extension later on.

[snip]

Quoted 10 lines
Quoted 10 lines
Documentation/kdbus.txt new file +10 -0
+KDBUS_CMD_BUS_MAKE, and KDBUS_CMD_ENDPOINT_MAKE take a
+struct kdbus_cmd_make argument.
+
+struct kdbus_cmd_make {
+  __u64 size;
+    The overall size of the struct, including its items.
+
+  __u64 flags;
+    The flags for creation.
+
Quoted 8 lines

Documentation/kdbus.txt line 283

Quoted 5 lines
Documentation/kdbus.txt new file +5 -0
+    KDBUS_MAKE_ACCESS_GROUP
+      Make the device file group-accessible
+
+    KDBUS_MAKE_ACCESS_WORLD
+      Make the device file world-accessible

This thing is a file. What's wrong with using a normal POSIX mode? (And what to the read, write, and exec modes do?)

Domains and buses are directories, endpoints are files. Domains also create control-files implicitly.

For kdbus clients there is just access or no access, but not distinction between read, write and execute access. Due to that we just break this down to per-group and world access bits, since doing more is pointless, and we shouldn't allow shoehorning more stuff into the access mode.

[snip]

Quoted 9 lines

Documentation/kdbus.txt line 469

Quoted 8 lines
Documentation/kdbus.txt new file +8 -0
+      KDBUS_ITEM_CREDS
+      KDBUS_ITEM_SECLABEL
+        Privileged bus users may submit these types in order to create
+        connections with faked credentials. The only real use case for this
+        is a proxy service which acts on behalf of some other tasks. For a
+        connection that runs in that mode, the message's metadata items will
+        be limited to what's specified here. See section 13 for more
+        information.
Quoted 3 lines

This is still confusing. There are multiple places in which metadata is attached. Which does this apply to? And why are only creds and seclabel listed?

Yes, and there are multiple places where metadata is *gathered*. This ioctl creates connections, so only the items that are actually *gathered* by that ioctl are documented here. These items are not part of any messages, but are used as identification of the connection owner (and in this particular case, to allow privileged proxies to overwrite the items so they can properly proxy a legacy-dbus peer connection).

[snip]

Quoted 5 lines
Quoted 5 lines

+6.5 Getting information about a connection's bus creator
+--------------------------------------------------------

Documentation/kdbus.txt new file +3 -0
+
+The KDBUS_CMD_BUS_CREATOR_INFO ioctl takes the same struct as
+KDBUS_CMD_CONN_INFO but is used to retrieve information about the creator of
Quoted 8 lines

Documentation/kdbus.txt line 563

Quoted 4 lines
Documentation/kdbus.txt new file +4 -0
+the bus the connection is attached to. The metadata returned by this call is
+collected during the creation of the bus and is never altered afterwards, so
+it provides pristine information on the task that created the bus, at the
+moment when it did so.

What's this for? I understand the need for the creator of busses to be authenticated, but doing it like this mean that anyone who will *fail* authentication can DoS the authentic creator.

This returns information on a bus owner, to determine whether a connection is connected to a system, user or session bus. Note that the bus-creator itself is not a valid peer on the bus, so you cannot send messages to them. Which kind of DoS do you have in mind?

Quoted 15 lines
Quoted 15 lines
Documentation/kdbus.txt new file +15 -0
+
+7.3 Passing of Payload Data
+---------------------------
+
+When connecting to the bus, receivers request a memory pool of a given size,
+large enough to carry all backlog of data enqueued for the connection. The
+pool is internally backed by a shared memory file which can be mmap()ed by
+the receiver.
+
+KDBUS_MSG_PAYLOAD_VEC:
+  Messages are directly copied by the sending process into the receiver's pool,
+  that way two peers can exchange data by effectively doing a single-copy from
+  one process to another, the kernel will not buffer the data anywhere else.
+
+KDBUS_MSG_PAYLOAD_MEMFD:
Quoted 8 lines

Documentation/kdbus.txt line 833

Quoted 6 lines
Documentation/kdbus.txt new file +6 -0
+  Messages can reference memfd files which contain the data.
+  memfd files are tmpfs-backed files that allow sealing of the content of the
+  file, which prevents all writable access to the file content.
+  Only sealed memfd files are accepted as payload data, which enforces
+  reliable passing of data; the receiver can assume that neither the sender nor
+  anyone else can alter the content after the message is sent.

This should specify *which* seals are checked.

True. Will be added to the documentation. For the record, it's the full set of seals right now, so F_SEAL_SHRINK|F_SEAL_GROW|F_SEAL_WRITE|F_SEAL_SEAL.

Quoted 43 lines
Quoted 43 lines
Documentation/kdbus.txt new file +43 -0
+
+Apart from the sender filling-in the content into memfd files, the data will
+be passed as zero-copy from one process to another, read-only, shared between
+the peers.
+
+
+7.4 Receiving messages
+----------------------
+
+Messages are received by the client with the KDBUS_CMD_MSG_RECV ioctl. The
+endpoint file of the bus supports poll() to wake up the receiving process when
+new messages are queued up to be received.
+
+With the KDBUS_CMD_MSG_RECV ioctl, a struct kdbus_cmd_recv is used.
+
+struct kdbus_cmd_recv {
+  __u64 flags;
+    Flags to control the receive command.
+
+    KDBUS_RECV_PEEK
+      Just return the location of the next message. Do not install file
+      descriptors or anything else. This is usually used to determine the
+      sender of the next queued message.
+
+    KDBUS_RECV_DROP
+      Drop the next message without doing anything else with it, and free the
+      pool slice. This a short-cut for KDBUS_RECV_PEEK and KDBUS_CMD_FREE.
+
+    KDBUS_RECV_USE_PRIORITY
+      Use the priority field (see below).
+
+  __u64 kernel_flags;
+    Valid flags for this command, returned by the kernel upon each call.
+
+  __s64 priority;
+      With KDBUS_RECV_USE_PRIORITY set in flags, receive the next message in
+      the queue with at least the given priority. If no such message is waiting
+      in the queue, -ENOMSG is returned.
+
+  __u64 offset;
+      Upon return of the ioctl, this field contains the offset in the
+      receiver's memory pool.
+};
Quoted 8 lines

Documentation/kdbus.txt line 881

Quoted 5 lines
Documentation/kdbus.txt new file +5 -0
+
+Unless KDBUS_RECV_DROP was passed, and given that the ioctl succeeded, the
+offset field contains the location of the new message inside the receiver's
+pool. The message is stored as struct kdbus_msg at this offset, and can be
+interpreted with the semantics described above.

I'm confused here. Is sent data written to the pool when send is called or when recv is called?

When send is called.

Quoted 1 line

If the former, what prevents DoS, especially DoS due to sending too many fds?

FDs are installed into the task only when the receiver issues CMD_RECV, so a task won't explode unless it issues that ioctl. Plus, receiving FDs is already a per-connection opt-in. Furthermore, you can CMD_PEEK messages which allows you to look at the full message _without_ installing FDs. If you don't want the FDs, you can CMD_DROP the message.

Quoted 11 lines

If the latter, where is the data buffered in the mean time?

Documentation/kdbus.txt line 886

Quoted 5 lines
Documentation/kdbus.txt new file +5 -0
+
+Also, if the connection allowed for file descriptor to be passed
+(KDBUS_HELLO_ACCEPT_FD), and if the message contained any, they will be
+installed into the receiving process after the KDBUS_CMD_MSG_RECV ioctl
+returns. The receiving task is obliged to close all of them appropriately.

This makes it sound like fds are installed at receive time. What prevents resource exhaustion due to having excessive numbers of fds in transit (that are presumably not accounted to anyone)?

We have a per-user message accounting for undelivered messages, as well as a maximum number of pending messages per connection on the receiving end. These limits are accounted on a "user<->user" basis, so the limit of a user A will not affect two other users (B and C) talking.

Quoted 5 lines
Quoted 5 lines
Documentation/kdbus.txt new file +5 -0
+
+7.5 Canceling messages synchronously waiting for replies
+--------------------------------------------------------
+
+When a connection sends a message with KDBUS_MSG_FLAGS_SYNC_REPLY and
Quoted 8 lines

Documentation/kdbus.txt line 900

Quoted 5 lines
Documentation/kdbus.txt new file +5 -0
+blocks while waiting for the reply, the KDBUS_CMD_MSG_CANCEL ioctl can be
+used on the same file descriptor to cancel the message, based on its cookie.
+If there are multiple messages with the same cookie that are all synchronously
+waiting for a reply, all of them will be canceled. Obviously, this is only
+possible in multi-threaded applications.

What does "cancel the message" mean? Does it just mean that the wait for the reply is cancelled?

Yes, exactly. That will be made clearer in the docs. Thanks.

Quoted 9 lines

Documentation/kdbus.txt line 1315

Quoted 6 lines

+11. Policy
+===============================================================================

Documentation/kdbus.txt new file +4 -0
+
+A policy databases restrict the possibilities of connections to own, see and
+talk to well-known names. It can be associated with a bus (through a policy
+holder connection) or a custom endpoint.

ISTM metadata items on bus names should be replaced with policy that applies to the domain as a whole and governs bus creation.

No, well-known names are bound to buses, so a bus is really the right place to hold policy about which process is allowed to claim them. Every user is allowed to create a bus of its own, there's no policy for that, and there shouldn't be.

It has nothing to do with metadata items.

Quoted 27 lines
Quoted 27 lines
Documentation/kdbus.txt new file +27 -0
+A set of policy rules is described by a name and multiple access rules, defined
+by the following struct.
+
+struct kdbus_policy_access {
+  __u64 type;  /* USER, GROUP, WORLD */
+    One of the following.
+
+    KDBUS_POLICY_ACCESS_USER
+      Grant access to a user with the uid stored in the 'id' field.
+
+    KDBUS_POLICY_ACCESS_GROUP
+      Grant access to a user with the gid stored in the 'id' field.
+
+    KDBUS_POLICY_ACCESS_WORLD
+      Grant access to everyone. The 'id' field is ignored.
+
+  __u64 access;        /* OWN, TALK, SEE */
+    The access to grant.
+
+    KDBUS_POLICY_SEE
+      Allow the name to be seen.
+
+    KDBUS_POLICY_TALK
+      Allow the name to be talked to.
+
+    KDBUS_POLICY_OWN
+      Allow the name to be owned.
Quoted 8 lines

Documentation/kdbus.txt line 1358

Quoted 5 lines
Documentation/kdbus.txt new file +5 -0
+
+  __u64 id;
+    For KDBUS_POLICY_ACCESS_USER, stores the uid.
+    For KDBUS_POLICY_ACCESS_GROUP, stores the gid.
+};

What happens if there are multiple matches?

We only have _granting_ policy entries. We search through the policy-db until we find an entry that grants access. We do _not_ stop on the first item that matches.

Quoted 16 lines

Documentation/kdbus.txt line 1425

Quoted 13 lines
Documentation/kdbus.txt new file +12 -0
+
+11.4 TALK access and multiple well-known names per connection
+-------------------------------------------------------------
+
+Note that TALK access is checked against all names of a connection.
+For example, if a connection owns both 'org.foo.bar' and 'org.blah.baz', and
+the policy database allows 'org.blah.baz' to be talked to by WORLD, then this
+permission is also granted to 'org.foo.bar'. That might sound illogical, but
+after all, we allow messages to be directed to either the name or a well-known
+name, and policy is applied to the connection, not the name. In other words,
+the effective TALK policy for a connection is the most permissive of all names
+the connection owns.

This does seem illogical. Does the recipient at least know which well-known name was addressed?

If the sender addressed it to a well-known name, yes. If the sender addressed the message to a unique-ID, there will be no such name, of course. Still, the policy applies to such transactions either way (standard D-Bus behavior).

Note however that dbus1 will not pass along the destination well-known name, hence most userspace libraries will ignore this information too, even if they run on kdbus which might pass this information around. The right way for services that carry multiple service names to discern which actual service is being talked to is having separate object paths for the different functionality to hide between the services.

Quoted 8 lines

Documentation/kdbus.txt line 1443

Quoted 6 lines

+11.5 Implicit policies
+----------------------

Documentation/kdbus.txt new file +4 -0
+
+Depending on the type of the endpoint, a set of implicit rules might be
+enforced. On default endpoints, the following set is enforced:
+

How do these rules interact with installed policy?

As said before, all policy entries _grant_ access. We look through all entries until we find one that grants access.

Quoted 7 lines

Documentation/kdbus.txt line 1448

Quoted 5 lines
Documentation/kdbus.txt new file +5 -0
+  * Privileged connections always override any installed policy. Those
+    connections could easily install their own policies, so there is no
+    reason to enforce installed policies.
+  * Connections can always talk to connections of the same user. This
+    includes broadcast messages.

Why?

All limits on buses are enforced on a user<->user basis. We don't want to provide policies that are more fine-grained than our accounting.

Quoted 3 lines

If anyone ever strengthens the concept of identity to include things other than users (hmm -- there are already groups), this could be very limiting.

If user-based accounting is not suitable, you can create custom endpoints. Future extensions to that are always welcome. So far, the default user-based accounting was enough. And I think it's suitable as default.

Quoted 7 lines

Documentation/kdbus.txt line 1452

Quoted 4 lines
Documentation/kdbus.txt new file +4 -0
+  * Connections that own names might send broadcast messages to other
+    connections that belong to a different user, but only if that
+    destination connection does not own any name.
+

This is weird. It is also differently illogical than the "illogical" thing above.

Actually it follows the same model described above. If two connections are running under the same user then broadcasts are allowed, but if they are running under different users *and* if the destination owns a well-known name, then broadcasts are subject to TALK policy checks since that destination may own a restricted well-known name that is not interested in broadcasts. So this implicit policy is just fast-path for the common case where the target is subscribed to a broadcast and does not own any name.

Quoted 10 lines
Quoted 10 lines

+12. Pool
+===============================================================================

Documentation/kdbus.txt new file +8 -0
+
+A pool for data received from the kernel is installed for every connection of
+the bus, and is sized according to kdbus_cmd_hello.pool_size. It is accessed
+when one of the following ioctls is issued:
+
+  * KDBUS_CMD_MSG_RECV, to receive a message
+  * KDBUS_CMD_NAME_LIST, to dump the name registry
+  * KDBUS_CMD_CONN_INFO, to retrieve information on a connection
Quoted 8 lines

Documentation/kdbus.txt line 1477

Quoted 5 lines
Documentation/kdbus.txt new file +5 -0
+
+Internally, the pool is organized in slices, stored in an rb-tree. The offsets
+returned by either one of the aforementioned ioctls describe offsets inside the
+pool. In order to make the slice available for subsequent calls, KDBUS_CMD_FREE
+has to be called on the offset.

Why are you documenting that the slices are stored in an rb-tree? That's just an implementation details, right?

Dropped, thanks.

Quoted 6 lines
Quoted 6 lines
Documentation/kdbus.txt new file +6 -0
+
+To access the memory, the caller is expected to mmap() it to its task, like
+this:
+
+  /*
+   * POOL_SIZE has to be a multiple of PAGE_SIZE, and it must match the
Quoted 8 lines

Documentation/kdbus.txt line 1489

Quoted 6 lines
Documentation/kdbus.txt new file +6 -0
+   * value that was previously passed in the .pool_size field of struct
+   * kdbus_cmd_hello.
+   */
+
+  buf = mmap(NULL, POOL_SIZE, PROT_READ, MAP_PRIVATE, conn_fd, 0);
+

Will mapping with PROT_WRITE fail? What about MAP_SHARED?

PROT_WRITE will fail and VM_MAYWRITE is cleared.

Quoted 1 line

And why are you suggesting MAP_PRIVATE? That's just strange.

This was a leftover from pre-3.17. memfds require you to use MAP_PRIVATE if SEAL_WRITE is set (which is a linux-specific behavior, where MAP_SHARED is always accounted as writable mapping as mprotect(VM_WRITE) can be called any time). I fixed this up.

Quoted 3 lines
Quoted 3 lines

+
+13. Metadata
+===============================================================================

[snip]

Quoted 8 lines
Quoted 8 lines

+13.1 Known item types
+---------------------

Documentation/kdbus.txt new file +6 -0
+
+The following attach flags are currently supported.
+
+  KDBUS_ATTACH_TIMESTAMP
+    Attaches an item of type KDBUS_ITEM_TIMESTAMP which contains both the
+    monotonic and the realtime timestamp, taken when the message was
Quoted 8 lines

Documentation/kdbus.txt line 1540

Quoted 6 lines
Documentation/kdbus.txt new file +6 -0
+    processed on the kernel side.
+
+  KDBUS_ATTACH_CREDS
+    Attaches an item of type KDBUS_ITEM_CREDS, containing credentials as
+    described in kdbus_creds: the uid, gid, pid, tid and starttime of the task.
+

As mentioned last time, please remove or justify starttime.

starttime allows detecting PID overflows. Exposing the process starttime is useful to detect when a PID is getting reused. Unfortunately, we don't have 64bit pids, so we need the pid+time combination to avoid ambiguity.

Quoted 11 lines

Documentation/kdbus.txt line 1549

Quoted 9 lines
Documentation/kdbus.txt new file +9 -0
+  KDBUS_ATTACH_AUXGROUPS
+    Attaches an item of type KDBUS_ITEM_AUXGROUPS, containing a dynamic
+    number of auxiliary groups the sending task was a member of.
+
+  KDBUS_ATTACH_NAMES
+    Attaches items of type KDBUS_ITEM_OWNED_NAME, one for each name the sending
+    connection currently owns. The name and flags are stored in kdbus_item.name
+    for each of them.
+

That's interesting. What's it for?

It a valuable piece of information for receivers to know which bus names a sender has claimed. For instance, we need this information for the D-Bus proxy service, because we have to apply D-Bus1 policy in that case, and we need to get a list of owned names in a race-free manner to check the policy against.

Quoted 13 lines
Quoted 13 lines
Documentation/kdbus.txt new file +13 -0
+  KDBUS_ATTACH_TID_COMM
+    Attaches an items of type KDBUS_ITEM_TID_COMM, transporting the sending
+    task's 'comm', for the tid.  The string is stored in kdbus_item.str.
+
+  KDBUS_ATTACH_PID_COMM
+    Attaches an items of type KDBUS_ITEM_PID_COMM, transporting the sending
+    task's 'comm', for the pid.  The string is stored in kdbus_item.str.
+
+  KDBUS_ATTACH_EXE
+    Attaches an item of type KDBUS_ITEM_EXE, containing the path to the
+    executable of the sending task, stored in kdbus_item.str.
+
+  KDBUS_ATTACH_CMDLINE
Quoted 8 lines

Documentation/kdbus.txt line 1565

Quoted 3 lines
Documentation/kdbus.txt new file +3 -0
+    Attaches an item of type KDBUS_ITEM_CMDLINE, containing the command line
+    arguments of the sending task, as an array of strings, stored in
+    kdbus_item.str.

Please remove these four items. They are genuinely useless. Anything that uses them for anything is either buggy or should have asked the sender to put the value in the payload (and immediately wondered why it was doing that).

We use them for logging, debugging and monitoring. With our wireshark extension it's pretty useful to know the comm-name of a process when monitoring a bus. As we explained last time, this is not about security. We're aware that a process can modify them. We use them only as additional meta-data for logging and debugging.

If we put those items into the payload, we have to transmit this data even if the destination process is not interested in this. Furthermore, each caller has to run multiple syscalls on each message to retrieve those values.

We use these items heavily for filtering and debugging, regardless of the payload protocol that is transmitted on the bus.

To give another specific use-case here: dbus supports bus activation, where a message sent to a non-running service causes it to be spawned implicitly without losing the message. Now, with such a scheme it is incredibly useful to be able to log which client caused a service to be triggered, hence we want to know the cmdline/exe/comm of the client. Not knowing this is a major pita when trying to trace the boot process and figuring out why a specific service got activated.

Also note that since v2 of the patch there's actually a per-sender mask for meta-data like this, hence a peer which doesn't want to pass its exec/cmdline/comm along can do that. Of course, this will seriously hamper debuggability and transparency...

Quoted 5 lines
Quoted 5 lines
Documentation/kdbus.txt new file +5 -0
+
+  KDBUS_ATTACH_CGROUP
+    Attaches an item of type KDBUS_ITEM_CGROUP with the task's cgroup path.
+
+  KDBUS_ATTACH_CAPS
Quoted 8 lines

Documentation/kdbus.txt line 1576

Quoted 6 lines
Documentation/kdbus.txt new file +6 -0
+    Attaches an item of type KDBUS_ITEM_CAPS, carrying sets of capabilities
+    that should be accessed via kdbus_item.caps.caps. Also, userspace should
+    be written in a way that it takes kdbus_item.caps.last_cap into account,
+    and derive the number of sets and rows from the item size and the reported
+    number of valid capability bits.
+

Please remove this, too, or justify its use.

cgroup information tells us which service is doing a bus request. This is useful for a variety of things. For example, the bus activation logging item above benefits from it. In general, if some message shall be logged about any client it is useful to know its service name.

Capabilities are useful to authenticate specific method calls. For example, when a client asks systemd to reboot, without this concept we can only check for UID==0 to decide whether to allow this. Breaking this down to capabilities in a race-free way has the benefit of allowing systemd to bind this to CAP_SYS_BOOT instead. There is no reason to deny a process with CAP_SYS_BOOT to reboot via bus-APIs, as they could just enforce it via syscalls, anyway.

We think it's a useful and reliable authentication method. Why should we remove it?

Anyway, these items are just optional. The sender can refuse the reveal them, and the item is only transmitted if the receiver opted in for it, too. So there's no need to drop any item type from the protocol.

Quoted 7 lines

Documentation/kdbus.txt line 1580

Quoted 4 lines
Documentation/kdbus.txt new file +4 -0
+  KDBUS_ATTACH_SECLABEL
+    Attaches an item of type KDBUS_ITEM_SECLABEL, which contains the SELinux
+    security label of the sending task. Access via kdbus_item->str.
+

This one, too, and please justify why code that uses it will work in containers an on non-selinux systems.

This maps to SCM_PEERSEC on AF_UNIX sockets. This is actually heavily used already on dbus1. For example, systemd actually uses this information about a bus peer to check whether certain operations are allowed, on top of the normal policy. To give an explicit example:
when starting a service systemd gets the client's peer label from AF_UNIX via SCM_PEERSEC, reads the security label of the service file in question, and then checks the selinux database (via one of libselinux APIs) whether to allow this change.

Note that this is really nothing we came up with, it's code from the SELinux folks, it's simple enough, and has been exposed and used that way since ages in dbus1. libselinux offers all the right APIs to make use of this, and kdbus really needs to provide the same functionality as dbus1 in this regard here.

Let met stress that checking the selinux database here is alway *on top* of the normal UID/caps based security checks services do. This is exactly how selinux enforces checks on files on top of UID/caps checks, or on process or anything else that is selinux-managed.

Quoted 10 lines

Documentation/kdbus.txt line 1584

Quoted 4 lines
Documentation/kdbus.txt new file +4 -0
+  KDBUS_ATTACH_AUDIT
+    Attaches an item of type KDBUS_ITEM_AUDIT, which contains the audio label
+    of the sending taskj. Access via kdbus_item->str.
+

I will NAK the hell out of this until, at the very least, someone documents what this means, how to parse it, what its stability rules are, who is allowed to see the value it contains, why that value will never evolve to become *more* security sensitive than it is now, etc.

Quoted 4 lines

Audit gets to do crazy sh*t because it's restricted to privileged receivers. This isn't restricted like that, so it doesn't deserve the same dispensation. (And, honestly, I'm not sure that audit really deserves its free pass on making sense.)

This was based on a misunderstanding, so I will ignore it here. Lets discuss this on the metadata-patch, in case it's still unclear.

Quoted 6 lines

Documentation/kdbus.txt line 1588

Quoted 4 lines
Documentation/kdbus.txt new file +4 -0
+  KDBUS_ATTACH_CONN_DESCRIPTION
+    Attaches an item of type KDBUS_ITEM_CONN_DESCRIPTION that contains the
+    sender connection's current name in kdbus_item.str.
+

Which name? Can't there be several?

No. There is only one connection description string, copied verbatim from what the connection supplied during HELLO.

Note that this is really just about debugging, since in some cases processes might end up with multiple kdbus fds, and it is useful in tools like "busctl" to know which one is which.

Quoted 4 lines
Quoted 4 lines
Documentation/kdbus.txt new file +4 -0
+
+13.1 Metadata and namespaces
+----------------------------
+
Quoted 8 lines

Documentation/kdbus.txt line 1598

Quoted 6 lines
Documentation/kdbus.txt new file +6 -0
+Metadata such as PIDs, UIDs or GIDs are automatically translated to the
+namespaces of the domain that is used to send a message over. The namespaces
+of a domain are pinned at creation time, which is when the filesystem has been
+mounted.
+
+Metadata items that cannot be translated are dropped.

What if the receiver said that the item was mandatory?

It is still dropped. It's the responsibility of the receiver to reject messages that lack required metadata.

Thanks for the review, Andy. Documentation fixes coming up! David

#5 lore raw

Re: kdbus: add documentation

Quoted 85 lines · David Herrmann

Hi Andy!

Quoted 24 lines · Andy Lutomirski
Quoted 15 lines · Greg Kroah-Hartman

From: Daniel Mack <[email protected]>

kdbus is a system for low-latency, low-overhead, easy to use interprocess communication (IPC).

The interface to all functions in this driver is implemented through ioctls on files exposed through the mount point of a kdbusfs. This patch adds detailed documentation about the kernel level API design.

---

Documentation/kdbus.txt line 63

Quoted 6 lines
Documentation/kdbus.txt new file +6 -0
+  Pool:
+    Each connection allocates a piece of shmem-backed memory that is used
+    to receive messages and answers to ioctl command from the kernel. It is
+    never used to send anything to the kernel. In order to access that memory,
+    userspace must mmap() it into its task.
+    See section 12 for more details.
Quoted 2 lines

At the risk of opening a can of worms, wouldn't this be much more useful if you could share a pool between multiple connections?

Within a process it could theoretically be possible to share the same memory pool between multiple connections made by the process. However, note that normally a process only has a single connection to the bus open (possibly two, if it opens a connection to both the system and the user bus). Now, sharing the receiver buffer could certainly be considered an optimization, but it would have no effect on "usefulness", though, as just allocating space from a single shared per-process receiver won't give you any new possibilities...

We have thought about this, but decided to delay it for now. Shared pools can easily be added as an extension later on.

[snip]

Quoted 10 lines
Quoted 10 lines
Documentation/kdbus.txt new file +10 -0
+KDBUS_CMD_BUS_MAKE, and KDBUS_CMD_ENDPOINT_MAKE take a
+struct kdbus_cmd_make argument.
+
+struct kdbus_cmd_make {
+  __u64 size;
+    The overall size of the struct, including its items.
+
+  __u64 flags;
+    The flags for creation.
+
Quoted 8 lines

Documentation/kdbus.txt line 283

Quoted 5 lines
Documentation/kdbus.txt new file +5 -0
+    KDBUS_MAKE_ACCESS_GROUP
+      Make the device file group-accessible
+
+    KDBUS_MAKE_ACCESS_WORLD
+      Make the device file world-accessible

This thing is a file. What's wrong with using a normal POSIX mode? (And what to the read, write, and exec modes do?)

Domains and buses are directories, endpoints are files. Domains also create control-files implicitly.

For kdbus clients there is just access or no access, but not distinction between read, write and execute access. Due to that we just break this down to per-group and world access bits, since doing more is pointless, and we shouldn't allow shoehorning more stuff into the access mode.

[snip]

Quoted 9 lines

Documentation/kdbus.txt line 469

Quoted 8 lines
Documentation/kdbus.txt new file +8 -0
+      KDBUS_ITEM_CREDS
+      KDBUS_ITEM_SECLABEL
+        Privileged bus users may submit these types in order to create
+        connections with faked credentials. The only real use case for this
+        is a proxy service which acts on behalf of some other tasks. For a
+        connection that runs in that mode, the message's metadata items will
+        be limited to what's specified here. See section 13 for more
+        information.
Quoted 3 lines

This is still confusing. There are multiple places in which metadata is attached. Which does this apply to? And why are only creds and seclabel listed?

Quoted 7 lines

Yes, and there are multiple places where metadata is *gathered*. This ioctl creates connections, so only the items that are actually *gathered* by that ioctl are documented here. These items are not part of any messages, but are used as identification of the connection owner (and in this particular case, to allow privileged proxies to overwrite the items so they can properly proxy a legacy-dbus peer connection).

But don't proxies need to override the per-message metadata, too? This is why I'm confused (and my confusion about what's happening goes down into the code, too). IMO it would be great if all the variables were named things like message_metadata, conn_metadata, bus_metadata, etc.

Quoted 16 lines

[snip]

Quoted 5 lines
Quoted 5 lines

+6.5 Getting information about a connection's bus creator
+--------------------------------------------------------

Documentation/kdbus.txt new file +3 -0
+
+The KDBUS_CMD_BUS_CREATOR_INFO ioctl takes the same struct as
+KDBUS_CMD_CONN_INFO but is used to retrieve information about the creator of
Quoted 8 lines

Documentation/kdbus.txt line 563

Quoted 4 lines
Documentation/kdbus.txt new file +4 -0
+the bus the connection is attached to. The metadata returned by this call is
+collected during the creation of the bus and is never altered afterwards, so
+it provides pristine information on the task that created the bus, at the
+moment when it did so.

What's this for? I understand the need for the creator of busses to be authenticated, but doing it like this mean that anyone who will *fail* authentication can DoS the authentic creator.

Quoted 4 lines

This returns information on a bus owner, to determine whether a connection is connected to a system, user or session bus. Note that the bus-creator itself is not a valid peer on the bus, so you cannot send messages to them. Which kind of DoS do you have in mind?

I assume that the logic is something like:

connect to bus
request bus metadata
if (bus metadata matches expectations) {
great, trust the bus!
} else {
oh crap!
}

If I'm understanding it right, then user code only really has two
outcomes: the good case and the "oh crap!" case. The problem is that "oh crap!" isn't a clean failure -- if it happens, then the application has just been DoSed, because in that case, one of two things happened:

1. Some policy mismatch means that the legitimate bus owner did create the bus, but the user application is confused. This will result in difficult-to-diagnose failures.

2. A malicious or confused program created the bus. This is a DoS -- even the legitimate bus creator can't actually create the bus now.

So I think that the policy should be applied at the time that the bus name is claimed, not at the time that someone else tries to use the bus. IOW, the way that you verify you're talking to the system bus should be by checking that the bus is called "system", not by checking that UID 0 created the bus.

Quoted 25 lines
Quoted 16 lines
Quoted 16 lines
Documentation/kdbus.txt new file +15 -0
+
+7.3 Passing of Payload Data
+---------------------------
+
+When connecting to the bus, receivers request a memory pool of a given size,
+large enough to carry all backlog of data enqueued for the connection. The
+pool is internally backed by a shared memory file which can be mmap()ed by
+the receiver.
+
+KDBUS_MSG_PAYLOAD_VEC:
+  Messages are directly copied by the sending process into the receiver's pool,
+  that way two peers can exchange data by effectively doing a single-copy from
+  one process to another, the kernel will not buffer the data anywhere else.
+
+KDBUS_MSG_PAYLOAD_MEMFD:
Quoted 8 lines

Documentation/kdbus.txt line 833

Quoted 6 lines
Documentation/kdbus.txt new file +6 -0
+  Messages can reference memfd files which contain the data.
+  memfd files are tmpfs-backed files that allow sealing of the content of the
+  file, which prevents all writable access to the file content.
+  Only sealed memfd files are accepted as payload data, which enforces
+  reliable passing of data; the receiver can assume that neither the sender nor
+  anyone else can alter the content after the message is sent.

This should specify *which* seals are checked.

Quoted 3 lines

True. Will be added to the documentation. For the record, it's the full set of seals right now, so F_SEAL_SHRINK|F_SEAL_GROW|F_SEAL_WRITE|F_SEAL_SEAL.

Makes sense.

Quoted 76 lines
Quoted 44 lines
Quoted 44 lines
Documentation/kdbus.txt new file +43 -0
+
+Apart from the sender filling-in the content into memfd files, the data will
+be passed as zero-copy from one process to another, read-only, shared between
+the peers.
+
+
+7.4 Receiving messages
+----------------------
+
+Messages are received by the client with the KDBUS_CMD_MSG_RECV ioctl. The
+endpoint file of the bus supports poll() to wake up the receiving process when
+new messages are queued up to be received.
+
+With the KDBUS_CMD_MSG_RECV ioctl, a struct kdbus_cmd_recv is used.
+
+struct kdbus_cmd_recv {
+  __u64 flags;
+    Flags to control the receive command.
+
+    KDBUS_RECV_PEEK
+      Just return the location of the next message. Do not install file
+      descriptors or anything else. This is usually used to determine the
+      sender of the next queued message.
+
+    KDBUS_RECV_DROP
+      Drop the next message without doing anything else with it, and free the
+      pool slice. This a short-cut for KDBUS_RECV_PEEK and KDBUS_CMD_FREE.
+
+    KDBUS_RECV_USE_PRIORITY
+      Use the priority field (see below).
+
+  __u64 kernel_flags;
+    Valid flags for this command, returned by the kernel upon each call.
+
+  __s64 priority;
+      With KDBUS_RECV_USE_PRIORITY set in flags, receive the next message in
+      the queue with at least the given priority. If no such message is waiting
+      in the queue, -ENOMSG is returned.
+
+  __u64 offset;
+      Upon return of the ioctl, this field contains the offset in the
+      receiver's memory pool.
+};
Quoted 8 lines

Documentation/kdbus.txt line 881

Quoted 5 lines
Documentation/kdbus.txt new file +5 -0
+
+Unless KDBUS_RECV_DROP was passed, and given that the ioctl succeeded, the
+offset field contains the location of the new message inside the receiver's
+pool. The message is stored as struct kdbus_msg at this offset, and can be
+interpreted with the semantics described above.

I'm confused here. Is sent data written to the pool when send is called or when recv is called?

When send is called.

Quoted 1 line

If the former, what prevents DoS, especially DoS due to sending too many fds?

FDs are installed into the task only when the receiver issues CMD_RECV, so a task won't explode unless it issues that ioctl. Plus, receiving FDs is already a per-connection opt-in. Furthermore, you can CMD_PEEK messages which allows you to look at the full message _without_ installing FDs. If you don't want the FDs, you can CMD_DROP the message.

Quoted 11 lines

If the latter, where is the data buffered in the mean time?

Documentation/kdbus.txt line 886

Quoted 5 lines
Documentation/kdbus.txt new file +5 -0
+
+Also, if the connection allowed for file descriptor to be passed
+(KDBUS_HELLO_ACCEPT_FD), and if the message contained any, they will be
+installed into the receiving process after the KDBUS_CMD_MSG_RECV ioctl
+returns. The receiving task is obliged to close all of them appropriately.

This makes it sound like fds are installed at receive time. What prevents resource exhaustion due to having excessive numbers of fds in transit (that are presumably not accounted to anyone)?

Quoted 5 lines

We have a per-user message accounting for undelivered messages, as well as a maximum number of pending messages per connection on the receiving end. These limits are accounted on a "user<->user" basis, so the limit of a user A will not affect two other users (B and C) talking.

But you can shove tons of fds in a message, and you can have lots of messages, and some of the fds can be fds of unix sockets that have fds queued up in them, and one of those fds could be the fd to the kdbus connection that sent the fd...

This is not advice as to what to do about it, but I think that it will be a problem at some point.

Quoted 10 lines
Quoted 9 lines

Documentation/kdbus.txt line 1315

Quoted 6 lines

+11. Policy
+===============================================================================

Documentation/kdbus.txt new file +4 -0
+
+A policy databases restrict the possibilities of connections to own, see and
+talk to well-known names. It can be associated with a bus (through a policy
+holder connection) or a custom endpoint.

ISTM metadata items on bus names should be replaced with policy that applies to the domain as a whole and governs bus creation.

Quoted 6 lines

No, well-known names are bound to buses, so a bus is really the right place to hold policy about which process is allowed to claim them. Every user is allowed to create a bus of its own, there's no policy for that, and there shouldn't be.

It has nothing to do with metadata items.

But it does -- the creator of the bus binds metadata to that bus at creation time.

I think that a better solution would be to have a global policy that says, for example, "to create the bus called 'system', the creator must have selinux label xyz" or "to create a user bus called uid-1000-privileged-ui-bus the creator must have some cgroup" or whatever.

Although maybe a better solution would leave this in the kernel but allow any cgroup to create a bus with a same that indicates the creating cgroup. Then I could have my desktop shell create a "/cgroup/path/to/desktop" for per-user privileged things.

Quoted 37 lines
Quoted 28 lines
Quoted 28 lines
Documentation/kdbus.txt new file +27 -0
+A set of policy rules is described by a name and multiple access rules, defined
+by the following struct.
+
+struct kdbus_policy_access {
+  __u64 type;  /* USER, GROUP, WORLD */
+    One of the following.
+
+    KDBUS_POLICY_ACCESS_USER
+      Grant access to a user with the uid stored in the 'id' field.
+
+    KDBUS_POLICY_ACCESS_GROUP
+      Grant access to a user with the gid stored in the 'id' field.
+
+    KDBUS_POLICY_ACCESS_WORLD
+      Grant access to everyone. The 'id' field is ignored.
+
+  __u64 access;        /* OWN, TALK, SEE */
+    The access to grant.
+
+    KDBUS_POLICY_SEE
+      Allow the name to be seen.
+
+    KDBUS_POLICY_TALK
+      Allow the name to be talked to.
+
+    KDBUS_POLICY_OWN
+      Allow the name to be owned.
Quoted 8 lines

Documentation/kdbus.txt line 1358

Quoted 5 lines
Documentation/kdbus.txt new file +5 -0
+
+  __u64 id;
+    For KDBUS_POLICY_ACCESS_USER, stores the uid.
+    For KDBUS_POLICY_ACCESS_GROUP, stores the gid.
+};

What happens if there are multiple matches?

Quoted 3 lines

We only have _granting_ policy entries. We search through the policy-db until we find an entry that grants access. We do _not_ stop on the first item that matches.

Yay! Can you document that more clearly?

Quoted 23 lines
Quoted 17 lines
Quoted 4 lines
Documentation/kdbus.txt new file +2 -0
+
+11.4 TALK access and multiple well-known names per connection

Documentation/kdbus.txt line 1425

Quoted 10 lines
Documentation/kdbus.txt new file +10 -0
+-------------------------------------------------------------
+
+Note that TALK access is checked against all names of a connection.
+For example, if a connection owns both 'org.foo.bar' and 'org.blah.baz', and
+the policy database allows 'org.blah.baz' to be talked to by WORLD, then this
+permission is also granted to 'org.foo.bar'. That might sound illogical, but
+after all, we allow messages to be directed to either the name or a well-known
+name, and policy is applied to the connection, not the name. In other words,
+the effective TALK policy for a connection is the most permissive of all names
+the connection owns.

This does seem illogical. Does the recipient at least know which well-known name was addressed?

If the sender addressed it to a well-known name, yes. If the sender addressed the message to a unique-ID, there will be no such name, of course. Still, the policy applies to such transactions either way (standard D-Bus behavior).

Quoted 7 lines

Note however that dbus1 will not pass along the destination well-known name, hence most userspace libraries will ignore this information too, even if they run on kdbus which might pass this information around. The right way for services that carry multiple service names to discern which actual service is being talked to is having separate object paths for the different functionality to hide between the services.

It seems unfortunate to keep around this really weird behavior for the benefit of legacy applications. Could there perhaps be a flag that a connection can set to indicate that it understands per-destination access control and therefore wants stricter policy enforcement?

Quoted 19 lines
Quoted 9 lines

Documentation/kdbus.txt line 1443

Quoted 7 lines

+11.5 Implicit policies
+----------------------

Documentation/kdbus.txt new file +4 -0
+
+Depending on the type of the endpoint, a set of implicit rules might be
+enforced. On default endpoints, the following set is enforced:
+

How do these rules interact with installed policy?

As said before, all policy entries _grant_ access. We look through all entries until we find one that grants access.

Quoted 6 lines
Quoted 5 lines
Documentation/kdbus.txt new file +5 -0
+  * Privileged connections always override any installed policy. Those
+    connections could easily install their own policies, so there is no
+    reason to enforce installed policies.
+  * Connections can always talk to connections of the same user. This
+    includes broadcast messages.
Quoted 4 lines
Quoted 1 line

Why?

All limits on buses are enforced on a user<->user basis. We don't want to provide policies that are more fine-grained than our accounting.

This seems completely at odds with all the fine-grained metadata stuff. Also, anything that relies on this may get very confused when the LSM hooks go in, because I'm reasonably sure that the intent is for them to *not* follow this principle.

Quoted 14 lines
Quoted 4 lines

If anyone ever strengthens the concept of identity to include things other than users (hmm -- there are already groups), this could be very limiting.

If user-based accounting is not suitable, you can create custom endpoints. Future extensions to that are always welcome. So far, the default user-based accounting was enough. And I think it's suitable as default.

Quoted 4 lines
Quoted 4 lines
Documentation/kdbus.txt new file +4 -0
+  * Connections that own names might send broadcast messages to other
+    connections that belong to a different user, but only if that
+    destination connection does not own any name.
+

(Also, what does "might" mean here?)

Quoted 4 lines
Quoted 3 lines

This is weird. It is also differently illogical than the "illogical" thing above.

Quoted 8 lines

Actually it follows the same model described above. If two connections are running under the same user then broadcasts are allowed, but if they are running under different users *and* if the destination owns a well-known name, then broadcasts are subject to TALK policy checks since that destination may own a restricted well-known name that is not interested in broadcasts. So this implicit policy is just fast-path for the common case where the target is subscribed to a broadcast and does not own any name.

Huh?

Say I have two users, "Sender" and "Receiver", each with a single connection. If Receiver owns no well-known names, then Sender can send to it. If Receiver owns one well-known name, then Sender needs to pass a TALK check on that name. If Reciever owns two well-known names, then Sender only needs to pass a TALK check on one of them.

Am I understanding this right? If I am, then I think this is in the category of baroque and inconsistent security rules which everyone will screw up and therefore introduce security vulnerabilities.

Can you really not enforce the much simpler rule that, to send to a name, you must have permission to send to *that* name? If legacy dbus1 receivers register two names and don't validate everything correctly, then only the legacy receivers have problems.

Quoted 15 lines
Quoted 6 lines
Quoted 6 lines
Documentation/kdbus.txt new file +6 -0
+
+To access the memory, the caller is expected to mmap() it to its task, like
+this:
+
+  /*
+   * POOL_SIZE has to be a multiple of PAGE_SIZE, and it must match the
Quoted 8 lines

Documentation/kdbus.txt line 1489

Quoted 6 lines
Documentation/kdbus.txt new file +6 -0
+   * value that was previously passed in the .pool_size field of struct
+   * kdbus_cmd_hello.
+   */
+
+  buf = mmap(NULL, POOL_SIZE, PROT_READ, MAP_PRIVATE, conn_fd, 0);
+

Will mapping with PROT_WRITE fail? What about MAP_SHARED?

Quoted 8 lines

PROT_WRITE will fail and VM_MAYWRITE is cleared.

Quoted 1 line

And why are you suggesting MAP_PRIVATE? That's just strange.

This was a leftover from pre-3.17. memfds require you to use MAP_PRIVATE if SEAL_WRITE is set (which is a linux-specific behavior, where MAP_SHARED is always accounted as writable mapping as mprotect(VM_WRITE) can be called any time). I fixed this up.

Thanks. (I assume that memfd has nothing to do with this directly, since these are pools, not memfds.)

Quoted 22 lines
Quoted 4 lines
Quoted 4 lines

+
+13. Metadata
+===============================================================================

[snip]

Quoted 8 lines
Quoted 8 lines

+13.1 Known item types
+---------------------

Documentation/kdbus.txt new file +6 -0
+
+The following attach flags are currently supported.
+
+  KDBUS_ATTACH_TIMESTAMP
+    Attaches an item of type KDBUS_ITEM_TIMESTAMP which contains both the
+    monotonic and the realtime timestamp, taken when the message was
Quoted 8 lines

Documentation/kdbus.txt line 1540

Quoted 6 lines
Documentation/kdbus.txt new file +6 -0
+    processed on the kernel side.
+
+  KDBUS_ATTACH_CREDS
+    Attaches an item of type KDBUS_ITEM_CREDS, containing credentials as
+    described in kdbus_creds: the uid, gid, pid, tid and starttime of the task.
+

As mentioned last time, please remove or justify starttime.

Quoted 4 lines

starttime allows detecting PID overflows. Exposing the process starttime is useful to detect when a PID is getting reused. Unfortunately, we don't have 64bit pids, so we need the pid+time combination to avoid ambiguity.

NAK, I think.

I agree that PID overflow is a real issue and should be addressed somehow. But please address it for real instead of adding Yet Another Hack (tm). In the mean time, leave that hack out, please.

I would *love* to see PIDs have extra high bits at the end, done in a way that supports CRIU and that guarantees no reuse unless something privileged intentionally mis-programs it. But starttime isn't that mechanism.

Quoted 13 lines
Quoted 12 lines

Documentation/kdbus.txt line 1549

Quoted 10 lines
Documentation/kdbus.txt new file +9 -0
+  KDBUS_ATTACH_AUXGROUPS
+    Attaches an item of type KDBUS_ITEM_AUXGROUPS, containing a dynamic
+    number of auxiliary groups the sending task was a member of.
+
+  KDBUS_ATTACH_NAMES
+    Attaches items of type KDBUS_ITEM_OWNED_NAME, one for each name the sending
+    connection currently owns. The name and flags are stored in kdbus_item.name
+    for each of them.
+

That's interesting. What's it for?

Quoted 5 lines

It a valuable piece of information for receivers to know which bus names a sender has claimed. For instance, we need this information for the D-Bus proxy service, because we have to apply D-Bus1 policy in that case, and we need to get a list of owned names in a race-free manner to check the policy against.

But if you change the rule to the sensible one where you need permission to TALK to the name that you're talking to, this goes away, right?

Quoted 23 lines
Quoted 14 lines
Quoted 14 lines
Documentation/kdbus.txt new file +13 -0
+  KDBUS_ATTACH_TID_COMM
+    Attaches an items of type KDBUS_ITEM_TID_COMM, transporting the sending
+    task's 'comm', for the tid.  The string is stored in kdbus_item.str.
+
+  KDBUS_ATTACH_PID_COMM
+    Attaches an items of type KDBUS_ITEM_PID_COMM, transporting the sending
+    task's 'comm', for the pid.  The string is stored in kdbus_item.str.
+
+  KDBUS_ATTACH_EXE
+    Attaches an item of type KDBUS_ITEM_EXE, containing the path to the
+    executable of the sending task, stored in kdbus_item.str.
+
+  KDBUS_ATTACH_CMDLINE
Quoted 8 lines

Documentation/kdbus.txt line 1565

Quoted 3 lines
Documentation/kdbus.txt new file +3 -0
+    Attaches an item of type KDBUS_ITEM_CMDLINE, containing the command line
+    arguments of the sending task, as an array of strings, stored in
+    kdbus_item.str.

Please remove these four items. They are genuinely useless. Anything that uses them for anything is either buggy or should have asked the sender to put the value in the payload (and immediately wondered why it was doing that).

Quoted 5 lines

We use them for logging, debugging and monitoring. With our wireshark extension it's pretty useful to know the comm-name of a process when monitoring a bus. As we explained last time, this is not about security. We're aware that a process can modify them. We use them only as additional meta-data for logging and debugging.

Use the PID. Really. Your wireshark extention can look this crap up in /proc and, if it fails due to a race, big frickin' deal.

Quoted 9 lines

If we put those items into the payload, we have to transmit this data even if the destination process is not interested in this. Furthermore, each caller has to run multiple syscalls on each message to retrieve those values.

We use these items heavily for filtering and debugging, regardless of the payload protocol that is transmitted on the bus.

Quoted 7 lines

To give another specific use-case here: dbus supports bus activation, where a message sent to a non-running service causes it to be spawned implicitly without losing the message. Now, with such a scheme it is incredibly useful to be able to log which client caused a service to be triggered, hence we want to know the cmdline/exe/comm of the client. Not knowing this is a major pita when trying to trace the boot process and figuring out why a specific service got activated.

Again, use the PID for tracing, please.

At the very least, make it impossible to specify these fields in the "must be received" set and rename them to something like KDBUS_INSTALL_UNRELIABLE_CMDLINE, etc, because they're unreliable

Finally, this stuff should only be readable by privileged users. And using the PID accomplishes that.

Quoted 5 lines

Also note that since v2 of the patch there's actually a per-sender mask for meta-data like this, hence a peer which doesn't want to pass its exec/cmdline/comm along can do that. Of course, this will seriously hamper debuggability and transparency...

Transparency is a terrible thing here.

How many users put passwords into things on the command line? Yes, it's a bad idea (for reasons that are entirely stupid), but now those passwords get *logged*.

If this is in the kernel, and someone complains that sensitive data is showing up on ten different logs on their system, they'll *correctly* blame the kernel. If you at least use the PID and restrict it to the logging code, then at least the bug report will go to the logging daemon, which will be *correctly* accused of doing something daft, and it can be fixed.

Quoted 20 lines
Quoted 14 lines

Documentation/kdbus.txt line 1576

Quoted 12 lines
Documentation/kdbus.txt new file +11 -0
+
+  KDBUS_ATTACH_CGROUP
+    Attaches an item of type KDBUS_ITEM_CGROUP with the task's cgroup path.
+
+  KDBUS_ATTACH_CAPS
+    Attaches an item of type KDBUS_ITEM_CAPS, carrying sets of capabilities
+    that should be accessed via kdbus_item.caps.caps. Also, userspace should
+    be written in a way that it takes kdbus_item.caps.last_cap into account,
+    and derive the number of sets and rows from the item size and the reported
+    number of valid capability bits.
+

Please remove this, too, or justify its use.

cgroup information tells us which service is doing a bus request. This is useful for a variety of things. For example, the bus activation logging item above benefits from it. In general, if some message shall be logged about any client it is useful to know its service name.

Quoted 7 lines

Capabilities are useful to authenticate specific method calls. For example, when a client asks systemd to reboot, without this concept we can only check for UID==0 to decide whether to allow this. Breaking this down to capabilities in a race-free way has the benefit of allowing systemd to bind this to CAP_SYS_BOOT instead. There is no reason to deny a process with CAP_SYS_BOOT to reboot via bus-APIs, as they could just enforce it via syscalls, anyway.

With all due respect, BS.

I admit that there is probably no reason to deny systemd-based reboot to a CAP_SYS_BOOT-capable process, but there is absolutely no reason to give processes that are supposed to reboot using systemd the CAP_SYS_BOOT capability.

In any event, I suspect you'll have a hard time justifying this for anything other than CAP_SYS_BOOT. Just because CAP_SYS_ADMIN users can probably do whatever they want doesn't mean that systemd should make that a built-in policy.

Also, wtf is the bounding set and such for? At the very least this should only be the effective set.

Quoted 3 lines

We think it's a useful and reliable authentication method. Why should we remove it?

Because the implementation is buggy and therefore it's insecure? Remember that caps are namespaced in an interesting way.

Quoted 5 lines

Anyway, these items are just optional. The sender can refuse the reveal them, and the item is only transmitted if the receiver opted in for it, too. So there's no need to drop any item type from the protocol.

No.

Because if receivers opt in to most of these, *they're doing it wrong*, and the kernel shouldn't be in the business of helping them.

Quoted 24 lines
Quoted 8 lines

Documentation/kdbus.txt line 1580

Quoted 5 lines
Documentation/kdbus.txt new file +4 -0
+  KDBUS_ATTACH_SECLABEL
+    Attaches an item of type KDBUS_ITEM_SECLABEL, which contains the SELinux
+    security label of the sending task. Access via kdbus_item->str.
+

This one, too, and please justify why code that uses it will work in containers an on non-selinux systems.

This maps to SCM_PEERSEC on AF_UNIX sockets. This is actually heavily used already on dbus1. For example, systemd actually uses this information about a bus peer to check whether certain operations are allowed, on top of the normal policy. To give an explicit example:
when starting a service systemd gets the client's peer label from AF_UNIX via SCM_PEERSEC, reads the security label of the service file in question, and then checks the selinux database (via one of libselinux APIs) whether to allow this change.

Note that this is really nothing we came up with, it's code from the SELinux folks, it's simple enough, and has been exposed and used that way since ages in dbus1. libselinux offers all the right APIs to make use of this, and kdbus really needs to provide the same functionality as dbus1 in this regard here.

Quoted 4 lines

Let met stress that checking the selinux database here is alway *on top* of the normal UID/caps based security checks services do. This is exactly how selinux enforces checks on files on top of UID/caps checks, or on process or anything else that is selinux-managed.

But I thought that the LSM hooks were going to replace all of that.

Can you get a selinux person to confirm that this is actually necessary?

Quoted 11 lines
Quoted 11 lines

Documentation/kdbus.txt line 1584

Quoted 5 lines
Documentation/kdbus.txt new file +4 -0
+  KDBUS_ATTACH_AUDIT
+    Attaches an item of type KDBUS_ITEM_AUDIT, which contains the audio label
+    of the sending taskj. Access via kdbus_item->str.
+

I will NAK the hell out of this until, at the very least, someone documents what this means, how to parse it, what its stability rules are, who is allowed to see the value it contains, why that value will never evolve to become *more* security sensitive than it is now, etc.

Quoted 7 lines
Quoted 4 lines

Audit gets to do crazy sh*t because it's restricted to privileged receivers. This isn't restricted like that, so it doesn't deserve the same dispensation. (And, honestly, I'm not sure that audit really deserves its free pass on making sense.)

This was based on a misunderstanding, so I will ignore it here. Lets discuss this on the metadata-patch, in case it's still unclear.

Yeah, I think you're right about this.

If I'm understanding this right, then I think it just needs a documentation change and possibly a renaming of the metadata item name.

Quoted 6 lines
Quoted 6 lines
Quoted 5 lines
Documentation/kdbus.txt new file +4 -0
+  KDBUS_ATTACH_CONN_DESCRIPTION
+    Attaches an item of type KDBUS_ITEM_CONN_DESCRIPTION that contains the
+    sender connection's current name in kdbus_item.str.
+
Quoted 8 lines
Quoted 1 line

Which name? Can't there be several?

No. There is only one connection description string, copied verbatim from what the connection supplied during HELLO.

Note that this is really just about debugging, since in some cases processes might end up with multiple kdbus fds, and it is useful in tools like "busctl" to know which one is which.

Fair enough.

Quoted 14 lines
Quoted 13 lines

Documentation/kdbus.txt line 1598

Quoted 11 lines
Documentation/kdbus.txt new file +10 -0
+
+13.1 Metadata and namespaces
+----------------------------
+
+Metadata such as PIDs, UIDs or GIDs are automatically translated to the
+namespaces of the domain that is used to send a message over. The namespaces
+of a domain are pinned at creation time, which is when the filesystem has been
+mounted.
+
+Metadata items that cannot be translated are dropped.

What if the receiver said that the item was mandatory?

Quoted 2 lines

It is still dropped. It's the responsibility of the receiver to reject messages that lack required metadata.

Thanks,
Andy

#6 lore raw

Re: kdbus: add documentation

Hi

Quoted 23 lines · Andy Lutomirski
Quoted 15 lines · David Herrmann

[snip]

Quoted 5 lines
Quoted 5 lines

+6.5 Getting information about a connection's bus creator
+--------------------------------------------------------

Documentation/kdbus.txt new file +3 -0
+
+The KDBUS_CMD_BUS_CREATOR_INFO ioctl takes the same struct as
+KDBUS_CMD_CONN_INFO but is used to retrieve information about the creator of
Quoted 8 lines

Documentation/kdbus.txt line 563

Quoted 4 lines
Documentation/kdbus.txt new file +4 -0
+the bus the connection is attached to. The metadata returned by this call is
+collected during the creation of the bus and is never altered afterwards, so
+it provides pristine information on the task that created the bus, at the
+moment when it did so.

What's this for? I understand the need for the creator of busses to be authenticated, but doing it like this mean that anyone who will *fail* authentication can DoS the authentic creator.

Quoted 4 lines

This returns information on a bus owner, to determine whether a connection is connected to a system, user or session bus. Note that the bus-creator itself is not a valid peer on the bus, so you cannot send messages to them. Which kind of DoS do you have in mind?

I assume that the logic is something like:

Quoted 7 lines

connect to bus
request bus metadata
if (bus metadata matches expectations) {
great, trust the bus!
} else {
oh crap!
}

Uh, no, this is really not the logic that should be assumed. It's more for code where you want to simply pass a bus fd, and the code knows nothing about it. Now, the code can derive some information from the bus fd, like for example who owns it. Then, depending on some of the creds returned it can determine whether to read configuration file set A or B and so on. This is particularly useful for all kinds of unprivileged bus services that end up running on any kind of bus and need to be able to figure out what they are actually operating on.

Quoted 19 lines

If I'm understanding it right, then user code only really has two
outcomes: the good case and the "oh crap!" case. The problem is that "oh crap!" isn't a clean failure -- if it happens, then the application has just been DoSed, because in that case, one of two things happened:

1. Some policy mismatch means that the legitimate bus owner did create the bus, but the user application is confused. This will result in difficult-to-diagnose failures.

2. A malicious or confused program created the bus. This is a DoS -- even the legitimate bus creator can't actually create the bus now.

So I think that the policy should be applied at the time that the bus name is claimed, not at the time that someone else tries to use the bus. IOW, the way that you verify you're talking to the system bus should be by checking that the bus is called "system", not by checking that UID 0 created the bus.

[snip]

Quoted 16 lines
Quoted 10 lines
Quoted 9 lines

Documentation/kdbus.txt line 886

Quoted 5 lines
Documentation/kdbus.txt new file +5 -0
+
+Also, if the connection allowed for file descriptor to be passed
+(KDBUS_HELLO_ACCEPT_FD), and if the message contained any, they will be
+installed into the receiving process after the KDBUS_CMD_MSG_RECV ioctl
+returns. The receiving task is obliged to close all of them appropriately.

This makes it sound like fds are installed at receive time. What prevents resource exhaustion due to having excessive numbers of fds in transit (that are presumably not accounted to anyone)?

Quoted 5 lines

We have a per-user message accounting for undelivered messages, as well as a maximum number of pending messages per connection on the receiving end. These limits are accounted on a "user<->user" basis, so the limit of a user A will not affect two other users (B and C) talking.

Quoted 4 lines

But you can shove tons of fds in a message, and you can have lots of messages, and some of the fds can be fds of unix sockets that have fds queued up in them, and one of those fds could be the fd to the kdbus connection that sent the fd...

You cannot send kdbus-fds or unix-fds over kdbus, right now. We have people working on the AF_UNIX gc to make it more generic and include external types. Until then, we simply prevent recursive fd passing.

Quoted 30 lines

This is not advice as to what to do about it, but I think that it will be a problem at some point.

Quoted 10 lines
Quoted 9 lines

Documentation/kdbus.txt line 1315

Quoted 6 lines

+11. Policy
+===============================================================================

Documentation/kdbus.txt new file +4 -0
+
+A policy databases restrict the possibilities of connections to own, see and
+talk to well-known names. It can be associated with a bus (through a policy
+holder connection) or a custom endpoint.

ISTM metadata items on bus names should be replaced with policy that applies to the domain as a whole and governs bus creation.

Quoted 6 lines

No, well-known names are bound to buses, so a bus is really the right place to hold policy about which process is allowed to claim them. Every user is allowed to create a bus of its own, there's no policy for that, and there shouldn't be.

It has nothing to do with metadata items.

But it does -- the creator of the bus binds metadata to that bus at creation time.

I think that a better solution would be to have a global policy that says, for example, "to create the bus called 'system', the creator must have selinux label xyz" or "to create a user bus called uid-1000-privileged-ui-bus the creator must have some cgroup" or whatever.

Quoted 4 lines

Although maybe a better solution would leave this in the kernel but allow any cgroup to create a bus with a same that indicates the creating cgroup. Then I could have my desktop shell create a "/cgroup/path/to/desktop" for per-user privileged things.

We enforce the UID as first entity of the bus name. Again, this is our default policy because we rely on user-based access control. If we want more fine-grained access-control, we can introduce other policies at any time. For instance, we could enforce "cg-<cgroup>-<busname>" later on, where the kernel requires the caller to prefix the bus with "cg-<cgroup>-", where <cgroup> is the cgroup-path encoded in some way.

We provide one policy as default, and we have a use-case for it. Further policies are always welcome as extensions later on. I don't see why we should provide all those right from the beginning without any users right now.

Quoted 37 lines
Quoted 37 lines
Quoted 36 lines
Quoted 23 lines
Documentation/kdbus.txt new file +22 -0
+A set of policy rules is described by a name and multiple access rules, defined
+by the following struct.
+
+struct kdbus_policy_access {
+  __u64 type;  /* USER, GROUP, WORLD */
+    One of the following.
+
+    KDBUS_POLICY_ACCESS_USER
+      Grant access to a user with the uid stored in the 'id' field.
+
+    KDBUS_POLICY_ACCESS_GROUP
+      Grant access to a user with the gid stored in the 'id' field.
+
+    KDBUS_POLICY_ACCESS_WORLD
+      Grant access to everyone. The 'id' field is ignored.
+
+  __u64 access;        /* OWN, TALK, SEE */
+    The access to grant.
+
+    KDBUS_POLICY_SEE
+      Allow the name to be seen.
+

Documentation/kdbus.txt line 1358

Quoted 10 lines
Documentation/kdbus.txt new file +10 -0
+    KDBUS_POLICY_TALK
+      Allow the name to be talked to.
+
+    KDBUS_POLICY_OWN
+      Allow the name to be owned.
+
+  __u64 id;
+    For KDBUS_POLICY_ACCESS_USER, stores the uid.
+    For KDBUS_POLICY_ACCESS_GROUP, stores the gid.
+};

What happens if there are multiple matches?

Quoted 5 lines
Quoted 3 lines

We only have _granting_ policy entries. We search through the policy-db until we find an entry that grants access. We do _not_ stop on the first item that matches.

Yay! Can you document that more clearly?

Sure!

Quoted 31 lines
Quoted 23 lines
Quoted 17 lines
Quoted 4 lines
Documentation/kdbus.txt new file +2 -0
+
+11.4 TALK access and multiple well-known names per connection

Documentation/kdbus.txt line 1425

Quoted 10 lines
Documentation/kdbus.txt new file +10 -0
+-------------------------------------------------------------
+
+Note that TALK access is checked against all names of a connection.
+For example, if a connection owns both 'org.foo.bar' and 'org.blah.baz', and
+the policy database allows 'org.blah.baz' to be talked to by WORLD, then this
+permission is also granted to 'org.foo.bar'. That might sound illogical, but
+after all, we allow messages to be directed to either the name or a well-known
+name, and policy is applied to the connection, not the name. In other words,
+the effective TALK policy for a connection is the most permissive of all names
+the connection owns.

This does seem illogical. Does the recipient at least know which well-known name was addressed?

If the sender addressed it to a well-known name, yes. If the sender addressed the message to a unique-ID, there will be no such name, of course. Still, the policy applies to such transactions either way (standard D-Bus behavior).

Quoted 7 lines

Note however that dbus1 will not pass along the destination well-known name, hence most userspace libraries will ignore this information too, even if they run on kdbus which might pass this information around. The right way for services that carry multiple service names to discern which actual service is being talked to is having separate object paths for the different functionality to hide between the services.

Quoted 4 lines

It seems unfortunate to keep around this really weird behavior for the benefit of legacy applications. Could there perhaps be a flag that a connection can set to indicate that it understands per-destination access control and therefore wants stricter policy enforcement?

We actually think that it's a good idea not to use the destination name for doing different things, to make things more transparent. For example, we have tools that can explore the bus, introspect things (like d-bus), and they should show the same objects regardless by which name you access a service. It's more transparent then, and really just reduces names to some labels that make addressing things easier, but that are actually completely unnecessary for actual method invocations.

This behaviour is also relied on by a number of current bindings. For example GLib's implementation usually caches the unique name of a peer, and uses that for talking to remote objects (rather than always using the well-known name), in order to get an error back when a name becomes unavailable (maybe because a service died) or is moved to a different peer. If daemons would always take the destination name into account this kind of logic could never work.

It does take some time to get used to the fact that names are exclusively used for message routing and policies, not as target-entity of actual method calls. But the current dbus1 behaviour makes a ton of sense, and is really something we want to keep. It improves how clients can do life-cycle tracking of remote objects.

Note that D-Bus modeled unique-names and well-known-names after IP addresses and DNS names. It's a very similar model, and, like DNS names, well-known names have no effect on the routing of messages.

Quoted 21 lines
Quoted 21 lines
Quoted 9 lines

Documentation/kdbus.txt line 1443

Quoted 7 lines

+11.5 Implicit policies
+----------------------

Documentation/kdbus.txt new file +4 -0
+
+Depending on the type of the endpoint, a set of implicit rules might be
+enforced. On default endpoints, the following set is enforced:
+

How do these rules interact with installed policy?

As said before, all policy entries _grant_ access. We look through all entries until we find one that grants access.

Quoted 7 lines

Documentation/kdbus.txt line 1448

Quoted 5 lines
Documentation/kdbus.txt new file +5 -0
+  * Privileged connections always override any installed policy. Those
+    connections could easily install their own policies, so there is no
+    reason to enforce installed policies.
+  * Connections can always talk to connections of the same user. This
+    includes broadcast messages.

Why?

Quoted 7 lines
Quoted 2 lines

All limits on buses are enforced on a user<->user basis. We don't want to provide policies that are more fine-grained than our accounting.

This seems completely at odds with all the fine-grained metadata stuff. Also, anything that relies on this may get very confused when the LSM hooks go in, because I'm reasonably sure that the intent is for them to *not* follow this principle.

User-based accounting has always been the default, right? We are open to extend the API to support any other accounting scheme (LSM, cgroup-based, ...). But like bus-name-policies, I think it's fine to keep this as future extension. If you think the current design precludes LSM-based accounting, lemme know and we can fix it. But we have talked to LSM people before (and there have been patches on LKML), and they seemed fine with it.

Quoted 38 lines
Quoted 14 lines
Quoted 4 lines

If anyone ever strengthens the concept of identity to include things other than users (hmm -- there are already groups), this could be very limiting.

If user-based accounting is not suitable, you can create custom endpoints. Future extensions to that are always welcome. So far, the default user-based accounting was enough. And I think it's suitable as default.

Quoted 4 lines
Quoted 4 lines
Documentation/kdbus.txt new file +4 -0
+  * Connections that own names might send broadcast messages to other
+    connections that belong to a different user, but only if that
+    destination connection does not own any name.
+

(Also, what does "might" mean here?)

Quoted 4 lines
Quoted 3 lines

This is weird. It is also differently illogical than the "illogical" thing above.

Quoted 8 lines

Actually it follows the same model described above. If two connections are running under the same user then broadcasts are allowed, but if they are running under different users *and* if the destination owns a well-known name, then broadcasts are subject to TALK policy checks since that destination may own a restricted well-known name that is not interested in broadcasts. So this implicit policy is just fast-path for the common case where the target is subscribed to a broadcast and does not own any name.

Huh?

Say I have two users, "Sender" and "Receiver", each with a single connection. If Receiver owns no well-known names, then Sender can send to it. If Receiver owns one well-known name, then Sender needs to pass a TALK check on that name. If Reciever owns two well-known names, then Sender only needs to pass a TALK check on one of them.

Quoted 8 lines

Am I understanding this right? If I am, then I think this is in the category of baroque and inconsistent security rules which everyone will screw up and therefore introduce security vulnerabilities.

Can you really not enforce the much simpler rule that, to send to a name, you must have permission to send to *that* name? If legacy dbus1 receivers register two names and don't validate everything correctly, then only the legacy receivers have problems.

Sorry, I got confused here. That implicit policy is now dropped.

Quoted 29 lines
Quoted 22 lines
Quoted 4 lines
Quoted 4 lines

+
+13. Metadata
+===============================================================================

[snip]

Quoted 8 lines
Quoted 8 lines

+13.1 Known item types
+---------------------

Documentation/kdbus.txt new file +6 -0
+
+The following attach flags are currently supported.
+
+  KDBUS_ATTACH_TIMESTAMP
+    Attaches an item of type KDBUS_ITEM_TIMESTAMP which contains both the
+    monotonic and the realtime timestamp, taken when the message was
Quoted 8 lines

Documentation/kdbus.txt line 1540

Quoted 6 lines
Documentation/kdbus.txt new file +6 -0
+    processed on the kernel side.
+
+  KDBUS_ATTACH_CREDS
+    Attaches an item of type KDBUS_ITEM_CREDS, containing credentials as
+    described in kdbus_creds: the uid, gid, pid, tid and starttime of the task.
+

As mentioned last time, please remove or justify starttime.

Quoted 4 lines

starttime allows detecting PID overflows. Exposing the process starttime is useful to detect when a PID is getting reused. Unfortunately, we don't have 64bit pids, so we need the pid+time combination to avoid ambiguity.

NAK, I think.

Quoted 8 lines

I agree that PID overflow is a real issue and should be addressed somehow. But please address it for real instead of adding Yet Another Hack (tm). In the mean time, leave that hack out, please.

I would *love* to see PIDs have extra high bits at the end, done in a way that supports CRIU and that guarantees no reuse unless something privileged intentionally mis-programs it. But starttime isn't that mechanism.

The starttime logic sufficiently fixes the issue. If one great day in the future somebody invents some completely new concept for making this problem go away, we can look into that, but even then the field is still valuable for informational purposes. I mean, the kernel tracks this and exposes this in /proc for a reason...

In the meantime, we don't have any other way of solving this problem, so we'll leave this in.

Quoted 19 lines
Quoted 13 lines
Quoted 12 lines

Documentation/kdbus.txt line 1549

Quoted 10 lines
Documentation/kdbus.txt new file +9 -0
+  KDBUS_ATTACH_AUXGROUPS
+    Attaches an item of type KDBUS_ITEM_AUXGROUPS, containing a dynamic
+    number of auxiliary groups the sending task was a member of.
+
+  KDBUS_ATTACH_NAMES
+    Attaches items of type KDBUS_ITEM_OWNED_NAME, one for each name the sending
+    connection currently owns. The name and flags are stored in kdbus_item.name
+    for each of them.
+

That's interesting. What's it for?

Quoted 5 lines

It a valuable piece of information for receivers to know which bus names a sender has claimed. For instance, we need this information for the D-Bus proxy service, because we have to apply D-Bus1 policy in that case, and we need to get a list of owned names in a race-free manner to check the policy against.

Quoted 3 lines

But if you change the rule to the sensible one where you need permission to TALK to the name that you're talking to, this goes away, right?

This does not work if a message is directed at a unique-name, as explained above (or, think broadcasts).

Quoted 23 lines
Quoted 23 lines
Quoted 22 lines
Quoted 7 lines
Documentation/kdbus.txt new file +6 -0
+  KDBUS_ATTACH_TID_COMM
+    Attaches an items of type KDBUS_ITEM_TID_COMM, transporting the sending
+    task's 'comm', for the tid.  The string is stored in kdbus_item.str.
+
+  KDBUS_ATTACH_PID_COMM
+    Attaches an items of type KDBUS_ITEM_PID_COMM, transporting the sending

Documentation/kdbus.txt line 1565

Quoted 10 lines
Documentation/kdbus.txt new file +10 -0
+    task's 'comm', for the pid.  The string is stored in kdbus_item.str.
+
+  KDBUS_ATTACH_EXE
+    Attaches an item of type KDBUS_ITEM_EXE, containing the path to the
+    executable of the sending task, stored in kdbus_item.str.
+
+  KDBUS_ATTACH_CMDLINE
+    Attaches an item of type KDBUS_ITEM_CMDLINE, containing the command line
+    arguments of the sending task, as an array of strings, stored in
+    kdbus_item.str.

Please remove these four items. They are genuinely useless. Anything that uses them for anything is either buggy or should have asked the sender to put the value in the payload (and immediately wondered why it was doing that).

Quoted 8 lines
Quoted 5 lines

We use them for logging, debugging and monitoring. With our wireshark extension it's pretty useful to know the comm-name of a process when monitoring a bus. As we explained last time, this is not about security. We're aware that a process can modify them. We use them only as additional meta-data for logging and debugging.

Use the PID. Really. Your wireshark extention can look this crap up in /proc and, if it fails due to a race, big frickin' deal.

I see no reason for leaving it up to the client to do this extra work if it can as well be attached by the kernel, really.

We use the PID on dbus1 systems for cases like this. But it's actually too racy to be useful. For example, in systemd we ship a tiny binary that is used as cgroup agent, which just pushes a message about the fact it just got called for a cgroup onto the bus and then exits. Since it only runs for a very very short time, any peer which then tries to read the metadata off it is pretty likely to fail. And there are quite a number of processes like that, that just do one thing and die, especially in the early boot process. For none of them we currently can generate useful log metadata, because all we have is a PID that we have barely any useful information about.
This is a real race we get lots of bug-reports for. With kdbus we want to fix this, by optionally attaching this useful data to the message, so that the receiver can get the information when it wants to.

Quoted 17 lines
Quoted 9 lines

If we put those items into the payload, we have to transmit this data even if the destination process is not interested in this. Furthermore, each caller has to run multiple syscalls on each message to retrieve those values.

We use these items heavily for filtering and debugging, regardless of the payload protocol that is transmitted on the bus.

Quoted 7 lines

To give another specific use-case here: dbus supports bus activation, where a message sent to a non-running service causes it to be spawned implicitly without losing the message. Now, with such a scheme it is incredibly useful to be able to log which client caused a service to be triggered, hence we want to know the cmdline/exe/comm of the client. Not knowing this is a major pita when trying to trace the boot process and figuring out why a specific service got activated.

Quoted 1 line

Again, use the PID for tracing, please.

No. It's racy. Processes can die too quickly. And this is not a race that would be about security, but it's a real-life race that is just awful to run into when you try to trace what's going on on your system.

Quoted 19 lines

At the very least, make it impossible to specify these fields in the "must be received" set and rename them to something like KDBUS_INSTALL_UNRELIABLE_CMDLINE, etc, because they're unreliable

Finally, this stuff should only be readable by privileged users. And using the PID accomplishes that.

Quoted 5 lines

Also note that since v2 of the patch there's actually a per-sender mask for meta-data like this, hence a peer which doesn't want to pass its exec/cmdline/comm along can do that. Of course, this will seriously hamper debuggability and transparency...

Transparency is a terrible thing here.

How many users put passwords into things on the command line? Yes, it's a bad idea (for reasons that are entirely stupid), but now those passwords get *logged*.

Quoted 6 lines

If this is in the kernel, and someone complains that sensitive data is showing up on ten different logs on their system, they'll *correctly* blame the kernel. If you at least use the PID and restrict it to the logging code, then at least the bug report will go to the logging daemon, which will be *correctly* accused of doing something daft, and it can be fixed.

Hmm? Not following here. This information is visible via /proc too. If you hide it from /proc via the hide_pid logic, then it is also gone from the kdbus meta-data. Also, note again that clients that don't want this information to be passed to services can declare that now with their sender creds mask, introduced with v2.

Quoted 28 lines
Quoted 20 lines
Quoted 14 lines

Documentation/kdbus.txt line 1576

Quoted 12 lines
Documentation/kdbus.txt new file +11 -0
+
+  KDBUS_ATTACH_CGROUP
+    Attaches an item of type KDBUS_ITEM_CGROUP with the task's cgroup path.
+
+  KDBUS_ATTACH_CAPS
+    Attaches an item of type KDBUS_ITEM_CAPS, carrying sets of capabilities
+    that should be accessed via kdbus_item.caps.caps. Also, userspace should
+    be written in a way that it takes kdbus_item.caps.last_cap into account,
+    and derive the number of sets and rows from the item size and the reported
+    number of valid capability bits.
+

Please remove this, too, or justify its use.

cgroup information tells us which service is doing a bus request. This is useful for a variety of things. For example, the bus activation logging item above benefits from it. In general, if some message shall be logged about any client it is useful to know its service name.

Quoted 7 lines

Capabilities are useful to authenticate specific method calls. For example, when a client asks systemd to reboot, without this concept we can only check for UID==0 to decide whether to allow this. Breaking this down to capabilities in a race-free way has the benefit of allowing systemd to bind this to CAP_SYS_BOOT instead. There is no reason to deny a process with CAP_SYS_BOOT to reboot via bus-APIs, as they could just enforce it via syscalls, anyway.

Quoted 6 lines

With all due respect, BS.

I admit that there is probably no reason to deny systemd-based reboot to a CAP_SYS_BOOT-capable process, but there is absolutely no reason to give processes that are supposed to reboot using systemd the CAP_SYS_BOOT capability.

No, and this is not how this works. Note that for unpriviliged clients systemd checks PolicyKit in order to identify whether to allow certain priviliged operations. However, PolicyKit requires bus chatte, is slow and quite complex, hence the code shortcuts things if it knows that the client is priviliged anyway, and doesn't even bother with PolicyKit at all. This is where the caps come into play, since this shortcutting really should *NOT* be done for every single client, but only for those with the rights to do the operation anyway.

Hence, this is really not about overloading capabilities with new meanings. Instead it is about shortcutting policykit for priviliged clients. And this shortcutting should be as restricted as possible.

Quoted 4 lines

In any event, I suspect you'll have a hard time justifying this for anything other than CAP_SYS_BOOT. Just because CAP_SYS_ADMIN users can probably do whatever they want doesn't mean that systemd should make that a built-in policy.

Well, the other option for these APIs is to use the euid, which is hardly any better.

systemd-timedated shortcuts policykit if the client has CAP_SYS_TIME and tries to change the system clock. Similar, if a process asks logind to kill a session, we bypass pk if the client has CAP_KILL.

Quoted 2 lines

Also, wtf is the bounding set and such for? At the very least this should only be the effective set.

Yes, the code that makes use of this for shortcutting pk uses the effective set only. The other ones we allow sending across for enhancing logging of security operations.

In general: all creds we collect at the very least are incredibly useful for generating log records in a race-free fashion. As pointed out above the "race-free" bit alone solves real-world issues that are highly annoying if we don't have it.

Quoted 6 lines
Quoted 3 lines

We think it's a useful and reliable authentication method. Why should we remove it?

Because the implementation is buggy and therefore it's insecure? Remember that caps are namespaced in an interesting way.

Yes, we are well aware of the fact that we currently have no good way to translate a full set of capabilities from one user-ns to another. Hence, the only sane thing to do in such situations is to drop the entire item, which is what we do. Once we have a reliable way of translating things, we can add that to our code. Note that a set capability flag will only gain you more access level, so if caps are missing from a message, a user might only have *less* privileges, not more.

Quoted 10 lines
Quoted 5 lines

Anyway, these items are just optional. The sender can refuse the reveal them, and the item is only transmitted if the receiver opted in for it, too. So there's no need to drop any item type from the protocol.

No.

Because if receivers opt in to most of these, *they're doing it wrong*, and the kernel shouldn't be in the business of helping them.

No, they are not doing it "wrong". The services would do things wrong if they'd make security decisions on bits that cannot be acquired in a race-free way. And services do things in a dirty way if they'd generated logging data in a race-ful way (like you suggest), by reading things from /proc.

Thanks
David

#7 lore raw

Re: kdbus: add documentation

Quoted 34 lines · David Herrmann

Hi

Quoted 23 lines · Andy Lutomirski
Quoted 15 lines · David Herrmann

[snip]

Quoted 5 lines
Quoted 5 lines

+6.5 Getting information about a connection's bus creator
+--------------------------------------------------------

Documentation/kdbus.txt new file +3 -0
+
+The KDBUS_CMD_BUS_CREATOR_INFO ioctl takes the same struct as
+KDBUS_CMD_CONN_INFO but is used to retrieve information about the creator of
Quoted 8 lines

Documentation/kdbus.txt line 563

Quoted 4 lines
Documentation/kdbus.txt new file +4 -0
+the bus the connection is attached to. The metadata returned by this call is
+collected during the creation of the bus and is never altered afterwards, so
+it provides pristine information on the task that created the bus, at the
+moment when it did so.

What's this for? I understand the need for the creator of busses to be authenticated, but doing it like this mean that anyone who will *fail* authentication can DoS the authentic creator.

Quoted 4 lines

This returns information on a bus owner, to determine whether a connection is connected to a system, user or session bus. Note that the bus-creator itself is not a valid peer on the bus, so you cannot send messages to them. Which kind of DoS do you have in mind?

I assume that the logic is something like:

Quoted 7 lines

connect to bus
request bus metadata
if (bus metadata matches expectations) {
great, trust the bus!
} else {
oh crap!
}

Quoted 8 lines

Uh, no, this is really not the logic that should be assumed. It's more for code where you want to simply pass a bus fd, and the code knows nothing about it. Now, the code can derive some information from the bus fd, like for example who owns it. Then, depending on some of the creds returned it can determine whether to read configuration file set A or B and so on. This is particularly useful for all kinds of unprivileged bus services that end up running on any kind of bus and need to be able to figure out what they are actually operating on.

The logic you've described is more or less the same thing that I described with a process transition in. It's:

connect to bus
send kdbus fd to another process, which does the rest:
request bus metadata
if (bus metadata matches expectations) {
great, trust the bus!
} else {
oh crap! (or malfunction or whatever)
}

ISTM you should have an API to get the *name* of the bus and check that.

Except that, if the service you pass that fd to is privileged, then you're completely screwed, because none of this checks that the *domain* is correct.

[snip]

Quoted 17 lines
Quoted 17 lines
Quoted 16 lines
Quoted 10 lines

Documentation/kdbus.txt line 886

Quoted 6 lines
Documentation/kdbus.txt new file +5 -0
+
+Also, if the connection allowed for file descriptor to be passed
+(KDBUS_HELLO_ACCEPT_FD), and if the message contained any, they will be
+installed into the receiving process after the KDBUS_CMD_MSG_RECV ioctl
+returns. The receiving task is obliged to close all of them appropriately.

This makes it sound like fds are installed at receive time. What prevents resource exhaustion due to having excessive numbers of fds in transit (that are presumably not accounted to anyone)?

We have a per-user message accounting for undelivered messages, as well as a maximum number of pending messages per connection on the receiving end. These limits are accounted on a "user<->user" basis, so the limit of a user A will not affect two other users (B and C) talking.

Quoted 8 lines
Quoted 4 lines

But you can shove tons of fds in a message, and you can have lots of messages, and some of the fds can be fds of unix sockets that have fds queued up in them, and one of those fds could be the fd to the kdbus connection that sent the fd...

You cannot send kdbus-fds or unix-fds over kdbus, right now. We have people working on the AF_UNIX gc to make it more generic and include external types. Until then, we simply prevent recursive fd passing.

OK, fair enough.

Quoted 43 lines
Quoted 31 lines

This is not advice as to what to do about it, but I think that it will be a problem at some point.

Quoted 10 lines
Quoted 9 lines

Documentation/kdbus.txt line 1315

Quoted 6 lines

+11. Policy
+===============================================================================

Documentation/kdbus.txt new file +4 -0
+
+A policy databases restrict the possibilities of connections to own, see and
+talk to well-known names. It can be associated with a bus (through a policy
+holder connection) or a custom endpoint.

ISTM metadata items on bus names should be replaced with policy that applies to the domain as a whole and governs bus creation.

Quoted 6 lines

No, well-known names are bound to buses, so a bus is really the right place to hold policy about which process is allowed to claim them. Every user is allowed to create a bus of its own, there's no policy for that, and there shouldn't be.

It has nothing to do with metadata items.

But it does -- the creator of the bus binds metadata to that bus at creation time.

I think that a better solution would be to have a global policy that says, for example, "to create the bus called 'system', the creator must have selinux label xyz" or "to create a user bus called uid-1000-privileged-ui-bus the creator must have some cgroup" or whatever.

Quoted 4 lines

Although maybe a better solution would leave this in the kernel but allow any cgroup to create a bus with a same that indicates the creating cgroup. Then I could have my desktop shell create a "/cgroup/path/to/desktop" for per-user privileged things.

We enforce the UID as first entity of the bus name. Again, this is our default policy because we rely on user-based access control. If we want more fine-grained access-control, we can introduce other policies at any time. For instance, we could enforce "cg-<cgroup>-<busname>" later on, where the kernel requires the caller to prefix the bus with "cg-<cgroup>-", where <cgroup> is the cgroup-path encoded in some way.

Quoted 4 lines

We provide one policy as default, and we have a use-case for it. Further policies are always welcome as extensions later on. I don't see why we should provide all those right from the beginning without any users right now.

OK

Quoted 105 lines
Quoted 38 lines
Quoted 38 lines
Quoted 37 lines
Quoted 24 lines
Documentation/kdbus.txt new file +22 -0
+A set of policy rules is described by a name and multiple access rules, defined
+by the following struct.
+
+struct kdbus_policy_access {
+  __u64 type;  /* USER, GROUP, WORLD */
+    One of the following.
+
+    KDBUS_POLICY_ACCESS_USER
+      Grant access to a user with the uid stored in the 'id' field.
+
+    KDBUS_POLICY_ACCESS_GROUP
+      Grant access to a user with the gid stored in the 'id' field.
+
+    KDBUS_POLICY_ACCESS_WORLD
+      Grant access to everyone. The 'id' field is ignored.
+
+  __u64 access;        /* OWN, TALK, SEE */
+    The access to grant.
+
+    KDBUS_POLICY_SEE
+      Allow the name to be seen.
+

Documentation/kdbus.txt line 1358

Quoted 10 lines
Documentation/kdbus.txt new file +10 -0
+    KDBUS_POLICY_TALK
+      Allow the name to be talked to.
+
+    KDBUS_POLICY_OWN
+      Allow the name to be owned.
+
+  __u64 id;
+    For KDBUS_POLICY_ACCESS_USER, stores the uid.
+    For KDBUS_POLICY_ACCESS_GROUP, stores the gid.
+};

What happens if there are multiple matches?

Quoted 5 lines
Quoted 3 lines

We only have _granting_ policy entries. We search through the policy-db until we find an entry that grants access. We do _not_ stop on the first item that matches.

Yay! Can you document that more clearly?

Sure!

Quoted 31 lines
Quoted 23 lines
Quoted 17 lines
Quoted 4 lines
Documentation/kdbus.txt new file +2 -0
+
+11.4 TALK access and multiple well-known names per connection

Documentation/kdbus.txt line 1425

Quoted 10 lines
Documentation/kdbus.txt new file +10 -0
+-------------------------------------------------------------
+
+Note that TALK access is checked against all names of a connection.
+For example, if a connection owns both 'org.foo.bar' and 'org.blah.baz', and
+the policy database allows 'org.blah.baz' to be talked to by WORLD, then this
+permission is also granted to 'org.foo.bar'. That might sound illogical, but
+after all, we allow messages to be directed to either the name or a well-known
+name, and policy is applied to the connection, not the name. In other words,
+the effective TALK policy for a connection is the most permissive of all names
+the connection owns.

This does seem illogical. Does the recipient at least know which well-known name was addressed?

If the sender addressed it to a well-known name, yes. If the sender addressed the message to a unique-ID, there will be no such name, of course. Still, the policy applies to such transactions either way (standard D-Bus behavior).

Quoted 7 lines

Note however that dbus1 will not pass along the destination well-known name, hence most userspace libraries will ignore this information too, even if they run on kdbus which might pass this information around. The right way for services that carry multiple service names to discern which actual service is being talked to is having separate object paths for the different functionality to hide between the services.

Quoted 4 lines

It seems unfortunate to keep around this really weird behavior for the benefit of legacy applications. Could there perhaps be a flag that a connection can set to indicate that it understands per-destination access control and therefore wants stricter policy enforcement?

We actually think that it's a good idea not to use the destination name for doing different things, to make things more transparent. For example, we have tools that can explore the bus, introspect things (like d-bus), and they should show the same objects regardless by which name you access a service. It's more transparent then, and really just reduces names to some labels that make addressing things easier, but that are actually completely unnecessary for actual method invocations.

This behaviour is also relied on by a number of current bindings. For example GLib's implementation usually caches the unique name of a peer, and uses that for talking to remote objects (rather than always using the well-known name), in order to get an error back when a name becomes unavailable (maybe because a service died) or is moved to a different peer. If daemons would always take the destination name into account this kind of logic could never work.

It does take some time to get used to the fact that names are exclusively used for message routing and policies, not as target-entity of actual method calls. But the current dbus1 behaviour makes a ton of sense, and is really something we want to keep. It improves how clients can do life-cycle tracking of remote objects.

Quoted 3 lines

Note that D-Bus modeled unique-names and well-known-names after IP addresses and DNS names. It's a very similar model, and, like DNS names, well-known names have no effect on the routing of messages.

DNS names also have no effect on your ability to send to an IP.

In any event, I think you can keep doing everything that you're currently doing if you check policy on the actual sent-to name. Users will just apply the *same* policy to all of their names (or just use one name), and everything will work. And, for bonus points, the security rules will make sense.

Quoted 30 lines
Quoted 22 lines
Quoted 22 lines
Quoted 10 lines

Documentation/kdbus.txt line 1443

Quoted 8 lines

+11.5 Implicit policies
+----------------------

Documentation/kdbus.txt new file +4 -0
+
+Depending on the type of the endpoint, a set of implicit rules might be
+enforced. On default endpoints, the following set is enforced:
+

How do these rules interact with installed policy?

As said before, all policy entries _grant_ access. We look through all entries until we find one that grants access.

Quoted 7 lines

Documentation/kdbus.txt line 1448

Quoted 5 lines
Documentation/kdbus.txt new file +5 -0
+  * Privileged connections always override any installed policy. Those
+    connections could easily install their own policies, so there is no
+    reason to enforce installed policies.
+  * Connections can always talk to connections of the same user. This
+    includes broadcast messages.

Why?

Quoted 7 lines
Quoted 2 lines

All limits on buses are enforced on a user<->user basis. We don't want to provide policies that are more fine-grained than our accounting.

This seems completely at odds with all the fine-grained metadata stuff. Also, anything that relies on this may get very confused when the LSM hooks go in, because I'm reasonably sure that the intent is for them to *not* follow this principle.

Quoted 7 lines

User-based accounting has always been the default, right? We are open to extend the API to support any other accounting scheme (LSM, cgroup-based, ...). But like bus-name-policies, I think it's fine to keep this as future extension. If you think the current design precludes LSM-based accounting, lemme know and we can fix it. But we have talked to LSM people before (and there have been patches on LKML), and they seemed fine with it.

OK, as long as restricted endpoints don't work like this.

Quoted 43 lines
Quoted 43 lines
Quoted 15 lines
Quoted 5 lines

If anyone ever strengthens the concept of identity to include things other than users (hmm -- there are already groups), this could be very limiting.

If user-based accounting is not suitable, you can create custom endpoints. Future extensions to that are always welcome. So far, the default user-based accounting was enough. And I think it's suitable as default.

Quoted 4 lines
Quoted 4 lines
Documentation/kdbus.txt new file +4 -0
+  * Connections that own names might send broadcast messages to other
+    connections that belong to a different user, but only if that
+    destination connection does not own any name.
+

(Also, what does "might" mean here?)

Quoted 4 lines
Quoted 3 lines

This is weird. It is also differently illogical than the "illogical" thing above.

Quoted 8 lines

Actually it follows the same model described above. If two connections are running under the same user then broadcasts are allowed, but if they are running under different users *and* if the destination owns a well-known name, then broadcasts are subject to TALK policy checks since that destination may own a restricted well-known name that is not interested in broadcasts. So this implicit policy is just fast-path for the common case where the target is subscribed to a broadcast and does not own any name.

Huh?

Say I have two users, "Sender" and "Receiver", each with a single connection. If Receiver owns no well-known names, then Sender can send to it. If Receiver owns one well-known name, then Sender needs to pass a TALK check on that name. If Reciever owns two well-known names, then Sender only needs to pass a TALK check on one of them.

Am I understanding this right? If I am, then I think this is in the category of baroque and inconsistent security rules which everyone will screw up and therefore introduce security vulnerabilities.

Quoted 7 lines
Quoted 4 lines

Can you really not enforce the much simpler rule that, to send to a name, you must have permission to send to *that* name? If legacy dbus1 receivers register two names and don't validate everything correctly, then only the legacy receivers have problems.

Sorry, I got confused here. That implicit policy is now dropped.

Sounds good.

Quoted 38 lines
Quoted 29 lines
Quoted 22 lines
Quoted 4 lines
Quoted 4 lines

+
+13. Metadata
+===============================================================================

[snip]

Quoted 8 lines
Quoted 8 lines

+13.1 Known item types
+---------------------

Documentation/kdbus.txt new file +6 -0
+
+The following attach flags are currently supported.
+
+  KDBUS_ATTACH_TIMESTAMP
+    Attaches an item of type KDBUS_ITEM_TIMESTAMP which contains both the
+    monotonic and the realtime timestamp, taken when the message was
Quoted 8 lines

Documentation/kdbus.txt line 1540

Quoted 6 lines
Documentation/kdbus.txt new file +6 -0
+    processed on the kernel side.
+
+  KDBUS_ATTACH_CREDS
+    Attaches an item of type KDBUS_ITEM_CREDS, containing credentials as
+    described in kdbus_creds: the uid, gid, pid, tid and starttime of the task.
+

As mentioned last time, please remove or justify starttime.

Quoted 4 lines

starttime allows detecting PID overflows. Exposing the process starttime is useful to detect when a PID is getting reused. Unfortunately, we don't have 64bit pids, so we need the pid+time combination to avoid ambiguity.

NAK, I think.

Quoted 8 lines

I agree that PID overflow is a real issue and should be addressed somehow. But please address it for real instead of adding Yet Another Hack (tm). In the mean time, leave that hack out, please.

I would *love* to see PIDs have extra high bits at the end, done in a way that supports CRIU and that guarantees no reuse unless something privileged intentionally mis-programs it. But starttime isn't that mechanism.

Quoted 9 lines

The starttime logic sufficiently fixes the issue. If one great day in the future somebody invents some completely new concept for making this problem go away, we can look into that, but even then the field is still valuable for informational purposes. I mean, the kernel tracks this and exposes this in /proc for a reason...

In the meantime, we don't have any other way of solving this problem, so we'll leave this in.

But this set of patches doesn't "leave this in". This set of patches *adds it*. Designing a poor new API is not excused by the fact that no one has developed the better one yet.

Quoted 19 lines
Quoted 19 lines
Quoted 18 lines
Quoted 12 lines

Documentation/kdbus.txt line 1549

Quoted 10 lines
Documentation/kdbus.txt new file +9 -0
+  KDBUS_ATTACH_AUXGROUPS
+    Attaches an item of type KDBUS_ITEM_AUXGROUPS, containing a dynamic
+    number of auxiliary groups the sending task was a member of.
+
+  KDBUS_ATTACH_NAMES
+    Attaches items of type KDBUS_ITEM_OWNED_NAME, one for each name the sending
+    connection currently owns. The name and flags are stored in kdbus_item.name
+    for each of them.
+

That's interesting. What's it for?

It a valuable piece of information for receivers to know which bus names a sender has claimed. For instance, we need this information for the D-Bus proxy service, because we have to apply D-Bus1 policy in that case, and we need to get a list of owned names in a race-free manner to check the policy against.

Quoted 6 lines
Quoted 3 lines

But if you change the rule to the sensible one where you need permission to TALK to the name that you're talking to, this goes away, right?

This does not work if a message is directed at a unique-name, as explained above (or, think broadcasts).

Is the issue that, if I send a proxied request to unique name foo, and unique name foo is help by someone who's claimed /a/b/c, then the proxy service needs to check for permission to talk to /a/b/c?

To me, this still feels like this is only an issue because of this weird concept of how names and policies interact. I really think that you should put some extra effort into making the policy matches self-contained in the sense of only matching on addressing information that's actually in the message.

For example, HELLO could indicate one of "anyone can talk to me" or "no one can talk to me without using a well-known name", then the problem is solved. Protocols that switch to using the unique name (e.g. glib) can send *both* the unique and well-known name and the access control will still work.

Quoted 36 lines
Quoted 24 lines
Quoted 24 lines
Quoted 23 lines
Quoted 8 lines
Documentation/kdbus.txt new file +6 -0
+  KDBUS_ATTACH_TID_COMM
+    Attaches an items of type KDBUS_ITEM_TID_COMM, transporting the sending
+    task's 'comm', for the tid.  The string is stored in kdbus_item.str.
+
+  KDBUS_ATTACH_PID_COMM
+    Attaches an items of type KDBUS_ITEM_PID_COMM, transporting the sending

Documentation/kdbus.txt line 1565

Quoted 10 lines
Documentation/kdbus.txt new file +10 -0
+    task's 'comm', for the pid.  The string is stored in kdbus_item.str.
+
+  KDBUS_ATTACH_EXE
+    Attaches an item of type KDBUS_ITEM_EXE, containing the path to the
+    executable of the sending task, stored in kdbus_item.str.
+
+  KDBUS_ATTACH_CMDLINE
+    Attaches an item of type KDBUS_ITEM_CMDLINE, containing the command line
+    arguments of the sending task, as an array of strings, stored in
+    kdbus_item.str.

Please remove these four items. They are genuinely useless. Anything that uses them for anything is either buggy or should have asked the sender to put the value in the payload (and immediately wondered why it was doing that).

Quoted 8 lines
Quoted 5 lines

We use them for logging, debugging and monitoring. With our wireshark extension it's pretty useful to know the comm-name of a process when monitoring a bus. As we explained last time, this is not about security. We're aware that a process can modify them. We use them only as additional meta-data for logging and debugging.

Use the PID. Really. Your wireshark extention can look this crap up in /proc and, if it fails due to a race, big frickin' deal.

I see no reason for leaving it up to the client to do this extra work if it can as well be attached by the kernel, really.

Quoted 14 lines

We use the PID on dbus1 systems for cases like this. But it's actually too racy to be useful. For example, in systemd we ship a tiny binary that is used as cgroup agent, which just pushes a message about the fact it just got called for a cgroup onto the bus and then exits. Since it only runs for a very very short time, any peer which then tries to read the metadata off it is pretty likely to fail. And there are quite a number of processes like that, that just do one thing and die, especially in the early boot process. For none of them we currently can generate useful log metadata, because all we have is a PID that we have barely any useful information about.
This is a real race we get lots of bug-reports for. With kdbus we want to fix this, by optionally attaching this useful data to the message, so that the receiver can get the information when it wants to.

I really don't think that this kind of mostly indiscriminate broadcasting of almost-invariably unnecessary and potentially dangerous information is justified by the limited logging and debugging benefit. I think you should find a better design that solves your problem.

[snip]

Quoted 13 lines
Quoted 6 lines

Transparency is a terrible thing here.

How many users put passwords into things on the command line? Yes, it's a bad idea (for reasons that are entirely stupid), but now those passwords get *logged*.

Quoted 6 lines

If this is in the kernel, and someone complains that sensitive data is showing up on ten different logs on their system, they'll *correctly* blame the kernel. If you at least use the PID and restrict it to the logging code, then at least the bug report will go to the logging daemon, which will be *correctly* accused of doing something daft, and it can be fixed.

Quoted 6 lines

Hmm? Not following here. This information is visible via /proc too. If you hide it from /proc via the hide_pid logic, then it is also gone from the kdbus meta-data. Also, note again that clients that don't want this information to be passed to services can declare that now with their sender creds mask, introduced with v2.

We're talking about users, not senders, and users aren't going to expect that they're sending their command line arond the bus. And there could also receivers who are sandboxed and can't access /proc.

My point is that this information is probably okay to expose to privileged logging daemons, and *maybe* to journald, but it's not okay to pass anywhere else.

Quoted 44 lines
Quoted 28 lines
Quoted 20 lines
Quoted 14 lines

Documentation/kdbus.txt line 1576

Quoted 12 lines
Documentation/kdbus.txt new file +11 -0
+
+  KDBUS_ATTACH_CGROUP
+    Attaches an item of type KDBUS_ITEM_CGROUP with the task's cgroup path.
+
+  KDBUS_ATTACH_CAPS
+    Attaches an item of type KDBUS_ITEM_CAPS, carrying sets of capabilities
+    that should be accessed via kdbus_item.caps.caps. Also, userspace should
+    be written in a way that it takes kdbus_item.caps.last_cap into account,
+    and derive the number of sets and rows from the item size and the reported
+    number of valid capability bits.
+

Please remove this, too, or justify its use.

cgroup information tells us which service is doing a bus request. This is useful for a variety of things. For example, the bus activation logging item above benefits from it. In general, if some message shall be logged about any client it is useful to know its service name.

Quoted 7 lines

Capabilities are useful to authenticate specific method calls. For example, when a client asks systemd to reboot, without this concept we can only check for UID==0 to decide whether to allow this. Breaking this down to capabilities in a race-free way has the benefit of allowing systemd to bind this to CAP_SYS_BOOT instead. There is no reason to deny a process with CAP_SYS_BOOT to reboot via bus-APIs, as they could just enforce it via syscalls, anyway.

Quoted 6 lines

With all due respect, BS.

I admit that there is probably no reason to deny systemd-based reboot to a CAP_SYS_BOOT-capable process, but there is absolutely no reason to give processes that are supposed to reboot using systemd the CAP_SYS_BOOT capability.

No, and this is not how this works. Note that for unpriviliged clients systemd checks PolicyKit in order to identify whether to allow certain priviliged operations. However, PolicyKit requires bus chatte, is slow and quite complex, hence the code shortcuts things if it knows that the client is priviliged anyway, and doesn't even bother with PolicyKit at all. This is where the caps come into play, since this shortcutting really should *NOT* be done for every single client, but only for those with the rights to do the operation anyway.

Quoted 3 lines

Hence, this is really not about overloading capabilities with new meanings. Instead it is about shortcutting policykit for priviliged clients. And this shortcutting should be as restricted as possible.

So this mechanism is there to speed up reboot and similar things?

Quoted 8 lines
Quoted 5 lines

In any event, I suspect you'll have a hard time justifying this for anything other than CAP_SYS_BOOT. Just because CAP_SYS_ADMIN users can probably do whatever they want doesn't mean that systemd should make that a built-in policy.

Well, the other option for these APIs is to use the euid, which is hardly any better.

It absolutely is better. You can, in software, change the rules, and euid works intelligently in namespaces. Aside from being a bad idea, caps are just *broken* without knowledge of the userns hierarchy *and* userns ownership information.

ns_capable is the in-kernel interface, but the return value of ns_capable can't be calculated from just the cap mask.

Also, have you ever tried to usefully assign caps to euid != 0 users? It's essentially entirely broken, especially if you try to use execve. Don't force the use of the crappy fscaps interface to allow non-root to reboot cleanly without invoking policykit -- you won't be doing anyone any favors. Just set your userspace policy the way you want it.

I've tried to fix this, I've written patches, I've designed alternative and IMO far superior cap transition rules. Guess what? They're not in the kernel because no one wants to touch caps. But that doesn't mean that the existing cap system is anything other than a giant pile of cr*p that happens to sort of work. Don't make user code have to deal with the mess more than it already has to.

Quoted 8 lines

systemd-timedated shortcuts policykit if the client has CAP_SYS_TIME and tries to change the system clock. Similar, if a process asks logind to kill a session, we bypass pk if the client has CAP_KILL.

Quoted 2 lines

Also, wtf is the bounding set and such for? At the very least this should only be the effective set.

Quoted 8 lines

Yes, the code that makes use of this for shortcutting pk uses the effective set only. The other ones we allow sending across for enhancing logging of security operations.

In general: all creds we collect at the very least are incredibly useful for generating log records in a race-free fashion. As pointed out above the "race-free" bit alone solves real-world issues that are highly annoying if we don't have it.

I find it highly implausible that kdbus logging users really benefit from knowing the *caps* of other participants in any context in which their euid isn't enough.

Quoted 8 lines
Quoted 7 lines
Quoted 4 lines

We think it's a useful and reliable authentication method. Why should we remove it?

Because the implementation is buggy and therefore it's insecure? Remember that caps are namespaced in an interesting way.

Quoted 8 lines

Yes, we are well aware of the fact that we currently have no good way to translate a full set of capabilities from one user-ns to another. Hence, the only sane thing to do in such situations is to drop the entire item, which is what we do. Once we have a reliable way of translating things, we can add that to our code. Note that a set capability flag will only gain you more access level, so if caps are missing from a message, a user might only have *less* privileges, not more.

Or you could remove it in the absence of a real legitimate use case.

Quoted 9 lines
Quoted 9 lines
Quoted 6 lines

Anyway, these items are just optional. The sender can refuse the reveal them, and the item is only transmitted if the receiver opted in for it, too. So there's no need to drop any item type from the protocol.

No.

Quoted 8 lines
Quoted 2 lines

Because if receivers opt in to most of these, *they're doing it wrong*, and the kernel shouldn't be in the business of helping them.

No, they are not doing it "wrong". The services would do things wrong if they'd make security decisions on bits that cannot be acquired in a race-free way. And services do things in a dirty way if they'd generated logging data in a race-ful way (like you suggest), by reading things from /proc.

Then find a clean way that's gated on having the right /proc access, which is not guaranteed to exist on all of your eventual users' systems, and, if that access doesn't exist because the admin or sandbox designer has sensibly revoked it, then kdbus shouldn't override them.

--Andy

#8 lore raw

Re: kdbus: add documentation

Quoted 5 lines · Andy Lutomirski

Then find a clean way that's gated on having the right /proc access, which is not guaranteed to exist on all of your eventual users' systems, and, if that access doesn't exist because the admin or sandbox designer has sensibly revoked it, then kdbus shouldn't override them.

One idea: add a sysctl that defaults to off that enables these metadata items, and keep it disabled on production systems. Then you get your debugging and everyone else gets unsurprising behavior.

--Andy

Quoted 2 lines

--Andy

Signature · 2 lines
Andy Lutomirski
AMA Capital Management, LLC
#9 lore raw

Re: kdbus: add documentation

In reply to Andy Lutomirski

* Andy Lutomirski:

Quoted 2 lines

At the risk of opening a can of worms, wouldn't this be much more useful if you could share a pool between multiple connections?

They would also be useful to reduce context switches when receiving data from all kinds of descriptors. At present, when polling, you receive notification, and then you have to call into the kernel, again, to actually fetch the data and associated information. The kernel could also queue the data for one specific recipient, addressing the same issue that SO_REUSEPORT tries to solve (on poll notification, the kernel does not know which recipient will eventually retrieve the data, so it has to notify and wake up all of them).

#10 lore raw

Re: kdbus: add documentation

Hi

Quoted 9 lines · Florian Weimer

* Andy Lutomirski:

Quoted 2 lines

At the risk of opening a can of worms, wouldn't this be much more useful if you could share a pool between multiple connections?

They would also be useful to reduce context switches when receiving data from all kinds of descriptors. At present, when polling, you receive notification, and then you have to call into the kernel, again, to actually fetch the data and associated information.

poll(2) and friends cannot return data for changed descriptors. I think a single trap for each KDBUS_CMD_MSG_RECV is acceptable. If this turns out to be a bottleneck, we can provide bulk-operations in the future. Anyway, I don't see how a _shared_ pool would change any of this?

Quoted 4 lines

kernel could also queue the data for one specific recipient, addressing the same issue that SO_REUSEPORT tries to solve (on poll notification, the kernel does not know which recipient will eventually retrieve the data, so it has to notify and wake up all of them).

We already queue data only for the addressed recipients. We *do* know all recipients of a message at poll-notification time. We only wake up recipients that actually got a message queued.

Not sure how this is related to SO_REUSEPORT. Can you elaborate on your optimizations?

Thanks
David

#11 lore raw

Re: kdbus: add documentation

* David Herrmann:

Quoted 5 lines

poll(2) and friends cannot return data for changed descriptors. I think a single trap for each KDBUS_CMD_MSG_RECV is acceptable. If this turns out to be a bottleneck, we can provide bulk-operations in the future. Anyway, I don't see how a _shared_ pool would change any of this?

I responded to Andy's messages because it seemed to be about generalizing the pool functionality.

Quoted 8 lines
Quoted 4 lines

kernel could also queue the data for one specific recipient, addressing the same issue that SO_REUSEPORT tries to solve (on poll notification, the kernel does not know which recipient will eventually retrieve the data, so it has to notify and wake up all of them).

We already queue data only for the addressed recipients. We *do* know all recipients of a message at poll-notification time. We only wake up recipients that actually got a message queued.

Exactly, but poll on, say, UDP sockets, does not work this way. What I'm trying to say is that this functionality is interesting for much more than kdbus.

Quoted 2 lines

Not sure how this is related to SO_REUSEPORT. Can you elaborate on your optimizations?

Without something like SO_REUSEPORT, it is a bad idea to have multiple threads polling the same socket. The semantics are such that the kernel has to wake *all* the waiting threads, and one of them will eventually pick up the datagram with a separate system call. But the kernel does not know which thread this will be.

With SO_REUSEPORT and a separately created socket for each polling thread, the kernel will only signal one poll operation because it assumes that any of the waiting threads will process the datagram, so it's sufficient just to notify one of them.

kdbus behaves like the latter, but also saves the need to separately obtain the datagram and related data from the kernel.

#12 lore raw

Re: kdbus: add documentation

In reply to Greg Kroah-Hartman

* Greg Kroah-Hartman:

Documentation/kdbus.txt line 7

Quoted 5 lines
Documentation/kdbus.txt new file +5 -0
+The focus of this document is an overview of the low-level, native kernel D-Bus
+transport called kdbus. Kdbus exposes its functionality via files in a
+filesystem called 'kdbusfs'. All communication between processes takes place
+via ioctls on files exposed through the mount point of a kdbusfs. The default
+mount point of kdbusfs is /sys/fs/kdbus.

Does this mean the bus does not enforce the correctness of the D-Bus introspection metadata? That's really unfortunate. Classic D-Bus does not do this, either, and combined with the variety of approaches used to implement D-Bus endpoints, it makes it really difficult to figure out what D-Bus services, exactly, a process provides.

#13 lore raw

Re: kdbus: add documentation

Hi

Quoted 13 lines · Florian Weimer

* Greg Kroah-Hartman:

Documentation/kdbus.txt line 7

Quoted 5 lines
Documentation/kdbus.txt new file +5 -0
+The focus of this document is an overview of the low-level, native kernel D-Bus
+transport called kdbus. Kdbus exposes its functionality via files in a
+filesystem called 'kdbusfs'. All communication between processes takes place
+via ioctls on files exposed through the mount point of a kdbusfs. The default
+mount point of kdbusfs is /sys/fs/kdbus.

Does this mean the bus does not enforce the correctness of the D-Bus introspection metadata? That's really unfortunate. Classic D-Bus does not do this, either, and combined with the variety of approaches used to implement D-Bus endpoints, it makes it really difficult to figure out what D-Bus services, exactly, a process provides.

kdbus operates on the transport-level only. We never touch or look at transferred data. As such, DBus introspection data as defined by org.freedesktop.DBus.Introspectable is not verified by the transport layer.

Thanks
David

#14 lore raw

Re: kdbus: add documentation

In reply to Greg Kroah-Hartman

* Greg Kroah-Hartman:

Documentation/kdbus.txt line 886

Quoted 6 lines

+7.4 Receiving messages

Documentation/kdbus.txt new file +4 -0
+Also, if the connection allowed for file descriptor to be passed
+(KDBUS_HELLO_ACCEPT_FD), and if the message contained any, they will be
+installed into the receiving process after the KDBUS_CMD_MSG_RECV ioctl
+returns. The receiving task is obliged to close all of them appropriately.

What happens if this is not possible because the file descriptor limit of the processes would be exceeded? EMFILE, and the message will not be received?

#15 lore raw

Re: kdbus: add documentation

Hi

Quoted 4 lines · Florian Weimer

* Greg Kroah-Hartman:

Quoted 1 line

+7.4 Receiving messages

Quoted 8 lines

Documentation/kdbus.txt line 886

Quoted 4 lines
Documentation/kdbus.txt new file +4 -0
+Also, if the connection allowed for file descriptor to be passed
+(KDBUS_HELLO_ACCEPT_FD), and if the message contained any, they will be
+installed into the receiving process after the KDBUS_CMD_MSG_RECV ioctl
+returns. The receiving task is obliged to close all of them appropriately.

What happens if this is not possible because the file descriptor limit of the processes would be exceeded? EMFILE, and the message will not be received?

The message is returned without installing the FDs. This is signaled by EMFILE, but a valid pool offset.

Thanks
David

#16 lore raw

Re: kdbus: add documentation

* David Herrmann:

Quoted 11 lines · Florian Weimer
Quoted 7 lines

* Greg Kroah-Hartman:

Quoted 1 line

+7.4 Receiving messages

What happens if this is not possible because the file descriptor limit of the processes would be exceeded? EMFILE, and the message will not be received?

The message is returned without installing the FDs. This is signaled by EMFILE, but a valid pool offset.

Oh. This is really surprising, so it needs documentation. But it's probably better than the alternative (return EMFILE and leave the message stuck, so that you receive it immediately again—this behavior makes non-blocking accept rather difficult to use correctly).

#17 lore raw

Re: kdbus: add documentation

Daniel, David,

Quoted 11 lines · Florian Weimer

* David Herrmann:

Quoted 9 lines · Florian Weimer
Quoted 7 lines

* Greg Kroah-Hartman:

Quoted 1 line

+7.4 Receiving messages

What happens if this is not possible because the file descriptor limit of the processes would be exceeded? EMFILE, and the message will not be received?

Quoted 7 lines
Quoted 2 lines

The message is returned without installing the FDs. This is signaled by EMFILE, but a valid pool offset.

Oh. This is really surprising, so it needs documentation. But it's probably better than the alternative (return EMFILE and leave the message stuck, so that you receive it immediately again—this behavior makes non-blocking accept rather difficult to use correctly).

So, was this point in the end explicitly documented? I not obvious that it is documented in the revised kdbus.txt that Greg K-H sent out 4 days ago.

Thanks,

Michael

Signature · 3 lines
Michael Kerrisk
Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/
Linux/UNIX System Programming Training: http://man7.org/training/
#18 lore raw

Re: kdbus: add documentation

Hi Michael,

Quoted 15 lines · Michael Kerrisk (man-pages)
Quoted 14 lines · Florian Weimer

* David Herrmann:

Quoted 11 lines · Florian Weimer
Quoted 7 lines

* Greg Kroah-Hartman:

Quoted 1 line

+7.4 Receiving messages

What happens if this is not possible because the file descriptor limit of the processes would be exceeded? EMFILE, and the message will not be received?

The message is returned without installing the FDs. This is signaled by EMFILE, but a valid pool offset.

Quoted 8 lines
Quoted 4 lines

Oh. This is really surprising, so it needs documentation. But it's probably better than the alternative (return EMFILE and leave the message stuck, so that you receive it immediately again—this behavior makes non-blocking accept rather difficult to use correctly).

So, was this point in the end explicitly documented? I not obvious that it is documented in the revised kdbus.txt that Greg K-H sent out 4 days ago.

No, we've revisited this point and changed the kernel behavior again in v3. We're no longer returning -EMFILE in this case, but rather set KDBUS_RECV_RETURN_INCOMPLETE_FDS in a new field in the receive ioctl struct called 'return_flags'. We believe that's a nicer way of signaling specific errors. The message will carry -1 for all FDs that failed to get installed, so the user can actually see which one is missing.

That's also documented in kdbus.txt, but we missed putting it into the Changelog - sorry for that.

Hope this helps,
Daniel

#19 lore raw

Re: kdbus: add documentation

Quoted 34 lines · Daniel Mack

Hi Michael,

Quoted 15 lines · Michael Kerrisk (man-pages)
Quoted 14 lines · Florian Weimer

* David Herrmann:

Quoted 11 lines · Florian Weimer
Quoted 7 lines

* Greg Kroah-Hartman:

Quoted 1 line

+7.4 Receiving messages

What happens if this is not possible because the file descriptor limit of the processes would be exceeded? EMFILE, and the message will not be received?

The message is returned without installing the FDs. This is signaled by EMFILE, but a valid pool offset.

Quoted 8 lines
Quoted 4 lines

Oh. This is really surprising, so it needs documentation. But it's probably better than the alternative (return EMFILE and leave the message stuck, so that you receive it immediately again—this behavior makes non-blocking accept rather difficult to use correctly).

So, was this point in the end explicitly documented? I not obvious that it is documented in the revised kdbus.txt that Greg K-H sent out 4 days ago.

No, we've revisited this point and changed the kernel behavior again in v3. We're no longer returning -EMFILE in this case, but rather set KDBUS_RECV_RETURN_INCOMPLETE_FDS in a new field in the receive ioctl struct called 'return_flags'. We believe that's a nicer way of signaling specific errors. The message will carry -1 for all FDs that failed to get installed, so the user can actually see which one is missing.

Quoted 2 lines

That's also documented in kdbus.txt, but we missed putting it into the Changelog - sorry for that.

Thanks for the info, Daniel.

Cheers,

Michael

Signature · 3 lines
Michael Kerrisk
Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/
Linux/UNIX System Programming Training: http://man7.org/training/
#20 lore raw

kdbus: add header file

In reply to Greg Kroah-Hartman

From: Daniel Mack <[email protected]>

This patch adds the header file which describes the low-level transport protocol used by various ioctls. The header file is located in include/uapi/linux/ as it is shared between kernel and userspace, and it only contains data structure definitionsi, enums and #defines for constants.

---
 include/uapi/linux/Kbuild  |   1 +
 include/uapi/linux/kdbus.h | 933 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 934 insertions(+)
 create mode 100644 include/uapi/linux/kdbus.h
include/uapi/linux/Kbuild +1 -0
index 4c94f31a8c99..84239f6a3210 100644
@@ -212,6 +212,7 @@ header-y += ixjuser.h
 header-y += jffs2.h
 header-y += joystick.h
 header-y += kd.h
+header-y += kdbus.h
 header-y += kdev_t.h
 header-y += kernel-page-flags.h
 header-y += kernel.h
include/uapi/linux/kdbus.h new file +933 -0

933 lines not on this page · raw message

Signature · 1 line
2.1.3
#21 lore raw

Re: kdbus: add header file

Quoted 4 lines · Greg Kroah-Hartman

From: Daniel Mack <[email protected]>
…

include/uapi/linux/kdbus.h new file +1 -0
+

include/uapi/linux/kdbus.h line 636

Quoted 10 lines
include/uapi/linux/kdbus.h new file +10 -0
+/**
+ * enum kdbus_make_flags - Flags for KDBUS_CMD_{BUS,EP,NS}_MAKE
+ * @KDBUS_MAKE_ACCESS_GROUP:	Make the device node group-accessible
+ * @KDBUS_MAKE_ACCESS_WORLD:	Make the device node world-accessible
+ */
+enum kdbus_make_flags {
+	KDBUS_MAKE_ACCESS_GROUP		= 1ULL <<  0,
+	KDBUS_MAKE_ACCESS_WORLD		= 1ULL <<  1,
+};
+

"device node"

…

Quoted 7 lines

+/**
+ * Ioctl API
+ * KDBUS_CMD_BUS_MAKE: After opening the "control" device node, this
+ * command creates a new bus with the specified
+ * name. The bus is immediately shut down and
+ * cleaned up when the opened "control" device node
+ * is closed.

"device node"

Quoted 7 lines

+ * KDBUS_CMD_ENDPOINT_MAKE: Creates a new named special endpoint to talk to
+ * the bus. Such endpoints usually carry a more
+ * restrictive policy and grant restricted access
+ * to specific applications.
+ * KDBUS_CMD_HELLO: By opening the bus device node a connection is
+ * created. After a HELLO the opened connection
+ * becomes an active peer on the bus.

"device node"

#22 lore raw

Re: kdbus: add header file

Hi Harald,

Quoted 4 lines · Harald Hoyer
Quoted 2 lines · Greg Kroah-Hartman

From: Daniel Mack <[email protected]>
…

Quoted 13 lines

include/uapi/linux/kdbus.h line 636

Quoted 11 lines
include/uapi/linux/kdbus.h new file +11 -0
+
+/**
+ * enum kdbus_make_flags - Flags for KDBUS_CMD_{BUS,EP,NS}_MAKE
+ * @KDBUS_MAKE_ACCESS_GROUP:	Make the device node group-accessible
+ * @KDBUS_MAKE_ACCESS_WORLD:	Make the device node world-accessible
+ */
+enum kdbus_make_flags {
+	KDBUS_MAKE_ACCESS_GROUP		= 1ULL <<  0,
+	KDBUS_MAKE_ACCESS_WORLD		= 1ULL <<  1,
+};
+

"device node"

Yes, these are indeed oversights from the old implementation. Fixed now upstream, along with the other details in kdbus.txt and some more elsewhere in the tree.

Thanks,
Daniel

#23 lore raw

kdbus: add driver skeleton, ioctl entry points and utility functions

In reply to Greg Kroah-Hartman

From: Daniel Mack <[email protected]>

Add the basic driver structure.

handle.c is the main ioctl command dispatcher that calls into other parts of the driver.

main.c contains the code that creates the initial domain at startup, and util.c has utility functions such as item iterators that are shared with other files.

limits.h describes limits on things like maximum data structure sizes, number of messages per users and suchlike. Some of the numbers currently picked are rough ideas of what what might be sufficient and are probably rather conservative.

---
 Documentation/ioctl/ioctl-number.txt |   1 +
 ipc/kdbus/handle.c                   | 993 +++++++++++++++++++++++++++++++++++
 ipc/kdbus/handle.h                   |  20 +
 ipc/kdbus/limits.h                   |  77 +++
 ipc/kdbus/main.c                     |  59 +++
 ipc/kdbus/util.c                     | 166 ++++++
 ipc/kdbus/util.h                     | 103 ++++
 7 files changed, 1419 insertions(+)
 create mode 100644 ipc/kdbus/handle.c
 create mode 100644 ipc/kdbus/handle.h
 create mode 100644 ipc/kdbus/limits.h
 create mode 100644 ipc/kdbus/main.c
 create mode 100644 ipc/kdbus/util.c
 create mode 100644 ipc/kdbus/util.h
Documentation/ioctl/ioctl-number.txt +1 -0
index 8136e1fd30fd..54e091ebb862 100644
@@ -292,6 +292,7 @@ Code  Seq#(hex)	Include File		Comments
 0x92	00-0F	drivers/usb/mon/mon_bin.c
 0x93	60-7F	linux/auto_fs.h
 0x94	all	fs/btrfs/ioctl.h
+0x95	all	uapi/linux/kdbus.h	kdbus IPC driver
 0x97	00-7F	fs/ceph/ioctl.h		Ceph file system
 0x99	00-0F				537-Addinboard driver
 					<mailto:[email protected]>
ipc/kdbus/handle.c new file +993 -0

993 lines not on this page · raw message

ipc/kdbus/handle.h new file +20 -0
new file mode 100644
index 000000000000..32809dad3720
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2013-2014 Kay Sievers
+ * Copyright (C) 2013-2014 Greg Kroah-Hartman <[email protected]>
+ * Copyright (C) 2013-2014 Daniel Mack <[email protected]>
+ * Copyright (C) 2013-2014 David Herrmann <[email protected]>
+ * Copyright (C) 2013-2014 Linux Foundation
+ *
+ * kdbus is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ */
+
+#ifndef __KDBUS_HANDLE_H
+#define __KDBUS_HANDLE_H
+
+extern const struct file_operations kdbus_handle_ep_ops;
+extern const struct file_operations kdbus_handle_control_ops;
+
+#endif
ipc/kdbus/limits.h new file +77 -0

77 lines not on this page · raw message

ipc/kdbus/main.c new file +59 -0

59 lines not on this page · raw message

ipc/kdbus/util.c new file +166 -0

166 lines not on this page · raw message

ipc/kdbus/util.h new file +103 -0

103 lines not on this page · raw message

Signature · 1 line
2.1.3
#24 lore raw

kdbus: add connection pool implementation

In reply to Greg Kroah-Hartman

From: Daniel Mack <[email protected]>

A pool for data received from the kernel is installed for every connection of the bus, and it is used to copy data from the kernel to userspace clients, for messages and other information.

It is accessed when one of the following ioctls is issued:

* KDBUS_CMD_MSG_RECV, to receive a message
* KDBUS_CMD_NAME_LIST, to dump the name registry
* KDBUS_CMD_CONN_INFO, to retrieve information on a connection

The offsets returned by either one of the aforementioned ioctls describe offsets inside the pool. Internally, the pool is organized in slices, that are dynamically allocated on demand. The overall size of the pool is chosen by the connection when it connects to the bus with KDBUS_CMD_HELLO.

In order to make the slice available for subsequent calls, KDBUS_CMD_FREE has to be called on the offset.

To access the memory, the caller is expected to mmap() it to its task.

---
 ipc/kdbus/pool.c | 722 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 ipc/kdbus/pool.h |  44 ++++
 2 files changed, 766 insertions(+)
 create mode 100644 ipc/kdbus/pool.c
 create mode 100644 ipc/kdbus/pool.h
ipc/kdbus/pool.c new file +722 -0
new file mode 100644
index 000000000000..3bf4ab426d3b
@@ -0,0 +1,722 @@
+/*
+ * Copyright (C) 2013-2014 Kay Sievers
+ * Copyright (C) 2013-2014 Greg Kroah-Hartman <[email protected]>
+ * Copyright (C) 2013-2014 Daniel Mack <[email protected]>
+ * Copyright (C) 2013-2014 David Herrmann <[email protected]>
+ * Copyright (C) 2013-2014 Linux Foundation
+ *
+ * kdbus is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ */
+
+#include <linux/aio.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/highmem.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/pagemap.h>
+#include <linux/rbtree.h>
+#include <linux/sched.h>
+#include <linux/shmem_fs.h>
+#include <linux/sizes.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+#include "pool.h"
+#include "util.h"
+
+/**
+ * struct kdbus_pool - the receiver's buffer
+ * @f:			The backing shmem file
+ * @size:		The size of the file
+ * @busy:		The currently used size
+ * @lock:		Pool data lock
+ * @slices:		All slices sorted by address
+ * @slices_busy:	Tree of allocated slices
+ * @slices_free:	Tree of free slices
+ *
+ * The receiver's buffer, managed as a pool of allocated and free
+ * slices containing the queued messages.
+ *
+ * Messages sent with KDBUS_CMD_MSG_SEND are copied direcly by the
+ * sending process into the receiver's pool.
+ *
+ * Messages received with KDBUS_CMD_MSG_RECV just return the offset
+ * to the data placed in the pool.
+ *
+ * The internally allocated memory needs to be returned by the receiver
+ * with KDBUS_CMD_MSG_FREE.
+ */
+struct kdbus_pool {
+	struct file *f;
+	size_t size;
+	size_t busy;
+	struct mutex lock;
+
+	struct list_head slices;
+	struct rb_root slices_busy;
+	struct rb_root slices_free;
+};
+
+/**
+ * struct kdbus_pool_slice - allocated element in kdbus_pool
+ * @pool:		Pool this slice belongs to
+ * @off:		Offset of slice in the shmem file
+ * @size:		Size of slice
+ * @entry:		Entry in "all slices" list
+ * @rb_node:		Entry in free or busy list
+ * @free:		Unused slice
+ * @public:		Slice was exposed to userspace and may be freed
+ *			with KDBUS_CMD_FREE.
+ *
+ * The pool has one or more slices, always spanning the entire size of the
+ * pool.
+ *
+ * Every slice is an element in a list sorted by the buffer address, to
+ * provide access to the next neighbor slice.
+ *
+ * Every slice is member in either the busy or the free tree. The free
+ * tree is organized by slice size, the busy tree organized by buffer
+ * offset.
+ */
+struct kdbus_pool_slice {
+	struct kdbus_pool *pool;
+	size_t off;
+	size_t size;
+
+	struct list_head entry;
+	struct rb_node rb_node;
+	bool free;
+	bool public;
+};
+
+static struct kdbus_pool_slice *kdbus_pool_slice_new(struct kdbus_pool *pool,
+						     size_t off, size_t size)
+{
+	struct kdbus_pool_slice *slice;
+
+	slice = kzalloc(sizeof(*slice), GFP_KERNEL);
+	if (!slice)
+		return NULL;
+
+	slice->pool = pool;
+	slice->off = off;
+	slice->size = size;
+	slice->free = true;
+	slice->public = false;
+	return slice;
+}
+
+/* insert a slice into the free tree */
+static void kdbus_pool_add_free_slice(struct kdbus_pool *pool,
+				      struct kdbus_pool_slice *slice)
+{
+	struct rb_node **n;
+	struct rb_node *pn = NULL;
+
+	n = &pool->slices_free.rb_node;
+	while (*n) {
+		struct kdbus_pool_slice *pslice;
+
+		pn = *n;
+		pslice = rb_entry(pn, struct kdbus_pool_slice, rb_node);
+		if (slice->size < pslice->size)
+			n = &pn->rb_left;
+		else
+			n = &pn->rb_right;
+	}
+
+	rb_link_node(&slice->rb_node, pn, n);
+	rb_insert_color(&slice->rb_node, &pool->slices_free);
+}
+
+/* insert a slice into the busy tree */
+static void kdbus_pool_add_busy_slice(struct kdbus_pool *pool,
+				      struct kdbus_pool_slice *slice)
+{
+	struct rb_node **n;
+	struct rb_node *pn = NULL;
+
+	n = &pool->slices_busy.rb_node;
+	while (*n) {
+		struct kdbus_pool_slice *pslice;
+
+		pn = *n;
+		pslice = rb_entry(pn, struct kdbus_pool_slice, rb_node);
+		if (slice->off < pslice->off)
+			n = &pn->rb_left;
+		else if (slice->off > pslice->off)
+			n = &pn->rb_right;
+	}
+
+	rb_link_node(&slice->rb_node, pn, n);
+	rb_insert_color(&slice->rb_node, &pool->slices_busy);
+}
+
+static struct kdbus_pool_slice *kdbus_pool_find_slice(struct kdbus_pool *pool,
+						      size_t off)
+{
+	struct rb_node *n;
+
+	n = pool->slices_busy.rb_node;
+	while (n) {
+		struct kdbus_pool_slice *s;
+
+		s = rb_entry(n, struct kdbus_pool_slice, rb_node);
+		if (off < s->off)
+			n = n->rb_left;
+		else if (off > s->off)
+			n = n->rb_right;
+		else
+			return s;
+	}
+
+	return NULL;
+}
+
+/**
+ * kdbus_pool_slice_alloc() - allocate memory from a pool
+ * @pool:		The receiver's pool
+ * @size:		The number of bytes to allocate
+ *
+ * The returned slice is used for kdbus_pool_slice_free() to
+ * free the allocated memory.
+ *
+ * Return: the allocated slice on success, ERR_PTR on failure.
+ */
+struct kdbus_pool_slice *kdbus_pool_slice_alloc(struct kdbus_pool *pool,
+						size_t size)
+{
+	size_t slice_size = KDBUS_ALIGN8(size);
+	struct rb_node *n, *found = NULL;
+	struct kdbus_pool_slice *s;
+	int ret = 0;
+
+	/* search a free slice with the closest matching size */
+	mutex_lock(&pool->lock);
+	n = pool->slices_free.rb_node;
+	while (n) {
+		s = rb_entry(n, struct kdbus_pool_slice, rb_node);
+		if (slice_size < s->size) {
+			found = n;
+			n = n->rb_left;
+		} else if (slice_size > s->size) {
+			n = n->rb_right;
+		} else {
+			found = n;
+			break;
+		}
+	}
+
+	/* no slice with the minimum size found in the pool */
+	if (!found) {
+		ret = -ENOBUFS;
+		goto exit_unlock;
+	}
+
+	/* no exact match, use the closest one */
+	if (!n)
+		s = rb_entry(found, struct kdbus_pool_slice, rb_node);
+
+	/* move slice from free to the busy tree */
+	rb_erase(found, &pool->slices_free);
+	kdbus_pool_add_busy_slice(pool, s);
+
+	/* we got a slice larger than what we asked for? */
+	if (s->size > slice_size) {
+		struct kdbus_pool_slice *s_new;
+
+		/* split-off the remainder of the size to its own slice */
+		s_new = kdbus_pool_slice_new(pool, s->off + slice_size,
+					     s->size - slice_size);
+		if (!s_new) {
+			ret = -ENOMEM;
+			goto exit_unlock;
+		}
+
+		list_add(&s_new->entry, &s->entry);
+		kdbus_pool_add_free_slice(pool, s_new);
+
+		/* adjust our size now that we split-off another slice */
+		s->size = slice_size;
+	}
+
+	s->free = false;
+	s->public = false;
+	pool->busy += s->size;
+	mutex_unlock(&pool->lock);
+
+	return s;
+
+exit_unlock:
+	mutex_unlock(&pool->lock);
+	return ERR_PTR(ret);
+}
+
+static void __kdbus_pool_slice_free(struct kdbus_pool_slice *slice)
+{
+	struct kdbus_pool *pool = slice->pool;
+
+	BUG_ON(slice->free);
+
+	rb_erase(&slice->rb_node, &pool->slices_busy);
+	pool->busy -= slice->size;
+
+	/* merge with the next free slice */
+	if (!list_is_last(&slice->entry, &pool->slices)) {
+		struct kdbus_pool_slice *s;
+
+		s = list_entry(slice->entry.next,
+			       struct kdbus_pool_slice, entry);
+		if (s->free) {
+			rb_erase(&s->rb_node, &pool->slices_free);
+			list_del(&s->entry);
+			slice->size += s->size;
+			kfree(s);
+		}
+	}
+
+	/* merge with previous free slice */
+	if (pool->slices.next != &slice->entry) {
+		struct kdbus_pool_slice *s;
+
+		s = list_entry(slice->entry.prev, struct kdbus_pool_slice,
+			       entry);
+		if (s->free) {
+			rb_erase(&s->rb_node, &pool->slices_free);
+			list_del(&slice->entry);
+			s->size += slice->size;
+			kfree(slice);
+			slice = s;
+		}
+	}
+
+	slice->free = true;
+	kdbus_pool_add_free_slice(pool, slice);
+}
+
+/**
+ * kdbus_pool_slice_free() - give allocated memory back to the pool
+ * @slice:		Slice allocated from the the pool
+ *
+ * The slice was returned by the call to kdbus_pool_alloc_slice(), the
+ * memory is returned to the pool.
+ */
+void kdbus_pool_slice_free(struct kdbus_pool_slice *slice)
+{
+	struct kdbus_pool *pool = slice->pool;
+
+	mutex_lock(&pool->lock);
+	__kdbus_pool_slice_free(slice);
+	mutex_unlock(&pool->lock);
+}
+
+/**
+ * kdbus_pool_release_offset() - release a public offset
+ * @pool:		pool to operate on
+ * @off:		offset to release
+ *
+ * This should be called whenever user-space frees a slice given to them. It
+ * verifies the slice is available and public, and then drops it. It ensures
+ * correct locking and barriers against queues.
+ *
+ * Return: 0 on success, ENXIO if the offset is invalid, EINVAL if the offset is
+ * valid but not public.
+ */
+int kdbus_pool_release_offset(struct kdbus_pool *pool, size_t off)
+{
+	struct kdbus_pool_slice *slice;
+	int ret = 0;
+
+	mutex_lock(&pool->lock);
+	slice = kdbus_pool_find_slice(pool, off);
+	if (slice) {
+		if (slice->public)
+			__kdbus_pool_slice_free(slice);
+		else
+			ret = -EINVAL;
+	} else {
+		ret = -ENXIO;
+	}
+	mutex_unlock(&pool->lock);
+
+	return ret;
+}
+
+/**
+ * kdbus_pool_slice_offset() - return the slice's offset inside the pool
+ * @slice:		The slice
+ *
+ * Return: the offset in bytes.
+ */
+size_t kdbus_pool_slice_offset(const struct kdbus_pool_slice *slice)
+{
+	return slice->off;
+}
+
+/**
+ * kdbus_pool_slice_make_public() - set a slice's public flag to true
+ * @slice:		The slice
+ */
+void kdbus_pool_slice_make_public(struct kdbus_pool_slice *slice)
+{
+	slice->public = true;
+}
+
+/**
+ * kdbus_pool_new() - create a new pool
+ * @name:		Name of the (deleted) file which shows up in
+ *			/proc, used for debugging
+ * @size:		Maximum size of the pool
+ *
+ * Return: a new kdbus_pool on success, ERR_PTR on failure.
+ */
+struct kdbus_pool *kdbus_pool_new(const char *name, size_t size)
+{
+	struct kdbus_pool_slice *s;
+	struct kdbus_pool *p;
+	struct file *f;
+	char *n = NULL;
+	int ret;
+
+	p = kzalloc(sizeof(*p), GFP_KERNEL);
+	if (!p)
+		return ERR_PTR(-ENOMEM);
+
+	if (name) {
+		n = kasprintf(GFP_KERNEL, KBUILD_MODNAME "-conn:%s", name);
+		if (!n) {
+			ret = -ENOMEM;
+			goto exit_free;
+		}
+	}
+
+	f = shmem_file_setup(n ?: KBUILD_MODNAME "-conn", size, VM_NORESERVE);
+	kfree(n);
+
+	if (IS_ERR(f)) {
+		ret = PTR_ERR(f);
+		goto exit_free;
+	}
+
+	ret = get_write_access(file_inode(f));
+	if (ret < 0)
+		goto exit_put_shmem;
+
+	/* allocate first slice spanning the entire pool */
+	s = kdbus_pool_slice_new(p, 0, size);
+	if (!s) {
+		ret = -ENOMEM;
+		goto exit_put_write;
+	}
+
+	p->f = f;
+	p->size = size;
+	p->busy = 0;
+	p->slices_free = RB_ROOT;
+	p->slices_busy = RB_ROOT;
+	mutex_init(&p->lock);
+
+	INIT_LIST_HEAD(&p->slices);
+	list_add(&s->entry, &p->slices);
+
+	kdbus_pool_add_free_slice(p, s);
+	return p;
+
+exit_put_write:
+	put_write_access(file_inode(f));
+exit_put_shmem:
+	fput(f);
+exit_free:
+	kfree(p);
+	return ERR_PTR(ret);
+}
+
+/**
+ * kdbus_pool_free() - destroy pool
+ * @pool:		The receiver's pool
+ */
+void kdbus_pool_free(struct kdbus_pool *pool)
+{
+	struct kdbus_pool_slice *s, *tmp;
+
+	if (!pool)
+		return;
+
+	list_for_each_entry_safe(s, tmp, &pool->slices, entry) {
+		list_del(&s->entry);
+		kfree(s);
+	}
+
+	put_write_access(file_inode(pool->f));
+	fput(pool->f);
+	kfree(pool);
+}
+
+/**
+ * kdbus_pool_remain() - the number of free bytes in the pool
+ * @pool:		The receiver's pool
+ *
+ * Return: the number of unallocated bytes in the pool
+ */
+size_t kdbus_pool_remain(struct kdbus_pool *pool)
+{
+	size_t size;
+
+	mutex_lock(&pool->lock);
+	size = pool->size - pool->busy;
+	mutex_unlock(&pool->lock);
+
+	return size;
+}
+
+/* copy data from a file to a page in the receiver's pool */
+static int kdbus_pool_copy_file(struct page *p, size_t start,
+				struct file *f, size_t off, size_t count)
+{
+	loff_t o = off;
+	char *kaddr;
+	ssize_t n;
+
+	kaddr = kmap(p);
+	n = f->f_op->read(f, (char __force __user *)kaddr + start, count, &o);
+	kunmap(p);
+	if (n < 0)
+		return n;
+	if (n != count)
+		return -EFAULT;
+
+	return 0;
+}
+
+/* copy data to a page in the receiver's pool */
+static int kdbus_pool_copy_data(struct page *p, size_t start,
+				const void __user *from, size_t count)
+{
+	unsigned long remain;
+	char *kaddr;
+
+	if (fault_in_pages_readable(from, count) < 0)
+		return -EFAULT;
+
+	kaddr = kmap_atomic(p);
+	pagefault_disable();
+	remain = __copy_from_user_inatomic(kaddr + start, from, count);
+	pagefault_enable();
+	kunmap_atomic(kaddr);
+	if (remain > 0)
+		return -EFAULT;
+
+	cond_resched();
+	return 0;
+}
+
+/* copy data to the receiver's pool */
+static size_t kdbus_pool_copy(const struct kdbus_pool_slice *slice, size_t off,
+			      const void __user *data, struct file *f_src,
+			      size_t off_src, size_t len)
+{
+	struct file *f_dst = slice->pool->f;
+	struct address_space *mapping = f_dst->f_mapping;
+	const struct address_space_operations *aops = mapping->a_ops;
+	unsigned long fpos = slice->off + off;
+	unsigned long rem = len;
+	size_t pos = 0;
+	int ret = 0;
+
+	BUG_ON(off + len > slice->size);
+	BUG_ON(slice->free);
+
+	while (rem > 0) {
+		struct page *p;
+		unsigned long o;
+		unsigned long n;
+		void *fsdata;
+		int status;
+
+		o = fpos & (PAGE_CACHE_SIZE - 1);
+		n = min_t(unsigned long, PAGE_CACHE_SIZE - o, rem);
+
+		status = aops->write_begin(f_dst, mapping, fpos, n, 0, &p,
+					   &fsdata);
+		if (status) {
+			ret = -EFAULT;
+			break;
+		}
+
+		if (data)
+			ret = kdbus_pool_copy_data(p, o, data + pos, n);
+		else
+			ret = kdbus_pool_copy_file(p, o, f_src,
+						   off_src + pos, n);
+		mark_page_accessed(p);
+
+		status = aops->write_end(f_dst, mapping, fpos, n, n, p, fsdata);
+
+		if (ret < 0)
+			break;
+		if (status != n) {
+			ret = -EFAULT;
+			break;
+		}
+
+		pos += n;
+		fpos += n;
+		rem -= n;
+	}
+
+	return ret;
+}
+
+/**
+ * kdbus_pool_slice_copy_user() - copy user memory to a slice
+ * @slice:		The slice to write to
+ * @off:		Offset in the slice to write to
+ * @data:		User memory to copy from
+ * @len:		Number of bytes to copy
+ *
+ * The offset was returned by the call to kdbus_pool_alloc_slice().
+ * The user memory at @data will be copied to the @off in the allocated
+ * slice in the pool.
+ *
+ * Return: the numbers of bytes copied, negative errno on failure.
+ */
+ssize_t
+kdbus_pool_slice_copy_user(const struct kdbus_pool_slice *slice, size_t off,
+			   const void __user *data, size_t len)
+{
+	return kdbus_pool_copy(slice, off, data, NULL, 0, len);
+}
+
+/**
+ * kdbus_pool_slice_copy() - copy kernel memory to a slice
+ * @slice:		The slice to write to
+ * @off:		Offset in the slice to write to
+ * @data:		Kernel memory to copy from
+ * @len:		Number of bytes to copy
+ *
+ * The slice was returned by the call to kdbus_pool_alloc_slice().
+ * The user memory at @data will be copied to the @off in the allocated
+ * slice in the pool.
+ *
+ * Return: the numbers of bytes copied, negative errno on failure.
+ */
+ssize_t kdbus_pool_slice_copy(const struct kdbus_pool_slice *slice, size_t off,
+			      const void *data, size_t len)
+{
+	mm_segment_t old_fs;
+	ssize_t ret;
+
+	old_fs = get_fs();
+	set_fs(get_ds());
+	ret = kdbus_pool_copy(slice, off,
+			      (const void __user *)data, NULL, 0, len);
+	set_fs(old_fs);
+
+	return ret;
+}
+
+/**
+ * kdbus_pool_slice_move() - move memory from one pool into another one
+ * @src_pool:		The receiver's pool to copy from
+ * @dst_pool:		The receiver's pool to copy to
+ * @slice:		Reference to the slice to copy from the source;
+ *			updated with the newly allocated slice in the
+ *			destination
+ *
+ * Move memory from one pool to another. Memory will be allocated in the
+ * destination pool, the memory copied over, and the free()d in source
+ * pool.
+ *
+ * Return: 0 on success, negative errno on failure.
+ */
+int kdbus_pool_slice_move(struct kdbus_pool *src_pool,
+			  struct kdbus_pool *dst_pool,
+			  struct kdbus_pool_slice **slice)
+{
+	mm_segment_t old_fs;
+	struct kdbus_pool_slice *slice_new;
+	int ret;
+
+	slice_new = kdbus_pool_slice_alloc(dst_pool, (*slice)->size);
+	if (IS_ERR(slice_new))
+		return PTR_ERR(slice_new);
+
+	old_fs = get_fs();
+	set_fs(get_ds());
+	ret = kdbus_pool_copy(slice_new, 0, NULL,
+			      src_pool->f, (*slice)->off, (*slice)->size);
+	set_fs(old_fs);
+	if (ret < 0)
+		goto exit_free;
+
+	kdbus_pool_slice_free(*slice);
+
+	*slice = slice_new;
+	return 0;
+
+exit_free:
+	kdbus_pool_slice_free(slice_new);
+	return ret;
+}
+
+/**
+ * kdbus_pool_slice_flush() - flush dcache memory area of a slice
+ * @slice:		The allocated slice to flush
+ *
+ * Dcache flushes are delayed to happen only right before the receiver
+ * gets the new buffer area announced. The mapped buffer is always
+ * read-only for the receiver, and only the area of the announced message
+ * needs to be flushed.
+ */
+void kdbus_pool_slice_flush(const struct kdbus_pool_slice *slice)
+{
+#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE == 1
+	struct address_space *mapping = slice->pool->f->f_mapping;
+	pgoff_t first = slice->off >> PAGE_CACHE_SHIFT;
+	pgoff_t last = (slice->off + slice->size +
+			PAGE_CACHE_SIZE-1) >> PAGE_CACHE_SHIFT;
+	pgoff_t i;
+
+	for (i = first; i < last; i++) {
+		struct page *page;
+
+		page = find_get_page(mapping, i);
+		if (!page)
+			continue;
+
+		flush_dcache_page(page);
+		put_page(page);
+	}
+#endif
+}
+
+/**
+ * kdbus_pool_mmap() -  map the pool into the process
+ * @pool:		The receiver's pool
+ * @vma:		passed by mmap() syscall
+ *
+ * Return: the result of the mmap() call, negative errno on failure.
+ */
+int kdbus_pool_mmap(const struct kdbus_pool *pool, struct vm_area_struct *vma)
+{
+	/* deny write access to the pool */
+	if (vma->vm_flags & VM_WRITE)
+		return -EPERM;
+	vma->vm_flags &= ~VM_MAYWRITE;
+
+	/* do not allow to map more than the size of the file */
+	if ((vma->vm_end - vma->vm_start) > pool->size)
+		return -EFAULT;
+
+	/* replace the connection file with our shmem file */
+	if (vma->vm_file)
+		fput(vma->vm_file);
+	vma->vm_file = get_file(pool->f);
+
+	return pool->f->f_op->mmap(pool->f, vma);
+}
ipc/kdbus/pool.h new file +44 -0

44 lines not on this page · raw message

Signature · 1 line
2.1.3
#25 lore raw

kdbus: add connection, queue handling and message validation code

In reply to Greg Kroah-Hartman

From: Daniel Mack <[email protected]>

This patch adds code to create and destroy connections, to validate incoming messages and to maintain the queue of messages that are associated with a connection.

Note that connection and queue have a 1:1 relation, the code is only split in two parts for cleaner separation and better readability.

---
 ipc/kdbus/connection.c | 1838 ++++++++++++++++++++++++++++++++++++++++++++++++
 ipc/kdbus/connection.h |  188 +++++
 ipc/kdbus/item.c       |  258 +++++++
 ipc/kdbus/item.h       |   41 ++
 ipc/kdbus/message.c    |  444 ++++++++++++
 ipc/kdbus/message.h    |   75 ++
 ipc/kdbus/queue.c      |  608 ++++++++++++++++
 ipc/kdbus/queue.h      |   93 +++
 ipc/kdbus/util.h       |    2 +-
 9 files changed, 3546 insertions(+), 1 deletion(-)
 create mode 100644 ipc/kdbus/connection.c
 create mode 100644 ipc/kdbus/connection.h
 create mode 100644 ipc/kdbus/item.c
 create mode 100644 ipc/kdbus/item.h
 create mode 100644 ipc/kdbus/message.c
 create mode 100644 ipc/kdbus/message.h
 create mode 100644 ipc/kdbus/queue.c
 create mode 100644 ipc/kdbus/queue.h
ipc/kdbus/connection.c new file +1838 -0
new file mode 100644
index 000000000000..73d149eecc25
@@ -0,0 +1,1838 @@
+/*
+ * Copyright (C) 2013-2014 Kay Sievers
+ * Copyright (C) 2013-2014 Greg Kroah-Hartman <[email protected]>
+ * Copyright (C) 2013-2014 Daniel Mack <[email protected]>
+ * Copyright (C) 2013-2014 David Herrmann <[email protected]>
+ * Copyright (C) 2013-2014 Linux Foundation
+ * Copyright (C) 2014 Djalal Harouni
+ *
+ * kdbus is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ */
+
+#include <linux/audit.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/hashtable.h>
+#include <linux/idr.h>
+#include <linux/init.h>
+#include <linux/math64.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/shmem_fs.h>
+#include <linux/sizes.h>
+#include <linux/slab.h>
+#include <linux/syscalls.h>
+
+#include "bus.h"
+#include "connection.h"
+#include "endpoint.h"
+#include "match.h"
+#include "message.h"
+#include "metadata.h"
+#include "names.h"
+#include "domain.h"
+#include "item.h"
+#include "notify.h"
+#include "policy.h"
+#include "util.h"
+#include "queue.h"
+
+#define KDBUS_CONN_ACTIVE_BIAS (INT_MIN + 1)
+
+/**
+ * struct kdbus_conn_reply - an entry of kdbus_conn's list of replies
+ * @kref:		Ref-count of this object
+ * @entry:		The entry of the connection's reply_list
+ * @reply_dst:		The connection the reply will be sent to (method origin)
+ * @queue_entry:	The queue enty item that is prepared by the replying
+ *			connection
+ * @deadline_ns:	The deadline of the reply, in nanoseconds
+ * @cookie:		The cookie of the requesting message
+ * @name_id:		ID of the well-known name the original msg was sent to
+ * @sync:		The reply block is waiting for synchronous I/O
+ * @waiting:		The condition to synchronously wait for
+ * @interrupted:	The sync reply was left in an interrupted state
+ * @err:		The error code for the synchronous reply
+ */
+struct kdbus_conn_reply {
+	struct kref kref;
+	struct list_head entry;
+	struct kdbus_conn *reply_dst;
+	struct kdbus_queue_entry *queue_entry;
+	u64 deadline_ns;
+	u64 cookie;
+	u64 name_id;
+	bool sync:1;
+	bool waiting:1;
+	bool interrupted:1;
+	int err;
+};
+
+static struct kdbus_conn_reply *
+kdbus_conn_reply_new(struct kdbus_conn *reply_dst,
+		     const struct kdbus_msg *msg,
+		     struct kdbus_name_entry *name_entry)
+{
+	bool sync = msg->flags & KDBUS_MSG_FLAGS_SYNC_REPLY;
+	struct kdbus_conn_reply *r;
+	int ret = 0;
+
+	if (atomic_inc_return(&reply_dst->reply_count) >
+	    KDBUS_CONN_MAX_REQUESTS_PENDING) {
+		ret = -EMLINK;
+		goto exit_dec_reply_count;
+	}
+
+	r = kzalloc(sizeof(*r), GFP_KERNEL);
+	if (!r) {
+		ret = -ENOMEM;
+		goto exit_dec_reply_count;
+	}
+
+	kref_init(&r->kref);
+	r->reply_dst = kdbus_conn_ref(reply_dst);
+	r->cookie = msg->cookie;
+	r->name_id = name_entry ? name_entry->name_id : 0;
+	r->deadline_ns = msg->timeout_ns;
+
+	if (sync) {
+		r->sync = true;
+		r->waiting = true;
+	}
+
+exit_dec_reply_count:
+	if (ret < 0) {
+		atomic_dec(&reply_dst->reply_count);
+		return ERR_PTR(ret);
+	}
+
+	return r;
+}
+
+static void __kdbus_conn_reply_free(struct kref *kref)
+{
+	struct kdbus_conn_reply *reply =
+		container_of(kref, struct kdbus_conn_reply, kref);
+
+	atomic_dec(&reply->reply_dst->reply_count);
+	kdbus_conn_unref(reply->reply_dst);
+	kfree(reply);
+}
+
+static struct kdbus_conn_reply*
+kdbus_conn_reply_ref(struct kdbus_conn_reply *r)
+{
+	if (r)
+		kref_get(&r->kref);
+	return r;
+}
+
+static struct kdbus_conn_reply*
+kdbus_conn_reply_unref(struct kdbus_conn_reply *r)
+{
+	if (r)
+		kref_put(&r->kref, __kdbus_conn_reply_free);
+	return NULL;
+}
+
+static void kdbus_conn_reply_sync(struct kdbus_conn_reply *reply, int err)
+{
+	BUG_ON(!reply->sync);
+
+	list_del_init(&reply->entry);
+	reply->waiting = false;
+	reply->err = err;
+	wake_up_interruptible(&reply->reply_dst->wait);
+}
+
+/*
+ * Check for maximum number of messages per individual user. This
+ * should prevent a single user from being able to fill the receiver's
+ * queue.
+ */
+static int kdbus_conn_queue_user_quota(const struct kdbus_conn *conn_src,
+				       struct kdbus_conn *conn_dst,
+				       struct kdbus_queue_entry *entry)
+{
+	struct kdbus_domain_user *user;
+
+	if (!conn_src)
+		return 0;
+
+	/*
+	 * Per-user accounting can be expensive if we have many different
+	 * users on the bus. Allow one set of messages to pass through
+	 * un-accounted. Only once we hit that limit, we start accounting.
+	 */
+	if (conn_dst->queue.msg_count < KDBUS_CONN_MAX_MSGS_PER_USER)
+		return 0;
+
+	user = conn_src->user;
+
+	/* extend array to store the user message counters */
+	if (user->idr >= conn_dst->msg_users_max) {
+		unsigned int *users;
+		unsigned int i;
+
+		i = 8 + KDBUS_ALIGN8(user->idr);
+		users = krealloc(conn_dst->msg_users, i * sizeof(unsigned int),
+				 GFP_KERNEL | __GFP_ZERO);
+		if (!users)
+			return -ENOMEM;
+
+		conn_dst->msg_users = users;
+		conn_dst->msg_users_max = i;
+	}
+
+	if (conn_dst->msg_users[user->idr] >= KDBUS_CONN_MAX_MSGS_PER_USER)
+		return -ENOBUFS;
+
+	conn_dst->msg_users[user->idr]++;
+	entry->user = kdbus_domain_user_ref(user);
+	return 0;
+}
+
+static void kdbus_conn_work(struct work_struct *work)
+{
+	struct kdbus_conn *conn;
+	struct kdbus_conn_reply *reply, *reply_tmp;
+	u64 deadline = ~0ULL;
+	struct timespec64 ts;
+	u64 now;
+
+	conn = container_of(work, struct kdbus_conn, work.work);
+	ktime_get_ts64(&ts);
+	now = timespec64_to_ns(&ts);
+
+	mutex_lock(&conn->lock);
+	if (!kdbus_conn_active(conn)) {
+		mutex_unlock(&conn->lock);
+		return;
+	}
+
+	list_for_each_entry_safe(reply, reply_tmp, &conn->reply_list, entry) {
+		/*
+		 * If the reply block is waiting for synchronous I/O,
+		 * the timeout is handled by wait_event_*_timeout(),
+		 * so we don't have to care for it here.
+		 */
+		if (reply->sync && !reply->interrupted)
+			continue;
+
+		if (reply->deadline_ns > now) {
+			/* remember next timeout */
+			if (deadline > reply->deadline_ns)
+				deadline = reply->deadline_ns;
+
+			continue;
+		}
+
+		/*
+		 * A zero deadline means the connection died, was
+		 * cleaned up already and the notification was sent.
+		 * Don't send notifications for reply trackers that were
+		 * left in an interrupted syscall state.
+		 */
+		if (reply->deadline_ns != 0 && !reply->interrupted)
+			kdbus_notify_reply_timeout(conn->ep->bus,
+						   reply->reply_dst->id,
+						   reply->cookie);
+
+		list_del_init(&reply->entry);
+		kdbus_conn_reply_unref(reply);
+	}
+
+	/* rearm delayed work with next timeout */
+	if (deadline != ~0ULL)
+		schedule_delayed_work(&conn->work,
+				      nsecs_to_jiffies(deadline - now));
+
+	mutex_unlock(&conn->lock);
+
+	kdbus_notify_flush(conn->ep->bus);
+}
+
+/**
+ * kdbus_cmd_msg_recv() - receive a message from the queue
+ * @conn:		Connection to work on
+ * @recv:		The command as passed in by the ioctl
+ *
+ * Return: 0 on success, negative errno on failure
+ */
+int kdbus_cmd_msg_recv(struct kdbus_conn *conn,
+		       struct kdbus_cmd_recv *recv)
+{
+	struct kdbus_queue_entry *entry = NULL;
+	unsigned int lost_count;
+	int ret = 0;
+
+	if (recv->offset > 0)
+		return -EINVAL;
+
+	mutex_lock(&conn->lock);
+	entry = kdbus_queue_entry_peek(&conn->queue, recv->priority,
+				       recv->flags & KDBUS_RECV_USE_PRIORITY);
+	if (IS_ERR(entry)) {
+		ret = PTR_ERR(entry);
+		goto exit_unlock;
+	}
+
+	/*
+	 * Make sure to never install fds into a connection that has
+	 * refused to receive any.
+	 */
+	if (WARN_ON(!(conn->flags & KDBUS_HELLO_ACCEPT_FD) &&
+		    entry->fds_count > 0)) {
+		ret = -EINVAL;
+		goto exit_unlock;
+	}
+
+	/* just drop the message */
+	if (recv->flags & KDBUS_RECV_DROP) {
+		bool reply_found = false;
+
+		if (entry->reply) {
+			struct kdbus_conn_reply *r;
+
+			/*
+			 * Walk the list of pending replies and see if the
+			 * one attached to this entry item is stil there.
+			 * It might have been removed by an incoming reply,
+			 * and we currently don't track reply entries in that
+			 * direction in order to prevent potentially dangling
+			 * pointers.
+			 */
+			list_for_each_entry(r, &conn->reply_list, entry) {
+				if (r == entry->reply) {
+					reply_found = true;
+					break;
+				}
+			}
+		}
+
+		if (reply_found) {
+			if (entry->reply->sync) {
+				kdbus_conn_reply_sync(entry->reply, -EPIPE);
+			} else {
+				list_del_init(&entry->reply->entry);
+				kdbus_conn_reply_unref(entry->reply);
+				kdbus_notify_reply_dead(conn->ep->bus,
+							entry->src_id,
+							entry->cookie);
+			}
+		}
+
+		kdbus_queue_entry_remove(conn, entry);
+		kdbus_pool_slice_free(entry->slice);
+
+		/* Free the resources of this entry */
+		kdbus_queue_entry_free(entry);
+
+		goto exit_unlock;
+	}
+
+	/*
+	 * If there have been lost broadcast messages, report the number
+	 * in the overloaded recv->dropped_msgs field and return -EOVERFLOW.
+	 */
+	lost_count = atomic_read(&conn->lost_count);
+	if (lost_count) {
+		recv->dropped_msgs = lost_count;
+		atomic_sub(lost_count, &conn->lost_count);
+		ret = -EOVERFLOW;
+		goto exit_unlock;
+	}
+
+	/* Give the offset back to the caller. */
+	recv->offset = kdbus_pool_slice_offset(entry->slice);
+
+	/*
+	 * Just return the location of the next message. Do not install
+	 * file descriptors or anything else. This is usually used to
+	 * determine the sender of the next queued message.
+	 *
+	 * File descriptor numbers referenced in the message items
+	 * are undefined, they are only valid with the full receive
+	 * not with peek.
+	 */
+	if (recv->flags & KDBUS_RECV_PEEK) {
+		kdbus_pool_slice_flush(entry->slice);
+		goto exit_unlock;
+	}
+
+	ret = kdbus_queue_entry_install(entry);
+	kdbus_pool_slice_make_public(entry->slice);
+	kdbus_queue_entry_remove(conn, entry);
+	kdbus_queue_entry_free(entry);
+
+exit_unlock:
+	mutex_unlock(&conn->lock);
+	kdbus_notify_flush(conn->ep->bus);
+	return ret;
+}
+
+/**
+ * kdbus_conn_reply_find() - Find the corresponding reply object
+ * @conn_replying:	The replying connection
+ * @conn_reply_dst:	The connection the reply will be sent to
+ *			(method origin)
+ * @cookie:		The cookie of the requesting message
+ *
+ * Lookup a reply object that should be sent as a reply by
+ * @conn_replying to @conn_reply_dst with the given cookie.
+ *
+ * For optimizations, callers should first check 'reply_count' of
+ * @conn_reply_dst to see if the connection has issued any requests
+ * that are waiting for replies, before calling this function.
+ *
+ * Return: the corresponding reply object or NULL if not found
+ */
+static struct kdbus_conn_reply *
+kdbus_conn_reply_find(struct kdbus_conn *conn_replying,
+		      struct kdbus_conn *conn_reply_dst,
+		      uint64_t cookie)
+{
+	struct kdbus_conn_reply *r;
+	struct kdbus_conn_reply *reply = NULL;
+
+	list_for_each_entry(r, &conn_replying->reply_list, entry) {
+		if (r->reply_dst == conn_reply_dst &&
+		    r->cookie == cookie) {
+			reply = r;
+			break;
+		}
+	}
+
+	return reply;
+}
+
+/**
+ * kdbus_cmd_msg_cancel() - cancel all pending sync requests
+ *			    with the given cookie
+ * @conn:		The connection
+ * @cookie:		The cookie
+ *
+ * Return: 0 on success, or -ENOENT if no pending request with that
+ * cookie was found.
+ */
+int kdbus_cmd_msg_cancel(struct kdbus_conn *conn,
+			 u64 cookie)
+{
+	struct kdbus_conn_reply *reply;
+	struct kdbus_conn *c;
+	int ret = -ENOENT;
+	int i;
+
+	if (atomic_read(&conn->reply_count) == 0)
+		return -ENOENT;
+
+	/* lock order: domain -> bus -> ep -> names -> conn */
+	down_read(&conn->ep->bus->conn_rwlock);
+	hash_for_each(conn->ep->bus->conn_hash, i, c, hentry) {
+		if (c == conn)
+			continue;
+
+		mutex_lock(&c->lock);
+		reply = kdbus_conn_reply_find(c, conn, cookie);
+		if (reply && reply->sync) {
+			kdbus_conn_reply_sync(reply, -ECANCELED);
+			ret = 0;
+		}
+		mutex_unlock(&c->lock);
+	}
+	up_read(&conn->ep->bus->conn_rwlock);
+
+	return ret;
+}
+
+static int kdbus_conn_check_access(struct kdbus_ep *ep,
+				   const struct kdbus_msg *msg,
+				   struct kdbus_conn *conn_src,
+				   struct kdbus_conn *conn_dst,
+				   struct kdbus_conn_reply **reply_wake)
+{
+	bool allowed = false;
+
+	/*
+	 * Walk the conn_src's list of expected replies. If there's any
+	 * matching entry, allow the message to be sent, and remove it.
+	 *
+	 * If conn_dst did not issue any previous request or if the
+	 * request was canceled then nothing to do, and fallback to
+	 * to a normal permission check
+	 */
+	if (reply_wake && msg->cookie_reply > 0 &&
+	    atomic_read(&conn_dst->reply_count) > 0) {
+		struct kdbus_conn_reply *r;
+
+		mutex_lock(&conn_src->lock);
+		r = kdbus_conn_reply_find(conn_src, conn_dst,
+					  msg->cookie_reply);
+		if (r) {
+			list_del_init(&r->entry);
+			if (r->sync)
+				*reply_wake = kdbus_conn_reply_ref(r);
+			else
+				kdbus_conn_reply_unref(r);
+
+			allowed = true;
+		}
+		mutex_unlock(&conn_src->lock);
+	}
+
+	if (allowed)
+		return 0;
+
+	/* ... otherwise, ask the policy DBs for permission */
+	return kdbus_ep_policy_check_talk_access(ep, conn_src, conn_dst);
+}
+
+/* Callers should take the conn_dst lock */
+static struct kdbus_queue_entry *
+kdbus_conn_entry_make(struct kdbus_conn *conn_src,
+		      struct kdbus_conn *conn_dst,
+		      const struct kdbus_kmsg *kmsg)
+{
+	struct kdbus_queue_entry *entry;
+
+	/* The remote connection was disconnected */
+	if (!kdbus_conn_active(conn_dst))
+		return ERR_PTR(-ECONNRESET);
+
+	/* The connection does not accept file descriptors */
+	if (!(conn_dst->flags & KDBUS_HELLO_ACCEPT_FD) && kmsg->fds_count > 0)
+		return ERR_PTR(-ECOMM);
+
+	entry = kdbus_queue_entry_alloc(conn_src, conn_dst, kmsg);
+	if (IS_ERR(entry))
+		return entry;
+
+	return entry;
+}
+
+/*
+ * Synchronously responding to a message, allocate a queue entry
+ * and attach it to the reply tracking object.
+ * The connection's queue will never get to see it.
+ */
+static int kdbus_conn_entry_sync_attach(struct kdbus_conn *conn_src,
+					struct kdbus_conn *conn_dst,
+					const struct kdbus_kmsg *kmsg,
+					struct kdbus_conn_reply *reply_wake)
+{
+	struct kdbus_queue_entry *entry;
+	int remote_ret;
+	int ret = 0;
+
+	mutex_lock(&conn_dst->lock);
+
+	/*
+	 * If we are still waiting then proceed, allocate a queue
+	 * entry and attach it to the reply object
+	 */
+	if (reply_wake->waiting) {
+		entry = kdbus_conn_entry_make(conn_src, conn_dst, kmsg);
+		if (IS_ERR(entry))
+			ret = PTR_ERR(entry);
+		else
+			/* Attach the entry to the reply object */
+			reply_wake->queue_entry = entry;
+	} else {
+		ret = -ECONNRESET;
+	}
+
+	/*
+	 * Update the reply object and wake up remote peer only
+	 * on appropriate return codes
+	 *
+	 * * -ECOMM: if the replying connection failed with -ECOMM
+	 *           then wakeup remote peer with -EREMOTEIO
+	 *
+	 *           We do this to differenciate between -ECOMM errors
+	 *           from the original sender perspective:
+	 *           -ECOMM error during the sync send and
+	 *           -ECOMM error during the sync reply, this last
+	 *           one is rewritten to -EREMOTEIO
+	 *
+	 * * Wake up on all other return codes.
+	 */
+	remote_ret = ret;
+
+	if (ret == -ECOMM)
+		remote_ret = -EREMOTEIO;
+
+	kdbus_conn_reply_sync(reply_wake, remote_ret);
+	kdbus_conn_reply_unref(reply_wake);
+
+	mutex_unlock(&conn_dst->lock);
+
+	return ret;
+}
+
+/**
+ * kdbus_conn_entry_insert - enqueue a message into the receiver's pool
+ * @conn_src:		The sending connection
+ * @conn_dst:		The connection to queue into
+ * @kmsg:		The kmag to queue
+ * @reply:		The reply tracker to attach to the queue entry
+ *
+ * Return: 0 on success. negative error otherwise.
+ */
+int kdbus_conn_entry_insert(struct kdbus_conn *conn_src,
+			    struct kdbus_conn *conn_dst,
+			    const struct kdbus_kmsg *kmsg,
+			    struct kdbus_conn_reply *reply)
+{
+	struct kdbus_queue_entry *entry;
+	int ret;
+
+	mutex_lock(&conn_dst->lock);
+
+	/* limit the maximum number of queued messages */
+	if (conn_dst->queue.msg_count > KDBUS_CONN_MAX_MSGS) {
+		ret = -ENOBUFS;
+		goto exit_unlock;
+	}
+
+	/* Get a queue entry for src and dst pairs */
+	entry = kdbus_conn_entry_make(conn_src, conn_dst, kmsg);
+	if (IS_ERR(entry)) {
+		ret = PTR_ERR(entry);
+		goto exit_unlock;
+	}
+
+	/* limit the number of queued messages from the same individual user */
+	ret = kdbus_conn_queue_user_quota(conn_src, conn_dst, entry);
+	if (ret < 0)
+		goto exit_queue_free;
+
+	/*
+	 * Remember the the reply associated with this queue entry, so we can
+	 * move the reply entry's connection when a connection moves from an
+	 * activator to an implementor.
+	 */
+	entry->reply = reply;
+
+	if (reply) {
+		list_add(&reply->entry, &conn_dst->reply_list);
+		if (!reply->sync)
+			schedule_delayed_work(&conn_dst->work, 0);
+	}
+
+	/* link the message into the receiver's entry */
+	kdbus_queue_entry_add(&conn_dst->queue, entry);
+	mutex_unlock(&conn_dst->lock);
+
+	/* wake up poll() */
+	wake_up_interruptible(&conn_dst->wait);
+	return 0;
+
+exit_queue_free:
+	kdbus_queue_entry_free(entry);
+exit_unlock:
+	mutex_unlock(&conn_dst->lock);
+	return ret;
+}
+
+static void kdbus_conn_eavesdrop(struct kdbus_bus *bus,
+				 struct kdbus_conn *conn,
+				 struct kdbus_kmsg *kmsg)
+{
+	struct kdbus_conn *c;
+	int ret;
+
+	/*
+	 * Monitor connections get all messages; ignore possible errors
+	 * when sending messages to monitor connections.
+	 */
+
+	down_read(&bus->conn_rwlock);
+	list_for_each_entry(c, &bus->monitors_list, monitor_entry) {
+		/*
+		 * The first monitor which requests additional
+		 * metadata causes the message to carry it; all
+		 * monitors after that will see all of the added
+		 * data, even when they did not ask for it.
+		 */
+		if (conn) {
+			ret = kdbus_kmsg_attach_metadata(kmsg, conn, c);
+			if (ret < 0)
+				break;
+		}
+
+		kdbus_conn_entry_insert(NULL, c, kmsg, NULL);
+	}
+	up_read(&bus->conn_rwlock);
+}
+
+static int kdbus_conn_wait_reply(struct kdbus_conn *conn_src,
+				 struct kdbus_conn *conn_dst,
+				 struct kdbus_msg *msg,
+				 struct kdbus_conn_reply *reply_wait,
+				 u64 timeout_ns)
+{
+	struct kdbus_queue_entry *entry;
+	int r, ret;
+
+	/*
+	 * Block until the reply arrives. reply_wait is left untouched
+	 * by the timeout scans that might be conducted for other,
+	 * asynchronous replies of conn_src.
+	 */
+	r = wait_event_interruptible_timeout(reply_wait->reply_dst->wait,
+		!reply_wait->waiting || !kdbus_conn_active(conn_src),
+		nsecs_to_jiffies(timeout_ns));
+	if (r < 0) {
+		/*
+		 * Interrupted system call. Unref the reply object, and
+		 * pass the return value down the chain. Mark the reply as
+		 * interrupted, so the cleanup work can remove it, but do
+		 * not unlink it from the list. Once the syscall restarts,
+		 * we'll pick it up and wait on it again.
+		 */
+		mutex_lock(&conn_dst->lock);
+		reply_wait->interrupted = true;
+		schedule_delayed_work(&conn_dst->work, 0);
+		mutex_unlock(&conn_dst->lock);
+
+		return r;
+	}
+
+	if (r == 0)
+		ret = -ETIMEDOUT;
+	else if (!kdbus_conn_active(conn_src))
+		ret = -ECONNRESET;
+	else
+		ret = reply_wait->err;
+
+	mutex_lock(&conn_dst->lock);
+	list_del_init(&reply_wait->entry);
+	mutex_unlock(&conn_dst->lock);
+
+	mutex_lock(&conn_src->lock);
+	reply_wait->waiting = false;
+	entry = reply_wait->queue_entry;
+	if (entry) {
+		if (ret == 0)
+			ret = kdbus_queue_entry_install(entry);
+
+		msg->offset_reply = kdbus_pool_slice_offset(entry->slice);
+		kdbus_pool_slice_make_public(entry->slice);
+		kdbus_queue_entry_free(entry);
+	}
+	mutex_unlock(&conn_src->lock);
+
+	kdbus_conn_reply_unref(reply_wait);
+
+	return ret;
+}
+
+/**
+ * kdbus_conn_kmsg_send() - send a message
+ * @ep:			Endpoint to send from
+ * @conn_src:		Connection, kernel-generated messages do not have one
+ * @kmsg:		Message to send
+ *
+ * Return: 0 on success, negative errno on failure
+ */
+int kdbus_conn_kmsg_send(struct kdbus_ep *ep,
+			 struct kdbus_conn *conn_src,
+			 struct kdbus_kmsg *kmsg)
+{
+	struct kdbus_conn_reply *reply_wait = NULL;
+	struct kdbus_conn_reply *reply_wake = NULL;
+	struct kdbus_name_entry *name_entry = NULL;
+	struct kdbus_msg *msg = &kmsg->msg;
+	struct kdbus_conn *conn_dst = NULL;
+	struct kdbus_bus *bus = ep->bus;
+	bool sync = msg->flags & KDBUS_MSG_FLAGS_SYNC_REPLY;
+	int ret = 0;
+
+	/* assign domain-global message sequence number */
+	BUG_ON(kmsg->seq > 0);
+	kmsg->seq = atomic64_inc_return(&bus->domain->msg_seq_last);
+
+	/* non-kernel senders append credentials/metadata */
+	if (conn_src) {
+		/*
+		 * If a connection has installed faked credentials when it was
+		 * created, make sure only those are sent out as attachments
+		 * of messages, and nothing that is gathered at retrieved from
+		 * 'current' at the time of sending.
+		 *
+		 * Hence, in such cases, duplicate the connection's owner_meta,
+		 * and take care not to augment it by attaching any new items.
+		 */
+		if (conn_src->owner_meta)
+			kmsg->meta = kdbus_meta_dup(conn_src->owner_meta);
+		else
+			kmsg->meta = kdbus_meta_new();
+
+		if (IS_ERR(kmsg->meta)) {
+			ret = PTR_ERR(kmsg->meta);
+			kmsg->meta = NULL;
+			return ret;
+		}
+	}
+
+	if (msg->dst_id == KDBUS_DST_ID_BROADCAST) {
+		kdbus_bus_broadcast(bus, conn_src, kmsg);
+		return 0;
+	}
+
+	if (kmsg->dst_name) {
+		name_entry = kdbus_name_lock(bus->name_registry,
+					     kmsg->dst_name);
+		if (!name_entry)
+			return -ESRCH;
+
+		/*
+		 * If both a name and a connection ID are given as destination
+		 * of a message, check that the currently owning connection of
+		 * the name matches the specified ID.
+		 * This way, we allow userspace to send the message to a
+		 * specific connection by ID only if the connection currently
+		 * owns the given name.
+		 */
+		if (msg->dst_id != KDBUS_DST_ID_NAME &&
+		    msg->dst_id != name_entry->conn->id) {
+			ret = -EREMCHG;
+			goto exit_name_unlock;
+		}
+
+		if (!name_entry->conn && name_entry->activator)
+			conn_dst = kdbus_conn_ref(name_entry->activator);
+		else
+			conn_dst = kdbus_conn_ref(name_entry->conn);
+
+		if ((msg->flags & KDBUS_MSG_FLAGS_NO_AUTO_START) &&
+		     kdbus_conn_is_activator(conn_dst)) {
+			ret = -EADDRNOTAVAIL;
+			goto exit_unref;
+		}
+	} else {
+		/* unicast message to unique name */
+		conn_dst = kdbus_bus_find_conn_by_id(bus, msg->dst_id);
+		if (!conn_dst)
+			return -ENXIO;
+
+		/*
+		 * Special-purpose connections are not allowed to be addressed
+		 * via their unique IDs.
+		 */
+		if (!kdbus_conn_is_ordinary(conn_dst)) {
+			ret = -ENXIO;
+			goto exit_unref;
+		}
+	}
+
+	/*
+	 * Record the sequence number of the registered name;
+	 * it will be passed on to the queue, in case messages
+	 * addressed to a name need to be moved from or to
+	 * activator connections of the same name.
+	 */
+	if (name_entry)
+		kmsg->dst_name_id = name_entry->name_id;
+
+	if (conn_src) {
+		/*
+		 * If we got here due to an interrupted system call, our reply
+		 * wait object is still queued on conn_dst, with the former
+		 * cookie. Look it up, and in case it exists, go dormant right
+		 * away again, and don't queue the message again.
+		 *
+		 * We also need to make sure that conn_src did really
+		 * issue a request or if the request did not get
+		 * canceled on the way before looking up any reply
+		 * object.
+		 */
+		if (sync && atomic_read(&conn_src->reply_count) > 0) {
+			mutex_lock(&conn_dst->lock);
+			reply_wait = kdbus_conn_reply_find(conn_dst,
+							   conn_src,
+							   kmsg->msg.cookie);
+			if (reply_wait) {
+				/* It was interrupted */
+				if (reply_wait->interrupted)
+					reply_wait->interrupted = false;
+				else
+					reply_wait = NULL;
+			}
+			mutex_unlock(&conn_dst->lock);
+
+			if (reply_wait)
+				goto wait_sync;
+		}
+
+		ret = kdbus_kmsg_attach_metadata(kmsg, conn_src, conn_dst);
+		if (ret < 0)
+			goto exit_unref;
+
+		if (msg->flags & KDBUS_MSG_FLAGS_EXPECT_REPLY) {
+			ret = kdbus_conn_check_access(ep, msg, conn_src,
+						      conn_dst, NULL);
+			if (ret < 0)
+				goto exit_unref;
+
+			reply_wait = kdbus_conn_reply_new(conn_src, msg,
+							  name_entry);
+			if (IS_ERR(reply_wait)) {
+				ret = PTR_ERR(reply_wait);
+				goto exit_unref;
+			}
+		} else {
+			ret = kdbus_conn_check_access(ep, msg, conn_src,
+						      conn_dst, &reply_wake);
+			if (ret < 0)
+				goto exit_unref;
+		}
+	}
+
+	if (reply_wake) {
+		/*
+		 * If we're synchronously responding to a message, allocate a
+		 * queue item and attach it to the reply tracking object.
+		 * The connection's queue will never get to see it.
+		 */
+		ret = kdbus_conn_entry_sync_attach(conn_src, conn_dst,
+						   kmsg, reply_wake);
+		if (ret < 0)
+			goto exit_unref;
+	} else {
+		/*
+		 * Otherwise, put it in the queue and wait for the connection
+		 * to dequeue and receive the message.
+		 */
+		ret = kdbus_conn_entry_insert(conn_src, conn_dst,
+					      kmsg, reply_wait);
+		if (ret < 0) {
+			if (reply_wait)
+				kdbus_conn_reply_unref(reply_wait);
+			goto exit_unref;
+		}
+	}
+
+	/* forward to monitors */
+	kdbus_conn_eavesdrop(bus, conn_src, kmsg);
+
+wait_sync:
+	/* no reason to keep names locked for replies */
+	name_entry = kdbus_name_unlock(bus->name_registry, name_entry);
+
+	if (sync) {
+		struct timespec64 ts;
+		u64 now, timeout;
+
+		BUG_ON(!reply_wait);
+
+		ktime_get_ts64(&ts);
+		now = timespec64_to_ns(&ts);
+
+		if (unlikely(msg->timeout_ns <= now))
+			timeout = 0;
+		else
+			timeout = msg->timeout_ns - now;
+
+		ret = kdbus_conn_wait_reply(conn_src, conn_dst, msg,
+					    reply_wait, timeout);
+	}
+
+exit_unref:
+	kdbus_conn_unref(conn_dst);
+exit_name_unlock:
+	kdbus_name_unlock(bus->name_registry, name_entry);
+
+	return ret;
+}
+
+/**
+ * kdbus_conn_disconnect() - disconnect a connection
+ * @conn:		The connection to disconnect
+ * @ensure_queue_empty:	Flag to indicate if the call should fail in
+ *			case the connection's message list is not
+ *			empty
+ *
+ * If @ensure_msg_list_empty is true, and the connection has pending messages,
+ * -EBUSY is returned.
+ *
+ * Return: 0 on success, negative errno on failure
+ */
+int kdbus_conn_disconnect(struct kdbus_conn *conn, bool ensure_queue_empty)
+{
+	struct kdbus_conn_reply *reply, *reply_tmp;
+	struct kdbus_queue_entry *entry, *tmp;
+	LIST_HEAD(reply_list);
+
+	mutex_lock(&conn->lock);
+	if (!kdbus_conn_active(conn)) {
+		mutex_unlock(&conn->lock);
+		return -EALREADY;
+	}
+
+	if (ensure_queue_empty && !list_empty(&conn->queue.msg_list)) {
+		mutex_unlock(&conn->lock);
+		return -EBUSY;
+	}
+
+	atomic_add(KDBUS_CONN_ACTIVE_BIAS, &conn->active);
+	mutex_unlock(&conn->lock);
+
+	wake_up_interruptible(&conn->wait);
+
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+	rwsem_acquire(&conn->dep_map, 0, 0, _RET_IP_);
+	if (atomic_read(&conn->active) != KDBUS_CONN_ACTIVE_BIAS)
+		lock_contended(&conn->dep_map, _RET_IP_);
+#endif
+
+	wait_event(conn->wait,
+		   atomic_read(&conn->active) == KDBUS_CONN_ACTIVE_BIAS);
+
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+	lock_acquired(&conn->dep_map, _RET_IP_);
+	rwsem_release(&conn->dep_map, 1, _RET_IP_);
+#endif
+
+	cancel_delayed_work_sync(&conn->work);
+
+	/* lock order: domain -> bus -> ep -> names -> conn */
+	mutex_lock(&conn->ep->lock);
+	down_write(&conn->ep->bus->conn_rwlock);
+
+	/* remove from bus and endpoint */
+	hash_del(&conn->hentry);
+	list_del(&conn->monitor_entry);
+	list_del(&conn->ep_entry);
+
+	up_write(&conn->ep->bus->conn_rwlock);
+	mutex_unlock(&conn->ep->lock);
+
+	/*
+	 * Remove all names associated with this connection; this possibly
+	 * moves queued messages back to the activator connection.
+	 */
+	kdbus_name_remove_by_conn(conn->ep->bus->name_registry, conn);
+
+	/* if we die while other connections wait for our reply, notify them */
+	mutex_lock(&conn->lock);
+	list_for_each_entry_safe(entry, tmp, &conn->queue.msg_list, entry) {
+		if (entry->reply)
+			kdbus_notify_reply_dead(conn->ep->bus, entry->src_id,
+						entry->cookie);
+
+		kdbus_queue_entry_remove(conn, entry);
+		kdbus_pool_slice_free(entry->slice);
+		kdbus_queue_entry_free(entry);
+	}
+	list_splice_init(&conn->reply_list, &reply_list);
+	mutex_unlock(&conn->lock);
+
+	list_for_each_entry_safe(reply, reply_tmp, &reply_list, entry) {
+		if (reply->sync) {
+			kdbus_conn_reply_sync(reply, -EPIPE);
+			continue;
+		}
+
+		/* send a 'connection dead' notification */
+		kdbus_notify_reply_dead(conn->ep->bus, reply->reply_dst->id,
+					reply->cookie);
+
+		list_del(&reply->entry);
+		kdbus_conn_reply_unref(reply);
+	}
+
+	kdbus_notify_id_change(conn->ep->bus, KDBUS_ITEM_ID_REMOVE,
+			       conn->id, conn->flags);
+
+	kdbus_notify_flush(conn->ep->bus);
+
+	return 0;
+}
+
+/**
+ * kdbus_conn_active() - connection is not disconnected
+ * @conn:		Connection to check
+ *
+ * Return true if the connection was not disconnected, yet. Note that a
+ * connection might be disconnected asynchronously, unless you hold the
+ * connection lock. If that's not suitable for you, see kdbus_conn_acquire() to
+ * suppress connection shutdown for a short period.
+ *
+ * Return: true if the connection is still active
+ */
+bool kdbus_conn_active(const struct kdbus_conn *conn)
+{
+	return atomic_read(&conn->active) >= 0;
+}
+
+/**
+ * kdbus_conn_flush_policy() - flush all cached policy entries that
+ *			       refer to a connecion
+ * @conn:	Connection to check
+ */
+void kdbus_conn_purge_policy_cache(struct kdbus_conn *conn)
+{
+	kdbus_policy_purge_cache(&conn->ep->policy_db, conn);
+	kdbus_policy_purge_cache(&conn->ep->bus->policy_db, conn);
+}
+
+static void __kdbus_conn_free(struct kref *kref)
+{
+	struct kdbus_conn *conn = container_of(kref, struct kdbus_conn, kref);
+
+	BUG_ON(kdbus_conn_active(conn));
+	BUG_ON(delayed_work_pending(&conn->work));
+	BUG_ON(!list_empty(&conn->queue.msg_list));
+	BUG_ON(!list_empty(&conn->names_list));
+	BUG_ON(!list_empty(&conn->names_queue_list));
+	BUG_ON(!list_empty(&conn->reply_list));
+
+	atomic_dec(&conn->user->connections);
+	kdbus_domain_user_unref(conn->user);
+
+	kdbus_conn_purge_policy_cache(conn);
+	kdbus_policy_remove_owner(&conn->ep->bus->policy_db, conn);
+
+	kdbus_meta_free(conn->owner_meta);
+	kdbus_match_db_free(conn->match_db);
+	kdbus_pool_free(conn->pool);
+	kdbus_ep_unref(conn->ep);
+	put_cred(conn->cred);
+	kfree(conn->name);
+	kfree(conn);
+}
+
+/**
+ * kdbus_conn_ref() - take a connection reference
+ * @conn:		Connection
+ *
+ * Return: the connection itself
+ */
+struct kdbus_conn *kdbus_conn_ref(struct kdbus_conn *conn)
+{
+	kref_get(&conn->kref);
+	return conn;
+}
+
+/**
+ * kdbus_conn_unref() - drop a connection reference
+ * @conn:		Connection (may be NULL)
+ *
+ * When the last reference is dropped, the connection's internal structure
+ * is freed.
+ *
+ * Return: NULL
+ */
+struct kdbus_conn *kdbus_conn_unref(struct kdbus_conn *conn)
+{
+	if (conn)
+		kref_put(&conn->kref, __kdbus_conn_free);
+	return NULL;
+}
+
+/**
+ * kdbus_conn_acquire() - acquire an active connection reference
+ * @conn:		Connection
+ *
+ * Users can close a connection via KDBUS_BYEBYE (or by destroying the
+ * endpoint/bus/...) at any time. Whenever this happens, we should deny any
+ * user-visible action on this connection and signal ECONNRESET instead.
+ * To avoid testing for connection availability everytime you take the
+ * connection-lock, you can acquire a connection for short periods.
+ *
+ * By calling kdbus_conn_acquire(), you gain an "active reference" to the
+ * connection. You must also hold a regular reference at any time! As long as
+ * you hold the active-ref, the connection will not be shut down. However, if
+ * the connection was shut down, you can never acquire an active-ref again.
+ *
+ * kdbus_conn_disconnect() disables the connection and then waits for all active
+ * references to be dropped. It will also wake up any pending operation.
+ * However, you must not sleep for an indefinite period while holding an
+ * active-reference. Otherwise, kdbus_conn_disconnect() might stall. If you need
+ * to sleep for an indefinite period, either release the reference and try to
+ * acquire it again after waking up, or make kdbus_conn_disconnect() wake up
+ * your wait-queue.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int kdbus_conn_acquire(struct kdbus_conn *conn)
+{
+	if (!atomic_inc_unless_negative(&conn->active))
+		return -ECONNRESET;
+
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+	rwsem_acquire_read(&conn->dep_map, 0, 1, _RET_IP_);
+#endif
+
+	return 0;
+}
+
+/**
+ * kdbus_conn_release() - release an active connection reference
+ * @conn:		Connection
+ *
+ * This releases an active reference that has been acquired via
+ * kdbus_conn_acquire(). If the connection was already disabled and this is the
+ * last active-ref that is dropped, the disconnect-waiter will be woken up and
+ * properly close the connection.
+ */
+void kdbus_conn_release(struct kdbus_conn *conn)
+{
+	int v;
+
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+	rwsem_release(&conn->dep_map, 1, _RET_IP_);
+#endif
+
+	v = atomic_dec_return(&conn->active);
+	if (v != KDBUS_CONN_ACTIVE_BIAS)
+		return;
+
+	wake_up_all(&conn->wait);
+}
+
+/**
+ * kdbus_conn_move_messages() - move messages from one connection to another
+ * @conn_dst:		Connection to copy to
+ * @conn_src:		Connection to copy from
+ * @name_id:		Filter for the sequence number of the registered
+ *			name, 0 means no filtering.
+ *
+ * Move all messages from one connection to another. This is used when
+ * an implementor connection is taking over/giving back a well-known name
+ * from/to an activator connection.
+ *
+ * Return: 0 on success, negative errno on failure.
+ */
+int kdbus_conn_move_messages(struct kdbus_conn *conn_dst,
+			     struct kdbus_conn *conn_src,
+			     u64 name_id)
+{
+	struct kdbus_queue_entry *q, *q_tmp;
+	struct kdbus_conn_reply *r, *r_tmp;
+	LIST_HEAD(reply_list);
+	LIST_HEAD(msg_list);
+	int ret = 0;
+
+	BUG_ON(!mutex_is_locked(&conn_dst->ep->bus->lock));
+	BUG_ON(conn_src == conn_dst);
+
+	/* remove all messages from the source */
+	mutex_lock(&conn_src->lock);
+	list_for_each_entry_safe(r, r_tmp, &conn_src->reply_list, entry) {
+		/* filter messages for a specific name */
+		if (name_id > 0 && r->name_id != name_id)
+			continue;
+
+		list_move_tail(&r->entry, &reply_list);
+	}
+	list_for_each_entry_safe(q, q_tmp, &conn_src->queue.msg_list, entry) {
+		/* filter messages for a specific name */
+		if (name_id > 0 && q->dst_name_id != name_id)
+			continue;
+
+		kdbus_queue_entry_remove(conn_src, q);
+
+		if (!(conn_dst->flags & KDBUS_HELLO_ACCEPT_FD) &&
+		    q->fds_count > 0) {
+			atomic_inc(&conn_dst->lost_count);
+			continue;
+		}
+
+		list_add_tail(&q->entry, &msg_list);
+	}
+	mutex_unlock(&conn_src->lock);
+
+	/* insert messages into destination */
+	mutex_lock(&conn_dst->lock);
+	if (!kdbus_conn_active(conn_dst)) {
+		struct kdbus_conn_reply *r, *r_tmp;
+
+		/* our destination connection died, just drop all messages */
+		mutex_unlock(&conn_dst->lock);
+		list_for_each_entry_safe(q, q_tmp, &msg_list, entry)
+			kdbus_queue_entry_free(q);
+		list_for_each_entry_safe(r, r_tmp, &reply_list, entry)
+			kdbus_conn_reply_unref(r);
+		return -ECONNRESET;
+	}
+
+	list_for_each_entry_safe(q, q_tmp, &msg_list, entry) {
+		ret = kdbus_pool_slice_move(conn_src->pool, conn_dst->pool,
+					    &q->slice);
+		if (ret < 0)
+			kdbus_queue_entry_free(q);
+		else
+			kdbus_queue_entry_add(&conn_dst->queue, q);
+	}
+	list_splice(&reply_list, &conn_dst->reply_list);
+	mutex_unlock(&conn_dst->lock);
+
+	/* wake up poll() */
+	wake_up_interruptible(&conn_dst->wait);
+
+	return ret;
+}
+
+/**
+ * kdbus_cmd_info() - retrieve info about a connection
+ * @conn:		Connection
+ * @cmd_info:		The command as passed in by the ioctl
+ *
+ * Return: 0 on success, negative errno on failure.
+ */
+int kdbus_cmd_info(struct kdbus_conn *conn,
+		   struct kdbus_cmd_info *cmd_info)
+{
+	struct kdbus_name_entry *entry = NULL;
+	struct kdbus_conn *owner_conn = NULL;
+	struct kdbus_info info = {};
+	struct kdbus_meta *meta = NULL;
+	struct kdbus_pool_slice *slice;
+	u64 extra_flags, attach_flags;
+	size_t pos, meta_size;
+	int ret = 0;
+
+	if (cmd_info->id == 0) {
+		const char *name;
+
+		name = kdbus_items_get_str(cmd_info->items,
+					   KDBUS_ITEMS_SIZE(cmd_info, items),
+					   KDBUS_ITEM_NAME);
+		if (IS_ERR(name))
+			return -EINVAL;
+
+		if (!kdbus_name_is_valid(name, false))
+			return -EINVAL;
+
+		/* check if 'conn' is allowed to see 'name' */
+		ret = kdbus_ep_policy_check_see_access(conn->ep, conn, name);
+		if (ret < 0)
+			return ret;
+
+		entry = kdbus_name_lock(conn->ep->bus->name_registry, name);
+		if (!entry)
+			return -ESRCH;
+		else if (entry->conn)
+			owner_conn = kdbus_conn_ref(entry->conn);
+	} else {
+		owner_conn = kdbus_bus_find_conn_by_id(conn->ep->bus,
+						       cmd_info->id);
+		if (!owner_conn) {
+			ret = -ENXIO;
+			goto exit;
+		}
+
+		/* check if 'conn' is allowed to see any of owner_conn's names*/
+		ret = kdbus_ep_policy_check_src_names(conn->ep, owner_conn,
+						      conn);
+		if (ret < 0)
+			goto exit;
+	}
+
+	info.size = sizeof(info);
+	info.id = owner_conn->id;
+	info.flags = owner_conn->flags;
+
+	/* mask out what information the connection wants to pass us */
+	attach_flags = cmd_info->flags &
+		       atomic64_read(&owner_conn->attach_flags_send);
+
+	meta_size = kdbus_meta_size(owner_conn->meta, conn, &attach_flags);
+	info.size += meta_size;
+
+	/*
+	 * Unlike the rest of the values which are cached at connection
+	 * creation time, some values need to be appended here because
+	 * at creation time a connection does not have names and other
+	 * properties.
+	 */
+	extra_flags = attach_flags & (KDBUS_ATTACH_NAMES |
+				      KDBUS_ATTACH_CONN_DESCRIPTION);
+	if (extra_flags) {
+		meta = kdbus_meta_new();
+		if (IS_ERR(meta)) {
+			ret = PTR_ERR(meta);
+			meta = NULL;
+			goto exit;
+		}
+
+		ret = kdbus_meta_append(meta, conn->ep->bus->domain,
+					owner_conn, 0, extra_flags);
+		if (ret < 0)
+			goto exit;
+
+		info.size += kdbus_meta_size(meta, conn, &extra_flags);
+	}
+
+	slice = kdbus_pool_slice_alloc(conn->pool, info.size);
+	if (IS_ERR(slice)) {
+		ret = PTR_ERR(slice);
+		slice = NULL;
+		goto exit;
+	}
+
+	ret = kdbus_pool_slice_copy(slice, 0, &info, sizeof(info));
+	if (ret < 0)
+		goto exit_free;
+
+	pos = sizeof(info);
+
+	if (meta_size) {
+		ret = kdbus_meta_write(owner_conn->meta, conn,
+				       attach_flags, slice, pos);
+		if (ret < 0)
+			goto exit_free;
+
+		pos += meta_size;
+	}
+
+	if (extra_flags) {
+		ret = kdbus_meta_write(meta, conn, extra_flags, slice, pos);
+		if (ret < 0)
+			goto exit_free;
+	}
+
+	/* write back the offset */
+	cmd_info->offset = kdbus_pool_slice_offset(slice);
+	kdbus_pool_slice_flush(slice);
+	kdbus_pool_slice_make_public(slice);
+
+exit_free:
+	if (ret < 0)
+		kdbus_pool_slice_free(slice);
+
+exit:
+	kdbus_meta_free(meta);
+	kdbus_conn_unref(owner_conn);
+	kdbus_name_unlock(conn->ep->bus->name_registry, entry);
+
+	return ret;
+}
+
+/**
+ * kdbus_cmd_conn_update() - update the attach-flags of a connection or
+ *			     the policy entries of a policy holding one
+ * @conn:		Connection
+ * @cmd:		The command as passed in by the ioctl
+ *
+ * Return: 0 on success, negative errno on failure.
+ */
+int kdbus_cmd_conn_update(struct kdbus_conn *conn,
+			  const struct kdbus_cmd_update *cmd)
+{
+	const struct kdbus_item *item;
+	bool policy_provided = false;
+	bool send_flags_provided = false;
+	bool recv_flags_provided = false;
+	u64 attach_flags_send;
+	u64 attach_flags_recv;
+	int ret;
+
+	KDBUS_ITEMS_FOREACH(item, cmd->items, KDBUS_ITEMS_SIZE(cmd, items)) {
+		switch (item->type) {
+		case KDBUS_ITEM_ATTACH_FLAGS_SEND:
+		case KDBUS_ITEM_ATTACH_FLAGS_RECV:
+			/*
+			 * Only ordinary or monitor connections
+			 * may update their attach-flags.
+			 */
+			if (!kdbus_conn_is_ordinary(conn) &&
+			    !kdbus_conn_is_monitor(conn))
+				return -EOPNOTSUPP;
+
+			if (item->type == KDBUS_ITEM_ATTACH_FLAGS_SEND) {
+				send_flags_provided = true;
+				attach_flags_send = item->data64[0];
+			} else {
+				recv_flags_provided = true;
+				attach_flags_recv = item->data64[0];
+			}
+			break;
+
+		case KDBUS_ITEM_NAME:
+		case KDBUS_ITEM_POLICY_ACCESS:
+			/*
+			 * Only policy holders may update their policy entries.
+			 */
+			if (!kdbus_conn_is_policy_holder(conn))
+				return -EOPNOTSUPP;
+
+			policy_provided = true;
+			break;
+		}
+	}
+
+	if (policy_provided) {
+		ret = kdbus_policy_set(&conn->ep->bus->policy_db, cmd->items,
+				       KDBUS_ITEMS_SIZE(cmd, items),
+				       1, true, conn);
+		if (ret < 0)
+			return ret;
+	}
+
+	if (send_flags_provided)
+		atomic64_set(&conn->attach_flags_send, attach_flags_send);
+
+	if (recv_flags_provided)
+		atomic64_set(&conn->attach_flags_recv, attach_flags_recv);
+
+	return 0;
+}
+
+/**
+ * kdbus_conn_new() - create a new connection
+ * @ep:			The endpoint the connection is connected to
+ * @hello:		The kdbus_cmd_hello as passed in by the user
+ * @meta:		The metadata gathered at open() time of the handle
+ * @privileged:		Whether to create a privileged connection
+ *
+ * Return: a new kdbus_conn on success, ERR_PTR on failure
+ */
+struct kdbus_conn *kdbus_conn_new(struct kdbus_ep *ep,
+				  struct kdbus_cmd_hello *hello,
+				  struct kdbus_meta *meta,
+				  bool privileged)
+{
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+	static struct lock_class_key __key;
+#endif
+	const struct kdbus_creds *creds = NULL;
+	struct kdbus_bus *bus = ep->bus;
+	const struct kdbus_item *item;
+	const char *conn_name = NULL;
+	const char *seclabel = NULL;
+	const char *name = NULL;
+	struct kdbus_conn *conn;
+	size_t seclabel_len = 0;
+	u64 attach_flags_send;
+	u64 attach_flags_recv;
+	bool is_policy_holder;
+	bool is_activator;
+	bool is_monitor;
+	int ret;
+
+	is_monitor = hello->flags & KDBUS_HELLO_MONITOR;
+	is_activator = hello->flags & KDBUS_HELLO_ACTIVATOR;
+	is_policy_holder = hello->flags & KDBUS_HELLO_POLICY_HOLDER;
+
+	/* can't be activator or policy holder and monitor at the same time */
+	if (is_monitor && (is_activator || is_policy_holder))
+		return ERR_PTR(-EINVAL);
+
+	/* can't be policy holder and activator at the same time */
+	if (is_activator && is_policy_holder)
+		return ERR_PTR(-EINVAL);
+
+	/* only privileged connections can activate and monitor */
+	if (!privileged && (is_activator || is_policy_holder || is_monitor))
+		return ERR_PTR(-EPERM);
+
+	KDBUS_ITEMS_FOREACH(item, hello->items,
+			    KDBUS_ITEMS_SIZE(hello, items)) {
+		switch (item->type) {
+		case KDBUS_ITEM_NAME:
+			if (!is_activator && !is_policy_holder)
+				return ERR_PTR(-EINVAL);
+
+			if (name)
+				return ERR_PTR(-EINVAL);
+
+			if (!kdbus_name_is_valid(item->str, true))
+				return ERR_PTR(-EINVAL);
+
+			name = item->str;
+			break;
+
+		case KDBUS_ITEM_CREDS:
+			/* privileged processes can impersonate somebody else */
+			if (!privileged)
+				return ERR_PTR(-EPERM);
+
+			if (item->size != KDBUS_ITEM_SIZE(sizeof(*creds)))
+				return ERR_PTR(-EINVAL);
+
+			creds = &item->creds;
+			break;
+
+		case KDBUS_ITEM_SECLABEL:
+			/* privileged processes can impersonate somebody else */
+			if (!privileged)
+				return ERR_PTR(-EPERM);
+
+			seclabel = item->str;
+			seclabel_len = item->size - KDBUS_ITEM_HEADER_SIZE;
+			break;
+
+		case KDBUS_ITEM_CONN_DESCRIPTION:
+			/* human-readable connection name (debugging) */
+			if (conn_name)
+				return ERR_PTR(-EINVAL);
+
+			conn_name = item->str;
+			break;
+		}
+	}
+
+	if ((is_activator || is_policy_holder) && !name)
+		return ERR_PTR(-EINVAL);
+
+	attach_flags_send = hello->attach_flags_send;
+	attach_flags_recv = hello->attach_flags_recv;
+
+	/* 'any' degrades to 'all' for compatibility */
+	if (attach_flags_send == _KDBUS_ATTACH_ANY)
+		attach_flags_send = _KDBUS_ATTACH_ALL;
+
+	if (attach_flags_recv == _KDBUS_ATTACH_ANY)
+		attach_flags_recv = _KDBUS_ATTACH_ALL;
+
+	/* reject unknown attach flags */
+	if (attach_flags_send & ~_KDBUS_ATTACH_ALL)
+		return ERR_PTR(-EINVAL);
+
+	if (attach_flags_recv & ~_KDBUS_ATTACH_ALL)
+		return ERR_PTR(-EINVAL);
+
+	/* Let userspace know which flags are enforced by the bus */
+	hello->attach_flags_send = bus->attach_flags_req | KDBUS_FLAG_KERNEL;
+
+	if (bus->attach_flags_req & ~attach_flags_send)
+		return ERR_PTR(-ECONNREFUSED);
+
+	conn = kzalloc(sizeof(*conn), GFP_KERNEL);
+	if (!conn)
+		return ERR_PTR(-ENOMEM);
+
+	if (is_activator || is_policy_holder) {
+		/*
+		 * Policy holders may install one name, and are
+		 * allowed to use wildcards.
+		 */
+		ret = kdbus_policy_set(&bus->policy_db, hello->items,
+				       KDBUS_ITEMS_SIZE(hello, items),
+				       1, is_policy_holder, conn);
+		if (ret < 0)
+			goto exit_free_conn;
+	}
+
+	if (conn_name) {
+		conn->name = kstrdup(conn_name, GFP_KERNEL);
+		if (!conn->name) {
+			ret = -ENOMEM;
+			goto exit_free_conn;
+		}
+	}
+
+	kref_init(&conn->kref);
+	atomic_set(&conn->active, 0);
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+	lockdep_init_map(&conn->dep_map, "s_active", &__key, 0);
+#endif
+	mutex_init(&conn->lock);
+	INIT_LIST_HEAD(&conn->names_list);
+	INIT_LIST_HEAD(&conn->names_queue_list);
+	INIT_LIST_HEAD(&conn->reply_list);
+	atomic_set(&conn->name_count, 0);
+	atomic_set(&conn->reply_count, 0);
+	atomic_set(&conn->lost_count, 0);
+	INIT_DELAYED_WORK(&conn->work, kdbus_conn_work);
+	conn->cred = get_current_cred();
+	init_waitqueue_head(&conn->wait);
+	kdbus_queue_init(&conn->queue);
+	conn->privileged = privileged;
+
+	/* init entry, so we can unconditionally remove it */
+	INIT_LIST_HEAD(&conn->monitor_entry);
+
+	conn->pool = kdbus_pool_new(conn->name, hello->pool_size);
+	if (IS_ERR(conn->pool)) {
+		ret = PTR_ERR(conn->pool);
+		conn->pool = NULL;
+		goto exit_unref_cred;
+	}
+
+	conn->match_db = kdbus_match_db_new();
+	if (IS_ERR(conn->match_db)) {
+		ret = PTR_ERR(conn->match_db);
+		conn->match_db = NULL;
+		goto exit_free_pool;
+	}
+
+	conn->ep = kdbus_ep_ref(ep);
+
+	/* get new id for this connection */
+	conn->id = atomic64_inc_return(&bus->conn_seq_last);
+
+	/* return properties of this connection to the caller */
+	hello->bus_flags = bus->bus_flags;
+	hello->bloom = bus->bloom;
+	hello->id = conn->id;
+
+	BUILD_BUG_ON(sizeof(bus->id128) != sizeof(hello->id128));
+	memcpy(hello->id128, bus->id128, sizeof(hello->id128));
+
+	conn->flags = hello->flags;
+	atomic64_set(&conn->attach_flags_send, attach_flags_send);
+	atomic64_set(&conn->attach_flags_recv, attach_flags_recv);
+
+	if (is_activator) {
+		u64 flags = KDBUS_NAME_ACTIVATOR;
+
+		ret = kdbus_name_acquire(bus->name_registry, conn,
+					 name, &flags);
+		if (ret < 0)
+			goto exit_unref_ep;
+	}
+
+	if (is_monitor) {
+		down_write(&bus->conn_rwlock);
+		list_add_tail(&conn->monitor_entry, &bus->monitors_list);
+		up_write(&bus->conn_rwlock);
+	}
+
+	/* privileged processes can impersonate somebody else */
+	if (creds || seclabel) {
+		conn->owner_meta = kdbus_meta_new();
+		if (IS_ERR(conn->owner_meta)) {
+			ret = PTR_ERR(conn->owner_meta);
+			conn->owner_meta = NULL;
+			goto exit_release_names;
+		}
+
+		if (creds) {
+			ret = kdbus_meta_append_data(conn->owner_meta,
+						     KDBUS_ITEM_CREDS,
+						     creds, sizeof(*creds));
+			if (ret < 0)
+				goto exit_free_meta;
+		}
+
+		if (seclabel) {
+			ret = kdbus_meta_append_data(conn->owner_meta,
+						     KDBUS_ITEM_SECLABEL,
+						     seclabel, seclabel_len);
+			if (ret < 0)
+				goto exit_free_meta;
+		}
+
+		/* use the information provided with the HELLO call */
+		conn->meta = conn->owner_meta;
+	} else {
+		/* use the connection's metadata gathered at open() */
+		conn->meta = meta;
+	}
+
+	/*
+	 * Account the connection against the current user (UID), or for
+	 * custom endpoints use the anonymous user assigned to the endpoint.
+	 */
+	if (ep->user) {
+		conn->user = kdbus_domain_user_ref(ep->user);
+	} else {
+		conn->user = kdbus_domain_get_user(ep->bus->domain,
+						   current_fsuid());
+		if (IS_ERR(conn->user)) {
+			ret = PTR_ERR(conn->user);
+			conn->user = NULL;
+			goto exit_free_meta;
+		}
+	}
+
+	/* lock order: domain -> bus -> ep -> names -> conn */
+	mutex_lock(&bus->lock);
+	mutex_lock(&ep->lock);
+	down_write(&bus->conn_rwlock);
+
+	if (atomic_inc_return(&conn->user->connections) > KDBUS_USER_MAX_CONN) {
+		atomic_dec(&conn->user->connections);
+		ret = -EMFILE;
+		goto exit_unref_user_unlock;
+	}
+
+	/* make sure the ep-node is active while we add our connection */
+	if (!kdbus_node_acquire(&ep->node)) {
+		atomic_dec(&conn->user->connections);
+		ret = -ESHUTDOWN;
+		goto exit_unref_user_unlock;
+	}
+
+	/* link into bus and endpoint */
+	list_add_tail(&conn->ep_entry, &ep->conn_list);
+	hash_add(bus->conn_hash, &conn->hentry, conn->id);
+
+	kdbus_node_release(&ep->node);
+	up_write(&bus->conn_rwlock);
+	mutex_unlock(&ep->lock);
+	mutex_unlock(&bus->lock);
+
+	/* notify subscribers about the new active connection */
+	ret = kdbus_notify_id_change(conn->ep->bus, KDBUS_ITEM_ID_ADD,
+				     conn->id, conn->flags);
+	if (ret < 0) {
+		atomic_dec(&conn->user->connections);
+		goto exit_domain_user_unref;
+	}
+
+	kdbus_notify_flush(conn->ep->bus);
+
+	return conn;
+
+exit_unref_user_unlock:
+	up_write(&bus->conn_rwlock);
+	mutex_unlock(&ep->lock);
+	mutex_unlock(&bus->lock);
+exit_domain_user_unref:
+	kdbus_domain_user_unref(conn->user);
+exit_free_meta:
+	kdbus_meta_free(conn->owner_meta);
+exit_release_names:
+	kdbus_name_remove_by_conn(bus->name_registry, conn);
+exit_unref_ep:
+	kdbus_ep_unref(conn->ep);
+	kdbus_match_db_free(conn->match_db);
+exit_free_pool:
+	kdbus_pool_free(conn->pool);
+exit_unref_cred:
+	put_cred(conn->cred);
+exit_free_conn:
+	kfree(conn->name);
+	kfree(conn);
+
+	return ERR_PTR(ret);
+}
+
+/**
+ * kdbus_conn_has_name() - check if a connection owns a name
+ * @conn:		Connection
+ * @name:		Well-know name to check for
+ *
+ * Return: true if the name is currently owned by the connection
+ */
+bool kdbus_conn_has_name(struct kdbus_conn *conn, const char *name)
+{
+	struct kdbus_name_entry *e;
+	bool match = false;
+
+	/* No need to go further if we do not own names */
+	if (atomic_read(&conn->name_count) == 0)
+		return false;
+
+	mutex_lock(&conn->lock);
+	list_for_each_entry(e, &conn->names_list, conn_entry) {
+		if (strcmp(e->name, name) == 0) {
+			match = true;
+			break;
+		}
+	}
+	mutex_unlock(&conn->lock);
+
+	return match;
+}
ipc/kdbus/connection.h new file +188 -0

188 lines not on this page · raw message

ipc/kdbus/item.c new file +258 -0

258 lines not on this page · raw message

ipc/kdbus/item.h new file +41 -0

41 lines not on this page · raw message

ipc/kdbus/message.c new file +444 -0

444 lines not on this page · raw message

ipc/kdbus/message.h new file +75 -0

75 lines not on this page · raw message

ipc/kdbus/queue.c new file +608 -0

156 lines not on this page · raw message

ipc/kdbus/queue.h new file +93 -0

93 lines not on this page · raw message

ipc/kdbus/util.h +1 -1
index e727a2134d0c..39347a394bc8 100644

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

Signature · 1 line
2.1.3

Part of the diff is not shown here. View the raw message.

#26 lore raw

kdbus: add node and filesystem implementation

In reply to Greg Kroah-Hartman

From: Daniel Mack <[email protected]>

kdbusfs is a filesystem that will expose a fresh kdbus domain context each time it is mounted. Per mount point, there will be a 'control' node, which can be used to create buses. fs.c contains the implementation of that pseudo-fs. Exported inodes of 'file' type have their i_fop set to either kdbus_handle_control_ops or kdbus_handle_ep_ops, depending on their type. The actual dispatching of file operations is done from handle.c

node.c is an implementation of a kdbus object that has an id and children, organized in an R/B tree. The tree is used by the filesystem code for lookup and iterator functions, and to deactivate children once the parent is deactivated. Every inode exported by kdbusfs is backed by a kdbus_node, hence it is embedded in struct kdbus_ep, struct kdbus_bus and struct kdbus_domain.

---
 include/uapi/linux/magic.h |   1 +
 ipc/kdbus/fs.c             | 417 ++++++++++++++++++++++
 ipc/kdbus/fs.h             |  22 ++
 ipc/kdbus/node.c           | 872 +++++++++++++++++++++++++++++++++++++++++++++
 ipc/kdbus/node.h           |  86 +++++
 5 files changed, 1398 insertions(+)
 create mode 100644 ipc/kdbus/fs.c
 create mode 100644 ipc/kdbus/fs.h
 create mode 100644 ipc/kdbus/node.c
 create mode 100644 ipc/kdbus/node.h
include/uapi/linux/magic.h +1 -0
index 77c60311a6c6..eecf6b9cd185 100644
@@ -72,5 +72,6 @@
 #define MTD_INODE_FS_MAGIC      0x11307854
 #define ANON_INODE_FS_MAGIC	0x09041934
 #define BTRFS_TEST_MAGIC	0x73727279
+#define KDBUS_SUPER_MAGIC	0x44427573
 
 #endif /* __LINUX_MAGIC_H__ */
ipc/kdbus/fs.c new file +417 -0

417 lines not on this page · raw message

ipc/kdbus/fs.h new file +22 -0
new file mode 100644
index 000000000000..29bc9ea07329
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2013-2014 Kay Sievers
+ * Copyright (C) 2013-2014 Greg Kroah-Hartman <[email protected]>
+ * Copyright (C) 2013-2014 Daniel Mack <[email protected]>
+ * Copyright (C) 2013-2014 David Herrmann <[email protected]>
+ * Copyright (C) 2013-2014 Linux Foundation
+ *
+ * kdbus is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ */
+
+#ifndef __KDBUSFS_H
+#define __KDBUSFS_H
+
+#include <linux/kernel.h>
+
+int kdbus_fs_init(void);
+void kdbus_fs_exit(void);
+
+#endif
ipc/kdbus/node.c new file +872 -0

872 lines not on this page · raw message

ipc/kdbus/node.h new file +86 -0

86 lines not on this page · raw message

Signature · 1 line
2.1.3
#27 lore raw

Re: kdbus: add node and filesystem implementation

Quoted 12 lines · Greg Kroah-Hartman
ipc/kdbus/fs.c new file +12 -0
+static struct dentry *fs_dir_iop_lookup(struct inode *dir,
+					struct dentry *dentry,
+					unsigned int flags)
+{
+	struct dentry *dnew = NULL;
+	struct kdbus_node *parent;
+	struct kdbus_node *node;
+	struct inode *inode;
+
+	parent = kdbus_node_from_dentry(dentry->d_parent);
+	if (!kdbus_node_acquire(parent))
+		return NULL;

ipc/kdbus/fs.c line 172

Quoted 10 lines
ipc/kdbus/fs.c new file +10 -0
+
+	/* returns reference to _acquired_ child node */
+	node = kdbus_node_find_child(parent, dentry->d_name.name);
+	if (node) {
+		dentry->d_fsdata = node;
+		inode = fs_inode_get(dir->i_sb, node);
+		if (IS_ERR(inode))
+			dnew = ERR_CAST(inode);
+		else
+			dnew = d_materialise_unique(dentry, inode);

d_materialise_unique() is gone in Al's fs tree:

[mandatory]
d_materialise_unique() is gone; d_splice_alias() does everything you need now. Remember that they have opposite orders of arguments ;-/

Maybe it's worth basing your git tree on top of Al's rather than a random -rc, since it's now a filesystem?

Thanks,
Sasha

#28 lore raw

Re: kdbus: add node and filesystem implementation

Hi

Quoted 26 lines · Sasha Levin
Quoted 12 lines · Greg Kroah-Hartman
ipc/kdbus/fs.c new file +12 -0
+static struct dentry *fs_dir_iop_lookup(struct inode *dir,
+                                     struct dentry *dentry,
+                                     unsigned int flags)
+{
+     struct dentry *dnew = NULL;
+     struct kdbus_node *parent;
+     struct kdbus_node *node;
+     struct inode *inode;
+
+     parent = kdbus_node_from_dentry(dentry->d_parent);
+     if (!kdbus_node_acquire(parent))
+             return NULL;

ipc/kdbus/fs.c line 172

Quoted 10 lines
ipc/kdbus/fs.c new file +10 -0
+
+     /* returns reference to _acquired_ child node */
+     node = kdbus_node_find_child(parent, dentry->d_name.name);
+     if (node) {
+             dentry->d_fsdata = node;
+             inode = fs_inode_get(dir->i_sb, node);
+             if (IS_ERR(inode))
+                     dnew = ERR_CAST(inode);
+             else
+                     dnew = d_materialise_unique(dentry, inode);

d_materialise_unique() is gone in Al's fs tree:

Quoted 3 lines

[mandatory]
d_materialise_unique() is gone; d_splice_alias() does everything you need now. Remember that they have opposite orders of arguments ;-/

That was actually pushed after we prepared v2, so I haven't seen it yet. I now rebased on top of vfs.git#for-next, with d_materialise_unique() -> d_splice_alias(). Thanks for the hint!

Quoted 2 lines

Maybe it's worth basing your git tree on top of Al's rather than a random -rc, since it's now a filesystem?

Sure, sounds good.

Thanks
David

#29 lore raw

Re: kdbus: add node and filesystem implementation

Quoted 33 lines · David Herrmann

Hi

Quoted 26 lines · Sasha Levin
Quoted 12 lines · Greg Kroah-Hartman
ipc/kdbus/fs.c new file +12 -0
+static struct dentry *fs_dir_iop_lookup(struct inode *dir,
+                                     struct dentry *dentry,
+                                     unsigned int flags)
+{
+     struct dentry *dnew = NULL;
+     struct kdbus_node *parent;
+     struct kdbus_node *node;
+     struct inode *inode;
+
+     parent = kdbus_node_from_dentry(dentry->d_parent);
+     if (!kdbus_node_acquire(parent))
+             return NULL;

ipc/kdbus/fs.c line 172

Quoted 10 lines
ipc/kdbus/fs.c new file +10 -0
+
+     /* returns reference to _acquired_ child node */
+     node = kdbus_node_find_child(parent, dentry->d_name.name);
+     if (node) {
+             dentry->d_fsdata = node;
+             inode = fs_inode_get(dir->i_sb, node);
+             if (IS_ERR(inode))
+                     dnew = ERR_CAST(inode);
+             else
+                     dnew = d_materialise_unique(dentry, inode);

d_materialise_unique() is gone in Al's fs tree:

Quoted 3 lines

[mandatory]
d_materialise_unique() is gone; d_splice_alias() does everything you need now. Remember that they have opposite orders of arguments ;-/

Quoted 8 lines

That was actually pushed after we prepared v2, so I haven't seen it yet. I now rebased on top of vfs.git#for-next, with d_materialise_unique() -> d_splice_alias(). Thanks for the hint!

Quoted 2 lines

Maybe it's worth basing your git tree on top of Al's rather than a random -rc, since it's now a filesystem?

Sure, sounds good.

No, I'll keep it as is, we can handle the merge issues later when it hits Linus's tree, this makes it easier for me and others to test it out properly.

thanks,

greg k-h

#30 lore raw

Re: kdbus: add node and filesystem implementation

Quoted 7 lines · Greg Kroah-Hartman
Quoted 4 lines
Quoted 4 lines

Maybe it's worth basing your git tree on top of Al's rather than a random

Quoted 1 line
Quoted 1 line

-rc, since it's now a filesystem?

Sure, sounds good.

No, I'll keep it as is, we can handle the merge issues later when it hits Linus's tree, this makes it easier for me and others to test it out properly.

It should be hitting -next, not Linus's tree. This is why we have an integration tree, no?

Thanks,
Sasha

#31 lore raw

Re: kdbus: add node and filesystem implementation

Quoted 11 lines · Sasha Levin
Quoted 7 lines · Greg Kroah-Hartman
Quoted 4 lines
Quoted 4 lines

Maybe it's worth basing your git tree on top of Al's rather than a random

Quoted 1 line
Quoted 1 line

-rc, since it's now a filesystem?

Sure, sounds good.

No, I'll keep it as is, we can handle the merge issues later when it hits Linus's tree, this makes it easier for me and others to test it out properly.

It should be hitting -next, not Linus's tree. This is why we have an integration tree, no?

Yes, it will hit -next, and the merge issue can be resolved there.

#32 lore raw

Re: kdbus: add node and filesystem implementation

In reply to Greg Kroah-Hartman
Quoted 24 lines · Greg Kroah-Hartman

From: Daniel Mack <[email protected]>

kdbusfs is a filesystem that will expose a fresh kdbus domain context each time it is mounted. Per mount point, there will be a 'control' node, which can be used to create buses. fs.c contains the implementation of that pseudo-fs. Exported inodes of 'file' type have their i_fop set to either kdbus_handle_control_ops or kdbus_handle_ep_ops, depending on their type. The actual dispatching of file operations is done from handle.c

node.c is an implementation of a kdbus object that has an id and children, organized in an R/B tree. The tree is used by the filesystem code for lookup and iterator functions, and to deactivate children once the parent is deactivated. Every inode exported by kdbusfs is backed by a kdbus_node, hence it is embedded in struct kdbus_ep, struct kdbus_bus and struct kdbus_domain.

---

ipc/kdbus/fs.c line 382

Quoted 7 lines
ipc/kdbus/fs.c new file +7 -0
+
+static struct file_system_type fs_type = {
+       .name           = KBUILD_MODNAME "fs",
+       .owner          = THIS_MODULE,
+       .mount          = fs_super_mount,
+       .kill_sb        = fs_super_kill,
+};

Does this want something like:

.fs_flags = FS_USERNS_MOUNT

This design may have the annoying property that, if a namespace-based sandbox wants to use kdbus itself, it will need to proxy anything from the parent that it wants to use.

Is there a good reason why individual *busses* don't show up in the filesystem? If they did, maybe they could be bind-mounted or otherwise arranged to cross namespace boundaries.

--Andy

#33 lore raw

Re: kdbus: add node and filesystem implementation

Quoted 38 lines · Andy Lutomirski
Quoted 24 lines · Greg Kroah-Hartman

From: Daniel Mack <[email protected]>

kdbusfs is a filesystem that will expose a fresh kdbus domain context each time it is mounted. Per mount point, there will be a 'control' node, which can be used to create buses. fs.c contains the implementation of that pseudo-fs. Exported inodes of 'file' type have their i_fop set to either kdbus_handle_control_ops or kdbus_handle_ep_ops, depending on their type. The actual dispatching of file operations is done from handle.c

node.c is an implementation of a kdbus object that has an id and children, organized in an R/B tree. The tree is used by the filesystem code for lookup and iterator functions, and to deactivate children once the parent is deactivated. Every inode exported by kdbusfs is backed by a kdbus_node, hence it is embedded in struct kdbus_ep, struct kdbus_bus and struct kdbus_domain.

---

ipc/kdbus/fs.c line 382

Quoted 7 lines
ipc/kdbus/fs.c new file +7 -0
+
+static struct file_system_type fs_type = {
+       .name           = KBUILD_MODNAME "fs",
+       .owner          = THIS_MODULE,
+       .mount          = fs_super_mount,
+       .kill_sb        = fs_super_kill,
+};

Does this want something like:

.fs_flags = FS_USERNS_MOUNT

Quoted 8 lines

This design may have the annoying property that, if a namespace-based sandbox wants to use kdbus itself, it will need to proxy anything from the parent that it wants to use.

Is there a good reason why individual *busses* don't show up in the filesystem? If they did, maybe they could be bind-mounted or otherwise arranged to cross namespace boundaries.

Whoops. Brainfart there -- busses do show up in the filesystem. Does bind-mounting them work?

--Andy

#34 lore raw

Re: kdbus: add node and filesystem implementation

In reply to Andy Lutomirski

Hi

Quoted 36 lines · Andy Lutomirski
Quoted 24 lines · Greg Kroah-Hartman

From: Daniel Mack <[email protected]>

kdbusfs is a filesystem that will expose a fresh kdbus domain context each time it is mounted. Per mount point, there will be a 'control' node, which can be used to create buses. fs.c contains the implementation of that pseudo-fs. Exported inodes of 'file' type have their i_fop set to either kdbus_handle_control_ops or kdbus_handle_ep_ops, depending on their type. The actual dispatching of file operations is done from handle.c

node.c is an implementation of a kdbus object that has an id and children, organized in an R/B tree. The tree is used by the filesystem code for lookup and iterator functions, and to deactivate children once the parent is deactivated. Every inode exported by kdbusfs is backed by a kdbus_node, hence it is embedded in struct kdbus_ep, struct kdbus_bus and struct kdbus_domain.

---

ipc/kdbus/fs.c line 382

Quoted 7 lines
ipc/kdbus/fs.c new file +7 -0
+
+static struct file_system_type fs_type = {
+       .name           = KBUILD_MODNAME "fs",
+       .owner          = THIS_MODULE,
+       .mount          = fs_super_mount,
+       .kill_sb        = fs_super_kill,
+};

Does this want something like:

Quoted 1 line

.fs_flags = FS_USERNS_MOUNT

Yes, we should add that. Nice catch!

Quoted 7 lines

This design may have the annoying property that, if a namespace-based sandbox wants to use kdbus itself, it will need to proxy anything from the parent that it wants to use.

Is there a good reason why individual *busses* don't show up in the filesystem? If they did, maybe they could be bind-mounted or otherwise arranged to cross namespace boundaries.

Buses show up as directories in kdbusfs. You can bind-mount them anywhere you want and you will get access to the endpoints in there.

Thanks
David

#35 lore raw

kdbus: add code to gather metadata

In reply to Greg Kroah-Hartman

From: Daniel Mack <[email protected]>

A connection chooses which metadata it wants to have attached to each message it receives with kdbus_cmd_hello.attach_flags. The metadata will be attached as items to the messages. All metadata refers to information about the sending task at sending time, unless otherwise stated. Also, the metadata is copied, not referenced, so even if the sending task doesn't exist anymore at the time the message is received, the information is still preserved.

See kdbus.txt for more details on which metadata can currently be attached to messages.

---
 ipc/kdbus/metadata.c | 698 +++++++++++++++++++++++++++++++++++++++++++++++++++
 ipc/kdbus/metadata.h |  38 +++
 2 files changed, 736 insertions(+)
 create mode 100644 ipc/kdbus/metadata.c
 create mode 100644 ipc/kdbus/metadata.h
ipc/kdbus/metadata.c new file +698 -0
new file mode 100644
index 000000000000..be70e6c8dcb6
@@ -0,0 +1,698 @@
+/*
+ * Copyright (C) 2013-2014 Kay Sievers
+ * Copyright (C) 2013-2014 Greg Kroah-Hartman <[email protected]>
+ * Copyright (C) 2013-2014 Daniel Mack <[email protected]>
+ * Copyright (C) 2013-2014 David Herrmann <[email protected]>
+ * Copyright (C) 2013-2014 Linux Foundation
+ *
+ * kdbus is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ */
+
+#include <linux/audit.h>
+#include <linux/capability.h>
+#include <linux/cgroup.h>
+#include <linux/cred.h>
+#include <linux/file.h>
+#include <linux/init.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/security.h>
+#include <linux/sizes.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/version.h>
+
+#include "bus.h"
+#include "connection.h"
+#include "domain.h"
+#include "endpoint.h"
+#include "item.h"
+#include "message.h"
+#include "metadata.h"
+#include "names.h"
+#include "pool.h"
+
+/**
+ * struct kdbus_meta - metadata buffer
+ * @attached:		Flags for already attached data
+ * @data:		Allocated buffer
+ * @size:		Number of bytes used
+ * @allocated_size:	Size of buffer
+ *
+ * Used to collect and store connection metadata in a pre-compiled
+ * buffer containing struct kdbus_item.
+ */
+struct kdbus_meta {
+	u64 attached;
+	struct kdbus_item *data;
+	size_t size;
+	size_t allocated_size;
+};
+
+/**
+ * kdbus_meta_new() - create new metadata object
+ *
+ * Return: a new kdbus_meta object on success, ERR_PTR on failure.
+ */
+struct kdbus_meta *kdbus_meta_new(void)
+{
+	struct kdbus_meta *m;
+
+	m = kzalloc(sizeof(*m), GFP_KERNEL);
+	if (!m)
+		return ERR_PTR(-ENOMEM);
+
+	return m;
+}
+
+/**
+ * kdbus_meta_dup() - Duplicate a meta object
+ *
+ * @orig:	The meta object to duplicate
+ *
+ * Return: a new kdbus_meta object on success, ERR_PTR on failure.
+ */
+struct kdbus_meta *kdbus_meta_dup(const struct kdbus_meta *orig)
+{
+	struct kdbus_meta *m;
+
+	BUG_ON(!orig);
+
+	m = kmalloc(sizeof(*m), GFP_KERNEL);
+	if (!m)
+		return ERR_PTR(-ENOMEM);
+
+	m->data = kmemdup(orig->data, orig->allocated_size, GFP_KERNEL);
+	if (!m->data) {
+		kfree(m);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	m->attached = orig->attached;
+	m->allocated_size = orig->allocated_size;
+	m->size = orig->size;
+
+	return m;
+}
+
+/**
+ * kdbus_meta_free() - release metadata
+ * @meta:		Metadata object
+ */
+void kdbus_meta_free(struct kdbus_meta *meta)
+{
+	if (!meta)
+		return;
+
+	kfree(meta->data);
+	kfree(meta);
+}
+
+static struct kdbus_item *
+kdbus_meta_append_item(struct kdbus_meta *meta, u64 type, size_t payload_size)
+{
+	size_t extra_size = KDBUS_ITEM_SIZE(payload_size);
+	struct kdbus_item *item;
+	size_t size;
+
+	/* get new metadata buffer, pre-allocate at least 512 bytes */
+	if (!meta->data) {
+		size = roundup_pow_of_two(256 + extra_size);
+		meta->data = kzalloc(size, GFP_KERNEL);
+		if (!meta->data)
+			return ERR_PTR(-ENOMEM);
+
+		meta->allocated_size = size;
+	}
+
+	/* double the pre-allocated buffer size if needed */
+	size = meta->size + extra_size;
+	if (size > meta->allocated_size) {
+		size_t size_diff;
+		struct kdbus_item *data;
+
+		size = roundup_pow_of_two(size);
+		size_diff = size - meta->allocated_size;
+		data = kmalloc(size, GFP_KERNEL);
+		if (!data)
+			return ERR_PTR(-ENOMEM);
+
+		memcpy(data, meta->data, meta->size);
+		memset((u8 *)data + meta->allocated_size, 0, size_diff);
+
+		kfree(meta->data);
+		meta->data = data;
+		meta->allocated_size = size;
+	}
+
+	/* insert new record */
+	item = (struct kdbus_item *)((u8 *)meta->data + meta->size);
+	item->type = type;
+	item->size = KDBUS_ITEM_HEADER_SIZE + payload_size;
+
+	meta->size += extra_size;
+
+	return item;
+}
+
+/**
+ * kdbus_meta_append_data() - append given raw data to metadata object
+ * @meta:		Metadata object
+ * @type:		KDBUS_ITEM_* type
+ * @data:		pointer to data to copy from. If it is NULL
+ *			then just make space in the metadata buffer.
+ * @len:		number of bytes to copy
+ *
+ * Return: 0 on success, negative errno on failure.
+ */
+int kdbus_meta_append_data(struct kdbus_meta *meta, u64 type,
+			   const void *data, size_t len)
+{
+	struct kdbus_item *item;
+
+	if (len == 0)
+		return 0;
+
+	item = kdbus_meta_append_item(meta, type, len);
+	if (IS_ERR(item))
+		return PTR_ERR(item);
+
+	if (data)
+		memcpy(item->data, data, len);
+
+	return 0;
+}
+
+static int kdbus_meta_append_str(struct kdbus_meta *meta, u64 type,
+				 const char *str)
+{
+	return kdbus_meta_append_data(meta, type, str, strlen(str) + 1);
+}
+
+static int kdbus_meta_append_timestamp(struct kdbus_meta *meta,
+				       u64 seq)
+{
+	struct kdbus_item *item;
+	struct timespec ts;
+
+	item = kdbus_meta_append_item(meta, KDBUS_ITEM_TIMESTAMP,
+				      sizeof(struct kdbus_timestamp));
+	if (IS_ERR(item))
+		return PTR_ERR(item);
+
+	if (seq > 0)
+		item->timestamp.seqnum = seq;
+
+	ktime_get_ts(&ts);
+	item->timestamp.monotonic_ns = timespec_to_ns(&ts);
+
+	ktime_get_real_ts(&ts);
+	item->timestamp.realtime_ns = timespec_to_ns(&ts);
+
+	return 0;
+}
+
+static int kdbus_meta_append_cred(struct kdbus_meta *meta,
+				  const struct kdbus_domain *domain)
+{
+	struct kdbus_creds creds = {
+		.uid = from_kuid_munged(domain->user_namespace, current_uid()),
+		.gid = from_kgid_munged(domain->user_namespace, current_gid()),
+		.pid = task_pid_nr_ns(current, domain->pid_namespace),
+		.tid = task_tgid_nr_ns(current, domain->pid_namespace),
+		.starttime = current->start_time,
+	};
+
+	return kdbus_meta_append_data(meta, KDBUS_ITEM_CREDS,
+				      &creds, sizeof(creds));
+}
+
+static int kdbus_meta_append_auxgroups(struct kdbus_meta *meta,
+				       const struct kdbus_domain *domain)
+{
+	struct group_info *info;
+	struct kdbus_item *item;
+	int i, ret = 0;
+	u64 *gid;
+
+	info = get_current_groups();
+	item = kdbus_meta_append_item(meta, KDBUS_ITEM_AUXGROUPS,
+				      info->ngroups * sizeof(*gid));
+	if (IS_ERR(item)) {
+		ret = PTR_ERR(item);
+		goto exit_put_groups;
+	}
+
+	gid = (u64 *) item->data;
+
+	for (i = 0; i < info->ngroups; i++)
+		gid[i] = from_kgid_munged(domain->user_namespace,
+					  GROUP_AT(info, i));
+
+exit_put_groups:
+	put_group_info(info);
+
+	return ret;
+}
+
+static int kdbus_meta_append_src_names(struct kdbus_meta *meta,
+				       struct kdbus_conn *conn)
+{
+	struct kdbus_name_entry *e;
+	int ret = 0;
+
+	if (!conn)
+		return 0;
+
+	mutex_lock(&conn->lock);
+	list_for_each_entry(e, &conn->names_list, conn_entry) {
+		struct kdbus_item *item;
+		size_t len;
+
+		len = strlen(e->name) + 1;
+		item = kdbus_meta_append_item(meta, KDBUS_ITEM_OWNED_NAME,
+					      sizeof(struct kdbus_name) + len);
+		if (IS_ERR(item)) {
+			ret = PTR_ERR(item);
+			break;
+		}
+
+		item->name.flags = e->flags;
+		memcpy(item->name.name, e->name, len);
+	}
+	mutex_unlock(&conn->lock);
+
+	return ret;
+}
+
+static int kdbus_meta_append_exe(struct kdbus_meta *meta)
+{
+	struct mm_struct *mm = get_task_mm(current);
+	struct path *exe_path = NULL;
+	char *pathname;
+	int ret = 0;
+	size_t len;
+	char *tmp;
+
+	if (!mm)
+		return -EFAULT;
+
+	down_read(&mm->mmap_sem);
+	if (mm->exe_file) {
+		path_get(&mm->exe_file->f_path);
+		exe_path = &mm->exe_file->f_path;
+	}
+	up_read(&mm->mmap_sem);
+
+	if (!exe_path)
+		goto exit_mmput;
+
+	tmp = (char *)__get_free_page(GFP_TEMPORARY | __GFP_ZERO);
+	if (!tmp) {
+		ret = -ENOMEM;
+		goto exit_path_put;
+	}
+
+	pathname = d_path(exe_path, tmp, PAGE_SIZE);
+	if (IS_ERR(pathname)) {
+		ret = PTR_ERR(pathname);
+		goto exit_free_page;
+	}
+
+	len = tmp + PAGE_SIZE - pathname;
+	ret = kdbus_meta_append_data(meta, KDBUS_ITEM_EXE, pathname, len);
+
+exit_free_page:
+	free_page((unsigned long) tmp);
+
+exit_path_put:
+	path_put(exe_path);
+
+exit_mmput:
+	mmput(mm);
+
+	return ret;
+}
+
+static int kdbus_meta_append_cmdline(struct kdbus_meta *meta)
+{
+	struct mm_struct *mm;
+	int ret = 0;
+	size_t len;
+	char *tmp;
+
+	tmp = (char *)__get_free_page(GFP_TEMPORARY | __GFP_ZERO);
+	if (!tmp)
+		return -ENOMEM;
+
+	mm = get_task_mm(current);
+	if (!mm) {
+		ret = -EFAULT;
+		goto exit_free_page;
+	}
+
+	if (!mm->arg_end)
+		goto exit_mmput;
+
+	len = mm->arg_end - mm->arg_start;
+	if (len > PAGE_SIZE)
+		len = PAGE_SIZE;
+
+	ret = copy_from_user(tmp, (const char __user *)mm->arg_start, len);
+	if (ret < 0)
+		goto exit_mmput;
+
+	ret = kdbus_meta_append_data(meta, KDBUS_ITEM_CMDLINE, tmp, len);
+
+exit_mmput:
+	mmput(mm);
+
+exit_free_page:
+	free_page((unsigned long) tmp);
+
+	return ret;
+}
+
+static int kdbus_meta_append_caps(struct kdbus_meta *meta)
+{
+	struct caps {
+		u32 last_cap;
+		struct {
+			u32 caps[_KERNEL_CAPABILITY_U32S];
+		} set[4];
+	} caps;
+	unsigned int i;
+	const struct cred *cred = current_cred();
+
+	caps.last_cap = CAP_LAST_CAP;
+
+	for (i = 0; i < _KERNEL_CAPABILITY_U32S; i++) {
+		caps.set[0].caps[i] = cred->cap_inheritable.cap[i];
+		caps.set[1].caps[i] = cred->cap_permitted.cap[i];
+		caps.set[2].caps[i] = cred->cap_effective.cap[i];
+		caps.set[3].caps[i] = cred->cap_bset.cap[i];
+	}
+
+	/* clear unused bits */
+	for (i = 0; i < 4; i++)
+		caps.set[i].caps[CAP_TO_INDEX(CAP_LAST_CAP)] &=
+			CAP_TO_MASK(CAP_LAST_CAP + 1) - 1;
+
+	return kdbus_meta_append_data(meta, KDBUS_ITEM_CAPS,
+				      &caps, sizeof(caps));
+}
+
+#ifdef CONFIG_CGROUPS
+static int kdbus_meta_append_cgroup(struct kdbus_meta *meta)
+{
+	char *buf, *path;
+	int ret;
+
+	buf = (char *)__get_free_page(GFP_TEMPORARY | __GFP_ZERO);
+	if (!buf)
+		return -ENOMEM;
+
+	path = task_cgroup_path(current, buf, PAGE_SIZE);
+
+	if (path)
+		ret = kdbus_meta_append_str(meta, KDBUS_ITEM_CGROUP, path);
+	else
+		ret = -ENAMETOOLONG;
+
+	free_page((unsigned long) buf);
+
+	return ret;
+}
+#endif
+
+#ifdef CONFIG_AUDITSYSCALL
+static int kdbus_meta_append_audit(struct kdbus_meta *meta,
+				   const struct kdbus_domain *domain)
+{
+	struct kdbus_audit audit;
+
+	audit.loginuid = from_kuid_munged(domain->user_namespace,
+					  audit_get_loginuid(current));
+	audit.sessionid = audit_get_sessionid(current);
+
+	return kdbus_meta_append_data(meta, KDBUS_ITEM_AUDIT,
+				      &audit, sizeof(audit));
+}
+#endif
+
+#ifdef CONFIG_SECURITY
+static int kdbus_meta_append_seclabel(struct kdbus_meta *meta)
+{
+	u32 len, sid;
+	char *label;
+	int ret;
+
+	security_task_getsecid(current, &sid);
+	ret = security_secid_to_secctx(sid, &label, &len);
+	if (ret == -EOPNOTSUPP)
+		return 0;
+	if (ret < 0)
+		return ret;
+
+	if (label && len > 0)
+		ret = kdbus_meta_append_data(meta, KDBUS_ITEM_SECLABEL,
+					     label, len);
+	security_release_secctx(label, len);
+
+	return ret;
+}
+#endif
+
+/**
+ * kdbus_meta_append() - collect metadata from current process
+ * @meta:		Metadata object
+ * @domain:		The domain to use for namespace translations
+ * @conn:		Current connection to read names from
+ * @seq:		Message sequence number
+ * @which:		KDBUS_ATTACH_* flags which typ of data to attach
+ *
+ * Collect the data specified in flags and allocate or extend
+ * the buffer in the metadata object.
+ *
+ * Return: 0 on success, negative errno on failure.
+ */
+int kdbus_meta_append(struct kdbus_meta *meta,
+		      struct kdbus_domain *domain,
+		      struct kdbus_conn *conn,
+		      u64 seq, u64 which)
+{
+	int ret;
+	u64 mask;
+
+	/* which metadata is wanted but not yet attached? */
+	mask = which & ~meta->attached;
+	if (mask == 0)
+		return 0;
+
+	if (mask & KDBUS_ATTACH_TIMESTAMP) {
+		ret = kdbus_meta_append_timestamp(meta, seq);
+		if (ret < 0)
+			return ret;
+
+		meta->attached |= KDBUS_ATTACH_TIMESTAMP;
+	}
+
+	if (mask & KDBUS_ATTACH_CREDS) {
+		ret = kdbus_meta_append_cred(meta, domain);
+		if (ret < 0)
+			return ret;
+
+		meta->attached |= KDBUS_ATTACH_CREDS;
+	}
+
+	if (mask & KDBUS_ATTACH_AUXGROUPS) {
+		ret = kdbus_meta_append_auxgroups(meta, domain);
+		if (ret < 0)
+			return ret;
+
+		meta->attached |= KDBUS_ATTACH_AUXGROUPS;
+	}
+
+	if (mask & KDBUS_ATTACH_NAMES && conn) {
+		ret = kdbus_meta_append_src_names(meta, conn);
+		if (ret < 0)
+			return ret;
+
+		meta->attached |= KDBUS_ATTACH_NAMES;
+	}
+
+	if (mask & KDBUS_ATTACH_TID_COMM) {
+		char comm[TASK_COMM_LEN];
+
+		get_task_comm(comm, current->group_leader);
+		ret = kdbus_meta_append_str(meta, KDBUS_ITEM_TID_COMM, comm);
+		if (ret < 0)
+			return ret;
+
+		meta->attached |= KDBUS_ATTACH_TID_COMM;
+	}
+
+	if (mask & KDBUS_ATTACH_PID_COMM) {
+		char comm[TASK_COMM_LEN];
+
+		get_task_comm(comm, current);
+		ret = kdbus_meta_append_str(meta, KDBUS_ITEM_PID_COMM, comm);
+		if (ret < 0)
+			return ret;
+
+		meta->attached |= KDBUS_ATTACH_PID_COMM;
+	}
+
+	if (mask & KDBUS_ATTACH_EXE) {
+		ret = kdbus_meta_append_exe(meta);
+		if (ret < 0)
+			return ret;
+
+		meta->attached |= KDBUS_ATTACH_EXE;
+	}
+
+	if (mask & KDBUS_ATTACH_CMDLINE) {
+		ret = kdbus_meta_append_cmdline(meta);
+		if (ret < 0)
+			return ret;
+
+		meta->attached |= KDBUS_ATTACH_CMDLINE;
+	}
+
+	/* we always return a 4 elements, the element size is 1/4  */
+	if (mask & KDBUS_ATTACH_CAPS) {
+		ret = kdbus_meta_append_caps(meta);
+		if (ret < 0)
+			return ret;
+
+		meta->attached |= KDBUS_ATTACH_CAPS;
+	}
+
+#ifdef CONFIG_CGROUPS
+	/* attach the path of the one group hierarchy specified for the bus */
+	if (mask & KDBUS_ATTACH_CGROUP) {
+		ret = kdbus_meta_append_cgroup(meta);
+		if (ret < 0)
+			return ret;
+
+		meta->attached |= KDBUS_ATTACH_CGROUP;
+	}
+#endif
+
+#ifdef CONFIG_AUDITSYSCALL
+	if (mask & KDBUS_ATTACH_AUDIT) {
+		ret = kdbus_meta_append_audit(meta, domain);
+		if (ret < 0)
+			return ret;
+
+		meta->attached |= KDBUS_ATTACH_AUDIT;
+	}
+#endif
+
+#ifdef CONFIG_SECURITY
+	if (mask & KDBUS_ATTACH_SECLABEL) {
+		ret = kdbus_meta_append_seclabel(meta);
+		if (ret < 0)
+			return ret;
+
+		meta->attached |= KDBUS_ATTACH_SECLABEL;
+	}
+#endif
+
+	if ((mask & KDBUS_ATTACH_CONN_DESCRIPTION) && conn && conn->name) {
+		ret = kdbus_meta_append_str(meta, KDBUS_ITEM_CONN_DESCRIPTION,
+					    conn->name);
+		if (ret < 0)
+			return ret;
+
+		meta->attached |= KDBUS_ATTACH_CONN_DESCRIPTION;
+	}
+
+	return 0;
+}
+
+static inline u64 kdbus_item_attach_flag(u64 type)
+{
+	BUG_ON(type < _KDBUS_ITEM_ATTACH_BASE);
+	BUG_ON(type >= _KDBUS_ITEM_ATTACH_BASE + 64);
+	return 1ULL << (type - _KDBUS_ITEM_ATTACH_BASE);
+}
+
+/**
+ * kdbus_meta_size() - calculate the size of an excerpt of a metadata db
+ * @meta:	The database object containing the metadata
+ * @conn_dst:	The connection that is about to receive the data
+ * @mask:	Pointer to KDBUS_ATTACH_* bitmask to calculate the size for.
+ *		Callers *must* use the same mask for calls to
+ *		kdbus_meta_write().
+ *
+ * Return: the size in bytes the masked data will consume. Data that should
+ * not received by @conn_dst will be filtered out.
+ */
+size_t kdbus_meta_size(const struct kdbus_meta *meta,
+		       const struct kdbus_conn *conn_dst,
+		       u64 *mask)
+{
+	struct kdbus_domain *domain = conn_dst->ep->bus->domain;
+	const struct kdbus_item *item;
+	size_t size = 0;
+
+	/*
+	 * We currently don't have a way to translate capability flags between
+	 * user namespaces, so let's drop these items in such cases.
+	 */
+	if (domain->user_namespace != current_user_ns())
+		*mask &= ~KDBUS_ATTACH_CAPS;
+
+	/*
+	 * If the domain was created with hide_pid enabled, drop all items
+	 * except for such not revealing anything about the task.
+	 */
+	if (domain->pid_namespace->hide_pid)
+		*mask &= KDBUS_ATTACH_TIMESTAMP | KDBUS_ATTACH_NAMES |
+			 KDBUS_ATTACH_CONN_DESCRIPTION;
+
+	KDBUS_ITEMS_FOREACH(item, meta->data, meta->size)
+		if (*mask & kdbus_item_attach_flag(item->type))
+			size += KDBUS_ALIGN8(item->size);
+
+	return size;
+}
+
+/**
+ * kdbus_meta_write() - Write an excerpt of a metadata db to a slice
+ * @meta:	The database object containing the metadata
+ * @conn_dst:	The connection that is about to receive the data
+ * @mask:	KDBUS_ATTACH_* bitmask to calculate the size for
+ * @slice:	The slice to copy the data to
+ * @off:	The initial offset in the slice to write to
+ *
+ * Copies some of the metadata's items to @slice, if that the item is
+ * suitable for @conn_dst to be received. Otherwise, the item is omitted.
+ * Privided the same input parameters, this function will write exactly as
+ * many bytes as reported by kdbus_meta_size().
+ *
+ * Return: 0 on success, negative error number otherwise.
+ */
+int kdbus_meta_write(const struct kdbus_meta *meta,
+		     const struct kdbus_conn *conn_dst, u64 mask,
+		     const struct kdbus_pool_slice *slice, size_t off)
+{
+	const struct kdbus_item *item;
+	int ret;
+
+	KDBUS_ITEMS_FOREACH(item, meta->data, meta->size)
+		if (mask & kdbus_item_attach_flag(item->type)) {
+			ret = kdbus_pool_slice_copy(slice, off, item,
+						    KDBUS_ALIGN8(item->size));
+			if (ret < 0)
+				return ret;
+
+			off += KDBUS_ALIGN8(item->size);
+		}
+
+	return 0;
+}
ipc/kdbus/metadata.h new file +38 -0
new file mode 100644
index 000000000000..db186bb23d31
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2013-2014 Kay Sievers
+ * Copyright (C) 2013-2014 Greg Kroah-Hartman <[email protected]>
+ * Copyright (C) 2013-2014 Daniel Mack <[email protected]>
+ * Copyright (C) 2013-2014 David Herrmann <[email protected]>
+ * Copyright (C) 2013-2014 Linux Foundation
+ *
+ * kdbus is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ */
+
+#ifndef __KDBUS_METADATA_H
+#define __KDBUS_METADATA_H
+
+struct kdbus_meta;
+struct kdbus_conn;
+struct kdbus_domain;
+struct kdbus_pool_slice;
+
+struct kdbus_meta *kdbus_meta_new(void);
+struct kdbus_meta *kdbus_meta_dup(const struct kdbus_meta *orig);
+int kdbus_meta_append_data(struct kdbus_meta *meta, u64 type,
+			   const void *buf, size_t len);
+int kdbus_meta_append(struct kdbus_meta *meta,
+		      struct kdbus_domain *domain,
+		      struct kdbus_conn *conn,
+		      u64 seq, u64 which);
+void kdbus_meta_free(struct kdbus_meta *meta);
+size_t kdbus_meta_size(const struct kdbus_meta *meta,
+		       const struct kdbus_conn *conn_dst,
+		       u64 *mask);
+int kdbus_meta_write(const struct kdbus_meta *meta,
+		     const struct kdbus_conn *conn_dst, u64 mask,
+		     const struct kdbus_pool_slice *slice, size_t off);
+
+#endif
Signature · 1 line
2.1.3
#36 lore raw

Re: kdbus: add code to gather metadata

Quoted 9 lines · Greg Kroah-Hartman

From: Daniel Mack <[email protected]>

A connection chooses which metadata it wants to have attached to each message it receives with kdbus_cmd_hello.attach_flags. The metadata will be attached as items to the messages. All metadata refers to information about the sending task at sending time, unless otherwise stated. Also, the metadata is copied, not referenced, so even if the sending task doesn't exist anymore at the time the message is received, the information is still preserved.

Namespace comments below.

ipc/kdbus/metadata.c line 225

Quoted 9 lines
ipc/kdbus/metadata.c new file +9 -0
+
+static int kdbus_meta_append_cred(struct kdbus_meta *meta,
+				  const struct kdbus_domain *domain)
+{
+	struct kdbus_creds creds = {
+		.uid = from_kuid_munged(domain->user_namespace, current_uid()),
+		.gid = from_kgid_munged(domain->user_namespace, current_gid()),
+		.pid = task_pid_nr_ns(current, domain->pid_namespace),
+		.tid = task_tgid_nr_ns(current, domain->pid_namespace),

This is better than before -- at least it gets translation right part of the way. But it's still wrong if the receiver's namespace doesn't match the domain.

Also, please move pid and tgid into their own item. They suck for reasons that have been beaten to death. Let's make it possible to deprecate them separately in the future.

ipc/kdbus/metadata.c line 226

Quoted 1 line
ipc/kdbus/metadata.c new file +1 -0
+		.starttime = current->start_time,

I'm repeating myself here, but... why?

Quoted 11 lines
ipc/kdbus/metadata.c new file +11 -0
+static int kdbus_meta_append_auxgroups(struct kdbus_meta *meta,
+				       const struct kdbus_domain *domain)
+{
+	struct group_info *info;
+	struct kdbus_item *item;
+	int i, ret = 0;
+	u64 *gid;
+
+	info = get_current_groups();
+	item = kdbus_meta_append_item(meta, KDBUS_ITEM_AUXGROUPS,
+				      info->ngroups * sizeof(*gid));

ipc/kdbus/metadata.c line 253

Quoted 10 lines
ipc/kdbus/metadata.c new file +10 -0
+	if (IS_ERR(item)) {
+		ret = PTR_ERR(item);
+		goto exit_put_groups;
+	}
+
+	gid = (u64 *) item->data;
+
+	for (i = 0; i < info->ngroups; i++)
+		gid[i] = from_kgid_munged(domain->user_namespace,
+					  GROUP_AT(info, i));

Ditto.

Quoted 1 line

+static int kdbus_meta_append_exe(struct kdbus_meta *meta)

NAK.

Quoted 18 lines
ipc/kdbus/metadata.c new file +18 -0
+{
+	struct mm_struct *mm = get_task_mm(current);
+	struct path *exe_path = NULL;
+	char *pathname;
+	int ret = 0;
+	size_t len;
+	char *tmp;
+
+	if (!mm)
+		return -EFAULT;
+
+	down_read(&mm->mmap_sem);
+	if (mm->exe_file) {
+		path_get(&mm->exe_file->f_path);
+		exe_path = &mm->exe_file->f_path;
+	}
+	up_read(&mm->mmap_sem);
+

ipc/kdbus/metadata.c line 319

Quoted 10 lines
ipc/kdbus/metadata.c new file +10 -0
+	if (!exe_path)
+		goto exit_mmput;
+
+	tmp = (char *)__get_free_page(GFP_TEMPORARY | __GFP_ZERO);
+	if (!tmp) {
+		ret = -ENOMEM;
+		goto exit_path_put;
+	}
+
+	pathname = d_path(exe_path, tmp, PAGE_SIZE);

My NAK notwithstanding, the namespacing here is completely bogus.

Quoted 1 line

+static int kdbus_meta_append_cmdline(struct kdbus_meta *meta)

NAK

Quoted 9 lines
ipc/kdbus/metadata.c new file +9 -0
+static int kdbus_meta_append_caps(struct kdbus_meta *meta)
+{
+	struct caps {
+		u32 last_cap;
+		struct {
+			u32 caps[_KERNEL_CAPABILITY_U32S];
+		} set[4];
+	} caps;
+	unsigned int i;

ipc/kdbus/metadata.c line 397

Quoted 10 lines
ipc/kdbus/metadata.c new file +10 -0
+	const struct cred *cred = current_cred();
+
+	caps.last_cap = CAP_LAST_CAP;
+
+	for (i = 0; i < _KERNEL_CAPABILITY_U32S; i++) {
+		caps.set[0].caps[i] = cred->cap_inheritable.cap[i];
+		caps.set[1].caps[i] = cred->cap_permitted.cap[i];
+		caps.set[2].caps[i] = cred->cap_effective.cap[i];
+		caps.set[3].caps[i] = cred->cap_bset.cap[i];
+	}

Please leave this in so that I can root every single kdbus-using system.
It'll be lots of fun.

Snark aside, the correct fix is IMO to delete this function entirely. Even if you could find a way to implement it safely (which will be distinctly nontrivial), it seems like a bad idea to begin with.

ipc/kdbus/metadata.c line 418

Quoted 11 lines
ipc/kdbus/metadata.c new file +11 -0
+#ifdef CONFIG_CGROUPS
+static int kdbus_meta_append_cgroup(struct kdbus_meta *meta)
+{
+	char *buf, *path;
+	int ret;
+
+	buf = (char *)__get_free_page(GFP_TEMPORARY | __GFP_ZERO);
+	if (!buf)
+		return -ENOMEM;
+
+	path = task_cgroup_path(current, buf, PAGE_SIZE);

This may have strange interactions with cgroupns. It's fixable, though, but only once you implement translation at receive time, and I think you'll have to do that to get any of this to work right.

Quoted 14 lines
ipc/kdbus/metadata.c new file +14 -0
+
+	if (path)
+		ret = kdbus_meta_append_str(meta, KDBUS_ITEM_CGROUP, path);
+	else
+		ret = -ENAMETOOLONG;
+
+	free_page((unsigned long) buf);
+
+	return ret;
+}
+#endif
+
+#ifdef CONFIG_AUDITSYSCALL
+static int kdbus_meta_append_audit(struct kdbus_meta *meta,

ipc/kdbus/metadata.c line 442

Quoted 10 lines
ipc/kdbus/metadata.c new file +10 -0
+				   const struct kdbus_domain *domain)
+{
+	struct kdbus_audit audit;
+
+	audit.loginuid = from_kuid_munged(domain->user_namespace,
+					  audit_get_loginuid(current));
+	audit.sessionid = audit_get_sessionid(current);
+
+	return kdbus_meta_append_data(meta, KDBUS_ITEM_AUDIT,
+				      &audit, sizeof(audit));

So *that's* what audit means. Please document this and consider renaming it to something like AUDIT_LOGINUID_AND_SESSIONID.

Quoted 7 lines
ipc/kdbus/metadata.c new file +7 -0
+#ifdef CONFIG_SECURITY
+static int kdbus_meta_append_seclabel(struct kdbus_meta *meta)
+{
+	u32 len, sid;
+	char *label;
+	int ret;
+

ipc/kdbus/metadata.c line 462

Quoted 10 lines
ipc/kdbus/metadata.c new file +10 -0
+	security_task_getsecid(current, &sid);
+	ret = security_secid_to_secctx(sid, &label, &len);
+	if (ret == -EOPNOTSUPP)
+		return 0;
+	if (ret < 0)
+		return ret;
+
+	if (label && len > 0)
+		ret = kdbus_meta_append_data(meta, KDBUS_ITEM_SECLABEL,
+					     label, len);

This thing needs a clear, valid use case. I think that the use case should document how non-enforcing mode is supposed to work, too.

Also, there should be a justification for why the LSM hooks by themselves aren't good enough to remove the need for this.

ipc/kdbus/metadata.c line 626

Quoted 4 lines
ipc/kdbus/metadata.c new file +4 -0
+
+/**
+ * kdbus_meta_size() - calculate the size of an excerpt of a metadata db
+ * @meta:	The database object containing the metadata

What is a "database object containing the metadata"?

Anyway, this is unreviewable because not only is the context in which this function called not specified in this patch, but the function has no callers in this patch. However...

Quoted 1 line

+ * @conn_dst: The connection that is about to receive the data

...this suggests that this is called in the recipient's context, so...

Quoted 11 lines

+ * @mask: Pointer to KDBUS_ATTACH_* bitmask to calculate the size for.
+ * Callers *must* use the same mask for calls to
+ * kdbus_meta_write().
+ *
+ * Return: the size in bytes the masked data will consume. Data that should
+ * not received by @conn_dst will be filtered out.
+ */

ipc/kdbus/metadata.c new file +4 -0
+size_t kdbus_meta_size(const struct kdbus_meta *meta,
+		       const struct kdbus_conn *conn_dst,
+		       u64 *mask)
+{

ipc/kdbus/metadata.c line 648

Quoted 10 lines
ipc/kdbus/metadata.c new file +10 -0
+	struct kdbus_domain *domain = conn_dst->ep->bus->domain;
+	const struct kdbus_item *item;
+	size_t size = 0;
+
+	/*
+	 * We currently don't have a way to translate capability flags between
+	 * user namespaces, so let's drop these items in such cases.
+	 */
+	if (domain->user_namespace != current_user_ns())
+		*mask &= ~KDBUS_ATTACH_CAPS;

...this is still completely wrong, and I'll be able to root kdbus systems :)

ipc/kdbus/metadata.c line 656

Quoted 8 lines
ipc/kdbus/metadata.c new file +8 -0
+
+	/*
+	 * If the domain was created with hide_pid enabled, drop all items
+	 * except for such not revealing anything about the task.
+	 */
+	if (domain->pid_namespace->hide_pid)
+		*mask &= KDBUS_ATTACH_TIMESTAMP | KDBUS_ATTACH_NAMES |
+			 KDBUS_ATTACH_CONN_DESCRIPTION;

Huh? This looks wrong.

I realize that some of the systemd people seem to think that hide_pid is unusable right now, but it really does seem to be usable. Doing this, however, will indeed make it unusable.

What are you trying to do here? I think that the correct fix is to remove support for all of the questionable metadata items and get rid of this check.

--Andy

#37 lore raw

Re: kdbus: add code to gather metadata

Hi Andy,

Sorry for the late response.

Quoted 4 lines · Andy Lutomirski
Quoted 4 lines
ipc/kdbus/metadata.c new file +4 -0
+static int kdbus_meta_append_cred(struct kdbus_meta *meta,
+				  const struct kdbus_domain *domain)
+{
+	struct kdbus_creds creds = {
Quoted 8 lines

ipc/kdbus/metadata.c line 225

Quoted 4 lines
ipc/kdbus/metadata.c new file +4 -0
+		.uid = from_kuid_munged(domain->user_namespace, current_uid()),
+		.gid = from_kgid_munged(domain->user_namespace, current_gid()),
+		.pid = task_pid_nr_ns(current, domain->pid_namespace),
+		.tid = task_tgid_nr_ns(current, domain->pid_namespace),

This is better than before -- at least it gets translation right part of the way. But it's still wrong if the receiver's namespace doesn't match the domain.

Alright. The code now translates the items into each receiver's namespaces individually, so we can also take possible chroot() environments into account to do path translations.

Quoted 3 lines

Also, please move pid and tgid into their own item. They suck for reasons that have been beaten to death. Let's make it possible to deprecate them separately in the future.

Ok, done now. As mentioned in the highpid thread, we can easily add another item once we have a better source of information.

Quoted 23 lines
Quoted 9 lines
ipc/kdbus/metadata.c new file +9 -0
+static int kdbus_meta_append_caps(struct kdbus_meta *meta)
+{
+	struct caps {
+		u32 last_cap;
+		struct {
+			u32 caps[_KERNEL_CAPABILITY_U32S];
+		} set[4];
+	} caps;
+	unsigned int i;

ipc/kdbus/metadata.c line 397

Quoted 10 lines
ipc/kdbus/metadata.c new file +10 -0
+	const struct cred *cred = current_cred();
+
+	caps.last_cap = CAP_LAST_CAP;
+
+	for (i = 0; i < _KERNEL_CAPABILITY_U32S; i++) {
+		caps.set[0].caps[i] = cred->cap_inheritable.cap[i];
+		caps.set[1].caps[i] = cred->cap_permitted.cap[i];
+		caps.set[2].caps[i] = cred->cap_effective.cap[i];
+		caps.set[3].caps[i] = cred->cap_bset.cap[i];
+	}

Please leave this in so that I can root every single kdbus-using system.
It'll be lots of fun.

Quoted 3 lines

Snark aside, the correct fix is IMO to delete this function entirely. Even if you could find a way to implement it safely (which will be distinctly nontrivial), it seems like a bad idea to begin with.

Yes, we currently have no way of translating caps from one user namespace to another, which means we cannot allow such an item to cross user namespaces. We can add this functionality later once we have the neccessary APIs.

Quoted 7 lines
Quoted 7 lines
ipc/kdbus/metadata.c new file +7 -0
+#ifdef CONFIG_CGROUPS
+static int kdbus_meta_append_cgroup(struct kdbus_meta *meta)
+{
+	char *buf, *path;
+	int ret;
+
+	buf = (char *)__get_free_page(GFP_TEMPORARY | __GFP_ZERO);
Quoted 8 lines

ipc/kdbus/metadata.c line 418

Quoted 4 lines
ipc/kdbus/metadata.c new file +4 -0
+	if (!buf)
+		return -ENOMEM;
+
+	path = task_cgroup_path(current, buf, PAGE_SIZE);

This may have strange interactions with cgroupns. It's fixable, though, but only once you implement translation at receive time, and I think you'll have to do that to get any of this to work right.

Yes, agreed. We'll add translation to this item once cgroup namespaces are in place. Until then, we'll expose the same information as other parts of the Linux API already do.

Quoted 7 lines
Quoted 7 lines
ipc/kdbus/metadata.c new file +7 -0
+#ifdef CONFIG_AUDITSYSCALL
+static int kdbus_meta_append_audit(struct kdbus_meta *meta,
+				   const struct kdbus_domain *domain)
+{
+	struct kdbus_audit audit;
+
+	audit.loginuid = from_kuid_munged(domain->user_namespace,
Quoted 8 lines

ipc/kdbus/metadata.c line 442

Quoted 5 lines
ipc/kdbus/metadata.c new file +5 -0
+					  audit_get_loginuid(current));
+	audit.sessionid = audit_get_sessionid(current);
+
+	return kdbus_meta_append_data(meta, KDBUS_ITEM_AUDIT,
+				      &audit, sizeof(audit));

So *that's* what audit means. Please document this and consider renaming it to something like AUDIT_LOGINUID_AND_SESSIONID.

The documentation was indeed bogus and is fixed now, along with man other details. Thanks for spotting this!

Quoted 12 lines
Quoted 12 lines
ipc/kdbus/metadata.c new file +12 -0
+#ifdef CONFIG_SECURITY
+static int kdbus_meta_append_seclabel(struct kdbus_meta *meta)
+{
+	u32 len, sid;
+	char *label;
+	int ret;
+
+	security_task_getsecid(current, &sid);
+	ret = security_secid_to_secctx(sid, &label, &len);
+	if (ret == -EOPNOTSUPP)
+		return 0;
+	if (ret < 0)
Quoted 8 lines

ipc/kdbus/metadata.c line 462

Quoted 5 lines
ipc/kdbus/metadata.c new file +5 -0
+		return ret;
+
+	if (label && len > 0)
+		ret = kdbus_meta_append_data(meta, KDBUS_ITEM_SECLABEL,
+					     label, len);

This thing needs a clear, valid use case. I think that the use case should document how non-enforcing mode is supposed to work, too.

kdbus just passes the seclabel along, if people want to use this for security checks, then they need to call into libselinux, and should do that by taking the enforcing mode into consideration. This is already done in a lot of software that way.

Quoted 2 lines

Also, there should be a justification for why the LSM hooks by themselves aren't good enough to remove the need for this.

SELinux and other MACs might want to do additional per-service security checks. For example, a service manager might want to check the security label of a service file against the security label of the client process using the SELinux database before allow access. For this, we need to be able to pass the client's security label race-free to libselinux so that it can make its decision.

I've added the above to the documentation now.

Thanks for your review again - much appreciated!

Daniel

#38 lore raw

Re: kdbus: add code to gather metadata

Quoted 18 lines · Daniel Mack

Hi Andy,

Sorry for the late response.

Quoted 4 lines · Andy Lutomirski
Quoted 4 lines
ipc/kdbus/metadata.c new file +4 -0
+static int kdbus_meta_append_cred(struct kdbus_meta *meta,
+                              const struct kdbus_domain *domain)
+{
+    struct kdbus_creds creds = {
Quoted 8 lines

ipc/kdbus/metadata.c line 225

Quoted 4 lines
ipc/kdbus/metadata.c new file +4 -0
+            .uid = from_kuid_munged(domain->user_namespace, current_uid()),
+            .gid = from_kgid_munged(domain->user_namespace, current_gid()),
+            .pid = task_pid_nr_ns(current, domain->pid_namespace),
+            .tid = task_tgid_nr_ns(current, domain->pid_namespace),

This is better than before -- at least it gets translation right part of the way. But it's still wrong if the receiver's namespace doesn't match the domain.

Quoted 3 lines

Alright. The code now translates the items into each receiver's namespaces individually, so we can also take possible chroot() environments into account to do path translations.

Thanks!

I suspect you'll get a lot of "(unreachable)/foo/bar".

Quoted 7 lines
Quoted 4 lines

Also, please move pid and tgid into their own item. They suck for reasons that have been beaten to death. Let's make it possible to deprecate them separately in the future.

Ok, done now. As mentioned in the highpid thread, we can easily add another item once we have a better source of information.

I'll see if I can get highpid in soon enough that starttime can be dropped entirely. Once it shows up, there will be an API that can probably never be removed that isn't namespaced correctly and can't be checkpointed.

Quoted 24 lines
Quoted 24 lines
Quoted 10 lines
ipc/kdbus/metadata.c new file +9 -0
+static int kdbus_meta_append_caps(struct kdbus_meta *meta)
+{
+    struct caps {
+            u32 last_cap;
+            struct {
+                    u32 caps[_KERNEL_CAPABILITY_U32S];
+            } set[4];
+    } caps;
+    unsigned int i;

ipc/kdbus/metadata.c line 397

Quoted 10 lines
ipc/kdbus/metadata.c new file +10 -0
+    const struct cred *cred = current_cred();
+
+    caps.last_cap = CAP_LAST_CAP;
+
+    for (i = 0; i < _KERNEL_CAPABILITY_U32S; i++) {
+            caps.set[0].caps[i] = cred->cap_inheritable.cap[i];
+            caps.set[1].caps[i] = cred->cap_permitted.cap[i];
+            caps.set[2].caps[i] = cred->cap_effective.cap[i];
+            caps.set[3].caps[i] = cred->cap_bset.cap[i];
+    }

Please leave this in so that I can root every single kdbus-using system.
It'll be lots of fun.

Quoted 8 lines
Quoted 3 lines

Snark aside, the correct fix is IMO to delete this function entirely. Even if you could find a way to implement it safely (which will be distinctly nontrivial), it seems like a bad idea to begin with.

Yes, we currently have no way of translating caps from one user namespace to another, which means we cannot allow such an item to cross user namespaces. We can add this functionality later once we have the neccessary APIs.

I still don't expect this metadata item to ever make sense to use. The best argument I've heard is that it would enable CAP_SYS_BOOT to ask systemd for a reboot. I think this is bogus:

Realistically, this probably just means that users of /sbin/reboot might continue to work as expected. Except:

1. CAP_SYS_BOOT was never sufficient for /sbin/reboot to reboot cleanly -- clean reboots historically went through /dev/initctl.

2. This only makes sense anyway if /sbin/reboot gets updated to speak dbus. So you have a new reboot binary that you want to work as long as it ends up with CAP_SYS_BOOT. But caps are so broken that this won't work intelligently no matter what kdbus does. A user can have CAP_SYS_BOOT or not, but whether or not /sbin/reboot inherits that bit is almost entirely a function of that user's euid and has very little to do with whether that user has CAP_SYS_BOOT. So you might as well just check euid == 0 in the first place.

And setting fscap bits on /sbin/reboot so that a new reboot binary can prove to systemd that it has CAP_SYS_BOOT makes no sense. Either put the policy in systemd in the first place, or make /sbin/reboot setuid root.

And passing the permitted, inheritable, and bounding sets makes even less sense. Yes, you could pass the entirety of /proc/PID/stat and /proc/PID/status, but that's silly, and passing caps around via kdbus for diagnostics seems ridiculous.

If you put it in now, it's here to stay even if it proves to be a bad idea, whereas if you don't put it in at first, you can always add it if a good reason comes up.

Quoted 17 lines
Quoted 16 lines

ipc/kdbus/metadata.c line 418

Quoted 12 lines
ipc/kdbus/metadata.c new file +11 -0
+#ifdef CONFIG_CGROUPS
+static int kdbus_meta_append_cgroup(struct kdbus_meta *meta)
+{
+    char *buf, *path;
+    int ret;
+
+    buf = (char *)__get_free_page(GFP_TEMPORARY | __GFP_ZERO);
+    if (!buf)
+            return -ENOMEM;
+
+    path = task_cgroup_path(current, buf, PAGE_SIZE);

This may have strange interactions with cgroupns. It's fixable, though, but only once you implement translation at receive time, and I think you'll have to do that to get any of this to work right.

Quoted 3 lines

Yes, agreed. We'll add translation to this item once cgroup namespaces are in place. Until then, we'll expose the same information as other parts of the Linux API already do.

I don't expect this to become a problem.

Quoted 17 lines
Quoted 16 lines

ipc/kdbus/metadata.c line 442

Quoted 13 lines
ipc/kdbus/metadata.c new file +12 -0
+#ifdef CONFIG_AUDITSYSCALL
+static int kdbus_meta_append_audit(struct kdbus_meta *meta,
+                               const struct kdbus_domain *domain)
+{
+    struct kdbus_audit audit;
+
+    audit.loginuid = from_kuid_munged(domain->user_namespace,
+                                      audit_get_loginuid(current));
+    audit.sessionid = audit_get_sessionid(current);
+
+    return kdbus_meta_append_data(meta, KDBUS_ITEM_AUDIT,
+                                  &audit, sizeof(audit));

So *that's* what audit means. Please document this and consider renaming it to something like AUDIT_LOGINUID_AND_SESSIONID.

Quoted 2 lines

The documentation was indeed bogus and is fixed now, along with man other details. Thanks for spotting this!

:)

Quoted 30 lines
Quoted 13 lines
Quoted 13 lines
ipc/kdbus/metadata.c new file +12 -0
+#ifdef CONFIG_SECURITY
+static int kdbus_meta_append_seclabel(struct kdbus_meta *meta)
+{
+    u32 len, sid;
+    char *label;
+    int ret;
+
+    security_task_getsecid(current, &sid);
+    ret = security_secid_to_secctx(sid, &label, &len);
+    if (ret == -EOPNOTSUPP)
+            return 0;
+    if (ret < 0)
Quoted 8 lines

ipc/kdbus/metadata.c line 462

Quoted 5 lines
ipc/kdbus/metadata.c new file +5 -0
+            return ret;
+
+    if (label && len > 0)
+            ret = kdbus_meta_append_data(meta, KDBUS_ITEM_SECLABEL,
+                                         label, len);

This thing needs a clear, valid use case. I think that the use case should document how non-enforcing mode is supposed to work, too.

kdbus just passes the seclabel along, if people want to use this for security checks, then they need to call into libselinux, and should do that by taking the enforcing mode into consideration. This is already done in a lot of software that way.

Quoted 2 lines

Also, there should be a justification for why the LSM hooks by themselves aren't good enough to remove the need for this.

Quoted 6 lines

SELinux and other MACs might want to do additional per-service security checks. For example, a service manager might want to check the security label of a service file against the security label of the client process using the SELinux database before allow access. For this, we need to be able to pass the client's security label race-free to libselinux so that it can make its decision.

Yeah, but what happens on systems that use a different LSM? And isn't the point of the new LSM kdbus hooks to do this automatically without userspace's help?

Admittedly, I don't see much of a problem with this feature existing, as long as the non-selinux people are okay with it.

Quoted 6 lines

I've added the above to the documentation now.

Thanks for your review again - much appreciated!

And thanks for addressing most of the issues. The code is starting to look much better to me.

--Andy

#39 lore raw

kdbus: add code for notifications and matches

In reply to Greg Kroah-Hartman

From: Daniel Mack <[email protected]>

This patch adds code for matches and notifications.

Notifications are broadcast messages generated by the kernel, which notify subscribes when connections are created or destroyed, when well-known-names have been claimed, released or changed ownership, or when reply messages have timed out.

Matches are used to tell the kernel driver which broadcast messages a connection is interested in. Matches can either be specific on one of the kernel-generated notification types, or carry a bloom filter mask to match against a message from userspace. The latter is a way to pre-filter messages from other connections in order to mitigate unnecessary wakeups.

---
 ipc/kdbus/match.c  | 524 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 ipc/kdbus/match.h  |  31 ++++
 ipc/kdbus/notify.c | 235 ++++++++++++++++++++++++
 ipc/kdbus/notify.h |  29 +++
 4 files changed, 819 insertions(+)
 create mode 100644 ipc/kdbus/match.c
 create mode 100644 ipc/kdbus/match.h
 create mode 100644 ipc/kdbus/notify.c
 create mode 100644 ipc/kdbus/notify.h
ipc/kdbus/match.c new file +524 -0
new file mode 100644
index 000000000000..e70ed28eff3f
@@ -0,0 +1,524 @@
+/*
+ * Copyright (C) 2013-2014 Kay Sievers
+ * Copyright (C) 2013-2014 Greg Kroah-Hartman <[email protected]>
+ * Copyright (C) 2013-2014 Daniel Mack <[email protected]>
+ * Copyright (C) 2013-2014 David Herrmann <[email protected]>
+ * Copyright (C) 2013-2014 Linux Foundation
+ * Copyright (C) 2014 Djalal Harouni <[email protected]>
+ *
+ * kdbus is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ */
+
+#include <linux/fs.h>
+#include <linux/hash.h>
+#include <linux/init.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/sizes.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+#include "bus.h"
+#include "connection.h"
+#include "endpoint.h"
+#include "item.h"
+#include "match.h"
+#include "message.h"
+
+/**
+ * struct kdbus_match_db - message filters
+ * @entries_list:	List of matches
+ * @mdb_rwlock:		Match data lock
+ * @entries_count:	Number of entries in database
+ */
+struct kdbus_match_db {
+	struct list_head entries_list;
+	struct rw_semaphore mdb_rwlock;
+	unsigned int entries_count;
+};
+
+/**
+ * struct kdbus_match_entry - a match database entry
+ * @cookie:		User-supplied cookie to lookup the entry
+ * @list_entry:		The list entry element for the db list
+ * @rules_list:		The list head for tracking rules of this entry
+ */
+struct kdbus_match_entry {
+	u64 cookie;
+	struct list_head list_entry;
+	struct list_head rules_list;
+};
+
+/**
+ * struct kdbus_bloom_mask - mask to match against filter
+ * @generations:	Number of generations carried
+ * @data:		Array of bloom bit fields
+ */
+struct kdbus_bloom_mask {
+	u64 generations;
+	u64 *data;
+};
+
+/**
+ * struct kdbus_match_rule - a rule appended to a match entry
+ * @type:		An item type to match agains
+ * @bloom_mask:		Bloom mask to match a message's filter against, used
+ *			with KDBUS_ITEM_BLOOM_MASK
+ * @name:		Name to match against, used with KDBUS_ITEM_NAME,
+ *			KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE}
+ * @old_id:		ID to match against, used with
+ *			KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE},
+ *			KDBUS_ITEM_ID_REMOVE
+ * @new_id:		ID to match against, used with
+ *			KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE},
+ *			KDBUS_ITEM_ID_REMOVE
+ * @src_id:		ID to match against, used with KDBUS_ITEM_ID
+ * @rules_entry:	Entry in the entry's rules list
+ */
+struct kdbus_match_rule {
+	u64 type;
+	union {
+		struct kdbus_bloom_mask bloom_mask;
+		struct {
+			char *name;
+			u64 old_id;
+			u64 new_id;
+		};
+		u64 src_id;
+	};
+	struct list_head rules_entry;
+};
+
+static void kdbus_match_rule_free(struct kdbus_match_rule *rule)
+{
+	switch (rule->type) {
+	case KDBUS_ITEM_BLOOM_MASK:
+		kfree(rule->bloom_mask.data);
+		break;
+
+	case KDBUS_ITEM_NAME:
+	case KDBUS_ITEM_NAME_ADD:
+	case KDBUS_ITEM_NAME_REMOVE:
+	case KDBUS_ITEM_NAME_CHANGE:
+		kfree(rule->name);
+		break;
+
+	case KDBUS_ITEM_ID:
+	case KDBUS_ITEM_ID_ADD:
+	case KDBUS_ITEM_ID_REMOVE:
+		break;
+
+	default:
+		BUG();
+	}
+
+	list_del(&rule->rules_entry);
+	kfree(rule);
+}
+
+static void kdbus_match_entry_free(struct kdbus_match_entry *entry)
+{
+	struct kdbus_match_rule *r, *tmp;
+
+	list_for_each_entry_safe(r, tmp, &entry->rules_list, rules_entry)
+		kdbus_match_rule_free(r);
+
+	list_del(&entry->list_entry);
+	kfree(entry);
+}
+
+/**
+ * kdbus_match_db_free() - free match db resources
+ * @mdb:		The match database
+ */
+void kdbus_match_db_free(struct kdbus_match_db *mdb)
+{
+	struct kdbus_match_entry *entry, *tmp;
+
+	down_write(&mdb->mdb_rwlock);
+	list_for_each_entry_safe(entry, tmp, &mdb->entries_list, list_entry)
+		kdbus_match_entry_free(entry);
+	up_write(&mdb->mdb_rwlock);
+
+	kfree(mdb);
+}
+
+/**
+ * kdbus_match_db_new() - create a new match database
+ *
+ * Return: a new kdbus_match_db on success, ERR_PTR on failure.
+ */
+struct kdbus_match_db *kdbus_match_db_new(void)
+{
+	struct kdbus_match_db *d;
+
+	d = kzalloc(sizeof(*d), GFP_KERNEL);
+	if (!d)
+		return ERR_PTR(-ENOMEM);
+
+	init_rwsem(&d->mdb_rwlock);
+	INIT_LIST_HEAD(&d->entries_list);
+
+	return d;
+}
+
+static bool kdbus_match_bloom(const struct kdbus_bloom_filter *filter,
+			      const struct kdbus_bloom_mask *mask,
+			      const struct kdbus_conn *conn)
+{
+	size_t n = conn->ep->bus->bloom.size / sizeof(u64);
+	const u64 *m;
+	size_t i;
+
+	/*
+	 * The message's filter carries a generation identifier, the
+	 * match's mask possibly carries an array of multiple generations
+	 * of the mask. Select the mask with the closest match of the
+	 * filter's generation.
+	 */
+	m = mask->data + (min(filter->generation, mask->generations - 1) * n);
+
+	/*
+	 * The message's filter contains the messages properties,
+	 * the match's mask contains the properties to look for in the
+	 * message. Check the mask bit field against the filter bit field,
+	 * if the message possibly carries the properties the connection
+	 * has subscribed to.
+	 */
+	for (i = 0; i < n; i++)
+		if ((filter->data[i] & m[i]) != m[i])
+			return false;
+
+	return true;
+}
+
+static bool kdbus_match_rules(const struct kdbus_match_entry *entry,
+			      struct kdbus_conn *conn_src,
+			      struct kdbus_kmsg *kmsg)
+{
+	struct kdbus_match_rule *r;
+
+	/*
+	 * Walk all the rules and bail out immediately
+	 * if any of them is unsatisfied.
+	 */
+
+	list_for_each_entry(r, &entry->rules_list, rules_entry) {
+		if (conn_src == NULL) {
+			/* kernel notifications */
+
+			if (kmsg->notify_type != r->type)
+				return false;
+
+			switch (r->type) {
+			case KDBUS_ITEM_ID_ADD:
+				if (r->new_id != KDBUS_MATCH_ID_ANY &&
+				    r->new_id != kmsg->notify_new_id)
+					return false;
+
+				break;
+
+			case KDBUS_ITEM_ID_REMOVE:
+				if (r->old_id != KDBUS_MATCH_ID_ANY &&
+				    r->old_id != kmsg->notify_old_id)
+					return false;
+
+				break;
+
+			case KDBUS_ITEM_NAME_ADD:
+			case KDBUS_ITEM_NAME_CHANGE:
+			case KDBUS_ITEM_NAME_REMOVE:
+				if ((r->old_id != KDBUS_MATCH_ID_ANY &&
+				     r->old_id != kmsg->notify_old_id) ||
+				    (r->new_id != KDBUS_MATCH_ID_ANY &&
+				     r->new_id != kmsg->notify_new_id) ||
+				    (r->name && kmsg->notify_name &&
+				     strcmp(r->name, kmsg->notify_name) != 0))
+					return false;
+
+				break;
+
+			default:
+				return false;
+			}
+		} else {
+			/* messages from userspace */
+
+			switch (r->type) {
+			case KDBUS_ITEM_BLOOM_MASK:
+				if (!kdbus_match_bloom(kmsg->bloom_filter,
+						       &r->bloom_mask,
+						       conn_src))
+					return false;
+				break;
+
+			case KDBUS_ITEM_ID:
+				if (r->src_id != conn_src->id &&
+				    r->src_id != KDBUS_MATCH_ID_ANY)
+					return false;
+
+				break;
+
+			case KDBUS_ITEM_NAME:
+				if (!kdbus_conn_has_name(conn_src, r->name))
+					return false;
+
+				break;
+
+			default:
+				return false;
+			}
+		}
+	}
+
+	return true;
+}
+
+/**
+ * kdbus_match_db_match_kmsg() - match a kmsg object agains the database entries
+ * @mdb:		The match database
+ * @conn_src:		The connection object originating the message
+ * @kmsg:		The kmsg to perform the match on
+ *
+ * This function will walk through all the database entries previously uploaded
+ * with kdbus_match_db_add(). As soon as any of them has an all-satisfied rule
+ * set, this function will return true.
+ *
+ * Return: true if there was a matching database entry, false otherwise.
+ */
+bool kdbus_match_db_match_kmsg(struct kdbus_match_db *mdb,
+			       struct kdbus_conn *conn_src,
+			       struct kdbus_kmsg *kmsg)
+{
+	struct kdbus_match_entry *entry;
+	bool matched = false;
+
+	down_read(&mdb->mdb_rwlock);
+	list_for_each_entry(entry, &mdb->entries_list, list_entry) {
+		matched = kdbus_match_rules(entry, conn_src, kmsg);
+		if (matched)
+			break;
+	}
+	up_read(&mdb->mdb_rwlock);
+
+	return matched;
+}
+
+static int kdbus_match_db_remove_unlocked(struct kdbus_match_db *mdb,
+					  uint64_t cookie)
+{
+	struct kdbus_match_entry *entry, *tmp;
+	bool found = false;
+
+	list_for_each_entry_safe(entry, tmp, &mdb->entries_list, list_entry)
+		if (entry->cookie == cookie) {
+			kdbus_match_entry_free(entry);
+			--mdb->entries_count;
+			found = true;
+		}
+
+	return found ? 0 : -ENOENT;
+}
+
+/**
+ * kdbus_match_db_add() - add an entry to the match database
+ * @conn:		The connection that was used in the ioctl call
+ * @cmd:		The command as provided by the ioctl call
+ *
+ * This function is used in the context of the KDBUS_CMD_MATCH_ADD ioctl
+ * interface.
+ *
+ * One call to this function (or one ioctl(KDBUS_CMD_MATCH_ADD), respectively,
+ * adds one new database entry with n rules attached to it. Each rule is
+ * described with an kdbus_item, and an entry is considered matching if all
+ * its rules are satisfied.
+ *
+ * The items attached to a kdbus_cmd_match struct have the following mapping:
+ *
+ * KDBUS_ITEM_BLOOM_MASK:	A bloom mask
+ * KDBUS_ITEM_NAME:		A connection's source name
+ * KDBUS_ITEM_ID:		A connection ID
+ * KDBUS_ITEM_NAME_ADD:
+ * KDBUS_ITEM_NAME_REMOVE:
+ * KDBUS_ITEM_NAME_CHANGE:	Well-known name changes, carry
+ *				kdbus_notify_name_change
+ * KDBUS_ITEM_ID_ADD:
+ * KDBUS_ITEM_ID_REMOVE:	Connection ID changes, carry
+ *				kdbus_notify_id_change
+ *
+ * For kdbus_notify_{id,name}_change structs, only the ID and name fields
+ * are looked at at when adding an entry. The flags are unused.
+ *
+ * Also note that KDBUS_ITEM_BLOOM_MASK, KDBUS_ITEM_NAME and KDBUS_ITEM_ID
+ * are used to match messages from userspace, while the others apply to
+ * kernel-generated notifications.
+ *
+ * Return: 0 on success, negative errno on failure
+ */
+int kdbus_match_db_add(struct kdbus_conn *conn,
+		       struct kdbus_cmd_match *cmd)
+{
+	struct kdbus_match_entry *entry = NULL;
+	struct kdbus_match_db *mdb = conn->match_db;
+	struct kdbus_item *item;
+	int ret = 0;
+
+	lockdep_assert_held(conn);
+
+	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+	if (!entry)
+		return -ENOMEM;
+
+	entry->cookie = cmd->cookie;
+	INIT_LIST_HEAD(&entry->list_entry);
+	INIT_LIST_HEAD(&entry->rules_list);
+
+	KDBUS_ITEMS_FOREACH(item, cmd->items, KDBUS_ITEMS_SIZE(cmd, items)) {
+		struct kdbus_match_rule *rule;
+		size_t size = item->size - offsetof(struct kdbus_item, data);
+
+		rule = kzalloc(sizeof(*rule), GFP_KERNEL);
+		if (!rule) {
+			ret = -ENOMEM;
+			break;
+		}
+
+		switch (item->type) {
+		/* First matches for userspace messages */
+		case KDBUS_ITEM_BLOOM_MASK: {
+			u64 bsize = conn->ep->bus->bloom.size;
+			u64 generations;
+			u64 remainder;
+
+			generations = div64_u64_rem(size, bsize, &remainder);
+			if (size < bsize || remainder > 0) {
+				ret = -EDOM;
+				break;
+			}
+
+			rule->bloom_mask.data = kmemdup(item->data,
+							size, GFP_KERNEL);
+			if (!rule->bloom_mask.data) {
+				ret = -ENOMEM;
+				break;
+			}
+
+			/* we get an array of n generations of bloom masks */
+			rule->bloom_mask.generations = generations;
+
+			break;
+		}
+
+		case KDBUS_ITEM_NAME:
+			/*
+			 * Do not allow wildcard for now, since we
+			 * must validate the wildcard first
+			 */
+			if (!kdbus_name_is_valid(item->str, false)) {
+				ret = -EINVAL;
+				break;
+			}
+
+			rule->name = kstrdup(item->str, GFP_KERNEL);
+			if (!rule->name)
+				ret = -ENOMEM;
+
+			break;
+
+		case KDBUS_ITEM_ID:
+			rule->src_id = item->id;
+			break;
+
+		/* Now matches for kernel messages */
+		case KDBUS_ITEM_NAME_ADD:
+		case KDBUS_ITEM_NAME_REMOVE:
+		case KDBUS_ITEM_NAME_CHANGE: {
+			rule->old_id = item->name_change.old_id.id;
+			rule->new_id = item->name_change.new_id.id;
+
+			if (size > sizeof(struct kdbus_notify_name_change)) {
+				rule->name = kstrdup(item->name_change.name,
+						     GFP_KERNEL);
+				if (!rule->name)
+					ret = -ENOMEM;
+			}
+
+			break;
+		}
+
+		case KDBUS_ITEM_ID_ADD:
+		case KDBUS_ITEM_ID_REMOVE:
+			if (item->type == KDBUS_ITEM_ID_ADD)
+				rule->new_id = item->id_change.id;
+			else
+				rule->old_id = item->id_change.id;
+
+			break;
+
+		default:
+			ret = -EINVAL;
+			break;
+		}
+
+		if (ret < 0) {
+			kfree(rule);
+			break;
+		}
+
+		rule->type = item->type;
+
+		list_add_tail(&rule->rules_entry, &entry->rules_list);
+	}
+
+	down_write(&mdb->mdb_rwlock);
+
+	/* Remove any entry that has the same cookie as the current one. */
+	if (cmd->flags & KDBUS_MATCH_REPLACE)
+		kdbus_match_db_remove_unlocked(mdb, entry->cookie);
+
+	/*
+	 * If the above removal caught any entry, there will be room for the
+	 * new one.
+	 */
+	if (++mdb->entries_count > KDBUS_MATCH_MAX) {
+		--mdb->entries_count;
+		ret = -EMFILE;
+	}
+
+	if (ret == 0)
+		list_add_tail(&entry->list_entry, &mdb->entries_list);
+	else
+		kdbus_match_entry_free(entry);
+
+	up_write(&mdb->mdb_rwlock);
+
+	return ret;
+}
+
+/**
+ * kdbus_match_db_remove() - remove an entry from the match database
+ * @conn:		The connection that was used in the ioctl call
+ * @cmd:		Pointer to the match data structure
+ *
+ * This function is used in the context of the KDBUS_CMD_MATCH_REMOVE
+ * ioctl interface.
+ *
+ * Return: 0 on success, negative errno on failure.
+ */
+int kdbus_match_db_remove(struct kdbus_conn *conn,
+			  struct kdbus_cmd_match *cmd)
+{
+	struct kdbus_match_db *mdb = conn->match_db;
+	int ret;
+
+	lockdep_assert_held(conn);
+
+	down_write(&mdb->mdb_rwlock);
+	ret = kdbus_match_db_remove_unlocked(mdb, cmd->cookie);
+	up_write(&mdb->mdb_rwlock);
+
+	return ret;
+}
ipc/kdbus/match.h new file +31 -0
new file mode 100644
index 000000000000..16b982ce607d
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2013-2014 Kay Sievers
+ * Copyright (C) 2013-2014 Greg Kroah-Hartman <[email protected]>
+ * Copyright (C) 2013-2014 Daniel Mack <[email protected]>
+ * Copyright (C) 2013-2014 David Herrmann <[email protected]>
+ * Copyright (C) 2013-2014 Linux Foundation
+ *
+ * kdbus is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ */
+
+#ifndef __KDBUS_MATCH_H
+#define __KDBUS_MATCH_H
+
+struct kdbus_conn;
+struct kdbus_kmsg;
+struct kdbus_match_db;
+
+struct kdbus_match_db *kdbus_match_db_new(void);
+void kdbus_match_db_free(struct kdbus_match_db *db);
+int kdbus_match_db_add(struct kdbus_conn *conn,
+		       struct kdbus_cmd_match *cmd);
+int kdbus_match_db_remove(struct kdbus_conn *conn,
+			  struct kdbus_cmd_match *cmd);
+bool kdbus_match_db_match_kmsg(struct kdbus_match_db *db,
+			       struct kdbus_conn *conn_src,
+			       struct kdbus_kmsg *kmsg);
+
+#endif
ipc/kdbus/notify.c new file +235 -0

235 lines not on this page · raw message

ipc/kdbus/notify.h new file +29 -0
new file mode 100644
index 000000000000..95d3711e49f3
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2013-2014 Kay Sievers
+ * Copyright (C) 2013-2014 Greg Kroah-Hartman <[email protected]>
+ * Copyright (C) 2013-2014 Daniel Mack <[email protected]>
+ * Copyright (C) 2013-2014 David Herrmann <[email protected]>
+ * Copyright (C) 2013-2014 Linux Foundation
+ *
+ * kdbus is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ */
+
+#ifndef __KDBUS_NOTIFY_H
+#define __KDBUS_NOTIFY_H
+
+struct kdbus_bus;
+
+int kdbus_notify_id_change(struct kdbus_bus *bus, u64 type, u64 id, u64 flags);
+int kdbus_notify_reply_timeout(struct kdbus_bus *bus, u64 id, u64 cookie);
+int kdbus_notify_reply_dead(struct kdbus_bus *bus, u64 id, u64 cookie);
+int kdbus_notify_name_change(struct kdbus_bus *bus, u64 type,
+			     u64 old_id, u64 new_id,
+			     u64 old_flags, u64 new_flags,
+			     const char *name);
+void kdbus_notify_flush(struct kdbus_bus *bus);
+void kdbus_notify_free(struct kdbus_bus *bus);
+
+#endif
Signature · 1 line
2.1.3
#40 lore raw

kdbus: add code for buses, domains and endpoints

In reply to Greg Kroah-Hartman

From: Daniel Mack <[email protected]>

Add the logic to handle the following entities:

Domain:
A domain is an unamed object containing a number of buses. A domain is automatically created when an instance of kdbusfs is mounted, and destroyed when it is unmounted. Every domain offers its own "control" device node to create buses. Domains have no connection to each other and cannot see nor talk to each other.

Bus:
A bus is a named object inside a domain. Clients exchange messages over a bus. Multiple buses themselves have no connection to each other; messages can only be exchanged on the same bus. The default entry point to a bus, where clients establish the connection to, is the "bus" device node /dev/kdbus/<bus name>/bus. Common operating system setups create one "system bus" per system, and one "user bus" for every logged-in user. Applications or services may create their own private named buses.

Endpoint:
An endpoint provides the device node to talk to a bus. Opening an endpoint creates a new connection to the bus to which the endpoint belongs. Every bus has a default endpoint called "bus". A bus can optionally offer additional endpoints with custom names to provide a restricted access to the same bus. Custom endpoints carry additional policy which can be used to give sandboxed processes only a locked-down, limited, filtered access to the same bus.

See Documentation/kdbus.txt for more details.

---
 ipc/kdbus/bus.c      | 459 +++++++++++++++++++++++++++++++++++++++++++++++
 ipc/kdbus/bus.h      |  98 ++++++++++
 ipc/kdbus/domain.c   | 349 ++++++++++++++++++++++++++++++++++++
 ipc/kdbus/domain.h   |  84 +++++++++
 ipc/kdbus/endpoint.c | 497 +++++++++++++++++++++++++++++++++++++++++++++++++++
 ipc/kdbus/endpoint.h |  91 ++++++++++
 6 files changed, 1578 insertions(+)
 create mode 100644 ipc/kdbus/bus.c
 create mode 100644 ipc/kdbus/bus.h
 create mode 100644 ipc/kdbus/domain.c
 create mode 100644 ipc/kdbus/domain.h
 create mode 100644 ipc/kdbus/endpoint.c
 create mode 100644 ipc/kdbus/endpoint.h
ipc/kdbus/bus.c new file +459 -0
new file mode 100644
index 000000000000..2808a2e87707
@@ -0,0 +1,459 @@
+/*
+ * Copyright (C) 2013-2014 Kay Sievers
+ * Copyright (C) 2013-2014 Greg Kroah-Hartman <[email protected]>
+ * Copyright (C) 2013-2014 Daniel Mack <[email protected]>
+ * Copyright (C) 2013-2014 David Herrmann <[email protected]>
+ * Copyright (C) 2013-2014 Linux Foundation
+ *
+ * kdbus is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ */
+
+#include <linux/fs.h>
+#include <linux/hashtable.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/random.h>
+#include <linux/sched.h>
+#include <linux/sizes.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+#include "bus.h"
+#include "notify.h"
+#include "connection.h"
+#include "domain.h"
+#include "endpoint.h"
+#include "item.h"
+#include "match.h"
+#include "message.h"
+#include "metadata.h"
+#include "names.h"
+#include "policy.h"
+
+static void kdbus_bus_free(struct kdbus_node *node)
+{
+	struct kdbus_bus *bus = container_of(node, struct kdbus_bus, node);
+
+	BUG_ON(!list_empty(&bus->monitors_list));
+	BUG_ON(!hash_empty(bus->conn_hash));
+
+	kdbus_notify_free(bus);
+
+	kdbus_domain_user_unref(bus->user);
+	kdbus_name_registry_free(bus->name_registry);
+	kdbus_domain_unref(bus->domain);
+	kdbus_policy_db_clear(&bus->policy_db);
+	kdbus_meta_free(bus->meta);
+	kfree(bus);
+}
+
+static void kdbus_bus_release(struct kdbus_node *node, bool was_active)
+{
+	struct kdbus_bus *bus = container_of(node, struct kdbus_bus, node);
+
+	if (was_active)
+		atomic_dec(&bus->user->buses);
+}
+
+/**
+ * kdbus_bus_new() - create a kdbus_cmd_make from user-supplied data
+ * @domain:		The domain to work on
+ * @make:		Information as passed in by userspace
+ * @uid:		The uid of the device node
+ * @gid:		The gid of the device node
+ *
+ * This function is part of the connection ioctl() interface and will parse
+ * the user-supplied data in order to create a new kdbus_bus.
+ *
+ * Return: the new bus on success, ERR_PTR on failure.
+ */
+struct kdbus_bus *kdbus_bus_new(struct kdbus_domain *domain,
+				const struct kdbus_cmd_make *make,
+				kuid_t uid, kgid_t gid)
+{
+	const struct kdbus_bloom_parameter *bloom = NULL;
+	const struct kdbus_item *item;
+	struct kdbus_bus *b;
+	const char *name = NULL;
+	char prefix[16];
+	int ret;
+
+	u64 attach_flags = 0;
+
+	KDBUS_ITEMS_FOREACH(item, make->items, KDBUS_ITEMS_SIZE(make, items)) {
+		switch (item->type) {
+		case KDBUS_ITEM_MAKE_NAME:
+			if (name)
+				return ERR_PTR(-EEXIST);
+
+			name = item->str;
+			break;
+
+		case KDBUS_ITEM_BLOOM_PARAMETER:
+			if (bloom)
+				return ERR_PTR(-EEXIST);
+
+			bloom = &item->bloom_parameter;
+			break;
+
+		case KDBUS_ITEM_ATTACH_FLAGS_RECV:
+			if (attach_flags)
+				return ERR_PTR(-EEXIST);
+
+			attach_flags = item->data64[0];
+			break;
+		}
+	}
+
+	if (!name || !bloom)
+		return ERR_PTR(-EBADMSG);
+
+	/* 'any' degrades to 'all' for compatibility */
+	if (attach_flags == _KDBUS_ATTACH_ANY)
+		attach_flags = _KDBUS_ATTACH_ALL;
+
+	/* reject unknown attach flags */
+	if (attach_flags & ~_KDBUS_ATTACH_ALL)
+		return ERR_PTR(-EINVAL);
+	if (bloom->size < 8 || bloom->size > KDBUS_BUS_BLOOM_MAX_SIZE)
+		return ERR_PTR(-EINVAL);
+	if (!KDBUS_IS_ALIGNED8(bloom->size))
+		return ERR_PTR(-EINVAL);
+	if (bloom->n_hash < 1)
+		return ERR_PTR(-EINVAL);
+
+	/* enforce "$UID-" prefix */
+	snprintf(prefix, sizeof(prefix), "%u-",
+		 from_kuid(domain->user_namespace, uid));
+	if (strncmp(name, prefix, strlen(prefix) != 0))
+		return ERR_PTR(-EINVAL);
+
+	b = kzalloc(sizeof(*b), GFP_KERNEL);
+	if (!b)
+		return ERR_PTR(-ENOMEM);
+
+	kdbus_node_init(&b->node, KDBUS_NODE_BUS);
+
+	b->node.free_cb = kdbus_bus_free;
+	b->node.release_cb = kdbus_bus_release;
+	b->node.uid = uid;
+	b->node.gid = gid;
+	b->node.mode = S_IRUSR | S_IXUSR;
+
+	b->access = make->flags & (KDBUS_MAKE_ACCESS_WORLD |
+				   KDBUS_MAKE_ACCESS_GROUP);
+	if (b->access & (KDBUS_MAKE_ACCESS_GROUP | KDBUS_MAKE_ACCESS_WORLD))
+		b->node.mode |= S_IRGRP | S_IXGRP;
+	if (b->access & KDBUS_MAKE_ACCESS_WORLD)
+		b->node.mode |= S_IROTH | S_IXOTH;
+
+	b->bus_flags = make->flags;
+	b->bloom = *bloom;
+	b->attach_flags_req = attach_flags;
+	mutex_init(&b->lock);
+	init_rwsem(&b->conn_rwlock);
+	hash_init(b->conn_hash);
+	INIT_LIST_HEAD(&b->monitors_list);
+	INIT_LIST_HEAD(&b->notify_list);
+	spin_lock_init(&b->notify_lock);
+	mutex_init(&b->notify_flush_lock);
+	atomic64_set(&b->conn_seq_last, 0);
+	b->domain = kdbus_domain_ref(domain);
+	kdbus_policy_db_init(&b->policy_db);
+	b->id = atomic64_inc_return(&domain->bus_seq_last);
+
+	/* generate unique bus id */
+	generate_random_uuid(b->id128);
+
+	ret = kdbus_node_link(&b->node, &domain->node, name);
+	if (ret < 0)
+		goto exit_unref;
+
+	/* cache the metadata/credentials of the creator */
+	b->meta = kdbus_meta_new();
+	if (IS_ERR(b->meta)) {
+		ret = PTR_ERR(b->meta);
+		b->meta = NULL;
+		goto exit_unref;
+	}
+
+	ret = kdbus_meta_append(b->meta, domain, NULL, 0,
+				KDBUS_ATTACH_CREDS	|
+				KDBUS_ATTACH_TID_COMM	|
+				KDBUS_ATTACH_PID_COMM	|
+				KDBUS_ATTACH_EXE	|
+				KDBUS_ATTACH_CMDLINE	|
+				KDBUS_ATTACH_CGROUP	|
+				KDBUS_ATTACH_CAPS	|
+				KDBUS_ATTACH_SECLABEL	|
+				KDBUS_ATTACH_AUDIT);
+	if (ret < 0)
+		goto exit_unref;
+
+	b->name_registry = kdbus_name_registry_new();
+	if (IS_ERR(b->name_registry)) {
+		ret = PTR_ERR(b->name_registry);
+		b->name_registry = NULL;
+		goto exit_unref;
+	}
+
+	b->user = kdbus_domain_get_user(domain, uid);
+	if (IS_ERR(b->user)) {
+		ret = PTR_ERR(b->user);
+		b->user = NULL;
+		goto exit_unref;
+	}
+
+	return b;
+
+exit_unref:
+	kdbus_node_deactivate(&b->node);
+	kdbus_node_unref(&b->node);
+	return ERR_PTR(ret);
+}
+
+/**
+ * kdbus_bus_ref() - increase the reference counter of a kdbus_bus
+ * @bus:		The bus to reference
+ *
+ * Every user of a bus, except for its creator, must add a reference to the
+ * kdbus_bus using this function.
+ *
+ * Return: the bus itself
+ */
+struct kdbus_bus *kdbus_bus_ref(struct kdbus_bus *bus)
+{
+	if (bus)
+		kdbus_node_ref(&bus->node);
+	return bus;
+}
+
+/**
+ * kdbus_bus_unref() - decrease the reference counter of a kdbus_bus
+ * @bus:		The bus to unref
+ *
+ * Release a reference. If the reference count drops to 0, the bus will be
+ * freed.
+ *
+ * Return: NULL
+ */
+struct kdbus_bus *kdbus_bus_unref(struct kdbus_bus *bus)
+{
+	if (bus)
+		kdbus_node_unref(&bus->node);
+	return NULL;
+}
+
+/**
+ * kdbus_bus_activate() - activate a bus
+ * @bus:		Bus
+ *
+ * Activate a bus and make it available to user-space.
+ *
+ * Returns: 0 on success, negative error code on failure
+ */
+int kdbus_bus_activate(struct kdbus_bus *bus)
+{
+	struct kdbus_ep *ep;
+	int ret;
+
+	if (atomic_inc_return(&bus->user->buses) > KDBUS_USER_MAX_BUSES) {
+		atomic_dec(&bus->user->buses);
+		return -EMFILE;
+	}
+
+	/*
+	 * kdbus_bus_activate() must not be called multiple times, so if
+	 * kdbus_node_activate() didn't activate the node, it must already be
+	 * dead.
+	 */
+	if (!kdbus_node_activate(&bus->node)) {
+		atomic_dec(&bus->user->buses);
+		return -ESHUTDOWN;
+	}
+
+	/*
+	 * Create a new default endpoint for this bus. If activation succeeds,
+	 * we drop our own reference, effectively causing the endpoint to be
+	 * deactivated and released when the parent domain is.
+	 */
+	ep = kdbus_ep_new(bus, "bus", bus->access,
+			  bus->node.uid, bus->node.gid, false);
+	if (IS_ERR(ep))
+		return PTR_ERR(ep);
+
+	ret = kdbus_ep_activate(ep);
+	if (ret < 0)
+		kdbus_ep_deactivate(ep);
+	kdbus_ep_unref(ep);
+
+	return 0;
+}
+
+/**
+ * kdbus_bus_deactivate() - deactivate a bus
+ * @bus:               The kdbus reference
+ *
+ * The passed bus will be disconnected and the associated endpoint will be
+ * unref'ed.
+ */
+void kdbus_bus_deactivate(struct kdbus_bus *bus)
+{
+	kdbus_node_deactivate(&bus->node);
+}
+
+/**
+ * kdbus_bus_find_conn_by_id() - find a connection with a given id
+ * @bus:		The bus to look for the connection
+ * @id:			The 64-bit connection id
+ *
+ * Looks up a connection with a given id. The returned connection
+ * is ref'ed, and needs to be unref'ed by the user. Returns NULL if
+ * the connection can't be found.
+ */
+struct kdbus_conn *kdbus_bus_find_conn_by_id(struct kdbus_bus *bus, u64 id)
+{
+	struct kdbus_conn *conn, *found = NULL;
+
+	down_read(&bus->conn_rwlock);
+	hash_for_each_possible(bus->conn_hash, conn, hentry, id)
+		if (conn->id == id) {
+			found = kdbus_conn_ref(conn);
+			break;
+		}
+	up_read(&bus->conn_rwlock);
+
+	return found;
+}
+
+/**
+ * kdbus_bus_broadcast() - send a message to all subscribed connections
+ * @bus:	The bus the connections are connected to
+ * @conn_src:	The source connection, may be %NULL for kernel notifications
+ * @kmsg:	The message to send.
+ *
+ * Send @kmsg to all connections that are currently active on the bus.
+ * Connections must still have matches installed in order to subscribe to
+ * let the message pass.
+ */
+void kdbus_bus_broadcast(struct kdbus_bus *bus,
+			 struct kdbus_conn *conn_src,
+			 struct kdbus_kmsg *kmsg)
+{
+	const struct kdbus_msg *msg = &kmsg->msg;
+	struct kdbus_conn *conn_dst;
+	unsigned int i;
+	int ret = 0;
+
+	down_read(&bus->conn_rwlock);
+
+	hash_for_each(bus->conn_hash, i, conn_dst, hentry) {
+		if (conn_dst->id == msg->src_id)
+			continue;
+
+		/*
+		 * Activator or policy holder connections will
+		 * not receive any broadcast messages, only
+		 * ordinary and monitor ones.
+		 */
+		if (!kdbus_conn_is_ordinary(conn_dst) &&
+		    !kdbus_conn_is_monitor(conn_dst))
+			continue;
+
+		if (!kdbus_match_db_match_kmsg(conn_dst->match_db, conn_src,
+					       kmsg))
+			continue;
+
+		ret = kdbus_ep_policy_check_notification(conn_dst->ep,
+							 conn_dst, kmsg);
+		if (ret < 0)
+			continue;
+
+		/*
+		 * The first receiver which requests additional metadata
+		 * causes the message to carry it; data that is in fact added
+		 * to the message is still subject to what the receiver
+		 * requested, and will be filtered by kdbus_meta_write().
+		 */
+		if (conn_src) {
+			/* Check if conn_src is allowed to signal */
+			ret = kdbus_ep_policy_check_broadcast(conn_dst->ep,
+							      conn_src,
+							      conn_dst);
+			if (ret < 0)
+				continue;
+
+			ret = kdbus_ep_policy_check_src_names(conn_dst->ep,
+							      conn_src,
+							      conn_dst);
+			if (ret < 0)
+				continue;
+
+			ret = kdbus_kmsg_attach_metadata(kmsg, conn_src,
+							 conn_dst);
+			if (ret < 0)
+				goto exit_unlock;
+		}
+
+		ret = kdbus_conn_entry_insert(conn_src, conn_dst, kmsg, NULL);
+		if (ret < 0)
+			atomic_inc(&conn_dst->lost_count);
+	}
+
+exit_unlock:
+	up_read(&bus->conn_rwlock);
+}
+
+
+/**
+ * kdbus_cmd_bus_creator_info() - get information on a bus creator
+ * @conn:	The querying connection
+ * @cmd_info:	The command buffer, as passed in from the ioctl
+ *
+ * Gather information on the creator of the bus @conn is connected to.
+ *
+ * Return: 0 on success, error otherwise.
+ */
+int kdbus_cmd_bus_creator_info(struct kdbus_conn *conn,
+			       struct kdbus_cmd_info *cmd_info)
+{
+	struct kdbus_bus *bus = conn->ep->bus;
+	struct kdbus_pool_slice *slice;
+	struct kdbus_info info = {};
+	u64 flags = cmd_info->flags;
+	int ret;
+
+	info.id = bus->id;
+	info.flags = bus->bus_flags;
+	info.size = sizeof(info) +
+		    kdbus_meta_size(bus->meta, conn, &flags);
+
+	if (info.size == 0)
+		return -EPERM;
+
+	slice = kdbus_pool_slice_alloc(conn->pool, info.size);
+	if (IS_ERR(slice))
+		return PTR_ERR(slice);
+
+	ret = kdbus_pool_slice_copy(slice, 0, &info, sizeof(info));
+	if (ret < 0)
+		goto exit_free_slice;
+
+	ret = kdbus_meta_write(bus->meta, conn, flags, slice, sizeof(info));
+	if (ret < 0)
+		goto exit_free_slice;
+
+	/* write back the offset */
+	cmd_info->offset = kdbus_pool_slice_offset(slice);
+	kdbus_pool_slice_flush(slice);
+	kdbus_pool_slice_make_public(slice);
+
+	return 0;
+
+exit_free_slice:
+	kdbus_pool_slice_free(slice);
+	return ret;
+}
ipc/kdbus/bus.h new file +98 -0

98 lines not on this page · raw message

ipc/kdbus/domain.c new file +349 -0

349 lines not on this page · raw message

ipc/kdbus/domain.h new file +84 -0

84 lines not on this page · raw message

ipc/kdbus/endpoint.c new file +497 -0

497 lines not on this page · raw message

ipc/kdbus/endpoint.h new file +91 -0

91 lines not on this page · raw message

Signature · 1 line
2.1.3
#41 lore raw

Re: kdbus: add code for buses, domains and endpoints

Quoted 12 lines · Greg Kroah-Hartman

From: Daniel Mack <[email protected]>

Add the logic to handle the following entities:

Domain:
A domain is an unamed object containing a number of buses. A domain is automatically created when an instance of kdbusfs is mounted, and destroyed when it is unmounted. Every domain offers its own "control" device node to create buses. Domains have no connection to each other and cannot see nor talk to each other.

Quoted 9 lines

Bus:
A bus is a named object inside a domain. Clients exchange messages over a bus. Multiple buses themselves have no connection to each other; messages can only be exchanged on the same bus. The default entry point to a bus, where clients establish the connection to, is the "bus" device node /dev/kdbus/<bus name>/bus. Common operating system setups create one "system bus" per system, and one "user bus" for every logged-in user. Applications or services may create their own private named buses.

might need a resync with the documentation.

Bus:
A bus is a named object inside a domain. Clients exchange messages over a bus. Multiple buses themselves have no connection to each other; messages can only be exchanged on the same bus. The default entry point to a bus, where clients establish the connection to, is the "bus" file /sys/fs/kdbus/<bus name>/bus.
Common operating system setups create one "system bus" per system, and one "user bus" for every logged-in user. Applications or services may create
their own private named buses. See section 5 for more details.

#42 lore raw

Re: kdbus: add code for buses, domains and endpoints

In reply to Greg Kroah-Hartman
Quoted 2 lines · Greg Kroah-Hartman

From: Daniel Mack <[email protected]>

…

Quoted 6 lines

+/**
+ * kdbus_bus_new() - create a kdbus_cmd_make from user-supplied data
+ * @domain: The domain to work on
+ * @make: Information as passed in by userspace
+ * @uid: The uid of the device node
+ * @gid: The gid of the device node

"device node" in several function comments.

#43 lore raw

kdbus: add name registry implementation

In reply to Greg Kroah-Hartman

From: Daniel Mack <[email protected]>

This patch adds the name registry implementation.

Each bus instantiates a name registry to resolve well-known names into unique connection IDs for message delivery. The registry will be queried when a message is sent with kdbus_msg.dst_id set to KDBUS_DST_ID_NAME, or when a registry dump is requested.

It's important to have this registry implemented in the kernel to implement lookups and take-overs in a race-free way.

---
 ipc/kdbus/names.c | 921 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 ipc/kdbus/names.h |  81 +++++
 2 files changed, 1002 insertions(+)
 create mode 100644 ipc/kdbus/names.c
 create mode 100644 ipc/kdbus/names.h
ipc/kdbus/names.c new file +921 -0
new file mode 100644
index 000000000000..552309bd6716
@@ -0,0 +1,921 @@
+/*
+ * Copyright (C) 2013-2014 Kay Sievers
+ * Copyright (C) 2013-2014 Greg Kroah-Hartman <[email protected]>
+ * Copyright (C) 2013-2014 Daniel Mack <[email protected]>
+ * Copyright (C) 2013-2014 David Herrmann <[email protected]>
+ * Copyright (C) 2013-2014 Linux Foundation
+ * Copyright (C) 2014 Djalal Harouni
+ *
+ * kdbus is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ */
+
+#include <linux/ctype.h>
+#include <linux/fs.h>
+#include <linux/hash.h>
+#include <linux/idr.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/rwsem.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+#include "bus.h"
+#include "connection.h"
+#include "endpoint.h"
+#include "item.h"
+#include "names.h"
+#include "notify.h"
+#include "policy.h"
+
+/**
+ * struct kdbus_name_queue_item - a queue item for a name
+ * @conn:		The associated connection
+ * @entry:		Name entry queuing up for
+ * @entry_entry:	List element for the list in @entry
+ * @conn_entry:		List element for the list in @conn
+ * @flags:		The queuing flags
+ */
+struct kdbus_name_queue_item {
+	struct kdbus_conn *conn;
+	struct kdbus_name_entry *entry;
+	struct list_head entry_entry;
+	struct list_head conn_entry;
+	u64 flags;
+};
+
+static void kdbus_name_entry_free(struct kdbus_name_entry *e)
+{
+	hash_del(&e->hentry);
+	kfree(e->name);
+	kfree(e);
+}
+
+/**
+ * kdbus_name_registry_free() - drop a name reg's reference
+ * @reg:		The name registry, may be %NULL
+ *
+ * Cleanup the name registry's internal structures.
+ */
+void kdbus_name_registry_free(struct kdbus_name_registry *reg)
+{
+	struct kdbus_name_entry *e;
+	struct hlist_node *tmp;
+	unsigned int i;
+
+	if (!reg)
+		return;
+
+	hash_for_each_safe(reg->entries_hash, i, tmp, e, hentry)
+		kdbus_name_entry_free(e);
+
+	kfree(reg);
+}
+
+/**
+ * kdbus_name_registry_new() - create a new name registry
+ *
+ * Return: a new kdbus_name_registry on success, ERR_PTR on failure.
+ */
+struct kdbus_name_registry *kdbus_name_registry_new(void)
+{
+	struct kdbus_name_registry *r;
+
+	r = kzalloc(sizeof(*r), GFP_KERNEL);
+	if (!r)
+		return ERR_PTR(-ENOMEM);
+
+	hash_init(r->entries_hash);
+	init_rwsem(&r->rwlock);
+
+	return r;
+}
+
+static struct kdbus_name_entry *
+kdbus_name_lookup(struct kdbus_name_registry *reg, u32 hash, const char *name)
+{
+	struct kdbus_name_entry *e;
+
+	hash_for_each_possible(reg->entries_hash, e, hentry, hash)
+		if (strcmp(e->name, name) == 0)
+			return e;
+
+	return NULL;
+}
+
+static void kdbus_name_queue_item_free(struct kdbus_name_queue_item *q)
+{
+	list_del(&q->entry_entry);
+	list_del(&q->conn_entry);
+	kfree(q);
+}
+
+/*
+ * The caller must hold the lock so we decrement the counter and
+ * delete the entry.
+ *
+ * The caller needs to hold its own reference, so the connection does not go
+ * away while the entry's reference is dropped under lock.
+ */
+static void kdbus_name_entry_remove_owner(struct kdbus_name_entry *e)
+{
+	BUG_ON(!e->conn);
+	BUG_ON(!mutex_is_locked(&e->conn->lock));
+
+	atomic_dec(&e->conn->name_count);
+	list_del(&e->conn_entry);
+	e->conn = kdbus_conn_unref(e->conn);
+}
+
+static void kdbus_name_entry_set_owner(struct kdbus_name_entry *e,
+				       struct kdbus_conn *conn)
+{
+	BUG_ON(e->conn);
+	BUG_ON(!mutex_is_locked(&conn->lock));
+
+	e->conn = kdbus_conn_ref(conn);
+	atomic_inc(&conn->name_count);
+	list_add_tail(&e->conn_entry, &e->conn->names_list);
+}
+
+static int kdbus_name_replace_owner(struct kdbus_name_entry *e,
+				    struct kdbus_conn *conn, u64 flags)
+{
+	struct kdbus_conn *conn_old = kdbus_conn_ref(e->conn);
+	int ret;
+
+	BUG_ON(conn == conn_old);
+	BUG_ON(!conn_old);
+
+	/* take lock of both connections in a defined order */
+	if (conn < conn_old) {
+		mutex_lock(&conn->lock);
+		mutex_lock_nested(&conn_old->lock, 1);
+	} else {
+		mutex_lock(&conn_old->lock);
+		mutex_lock_nested(&conn->lock, 1);
+	}
+
+	if (!kdbus_conn_active(conn)) {
+		ret = -ECONNRESET;
+		goto exit_unlock;
+	}
+
+	ret = kdbus_notify_name_change(conn->ep->bus, KDBUS_ITEM_NAME_CHANGE,
+				       e->conn->id, conn->id,
+				       e->flags, flags, e->name);
+	if (ret < 0)
+		goto exit_unlock;
+
+	/* hand over name ownership */
+	kdbus_name_entry_remove_owner(e);
+	kdbus_name_entry_set_owner(e, conn);
+	e->flags = flags;
+
+exit_unlock:
+	mutex_unlock(&conn_old->lock);
+	mutex_unlock(&conn->lock);
+
+	kdbus_conn_unref(conn_old);
+	return ret;
+}
+
+static int kdbus_name_entry_release(struct kdbus_name_entry *e,
+				    struct kdbus_bus *bus)
+{
+	struct kdbus_conn *conn;
+
+	/* give it to first active waiter in the queue */
+	while (!list_empty(&e->queue_list)) {
+		struct kdbus_name_queue_item *q;
+		int ret;
+
+		q = list_first_entry(&e->queue_list,
+				     struct kdbus_name_queue_item,
+				     entry_entry);
+
+		ret = kdbus_name_replace_owner(e, q->conn, q->flags);
+		if (ret < 0)
+			continue;
+
+		kdbus_name_queue_item_free(q);
+		return 0;
+	}
+
+	/* hand it back to an active activator connection */
+	if (e->activator && e->activator != e->conn) {
+		u64 flags = KDBUS_NAME_ACTIVATOR;
+		int ret;
+
+		/*
+		 * Move messages still queued in the old connection
+		 * and addressed to that name to the new connection.
+		 * This allows a race and loss-free name and message
+		 * takeover and exit-on-idle services.
+		 */
+		ret = kdbus_conn_move_messages(e->activator, e->conn,
+					       e->name_id);
+		if (ret < 0)
+			goto exit_release;
+
+		return kdbus_name_replace_owner(e, e->activator, flags);
+	}
+
+exit_release:
+	/* release the name */
+	kdbus_notify_name_change(e->conn->ep->bus, KDBUS_ITEM_NAME_REMOVE,
+				 e->conn->id, 0,
+				 e->flags, 0, e->name);
+
+	conn = kdbus_conn_ref(e->conn);
+	mutex_lock(&conn->lock);
+	kdbus_name_entry_remove_owner(e);
+	mutex_unlock(&conn->lock);
+	kdbus_conn_unref(conn);
+
+	kdbus_conn_unref(e->activator);
+	kdbus_name_entry_free(e);
+
+	return 0;
+}
+
+static int kdbus_name_release(struct kdbus_name_registry *reg,
+			      struct kdbus_conn *conn,
+			      const char *name)
+{
+	struct kdbus_name_queue_item *q_tmp, *q;
+	struct kdbus_name_entry *e = NULL;
+	u32 hash;
+	int ret = 0;
+
+	hash = kdbus_str_hash(name);
+
+	/* lock order: domain -> bus -> ep -> names -> connection */
+	mutex_lock(&conn->ep->bus->lock);
+	down_write(&reg->rwlock);
+
+	e = kdbus_name_lookup(reg, hash, name);
+	if (!e) {
+		ret = -ESRCH;
+		goto exit_unlock;
+	}
+
+	/* Is the connection already the real owner of the name? */
+	if (e->conn == conn) {
+		ret = kdbus_name_entry_release(e, conn->ep->bus);
+	} else {
+		/*
+		 * Otherwise, walk the list of queued entries and search
+		 * for items for connection.
+		 */
+
+		/* In case the name belongs to somebody else */
+		ret = -EADDRINUSE;
+
+		list_for_each_entry_safe(q, q_tmp,
+					 &e->queue_list,
+					 entry_entry) {
+			if (q->conn != conn)
+				continue;
+
+			kdbus_name_queue_item_free(q);
+			ret = 0;
+			break;
+		}
+	}
+
+	/*
+	 * Now that the connection has lost a name, purge all cached policy
+	 * entries, so upon the next message, TALK access will be checked
+	 * against the names the connection actually owns.
+	 */
+	if (ret == 0)
+		kdbus_conn_purge_policy_cache(conn);
+
+exit_unlock:
+	up_write(&reg->rwlock);
+	mutex_unlock(&conn->ep->bus->lock);
+
+	return ret;
+}
+
+/**
+ * kdbus_name_remove_by_conn() - remove all name entries of a given connection
+ * @reg:		The name registry
+ * @conn:		The connection which entries to remove
+ *
+ * This function removes all name entry held by a given connection.
+ */
+void kdbus_name_remove_by_conn(struct kdbus_name_registry *reg,
+			       struct kdbus_conn *conn)
+{
+	struct kdbus_name_queue_item *q_tmp, *q;
+	struct kdbus_conn *activator = NULL;
+	struct kdbus_name_entry *e_tmp, *e;
+	LIST_HEAD(names_queue_list);
+	LIST_HEAD(names_list);
+
+	/* lock order: domain -> bus -> ep -> names -> conn */
+	mutex_lock(&conn->ep->bus->lock);
+	down_write(&reg->rwlock);
+
+	mutex_lock(&conn->lock);
+	list_splice_init(&conn->names_list, &names_list);
+	list_splice_init(&conn->names_queue_list, &names_queue_list);
+	mutex_unlock(&conn->lock);
+
+	if (kdbus_conn_is_activator(conn)) {
+		activator = conn->activator_of->activator;
+		conn->activator_of->activator = NULL;
+	}
+	list_for_each_entry_safe(q, q_tmp, &names_queue_list, conn_entry)
+		kdbus_name_queue_item_free(q);
+	list_for_each_entry_safe(e, e_tmp, &names_list, conn_entry)
+		kdbus_name_entry_release(e, conn->ep->bus);
+
+	up_write(&reg->rwlock);
+	mutex_unlock(&conn->ep->bus->lock);
+
+	kdbus_conn_unref(activator);
+	kdbus_notify_flush(conn->ep->bus);
+}
+
+/**
+ * kdbus_name_lock() - look up a name in a name registry and lock it
+ * @reg:		The name registry
+ * @name:		The name to look up
+ *
+ * Search for a name in a given name registry and return it with the
+ * registry-lock held. If the object is not found, the lock is not acquired and
+ * NULL is returned. The caller is responsible of unlocking the name via
+ * kdbus_name_unlock() again. Note that kdbus_name_unlock() can be safely called
+ * with NULL as name. In this case, it's a no-op as nothing was locked.
+ *
+ * The *_lock() + *_unlock() logic is only required for callers that need to
+ * protect their code against concurrent activator/implementor name changes.
+ * Multiple readers can lock names concurrently. However, you may not change
+ * name-ownership while holding a name-lock.
+ *
+ * Return: NULL if name is unknown, otherwise return a pointer to the name
+ *         entry with the name-lock held (reader lock only).
+ */
+struct kdbus_name_entry *kdbus_name_lock(struct kdbus_name_registry *reg,
+					 const char *name)
+{
+	struct kdbus_name_entry *e = NULL;
+	u32 hash = kdbus_str_hash(name);
+
+	down_read(&reg->rwlock);
+	e = kdbus_name_lookup(reg, hash, name);
+	if (e)
+		return e;
+	up_read(&reg->rwlock);
+
+	return NULL;
+}
+
+/**
+ * kdbus_name_unlock() - unlock one name in a name registry
+ * @reg:		The name registry
+ * @entry:		The locked name entry or NULL
+ *
+ * This is the unlock-counterpart of kdbus_name_lock(). It unlocks a name that
+ * was previously successfully locked. You can safely pass NULL as entry and
+ * this will become a no-op. Therefore, it's safe to always call this on the
+ * return-value of kdbus_name_lock().
+ *
+ * Return: This always returns NULL.
+ */
+struct kdbus_name_entry *kdbus_name_unlock(struct kdbus_name_registry *reg,
+					   struct kdbus_name_entry *entry)
+{
+	if (entry) {
+		BUG_ON(!rwsem_is_locked(&reg->rwlock));
+		up_read(&reg->rwlock);
+	}
+
+	return NULL;
+}
+
+static int kdbus_name_queue_conn(struct kdbus_conn *conn, u64 flags,
+				 struct kdbus_name_entry *e)
+{
+	struct kdbus_name_queue_item *q;
+
+	q = kzalloc(sizeof(*q), GFP_KERNEL);
+	if (!q)
+		return -ENOMEM;
+
+	q->conn = conn;
+	q->flags = flags;
+	q->entry = e;
+
+	list_add_tail(&q->entry_entry, &e->queue_list);
+	list_add_tail(&q->conn_entry, &conn->names_queue_list);
+
+	return 0;
+}
+
+/**
+ * kdbus_name_is_valid() - check if a name is valid
+ * @p:			The name to check
+ * @allow_wildcard:	Whether or not to allow a wildcard name
+ *
+ * A name is valid if all of the following criterias are met:
+ *
+ *  - The name has two or more elements separated by a period ('.') character.
+ *  - All elements must contain at least one character.
+ *  - Each element must only contain the ASCII characters "[A-Z][a-z][0-9]_-"
+ *    and must not begin with a digit.
+ *  - The name must not exceed KDBUS_NAME_MAX_LEN.
+ *  - If @allow_wildcard is true, the name may end on '.*'
+ */
+bool kdbus_name_is_valid(const char *p, bool allow_wildcard)
+{
+	bool dot, found_dot = false;
+	const char *q;
+
+	for (dot = true, q = p; *q; q++) {
+		if (*q == '.') {
+			if (dot)
+				return false;
+
+			found_dot = true;
+			dot = true;
+		} else {
+			bool good;
+
+			good = isalpha(*q) || (!dot && isdigit(*q)) ||
+				*q == '_' || *q == '-' ||
+				(allow_wildcard && dot &&
+					*q == '*' && *(q + 1) == '\0');
+
+			if (!good)
+				return false;
+
+			dot = false;
+		}
+	}
+
+	if (q - p > KDBUS_NAME_MAX_LEN)
+		return false;
+
+	if (dot)
+		return false;
+
+	if (!found_dot)
+		return false;
+
+	return true;
+}
+
+/**
+ * kdbus_name_acquire() - acquire a name
+ * @reg:		The name registry
+ * @conn:		The connection to pin this entry to
+ * @name:		The name to acquire
+ * @flags:		Acquisition flags (KDBUS_NAME_*)
+ *
+ * Callers must ensure that @conn is either a privileged bus user or has
+ * sufficient privileges in the policy-db to own the well-known name @name.
+ *
+ * Return: 0 success, negative error number on failure.
+ */
+int kdbus_name_acquire(struct kdbus_name_registry *reg,
+		       struct kdbus_conn *conn,
+		       const char *name, u64 *flags)
+{
+	struct kdbus_name_entry *e = NULL;
+	u32 hash;
+	int ret = 0;
+
+	/* lock order: domain -> bus -> ep -> names -> conn */
+	mutex_lock(&conn->ep->bus->lock);
+	down_write(&reg->rwlock);
+
+	hash = kdbus_str_hash(name);
+	e = kdbus_name_lookup(reg, hash, name);
+	if (e) {
+		/* connection already owns that name */
+		if (e->conn == conn) {
+			ret = -EALREADY;
+			goto exit_unlock;
+		}
+
+		if (kdbus_conn_is_activator(conn)) {
+			/* An activator can only own a single name */
+			if (conn->activator_of) {
+				if (conn->activator_of == e)
+					ret = -EALREADY;
+				else
+					ret = -EINVAL;
+			} else if (!e->activator && !conn->activator_of) {
+				/*
+				 * Activator registers for name that is
+				 * already owned
+				 */
+				e->activator = kdbus_conn_ref(conn);
+				conn->activator_of = e;
+			}
+
+			goto exit_unlock;
+		}
+
+		/* take over the name of an activator connection */
+		if (e->flags & KDBUS_NAME_ACTIVATOR) {
+			/*
+			 * Take over the messages queued in the activator
+			 * connection, the activator itself never reads them.
+			 */
+			ret = kdbus_conn_move_messages(conn, e->activator, 0);
+			if (ret < 0)
+				goto exit_unlock;
+
+			ret = kdbus_name_replace_owner(e, conn, *flags);
+			goto exit_unlock;
+		}
+
+		/* take over the name if both parties agree */
+		if ((*flags & KDBUS_NAME_REPLACE_EXISTING) &&
+		    (e->flags & KDBUS_NAME_ALLOW_REPLACEMENT)) {
+			/*
+			 * Move name back to the queue, in case we take it away
+			 * from a connection which asked for queuing.
+			 */
+			if (e->flags & KDBUS_NAME_QUEUE) {
+				ret = kdbus_name_queue_conn(e->conn,
+							    e->flags, e);
+				if (ret < 0)
+					goto exit_unlock;
+			}
+
+			ret = kdbus_name_replace_owner(e, conn, *flags);
+			goto exit_unlock;
+		}
+
+		/* add it to the queue waiting for the name */
+		if (*flags & KDBUS_NAME_QUEUE) {
+			ret = kdbus_name_queue_conn(conn, *flags, e);
+
+			/* tell the caller that we queued it */
+			*flags |= KDBUS_NAME_IN_QUEUE;
+
+			goto exit_unlock;
+		}
+
+		/* the name is busy, return a failure */
+		ret = -EEXIST;
+		goto exit_unlock;
+	} else {
+		/* An activator can only own a single name */
+		if (kdbus_conn_is_activator(conn) &&
+		    conn->activator_of) {
+			ret = -EINVAL;
+			goto exit_unlock;
+		}
+	}
+
+	/* new name entry */
+	e = kzalloc(sizeof(*e), GFP_KERNEL);
+	if (!e) {
+		ret = -ENOMEM;
+		goto exit_unlock;
+	}
+
+	e->name = kstrdup(name, GFP_KERNEL);
+	if (!e->name) {
+		kfree(e);
+		ret = -ENOMEM;
+		goto exit_unlock;
+	}
+
+	if (kdbus_conn_is_activator(conn)) {
+		e->activator = kdbus_conn_ref(conn);
+		conn->activator_of = e;
+	}
+
+	e->flags = *flags;
+	INIT_LIST_HEAD(&e->queue_list);
+	e->name_id = ++reg->name_seq_last;
+
+	mutex_lock(&conn->lock);
+	if (!kdbus_conn_active(conn)) {
+		mutex_unlock(&conn->lock);
+		kfree(e);
+		ret = -ECONNRESET;
+		goto exit_unlock;
+	}
+	hash_add(reg->entries_hash, &e->hentry, hash);
+	kdbus_name_entry_set_owner(e, conn);
+	mutex_unlock(&conn->lock);
+
+	kdbus_notify_name_change(e->conn->ep->bus, KDBUS_ITEM_NAME_ADD,
+				 0, e->conn->id,
+				 0, e->flags, e->name);
+
+exit_unlock:
+	up_write(&reg->rwlock);
+	mutex_unlock(&conn->ep->bus->lock);
+	kdbus_notify_flush(conn->ep->bus);
+	return ret;
+}
+
+/**
+ * kdbus_cmd_name_acquire() - acquire a name from a ioctl command buffer
+ * @reg:		The name registry
+ * @conn:		The connection to pin this entry to
+ * @cmd:		The command as passed in by the ioctl
+ *
+ * Return: 0 on success, negative errno on failure.
+ */
+int kdbus_cmd_name_acquire(struct kdbus_name_registry *reg,
+			   struct kdbus_conn *conn,
+			   struct kdbus_cmd_name *cmd)
+{
+	const char *name;
+	int ret;
+
+	name = kdbus_items_get_str(cmd->items, KDBUS_ITEMS_SIZE(cmd, items),
+				   KDBUS_ITEM_NAME);
+	if (IS_ERR(name))
+		return -EINVAL;
+
+	if (!kdbus_name_is_valid(name, false))
+		return -EINVAL;
+
+	/*
+	 * Do atomic_inc_return here to reserve our slot, then decrement
+	 * it before returning.
+	 */
+	if (atomic_inc_return(&conn->name_count) > KDBUS_CONN_MAX_NAMES) {
+		ret = -E2BIG;
+		goto out_dec;
+	}
+
+	ret = kdbus_ep_policy_check_own_access(conn->ep, conn, name);
+	if (ret < 0)
+		goto out_dec;
+
+	ret = kdbus_name_acquire(reg, conn, name, &cmd->flags);
+	kdbus_notify_flush(conn->ep->bus);
+
+out_dec:
+	/* Decrement the previous allocated slot */
+	atomic_dec(&conn->name_count);
+	return ret;
+}
+
+/**
+ * kdbus_cmd_name_release() - release a name entry from a ioctl command buffer
+ * @reg:		The name registry
+ * @conn:		The connection that holds the name
+ * @cmd:		The command as passed in by the ioctl
+ *
+ * Return: 0 on success, negative errno on failure.
+ */
+int kdbus_cmd_name_release(struct kdbus_name_registry *reg,
+			   struct kdbus_conn *conn,
+			   const struct kdbus_cmd_name *cmd)
+{
+	int ret;
+	const char *name;
+
+	name = kdbus_items_get_str(cmd->items, KDBUS_ITEMS_SIZE(cmd, items),
+				   KDBUS_ITEM_NAME);
+	if (IS_ERR(name))
+		return -EINVAL;
+
+	if (!kdbus_name_is_valid(name, false))
+		return -EINVAL;
+
+	ret = kdbus_ep_policy_check_see_access(conn->ep, conn, name);
+	if (ret < 0)
+		return ret;
+
+	ret = kdbus_name_release(reg, conn, name);
+
+	kdbus_notify_flush(conn->ep->bus);
+	return ret;
+}
+
+static int kdbus_name_list_write(struct kdbus_conn *conn,
+				 struct kdbus_conn *c,
+				 struct kdbus_pool_slice *slice,
+				 size_t *pos,
+				 struct kdbus_name_entry *e,
+				 bool write)
+{
+	const size_t len = sizeof(struct kdbus_name_info);
+	size_t p = *pos;
+	size_t name_item_size = 0;
+
+	if (e) {
+		name_item_size = offsetof(struct kdbus_item, name.name) +
+				 KDBUS_ALIGN8(strlen(e->name) + 1);
+
+		if (kdbus_ep_policy_check_see_access_unlocked(conn->ep, conn,
+							      e->name) < 0)
+			return 0;
+	}
+
+	if (write) {
+		int ret;
+		struct kdbus_name_info info = {
+			.size = len,
+			.owner_id = c->id,
+			.conn_flags = c->flags,
+		};
+
+		info.size += name_item_size;
+
+		/* write record */
+		ret = kdbus_pool_slice_copy(slice, p, &info, len);
+		if (ret < 0)
+			return ret;
+		p += len;
+
+		/* append name */
+		if (e) {
+			/* fake the header of a kdbus_name item */
+			struct {
+				__u64 size;
+				__u64 type;
+				__u64 flags;
+			} h;
+			size_t nlen;
+
+			h.size = name_item_size;
+			h.type = KDBUS_ITEM_OWNED_NAME;
+			h.flags = e->flags;
+
+			ret = kdbus_pool_slice_copy(slice, p, &h, sizeof(h));
+			if (ret < 0)
+				return ret;
+
+			p += sizeof(h);
+
+			nlen = name_item_size - sizeof(h);
+			ret = kdbus_pool_slice_copy(slice, p, e->name, nlen);
+			if (ret < 0)
+				return ret;
+
+			p += nlen;
+		}
+	} else {
+		p += len + name_item_size;
+	}
+
+	*pos = p;
+	return 0;
+}
+
+static int kdbus_name_list_all(struct kdbus_conn *conn, u64 flags,
+			       struct kdbus_pool_slice *slice,
+			       size_t *pos, bool write)
+{
+	struct kdbus_conn *c;
+	size_t p = *pos;
+	int ret, i;
+
+	hash_for_each(conn->ep->bus->conn_hash, i, c, hentry) {
+		bool added = false;
+
+		/* skip activators */
+		if (!(flags & KDBUS_NAME_LIST_ACTIVATORS) &&
+		    kdbus_conn_is_activator(c))
+			continue;
+
+		/* all names the connection owns */
+		if (flags & (KDBUS_NAME_LIST_NAMES |
+			     KDBUS_NAME_LIST_ACTIVATORS)) {
+			struct kdbus_name_entry *e;
+
+			mutex_lock(&c->lock);
+			list_for_each_entry(e, &c->names_list, conn_entry) {
+				struct kdbus_conn *a = e->activator;
+
+				if ((flags & KDBUS_NAME_LIST_ACTIVATORS) &&
+				    a && a != c) {
+					ret = kdbus_name_list_write(conn, a,
+							slice, &p, e, write);
+					if (ret < 0) {
+						mutex_unlock(&c->lock);
+						return ret;
+					}
+
+					added = true;
+				}
+
+				if (flags & KDBUS_NAME_LIST_NAMES ||
+				    kdbus_conn_is_activator(c)) {
+					ret = kdbus_name_list_write(conn, c,
+							slice, &p, e, write);
+					if (ret < 0) {
+						mutex_unlock(&c->lock);
+						return ret;
+					}
+
+					added = true;
+				}
+			}
+			mutex_unlock(&c->lock);
+		}
+
+		/* queue of names the connection is currently waiting for */
+		if (flags & KDBUS_NAME_LIST_QUEUED) {
+			struct kdbus_name_queue_item *q;
+
+			mutex_lock(&c->lock);
+			list_for_each_entry(q, &c->names_queue_list,
+					    conn_entry) {
+				ret = kdbus_name_list_write(conn, c,
+						slice, &p, q->entry, write);
+				if (ret < 0) {
+					mutex_unlock(&c->lock);
+					return ret;
+				}
+
+				added = true;
+			}
+			mutex_unlock(&c->lock);
+		}
+
+		/* nothing added so far, just add the unique ID */
+		if (!added && flags & KDBUS_NAME_LIST_UNIQUE) {
+			ret = kdbus_name_list_write(conn, c,
+					slice, &p, NULL, write);
+			if (ret < 0)
+				return ret;
+		}
+	}
+
+	*pos = p;
+	return 0;
+}
+
+/**
+ * kdbus_cmd_name_list() - list names of a connection
+ * @reg:		The name registry
+ * @conn:		The connection holding the name entries
+ * @cmd:		The command as passed in by the ioctl
+ *
+ * Return: 0 on success, negative errno on failure.
+ */
+int kdbus_cmd_name_list(struct kdbus_name_registry *reg,
+			struct kdbus_conn *conn,
+			struct kdbus_cmd_name_list *cmd)
+{
+	struct kdbus_policy_db *policy_db;
+	struct kdbus_name_list list = {};
+	struct kdbus_pool_slice *slice;
+	size_t pos;
+	int ret;
+
+	policy_db = &conn->ep->policy_db;
+
+	/* lock order: domain -> bus -> ep -> names -> conn */
+	down_read(&reg->rwlock);
+	down_read(&conn->ep->bus->conn_rwlock);
+	down_read(&policy_db->entries_rwlock);
+
+	/* size of header + records */
+	pos = sizeof(struct kdbus_name_list);
+	ret = kdbus_name_list_all(conn, cmd->flags, NULL, &pos, false);
+	if (ret < 0)
+		goto exit_unlock;
+
+	slice = kdbus_pool_slice_alloc(conn->pool, pos);
+	if (IS_ERR(slice)) {
+		ret = PTR_ERR(slice);
+		goto exit_unlock;
+	}
+
+	/* copy the header, specifying the overall size */
+	list.size = pos;
+	ret = kdbus_pool_slice_copy(slice, 0, &list, sizeof(list));
+	if (ret < 0)
+		goto exit_pool_free;
+
+	/* copy the records */
+	pos = sizeof(struct kdbus_name_list);
+	ret = kdbus_name_list_all(conn, cmd->flags, slice, &pos, true);
+	if (ret < 0)
+		goto exit_pool_free;
+
+	cmd->offset = kdbus_pool_slice_offset(slice);
+	kdbus_pool_slice_flush(slice);
+	kdbus_pool_slice_make_public(slice);
+
+exit_pool_free:
+	if (ret < 0)
+		kdbus_pool_slice_free(slice);
+exit_unlock:
+	up_read(&policy_db->entries_rwlock);
+	up_read(&conn->ep->bus->conn_rwlock);
+	up_read(&reg->rwlock);
+	return ret;
+}
ipc/kdbus/names.h new file +81 -0

81 lines not on this page · raw message

Signature · 1 line
2.1.3
#44 lore raw

kdbus: add policy database implementation

In reply to Greg Kroah-Hartman

From: Daniel Mack <[email protected]>

This patch adds the policy database implementation.

A policy databases restrict the possibilities of connections to own, see and talk to well-known names. It can be associated with a bus (through a policy holder connection) or a custom endpoint.

By default, buses have an empty policy database that is augmented on demand when a policy holder connection is instantiated.

Policies are set through KDBUS_CMD_HELLO (when creating a policy holder connection), KDBUS_CMD_CONN_UPDATE (when updating a policy holder connection), KDBUS_CMD_EP_MAKE (creating a custom endpoint) or KDBUS_CMD_EP_UPDATE (updating a custom endpoint). In all cases, the name and policy access information is stored in items of type KDBUS_ITEM_NAME and KDBUS_ITEM_POLICY_ACCESS.

See Documentation/kdbus.txt for more details.

---
 ipc/kdbus/policy.c | 629 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 ipc/kdbus/policy.h |  61 ++++++
 2 files changed, 690 insertions(+)
 create mode 100644 ipc/kdbus/policy.c
 create mode 100644 ipc/kdbus/policy.h
ipc/kdbus/policy.c new file +629 -0
new file mode 100644
index 000000000000..53652dfa2973
@@ -0,0 +1,629 @@
+/*
+ * Copyright (C) 2013-2014 Kay Sievers
+ * Copyright (C) 2013-2014 Greg Kroah-Hartman <[email protected]>
+ * Copyright (C) 2013-2014 Daniel Mack <[email protected]>
+ * Copyright (C) 2013-2014 David Herrmann <[email protected]>
+ * Copyright (C) 2013-2014 Linux Foundation
+ * Copyright (C) 2014 Djalal Harouni
+ *
+ * kdbus is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ */
+
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/sizes.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+#include "bus.h"
+#include "connection.h"
+#include "domain.h"
+#include "item.h"
+#include "names.h"
+#include "policy.h"
+
+#define KDBUS_POLICY_HASH_SIZE	64
+
+/**
+ * struct kdbus_policy_db_cache_entry - a cached entry
+ * @conn_a:		Connection A
+ * @conn_b:		Connection B
+ * @owner:		Owner of policy-entry that produced this cache-entry
+ * @hentry:		The hash table entry for the database's entries_hash
+ */
+struct kdbus_policy_db_cache_entry {
+	struct kdbus_conn *conn_a;
+	struct kdbus_conn *conn_b;
+	const void *owner;
+	struct hlist_node hentry;
+};
+
+/**
+ * struct kdbus_policy_db_entry_access - a database entry access item
+ * @type:		One of KDBUS_POLICY_ACCESS_* types
+ * @access:		Access to grant. One of KDBUS_POLICY_*
+ * @uid:		For KDBUS_POLICY_ACCESS_USER, the global uid
+ * @gid:		For KDBUS_POLICY_ACCESS_GROUP, the global gid
+ * @list:		List entry item for the entry's list
+ *
+ * This is the internal version of struct kdbus_policy_db_access.
+ */
+struct kdbus_policy_db_entry_access {
+	u8 type;		/* USER, GROUP, WORLD */
+	u8 access;		/* OWN, TALK, SEE */
+	union {
+		kuid_t uid;	/* global uid */
+		kgid_t gid;	/* global gid */
+	};
+	struct list_head list;
+};
+
+/**
+ * struct kdbus_policy_db_entry - a policy database entry
+ * @name:		The name to match the policy entry against
+ * @hentry:		The hash entry for the database's entries_hash
+ * @access_list:	List head for keeping tracks of the entry's
+ *			access items.
+ * @owner:		The owner of this entry. Can be a kdbus_conn or
+ *			a kdbus_ep object.
+ * @wildcard:		The name is a wildcard, such as ending on '.*'
+ */
+struct kdbus_policy_db_entry {
+	char *name;
+	struct hlist_node hentry;
+	struct list_head access_list;
+	const void *owner;
+	bool wildcard:1;
+};
+
+static void kdbus_policy_entry_free(struct kdbus_policy_db_entry *e)
+{
+	struct kdbus_policy_db_entry_access *a, *tmp;
+
+	list_for_each_entry_safe(a, tmp, &e->access_list, list) {
+		list_del(&a->list);
+		kfree(a);
+	}
+
+	kfree(e->name);
+	kfree(e);
+}
+
+static const struct kdbus_policy_db_entry *
+kdbus_policy_lookup(struct kdbus_policy_db *db,
+		    const char *name, u32 hash, bool wildcard)
+{
+	struct kdbus_policy_db_entry *e, *found = NULL;
+
+	hash_for_each_possible(db->entries_hash, e, hentry, hash)
+		if (strcmp(e->name, name) == 0 && !e->wildcard)
+			return e;
+
+	if (wildcard) {
+		const char *tmp;
+		char *dot;
+
+		tmp = kstrdup(name, GFP_KERNEL);
+		if (!tmp)
+			return NULL;
+
+		dot = strrchr(tmp, '.');
+		if (!dot)
+			goto exit_free;
+
+		*dot = '\0';
+		hash = kdbus_str_hash(tmp);
+
+		hash_for_each_possible(db->entries_hash, e, hentry, hash)
+			if (strcmp(e->name, tmp) == 0 && e->wildcard) {
+				found = e;
+				/* never "break;" in hash_for_each() */
+				goto exit_free;
+			}
+
+exit_free:
+		kfree(tmp);
+	}
+
+	return found;
+}
+
+/**
+ * kdbus_policy_db_clear - release all memory from a policy db
+ * @db:		The policy database
+ */
+void kdbus_policy_db_clear(struct kdbus_policy_db *db)
+{
+	struct kdbus_policy_db_cache_entry *ce;
+	struct kdbus_policy_db_entry *e;
+	struct hlist_node *tmp;
+	unsigned int i;
+
+	BUG_ON(!db);
+
+	/* purge entries */
+	down_write(&db->entries_rwlock);
+	hash_for_each_safe(db->entries_hash, i, tmp, e, hentry) {
+		hash_del(&e->hentry);
+		kdbus_policy_entry_free(e);
+	}
+	up_write(&db->entries_rwlock);
+
+	/* purge cache */
+	mutex_lock(&db->cache_lock);
+	hash_for_each_safe(db->talk_access_hash, i, tmp, ce, hentry) {
+		hash_del(&ce->hentry);
+		kfree(ce);
+	}
+	mutex_unlock(&db->cache_lock);
+}
+
+/**
+ * kdbus_policy_db_init() - initialize a new policy database
+ * @db:		The location of the database
+ *
+ * This initializes a new policy-db. The underlying memory must have been
+ * cleared to zero by the caller.
+ */
+void kdbus_policy_db_init(struct kdbus_policy_db *db)
+{
+	hash_init(db->entries_hash);
+	hash_init(db->talk_access_hash);
+	init_rwsem(&db->entries_rwlock);
+	mutex_init(&db->cache_lock);
+}
+
+static int kdbus_policy_check_access(const struct kdbus_policy_db_entry *e,
+				     const struct cred *cred,
+				     unsigned int access)
+{
+	struct kdbus_policy_db_entry_access *a;
+	struct group_info *group_info;
+	int i;
+
+	if (!e)
+		return -EPERM;
+
+	group_info = cred->group_info;
+
+	list_for_each_entry(a, &e->access_list, list) {
+		if (a->access >= access) {
+			switch (a->type) {
+			case KDBUS_POLICY_ACCESS_USER:
+				if (uid_eq(cred->uid, a->uid))
+					return 0;
+				break;
+			case KDBUS_POLICY_ACCESS_GROUP:
+				if (gid_eq(cred->gid, a->gid))
+					return 0;
+
+				for (i = 0; i < group_info->ngroups; i++) {
+					kgid_t gid = GROUP_AT(group_info, i);
+
+					if (gid_eq(gid, a->gid))
+						return 0;
+				}
+
+				break;
+			case KDBUS_POLICY_ACCESS_WORLD:
+				return 0;
+			}
+		}
+	}
+
+	return -EPERM;
+}
+
+/**
+ * kdbus_policy_check_own_access() - check whether a connection is allowed
+ *				     to own a name
+ * @db:		The policy database
+ * @cred:	The creds to check against
+ * @name:	The name to check
+ *
+ * Return: 0 if the connection is allowed to own the name, -EPERM otherwise
+ */
+int kdbus_policy_check_own_access(struct kdbus_policy_db *db,
+				  const struct cred *cred,
+				  const char *name)
+{
+	const struct kdbus_policy_db_entry *e;
+	int ret;
+
+	down_read(&db->entries_rwlock);
+	e = kdbus_policy_lookup(db, name, kdbus_str_hash(name), true);
+	ret = kdbus_policy_check_access(e, cred, KDBUS_POLICY_OWN);
+	up_read(&db->entries_rwlock);
+
+	return ret;
+}
+
+/**
+ * kdbus_policy_check_talk_access() - check if one connection is allowed
+ *				       to send a message to another connection
+ * @db:			The policy database
+ * @conn_src:		The source connection
+ * @conn_dst:		The destination connection
+ *
+ * Return: 0 if access is granted, -EPERM if not, negative errno on failure
+ */
+int kdbus_policy_check_talk_access(struct kdbus_policy_db *db,
+				   struct kdbus_conn *conn_src,
+				   struct kdbus_conn *conn_dst)
+{
+	struct kdbus_policy_db_cache_entry *ce;
+	struct kdbus_name_entry *name_entry;
+	unsigned int hash = 0;
+	const void *owner;
+	int ret;
+
+	/*
+	 * If there was a positive match for these two connections before,
+	 * there's an entry in the hash table for them.
+	 */
+	hash ^= hash_ptr(conn_src, KDBUS_POLICY_HASH_SIZE);
+	hash ^= hash_ptr(conn_dst, KDBUS_POLICY_HASH_SIZE);
+
+	mutex_lock(&db->cache_lock);
+	hash_for_each_possible(db->talk_access_hash, ce, hentry, hash)
+		if (ce->conn_a == conn_src && ce->conn_b == conn_dst) {
+			mutex_unlock(&db->cache_lock);
+			return 0;
+		}
+	mutex_unlock(&db->cache_lock);
+
+	/*
+	 * Otherwise, walk the connection list and store a hash-table entry if
+	 * send access is granted.
+	 */
+
+	down_read(&db->entries_rwlock);
+
+	ret = -EPERM;
+	mutex_lock(&conn_dst->lock);
+	list_for_each_entry(name_entry, &conn_dst->names_list, conn_entry) {
+		u32 hash = kdbus_str_hash(name_entry->name);
+		const struct kdbus_policy_db_entry *e;
+
+		e = kdbus_policy_lookup(db, name_entry->name, hash, true);
+		if (kdbus_policy_check_access(e, conn_src->cred,
+					      KDBUS_POLICY_TALK) == 0) {
+			owner = e->owner;
+			ret = 0;
+			break;
+		}
+	}
+	mutex_unlock(&conn_dst->lock);
+
+	if (ret >= 0) {
+		ret = -ENOMEM;
+		ce = kmalloc(sizeof(*ce), GFP_KERNEL);
+		if (ce) {
+			ce->conn_a = conn_src;
+			ce->conn_b = conn_dst;
+			ce->owner = owner;
+			INIT_HLIST_NODE(&ce->hentry);
+
+			mutex_lock(&db->cache_lock);
+			hash_add(db->talk_access_hash, &ce->hentry, hash);
+			mutex_unlock(&db->cache_lock);
+
+			ret = 0;
+		}
+	}
+
+	up_read(&db->entries_rwlock);
+
+	return ret;
+}
+
+/**
+ * kdbus_policy_check_see_access_unlocked() - Check whether a connection is
+ *					      allowed to see a given name
+ * @db:		The policy database
+ * @cred:	The cred to check against
+ * @name:	The name
+ *
+ * Return: 0 if permission to see the name is granted, -EPERM otherwise
+ */
+int kdbus_policy_check_see_access_unlocked(struct kdbus_policy_db *db,
+					   const struct cred *cred,
+					   const char *name)
+{
+	const struct kdbus_policy_db_entry *e;
+
+	e = kdbus_policy_lookup(db, name, kdbus_str_hash(name), true);
+	return kdbus_policy_check_access(e, cred, KDBUS_POLICY_SEE);
+}
+
+static void __kdbus_policy_remove_owner_cache(struct kdbus_policy_db *db,
+					      const void *owner)
+{
+	struct kdbus_policy_db_cache_entry *ce;
+	struct hlist_node *tmp;
+	int i;
+
+	mutex_lock(&db->cache_lock);
+	hash_for_each_safe(db->talk_access_hash, i, tmp, ce, hentry)
+		if (ce->owner == owner) {
+			hash_del(&ce->hentry);
+			kfree(ce);
+		}
+	mutex_unlock(&db->cache_lock);
+}
+
+static void __kdbus_policy_remove_owner(struct kdbus_policy_db *db,
+					const void *owner)
+{
+	struct kdbus_policy_db_entry *e;
+	struct hlist_node *tmp;
+	int i;
+
+	hash_for_each_safe(db->entries_hash, i, tmp, e, hentry)
+		if (e->owner == owner) {
+			hash_del(&e->hentry);
+			kdbus_policy_entry_free(e);
+		}
+}
+
+/**
+ * kdbus_policy_remove_owner() - remove all entries related to a connection
+ * @db:		The policy database
+ * @owner:	The connection which items to remove
+ */
+void kdbus_policy_remove_owner(struct kdbus_policy_db *db,
+			       const void *owner)
+{
+	down_write(&db->entries_rwlock);
+	__kdbus_policy_remove_owner(db, owner);
+	__kdbus_policy_remove_owner_cache(db, owner);
+	up_write(&db->entries_rwlock);
+}
+
+/**
+ * kdbus_policy_purge_cache_for_conn() - remove all cached entries related to
+ *				a connection
+ * @db:		The policy database
+ * @conn:	The connection which items to remove
+ */
+void kdbus_policy_purge_cache(struct kdbus_policy_db *db,
+			      const struct kdbus_conn *conn)
+{
+	struct kdbus_policy_db_cache_entry *ce;
+	struct hlist_node *tmp;
+	int i;
+
+	mutex_lock(&db->cache_lock);
+	hash_for_each_safe(db->talk_access_hash, i, tmp, ce, hentry)
+		if (ce->conn_a == conn || ce->conn_b == conn) {
+			hash_del(&ce->hentry);
+			kfree(ce);
+		}
+	mutex_unlock(&db->cache_lock);
+}
+
+/*
+ * Convert user provided policy access to internal kdbus policy
+ * access
+ */
+static struct kdbus_policy_db_entry_access *
+kdbus_policy_make_access(const struct kdbus_policy_access *uaccess)
+{
+	int ret;
+	struct kdbus_policy_db_entry_access *a;
+
+	a = kzalloc(sizeof(*a), GFP_KERNEL);
+	if (!a)
+		return ERR_PTR(-ENOMEM);
+
+	ret = -EINVAL;
+	switch (uaccess->access) {
+	case KDBUS_POLICY_SEE:
+	case KDBUS_POLICY_TALK:
+	case KDBUS_POLICY_OWN:
+		a->access = uaccess->access;
+		break;
+	default:
+		goto err;
+	}
+
+	switch (uaccess->type) {
+	case KDBUS_POLICY_ACCESS_USER:
+		a->uid = make_kuid(current_user_ns(), uaccess->id);
+		if (!uid_valid(a->uid))
+			goto err;
+
+		break;
+	case KDBUS_POLICY_ACCESS_GROUP:
+		a->gid = make_kgid(current_user_ns(), uaccess->id);
+		if (!gid_valid(a->gid))
+			goto err;
+
+		break;
+	case KDBUS_POLICY_ACCESS_WORLD:
+		a->uid = current_uid();
+		break;
+	default:
+		goto err;
+	}
+
+	a->type = uaccess->type;
+
+	return a;
+
+err:
+	kfree(a);
+	return ERR_PTR(ret);
+}
+
+/**
+ * kdbus_policy_set() - set a connection's policy rules
+ * @db:				The policy database
+ * @items:			A list of kdbus_item elements that contain both
+ *				names and access rules to set.
+ * @items_size:			The total size of the items.
+ * @max_policies:		The maximum number of policy entries to allow.
+ *				Pass 0 for no limit.
+ * @allow_wildcards:		Boolean value whether wildcard entries (such
+ *				ending on '.*') should be allowed.
+ * @owner:			The owner of the new policy items.
+ *
+ * This function sets a new set of policies for a given owner. The names and
+ * access rules are gathered by walking the list of items passed in as
+ * argument. An item of type KDBUS_ITEM_NAME is expected before any number of
+ * KDBUS_ITEM_POLICY_ACCESS items. If there are more repetitions of this
+ * pattern than denoted in @max_policies, -EINVAL is returned.
+ *
+ * In order to allow atomic replacement of rules, the function first removes
+ * all entries that have been created for the given owner previously.
+ *
+ * Return: 0 on success, negative errno on failure.
+ */
+int kdbus_policy_set(struct kdbus_policy_db *db,
+		     const struct kdbus_item *items,
+		     size_t items_size,
+		     size_t max_policies,
+		     bool allow_wildcards,
+		     const void *owner)
+{
+	struct kdbus_policy_db_entry_access *a;
+	struct kdbus_policy_db_entry *e, *p;
+	const struct kdbus_item *item;
+	struct hlist_node *tmp;
+	HLIST_HEAD(entries);
+	HLIST_HEAD(restore);
+	size_t count = 0;
+	int i, ret = 0;
+	u32 hash;
+
+	if (items_size > KDBUS_POLICY_MAX_SIZE)
+		return -E2BIG;
+
+	/* Walk the list of items and look for new policies */
+	e = NULL;
+	KDBUS_ITEMS_FOREACH(item, items, items_size) {
+		switch (item->type) {
+		case KDBUS_ITEM_NAME: {
+			size_t len;
+
+			if (max_policies && ++count > max_policies) {
+				ret = -E2BIG;
+				goto exit;
+			}
+
+			if (!kdbus_name_is_valid(item->str, true)) {
+				ret = -EINVAL;
+				goto exit;
+			}
+
+			e = kzalloc(sizeof(*e), GFP_KERNEL);
+			if (!e) {
+				ret = -ENOMEM;
+				goto exit;
+			}
+
+			INIT_LIST_HEAD(&e->access_list);
+			e->owner = owner;
+			hlist_add_head(&e->hentry, &entries);
+
+			e->name = kstrdup(item->str, GFP_KERNEL);
+			if (!e->name) {
+				ret = -ENOMEM;
+				goto exit;
+			}
+
+			/*
+			 * If a supplied name ends with an '.*', cut off that
+			 * part, only store anything before it, and mark the
+			 * entry as wildcard.
+			 */
+			len = strlen(e->name);
+			if (len > 2 &&
+			    e->name[len - 3] == '.' &&
+			    e->name[len - 2] == '*') {
+				if (!allow_wildcards) {
+					ret = -EINVAL;
+					goto exit;
+				}
+
+				e->name[len - 3] = '\0';
+				e->wildcard = true;
+			}
+
+			break;
+		}
+
+		case KDBUS_ITEM_POLICY_ACCESS:
+			if (!e) {
+				ret = -EINVAL;
+				goto exit;
+			}
+
+			a = kdbus_policy_make_access(&item->policy_access);
+			if (IS_ERR(a)) {
+				ret = PTR_ERR(a);
+				goto exit;
+			}
+
+			list_add_tail(&a->list, &e->access_list);
+			break;
+		}
+	}
+
+	down_write(&db->entries_rwlock);
+
+	/* remember previous entries to restore in case of failure */
+	hash_for_each_safe(db->entries_hash, i, tmp, e, hentry)
+		if (e->owner == owner) {
+			hash_del(&e->hentry);
+			hlist_add_head(&e->hentry, &restore);
+		}
+
+	hlist_for_each_entry_safe(e, tmp, &entries, hentry) {
+		/* prevent duplicates */
+		hash = kdbus_str_hash(e->name);
+		hash_for_each_possible(db->entries_hash, p, hentry, hash)
+			if (strcmp(e->name, p->name) == 0 &&
+			    e->wildcard == p->wildcard) {
+				ret = -EEXIST;
+				goto restore;
+			}
+
+		hlist_del(&e->hentry);
+		hash_add(db->entries_hash, &e->hentry, hash);
+	}
+
+	/* purge all cache-entries produced by previous rules */
+	__kdbus_policy_remove_owner_cache(db, owner);
+
+restore:
+	/* if we failed, flush all entries we added so far, but keep cache */
+	if (ret < 0)
+		__kdbus_policy_remove_owner(db, owner);
+
+	/* if we failed, restore entries, otherwise release them */
+	hlist_for_each_entry_safe(e, tmp, &restore, hentry) {
+		hlist_del(&e->hentry);
+		if (ret < 0) {
+			hash = kdbus_str_hash(e->name);
+			hash_add(db->entries_hash, &e->hentry, hash);
+		} else {
+			kdbus_policy_entry_free(e);
+		}
+	}
+
+	up_write(&db->entries_rwlock);
+
+exit:
+	hlist_for_each_entry_safe(e, tmp, &entries, hentry) {
+		hlist_del(&e->hentry);
+		kdbus_policy_entry_free(e);
+	}
+
+	return ret;
+}
ipc/kdbus/policy.h new file +61 -0

61 lines not on this page · raw message

Signature · 1 line
2.1.3
#45 lore raw

kdbus: add Makefile, Kconfig and MAINTAINERS entry

In reply to Greg Kroah-Hartman

From: Daniel Mack <[email protected]>

This patch hooks up the build system to actually compile the files added by previous patches. It also adds an entry to MAINTAINERS to direct people to Greg KH, David Herrmann, Djalal Harouni and me for questions and patches.

---
 MAINTAINERS        | 12 ++++++++++++
 init/Kconfig       | 12 ++++++++++++
 ipc/Makefile       |  2 +-
 ipc/kdbus/Makefile | 21 +++++++++++++++++++++
 4 files changed, 46 insertions(+), 1 deletion(-)
 create mode 100644 ipc/kdbus/Makefile
MAINTAINERS +12 -0
index c444907ccd69..cfb1819667bc 100644
@@ -5276,6 +5276,18 @@ S:	Maintained
 F:	Documentation/kbuild/kconfig-language.txt
 F:	scripts/kconfig/
 
+KDBUS
+M:	Greg Kroah-Hartman <[email protected]>
+M:	Daniel Mack <[email protected]>
+M:	David Herrmann <[email protected]>
+M:	Djalal Harouni <[email protected]>
+L:	[email protected]
+S:	Maintained
+F:	ipc/kdbus/*
+F:	Documentation/kdbus.txt
+F:	include/uapi/linux/kdbus.h
+F:	tools/testing/selftests/kdbus/
+
 KDUMP
 M:	Vivek Goyal <[email protected]>
 M:	Haren Myneni <[email protected]>
init/Kconfig +12 -0
index 2081a4d3d917..44bf491c971f 100644
@@ -261,6 +261,18 @@ config POSIX_MQUEUE_SYSCTL
 	depends on SYSCTL
 	default y
 
+config KDBUS
+	tristate "kdbus interprocess communication"
+	depends on TMPFS
+	help
+	  D-Bus is a system for low-latency, low-overhead, easy to use
+	  interprocess communication (IPC).
+
+	  See Documentation/kdbus.txt
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called kdbus.
+
 config CROSS_MEMORY_ATTACH
 	bool "Enable process_vm_readv/writev syscalls"
 	depends on MMU
ipc/Makefile +1 -1
index 9075e172e52c..df8df7c4e33c 100644
@@ -9,4 +9,4 @@ obj_mq-$(CONFIG_COMPAT) += compat_mq.o
 obj-$(CONFIG_POSIX_MQUEUE) += mqueue.o msgutil.o $(obj_mq-y)
 obj-$(CONFIG_IPC_NS) += namespace.o
 obj-$(CONFIG_POSIX_MQUEUE_SYSCTL) += mq_sysctl.o
-
+obj-$(CONFIG_KDBUS) += kdbus/
ipc/kdbus/Makefile new file +21 -0
new file mode 100644
index 000000000000..37e5dd4f218a
@@ -0,0 +1,21 @@
+kdbus-y := \
+	bus.o \
+	connection.o \
+	endpoint.o \
+	fs.o \
+	handle.o \
+	item.o \
+	main.o \
+	match.o \
+	message.o \
+	metadata.o \
+	names.o \
+	node.o \
+	notify.o \
+	domain.o \
+	policy.o \
+	pool.o \
+	queue.o \
+	util.o
+
+obj-$(CONFIG_KDBUS) += kdbus.o
Signature · 1 line
2.1.3
#46 lore raw

kdbus: add selftests

In reply to Greg Kroah-Hartman

From: Daniel Mack <[email protected]>

This patch adds a quite extensive test suite for kdbus that checks the most important code pathes in the driver. The idea is to extend the test suite over time.

Also, this code can serve as an example implementation to show how to use the kernel API from userspace.

---
 tools/testing/selftests/Makefile                 |    1 +
 tools/testing/selftests/kdbus/.gitignore         |   11 +
 tools/testing/selftests/kdbus/Makefile           |   45 +
 tools/testing/selftests/kdbus/kdbus-enum.c       |   94 ++
 tools/testing/selftests/kdbus/kdbus-enum.h       |   14 +
 tools/testing/selftests/kdbus/kdbus-test.c       |  546 ++++++++++
 tools/testing/selftests/kdbus/kdbus-test.h       |   81 ++
 tools/testing/selftests/kdbus/kdbus-util.c       | 1240 ++++++++++++++++++++++
 tools/testing/selftests/kdbus/kdbus-util.h       |  143 +++
 tools/testing/selftests/kdbus/test-activator.c   |  317 ++++++
 tools/testing/selftests/kdbus/test-benchmark.c   |  409 +++++++
 tools/testing/selftests/kdbus/test-bus.c         |  130 +++
 tools/testing/selftests/kdbus/test-chat.c        |  123 +++
 tools/testing/selftests/kdbus/test-connection.c  |  501 +++++++++
 tools/testing/selftests/kdbus/test-daemon.c      |   66 ++
 tools/testing/selftests/kdbus/test-endpoint.c    |  221 ++++
 tools/testing/selftests/kdbus/test-fd.c          |  664 ++++++++++++
 tools/testing/selftests/kdbus/test-free.c        |   34 +
 tools/testing/selftests/kdbus/test-match.c       |  437 ++++++++
 tools/testing/selftests/kdbus/test-message.c     |  371 +++++++
 tools/testing/selftests/kdbus/test-metadata-ns.c |  258 +++++
 tools/testing/selftests/kdbus/test-monitor.c     |  156 +++
 tools/testing/selftests/kdbus/test-names.c       |  184 ++++
 tools/testing/selftests/kdbus/test-policy-ns.c   |  622 +++++++++++
 tools/testing/selftests/kdbus/test-policy-priv.c | 1168 ++++++++++++++++++++
 tools/testing/selftests/kdbus/test-policy.c      |   81 ++
 tools/testing/selftests/kdbus/test-race.c        |  313 ++++++
 tools/testing/selftests/kdbus/test-sync.c        |  241 +++++
 tools/testing/selftests/kdbus/test-timeout.c     |   97 ++
 29 files changed, 8568 insertions(+)
 create mode 100644 tools/testing/selftests/kdbus/.gitignore
 create mode 100644 tools/testing/selftests/kdbus/Makefile
 create mode 100644 tools/testing/selftests/kdbus/kdbus-enum.c
 create mode 100644 tools/testing/selftests/kdbus/kdbus-enum.h
 create mode 100644 tools/testing/selftests/kdbus/kdbus-test.c
 create mode 100644 tools/testing/selftests/kdbus/kdbus-test.h
 create mode 100644 tools/testing/selftests/kdbus/kdbus-util.c
 create mode 100644 tools/testing/selftests/kdbus/kdbus-util.h
 create mode 100644 tools/testing/selftests/kdbus/test-activator.c
 create mode 100644 tools/testing/selftests/kdbus/test-benchmark.c
 create mode 100644 tools/testing/selftests/kdbus/test-bus.c
 create mode 100644 tools/testing/selftests/kdbus/test-chat.c
 create mode 100644 tools/testing/selftests/kdbus/test-connection.c
 create mode 100644 tools/testing/selftests/kdbus/test-daemon.c
 create mode 100644 tools/testing/selftests/kdbus/test-endpoint.c
 create mode 100644 tools/testing/selftests/kdbus/test-fd.c
 create mode 100644 tools/testing/selftests/kdbus/test-free.c
 create mode 100644 tools/testing/selftests/kdbus/test-match.c
 create mode 100644 tools/testing/selftests/kdbus/test-message.c
 create mode 100644 tools/testing/selftests/kdbus/test-metadata-ns.c
 create mode 100644 tools/testing/selftests/kdbus/test-monitor.c
 create mode 100644 tools/testing/selftests/kdbus/test-names.c
 create mode 100644 tools/testing/selftests/kdbus/test-policy-ns.c
 create mode 100644 tools/testing/selftests/kdbus/test-policy-priv.c
 create mode 100644 tools/testing/selftests/kdbus/test-policy.c
 create mode 100644 tools/testing/selftests/kdbus/test-race.c
 create mode 100644 tools/testing/selftests/kdbus/test-sync.c
 create mode 100644 tools/testing/selftests/kdbus/test-timeout.c
tools/testing/selftests/Makefile +1 -0
index 45f145c6f843..10cd20e07244 100644
@@ -2,6 +2,7 @@ TARGETS = breakpoints
 TARGETS += cpu-hotplug
 TARGETS += efivarfs
 TARGETS += kcmp
+TARGETS += kdbus
 TARGETS += memfd
 TARGETS += memory-hotplug
 TARGETS += mqueue
tools/testing/selftests/kdbus/.gitignore new file +11 -0
new file mode 100644
index 000000000000..4b97beee5f80
@@ -0,0 +1,11 @@
+*.cmd
+*.ko
+*.mod.c
+modules.order
+Module.symvers
+*.o
+*.swp
+.tmp_versions
+tags
+tools/kdbus-monitor
+test/kdbus-test
tools/testing/selftests/kdbus/Makefile new file +45 -0

45 lines not on this page · raw message

tools/testing/selftests/kdbus/kdbus-enum.c new file +94 -0

94 lines not on this page · raw message

tools/testing/selftests/kdbus/kdbus-enum.h new file +14 -0
new file mode 100644
index 000000000000..110bfd332859
@@ -0,0 +1,14 @@
+/*
+ * Copyright (C) 2013-2014 Kay Sievers
+ *
+ * kdbus is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ */
+#pragma once
+
+const char *enum_CMD(long long id);
+const char *enum_MSG(long long id);
+const char *enum_MATCH(long long id);
+const char *enum_PAYLOAD(long long id);
tools/testing/selftests/kdbus/kdbus-test.c new file +546 -0

546 lines not on this page · raw message

tools/testing/selftests/kdbus/kdbus-test.h new file +81 -0

81 lines not on this page · raw message

tools/testing/selftests/kdbus/kdbus-util.c new file +1240 -0

1,240 lines not on this page · raw message

tools/testing/selftests/kdbus/kdbus-util.h new file +143 -0

143 lines not on this page · raw message

tools/testing/selftests/kdbus/test-activator.c new file +317 -0

317 lines not on this page · raw message

tools/testing/selftests/kdbus/test-benchmark.c new file +409 -0

409 lines not on this page · raw message

tools/testing/selftests/kdbus/test-bus.c new file +130 -0

93 lines not on this page · raw message

tools/testing/selftests/kdbus/test-chat.c new file +123 -0

123 lines not on this page · raw message

tools/testing/selftests/kdbus/test-connection.c new file +501 -0

501 lines not on this page · raw message

tools/testing/selftests/kdbus/test-daemon.c new file +66 -0

66 lines not on this page · raw message

tools/testing/selftests/kdbus/test-endpoint.c new file +221 -0

221 lines not on this page · raw message

tools/testing/selftests/kdbus/test-fd.c new file +664 -0

664 lines not on this page · raw message

tools/testing/selftests/kdbus/test-free.c new file +34 -0
new file mode 100644
index 000000000000..f43e3f616738

Lines of this file are not shown. View the raw message.

tools/testing/selftests/kdbus/test-match.c new file +437 -0

437 lines not on this page · raw message

tools/testing/selftests/kdbus/test-message.c new file +371 -0

371 lines not on this page · raw message

tools/testing/selftests/kdbus/test-metadata-ns.c new file +258 -0

258 lines not on this page · raw message

tools/testing/selftests/kdbus/test-monitor.c new file +156 -0

156 lines not on this page · raw message

tools/testing/selftests/kdbus/test-names.c new file +184 -0

184 lines not on this page · raw message

tools/testing/selftests/kdbus/test-policy-ns.c new file +622 -0

622 lines not on this page · raw message

tools/testing/selftests/kdbus/test-policy-priv.c new file +1168 -0

1,168 lines not on this page · raw message

tools/testing/selftests/kdbus/test-policy.c new file +81 -0

81 lines not on this page · raw message

tools/testing/selftests/kdbus/test-race.c new file +313 -0

313 lines not on this page · raw message

tools/testing/selftests/kdbus/test-sync.c new file +241 -0

241 lines not on this page · raw message

tools/testing/selftests/kdbus/test-timeout.c new file +97 -0

97 lines not on this page · raw message

The rest of this diff is not shown. View the raw message.

Signature · 1 line
2.1.3

Part of the diff is not shown here. View the raw message.

#47 lore raw
In reply to Greg Kroah-Hartman
Quoted 6 lines · Greg Kroah-Hartman

kdbus is a kernel-level IPC implementation that aims for resemblance to the the protocol layer with the existing userspace D-Bus daemon while enabling some features that couldn't be implemented before in userspace.

The documentation in the first patch in this series explains the protocol and the API details.

Ugh, and I can't seem to remember to put the patch numbers on the series, sorry about that, my git format-patch default options are set up for applying patches and responding to them, not generating numbered series :(

If someone wants the numbers, I can resend them, otherwise, just stick with the git tree...

thanks,

greg k-h