diff options
Diffstat (limited to 'kdbus.patch')
-rw-r--r-- | kdbus.patch | 52079 |
1 files changed, 0 insertions, 52079 deletions
diff --git a/kdbus.patch b/kdbus.patch deleted file mode 100644 index c4286e8c7..000000000 --- a/kdbus.patch +++ /dev/null @@ -1,52079 +0,0 @@ -From 48480f8c402cc616a6ac03a51cee6f988a5c916c Mon Sep 17 00:00:00 2001 -From: Daniel Mack <daniel@zonque.org> -Date: Thu, 11 Sep 2014 21:50:47 +0200 -Subject: [PATCH 001/132] kdbus: add documentation - -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 via ioctls -on files exposed through a filesystem called 'kdbusfs'. The default -mount point of kdbusfs is /sys/fs/kdbus. This patch adds detailed -documentation about the kernel level API design. - -This patch adds a set of comprehensive set of DocBook files which -can be turned into man-pages using 'make mandocs', or into HTML -files with 'make htmldocs'. - -Signed-off-by: Daniel Mack <daniel@zonque.org> -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Djalal Harouni <tixxdz@opendz.org> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - Documentation/Makefile | 2 +- - Documentation/kdbus/Makefile | 30 + - Documentation/kdbus/kdbus.bus.xml | 360 +++++++++ - Documentation/kdbus/kdbus.connection.xml | 1252 +++++++++++++++++++++++++++++ - Documentation/kdbus/kdbus.endpoint.xml | 436 ++++++++++ - Documentation/kdbus/kdbus.fs.xml | 124 +++ - Documentation/kdbus/kdbus.item.xml | 840 ++++++++++++++++++++ - Documentation/kdbus/kdbus.match.xml | 553 +++++++++++++ - Documentation/kdbus/kdbus.message.xml | 1277 ++++++++++++++++++++++++++++++ - Documentation/kdbus/kdbus.name.xml | 711 +++++++++++++++++ - Documentation/kdbus/kdbus.policy.xml | 406 ++++++++++ - Documentation/kdbus/kdbus.pool.xml | 320 ++++++++ - Documentation/kdbus/kdbus.xml | 1012 +++++++++++++++++++++++ - Documentation/kdbus/stylesheet.xsl | 16 + - Makefile | 1 + - 15 files changed, 7339 insertions(+), 1 deletion(-) - create mode 100644 Documentation/kdbus/Makefile - create mode 100644 Documentation/kdbus/kdbus.bus.xml - create mode 100644 Documentation/kdbus/kdbus.connection.xml - create mode 100644 Documentation/kdbus/kdbus.endpoint.xml - create mode 100644 Documentation/kdbus/kdbus.fs.xml - create mode 100644 Documentation/kdbus/kdbus.item.xml - create mode 100644 Documentation/kdbus/kdbus.match.xml - create mode 100644 Documentation/kdbus/kdbus.message.xml - create mode 100644 Documentation/kdbus/kdbus.name.xml - create mode 100644 Documentation/kdbus/kdbus.policy.xml - create mode 100644 Documentation/kdbus/kdbus.pool.xml - create mode 100644 Documentation/kdbus/kdbus.xml - create mode 100644 Documentation/kdbus/stylesheet.xsl - -diff --git a/Documentation/Makefile b/Documentation/Makefile -index 6883a1b9b351..5e3fde632d03 100644 ---- a/Documentation/Makefile -+++ b/Documentation/Makefile -@@ -1,4 +1,4 @@ - subdir-y := accounting auxdisplay blackfin connector \ -- filesystems filesystems ia64 laptops mic misc-devices \ -+ filesystems filesystems ia64 kdbus laptops mic misc-devices \ - networking pcmcia prctl ptp spi timers vDSO video4linux \ - watchdog -diff --git a/Documentation/kdbus/Makefile b/Documentation/kdbus/Makefile -new file mode 100644 -index 000000000000..cd6b48ee41bf ---- /dev/null -+++ b/Documentation/kdbus/Makefile -@@ -0,0 +1,30 @@ -+DOCS := \ -+ kdbus.xml \ -+ kdbus.bus.xml \ -+ kdbus.connection.xml \ -+ kdbus.endpoint.xml \ -+ kdbus.fs.xml \ -+ kdbus.item.xml \ -+ kdbus.match.xml \ -+ kdbus.message.xml \ -+ kdbus.name.xml \ -+ kdbus.policy.xml \ -+ kdbus.pool.xml -+ -+XMLFILES := $(addprefix $(obj)/,$(DOCS)) -+MANFILES := $(patsubst %.xml, %.7, $(XMLFILES)) -+HTMLFILES := $(patsubst %.xml, %.html, $(XMLFILES)) -+ -+XMLTO_ARGS := -m $(obj)/stylesheet.xsl -+ -+%.7: %.xml -+ xmlto man $(XMLTO_ARGS) -o . $< -+ -+%.html: %.xml -+ xmlto html-nochunks $(XMLTO_ARGS) -o . $< -+ -+mandocs: $(MANFILES) -+ -+htmldocs: $(HTMLFILES) -+ -+clean-files := $(MANFILES) $(HTMLFILES) -diff --git a/Documentation/kdbus/kdbus.bus.xml b/Documentation/kdbus/kdbus.bus.xml -new file mode 100644 -index 000000000000..4d875e59ac02 ---- /dev/null -+++ b/Documentation/kdbus/kdbus.bus.xml -@@ -0,0 +1,360 @@ -+<?xml version='1.0'?> <!--*-nxml-*--> -+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" -+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> -+ -+<refentry id="kdbus.bus"> -+ -+ <refentryinfo> -+ <title>kdbus.bus</title> -+ <productname>kdbus.bus</productname> -+ </refentryinfo> -+ -+ <refmeta> -+ <refentrytitle>kdbus.bus</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </refmeta> -+ -+ <refnamediv> -+ <refname>kdbus.bus</refname> -+ <refpurpose>kdbus bus</refpurpose> -+ </refnamediv> -+ -+ <refsect1> -+ <title>Description</title> -+ -+ <para> -+ A bus is a resource that is shared between connections in order to -+ transmit messages (see -+ <citerefentry> -+ <refentrytitle>kdbus.message</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ ). -+ Each bus is independent, and operations on the bus will not have any -+ effect on other buses. A bus is a management entity that controls the -+ addresses of its connections, their policies and message transactions -+ performed via this bus. -+ </para> -+ <para> -+ Each bus is bound to the mount instance it was created on. It has a -+ custom name that is unique across all buses of a domain. In -+ <citerefentry> -+ <refentrytitle>kdbus.fs</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ , a bus is presented as a directory. No operations can be performed on -+ the bus itself; instead you need to perform the operations on an endpoint -+ associated with the bus. Endpoints are accessible as files underneath the -+ bus directory. A default endpoint called <constant>bus</constant> is -+ provided on each bus. -+ </para> -+ <para> -+ Bus names may be chosen freely except for one restriction: the name must -+ be prefixed with the numeric effective UID of the creator and a dash. This -+ is required to avoid namespace clashes between different users. When -+ creating a bus, the name that is passed in must be properly formatted, or -+ the kernel will refuse creation of the bus. Example: -+ <literal>1047-foobar</literal> is an acceptable name for a bus -+ registered by a user with UID 1047. However, -+ <literal>1024-foobar</literal> is not, and neither is -+ <literal>foobar</literal>. The UID must be provided in the -+ user-namespace of the bus owner. -+ </para> -+ <para> -+ To create a new bus, you need to open the control file of a domain and -+ employ the <constant>KDBUS_CMD_BUS_MAKE</constant> ioctl. The control -+ file descriptor that was used to issue -+ <constant>KDBUS_CMD_BUS_MAKE</constant> must not previously have been -+ used for any other control-ioctl and must 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 to create a single new bus; from that -+ point on, it is not used for any further communication until the final -+ <citerefentry> -+ <refentrytitle>close</refentrytitle> -+ <manvolnum>2</manvolnum> -+ </citerefentry> -+ . -+ </para> -+ <para> -+ Each bus will generate a random, 128-bit UUID upon creation. This UUID -+ will be returned to creators of connections through -+ <varname>kdbus_cmd_hello.id128</varname> and can be used to uniquely -+ identify buses, even across different machines or containers. The UUID -+ will have its variant bits set to <literal>DCE</literal>, and denote -+ version 4 (random). For more details on UUIDs, see <ulink -+ url="https://en.wikipedia.org/wiki/Universally_unique_identifier"> -+ the Wikipedia article on UUIDs</ulink>. -+ </para> -+ -+ </refsect1> -+ -+ <refsect1> -+ <title>Creating buses</title> -+ <para> -+ To create a new bus, the <constant>KDBUS_CMD_BUS_MAKE</constant> -+ command is used. It takes a <type>struct kdbus_cmd</type> argument. -+ </para> -+ <programlisting> -+struct kdbus_cmd { -+ __u64 size; -+ __u64 flags; -+ __u64 return_flags; -+ struct kdbus_item items[0]; -+}; -+ </programlisting> -+ -+ <para>The fields in this struct are described below.</para> -+ -+ <variablelist> -+ <varlistentry> -+ <term><varname>size</varname></term> -+ <listitem><para> -+ The overall size of the struct, including its items. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>flags</varname></term> -+ <listitem><para>The flags for creation.</para> -+ <variablelist> -+ <varlistentry> -+ <term><constant>KDBUS_MAKE_ACCESS_GROUP</constant></term> -+ <listitem> -+ <para>Make the bus file group-accessible.</para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_MAKE_ACCESS_WORLD</constant></term> -+ <listitem> -+ <para>Make the bus file world-accessible.</para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_FLAG_NEGOTIATE</constant></term> -+ <listitem> -+ <para> -+ Requests a set of valid flags for this ioctl. When this bit is -+ set, no action is taken; the ioctl will return -+ <errorcode>0</errorcode>, and the <varname>flags</varname> -+ field will have all bits set that are valid for this command. -+ The <constant>KDBUS_FLAG_NEGOTIATE</constant> bit will be -+ cleared by the operation. -+ </para> -+ </listitem> -+ </varlistentry> -+ </variablelist> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>return_flags</varname></term> -+ <listitem><para> -+ Flags returned by the kernel. Currently unused and always set to -+ <constant>0</constant> by the kernel. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>items</varname></term> -+ <listitem> -+ <para> -+ The following items (see -+ <citerefentry> -+ <refentrytitle>kdbus.item</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ ) are expected for <constant>KDBUS_CMD_BUS_MAKE</constant>. -+ </para> -+ <variablelist> -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_MAKE_NAME</constant></term> -+ <listitem> -+ <para> -+ Contains a null-terminated string that identifies the -+ bus. The name must be unique across the kdbus domain and -+ must start with the effective UID of the caller, followed by -+ a '<literal>-</literal>' (dash). This item is mandatory. -+ </para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_BLOOM_PARAMETER</constant></term> -+ <listitem> -+ <para> -+ Bus-wide bloom parameters passed in a -+ <type>struct kdbus_bloom_parameter</type>. These settings are -+ copied back to new connections verbatim. This item is -+ mandatory. See -+ <citerefentry> -+ <refentrytitle>kdbus.item</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for a more detailed description of this item. -+ </para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_ATTACH_FLAGS_RECV</constant></term> -+ <listitem> -+ <para> -+ An optional item that contains a set of required attach flags -+ that connections must allow. This item is used as a -+ negotiation measure during connection creation. If connections -+ do not satisfy the bus requirements, they are not allowed on -+ the bus. If not set, the bus does not require any metadata to -+ be attached; in this case connections are free to set their -+ own attach flags. -+ </para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_ATTACH_FLAGS_SEND</constant></term> -+ <listitem> -+ <para> -+ An optional item that contains a set of attach flags that are -+ returned to connections when they query the bus creator -+ metadata. If not set, no metadata is returned. -+ </para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_NEGOTIATE</constant></term> -+ <listitem><para> -+ With this item, programs can <emphasis>probe</emphasis> the -+ kernel for known item types. See -+ <citerefentry> -+ <refentrytitle>kdbus.item</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more details. -+ </para></listitem> -+ </varlistentry> -+ </variablelist> -+ </listitem> -+ </varlistentry> -+ </variablelist> -+ -+ <para> -+ Unrecognized items are rejected, and the ioctl will fail with -+ <varname>errno</varname> set to <constant>EINVAL</constant>. -+ </para> -+ </refsect1> -+ -+ <refsect1> -+ <title>Return value</title> -+ <para> -+ On success, all mentioned ioctl commands return <errorcode>0</errorcode>; -+ on error, <errorcode>-1</errorcode> is returned, and -+ <varname>errno</varname> is set to indicate the error. -+ If the issued ioctl is illegal for the file descriptor used, -+ <varname>errno</varname> will be set to <constant>ENOTTY</constant>. -+ </para> -+ -+ <refsect2> -+ <title> -+ <constant>KDBUS_CMD_BUS_MAKE</constant> may fail with the following -+ errors -+ </title> -+ -+ <variablelist> -+ <varlistentry> -+ <term><constant>EBADMSG</constant></term> -+ <listitem><para> -+ A mandatory item is missing. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>EINVAL</constant></term> -+ <listitem><para> -+ The flags supplied in the <constant>struct kdbus_cmd</constant> -+ are invalid or the supplied name does not start with the current -+ UID and a '<literal>-</literal>' (dash). -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>EEXIST</constant></term> -+ <listitem><para> -+ A bus of that name already exists. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>ESHUTDOWN</constant></term> -+ <listitem><para> -+ The kdbus mount instance for the bus was already shut down. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>EMFILE</constant></term> -+ <listitem><para> -+ The maximum number of buses for the current user is exhausted. -+ </para></listitem> -+ </varlistentry> -+ </variablelist> -+ </refsect2> -+ </refsect1> -+ -+ <refsect1> -+ <title>See Also</title> -+ <simplelist type="inline"> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.connection</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.endpoint</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.fs</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.item</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.message</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.name</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.pool</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ </simplelist> -+ </refsect1> -+</refentry> -diff --git a/Documentation/kdbus/kdbus.connection.xml b/Documentation/kdbus/kdbus.connection.xml -new file mode 100644 -index 000000000000..09852125b2d4 ---- /dev/null -+++ b/Documentation/kdbus/kdbus.connection.xml -@@ -0,0 +1,1252 @@ -+<?xml version='1.0'?> <!--*-nxml-*--> -+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" -+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> -+ -+<refentry id="kdbus.connection"> -+ -+ <refentryinfo> -+ <title>kdbus.connection</title> -+ <productname>kdbus.connection</productname> -+ </refentryinfo> -+ -+ <refmeta> -+ <refentrytitle>kdbus.connection</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </refmeta> -+ -+ <refnamediv> -+ <refname>kdbus.connection</refname> -+ <refpurpose>kdbus connection</refpurpose> -+ </refnamediv> -+ -+ <refsect1> -+ <title>Description</title> -+ -+ <para> -+ Connections are identified by their <emphasis>connection ID</emphasis>, -+ internally implemented as a <type>uint64_t</type> counter. -+ The IDs of every newly created bus start at <constant>1</constant>, and -+ every new connection will increment the counter by <constant>1</constant>. -+ The IDs are not reused. -+ </para> -+ <para> -+ In higher level tools, the user visible representation of a connection is -+ defined by the D-Bus protocol specification as -+ <constant>":1.<ID>"</constant>. -+ </para> -+ <para> -+ Messages with a specific <type>uint64_t</type> destination ID are -+ directly delivered to the connection with the corresponding ID. Signal -+ messages (see -+ <citerefentry> -+ <refentrytitle>kdbus.message</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry>) -+ may be addressed to the special destination ID -+ <constant>KDBUS_DST_ID_BROADCAST</constant> (~0ULL) and will then -+ potentially be delivered to all currently active connections on the bus. -+ However, in order to receive any signal messages, clients must subscribe -+ to them by installing a match (see -+ <citerefentry> -+ <refentrytitle>kdbus.match</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ ). -+ </para> -+ <para> -+ Messages synthesized and sent directly by the kernel will carry the -+ special source ID <constant>KDBUS_SRC_ID_KERNEL</constant> (0). -+ </para> -+ <para> -+ In addition to the unique <type>uint64_t</type> connection ID, -+ established connections can request the ownership of -+ <emphasis>well-known names</emphasis>, 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 -+ <citerefentry> -+ <refentrytitle>kdbus.name</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ on name acquisition, the name registry, and the validity of names. -+ </para> -+ <para> -+ Messages can specify the special destination ID -+ <constant>KDBUS_DST_ID_NAME</constant> (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. -+ </para> -+ -+ <programlisting><![CDATA[ -+ +-------------------------------------------------------------------------+ -+ | +---------------+ +---------------------------+ | -+ | | 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 | | | | -+ | | | | | | -+ | | | | | | -+ | | | <-----------------------------------+ | | -+ | | | | | -+ | | | <----------------------------------------------+ | -+ | +---------------+ | -+ +-------------------------------------------------------------------------+ -+ ]]></programlisting> -+ </refsect1> -+ -+ <refsect1> -+ <title>Privileged connections</title> -+ <para> -+ A connection is considered <emphasis>privileged</emphasis> if the user -+ it was created by is the same that created the bus, or if the creating -+ task had <constant>CAP_IPC_OWNER</constant> set when it called -+ <constant>KDBUS_CMD_HELLO</constant> (see below). -+ </para> -+ <para> -+ Privileged connections have permission to employ certain restricted -+ functions and commands, which are explained below and in other kdbus -+ man-pages. -+ </para> -+ </refsect1> -+ -+ <refsect1> -+ <title>Activator and policy holder connection</title> -+ <para> -+ An <emphasis>activator</emphasis> connection is a placeholder for a -+ <emphasis>well-known name</emphasis>. Messages sent to such a connection -+ can be used to start an implementer connection, which will then get all -+ the messages from the activator copied over. An activator connection -+ cannot be used to send any message. -+ </para> -+ <para> -+ A <emphasis>policy holder</emphasis> 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. -+ </para> -+ <para> -+ The creation of activator or policy holder connections is restricted to -+ privileged users on the bus (see above). -+ </para> -+ </refsect1> -+ -+ <refsect1> -+ <title>Monitor connections</title> -+ <para> -+ Monitors are eavesdropping connections that receive all the traffic on the -+ bus, but is invisible to other connections. Such connections have all -+ properties of any other, regular connection, except for the following -+ details: -+ </para> -+ -+ <itemizedlist> -+ <listitem><para> -+ They will get every message sent over the bus, both unicasts and -+ broadcasts. -+ </para></listitem> -+ -+ <listitem><para> -+ Installing matches for signal messages is neither necessary -+ nor allowed. -+ </para></listitem> -+ -+ <listitem><para> -+ They cannot send messages or be directly addressed as receiver. -+ </para></listitem> -+ -+ <listitem><para> -+ They cannot own well-known names. Therefore, they also can't operate as -+ activators. -+ </para></listitem> -+ -+ <listitem><para> -+ Their creation and destruction will not cause -+ <constant>KDBUS_ITEM_ID_{ADD,REMOVE}</constant> (see -+ <citerefentry> -+ <refentrytitle>kdbus.item</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry>). -+ </para></listitem> -+ -+ <listitem><para> -+ They are not listed with their unique name in name registry dumps -+ (see <constant>KDBUS_CMD_NAME_LIST</constant> in -+ <citerefentry> -+ <refentrytitle>kdbus.name</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry>), so other connections cannot detect the presence of -+ a monitor. -+ </para></listitem> -+ </itemizedlist> -+ <para> -+ The creation of monitor connections is restricted to privileged users on -+ the bus (see above). -+ </para> -+ </refsect1> -+ -+ <refsect1> -+ <title>Creating connections</title> -+ <para> -+ A connection to a bus is created by opening an endpoint file (see -+ <citerefentry> -+ <refentrytitle>kdbus.endpoint</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry>) -+ of a bus and becoming an active client with the -+ <constant>KDBUS_CMD_HELLO</constant> ioctl. Every 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. -+ </para> -+ <para> -+ The <constant>KDBUS_CMD_HELLO</constant> ioctl takes a <type>struct -+ kdbus_cmd_hello</type> as argument. -+ </para> -+ -+ <programlisting> -+struct kdbus_cmd_hello { -+ __u64 size; -+ __u64 flags; -+ __u64 return_flags; -+ __u64 attach_flags_send; -+ __u64 attach_flags_recv; -+ __u64 bus_flags; -+ __u64 id; -+ __u64 pool_size; -+ __u64 offset; -+ __u8 id128[16]; -+ struct kdbus_item items[0]; -+}; -+ </programlisting> -+ -+ <para>The fields in this struct are described below.</para> -+ -+ <variablelist> -+ <varlistentry> -+ <term><varname>size</varname></term> -+ <listitem><para> -+ The overall size of the struct, including its items. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>flags</varname></term> -+ <listitem> -+ <para>Flags to apply to this connection</para> -+ <variablelist> -+ <varlistentry> -+ <term><constant>KDBUS_HELLO_ACCEPT_FD</constant></term> -+ <listitem> -+ <para> -+ When this flag is set, the connection can be sent file -+ descriptors as message payload of unicast messages. If it's -+ not set, an attempt to send file descriptors will result in -+ <constant>-ECOMM</constant> on the sender's side. -+ </para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_HELLO_ACTIVATOR</constant></term> -+ <listitem> -+ <para> -+ Make this connection an activator (see above). With this bit -+ set, an item of type <constant>KDBUS_ITEM_NAME</constant> has -+ to be attached. This item describes the well-known name this -+ connection should be an activator for. -+ A connection can not be an activator and a policy holder at -+ the same time time, so this bit is not allowed together with -+ <constant>KDBUS_HELLO_POLICY_HOLDER</constant>. -+ </para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_HELLO_POLICY_HOLDER</constant></term> -+ <listitem> -+ <para> -+ Make this connection a policy holder (see above). With this -+ bit set, an item of type <constant>KDBUS_ITEM_NAME</constant> -+ has to be attached. This item describes the well-known name -+ this connection should hold a policy for. -+ A connection can not be an activator and a policy holder at -+ the same time time, so this bit is not allowed together with -+ <constant>KDBUS_HELLO_ACTIVATOR</constant>. -+ </para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_HELLO_MONITOR</constant></term> -+ <listitem> -+ <para> -+ Make this connection a monitor connection (see above). -+ </para> -+ <para> -+ This flag can only be set by privileged bus connections. See -+ below for more information. -+ A connection can not be monitor and an activator or a policy -+ holder at the same time time, so this bit is not allowed -+ together with <constant>KDBUS_HELLO_ACTIVATOR</constant> or -+ <constant>KDBUS_HELLO_POLICY_HOLDER</constant>. -+ </para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_FLAG_NEGOTIATE</constant></term> -+ <listitem> -+ <para> -+ Requests a set of valid flags for this ioctl. When this bit is -+ set, no action is taken; the ioctl will return -+ <errorcode>0</errorcode>, and the <varname>flags</varname> -+ field will have all bits set that are valid for this command. -+ The <constant>KDBUS_FLAG_NEGOTIATE</constant> bit will be -+ cleared by the operation. -+ </para> -+ </listitem> -+ </varlistentry> -+ </variablelist> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>return_flags</varname></term> -+ <listitem><para> -+ Flags returned by the kernel. Currently unused and always set to -+ <constant>0</constant> by the kernel. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>attach_flags_send</varname></term> -+ <listitem><para> -+ 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 be attached -+ to the message. Note, however, that the bus may optionally require -+ some of those bits to be set. If the match fails, the ioctl will fail -+ with <varname>errno</varname> set to -+ <constant>ECONNREFUSED</constant>. In either case, when returning the -+ field will be set to the mask of metadata items that are enforced by -+ the bus with the <constant>KDBUS_FLAGS_KERNEL</constant> bit set as -+ well. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>attach_flags_recv</varname></term> -+ <listitem><para> -+ Request the attachment of metadata for each message received by this -+ connection. See -+ <citerefentry> -+ <refentrytitle>kdbus</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for information about metadata, and -+ <citerefentry> -+ <refentrytitle>kdbus.item</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ regarding items in general. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>bus_flags</varname></term> -+ <listitem><para> -+ Upon successful completion of the ioctl, this member will contain the -+ flags of the bus it connected to. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>id</varname></term> -+ <listitem><para> -+ Upon successful completion of the command, this member will contain -+ the numerical ID of the new connection. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>pool_size</varname></term> -+ <listitem><para> -+ The size of the communication pool, in bytes. The pool can be -+ accessed by calling -+ <citerefentry> -+ <refentrytitle>mmap</refentrytitle> -+ <manvolnum>2</manvolnum> -+ </citerefentry> -+ on the file descriptor that was used to issue the -+ <constant>KDBUS_CMD_HELLO</constant> ioctl. -+ The pool size of a connection must be greater than -+ <constant>0</constant> and a multiple of -+ <constant>PAGE_SIZE</constant>. See -+ <citerefentry> -+ <refentrytitle>kdbus.pool</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more information. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>offset</varname></term> -+ <listitem><para> -+ The kernel will return the offset in the pool where returned details -+ will be stored. See below. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>id128</varname></term> -+ <listitem><para> -+ Upon successful completion of the ioctl, this member will contain the -+ <emphasis>128-bit UUID</emphasis> of the connected bus. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>items</varname></term> -+ <listitem> -+ <para> -+ Variable list of items containing optional additional information. -+ The following items are currently expected/valid: -+ </para> -+ <variablelist> -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_CONN_DESCRIPTION</constant></term> -+ <listitem> -+ <para> -+ Contains a string that describes this connection, so it can -+ be identified later. -+ </para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_NAME</constant></term> -+ <term><constant>KDBUS_ITEM_POLICY_ACCESS</constant></term> -+ <listitem> -+ <para> -+ For activators and policy holders only, combinations of -+ these two items describe policy access entries. See -+ <citerefentry> -+ <refentrytitle>kdbus.policy</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for further details. -+ </para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_CREDS</constant></term> -+ <term><constant>KDBUS_ITEM_PIDS</constant></term> -+ <term><constant>KDBUS_ITEM_SECLABEL</constant></term> -+ <listitem> -+ <para> -+ Privileged bus users may submit these types in order to -+ create connections with faked credentials. This information -+ will be returned when peer information is queried by -+ <constant>KDBUS_CMD_CONN_INFO</constant>. See below for more -+ information on retrieving information on connections. -+ </para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_NEGOTIATE</constant></term> -+ <listitem><para> -+ With this item, programs can <emphasis>probe</emphasis> the -+ kernel for known item types. See -+ <citerefentry> -+ <refentrytitle>kdbus.item</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more details. -+ </para></listitem> -+ </varlistentry> -+ </variablelist> -+ -+ <para> -+ Unrecognized items are rejected, and the ioctl will fail with -+ <varname>errno</varname> set to <constant>EINVAL</constant>. -+ </para> -+ </listitem> -+ </varlistentry> -+ </variablelist> -+ -+ <para> -+ At the offset returned in the <varname>offset</varname> field of -+ <type>struct kdbus_cmd_hello</type>, the kernel will store items -+ of the following types: -+ </para> -+ -+ <variablelist> -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_BLOOM_PARAMETER</constant></term> -+ <listitem> -+ <para> -+ Bloom filter parameter as defined by the bus creator. -+ </para> -+ </listitem> -+ </varlistentry> -+ </variablelist> -+ -+ <para> -+ The offset in the pool has to be freed with the -+ <constant>KDBUS_CMD_FREE</constant> ioctl. See -+ <citerefentry> -+ <refentrytitle>kdbus.pool</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for further information. -+ </para> -+ </refsect1> -+ -+ <refsect1> -+ <title>Retrieving information on a connection</title> -+ <para> -+ The <constant>KDBUS_CMD_CONN_INFO</constant> ioctl can be used to -+ retrieve credentials and properties of the initial creator of a -+ connection. This ioctl uses the following struct. -+ </para> -+ -+ <programlisting> -+struct kdbus_cmd_info { -+ __u64 size; -+ __u64 flags; -+ __u64 return_flags; -+ __u64 id; -+ __u64 attach_flags; -+ __u64 offset; -+ __u64 info_size; -+ struct kdbus_item items[0]; -+}; -+ </programlisting> -+ -+ <variablelist> -+ <varlistentry> -+ <term><varname>size</varname></term> -+ <listitem><para> -+ The overall size of the struct, including its items. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>flags</varname></term> -+ <listitem><para> -+ Currently, no flags are supported. -+ <constant>KDBUS_FLAG_NEGOTIATE</constant> is accepted to probe for -+ valid flags. If set, the ioctl will return <errorcode>0</errorcode>, -+ and the <varname>flags</varname> field is set to -+ <constant>0</constant>. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>return_flags</varname></term> -+ <listitem><para> -+ Flags returned by the kernel. Currently unused and always set to -+ <constant>0</constant> by the kernel. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>id</varname></term> -+ <listitem><para> -+ The numerical ID of the connection for which information is to be -+ retrieved. If set to a non-zero value, the -+ <constant>KDBUS_ITEM_OWNED_NAME</constant> item is ignored. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>flags</varname></term> -+ <listitem><para> -+ Specifies which metadata items should be attached to the answer. See -+ <citerefentry> -+ <refentrytitle>kdbus.message</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>offset</varname></term> -+ <listitem><para> -+ When the ioctl returns, this field will contain the offset of the -+ connection information inside the caller's pool. See -+ <citerefentry> -+ <refentrytitle>kdbus.pool</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for further information. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>info_size</varname></term> -+ <listitem><para> -+ The kernel will return the size of the returned information, so -+ applications can optionally -+ <citerefentry> -+ <refentrytitle>mmap</refentrytitle> -+ <manvolnum>2</manvolnum> -+ </citerefentry> -+ specific parts of the pool. See -+ <citerefentry> -+ <refentrytitle>kdbus.pool</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for further information. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>items</varname></term> -+ <listitem> -+ <para> -+ The following items are expected for -+ <constant>KDBUS_CMD_CONN_INFO</constant>. -+ </para> -+ <variablelist> -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_OWNED_NAME</constant></term> -+ <listitem> -+ <para> -+ Contains the well-known name of the connection to look up as. -+ This item is mandatory if the <varname>id</varname> field is -+ set to 0. -+ </para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_NEGOTIATE</constant></term> -+ <listitem><para> -+ With this item, programs can <emphasis>probe</emphasis> the -+ kernel for known item types. See -+ <citerefentry> -+ <refentrytitle>kdbus.item</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more details. -+ </para></listitem> -+ </varlistentry> -+ </variablelist> -+ <para> -+ Unrecognized items are rejected, and the ioctl will fail with -+ <varname>errno</varname> set to <constant>EINVAL</constant>. -+ </para> -+ </listitem> -+ </varlistentry> -+ </variablelist> -+ -+ <para> -+ When the ioctl returns, the following struct will be stored in the -+ caller's pool at <varname>offset</varname>. The fields in this struct -+ are described below. -+ </para> -+ -+ <programlisting> -+struct kdbus_info { -+ __u64 size; -+ __u64 id; -+ __u64 flags; -+ struct kdbus_item items[0]; -+}; -+ </programlisting> -+ -+ <variablelist> -+ <varlistentry> -+ <term><varname>size</varname></term> -+ <listitem><para> -+ The overall size of the struct, including its items. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>id</varname></term> -+ <listitem><para> -+ The connection's unique ID. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>flags</varname></term> -+ <listitem><para> -+ The connection's flags as specified when it was created. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>items</varname></term> -+ <listitem> -+ <para> -+ Depending on the <varname>flags</varname> field in -+ <type>struct kdbus_cmd_info</type>, items of types -+ <constant>KDBUS_ITEM_OWNED_NAME</constant> and -+ <constant>KDBUS_ITEM_CONN_DESCRIPTION</constant> may follow here. -+ <constant>KDBUS_ITEM_NEGOTIATE</constant> is also allowed. -+ </para> -+ </listitem> -+ </varlistentry> -+ </variablelist> -+ -+ <para> -+ Once the caller is finished with parsing the return buffer, it needs to -+ employ the <constant>KDBUS_CMD_FREE</constant> command for the offset, in -+ order to free the buffer part. See -+ <citerefentry> -+ <refentrytitle>kdbus.pool</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for further information. -+ </para> -+ </refsect1> -+ -+ <refsect1> -+ <title>Getting information about a connection's bus creator</title> -+ <para> -+ The <constant>KDBUS_CMD_BUS_CREATOR_INFO</constant> ioctl takes the same -+ struct as <constant>KDBUS_CMD_CONN_INFO</constant>, 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. -+ </para> -+ <para> -+ In response to this call, a slice in the connection's pool is allocated -+ and filled with an object of type <type>struct kdbus_info</type>, -+ pointed to by the ioctl's <varname>offset</varname> field. -+ </para> -+ -+ <programlisting> -+struct kdbus_info { -+ __u64 size; -+ __u64 id; -+ __u64 flags; -+ struct kdbus_item items[0]; -+}; -+ </programlisting> -+ -+ <variablelist> -+ <varlistentry> -+ <term><varname>size</varname></term> -+ <listitem><para> -+ The overall size of the struct, including its items. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>id</varname></term> -+ <listitem><para> -+ The bus ID. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>flags</varname></term> -+ <listitem><para> -+ The bus flags as specified when it was created. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>items</varname></term> -+ <listitem> -+ <para> -+ Metadata information is stored in items here. The item list -+ contains a <constant>KDBUS_ITEM_MAKE_NAME</constant> item that -+ indicates the bus name of the calling connection. -+ <constant>KDBUS_ITEM_NEGOTIATE</constant> is allowed to probe -+ for known item types. -+ </para> -+ </listitem> -+ </varlistentry> -+ </variablelist> -+ -+ <para> -+ Once the caller is finished with parsing the return buffer, it needs to -+ employ the <constant>KDBUS_CMD_FREE</constant> command for the offset, in -+ order to free the buffer part. See -+ <citerefentry> -+ <refentrytitle>kdbus.pool</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for further information. -+ </para> -+ </refsect1> -+ -+ <refsect1> -+ <title>Updating connection details</title> -+ <para> -+ Some of a connection's details can be updated with the -+ <constant>KDBUS_CMD_CONN_UPDATE</constant> ioctl, using the file -+ descriptor that was used to create the connection. The update command -+ uses the following struct. -+ </para> -+ -+ <programlisting> -+struct kdbus_cmd { -+ __u64 size; -+ __u64 flags; -+ __u64 return_flags; -+ struct kdbus_item items[0]; -+}; -+ </programlisting> -+ -+ <variablelist> -+ <varlistentry> -+ <term><varname>size</varname></term> -+ <listitem><para> -+ The overall size of the struct, including its items. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>flags</varname></term> -+ <listitem><para> -+ Currently, no flags are supported. -+ <constant>KDBUS_FLAG_NEGOTIATE</constant> is accepted to probe for -+ valid flags. If set, the ioctl will return <errorcode>0</errorcode>, -+ and the <varname>flags</varname> field is set to -+ <constant>0</constant>. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>return_flags</varname></term> -+ <listitem><para> -+ Flags returned by the kernel. Currently unused and always set to -+ <constant>0</constant> by the kernel. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>items</varname></term> -+ <listitem> -+ <para> -+ Items to describe the connection details to be updated. The -+ following item types are supported. -+ </para> -+ <variablelist> -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_ATTACH_FLAGS_SEND</constant></term> -+ <listitem> -+ <para> -+ Supply a new set of metadata items that this connection -+ permits to be sent along with messages. -+ </para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_ATTACH_FLAGS_RECV</constant></term> -+ <listitem> -+ <para> -+ Supply a new set of metadata items that this connection -+ requests to be attached to each message. -+ </para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_NAME</constant></term> -+ <term><constant>KDBUS_ITEM_POLICY_ACCESS</constant></term> -+ <listitem> -+ <para> -+ Policy holder connections may supply a new set of policy -+ information with these items. For other connection types, -+ <constant>EOPNOTSUPP</constant> is returned in -+ <varname>errno</varname>. -+ </para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_NEGOTIATE</constant></term> -+ <listitem><para> -+ With this item, programs can <emphasis>probe</emphasis> the -+ kernel for known item types. See -+ <citerefentry> -+ <refentrytitle>kdbus.item</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more details. -+ </para></listitem> -+ </varlistentry> -+ </variablelist> -+ -+ <para> -+ Unrecognized items are rejected, and the ioctl will fail with -+ <varname>errno</varname> set to <constant>EINVAL</constant>. -+ </para> -+ </listitem> -+ </varlistentry> -+ </variablelist> -+ </refsect1> -+ -+ <refsect1> -+ <title>Termination of connections</title> -+ <para> -+ A connection can be terminated by simply calling -+ <citerefentry> -+ <refentrytitle>close</refentrytitle> -+ <manvolnum>2</manvolnum> -+ </citerefentry> -+ on its file descriptor. All pending incoming messages will be discarded, -+ and the memory allocated by the pool will be freed. -+ </para> -+ -+ <para> -+ An alternative way of closing down a connection is via the -+ <constant>KDBUS_CMD_BYEBYE</constant> ioctl. This ioctl will succeed only -+ if the message queue of the connection is empty at the time of closing; -+ otherwise, the ioctl will fail with <varname>errno</varname> set to -+ <constant>EBUSY</constant>. 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. The ioctl takes an argument of -+ type <type>struct kdbus_cmd</type>. -+ </para> -+ -+ <programlisting> -+struct kdbus_cmd { -+ __u64 size; -+ __u64 flags; -+ __u64 return_flags; -+ struct kdbus_item items[0]; -+}; -+ </programlisting> -+ -+ <variablelist> -+ <varlistentry> -+ <term><varname>size</varname></term> -+ <listitem><para> -+ The overall size of the struct, including its items. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>flags</varname></term> -+ <listitem><para> -+ Currently, no flags are supported. -+ <constant>KDBUS_FLAG_NEGOTIATE</constant> is accepted to probe for -+ valid flags. If set, the ioctl will fail with -+ <varname>errno</varname> set to <constant>EPROTO</constant>, and -+ the <varname>flags</varname> field is set to <constant>0</constant>. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>return_flags</varname></term> -+ <listitem><para> -+ Flags returned by the kernel. Currently unused and always set to -+ <constant>0</constant> by the kernel. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>items</varname></term> -+ <listitem> -+ <para> -+ Items to describe the connection details to be updated. The -+ following item types are supported. -+ </para> -+ <variablelist> -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_NEGOTIATE</constant></term> -+ <listitem><para> -+ With this item, programs can <emphasis>probe</emphasis> the -+ kernel for known item types. See -+ <citerefentry> -+ <refentrytitle>kdbus.item</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more details. -+ </para></listitem> -+ </varlistentry> -+ </variablelist> -+ -+ <para> -+ Unrecognized items are rejected, and the ioctl will fail with -+ <varname>errno</varname> set to <constant>EINVAL</constant>. -+ </para> -+ </listitem> -+ </varlistentry> -+ </variablelist> -+ </refsect1> -+ -+ <refsect1> -+ <title>Return value</title> -+ <para> -+ On success, all mentioned ioctl commands return <errorcode>0</errorcode>; -+ on error, <errorcode>-1</errorcode> is returned, and -+ <varname>errno</varname> is set to indicate the error. -+ If the issued ioctl is illegal for the file descriptor used, -+ <varname>errno</varname> will be set to <constant>ENOTTY</constant>. -+ </para> -+ -+ <refsect2> -+ <title> -+ <constant>KDBUS_CMD_HELLO</constant> may fail with the following -+ errors -+ </title> -+ -+ <variablelist> -+ <varlistentry> -+ <term><constant>EFAULT</constant></term> -+ <listitem><para> -+ The supplied pool size was 0 or not a multiple of the page size. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>EINVAL</constant></term> -+ <listitem><para> -+ The flags supplied in <type>struct kdbus_cmd_hello</type> -+ are invalid. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>EINVAL</constant></term> -+ <listitem><para> -+ An illegal combination of -+ <constant>KDBUS_HELLO_MONITOR</constant>, -+ <constant>KDBUS_HELLO_ACTIVATOR</constant> and -+ <constant>KDBUS_HELLO_POLICY_HOLDER</constant> was passed in -+ <varname>flags</varname>. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>EINVAL</constant></term> -+ <listitem><para> -+ An invalid set of items was supplied. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>ECONNREFUSED</constant></term> -+ <listitem><para> -+ The attach_flags_send field did not satisfy the requirements of -+ the bus. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>EPERM</constant></term> -+ <listitem><para> -+ A <constant>KDBUS_ITEM_CREDS</constant> items was supplied, but the -+ current user is not privileged. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>ESHUTDOWN</constant></term> -+ <listitem><para> -+ The bus you were trying to connect to has already been shut down. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>EMFILE</constant></term> -+ <listitem><para> -+ The maximum number of connections on the bus has been reached. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>EOPNOTSUPP</constant></term> -+ <listitem><para> -+ The endpoint does not support the connection flags supplied in -+ <type>struct kdbus_cmd_hello</type>. -+ </para></listitem> -+ </varlistentry> -+ </variablelist> -+ </refsect2> -+ -+ <refsect2> -+ <title> -+ <constant>KDBUS_CMD_BYEBYE</constant> may fail with the following -+ errors -+ </title> -+ -+ <variablelist> -+ <varlistentry> -+ <term><constant>EALREADY</constant></term> -+ <listitem><para> -+ The connection has already been shut down. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>EBUSY</constant></term> -+ <listitem><para> -+ There are still messages queued up in the connection's pool. -+ </para></listitem> -+ </varlistentry> -+ </variablelist> -+ </refsect2> -+ -+ <refsect2> -+ <title> -+ <constant>KDBUS_CMD_CONN_INFO</constant> may fail with the following -+ errors -+ </title> -+ -+ <variablelist> -+ <varlistentry> -+ <term><constant>EINVAL</constant></term> -+ <listitem><para> -+ Invalid flags, or neither an ID nor a name was provided, or the -+ name is invalid. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>ESRCH</constant></term> -+ <listitem><para> -+ Connection lookup by name failed. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>ENXIO</constant></term> -+ <listitem><para> -+ No connection with the provided connection ID found. -+ </para></listitem> -+ </varlistentry> -+ </variablelist> -+ </refsect2> -+ -+ <refsect2> -+ <title> -+ <constant>KDBUS_CMD_CONN_UPDATE</constant> may fail with the following -+ errors -+ </title> -+ -+ <variablelist> -+ <varlistentry> -+ <term><constant>EINVAL</constant></term> -+ <listitem><para> -+ Illegal flags or items. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>EINVAL</constant></term> -+ <listitem><para> -+ Wildcards submitted in policy entries, or illegal sequence -+ of policy items. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>EOPNOTSUPP</constant></term> -+ <listitem><para> -+ Operation not supported by connection. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>E2BIG</constant></term> -+ <listitem><para> -+ Too many policy items attached. -+ </para></listitem> -+ </varlistentry> -+ </variablelist> -+ </refsect2> -+ </refsect1> -+ -+ <refsect1> -+ <title>See Also</title> -+ <simplelist type="inline"> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.bus</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.endpoint</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.message</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.name</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.policy</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.pool</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.item</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ </simplelist> -+ </refsect1> -+</refentry> -diff --git a/Documentation/kdbus/kdbus.endpoint.xml b/Documentation/kdbus/kdbus.endpoint.xml -new file mode 100644 -index 000000000000..76e325d4e931 ---- /dev/null -+++ b/Documentation/kdbus/kdbus.endpoint.xml -@@ -0,0 +1,436 @@ -+<?xml version='1.0'?> <!--*-nxml-*--> -+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" -+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> -+ -+<refentry id="kdbus.endpoint"> -+ -+ <refentryinfo> -+ <title>kdbus.endpoint</title> -+ <productname>kdbus.endpoint</productname> -+ </refentryinfo> -+ -+ <refmeta> -+ <refentrytitle>kdbus.endpoint</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </refmeta> -+ -+ <refnamediv> -+ <refname>kdbus.endpoint</refname> -+ <refpurpose>kdbus endpoint</refpurpose> -+ </refnamediv> -+ -+ <refsect1> -+ <title>Description</title> -+ -+ <para> -+ Endpoints are entry points to a bus (see -+ <citerefentry> -+ <refentrytitle>kdbus.bus</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry>). -+ 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). An endpoint is presented as file underneath the directory -+ of the parent bus. -+ </para> -+ <para> -+ To create a custom endpoint, open the default endpoint -+ (<literal>bus</literal>) and use the -+ <constant>KDBUS_CMD_ENDPOINT_MAKE</constant> ioctl with -+ <type>struct kdbus_cmd</type>. Custom endpoints always have a policy -+ database that, by default, forbids any operation. You have to explicitly -+ install policy entries to allow any operation on this endpoint. -+ </para> -+ <para> -+ Once <constant>KDBUS_CMD_ENDPOINT_MAKE</constant> succeeded, the new -+ endpoint will appear in the filesystem -+ (<citerefentry> -+ <refentrytitle>kdbus.bus</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry>), and the used file descriptor will manage the -+ newly created endpoint resource. It cannot be used to manage further -+ resources and must be kept open as long as the endpoint is needed. The -+ endpoint will be terminated as soon as the file descriptor is closed. -+ </para> -+ <para> -+ Endpoint names may be chosen freely except for one restriction: the name -+ must be prefixed with the numeric effective UID of the creator and a dash. -+ This is required to avoid namespace clashes between different users. When -+ creating an endpoint, the name that is passed in must be properly -+ formatted or the kernel will refuse creation of the endpoint. Example: -+ <literal>1047-my-endpoint</literal> is an acceptable name for an -+ endpoint registered by a user with UID 1047. However, -+ <literal>1024-my-endpoint</literal> is not, and neither is -+ <literal>my-endpoint</literal>. The UID must be provided in the -+ user-namespace of the bus. -+ </para> -+ <para> -+ To create connections to a bus, use <constant>KDBUS_CMD_HELLO</constant> -+ on a file descriptor returned by <function>open()</function> on an -+ endpoint node. See -+ <citerefentry> -+ <refentrytitle>kdbus.connection</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for further details. -+ </para> -+ </refsect1> -+ -+ <refsect1> -+ <title>Creating custom endpoints</title> -+ <para> -+ To create a new endpoint, the -+ <constant>KDBUS_CMD_ENDPOINT_MAKE</constant> command is used. Along with -+ the endpoint's name, which will be used to expose the endpoint in the -+ <citerefentry> -+ <refentrytitle>kdbus.fs</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry>, -+ the command also optionally takes items to set up the endpoint's -+ <citerefentry> -+ <refentrytitle>kdbus.policy</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry>. -+ <constant>KDBUS_CMD_ENDPOINT_MAKE</constant> takes a -+ <type>struct kdbus_cmd</type> argument. -+ </para> -+ <programlisting> -+struct kdbus_cmd { -+ __u64 size; -+ __u64 flags; -+ __u64 return_flags; -+ struct kdbus_item items[0]; -+}; -+ </programlisting> -+ -+ <para>The fields in this struct are described below.</para> -+ -+ <variablelist> -+ <varlistentry> -+ <term><varname>size</varname></term> -+ <listitem><para> -+ The overall size of the struct, including its items. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>flags</varname></term> -+ <listitem><para>The flags for creation.</para> -+ <variablelist> -+ <varlistentry> -+ <term><constant>KDBUS_MAKE_ACCESS_GROUP</constant></term> -+ <listitem> -+ <para>Make the endpoint file group-accessible.</para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_MAKE_ACCESS_WORLD</constant></term> -+ <listitem> -+ <para>Make the endpoint file world-accessible.</para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_FLAG_NEGOTIATE</constant></term> -+ <listitem> -+ <para> -+ Requests a set of valid flags for this ioctl. When this bit is -+ set, no action is taken; the ioctl will return -+ <errorcode>0</errorcode>, and the <varname>flags</varname> -+ field will have all bits set that are valid for this command. -+ The <constant>KDBUS_FLAG_NEGOTIATE</constant> bit will be -+ cleared by the operation. -+ </para> -+ </listitem> -+ </varlistentry> -+ </variablelist> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>return_flags</varname></term> -+ <listitem><para> -+ Flags returned by the kernel. Currently unused and always set to -+ <constant>0</constant> by the kernel. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>items</varname></term> -+ <listitem> -+ <para> -+ The following items are expected for -+ <constant>KDBUS_CMD_ENDPOINT_MAKE</constant>. -+ </para> -+ <variablelist> -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_MAKE_NAME</constant></term> -+ <listitem> -+ <para>Contains a string to identify the endpoint name.</para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_NAME</constant></term> -+ <term><constant>KDBUS_ITEM_POLICY_ACCESS</constant></term> -+ <listitem> -+ <para> -+ These items are used to set the policy attached to the -+ endpoint. For more details on bus and endpoint policies, see -+ <citerefentry> -+ <refentrytitle>kdbus.policy</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry>. -+ </para> -+ </listitem> -+ </varlistentry> -+ </variablelist> -+ <para> -+ Unrecognized items are rejected, and the ioctl will fail with -+ <varname>errno</varname> set to <varname>EINVAL</varname>. -+ </para> -+ </listitem> -+ </varlistentry> -+ </variablelist> -+ </refsect1> -+ -+ <refsect1> -+ <title>Updating endpoints</title> -+ <para> -+ To update an existing endpoint, the -+ <constant>KDBUS_CMD_ENDPOINT_UPDATE</constant> command is used on the file -+ descriptor that was used to create the update, using -+ <constant>KDBUS_CMD_ENDPOINT_MAKE</constant>. The only relevant detail of -+ the endpoint that can be updated is the policy. When the command is -+ employed, the policy of the endpoint is <emphasis>replaced</emphasis> -+ atomically with the new set of rules. -+ The command takes a <type>struct kdbus_cmd</type> argument. -+ </para> -+ <programlisting> -+struct kdbus_cmd { -+ __u64 size; -+ __u64 flags; -+ __u64 return_flags; -+ struct kdbus_item items[0]; -+}; -+ </programlisting> -+ -+ <para>The fields in this struct are described below.</para> -+ -+ <variablelist> -+ <varlistentry> -+ <term><varname>size</varname></term> -+ <listitem><para> -+ The overall size of the struct, including its items. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>flags</varname></term> -+ <listitem><para> -+ Unused for this command. -+ <constant>KDBUS_FLAG_NEGOTIATE</constant> is accepted to probe for -+ valid flags. If set, the ioctl will return <errorcode>0</errorcode>, -+ and the <varname>flags</varname> field is set to -+ <constant>0</constant>. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>return_flags</varname></term> -+ <listitem><para> -+ Flags returned by the kernel. Currently unused and always set to -+ <constant>0</constant> by the kernel. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>items</varname></term> -+ <listitem> -+ <para> -+ The following items are expected for -+ <constant>KDBUS_CMD_ENDPOINT_UPDATE</constant>. -+ </para> -+ <variablelist> -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_NAME</constant></term> -+ <term><constant>KDBUS_ITEM_POLICY_ACCESS</constant></term> -+ <listitem> -+ <para> -+ These items are used to set the policy attached to the -+ endpoint. For more details on bus and endpoint policies, see -+ <citerefentry> -+ <refentrytitle>kdbus.policy</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry>. -+ Existing policy is atomically replaced with the new rules -+ provided. -+ </para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_NEGOTIATE</constant></term> -+ <listitem><para> -+ With this item, programs can <emphasis>probe</emphasis> the -+ kernel for known item types. See -+ <citerefentry> -+ <refentrytitle>kdbus.item</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more details. -+ </para></listitem> -+ </varlistentry> -+ </variablelist> -+ <para> -+ Unrecognized items are rejected, and the ioctl will fail with -+ <varname>errno</varname> set to <constant>EINVAL</constant>. -+ </para> -+ </listitem> -+ </varlistentry> -+ </variablelist> -+ </refsect1> -+ -+ <refsect1> -+ <title>Return value</title> -+ <para> -+ On success, all mentioned ioctl commands return <errorcode>0</errorcode>; -+ on error, <errorcode>-1</errorcode> is returned, and -+ <varname>errno</varname> is set to indicate the error. -+ If the issued ioctl is illegal for the file descriptor used, -+ <varname>errno</varname> will be set to <constant>ENOTTY</constant>. -+ </para> -+ -+ <refsect2> -+ <title> -+ <constant>KDBUS_CMD_ENDPOINT_MAKE</constant> may fail with the -+ following errors -+ </title> -+ -+ <variablelist> -+ <varlistentry> -+ <term><constant>EINVAL</constant></term> -+ <listitem><para> -+ The flags supplied in the <type>struct kdbus_cmd</type> -+ are invalid. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>EINVAL</constant></term> -+ <listitem><para> -+ Illegal combination of <constant>KDBUS_ITEM_NAME</constant> and -+ <constant>KDBUS_ITEM_POLICY_ACCESS</constant> was provided. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>EEXIST</constant></term> -+ <listitem><para> -+ An endpoint of that name already exists. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>EPERM</constant></term> -+ <listitem><para> -+ The calling user is not privileged. See -+ <citerefentry> -+ <refentrytitle>kdbus</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for information about privileged users. -+ </para></listitem> -+ </varlistentry> -+ </variablelist> -+ </refsect2> -+ -+ <refsect2> -+ <title> -+ <constant>KDBUS_CMD_ENDPOINT_UPDATE</constant> may fail with the -+ following errors -+ </title> -+ -+ <variablelist> -+ <varlistentry> -+ <term><constant>EINVAL</constant></term> -+ <listitem><para> -+ The flags supplied in <type>struct kdbus_cmd</type> -+ are invalid. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>EINVAL</constant></term> -+ <listitem><para> -+ Illegal combination of <constant>KDBUS_ITEM_NAME</constant> and -+ <constant>KDBUS_ITEM_POLICY_ACCESS</constant> was provided. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>EEXIST</constant></term> -+ <listitem><para> -+ An endpoint of that name already exists. -+ </para></listitem> -+ </varlistentry> -+ </variablelist> -+ </refsect2> -+ </refsect1> -+ -+ <refsect1> -+ <title>See Also</title> -+ <simplelist type="inline"> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.bus</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.endpoint</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.fs</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.item</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.message</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.name</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.pool</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ </simplelist> -+ </refsect1> -+</refentry> -diff --git a/Documentation/kdbus/kdbus.fs.xml b/Documentation/kdbus/kdbus.fs.xml -new file mode 100644 -index 000000000000..8c2a90e10b66 ---- /dev/null -+++ b/Documentation/kdbus/kdbus.fs.xml -@@ -0,0 +1,124 @@ -+<?xml version='1.0'?> <!--*-nxml-*--> -+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" -+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> -+ -+<refentry id="kdbus_fs"> -+ -+ <refentryinfo> -+ <title>kdbus.fs</title> -+ <productname>kdbus.fs</productname> -+ </refentryinfo> -+ -+ <refmeta> -+ <refentrytitle>kdbus.fs</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </refmeta> -+ -+ <refnamediv> -+ <refname>kdbus.fs</refname> -+ <refpurpose>kdbus file system</refpurpose> -+ </refnamediv> -+ -+ <refsect1> -+ <title>File-system Layout</title> -+ -+ <para> -+ The <emphasis>kdbusfs</emphasis> pseudo filesystem provides access to -+ kdbus entities, such as <emphasis>buses</emphasis> and -+ <emphasis>endpoints</emphasis>. Each time the filesystem is mounted, -+ a new, isolated kdbus instance is created, which is independent from the -+ other instances. -+ </para> -+ <para> -+ The system-wide standard mount point for <emphasis>kdbusfs</emphasis> is -+ <constant>/sys/fs/kdbus</constant>. -+ </para> -+ -+ <para> -+ Buses are represented as directories in the file system layout, whereas -+ endpoints are exposed as files inside these directories. At the top-level, -+ a <emphasis>control</emphasis> node is present, which can be opened to -+ create new buses via the <constant>KDBUS_CMD_BUS_MAKE</constant> ioctl. -+ Each <emphasis>bus</emphasis> shows a default endpoint called -+ <varname>bus</varname>, which can be opened to either create a connection -+ with the <constant>KDBUS_CMD_HELLO</constant> ioctl, or to create new -+ custom endpoints for the bus with -+ <constant>KDBUS_CMD_ENDPOINT_MAKE</constant>. See -+ <citerefentry> -+ <refentrytitle>kdbus.bus</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry>, -+ <citerefentry> -+ <refentrytitle>kdbus.connection</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> and -+ <citerefentry> -+ <refentrytitle>kdbus.endpoint</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more details. -+ </para> -+ -+ <para>Following, you can see an example layout of the -+ <emphasis>kdbusfs</emphasis> filesystem:</para> -+ -+<programlisting> -+ /sys/fs/kdbus/ ; mount-point -+ |-- 0-system ; bus directory -+ | |-- bus ; default endpoint -+ | `-- 1017-custom ; custom endpoint -+ |-- 1000-user ; bus directory -+ | |-- bus ; default endpoint -+ | |-- 1000-service-A ; custom endpoint -+ | `-- 1000-service-B ; custom endpoint -+ `-- control ; control file -+</programlisting> -+ </refsect1> -+ -+ <refsect1> -+ <title>Mounting instances</title> -+ <para> -+ In order to get a new and separate kdbus environment, a new instance -+ of <emphasis>kdbusfs</emphasis> can be mounted like this: -+ </para> -+<programlisting> -+ # mount -t kdbusfs kdbusfs /tmp/new_kdbus/ -+</programlisting> -+ </refsect1> -+ -+ <refsect1> -+ <title>See Also</title> -+ <simplelist type="inline"> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.bus</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.connection</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.endpoint</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>mount</refentrytitle> -+ <manvolnum>8</manvolnum> -+ </citerefentry> -+ </member> -+ </simplelist> -+ </refsect1> -+</refentry> -diff --git a/Documentation/kdbus/kdbus.item.xml b/Documentation/kdbus/kdbus.item.xml -new file mode 100644 -index 000000000000..bfe47362097f ---- /dev/null -+++ b/Documentation/kdbus/kdbus.item.xml -@@ -0,0 +1,840 @@ -+<?xml version='1.0'?> <!--*-nxml-*--> -+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" -+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> -+ -+<refentry id="kdbus"> -+ -+ <refentryinfo> -+ <title>kdbus.item</title> -+ <productname>kdbus item</productname> -+ </refentryinfo> -+ -+ <refmeta> -+ <refentrytitle>kdbus.item</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </refmeta> -+ -+ <refnamediv> -+ <refname>kdbus.item</refname> -+ <refpurpose>kdbus item structure, layout and usage</refpurpose> -+ </refnamediv> -+ -+ <refsect1> -+ <title>Description</title> -+ -+ <para> -+ To flexibly augment transport structures, data blobs of type -+ <type>struct kdbus_item</type> can be attached to the structs passed -+ into the ioctls. Some ioctls make items of certain types mandatory, -+ others are optional. Items that are unsupported by ioctls they are -+ attached to will cause the ioctl to fail with <varname>errno</varname> -+ set to <constant>EINVAL</constant>. -+ Items are also used for information stored in a connection's -+ <emphasis>pool</emphasis>, such as received messages, name lists or -+ requested connection or bus owner information. Depending on the type of -+ an item, its total size is either fixed or variable. -+ </para> -+ -+ <refsect2> -+ <title>Chaining items</title> -+ <para> -+ Whenever items are used as part of the kdbus kernel API, they are -+ embedded in structs that are embedded inside structs that themselves -+ include a size field containing the overall size of the structure. -+ This allows multiple items to be chained up, and an item iterator -+ (see below) is capable of detecting the end of an item chain. -+ </para> -+ </refsect2> -+ -+ <refsect2> -+ <title>Alignment</title> -+ <para> -+ The kernel expects all items to be aligned to 8-byte boundaries. -+ Unaligned items will cause the ioctl they are used with to fail -+ with <varname>errno</varname> set to <constant>EINVAL</constant>. -+ An item that has an unaligned size itself hence needs to be padded -+ if it is followed by another item. -+ </para> -+ </refsect2> -+ -+ <refsect2> -+ <title>Iterating items</title> -+ <para> -+ A simple iterator would iterate over the items until the items have -+ reached the embedding structure's overall size. An example -+ implementation is shown below. -+ </para> -+ -+ <programlisting><![CDATA[ -+#define KDBUS_ALIGN8(val) (((val) + 7) & ~7) -+ -+#define KDBUS_ITEM_NEXT(item) \ -+ (typeof(item))(((uint8_t *)item) + KDBUS_ALIGN8((item)->size)) -+ -+#define KDBUS_ITEM_FOREACH(item, head, first) \ -+ for (item = (head)->first; \ -+ ((uint8_t *)(item) < (uint8_t *)(head) + (head)->size) && \ -+ ((uint8_t *)(item) >= (uint8_t *)(head)); \ -+ item = KDBUS_ITEM_NEXT(item)) -+ ]]></programlisting> -+ </refsect2> -+ </refsect1> -+ -+ <refsect1> -+ <title>Item layout</title> -+ <para> -+ A <type>struct kdbus_item</type> consists of a -+ <varname>size</varname> field, describing its overall size, and a -+ <varname>type</varname> field, both 64 bit wide. They are followed by -+ a union to store information that is specific to the item's type. -+ The struct layout is shown below. -+ </para> -+ -+ <programlisting> -+struct kdbus_item { -+ __u64 size; -+ __u64 type; -+ /* item payload - see below */ -+ union { -+ __u8 data[0]; -+ __u32 data32[0]; -+ __u64 data64[0]; -+ char str[0]; -+ -+ __u64 id; -+ struct kdbus_vec vec; -+ struct kdbus_creds creds; -+ struct kdbus_pids pids; -+ struct kdbus_audit audit; -+ struct kdbus_caps caps; -+ struct kdbus_timestamp timestamp; -+ struct kdbus_name name; -+ struct kdbus_bloom_parameter bloom_parameter; -+ struct kdbus_bloom_filter bloom_filter; -+ struct kdbus_memfd memfd; -+ int fds[0]; -+ struct kdbus_notify_name_change name_change; -+ struct kdbus_notify_id_change id_change; -+ struct kdbus_policy_access policy_access; -+ }; -+}; -+ </programlisting> -+ -+ <para> -+ <type>struct kdbus_item</type> should never be used to allocate -+ an item instance, as its size may grow in future releases of the API. -+ Instead, it should be manually assembled by storing the -+ <varname>size</varname>, <varname>type</varname> and payload to a -+ struct of its own. -+ </para> -+ </refsect1> -+ -+ <refsect1> -+ <title>Item types</title> -+ -+ <refsect2> -+ <title>Negotiation item</title> -+ <variablelist> -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_NEGOTIATE</constant></term> -+ <listitem><para> -+ With this item is attached to any ioctl, programs can -+ <emphasis>probe</emphasis> the kernel for known item items. -+ The item carries an array of <type>uint64_t</type> values in -+ <varname>item.data64</varname>, each set to an item type to -+ probe. The kernel will reset each member of this array that is -+ not recognized as valid item type to <constant>0</constant>. -+ This way, users can negotiate kernel features at start-up to -+ keep newer userspace compatible with older kernels. This item -+ is never attached by the kernel in response to any command. -+ </para></listitem> -+ </varlistentry> -+ </variablelist> -+ </refsect2> -+ -+ <refsect2> -+ <title>Command specific items</title> -+ <variablelist> -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_PAYLOAD_VEC</constant></term> -+ <term><constant>KDBUS_ITEM_PAYLOAD_OFF</constant></term> -+ <listitem><para> -+ Messages are directly copied by the sending process into the -+ receiver's -+ <citerefentry> -+ <refentrytitle>kdbus.pool</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry>. -+ This 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. <constant>KDBUS_ITEM_PAYLOAD_VEC</constant> -+ is used when <emphasis>sending</emphasis> message. The item -+ references a memory address when the payload data can be found. -+ <constant>KDBUS_ITEM_PAYLOAD_OFF</constant> is used when messages -+ are <emphasis>received</emphasis>, and the -+ <constant>offset</constant> value describes the offset inside the -+ receiving connection's -+ <citerefentry> -+ <refentrytitle>kdbus.pool</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ where the message payload can be found. See -+ <citerefentry> -+ <refentrytitle>kdbus.message</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more information on passing of payload data along with a -+ message. -+ <programlisting> -+struct kdbus_vec { -+ __u64 size; -+ union { -+ __u64 address; -+ __u64 offset; -+ }; -+}; -+ </programlisting> -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_PAYLOAD_MEMFD</constant></term> -+ <listitem><para> -+ Transports a file descriptor of a <emphasis>memfd</emphasis> in -+ <type>struct kdbus_memfd</type> in <varname>item.memfd</varname>. -+ The <varname>size</varname> field has to match the actual size of -+ the memfd that was specified when it was created. The -+ <varname>start</varname> parameter denotes the offset inside the -+ memfd at which the referenced payload starts. See -+ <citerefentry> -+ <refentrytitle>kdbus.message</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more information on passing of payload data along with a -+ message. -+ <programlisting> -+struct kdbus_memfd { -+ __u64 start; -+ __u64 size; -+ int fd; -+ __u32 __pad; -+}; -+ </programlisting> -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_FDS</constant></term> -+ <listitem><para> -+ Contains an array of <emphasis>file descriptors</emphasis>. -+ When used with <constant>KDBUS_CMD_SEND</constant>, the values of -+ this array must be filled with valid file descriptor numbers. -+ When received as item attached to a message, the array will -+ contain the numbers of the installed file descriptors, or -+ <constant>-1</constant> in case an error occurred. -+ file descriptor. -+ In either case, the number of entries in the array is derived from -+ the item's total size. See -+ <citerefentry> -+ <refentrytitle>kdbus.message</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more information. -+ </para></listitem> -+ </varlistentry> -+ </variablelist> -+ </refsect2> -+ -+ <refsect2> -+ <title>Items specific to some commands</title> -+ <variablelist> -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_CANCEL_FD</constant></term> -+ <listitem><para> -+ Transports a file descriptor that can be used to cancel a -+ synchronous <constant>KDBUS_CMD_SEND</constant> operation by -+ writing to it. The file descriptor is stored in -+ <varname>item.fd[0]</varname>. The item may only contain one -+ file descriptor. See -+ <citerefentry> -+ <refentrytitle>kdbus.message</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more information on this item and how to use it. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_BLOOM_PARAMETER</constant></term> -+ <listitem><para> -+ Contains a set of <emphasis>bloom parameters</emphasis> as -+ <type>struct kdbus_bloom_parameter</type> in -+ <varname>item.bloom_parameter</varname>. -+ The item is passed from userspace to kernel during the -+ <constant>KDBUS_CMD_BUS_MAKE</constant> ioctl, and returned -+ verbatim when <constant>KDBUS_CMD_HELLO</constant> is called. -+ The kernel does not use the bloom parameters, but they need to -+ be known by each connection on the bus in order to define the -+ bloom filter hash details. See -+ <citerefentry> -+ <refentrytitle>kdbus.match</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more information on matching and bloom filters. -+ <programlisting> -+struct kdbus_bloom_parameter { -+ __u64 size; -+ __u64 n_hash; -+}; -+ </programlisting> -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_BLOOM_FILTER</constant></term> -+ <listitem><para> -+ Carries a <emphasis>bloom filter</emphasis> as -+ <type>struct kdbus_bloom_filter</type> in -+ <varname>item.bloom_filter</varname>. It is mandatory to send this -+ item attached to a <type>struct kdbus_msg</type>, in case the -+ message is a signal. This item is never transported from kernel to -+ userspace. See -+ <citerefentry> -+ <refentrytitle>kdbus.match</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more information on matching and bloom filters. -+ <programlisting> -+struct kdbus_bloom_filter { -+ __u64 generation; -+ __u64 data[0]; -+}; -+ </programlisting> -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_BLOOM_MASK</constant></term> -+ <listitem><para> -+ Transports a <emphasis>bloom mask</emphasis> as binary data blob -+ stored in <varname>item.data</varname>. This item is used to -+ describe a match into a connection's match database. See -+ <citerefentry> -+ <refentrytitle>kdbus.match</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more information on matching and bloom filters. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_DST_NAME</constant></term> -+ <listitem><para> -+ Contains a <emphasis>well-known name</emphasis> to send a -+ message to, as null-terminated string in -+ <varname>item.str</varname>. This item is used with -+ <constant>KDBUS_CMD_SEND</constant>. See -+ <citerefentry> -+ <refentrytitle>kdbus.message</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more information on how to send a message. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_MAKE_NAME</constant></term> -+ <listitem><para> -+ Contains a <emphasis>bus name</emphasis> or -+ <emphasis>endpoint name</emphasis>, stored as null-terminated -+ string in <varname>item.str</varname>. This item is sent from -+ userspace to kernel when buses or endpoints are created, and -+ returned back to userspace when the bus creator information is -+ queried. See -+ <citerefentry> -+ <refentrytitle>kdbus.bus</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ and -+ <citerefentry> -+ <refentrytitle>kdbus.endpoint</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry>. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_ATTACH_FLAGS_SEND</constant></term> -+ <term><constant>KDBUS_ITEM_ATTACH_FLAGS_RECV</constant></term> -+ <listitem><para> -+ Contains a set of <emphasis>attach flags</emphasis> at -+ <emphasis>send</emphasis> or <emphasis>receive</emphasis> time. See -+ <citerefentry> -+ <refentrytitle>kdbus</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry>, -+ <citerefentry> -+ <refentrytitle>kdbus.bus</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> and -+ <citerefentry> -+ <refentrytitle>kdbus.connection</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more information on attach flags. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_ID</constant></term> -+ <listitem><para> -+ Transports a connection's <emphasis>numerical ID</emphasis> of -+ a connection as <type>uint64_t</type> value in -+ <varname>item.id</varname>. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_NAME</constant></term> -+ <listitem><para> -+ Transports a name associated with the -+ <emphasis>name registry</emphasis> as null-terminated string as -+ <type>struct kdbus_name</type> in -+ <varname>item.name</varname>. The <varname>flags</varname> -+ contains the flags of the name. See -+ <citerefentry> -+ <refentrytitle>kdbus.name</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more information on how to access the name registry of a bus. -+ <programlisting> -+struct kdbus_name { -+ __u64 flags; -+ char name[0]; -+}; -+ </programlisting> -+ </para></listitem> -+ </varlistentry> -+ </variablelist> -+ </refsect2> -+ -+ <refsect2> -+ <title>Items attached by the kernel as metadata</title> -+ -+ <variablelist> -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_TIMESTAMP</constant></term> -+ <listitem><para> -+ Contains both the <emphasis>monotonic</emphasis> and the -+ <emphasis>realtime</emphasis> timestamp, taken when the message -+ was processed on the kernel side. -+ Stored as <type>struct kdbus_timestamp</type> in -+ <varname>item.timestamp</varname>. -+ <programlisting> -+struct kdbus_timestamp { -+ __u64 seqnum; -+ __u64 monotonic_ns; -+ __u64 realtime_ns; -+}; -+ </programlisting> -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_CREDS</constant></term> -+ <listitem><para> -+ Contains a set of <emphasis>user</emphasis> and -+ <emphasis>group</emphasis> information as 32-bit values, in the -+ usual four flavors: real, effective, saved and filesystem related. -+ Stored as <type>struct kdbus_creds</type> in -+ <varname>item.creds</varname>. -+ <programlisting> -+struct kdbus_creds { -+ __u32 uid; -+ __u32 euid; -+ __u32 suid; -+ __u32 fsuid; -+ __u32 gid; -+ __u32 egid; -+ __u32 sgid; -+ __u32 fsgid; -+}; -+ </programlisting> -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_PIDS</constant></term> -+ <listitem><para> -+ Contains the <emphasis>PID</emphasis>, <emphasis>TID</emphasis> -+ and <emphasis>parent PID (PPID)</emphasis> of a remote peer. -+ Stored as <type>struct kdbus_pids</type> in -+ <varname>item.pids</varname>. -+ <programlisting> -+struct kdbus_pids { -+ __u64 pid; -+ __u64 tid; -+ __u64 ppid; -+}; -+ </programlisting> -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_AUXGROUPS</constant></term> -+ <listitem><para> -+ Contains the <emphasis>auxiliary (supplementary) groups</emphasis> -+ a remote peer is a member of, stored as array of -+ <type>uint32_t</type> values in <varname>item.data32</varname>. -+ The array length can be determined by looking at the item's total -+ size, subtracting the size of the header and and dividing the -+ remainder by <constant>sizeof(uint32_t)</constant>. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_OWNED_NAME</constant></term> -+ <listitem><para> -+ Contains a <emphasis>well-known name</emphasis> currently owned -+ by a connection. The name is stored as null-terminated string in -+ <varname>item.str</varname>. Its length can also be derived from -+ the item's total size. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_TID_COMM</constant> [*]</term> -+ <listitem><para> -+ Contains the <emphasis>comm</emphasis> string of a task's -+ <emphasis>TID</emphasis> (thread ID), stored as null-terminated -+ string in <varname>item.str</varname>. Its length can also be -+ derived from the item's total size. Receivers of this item should -+ not use its contents for any kind of security measures. See below. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_PID_COMM</constant> [*]</term> -+ <listitem><para> -+ Contains the <emphasis>comm</emphasis> string of a task's -+ <emphasis>PID</emphasis> (process ID), stored as null-terminated -+ string in <varname>item.str</varname>. Its length can also be -+ derived from the item's total size. Receivers of this item should -+ not use its contents for any kind of security measures. See below. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_EXE</constant> [*]</term> -+ <listitem><para> -+ Contains the <emphasis>path to the executable</emphasis> of a task, -+ stored as null-terminated string in <varname>item.str</varname>. Its -+ length can also be derived from the item's total size. Receivers of -+ this item should not use its contents for any kind of security -+ measures. See below. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_CMDLINE</constant> [*]</term> -+ <listitem><para> -+ Contains the <emphasis>command line arguments</emphasis> of a -+ task, stored as an <emphasis>array</emphasis> of null-terminated -+ strings in <varname>item.str</varname>. The total length of all -+ strings in the array can be derived from the item's total size. -+ Receivers of this item should not use its contents for any kind -+ of security measures. See below. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_CGROUP</constant></term> -+ <listitem><para> -+ Contains the <emphasis>cgroup path</emphasis> of a task, stored -+ as null-terminated string in <varname>item.str</varname>. Its -+ length can also be derived from the item's total size. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_CAPS</constant></term> -+ <listitem><para> -+ Contains sets of <emphasis>capabilities</emphasis>, stored as -+ <type>struct kdbus_caps</type> in <varname>item.caps</varname>. -+ As the item size may increase in the future, programs should be -+ written in a way that it takes -+ <varname>item.caps.last_cap</varname> into account, and derive -+ the number of sets and rows from the item size and the reported -+ number of valid capability bits. -+ <programlisting> -+struct kdbus_caps { -+ __u32 last_cap; -+ __u32 caps[0]; -+}; -+ </programlisting> -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_SECLABEL</constant></term> -+ <listitem><para> -+ Contains the <emphasis>LSM label</emphasis> of a task, stored as -+ null-terminated string in <varname>item.str</varname>. Its length -+ can also be derived from the item's total size. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_AUDIT</constant></term> -+ <listitem><para> -+ Contains the audit <emphasis>sessionid</emphasis> and -+ <emphasis>loginuid</emphasis> of a task, stored as -+ <type>struct kdbus_audit</type> in -+ <varname>item.audit</varname>. -+ <programlisting> -+struct kdbus_audit { -+ __u32 sessionid; -+ __u32 loginuid; -+}; -+ </programlisting> -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_CONN_DESCRIPTION</constant></term> -+ <listitem><para> -+ Contains the <emphasis>connection description</emphasis>, as set -+ by <constant>KDBUS_CMD_HELLO</constant> or -+ <constant>KDBUS_CMD_CONN_UPDATE</constant>, stored as -+ null-terminated string in <varname>item.str</varname>. Its length -+ can also be derived from the item's total size. -+ </para></listitem> -+ </varlistentry> -+ </variablelist> -+ -+ <para> -+ All metadata is automatically translated into the -+ <emphasis>namespaces</emphasis> of the task that receives them. See -+ <citerefentry> -+ <refentrytitle>kdbus.message</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more information. -+ </para> -+ -+ <para> -+ [*] Note that the content stored in metadata items of type -+ <constant>KDBUS_ITEM_TID_COMM</constant>, -+ <constant>KDBUS_ITEM_PID_COMM</constant>, -+ <constant>KDBUS_ITEM_EXE</constant> and -+ <constant>KDBUS_ITEM_CMDLINE</constant> -+ can easily be tampered by the sending tasks. Therefore, they should -+ <emphasis>not</emphasis> be used for any sort of security relevant -+ assumptions. The only reason they are transmitted is to let -+ receivers know about details that were set when metadata was -+ collected, even though the task they were collected from is not -+ active any longer when the items are received. -+ </para> -+ </refsect2> -+ -+ <refsect2> -+ <title>Items used for policy entries, matches and notifications</title> -+ -+ <variablelist> -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_POLICY_ACCESS</constant></term> -+ <listitem><para> -+ This item describes a <emphasis>policy access</emphasis> entry to -+ access the policy database of a -+ <citerefentry> -+ <refentrytitle>kdbus.bus</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> or -+ <citerefentry> -+ <refentrytitle>kdbus.endpoint</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry>. -+ Please refer to -+ <citerefentry> -+ <refentrytitle>kdbus.policy</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more information on the policy database and how to access it. -+ <programlisting> -+struct kdbus_policy_access { -+ __u64 type; -+ __u64 access; -+ __u64 id; -+}; -+ </programlisting> -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_ID_ADD</constant></term> -+ <term><constant>KDBUS_ITEM_ID_REMOVE</constant></term> -+ <listitem><para> -+ This item is sent as attachment to a -+ <emphasis>kernel notification</emphasis> and indicates that a -+ new connection was created on the bus, or that a connection was -+ disconnected, respectively. It stores a -+ <type>struct kdbus_notify_id_change</type> in -+ <varname>item.id_change</varname>. -+ The <varname>id</varname> field contains the numeric ID of the -+ connection that was added or removed, and <varname>flags</varname> -+ is set to the connection flags, as passed by -+ <constant>KDBUS_CMD_HELLO</constant>. See -+ <citerefentry> -+ <refentrytitle>kdbus.match</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ and -+ <citerefentry> -+ <refentrytitle>kdbus.message</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more information on matches and notification messages. -+ <programlisting> -+struct kdbus_notify_id_change { -+ __u64 id; -+ __u64 flags; -+}; -+ </programlisting> -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_NAME_ADD</constant></term> -+ <term><constant>KDBUS_ITEM_NAME_REMOVE</constant></term> -+ <term><constant>KDBUS_ITEM_NAME_CHANGE</constant></term> -+ <listitem><para> -+ This item is sent as attachment to a -+ <emphasis>kernel notification</emphasis> and indicates that a -+ <emphasis>well-known name</emphasis> appeared, disappeared or -+ transferred to another owner on the bus. It stores a -+ <type>struct kdbus_notify_name_change</type> in -+ <varname>item.name_change</varname>. -+ <varname>old_id</varname> describes the former owner of the name -+ and is set to <constant>0</constant> values in case of -+ <constant>KDBUS_ITEM_NAME_ADD</constant>. -+ <varname>new_id</varname> describes the new owner of the name and -+ is set to <constant>0</constant> values in case of -+ <constant>KDBUS_ITEM_NAME_REMOVE</constant>. -+ The <varname>name</varname> field contains the well-known name the -+ notification is about, as null-terminated string. See -+ <citerefentry> -+ <refentrytitle>kdbus.match</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ and -+ <citerefentry> -+ <refentrytitle>kdbus.message</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more information on matches and notification messages. -+ <programlisting> -+struct kdbus_notify_name_change { -+ struct kdbus_notify_id_change old_id; -+ struct kdbus_notify_id_change new_id; -+ char name[0]; -+}; -+ </programlisting> -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_REPLY_TIMEOUT</constant></term> -+ <listitem><para> -+ This item is sent as attachment to a -+ <emphasis>kernel notification</emphasis>. It informs the receiver -+ that an expected reply to a message was not received in time. -+ The remote peer ID and the message cookie is stored in the message -+ header. See -+ <citerefentry> -+ <refentrytitle>kdbus.message</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more information about messages, timeouts and notifications. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_REPLY_DEAD</constant></term> -+ <listitem><para> -+ This item is sent as attachment to a -+ <emphasis>kernel notification</emphasis>. It informs the receiver -+ that a remote connection a reply is expected from was disconnected -+ before that reply was sent. The remote peer ID and the message -+ cookie is stored in the message header. See -+ <citerefentry> -+ <refentrytitle>kdbus.message</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more information about messages, timeouts and notifications. -+ </para></listitem> -+ </varlistentry> -+ </variablelist> -+ </refsect2> -+ </refsect1> -+ -+ <refsect1> -+ <title>See Also</title> -+ <simplelist type="inline"> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.bus</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.connection</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.endpoint</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.fs</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.message</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.name</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.pool</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>memfd_create</refentrytitle> -+ <manvolnum>2</manvolnum> -+ </citerefentry> -+ </member> -+ </simplelist> -+ </refsect1> -+ -+</refentry> -diff --git a/Documentation/kdbus/kdbus.match.xml b/Documentation/kdbus/kdbus.match.xml -new file mode 100644 -index 000000000000..ef77b64e5890 ---- /dev/null -+++ b/Documentation/kdbus/kdbus.match.xml -@@ -0,0 +1,553 @@ -+<?xml version='1.0'?> <!--*-nxml-*--> -+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" -+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> -+ -+<refentry id="kdbus.match"> -+ -+ <refentryinfo> -+ <title>kdbus.match</title> -+ <productname>kdbus.match</productname> -+ </refentryinfo> -+ -+ <refmeta> -+ <refentrytitle>kdbus.match</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </refmeta> -+ -+ <refnamediv> -+ <refname>kdbus.match</refname> -+ <refpurpose>kdbus match</refpurpose> -+ </refnamediv> -+ -+ <refsect1> -+ <title>Description</title> -+ -+ <para> -+ kdbus connections can install matches in order to subscribe to signal -+ messages sent on the bus. Such signal messages can be either directed -+ to a single connection (by setting a specific connection ID in -+ <varname>struct kdbus_msg.dst_id</varname> or by sending it to a -+ well-known name), or to potentially <emphasis>all</emphasis> currently -+ active connections on the bus (by setting -+ <varname>struct kdbus_msg.dst_id</varname> to -+ <constant>KDBUS_DST_ID_BROADCAST</constant>). -+ A signal message always has the <constant>KDBUS_MSG_SIGNAL</constant> -+ bit set in the <varname>flags</varname> bitfield. -+ Also, signal messages can originate from either the kernel (called -+ <emphasis>notifications</emphasis>), or from other bus connections. -+ In either case, a bus connection needs to have a suitable -+ <emphasis>match</emphasis> installed in order to receive any signal -+ message. Without any rules installed in the connection, no signal message -+ will be received. -+ </para> -+ </refsect1> -+ -+ <refsect1> -+ <title>Matches for signal messages from other connections</title> -+ <para> -+ Matches for messages from other connections (not kernel notifications) -+ are implemented as bloom filters (see below). The sender adds certain -+ properties of the message as elements to a bloom filter bit field, and -+ sends that along with the signal message. -+ -+ The receiving connection adds the message properties it is interested in -+ as elements to a bloom mask bit field, and uploads the mask as match rule, -+ possibly along with some other rules to further limit the match. -+ -+ The kernel will match the signal message's bloom filter against the -+ connections bloom mask (simply by &-ing it), and will decide whether -+ the message should be delivered to a connection. -+ </para> -+ <para> -+ The kernel has no notion of any specific properties of the signal message, -+ all it sees are the bit fields of the bloom filter and the 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 signal messages -+ 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 <emphasis>generation</emphasis> 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. -+ </para> -+ </refsect1> -+ -+ <refsect1> -+ <title>Bloom filters</title> -+ <para> -+ 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 signal messages that have a -+ matching filter. -+ -+ For general information, see -+ <ulink url="https://en.wikipedia.org/wiki/Bloom_filter">the Wikipedia -+ article on bloom filters</ulink>. -+ </para> -+ <para> -+ The size of the bloom filter is defined per bus when it is created, in -+ <varname>kdbus_bloom_parameter.size</varname>. All bloom filters attached -+ to signal 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 in userspace applications. 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 -+ <emphasis>AND</emphasis> logic, but the mask may have more bits set than -+ the filter. Consequently, false positive matches are expected to happen, -+ and programs must deal with that fact by checking the contents of the -+ payload again at receive time. -+ </para> -+ <para> -+ Masks are entities that are always passed to the kernel as part of a -+ match (with an item of type <constant>KDBUS_ITEM_BLOOM_MASK</constant>), -+ and filters can be attached to signals, with an item of type -+ <constant>KDBUS_ITEM_BLOOM_FILTER</constant>. For a filter to match, all -+ its bits have to be set in the match mask as well. -+ </para> -+ <para> -+ For example, consider a bus that has a bloom size of 8 bytes, and the -+ following mask/filter combinations: -+ </para> -+ <programlisting><![CDATA[ -+ filter 0x0101010101010101 -+ mask 0x0101010101010101 -+ -> matches -+ -+ filter 0x0303030303030303 -+ mask 0x0101010101010101 -+ -> doesn't match -+ -+ filter 0x0101010101010101 -+ mask 0x0303030303030303 -+ -> matches -+ ]]></programlisting> -+ -+ <para> -+ Hence, in order to catch all messages, a mask filled with -+ <constant>0xff</constant> bytes can be installed as a wildcard match rule. -+ </para> -+ -+ <refsect2> -+ <title>Generations</title> -+ -+ <para> -+ Uploaded matches may contain multiple masks, which have are as large as -+ the bloom size defined by the bus. Each block of a mask is called a -+ <emphasis>generation</emphasis>, starting at index 0. -+ -+ At match time, when a signal 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 programs to provide backward -+ compatible masks at upload time, while older clients can still match -+ against older versions of filters. -+ </para> -+ </refsect2> -+ </refsect1> -+ -+ <refsect1> -+ <title>Matches for kernel notifications</title> -+ <para> -+ To receive kernel generated notifications (see -+ <citerefentry> -+ <refentrytitle>kdbus.message</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry>), -+ a connection must install match rules that are different from -+ the bloom filter matches described in the section above. They can be -+ filtered by the connection ID that caused the notification to be sent, by -+ one of the names it currently owns, or by the type of the notification -+ (ID/name add/remove/change). -+ </para> -+ </refsect1> -+ -+ <refsect1> -+ <title>Adding a match</title> -+ <para> -+ To add a match, the <constant>KDBUS_CMD_MATCH_ADD</constant> 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 <emphasis>rule</emphasis>, and the collection of them, -+ which is submitted as one block via the ioctl, is called a -+ <emphasis>match</emphasis>. 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 decrease the chance that the connection's process will be -+ woken up needlessly. -+ -+ 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. -+ </para> -+ -+ <programlisting> -+struct kdbus_cmd_match { -+ __u64 size; -+ __u64 flags; -+ __u64 return_flags; -+ __u64 cookie; -+ struct kdbus_item items[0]; -+}; -+ </programlisting> -+ -+ <para>The fields in this struct are described below.</para> -+ -+ <variablelist> -+ <varlistentry> -+ <term><varname>size</varname></term> -+ <listitem><para> -+ The overall size of the struct, including its items. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>flags</varname></term> -+ <listitem><para>Flags to control the behavior of the ioctl.</para> -+ <variablelist> -+ <varlistentry> -+ <term><constant>KDBUS_MATCH_REPLACE</constant></term> -+ <listitem> -+ <para>Make the endpoint file group-accessible</para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_FLAG_NEGOTIATE</constant></term> -+ <listitem> -+ <para> -+ Requests a set of valid flags for this ioctl. When this bit is -+ set, no action is taken; the ioctl will return -+ <errorcode>0</errorcode>, and the <varname>flags</varname> -+ field will have all bits set that are valid for this command. -+ The <constant>KDBUS_FLAG_NEGOTIATE</constant> bit will be -+ cleared by the operation. -+ </para> -+ </listitem> -+ </varlistentry> -+ </variablelist> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>return_flags</varname></term> -+ <listitem><para> -+ Flags returned by the kernel. Currently unused and always set to -+ <constant>0</constant> by the kernel. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>cookie</varname></term> -+ <listitem><para> -+ A cookie which identifies the match, so it can be referred to when -+ removing it. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>items</varname></term> -+ <listitem> -+ <para> -+ Items to define the actual rules of the matches. The following item -+ types are expected. Each item will create one new match rule. -+ </para> -+ <variablelist> -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_BLOOM_MASK</constant></term> -+ <listitem> -+ <para> -+ 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 the section below for more information on bloom filters. -+ </para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_NAME</constant></term> -+ <listitem> -+ <para> -+ When used as part of kernel notifications, this item specifies -+ a name that is acquired, lost or that changed its owner (see -+ below). When used as part of a match for user-generated signal -+ messages, it specifies a name that the sending connection must -+ own at the time of sending the signal. -+ </para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_ID</constant></term> -+ <listitem> -+ <para> -+ Specify a sender connection's ID that will match this rule. -+ For kernel notifications, this specifies the ID of a -+ connection that was added to or removed from the bus. -+ For used-generated signals, it specifies the ID of the -+ connection that sent the signal message. -+ </para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_NAME_ADD</constant></term> -+ <term><constant>KDBUS_ITEM_NAME_REMOVE</constant></term> -+ <term><constant>KDBUS_ITEM_NAME_CHANGE</constant></term> -+ <listitem> -+ <para> -+ These items request delivery of kernel notifications that -+ describe a name acquisition, loss, or change. The details -+ are stored in the item's -+ <varname>kdbus_notify_name_change</varname> member. -+ All information specified must be matched in order to make -+ the message pass. Use -+ <constant>KDBUS_MATCH_ID_ANY</constant> to -+ match against any unique connection ID. -+ </para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_ID_ADD</constant></term> -+ <term><constant>KDBUS_ITEM_ID_REMOVE</constant></term> -+ <listitem> -+ <para> -+ These items request delivery of kernel notifications that are -+ generated when a connection is created or terminated. -+ <type>struct kdbus_notify_id_change</type> 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 <constant>KDBUS_MATCH_ID_ANY</constant>, -+ all of them. -+ </para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_NEGOTIATE</constant></term> -+ <listitem><para> -+ With this item, programs can <emphasis>probe</emphasis> the -+ kernel for known item types. See -+ <citerefentry> -+ <refentrytitle>kdbus.item</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more details. -+ </para></listitem> -+ </varlistentry> -+ </variablelist> -+ -+ <para> -+ Unrecognized items are rejected, and the ioctl will fail with -+ <varname>errno</varname> set to <constant>EINVAL</constant>. -+ </para> -+ </listitem> -+ </varlistentry> -+ </variablelist> -+ -+ <para> -+ Refer to -+ <citerefentry> -+ <refentrytitle>kdbus.message</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more information on message types. -+ </para> -+ </refsect1> -+ -+ <refsect1> -+ <title>Removing a match</title> -+ <para> -+ Matches can be removed with the -+ <constant>KDBUS_CMD_MATCH_REMOVE</constant> ioctl, which takes -+ <type>struct kdbus_cmd_match</type> as argument, but its fields -+ usage slightly differs compared to that of -+ <constant>KDBUS_CMD_MATCH_ADD</constant>. -+ </para> -+ -+ <programlisting> -+struct kdbus_cmd_match { -+ __u64 size; -+ __u64 cookie; -+ __u64 flags; -+ __u64 return_flags; -+ struct kdbus_item items[0]; -+}; -+ </programlisting> -+ -+ <para>The fields in this struct are described below.</para> -+ -+ <variablelist> -+ <varlistentry> -+ <term><varname>size</varname></term> -+ <listitem><para> -+ The overall size of the struct, including its items. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>cookie</varname></term> -+ <listitem><para> -+ The cookie of the match, as it was passed when the match was added. -+ All matches that have this cookie will be removed. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>flags</varname></term> -+ <listitem><para> -+ No flags are supported for this use case. -+ <constant>KDBUS_FLAG_NEGOTIATE</constant> is accepted to probe for -+ valid flags. If set, the ioctl will fail with -+ <errorcode>-1</errorcode>, <varname>errno</varname> is set to -+ <constant>EPROTO</constant>, and the <varname>flags</varname> field -+ is set to <constant>0</constant>. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>return_flags</varname></term> -+ <listitem><para> -+ Flags returned by the kernel. Currently unused and always set to -+ <constant>0</constant> by the kernel. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>items</varname></term> -+ <listitem> -+ <para> -+ No items are supported for this use case, but -+ <constant>KDBUS_ITEM_NEGOTIATE</constant> is allowed nevertheless. -+ </para> -+ </listitem> -+ </varlistentry> -+ </variablelist> -+ </refsect1> -+ -+ <refsect1> -+ <title>Return value</title> -+ <para> -+ On success, all mentioned ioctl commands return <errorcode>0</errorcode>; -+ on error, <errorcode>-1</errorcode> is returned, and -+ <varname>errno</varname> is set to indicate the error. -+ If the issued ioctl is illegal for the file descriptor used, -+ <varname>errno</varname> will be set to <constant>ENOTTY</constant>. -+ </para> -+ -+ <refsect2> -+ <title> -+ <constant>KDBUS_CMD_MATCH_ADD</constant> may fail with the following -+ errors -+ </title> -+ -+ <variablelist> -+ <varlistentry> -+ <term><constant>EINVAL</constant></term> -+ <listitem><para> -+ Illegal flags or items. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>EDOM</constant></term> -+ <listitem><para> -+ Illegal bloom filter size. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>EMFILE</constant></term> -+ <listitem><para> -+ Too many matches for this connection. -+ </para></listitem> -+ </varlistentry> -+ </variablelist> -+ </refsect2> -+ -+ <refsect2> -+ <title> -+ <constant>KDBUS_CMD_MATCH_REMOVE</constant> may fail with the following -+ errors -+ </title> -+ -+ <variablelist> -+ <varlistentry> -+ <term><constant>EINVAL</constant></term> -+ <listitem><para> -+ Illegal flags. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>EBADSLT</constant></term> -+ <listitem><para> -+ A match entry with the given cookie could not be found. -+ </para></listitem> -+ </varlistentry> -+ </variablelist> -+ </refsect2> -+ </refsect1> -+ -+ <refsect1> -+ <title>See Also</title> -+ <simplelist type="inline"> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.bus</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.match</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.fs</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.item</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.message</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.name</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.pool</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ </simplelist> -+ </refsect1> -+</refentry> -diff --git a/Documentation/kdbus/kdbus.message.xml b/Documentation/kdbus/kdbus.message.xml -new file mode 100644 -index 000000000000..c25000dcfbc7 ---- /dev/null -+++ b/Documentation/kdbus/kdbus.message.xml -@@ -0,0 +1,1277 @@ -+<?xml version='1.0'?> <!--*-nxml-*--> -+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" -+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> -+ -+<refentry id="kdbus.message"> -+ -+ <refentryinfo> -+ <title>kdbus.message</title> -+ <productname>kdbus.message</productname> -+ </refentryinfo> -+ -+ <refmeta> -+ <refentrytitle>kdbus.message</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </refmeta> -+ -+ <refnamediv> -+ <refname>kdbus.message</refname> -+ <refpurpose>kdbus message</refpurpose> -+ </refnamediv> -+ -+ <refsect1> -+ <title>Description</title> -+ -+ <para> -+ A kdbus message is used to exchange information between two connections -+ on a bus, or to transport notifications from the kernel to one or many -+ connections. This document describes the layout of messages, how payload -+ is added to them and how they are sent and received. -+ </para> -+ </refsect1> -+ -+ <refsect1> -+ <title>Message layout</title> -+ -+ <para>The layout of a message is shown below.</para> -+ -+ <programlisting> -+ +-------------------------------------------------------------------------+ -+ | 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 | | -+ | | ... | | -+ | +---------------------------------------------------------------------+ | -+ | ... further data records ... | -+ +-------------------------------------------------------------------------+ -+ </programlisting> -+ </refsect1> -+ -+ <refsect1> -+ <title>Message payload</title> -+ -+ <para> -+ 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 <function>mmap()</function>ed by the receiver. See -+ <citerefentry> -+ <refentrytitle>kdbus.pool</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more information. -+ </para> -+ -+ <para> -+ Message payload must be described in items attached to a message when -+ it is sent. A receiver can access the payload by looking at the items -+ that are attached to a message in its pool. The following items are used. -+ </para> -+ -+ <variablelist> -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_PAYLOAD_VEC</constant></term> -+ <listitem> -+ <para> -+ This item references a piece of memory on the sender side which is -+ directly copied into the receiver's pool. This 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. -+ This item is never found in a message received by a connection. -+ </para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_PAYLOAD_OFF</constant></term> -+ <listitem> -+ <para> -+ This item is attached to messages on the receiving side and points -+ to a memory area inside the receiver's pool. The -+ <varname>offset</varname> variable in the item denotes the memory -+ location relative to the message itself. -+ </para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_PAYLOAD_MEMFD</constant></term> -+ <listitem> -+ <para> -+ Messages can reference <emphasis>memfd</emphasis> 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. -+ </para> -+ <para> -+ Only memfds that have -+ <constant>(F_SEAL_SHRINK|F_SEAL_GROW|F_SEAL_WRITE|F_SEAL_SEAL) -+ </constant> -+ set 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. If those -+ seals are not set on the memfd, the ioctl will fail with -+ <errorcode>-1</errorcode>, and <varname>errno</varname> will be -+ set to <constant>ETXTBUSY</constant>. -+ </para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_FDS</constant></term> -+ <listitem> -+ <para> -+ Messages can transport regular file descriptors via -+ <constant>KDBUS_ITEM_FDS</constant>. This item carries an array -+ of <type>int</type> values in <varname>item.fd</varname>. The -+ maximum number of file descriptors in the item is -+ <constant>253</constant>, and only one item of this type is -+ accepted per message. All passed values must be valid file -+ descriptors; the open count of each file descriptors is increased -+ by installing it to the receiver's task. This item can only be -+ used for directed messages, not for broadcasts, and only to -+ remote peers that have opted-in for receiving file descriptors -+ at connection time (<constant>KDBUS_HELLO_ACCEPT_FD</constant>). -+ </para> -+ </listitem> -+ </varlistentry> -+ </variablelist> -+ -+ <para> -+ The sender must not make any assumptions on the type in which data is -+ received by the remote peer. The kernel is free to re-pack multiple -+ <constant>KDBUS_ITEM_PAYLOAD_VEC</constant> and -+ <constant>KDBUS_ITEM_PAYLOAD_MEMFD</constant> payloads. For instance, the -+ kernel may decide to merge multiple <constant>VECs</constant> into a -+ single <constant>VEC</constant>, inline <constant>MEMFD</constant> -+ payloads into memory, or merge all passed <constant>VECs</constant> into a -+ single <constant>MEMFD</constant>. However, the kernel preserves the order -+ of passed data. This means that the order of all <constant>VEC</constant> -+ and <constant>MEMFD</constant> items is not changed in respect to each -+ other. In other words: All passed <constant>VEC</constant> and -+ <constant>MEMFD</constant> data payloads are treated as a single stream -+ of data that may be received by the remote peer in a different set of -+ chunks than it was sent as. -+ </para> -+ </refsect1> -+ -+ <refsect1> -+ <title>Sending messages</title> -+ -+ <para> -+ Messages are passed to the kernel with the -+ <constant>KDBUS_CMD_SEND</constant> ioctl. Depending on the destination -+ address of the message, the kernel delivers the message to the specific -+ destination connection, or to some subset of 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 above). -+ </para> -+ -+ <para> -+ The <constant>KDBUS_CMD_SEND</constant> ioctl uses a -+ <type>struct kdbus_cmd_send</type> to describe the message -+ transfer. -+ </para> -+ <programlisting> -+struct kdbus_cmd_send { -+ __u64 size; -+ __u64 flags; -+ __u64 return_flags; -+ __u64 msg_address; -+ struct kdbus_msg_info reply; -+ struct kdbus_item items[0]; -+}; -+ </programlisting> -+ -+ <para>The fields in this struct are described below.</para> -+ -+ <variablelist> -+ <varlistentry> -+ <term><varname>size</varname></term> -+ <listitem><para> -+ The overall size of the struct, including its items. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>flags</varname></term> -+ <listitem><para>Flags for message delivery</para> -+ <variablelist> -+ <varlistentry> -+ <term><constant>KDBUS_SEND_SYNC_REPLY</constant></term> -+ <listitem> -+ <para> -+ 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 -+ <constant>KDBUS_SEND_SYNC_REPLY</constant> controls. The -+ <constant>KDBUS_CMD_SEND</constant> 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 -+ <citerefentry> -+ <refentrytitle>signal</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry>. -+ -+ The offset of the reply message in the sender's pool is stored -+ in in <varname>offset_reply</varname> when the ioctl has -+ returned without error. Hence, there is no need for another -+ <constant>KDBUS_CMD_RECV</constant> ioctl or anything else to -+ receive the reply. -+ </para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_FLAG_NEGOTIATE</constant></term> -+ <listitem> -+ <para> -+ Request a set of valid flags for this ioctl. When this bit is -+ set, no action is taken; the ioctl will fail with -+ <errorcode>-1</errorcode>, <varname>errno</varname> -+ is set to <constant>EPROTO</constant>. -+ Once the ioctl returned, the <varname>flags</varname> -+ field will have all bits set that the kernel recognizes as -+ valid for this command. -+ The <constant>KDBUS_FLAG_NEGOTIATE</constant> bit will be -+ cleared by the operation. -+ </para> -+ </listitem> -+ </varlistentry> -+ </variablelist> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>return_flags</varname></term> -+ <listitem><para> -+ Flags returned by the kernel. Currently unused and always set to -+ <constant>0</constant> by the kernel. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>msg_address</varname></term> -+ <listitem><para> -+ In this field, users have to provide a pointer to a message -+ (<type>struct kdbus_msg</type>) to send. See below for a -+ detailed description. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>reply</varname></term> -+ <listitem><para> -+ Only used for synchronous replies. See description of -+ <type>struct kdbus_cmd_recv</type> for more details. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>items</varname></term> -+ <listitem> -+ <para> -+ The following items are currently recognized. -+ </para> -+ <variablelist> -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_CANCEL_FD</constant></term> -+ <listitem> -+ <para> -+ When this optional item is passed in, and the call is -+ executed as SYNC call, the passed in file descriptor can be -+ used as alternative cancellation point. The kernel will call -+ <citerefentry> -+ <refentrytitle>poll</refentrytitle> -+ <manvolnum>2</manvolnum> -+ </citerefentry> -+ on this file descriptor, and once it reports any incoming -+ bytes, the blocking send operation will be canceled; the -+ blocking, synchronous ioctl call will return -+ <errorcode>-1</errorcode>, and <varname>errno</varname> will -+ be set to <errorname>ECANCELED</errorname>. -+ Any type of file descriptor on which -+ <citerefentry> -+ <refentrytitle>poll</refentrytitle> -+ <manvolnum>2</manvolnum> -+ </citerefentry> -+ can be called on can be used as payload to this item; for -+ example, an eventfd can be used for this purpose, see -+ <citerefentry> -+ <refentrytitle>eventfd</refentrytitle> -+ <manvolnum>2</manvolnum> -+ </citerefentry>. -+ For asynchronous message sending, this item is allowed but -+ ignored. -+ </para> -+ </listitem> -+ </varlistentry> -+ </variablelist> -+ <para> -+ Unrecognized items are rejected, and the ioctl will fail with -+ <varname>errno</varname> set to <constant>EINVAL</constant>. -+ </para> -+ </listitem> -+ </varlistentry> -+ </variablelist> -+ -+ <para> -+ The fields in this struct are described below. -+ The message referenced the <varname>msg_address</varname> above has -+ the following layout. -+ </para> -+ -+ <programlisting> -+struct kdbus_msg { -+ __u64 size; -+ __u64 flags; -+ __s64 priority; -+ __u64 dst_id; -+ __u64 src_id; -+ __u64 payload_type; -+ __u64 cookie; -+ __u64 timeout_ns; -+ __u64 cookie_reply; -+ struct kdbus_item items[0]; -+}; -+ </programlisting> -+ -+ <para>The fields in this struct are described below.</para> -+ -+ <variablelist> -+ <varlistentry> -+ <term><varname>size</varname></term> -+ <listitem><para> -+ The overall size of the struct, including its items. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>flags</varname></term> -+ <listitem><para>Flags to describe message details.</para> -+ <variablelist> -+ <varlistentry> -+ <term><constant>KDBUS_MSG_EXPECT_REPLY</constant></term> -+ <listitem> -+ <para> -+ Expect a reply to this message from the remote peer. 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 -+ <constant>CLOCK_MONOTONIC</constant>. -+ </para><para> -+ For a message to be accepted as reply, it must be a direct -+ message to the original sender (not a broadcast and not a -+ signal message), and its -+ <varname>kdbus_msg.reply_cookie</varname> must match the -+ previous message's <varname>kdbus_msg.cookie</varname>. -+ </para><para> -+ Expected replies also temporarily open the policy of the -+ sending connection, so the other peer is allowed to respond -+ within the given time window. -+ </para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_MSG_NO_AUTO_START</constant></term> -+ <listitem> -+ <para> -+ By default, when a message is sent to an activator -+ connection, the activator is notified and will start an -+ implementer. This flag inhibits that behavior. With this bit -+ set, and the remote being an activator, the ioctl will fail -+ with <varname>errno</varname> set to -+ <constant>EADDRNOTAVAIL</constant>. -+ </para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_FLAG_NEGOTIATE</constant></term> -+ <listitem> -+ <para> -+ Requests a set of valid flags for this ioctl. When this bit is -+ set, no action is taken; the ioctl will return -+ <errorcode>0</errorcode>, and the <varname>flags</varname> -+ field will have all bits set that are valid for this command. -+ The <constant>KDBUS_FLAG_NEGOTIATE</constant> bit will be -+ cleared by the operation. -+ </para> -+ </listitem> -+ </varlistentry> -+ </variablelist> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>priority</varname></term> -+ <listitem><para> -+ 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 field -+ should be set to <constant>0</constant>. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>dst_id</varname></term> -+ <listitem><para> -+ The numeric ID of the destination connection, or -+ <constant>KDBUS_DST_ID_BROADCAST</constant> -+ (~0ULL) to address every peer on the bus, or -+ <constant>KDBUS_DST_ID_NAME</constant> (0) to look -+ it up dynamically from the bus' name registry. -+ In the latter case, an item of type -+ <constant>KDBUS_ITEM_DST_NAME</constant> is mandatory. -+ Also see -+ <citerefentry> -+ <refentrytitle>kdbus.name</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ . -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>src_id</varname></term> -+ <listitem><para> -+ Upon return of the ioctl, this member will contain the sending -+ connection's numerical ID. Should be 0 at send time. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>payload_type</varname></term> -+ <listitem><para> -+ Type of the payload in the actual data records. Currently, only -+ <constant>KDBUS_PAYLOAD_DBUS</constant> is accepted as input value -+ of this field. When receiving messages that are generated by the -+ kernel (notifications), this field will contain -+ <constant>KDBUS_PAYLOAD_KERNEL</constant>. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>cookie</varname></term> -+ <listitem><para> -+ Cookie of this message, for later recognition. Also, when replying -+ to a message (see above), the <varname>cookie_reply</varname> -+ field must match this value. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>timeout_ns</varname></term> -+ <listitem><para> -+ If the message sent requires a reply from the remote peer (see above), -+ this field contains the timeout in absolute nanoseconds based on -+ <constant>CLOCK_MONOTONIC</constant>. Also see -+ <citerefentry> -+ <refentrytitle>clock_gettime</refentrytitle> -+ <manvolnum>2</manvolnum> -+ </citerefentry>. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>cookie_reply</varname></term> -+ <listitem><para> -+ If the message sent is a reply to another message, this field must -+ match the cookie of the formerly received message. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>items</varname></term> -+ <listitem> -+ <para> -+ A dynamically sized list of items to contain additional information. -+ The following items are expected/valid: -+ </para> -+ <variablelist> -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_PAYLOAD_VEC</constant></term> -+ <term><constant>KDBUS_ITEM_PAYLOAD_MEMFD</constant></term> -+ <term><constant>KDBUS_ITEM_FDS</constant></term> -+ <listitem> -+ <para> -+ Actual data records containing the payload. See section -+ "Passing of Payload Data". -+ </para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_BLOOM_FILTER</constant></term> -+ <listitem> -+ <para> -+ Bloom filter for matches (see below). -+ </para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ITEM_DST_NAME</constant></term> -+ <listitem> -+ <para> -+ Well-known name to send this message to. Required if -+ <varname>dst_id</varname> is set to -+ <constant>KDBUS_DST_ID_NAME</constant>. -+ If a connection holding the given name can't be found, -+ the ioctl will fail with <varname>errno</varname> set to -+ <constant>ESRCH</constant> is returned. -+ </para> -+ <para> -+ 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 programs to tie the message -+ sending to the condition that a name is currently owned by a -+ certain unique name. -+ </para> -+ </listitem> -+ </varlistentry> -+ </variablelist> -+ </listitem> -+ </varlistentry> -+ </variablelist> -+ -+ <para> -+ The message will be augmented by the requested metadata items when -+ queued into the receiver's pool. See -+ <citerefentry> -+ <refentrytitle>kdbus.connection</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ and -+ <citerefentry> -+ <refentrytitle>kdbus.item</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more information on metadata. -+ </para> -+ </refsect1> -+ -+ <refsect1> -+ <title>Receiving messages</title> -+ -+ <para> -+ Messages are received by the client with the -+ <constant>KDBUS_CMD_RECV</constant> ioctl. The endpoint file of the bus -+ supports <function>poll()/epoll()/select()</function>; when new messages -+ are available on the connection's file descriptor, -+ <constant>POLLIN</constant> is reported. For compatibility reasons, -+ <constant>POLLOUT</constant> is always reported as well. Note, however, -+ that the latter does not guarantee that a message can in fact be sent, as -+ this depends on how many pending messages the receiver has in its pool. -+ </para> -+ -+ <para> -+ With the <constant>KDBUS_CMD_RECV</constant> ioctl, a -+ <type>struct kdbus_cmd_recv</type> is used. -+ </para> -+ -+ <programlisting> -+struct kdbus_cmd_recv { -+ __u64 size; -+ __u64 flags; -+ __u64 return_flags; -+ __s64 priority; -+ __u64 dropped_msgs; -+ struct kdbus_msg_info msg; -+ struct kdbus_item items[0]; -+}; -+ </programlisting> -+ -+ <para>The fields in this struct are described below.</para> -+ -+ <variablelist> -+ <varlistentry> -+ <term><varname>size</varname></term> -+ <listitem><para> -+ The overall size of the struct, including its items. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>flags</varname></term> -+ <listitem><para>Flags to control the receive command.</para> -+ <variablelist> -+ <varlistentry> -+ <term><constant>KDBUS_RECV_PEEK</constant></term> -+ <listitem> -+ <para> -+ 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. -+ </para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_RECV_DROP</constant></term> -+ <listitem> -+ <para> -+ Drop the next message without doing anything else with it, -+ and free the pool slice. This a short-cut for -+ <constant>KDBUS_RECV_PEEK</constant> and -+ <constant>KDBUS_CMD_FREE</constant>. -+ </para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_RECV_USE_PRIORITY</constant></term> -+ <listitem> -+ <para> -+ Dequeue the messages ordered by their priority, and filtering -+ them with the priority field (see below). -+ </para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_FLAG_NEGOTIATE</constant></term> -+ <listitem> -+ <para> -+ Request a set of valid flags for this ioctl. When this bit is -+ set, no action is taken; the ioctl will fail with -+ <errorcode>-1</errorcode>, <varname>errno</varname> -+ is set to <constant>EPROTO</constant>. -+ Once the ioctl returned, the <varname>flags</varname> -+ field will have all bits set that the kernel recognizes as -+ valid for this command. -+ </para> -+ </listitem> -+ </varlistentry> -+ </variablelist> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>return_flags</varname></term> -+ <listitem><para> -+ Flags returned by the kernel. If the <varname>dropped_msgs</varname> -+ field is non-zero, <constant>KDBUS_RECV_RETURN_DROPPED_MSGS</constant> -+ is set. If a file descriptor could not be installed, the -+ <constant>KDBUS_RECV_RETURN_INCOMPLETE_FDS</constant> flag is set. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>priority</varname></term> -+ <listitem><para> -+ With <constant>KDBUS_RECV_USE_PRIORITY</constant> set in -+ <varname>flags</varname>, messages will be dequeued ordered by their -+ priority, starting with the highest value. Also, messages will be -+ filtered by the value given in this field, so the returned message -+ will at least have the requested priority. If no such message is -+ waiting in the queue, the ioctl will fail, and -+ <varname>errno</varname> will be set to <constant>EAGAIN</constant>. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>dropped_msgs</varname></term> -+ <listitem><para> -+ Whenever a message with <constant>KDBUS_MSG_SIGNAL</constant> is sent -+ but cannot be queued on a peer (e.g., as it contains FDs but the peer -+ does not support FDs, or there is no space left in the peer's pool..) -+ the 'dropped_msgs' counter of the peer is incremented. On the next -+ RECV ioctl, the 'dropped_msgs' field is copied into the ioctl struct -+ and cleared on the peer. If it was non-zero, the -+ <constant>KDBUS_RECV_RETURN_DROPPED_MSGS</constant> flag will be set -+ in <varname>return_flags</varname>. Note that this will only happen -+ if the ioctl succeeded or failed with <constant>EAGAIN</constant>. In -+ other error cases, the 'dropped_msgs' field of the peer is left -+ untouched. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>msg</varname></term> -+ <listitem><para> -+ Embedded struct containing information on the received message when -+ this command succeeded (see below). -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>items</varname></term> -+ <listitem><para> -+ Items to specify further details for the receive command. -+ Currently unused, and all items will be rejected with -+ <varname>errno</varname> set to <constant>EINVAL</constant>. -+ </para></listitem> -+ </varlistentry> -+ </variablelist> -+ -+ <para> -+ Both <type>struct kdbus_cmd_recv</type> and -+ <type>struct kdbus_cmd_send</type> embed -+ <type>struct kdbus_msg_info</type>. -+ For the <constant>KDBUS_CMD_SEND</constant> ioctl, it is used to catch -+ synchronous replies, if one was requested, and is unused otherwise. -+ </para> -+ -+ <programlisting> -+struct kdbus_msg_info { -+ __u64 offset; -+ __u64 msg_size; -+ __u64 return_flags; -+}; -+ </programlisting> -+ -+ <para>The fields in this struct are described below.</para> -+ -+ <variablelist> -+ <varlistentry> -+ <term><varname>offset</varname></term> -+ <listitem><para> -+ Upon return of the ioctl, this field contains the offset in the -+ receiver's memory pool. The memory must be freed with -+ <constant>KDBUS_CMD_FREE</constant>. See -+ <citerefentry> -+ <refentrytitle>kdbus.pool</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for further details. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>msg_size</varname></term> -+ <listitem><para> -+ Upon successful return of the ioctl, this field contains the size of -+ the allocated slice at offset <varname>offset</varname>. -+ It is the combination of the size of the stored -+ <type>struct kdbus_msg</type> object plus all appended VECs. -+ You can use it in combination with <varname>offset</varname> to map -+ a single message, instead of mapping the entire pool. See -+ <citerefentry> -+ <refentrytitle>kdbus.pool</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for further details. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>return_flags</varname></term> -+ <listitem> -+ <para> -+ Kernel-provided return flags. Currently, the following flags are -+ defined. -+ </para> -+ <variablelist> -+ <varlistentry> -+ <term><constant>KDBUS_RECV_RETURN_INCOMPLETE_FDS</constant></term> -+ <listitem> -+ <para> -+ The message contained memfds or file descriptors, and the -+ kernel failed to install one or more of them at receive time. -+ Most probably that happened because the maximum number of -+ file descriptors for the receiver's task were exceeded. -+ In such cases, the message is still delivered, so this is not -+ a fatal condition. File descriptors numbers inside the -+ <constant>KDBUS_ITEM_FDS</constant> item or memfd files -+ referenced by <constant>KDBUS_ITEM_PAYLOAD_MEMFD</constant> -+ items which could not be installed will be set to -+ <constant>-1</constant>. -+ </para> -+ </listitem> -+ </varlistentry> -+ </variablelist> -+ </listitem> -+ </varlistentry> -+ </variablelist> -+ -+ <para> -+ Unless <constant>KDBUS_RECV_DROP</constant> was passed, the -+ <varname>offset</varname> field contains the location of the new message -+ inside the receiver's pool after the <constant>KDBUS_CMD_RECV</constant> -+ ioctl was employed. The message is stored as <type>struct kdbus_msg</type> -+ at this offset, and can be interpreted with the semantics described above. -+ </para> -+ <para> -+ Also, if the connection allowed for file descriptor to be passed -+ (<constant>KDBUS_HELLO_ACCEPT_FD</constant>), and if the message contained -+ any, they will be installed into the receiving process when the -+ <constant>KDBUS_CMD_RECV</constant> ioctl is called. -+ <emphasis>memfds</emphasis> may always be part of the message payload. -+ The receiving task is obliged to close all file descriptors appropriately -+ once no longer needed. If <constant>KDBUS_RECV_PEEK</constant> is set, no -+ file descriptors are installed. This allows for peeking at a message, -+ looking at its metadata only and dropping it via -+ <constant>KDBUS_RECV_DROP</constant>, without installing any of the file -+ descriptors into the receiving process. -+ </para> -+ <para> -+ The caller is obliged to call the <constant>KDBUS_CMD_FREE</constant> -+ ioctl with the returned offset when the memory is no longer needed. -+ </para> -+ </refsect1> -+ -+ <refsect1> -+ <title>Notifications</title> -+ <para> -+ A kernel notification is a regular kdbus message with the following -+ details. -+ </para> -+ -+ <itemizedlist> -+ <listitem><para> -+ kdbus_msg.src_id == <constant>KDBUS_SRC_ID_KERNEL</constant> -+ </para></listitem> -+ <listitem><para> -+ kdbus_msg.dst_id == <constant>KDBUS_DST_ID_BROADCAST</constant> -+ </para></listitem> -+ <listitem><para> -+ kdbus_msg.payload_type == <constant>KDBUS_PAYLOAD_KERNEL</constant> -+ </para></listitem> -+ <listitem><para> -+ Has exactly one of the items attached that are described below. -+ </para></listitem> -+ <listitem><para> -+ Always has a timestamp item (<constant>KDBUS_ITEM_TIMESTAMP</constant>) -+ attached. -+ </para></listitem> -+ </itemizedlist> -+ -+ <para> -+ The kernel will notify its users of the following events. -+ </para> -+ -+ <itemizedlist> -+ <listitem><para> -+ When connection <emphasis>A</emphasis> is terminated while connection -+ <emphasis>B</emphasis> is waiting for a reply from it, connection -+ <emphasis>B</emphasis> is notified with a message with an item of -+ type <constant>KDBUS_ITEM_REPLY_DEAD</constant>. -+ </para></listitem> -+ -+ <listitem><para> -+ When connection <emphasis>A</emphasis> does not receive a reply from -+ connection <emphasis>B</emphasis> within the specified timeout window, -+ connection <emphasis>A</emphasis> will receive a message with an -+ item of type <constant>KDBUS_ITEM_REPLY_TIMEOUT</constant>. -+ </para></listitem> -+ -+ <listitem><para> -+ When an ordinary connection (not a monitor) is created on or removed -+ from a bus, messages with an item of type -+ <constant>KDBUS_ITEM_ID_ADD</constant> or -+ <constant>KDBUS_ITEM_ID_REMOVE</constant>, respectively, are delivered -+ to all bus members that match these messages through their match -+ database. Eavesdroppers (monitor connections) do not cause such -+ notifications to be sent. They are invisible on the bus. -+ </para></listitem> -+ -+ <listitem><para> -+ When a connection gains or loses ownership of a name, messages with an -+ item of type <constant>KDBUS_ITEM_NAME_ADD</constant>, -+ <constant>KDBUS_ITEM_NAME_REMOVE</constant> or -+ <constant>KDBUS_ITEM_NAME_CHANGE</constant> are delivered to all bus -+ members that match these messages through their match database. -+ </para></listitem> -+ </itemizedlist> -+ </refsect1> -+ -+ <refsect1> -+ <title>Return value</title> -+ <para> -+ On success, all mentioned ioctl commands return <errorcode>0</errorcode>; -+ on error, <errorcode>-1</errorcode> is returned, and -+ <varname>errno</varname> is set to indicate the error. -+ If the issued ioctl is illegal for the file descriptor used, -+ <varname>errno</varname> will be set to <constant>ENOTTY</constant>. -+ </para> -+ -+ <refsect2> -+ <title> -+ <constant>KDBUS_CMD_SEND</constant> may fail with the following -+ errors -+ </title> -+ -+ <variablelist> -+ <varlistentry> -+ <term><constant>EOPNOTSUPP</constant></term> -+ <listitem><para> -+ The connection is not an ordinary connection, or the passed -+ file descriptors in <constant>KDBUS_ITEM_FDS</constant> item are -+ either kdbus handles or unix domain sockets. Both are currently -+ unsupported. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>EINVAL</constant></term> -+ <listitem><para> -+ The submitted payload type is -+ <constant>KDBUS_PAYLOAD_KERNEL</constant>, -+ <constant>KDBUS_MSG_EXPECT_REPLY</constant> was set without timeout -+ or cookie values, <constant>KDBUS_SEND_SYNC_REPLY</constant> was -+ set without <constant>KDBUS_MSG_EXPECT_REPLY</constant>, an invalid -+ item was supplied, <constant>src_id</constant> was non-zero and was -+ different from the current connection's ID, a supplied memfd had a -+ size of 0, or a string was not properly null-terminated. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>ENOTUNIQ</constant></term> -+ <listitem><para> -+ The supplied destination is -+ <constant>KDBUS_DST_ID_BROADCAST</constant> and either -+ file descriptors were passed, or -+ <constant>KDBUS_MSG_EXPECT_REPLY</constant> was set, -+ or a timeout was given. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>E2BIG</constant></term> -+ <listitem><para> -+ Too many items -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>EMSGSIZE</constant></term> -+ <listitem><para> -+ The size of the message header and items or the payload vector -+ is excessive. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>EEXIST</constant></term> -+ <listitem><para> -+ Multiple <constant>KDBUS_ITEM_FDS</constant>, -+ <constant>KDBUS_ITEM_BLOOM_FILTER</constant> or -+ <constant>KDBUS_ITEM_DST_NAME</constant> items were supplied. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>EBADF</constant></term> -+ <listitem><para> -+ The supplied <constant>KDBUS_ITEM_FDS</constant> or -+ <constant>KDBUS_ITEM_PAYLOAD_MEMFD</constant> items -+ contained an illegal file descriptor. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>EMEDIUMTYPE</constant></term> -+ <listitem><para> -+ The supplied memfd is not a sealed kdbus memfd. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>EMFILE</constant></term> -+ <listitem><para> -+ Too many file descriptors inside a -+ <constant>KDBUS_ITEM_FDS</constant>. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>EBADMSG</constant></term> -+ <listitem><para> -+ An item had illegal size, both a <constant>dst_id</constant> and a -+ <constant>KDBUS_ITEM_DST_NAME</constant> was given, or both a name -+ and a bloom filter was given. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>ETXTBSY</constant></term> -+ <listitem><para> -+ The supplied kdbus memfd file cannot be sealed or the seal -+ was removed, because it is shared with other processes or -+ still mapped with -+ <citerefentry> -+ <refentrytitle>mmap</refentrytitle> -+ <manvolnum>2</manvolnum> -+ </citerefentry>. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>ECOMM</constant></term> -+ <listitem><para> -+ A peer does not accept the file descriptors addressed to it. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>EFAULT</constant></term> -+ <listitem><para> -+ The supplied bloom filter size was not 64-bit aligned, or supplied -+ memory could not be accessed by the kernel. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>EDOM</constant></term> -+ <listitem><para> -+ The supplied bloom filter size did not match the bloom filter -+ size of the bus. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>EDESTADDRREQ</constant></term> -+ <listitem><para> -+ <constant>dst_id</constant> was set to -+ <constant>KDBUS_DST_ID_NAME</constant>, but no -+ <constant>KDBUS_ITEM_DST_NAME</constant> was attached. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>ESRCH</constant></term> -+ <listitem><para> -+ The name to look up was not found in the name registry. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>EADDRNOTAVAIL</constant></term> -+ <listitem><para> -+ <constant>KDBUS_MSG_NO_AUTO_START</constant> was given but the -+ destination connection is an activator. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>ENXIO</constant></term> -+ <listitem><para> -+ The passed numeric destination connection ID couldn't be found, -+ or is not connected. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>ECONNRESET</constant></term> -+ <listitem><para> -+ The destination connection is no longer active. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>ETIMEDOUT</constant></term> -+ <listitem><para> -+ Timeout while synchronously waiting for a reply. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>EINTR</constant></term> -+ <listitem><para> -+ Interrupted system call while synchronously waiting for a reply. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>EPIPE</constant></term> -+ <listitem><para> -+ When sending a message, a synchronous reply from the receiving -+ connection was expected but the connection died before answering. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>ENOBUFS</constant></term> -+ <listitem><para> -+ Too many pending messages on the receiver side. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>EREMCHG</constant></term> -+ <listitem><para> -+ Both a well-known name and a unique name (ID) was given, but -+ the name is not currently owned by that connection. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>EXFULL</constant></term> -+ <listitem><para> -+ The memory pool of the receiver is full. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>EREMOTEIO</constant></term> -+ <listitem><para> -+ While synchronously waiting for a reply, the remote peer -+ failed with an I/O error. -+ </para></listitem> -+ </varlistentry> -+ </variablelist> -+ </refsect2> -+ -+ <refsect2> -+ <title> -+ <constant>KDBUS_CMD_RECV</constant> may fail with the following -+ errors -+ </title> -+ -+ <variablelist> -+ <varlistentry> -+ <term><constant>EOPNOTSUPP</constant></term> -+ <listitem><para> -+ The connection is not an ordinary connection, or the passed -+ file descriptors are either kdbus handles or unix domain -+ sockets. Both are currently unsupported. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>EINVAL</constant></term> -+ <listitem><para> -+ Invalid flags or offset. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>EAGAIN</constant></term> -+ <listitem><para> -+ No message found in the queue -+ </para></listitem> -+ </varlistentry> -+ </variablelist> -+ </refsect2> -+ </refsect1> -+ -+ <refsect1> -+ <title>See Also</title> -+ <simplelist type="inline"> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.bus</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.connection</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.endpoint</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.fs</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.item</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.name</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.pool</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>clock_gettime</refentrytitle> -+ <manvolnum>2</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>ioctl</refentrytitle> -+ <manvolnum>2</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>poll</refentrytitle> -+ <manvolnum>2</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>select</refentrytitle> -+ <manvolnum>2</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>epoll</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>eventfd</refentrytitle> -+ <manvolnum>2</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>memfd_create</refentrytitle> -+ <manvolnum>2</manvolnum> -+ </citerefentry> -+ </member> -+ </simplelist> -+ </refsect1> -+</refentry> -diff --git a/Documentation/kdbus/kdbus.name.xml b/Documentation/kdbus/kdbus.name.xml -new file mode 100644 -index 000000000000..3f5f6a6c5ed6 ---- /dev/null -+++ b/Documentation/kdbus/kdbus.name.xml -@@ -0,0 +1,711 @@ -+<?xml version='1.0'?> <!--*-nxml-*--> -+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" -+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> -+ -+<refentry id="kdbus.name"> -+ -+ <refentryinfo> -+ <title>kdbus.name</title> -+ <productname>kdbus.name</productname> -+ </refentryinfo> -+ -+ <refmeta> -+ <refentrytitle>kdbus.name</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </refmeta> -+ -+ <refnamediv> -+ <refname>kdbus.name</refname> -+ <refpurpose>kdbus.name</refpurpose> -+ </refnamediv> -+ -+ <refsect1> -+ <title>Description</title> -+ <para> -+ Each -+ <citerefentry> -+ <refentrytitle>kdbus.bus</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ 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 <varname>kdbus_msg.dst_id</varname> set to -+ <constant>KDBUS_DST_ID_NAME</constant>, or when a registry dump is -+ requested with <constant>KDBUS_CMD_NAME_LIST</constant>. -+ </para> -+ -+ <para> -+ All of the below is subject to policy rules for <emphasis>SEE</emphasis> -+ and <emphasis>OWN</emphasis> permissions. See -+ <citerefentry> -+ <refentrytitle>kdbus.policy</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more information. -+ </para> -+ </refsect1> -+ -+ <refsect1> -+ <title>Name validity</title> -+ <para> -+ A name has to comply with the following rules in order to be considered -+ valid. -+ </para> -+ -+ <itemizedlist> -+ <listitem> -+ <para> -+ The name has two or more elements separated by a -+ '<literal>.</literal>' (period) character. -+ </para> -+ </listitem> -+ <listitem> -+ <para> -+ All elements must contain at least one character. -+ </para> -+ </listitem> -+ <listitem> -+ <para> -+ Each element must only contain the ASCII characters -+ <literal>[A-Z][a-z][0-9]_</literal> and must not begin with a -+ digit. -+ </para> -+ </listitem> -+ <listitem> -+ <para> -+ The name must contain at least one '<literal>.</literal>' (period) -+ character (and thus at least two elements). -+ </para> -+ </listitem> -+ <listitem> -+ <para> -+ The name must not begin with a '<literal>.</literal>' (period) -+ character. -+ </para> -+ </listitem> -+ <listitem> -+ <para> -+ The name must not exceed <constant>255</constant> characters in -+ length. -+ </para> -+ </listitem> -+ </itemizedlist> -+ </refsect1> -+ -+ <refsect1> -+ <title>Acquiring a name</title> -+ <para> -+ To acquire a name, a client uses the -+ <constant>KDBUS_CMD_NAME_ACQUIRE</constant> ioctl with -+ <type>struct kdbus_cmd</type> as argument. -+ </para> -+ -+ <programlisting> -+struct kdbus_cmd { -+ __u64 size; -+ __u64 flags; -+ __u64 return_flags; -+ struct kdbus_item items[0]; -+}; -+ </programlisting> -+ -+ <para>The fields in this struct are described below.</para> -+ -+ <variablelist> -+ <varlistentry> -+ <term><varname>size</varname></term> -+ <listitem><para> -+ The overall size of the struct, including its items. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>flags</varname></term> -+ <listitem><para>Flags to control details in the name acquisition.</para> -+ <variablelist> -+ <varlistentry> -+ <term><constant>KDBUS_NAME_REPLACE_EXISTING</constant></term> -+ <listitem> -+ <para> -+ Acquiring a name that is already present usually fails, -+ unless this flag is set in the call, and -+ <constant>KDBUS_NAME_ALLOW_REPLACEMENT</constant> (see below) -+ was set when the current owner of the name acquired it, or -+ if the current owner is an activator connection (see -+ <citerefentry> -+ <refentrytitle>kdbus.connection</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry>). -+ </para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_NAME_ALLOW_REPLACEMENT</constant></term> -+ <listitem> -+ <para> -+ Allow other connections to take over this name. When this -+ happens, the former owner of the connection will be notified -+ of the name loss. -+ </para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_NAME_QUEUE</constant></term> -+ <listitem> -+ <para> -+ A name that is already acquired by a connection can not be -+ acquired again (unless the -+ <constant>KDBUS_NAME_ALLOW_REPLACEMENT</constant> flag was -+ set during acquisition; see above). -+ 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. -+ </para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_FLAG_NEGOTIATE</constant></term> -+ <listitem> -+ <para> -+ Request a set of valid flags for this ioctl. When this bit is -+ set, no action is taken; the ioctl will fail with -+ <errorcode>-1</errorcode>, and <varname>errno</varname> -+ is set to <constant>EPROTO</constant>. -+ Once the ioctl returned, the <varname>flags</varname> -+ field will have all bits set that the kernel recognizes as -+ valid for this command. -+ The <constant>KDBUS_FLAG_NEGOTIATE</constant> bit will be -+ cleared by the operation. -+ </para> -+ </listitem> -+ </varlistentry> -+ </variablelist> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>return_flags</varname></term> -+ <listitem> -+ <para> -+ Flags returned by the kernel. Currently, the following may be -+ returned by the kernel. -+ </para> -+ <variablelist> -+ <varlistentry> -+ <term><constant>KDBUS_NAME_IN_QUEUE</constant></term> -+ <listitem> -+ <para> -+ The name was not acquired yet, but the connection was -+ placed in the queue of peers waiting for the name. -+ This can only happen if <constant>KDBUS_NAME_QUEUE</constant> -+ was set in the <varname>flags</varname> member (see above). -+ The connection will receive a name owner change notification -+ once the current owner has given up the name and its -+ ownership was transferred. -+ </para> -+ </listitem> -+ </varlistentry> -+ </variablelist> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>items</varname></term> -+ <listitem> -+ <para> -+ Items to submit the name. Currently, one item of type -+ <constant>KDBUS_ITEM_NAME</constant> is expected and allowed, and -+ the contained string must be a valid bus name. -+ <constant>KDBUS_ITEM_NEGOTIATE</constant> may be used to probe for -+ valid item types. See -+ <citerefentry> -+ <refentrytitle>kdbus.item</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for a detailed description of how this item is used. -+ </para> -+ <para> -+ Unrecognized items are rejected, and the ioctl will fail with -+ <varname>errno</varname> set to <errorname>>EINVAL</errorname>. -+ </para> -+ </listitem> -+ </varlistentry> -+ </variablelist> -+ </refsect1> -+ -+ <refsect1> -+ <title>Releasing a name</title> -+ <para> -+ A connection may release a name explicitly with the -+ <constant>KDBUS_CMD_NAME_RELEASE</constant> ioctl. If the connection was -+ an implementer 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 first one in the queue (the oldest entry) will become -+ the new owner. The same happens implicitly for all names once a -+ connection terminates. See -+ <citerefentry> -+ <refentrytitle>kdbus.connection</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more information on connections. -+ </para> -+ <para> -+ The <constant>KDBUS_CMD_NAME_RELEASE</constant> ioctl uses the same data -+ structure as the acquisition call -+ (<constant>KDBUS_CMD_NAME_ACQUIRE</constant>), -+ but with slightly different field usage. -+ </para> -+ -+ <programlisting> -+struct kdbus_cmd { -+ __u64 size; -+ __u64 flags; -+ __u64 return_flags; -+ struct kdbus_item items[0]; -+}; -+ </programlisting> -+ -+ <para>The fields in this struct are described below.</para> -+ -+ <variablelist> -+ <varlistentry> -+ <term><varname>size</varname></term> -+ <listitem><para> -+ The overall size of the struct, including its items. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>flags</varname></term> -+ <listitem><para> -+ Flags to the command. Currently unused. -+ <constant>KDBUS_FLAG_NEGOTIATE</constant> is accepted to probe for -+ valid flags. If set, the ioctl will return <errorcode>0</errorcode>, -+ and the <varname>flags</varname> field is set to -+ <constant>0</constant>. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>return_flags</varname></term> -+ <listitem><para> -+ Flags returned by the kernel. Currently unused and always set to -+ <constant>0</constant> by the kernel. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>items</varname></term> -+ <listitem> -+ <para> -+ Items to submit the name. Currently, one item of type -+ <constant>KDBUS_ITEM_NAME</constant> is expected and allowed, and -+ the contained string must be a valid bus name. -+ <constant>KDBUS_ITEM_NEGOTIATE</constant> may be used to probe for -+ valid item types. See -+ <citerefentry> -+ <refentrytitle>kdbus.item</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for a detailed description of how this item is used. -+ </para> -+ <para> -+ Unrecognized items are rejected, and the ioctl will fail with -+ <varname>errno</varname> set to <constant>EINVAL</constant>. -+ </para> -+ </listitem> -+ </varlistentry> -+ </variablelist> -+ </refsect1> -+ -+ <refsect1> -+ <title>Dumping the name registry</title> -+ <para> -+ A connection may request a complete or filtered dump of currently active -+ bus names with the <constant>KDBUS_CMD_LIST</constant> ioctl, which -+ takes a <type>struct kdbus_cmd_list</type> as argument. -+ </para> -+ -+ <programlisting> -+struct kdbus_cmd_list { -+ __u64 flags; -+ __u64 return_flags; -+ __u64 offset; -+}; -+ </programlisting> -+ -+ <para>The fields in this struct are described below.</para> -+ -+ <variablelist> -+ <varlistentry> -+ <term><varname>flags</varname></term> -+ <listitem> -+ <para> -+ Any combination of flags to specify which names should be dumped. -+ </para> -+ <variablelist> -+ <varlistentry> -+ <term><constant>KDBUS_LIST_UNIQUE</constant></term> -+ <listitem> -+ <para> -+ List the unique (numeric) IDs of the connection, whether it -+ owns a name or not. -+ </para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_LIST_NAMES</constant></term> -+ <listitem> -+ <para> -+ List well-known names stored in the database which are -+ actively owned by a real connection (not an activator). -+ </para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_LIST_ACTIVATORS</constant></term> -+ <listitem> -+ <para> -+ List names that are owned by an activator. -+ </para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_LIST_QUEUED</constant></term> -+ <listitem> -+ <para> -+ List connections that are not yet owning a name but are -+ waiting for it to become available. -+ </para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_FLAG_NEGOTIATE</constant></term> -+ <listitem> -+ <para> -+ Request a set of valid flags for this ioctl. When this bit is -+ set, no action is taken; the ioctl will fail with -+ <errorcode>-1</errorcode>, and <varname>errno</varname> -+ is set to <constant>EPROTO</constant>. -+ Once the ioctl returned, the <varname>flags</varname> -+ field will have all bits set that the kernel recognizes as -+ valid for this command. -+ The <constant>KDBUS_FLAG_NEGOTIATE</constant> bit will be -+ cleared by the operation. -+ </para> -+ </listitem> -+ </varlistentry> -+ </variablelist> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>return_flags</varname></term> -+ <listitem><para> -+ Flags returned by the kernel. Currently unused and always set to -+ <constant>0</constant> by the kernel. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>offset</varname></term> -+ <listitem><para> -+ When the ioctl returns successfully, the offset to the name registry -+ dump inside the connection's pool will be stored in this field. -+ </para></listitem> -+ </varlistentry> -+ </variablelist> -+ -+ <para> -+ The returned list of names is stored in a <type>struct kdbus_list</type> -+ that in turn contains an array of type <type>struct kdbus_info</type>, -+ The array-size in bytes is given as <varname>list_size</varname>. -+ The fields inside <type>struct kdbus_info</type> is described next. -+ </para> -+ -+ <programlisting> -+struct kdbus_info { -+ __u64 size; -+ __u64 id; -+ __u64 flags; -+ struct kdbus_item items[0]; -+}; -+ </programlisting> -+ -+ <para>The fields in this struct are described below.</para> -+ -+ <variablelist> -+ <varlistentry> -+ <term><varname>size</varname></term> -+ <listitem><para> -+ The overall size of the struct, including its items. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>id</varname></term> -+ <listitem><para> -+ The owning connection's unique ID. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>flags</varname></term> -+ <listitem><para> -+ The flags of the owning connection. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>items</varname></term> -+ <listitem> -+ <para> -+ Items containing the actual name. Currently, one item of type -+ <constant>KDBUS_ITEM_OWNED_NAME</constant> will be attached, -+ including the name's flags. In that item, the flags field of the -+ name may carry the following bits: -+ </para> -+ <variablelist> -+ <varlistentry> -+ <term><constant>KDBUS_NAME_ALLOW_REPLACEMENT</constant></term> -+ <listitem> -+ <para> -+ Other connections are allowed to take over this name from the -+ connection that owns it. -+ </para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_NAME_IN_QUEUE</constant></term> -+ <listitem> -+ <para> -+ When retrieving a list of currently acquired names in the -+ registry, this flag indicates whether the connection -+ actually owns the name or is currently waiting for it to -+ become available. -+ </para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_NAME_ACTIVATOR</constant></term> -+ <listitem> -+ <para> -+ An activator connection owns a name as a placeholder for an -+ implementer, which is started on demand by programs as soon -+ as the first message arrives. There's some more information -+ on this topic in -+ <citerefentry> -+ <refentrytitle>kdbus.connection</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ . -+ </para> -+ <para> -+ In contrast to -+ <constant>KDBUS_NAME_REPLACE_EXISTING</constant>, -+ 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 implementer connection terminates. -+ </para> -+ <para> -+ This flag can not be used when acquiring a name, but is -+ implicitly set through <constant>KDBUS_CMD_HELLO</constant> -+ with <constant>KDBUS_HELLO_ACTIVATOR</constant> set in -+ <varname>kdbus_cmd_hello.conn_flags</varname>. -+ </para> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_FLAG_NEGOTIATE</constant></term> -+ <listitem> -+ <para> -+ Requests a set of valid flags for this ioctl. When this bit is -+ set, no action is taken; the ioctl will return -+ <errorcode>0</errorcode>, and the <varname>flags</varname> -+ field will have all bits set that are valid for this command. -+ The <constant>KDBUS_FLAG_NEGOTIATE</constant> bit will be -+ cleared by the operation. -+ </para> -+ </listitem> -+ </varlistentry> -+ </variablelist> -+ </listitem> -+ </varlistentry> -+ </variablelist> -+ -+ <para> -+ The returned buffer must be freed with the -+ <constant>KDBUS_CMD_FREE</constant> ioctl when the user is finished with -+ it. See -+ <citerefentry> -+ <refentrytitle>kdbus.pool</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more information. -+ </para> -+ </refsect1> -+ -+ <refsect1> -+ <title>Return value</title> -+ <para> -+ On success, all mentioned ioctl commands return <errorcode>0</errorcode>; -+ on error, <errorcode>-1</errorcode> is returned, and -+ <varname>errno</varname> is set to indicate the error. -+ If the issued ioctl is illegal for the file descriptor used, -+ <varname>errno</varname> will be set to <constant>ENOTTY</constant>. -+ </para> -+ -+ <refsect2> -+ <title> -+ <constant>KDBUS_CMD_NAME_ACQUIRE</constant> may fail with the following -+ errors -+ </title> -+ -+ <variablelist> -+ <varlistentry> -+ <term><constant>EINVAL</constant></term> -+ <listitem><para> -+ Illegal command flags, illegal name provided, or an activator -+ tried to acquire a second name. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>EPERM</constant></term> -+ <listitem><para> -+ Policy prohibited name ownership. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>EALREADY</constant></term> -+ <listitem><para> -+ Connection already owns that name. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>EEXIST</constant></term> -+ <listitem><para> -+ The name already exists and can not be taken over. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>E2BIG</constant></term> -+ <listitem><para> -+ The maximum number of well-known names per connection is exhausted. -+ </para></listitem> -+ </varlistentry> -+ </variablelist> -+ </refsect2> -+ -+ <refsect2> -+ <title> -+ <constant>KDBUS_CMD_NAME_RELEASE</constant> -+ may fail with the following errors -+ </title> -+ -+ <variablelist> -+ <varlistentry> -+ <term><constant>EINVAL</constant></term> -+ <listitem><para> -+ Invalid command flags, or invalid name provided. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>ESRCH</constant></term> -+ <listitem><para> -+ Name is not found in the registry. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>EADDRINUSE</constant></term> -+ <listitem><para> -+ Name is owned by a different connection and can't be released. -+ </para></listitem> -+ </varlistentry> -+ </variablelist> -+ </refsect2> -+ -+ <refsect2> -+ <title> -+ <constant>KDBUS_CMD_LIST</constant> may fail with the following -+ errors -+ </title> -+ -+ <variablelist> -+ <varlistentry> -+ <term><constant>EINVAL</constant></term> -+ <listitem><para> -+ Invalid command flags -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>ENOBUFS</constant></term> -+ <listitem><para> -+ No available memory in the connection's pool. -+ </para></listitem> -+ </varlistentry> -+ </variablelist> -+ </refsect2> -+ </refsect1> -+ -+ <refsect1> -+ <title>See Also</title> -+ <simplelist type="inline"> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.bus</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.connection</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.item</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.policy</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.pool</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ </simplelist> -+ </refsect1> -+</refentry> -diff --git a/Documentation/kdbus/kdbus.policy.xml b/Documentation/kdbus/kdbus.policy.xml -new file mode 100644 -index 000000000000..67324163880a ---- /dev/null -+++ b/Documentation/kdbus/kdbus.policy.xml -@@ -0,0 +1,406 @@ -+<?xml version='1.0'?> <!--*-nxml-*--> -+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" -+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> -+ -+<refentry id="kdbus.policy"> -+ -+ <refentryinfo> -+ <title>kdbus.policy</title> -+ <productname>kdbus.policy</productname> -+ </refentryinfo> -+ -+ <refmeta> -+ <refentrytitle>kdbus.policy</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </refmeta> -+ -+ <refnamediv> -+ <refname>kdbus.policy</refname> -+ <refpurpose>kdbus policy</refpurpose> -+ </refnamediv> -+ -+ <refsect1> -+ <title>Description</title> -+ -+ <para> -+ A kdbus policy restricts the possibilities of connections to own, see and -+ talk to well-known names. A policy can be associated with a bus (through a -+ policy holder connection) or a custom endpoint. kdbus stores its policy -+ information in a database that can be accessed through the following -+ ioctl commands: -+ </para> -+ -+ <variablelist> -+ <varlistentry> -+ <term><constant>KDBUS_CMD_HELLO</constant></term> -+ <listitem><para> -+ When creating, or updating, a policy holder connection. See -+ <citerefentry> -+ <refentrytitle>kdbus.connection</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry>. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_CMD_ENDPOINT_MAKE</constant></term> -+ <term><constant>KDBUS_CMD_ENDPOINT_UPDATE</constant></term> -+ <listitem><para> -+ When creating, or updating, a bus custom endpoint. See -+ <citerefentry> -+ <refentrytitle>kdbus.endpoint</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry>. -+ </para></listitem> -+ </varlistentry> -+ </variablelist> -+ -+ <para> -+ In all cases, the name and policy access information is stored in items -+ of type <constant>KDBUS_ITEM_NAME</constant> and -+ <constant>KDBUS_ITEM_POLICY_ACCESS</constant>. For this transport, the -+ following rules apply. -+ </para> -+ -+ <itemizedlist> -+ <listitem> -+ <para> -+ An item of type <constant>KDBUS_ITEM_NAME</constant> must be followed -+ by at least one <constant>KDBUS_ITEM_POLICY_ACCESS</constant> item. -+ </para> -+ </listitem> -+ -+ <listitem> -+ <para> -+ An item of type <constant>KDBUS_ITEM_NAME</constant> can be followed -+ by an arbitrary number of -+ <constant>KDBUS_ITEM_POLICY_ACCESS</constant> items. -+ </para> -+ </listitem> -+ -+ <listitem> -+ <para> -+ An arbitrary number of groups of names and access levels can be given. -+ </para> -+ </listitem> -+ </itemizedlist> -+ -+ <para> -+ Names passed in items of type <constant>KDBUS_ITEM_NAME</constant> must -+ comply to the rules of valid kdbus.name. See -+ <citerefentry> -+ <refentrytitle>kdbus.name</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more information. -+ -+ The payload of an item of type -+ <constant>KDBUS_ITEM_POLICY_ACCESS</constant> is defined by the following -+ struct. For more information on the layout of items, please refer to -+ <citerefentry> -+ <refentrytitle>kdbus.item</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry>. -+ </para> -+ -+ <programlisting> -+struct kdbus_policy_access { -+ __u64 type; -+ __u64 access; -+ __u64 id; -+}; -+ </programlisting> -+ -+ <para>The fields in this struct are described below.</para> -+ -+ <variablelist> -+ <varlistentry> -+ <term><varname>type</varname></term> -+ <listitem> -+ <para> -+ One of the following. -+ </para> -+ -+ <variablelist> -+ <varlistentry> -+ <term><constant>KDBUS_POLICY_ACCESS_USER</constant></term> -+ <listitem><para> -+ Grant access to a user with the UID stored in the -+ <varname>id</varname> field. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_POLICY_ACCESS_GROUP</constant></term> -+ <listitem><para> -+ Grant access to a user with the GID stored in the -+ <varname>id</varname> field. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_POLICY_ACCESS_WORLD</constant></term> -+ <listitem><para> -+ Grant access to everyone. The <varname>id</varname> field -+ is ignored. -+ </para></listitem> -+ </varlistentry> -+ </variablelist> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>access</varname></term> -+ <listitem> -+ <para> -+ The access to grant. One of the following. -+ </para> -+ -+ <variablelist> -+ <varlistentry> -+ <term><constant>KDBUS_POLICY_SEE</constant></term> -+ <listitem><para> -+ Allow the name to be seen. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_POLICY_TALK</constant></term> -+ <listitem><para> -+ Allow the name to be talked to. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_POLICY_OWN</constant></term> -+ <listitem><para> -+ Allow the name to be owned. -+ </para></listitem> -+ </varlistentry> -+ </variablelist> -+ </listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>id</varname></term> -+ <listitem><para> -+ For <constant>KDBUS_POLICY_ACCESS_USER</constant>, stores the UID. -+ For <constant>KDBUS_POLICY_ACCESS_GROUP</constant>, stores the GID. -+ </para></listitem> -+ </varlistentry> -+ -+ </variablelist> -+ -+ <para> -+ All endpoints of buses have an empty policy database by default. -+ Therefore, unless policy rules are added, all operations will also be -+ denied by default. Also see -+ <citerefentry> -+ <refentrytitle>kdbus.endpoint</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry>. -+ </para> -+ </refsect1> -+ -+ <refsect1> -+ <title>Wildcard names</title> -+ <para> -+ Policy holder connections may upload names that contain the wildcard -+ suffix (<literal>".*"</literal>). Such a policy entry is effective for -+ every well-known name that extends the provided name by exactly one more -+ level. -+ -+ For example, the name <literal>foo.bar.*</literal> matches both -+ <literal>"foo.bar.baz"</literal> and -+ <literal>"foo.bar.bazbaz"</literal> are, but not -+ <literal>"foo.bar.baz.baz"</literal>. -+ -+ 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. -+ </para> -+ </refsect1> -+ -+ <refsect1> -+ <title>Privileged connections</title> -+ <para> -+ The policy database is overruled when action is taken by a privileged -+ connection. Please refer to -+ <citerefentry> -+ <refentrytitle>kdbus.connection</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more information on what makes a connection privileged. -+ </para> -+ </refsect1> -+ -+ <refsect1> -+ <title>Examples</title> -+ <para> -+ For instance, a set of policy rules may look like this: -+ </para> -+ -+ <programlisting> -+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 -+ </programlisting> -+ -+ <para> -+ 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. -+ </para> -+ </refsect1> -+ -+ <refsect1> -+ <title>TALK access and multiple well-known names per connection</title> -+ <para> -+ Note that TALK access is checked against all names of a connection. For -+ example, if a connection owns both <constant>'org.foo.bar'</constant> and -+ <constant>'org.blah.baz'</constant>, and the policy database allows -+ <constant>'org.blah.baz'</constant> to be talked to by WORLD, then this -+ permission is also granted to <constant>'org.foo.bar'</constant>. That -+ might sound illogical, but after all, we allow messages to be directed to -+ either the ID 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. -+ -+ For broadcast messages, the receiver needs TALK permissions to the sender -+ to receive the broadcast. -+ </para> -+ <para> -+ Both the endpoint and the bus policy databases are consulted to allow -+ name registry listing, owning a well-known name and message delivery. -+ If either one fails, the operation is failed with -+ <varname>errno</varname> set to <constant>EPERM</constant>. -+ -+ 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. -+ -+ Also see -+ <citerefentry> -+ <refentrytitle>kdbus.match</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry>. -+ </para> -+ </refsect1> -+ -+ <refsect1> -+ <title>Implicit policies</title> -+ <para> -+ Depending on the type of the endpoint, a set of implicit rules that -+ override installed policies might be enforced. -+ -+ On default endpoints, the following set is enforced and checked before -+ any user-supplied policy is checked. -+ </para> -+ -+ <itemizedlist> -+ <listitem> -+ <para> -+ Privileged connections always override any installed policy. Those -+ connections could easily install their own policies, so there is no -+ reason to enforce installed policies. -+ </para> -+ </listitem> -+ <listitem> -+ <para> -+ Connections can always talk to connections of the same user. This -+ includes broadcast messages. -+ </para> -+ </listitem> -+ </itemizedlist> -+ -+ <para> -+ Custom endpoints have stricter policies. The following rules apply: -+ </para> -+ -+ <itemizedlist> -+ <listitem> -+ <para> -+ Policy rules are always enforced, even if the connection is a -+ privileged connection. -+ </para> -+ </listitem> -+ <listitem> -+ <para> -+ Policy rules are always enforced for <constant>TALK</constant> access, -+ even if both ends are running under the same user. This includes -+ broadcast messages. -+ </para> -+ </listitem> -+ <listitem> -+ <para> -+ To restrict the set of names that can be seen, endpoint policies can -+ install <constant>SEE</constant> policies. -+ </para> -+ </listitem> -+ </itemizedlist> -+ </refsect1> -+ -+ <refsect1> -+ <title>See Also</title> -+ <simplelist type="inline"> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.bus</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.endpoint</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.fs</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.item</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.message</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.name</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.pool</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ </simplelist> -+ </refsect1> -+</refentry> -diff --git a/Documentation/kdbus/kdbus.pool.xml b/Documentation/kdbus/kdbus.pool.xml -new file mode 100644 -index 000000000000..05fd01902ad4 ---- /dev/null -+++ b/Documentation/kdbus/kdbus.pool.xml -@@ -0,0 +1,320 @@ -+<?xml version='1.0'?> <!--*-nxml-*--> -+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" -+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> -+ -+<refentry id="kdbus.pool"> -+ -+ <refentryinfo> -+ <title>kdbus.pool</title> -+ <productname>kdbus.pool</productname> -+ </refentryinfo> -+ -+ <refmeta> -+ <refentrytitle>kdbus.pool</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </refmeta> -+ -+ <refnamediv> -+ <refname>kdbus.pool</refname> -+ <refpurpose>kdbus pool</refpurpose> -+ </refnamediv> -+ -+ <refsect1> -+ <title>Description</title> -+ <para> -+ A pool for data received from the kernel is installed for every -+ <emphasis>connection</emphasis> of the <emphasis>bus</emphasis>, and -+ is sized according to the information stored in the -+ <varname>pool_size</varname> member of <type>struct kdbus_cmd_hello</type> -+ when <constant>KDBUS_CMD_HELLO</constant> is employed. Internally, the -+ pool is segmented into <emphasis>slices</emphasis>, each referenced by its -+ <emphasis>offset</emphasis> in the pool, expressed in <type>bytes</type>. -+ See -+ <citerefentry> -+ <refentrytitle>kdbus.connection</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more information about <constant>KDBUS_CMD_HELLO</constant>. -+ </para> -+ -+ <para> -+ The pool is written to by the kernel when one of the following -+ <emphasis>ioctls</emphasis> is issued: -+ -+ <variablelist> -+ <varlistentry> -+ <term><constant>KDBUS_CMD_HELLO</constant></term> -+ <listitem><para> -+ ... to receive details about the bus the connection was made to -+ </para></listitem> -+ </varlistentry> -+ <varlistentry> -+ <term><constant>KDBUS_CMD_RECV</constant></term> -+ <listitem><para> -+ ... to receive a message -+ </para></listitem> -+ </varlistentry> -+ <varlistentry> -+ <term><constant>KDBUS_CMD_LIST</constant></term> -+ <listitem><para> -+ ... to dump the name registry -+ </para></listitem> -+ </varlistentry> -+ <varlistentry> -+ <term><constant>KDBUS_CMD_CONN_INFO</constant></term> -+ <listitem><para> -+ ... to retrieve information on a connection -+ </para></listitem> -+ </varlistentry> -+ </variablelist> -+ -+ </para> -+ <para> -+ The <varname>offset</varname> fields returned by either one of the -+ aforementioned ioctls describe offsets inside the pool. In order to make -+ the slice available for subsequent calls, -+ <constant>KDBUS_CMD_FREE</constant> has to be called on that offset -+ (see below). Otherwise, the pool will fill up, and the connection won't -+ be able to receive any more information through its pool. -+ </para> -+ </refsect1> -+ -+ <refsect1> -+ <title>Pool slice allocation</title> -+ <para> -+ Pool slices are allocated by the kernel in order to report information -+ back to a task, such as messages, returned name list etc. -+ Allocation of pool slices cannot be initiated by userspace. See -+ <citerefentry> -+ <refentrytitle>kdbus.connection</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ and -+ <citerefentry> -+ <refentrytitle>kdbus.name</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for examples of commands that use the <emphasis>pool</emphasis> to -+ return data. -+ </para> -+ </refsect1> -+ -+ <refsect1> -+ <title>Accessing the pool memory</title> -+ <para> -+ Memory in the pool is read-only for userspace and may only be written -+ to by the kernel. To read from the pool memory, the caller is expected to -+ <citerefentry> -+ <refentrytitle>mmap</refentrytitle> -+ <manvolnum>2</manvolnum> -+ </citerefentry> -+ the buffer into its task, like this: -+ </para> -+ <programlisting> -+uint8_t *buf = mmap(NULL, size, PROT_READ, MAP_SHARED, conn_fd, 0); -+ </programlisting> -+ -+ <para> -+ In order to map the entire pool, the <varname>size</varname> parameter in -+ the example above should be set to the value of the -+ <varname>pool_size</varname> member of -+ <type>struct kdbus_cmd_hello</type> when -+ <constant>KDBUS_CMD_HELLO</constant> was employed to create the -+ connection (see above). -+ </para> -+ -+ <para> -+ The <emphasis>file descriptor</emphasis> used to map the memory must be -+ the one that was used to create the <emphasis>connection</emphasis>. -+ In other words, the one that was used to call -+ <constant>KDBUS_CMD_HELLO</constant>. See -+ <citerefentry> -+ <refentrytitle>kdbus.connection</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more details. -+ </para> -+ -+ <para> -+ Alternatively, instead of mapping the entire pool buffer, only parts -+ of it can be mapped. Every kdbus command that returns an -+ <emphasis>offset</emphasis> (see above) also reports a -+ <emphasis>size</emphasis> along with it, so programs can be written -+ in a way that it only maps portions of the pool to access a specific -+ <emphasis>slice</emphasis>. -+ </para> -+ -+ <para> -+ When access to the pool memory is no longer needed, programs should -+ call <function>munmap()</function> on the pointer returned by -+ <function>mmap()</function>. -+ </para> -+ </refsect1> -+ -+ <refsect1> -+ <title>Freeing pool slices</title> -+ <para> -+ The <constant>KDBUS_CMD_FREE</constant> ioctl is used to free a slice -+ inside the pool, describing an offset that was returned in an -+ <varname>offset</varname> field of another ioctl struct. -+ The <constant>KDBUS_CMD_FREE</constant> command takes a -+ <type>struct kdbus_cmd_free</type> as argument. -+ </para> -+ -+<programlisting> -+struct kdbus_cmd_free { -+ __u64 size; -+ __u64 flags; -+ __u64 return_flags; -+ __u64 offset; -+ struct kdbus_item items[0]; -+}; -+</programlisting> -+ -+ <para>The fields in this struct are described below.</para> -+ -+ <variablelist> -+ <varlistentry> -+ <term><varname>size</varname></term> -+ <listitem><para> -+ The overall size of the struct, including its items. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>flags</varname></term> -+ <listitem><para> -+ Currently unused. -+ <constant>KDBUS_FLAG_NEGOTIATE</constant> is accepted to probe for -+ valid flags. If set, the ioctl will return <errorcode>0</errorcode>, -+ and the <varname>flags</varname> field is set to -+ <constant>0</constant>. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>return_flags</varname></term> -+ <listitem><para> -+ Flags returned by the kernel. Currently unused and always set to -+ <constant>0</constant> by the kernel. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>offset</varname></term> -+ <listitem><para> -+ The offset to free, as returned by other ioctls that allocated -+ memory for returned information. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><varname>items</varname></term> -+ <listitem><para> -+ Items to specify further details for the receive command. -+ Currently unused. -+ Unrecognized items are rejected, and the ioctl will fail with -+ <varname>errno</varname> set to <constant>EINVAL</constant>. -+ All items except for -+ <constant>KDBUS_ITEM_NEGOTIATE</constant> (see -+ <citerefentry> -+ <refentrytitle>kdbus.item</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ ) will be rejected. -+ </para></listitem> -+ </varlistentry> -+ </variablelist> -+ </refsect1> -+ -+ <refsect1> -+ <title>Return value</title> -+ <para> -+ On success, all mentioned ioctl commands return <errorcode>0</errorcode>; -+ on error, <errorcode>-1</errorcode> is returned, and -+ <varname>errno</varname> is set to indicate the error. -+ If the issued ioctl is illegal for the file descriptor used, -+ <varname>errno</varname> will be set to <constant>ENOTTY</constant>. -+ </para> -+ -+ <refsect2> -+ <title> -+ <constant>KDBUS_CMD_FREE</constant> may fail with the following -+ errors -+ </title> -+ -+ <variablelist> -+ <varlistentry> -+ <term><constant>ENXIO</constant></term> -+ <listitem><para> -+ No pool slice found at given offset. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>EINVAL</constant></term> -+ <listitem><para> -+ Invalid flags provided. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>EINVAL</constant></term> -+ <listitem><para> -+ The offset is valid, but the user is not allowed to free the slice. -+ This happens, for example, if the offset was retrieved with -+ <constant>KDBUS_RECV_PEEK</constant>. -+ </para></listitem> -+ </varlistentry> -+ </variablelist> -+ </refsect2> -+ </refsect1> -+ -+ <refsect1> -+ <title>See Also</title> -+ <simplelist type="inline"> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.bus</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.connection</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.endpoint</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.name</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>mmap</refentrytitle> -+ <manvolnum>2</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>munmap</refentrytitle> -+ <manvolnum>2</manvolnum> -+ </citerefentry> -+ </member> -+ </simplelist> -+ </refsect1> -+</refentry> -diff --git a/Documentation/kdbus/kdbus.xml b/Documentation/kdbus/kdbus.xml -new file mode 100644 -index 000000000000..194abd2e76cc ---- /dev/null -+++ b/Documentation/kdbus/kdbus.xml -@@ -0,0 +1,1012 @@ -+<?xml version='1.0'?> <!--*-nxml-*--> -+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" -+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> -+ -+<refentry id="kdbus"> -+ -+ <refentryinfo> -+ <title>kdbus</title> -+ <productname>kdbus</productname> -+ </refentryinfo> -+ -+ <refmeta> -+ <refentrytitle>kdbus</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </refmeta> -+ -+ <refnamediv> -+ <refname>kdbus</refname> -+ <refpurpose>Kernel Message Bus</refpurpose> -+ </refnamediv> -+ -+ <refsect1> -+ <title>Synopsis</title> -+ <para> -+ kdbus is an inter-process communication bus system controlled by the -+ kernel. It provides user-space with an API to create buses and send -+ unicast and multicast messages to one, or many, peers connected to the -+ same bus. It does not enforce any layout on the transmitted data, but -+ only provides the transport layer used for message interchange between -+ peers. -+ </para> -+ <para> -+ This set of man-pages gives a comprehensive overview of the kernel-level -+ API, with all ioctl commands, associated structs and bit masks. However, -+ most people will not use this API level directly, but rather let one of -+ the high-level abstraction libraries help them integrate D-Bus -+ functionality into their applications. -+ </para> -+ </refsect1> -+ -+ <refsect1> -+ <title>Description</title> -+ <para> -+ kdbus provides a pseudo filesystem called <emphasis>kdbusfs</emphasis>, -+ which is usually mounted on <filename>/sys/fs/kdbus</filename>. Bus -+ primitives can be accessed as files and sub-directories underneath this -+ mount-point. Any advanced operations are done via -+ <function>ioctl()</function> on files created by -+ <emphasis>kdbusfs</emphasis>. Multiple mount-points of -+ <emphasis>kdbusfs</emphasis> are independent of each other. This allows -+ namespacing of kdbus by mounting a new instance of -+ <emphasis>kdbusfs</emphasis> in a new mount-namespace. kdbus calls these -+ mount instances domains and each bus belongs to exactly one domain. -+ </para> -+ -+ <para> -+ kdbus was designed as a transport layer for D-Bus, but is in no way -+ limited, nor controlled by the D-Bus protocol specification. The D-Bus -+ protocol is one possible application layer on top of kdbus. -+ </para> -+ -+ <para> -+ For the general D-Bus protocol specification, its payload format, its -+ marshaling, and its communication semantics, please refer to the -+ <ulink url="http://dbus.freedesktop.org/doc/dbus-specification.html"> -+ D-Bus specification</ulink>. -+ </para> -+ -+ </refsect1> -+ -+ <refsect1> -+ <title>Terminology</title> -+ -+ <refsect2> -+ <title>Domain</title> -+ <para> -+ A domain is a <emphasis>kdbusfs</emphasis> mount-point containing all -+ the bus primitives. Each domain is independent, and separate domains -+ do not affect each other. -+ </para> -+ </refsect2> -+ -+ <refsect2> -+ <title>Bus</title> -+ <para> -+ 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 endpoint of -+ a bus, to which clients establish connections, 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 buses. The kernel driver does not -+ distinguish between different bus types, they are all handled the same -+ way. See -+ <citerefentry> -+ <refentrytitle>kdbus.bus</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more details. -+ </para> -+ </refsect2> -+ -+ <refsect2> -+ <title>Endpoint</title> -+ <para> -+ An endpoint provides a file to talk to a bus. Opening an endpoint -+ creates a new connection to the bus to which the endpoint belongs. All -+ endpoints have unique names and are accessible as files underneath the -+ directory of a bus, e.g., /sys/fs/kdbus/<bus>/<endpoint> -+ 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 -+ locked-down, limited, filtered access to a bus. See -+ <citerefentry> -+ <refentrytitle>kdbus.endpoint</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more details. -+ </para> -+ </refsect2> -+ -+ <refsect2> -+ <title>Connection</title> -+ <para> -+ A connection to a bus is created by opening an endpoint file of a -+ bus. Every ordinary 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 -+ <citerefentry> -+ <refentrytitle>kdbus.connection</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more details. -+ </para> -+ </refsect2> -+ -+ <refsect2> -+ <title>Pool</title> -+ <para> -+ Each connection allocates a piece of shmem-backed memory that is -+ used to receive messages and answers to ioctl commands from the kernel. -+ It is never used to send anything to the kernel. In order to access that -+ memory, an application must mmap() it into its address space. See -+ <citerefentry> -+ <refentrytitle>kdbus.pool</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more details. -+ </para> -+ </refsect2> -+ -+ <refsect2> -+ <title>Well-known Name</title> -+ <para> -+ 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. A -+ connection that offers a service on a bus is usually reached by its -+ well-known name. An analogy of connection ID and well-known name is an -+ IP address and a DNS name associated with that address. See -+ <citerefentry> -+ <refentrytitle>kdbus.name</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more details. -+ </para> -+ </refsect2> -+ -+ <refsect2> -+ <title>Message</title> -+ <para> -+ 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 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, just like passing file -+ descriptors over UNIX domain sockets. 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 time stamps, 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 -+ <citerefentry> -+ <refentrytitle>kdbus.message</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more details. -+ </para> -+ </refsect2> -+ -+ <refsect2> -+ <title>Item</title> -+ <para> -+ The API of kdbus implements the notion of items, submitted through and -+ returned by most ioctls, and stored inside data structures in the -+ connection's pool. See -+ <citerefentry> -+ <refentrytitle>kdbus.item</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more details. -+ </para> -+ </refsect2> -+ -+ <refsect2> -+ <title>Broadcast, signal, filter, match</title> -+ <para> -+ Signals are messages that a receiver opts in for by installing a blob of -+ bytes, called a 'match'. Signal messages must always carry a -+ counter-part blob, called a 'filter', and signals are only delivered to -+ peers which have a match that white-lists the message's filter. Senders -+ of signal messages can use either a single connection ID as receiver, -+ or the special connection ID -+ <constant>KDBUS_DST_ID_BROADCAST</constant> to potentially send it to -+ all connections of a bus, following the logic described above. See -+ <citerefentry> -+ <refentrytitle>kdbus.match</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ and -+ <citerefentry> -+ <refentrytitle>kdbus.message</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more details. -+ </para> -+ </refsect2> -+ -+ <refsect2> -+ <title>Policy</title> -+ <para> -+ A policy is a set of rules that define which connections can see, talk -+ to, or register a well-known name on the bus. A policy is attached to -+ buses and custom endpoints, and modified by policy holder connections or -+ owners of custom endpoints. See -+ <citerefentry> -+ <refentrytitle>kdbus.policy</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more details. -+ </para> -+ </refsect2> -+ -+ <refsect2> -+ <title>Privileged bus users</title> -+ <para> -+ 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. See -+ <citerefentry> -+ <refentrytitle>kdbus.connection</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more details. -+ </para> -+ </refsect2> -+ </refsect1> -+ -+ <refsect1> -+ <title>Bus Layout</title> -+ -+ <para> -+ A <emphasis>bus</emphasis> provides and defines an environment that peers -+ can connect to for message interchange. A bus is created via the kdbus -+ control interface and can be modified by the bus creator. It applies the -+ policy that control all bus operations. The bus creator itself does not -+ participate as a peer. To establish a peer -+ <emphasis>connection</emphasis>, you have to open one of the -+ <emphasis>endpoints</emphasis> of a bus. Each bus provides a default -+ endpoint, but further endpoints can be created on-demand. Endpoints are -+ used to apply additional policies for all connections on this endpoint. -+ Thus, they provide additional filters to further restrict access of -+ specific connections to the bus. -+ </para> -+ -+ <para> -+ Following, you can see an example bus layout: -+ </para> -+ -+ <programlisting><![CDATA[ -+ Bus Creator -+ | -+ | -+ +-----+ -+ | Bus | -+ +-----+ -+ | -+ __________________/ \__________________ -+ / \ -+ | | -+ +----------+ +----------+ -+ | Endpoint | | Endpoint | -+ +----------+ +----------+ -+ _________/|\_________ _________/|\_________ -+ / | \ / | \ -+ | | | | | | -+ | | | | | | -+ Connection Connection Connection Connection Connection Connection -+ ]]></programlisting> -+ -+ </refsect1> -+ -+ <refsect1> -+ <title>Data structures and interconnections</title> -+ <programlisting><![CDATA[ -+ +--------------------------------------------------------------------------+ -+ | 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 | | | -+ | | +--------------+ +--------------+ +--------------------------------+ | | -+ | +----------------------------------------------------------------------+ | -+ +--------------------------------------------------------------------------+ -+ ]]></programlisting> -+ </refsect1> -+ -+ <refsect1> -+ <title>Metadata</title> -+ -+ <refsect2> -+ <title>When metadata is collected</title> -+ <para> -+ kdbus records data about the system in certain situations. Such metadata -+ can refer to the currently active process (creds, PIDs, current user -+ groups, process names and its executable path, cgroup membership, -+ capabilities, security label and audit information), connection -+ information (description string, currently owned names) and time stamps. -+ </para> -+ <para> -+ Metadata is collected at the following times. -+ </para> -+ -+ <itemizedlist> -+ <listitem><para> -+ When a bus is created (<constant>KDBUS_CMD_MAKE</constant>), -+ information about the calling task is collected. This data is returned -+ by the kernel via the <constant>KDBUS_CMD_BUS_CREATOR_INFO</constant> -+ call. -+ </para></listitem> -+ -+ <listitem> -+ <para> -+ When a connection is created (<constant>KDBUS_CMD_HELLO</constant>), -+ information about the calling task is collected. Alternatively, a -+ privileged connection may provide 'faked' information about -+ credentials, PIDs and security labels which will be stored instead. -+ This data is returned by the kernel as information on a connection -+ (<constant>KDBUS_CMD_CONN_INFO</constant>). Only metadata that a -+ connection allowed to be sent (by setting its bit in -+ <varname>attach_flags_send</varname>) will be exported in this way. -+ </para> -+ </listitem> -+ -+ <listitem> -+ <para> -+ When a message is sent (<constant>KDBUS_CMD_SEND</constant>), -+ information about the sending task and the sending connection are -+ collected. This metadata will be attached to the message when it -+ arrives in the receiver's pool. If the connection sending the -+ message installed faked credentials (see -+ <citerefentry> -+ <refentrytitle>kdbus.connection</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry>), -+ the message will not be augmented by any information about the -+ currently sending task. Note that only metadata that was requested -+ by the receiving connection will be collected and attached to -+ messages. -+ </para> -+ </listitem> -+ </itemizedlist> -+ -+ <para> -+ Which metadata items are actually delivered depends on the following -+ sets and masks: -+ </para> -+ -+ <itemizedlist> -+ <listitem><para> -+ (a) the system-wide kmod creds mask -+ (module parameter <varname>attach_flags_mask</varname>) -+ </para></listitem> -+ -+ <listitem><para> -+ (b) the per-connection send creds mask, set by the connecting client -+ </para></listitem> -+ -+ <listitem><para> -+ (c) the per-connection receive creds mask, set by the connecting -+ client -+ </para></listitem> -+ -+ <listitem><para> -+ (d) the per-bus minimal creds mask, set by the bus creator -+ </para></listitem> -+ -+ <listitem><para> -+ (e) the per-bus owner creds mask, set by the bus creator -+ </para></listitem> -+ -+ <listitem><para> -+ (f) the mask specified when querying creds of a bus peer -+ </para></listitem> -+ -+ <listitem><para> -+ (g) the mask specified when querying creds of a bus owner -+ </para></listitem> -+ </itemizedlist> -+ -+ <para> -+ With the following rules: -+ </para> -+ -+ <itemizedlist> -+ <listitem> -+ <para> -+ [1] The creds attached to messages are determined as -+ <constant>a & b & c</constant>. -+ </para> -+ </listitem> -+ -+ <listitem> -+ <para> -+ [2] When connecting to a bus (<constant>KDBUS_CMD_HELLO</constant>), -+ and <constant>~b & d != 0</constant>, the call will fail with, -+ <errorcode>-1</errorcode>, and <varname>errno</varname> is set to -+ <constant>ECONNREFUSED</constant>. -+ </para> -+ </listitem> -+ -+ <listitem> -+ <para> -+ [3] When querying creds of a bus peer, the creds returned are -+ <constant>a & b & f</constant>. -+ </para> -+ </listitem> -+ -+ <listitem> -+ <para> -+ [4] When querying creds of a bus owner, the creds returned are -+ <constant>a & e & g</constant>. -+ </para> -+ </listitem> -+ </itemizedlist> -+ -+ <para> -+ Hence, programs might not always get all requested metadata items that -+ it requested. Code must be written so that it can cope with this fact. -+ </para> -+ </refsect2> -+ -+ <refsect2> -+ <title>Benefits and heads-up</title> -+ <para> -+ Attaching metadata to messages has two major benefits. -+ -+ <itemizedlist> -+ <listitem> -+ <para> -+ Metadata attached to messages is gathered at the moment when the -+ other side calls <constant>KDBUS_CMD_SEND</constant>, or, -+ respectively, then the kernel notification is generated. There is -+ no need for the receiving peer to retrieve information about the -+ task in a second step. This closes a race gap that would otherwise -+ be inherent. -+ </para> -+ </listitem> -+ <listitem> -+ <para> -+ As metadata is delivered along with messages in the same data -+ blob, no extra calls to kernel functions etc. are needed to gather -+ them. -+ </para> -+ </listitem> -+ </itemizedlist> -+ -+ Note, however, that collecting metadata does come at a price for -+ performance, so developers should carefully assess which metadata to -+ really opt-in for. For best practice, data that is not needed as part -+ of a message should not be requested by the connection in the first -+ place (see <varname>attach_flags_recv</varname> in -+ <constant>KDBUS_CMD_HELLO</constant>). -+ </para> -+ </refsect2> -+ -+ <refsect2> -+ <title>Attach flags for metadata items</title> -+ <para> -+ To let the kernel know which metadata information to attach as items -+ to the aforementioned commands, it uses a bitmask. In those, the -+ following <emphasis>attach flags</emphasis> are currently supported. -+ Both the the <varname>attach_flags_recv</varname> and -+ <varname>attach_flags_send</varname> fields of -+ <type>struct kdbus_cmd_hello</type>, as well as the payload of the -+ <constant>KDBUS_ITEM_ATTACH_FLAGS_SEND</constant> and -+ <constant>KDBUS_ITEM_ATTACH_FLAGS_RECV</constant> items follow this -+ scheme. -+ </para> -+ -+ <variablelist> -+ <varlistentry> -+ <term><constant>KDBUS_ATTACH_TIMESTAMP</constant></term> -+ <listitem><para> -+ Requests the attachment of an item of type -+ <constant>KDBUS_ITEM_TIMESTAMP</constant>. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ATTACH_CREDS</constant></term> -+ <listitem><para> -+ Requests the attachment of an item of type -+ <constant>KDBUS_ITEM_CREDS</constant>. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ATTACH_PIDS</constant></term> -+ <listitem><para> -+ Requests the attachment of an item of type -+ <constant>KDBUS_ITEM_PIDS</constant>. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ATTACH_AUXGROUPS</constant></term> -+ <listitem><para> -+ Requests the attachment of an item of type -+ <constant>KDBUS_ITEM_AUXGROUPS</constant>. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ATTACH_NAMES</constant></term> -+ <listitem><para> -+ Requests the attachment of an item of type -+ <constant>KDBUS_ITEM_OWNED_NAME</constant>. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ATTACH_TID_COMM</constant></term> -+ <listitem><para> -+ Requests the attachment of an item of type -+ <constant>KDBUS_ITEM_TID_COMM</constant>. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ATTACH_PID_COMM</constant></term> -+ <listitem><para> -+ Requests the attachment of an item of type -+ <constant>KDBUS_ITEM_PID_COMM</constant>. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ATTACH_EXE</constant></term> -+ <listitem><para> -+ Requests the attachment of an item of type -+ <constant>KDBUS_ITEM_EXE</constant>. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ATTACH_CMDLINE</constant></term> -+ <listitem><para> -+ Requests the attachment of an item of type -+ <constant>KDBUS_ITEM_CMDLINE</constant>. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ATTACH_CGROUP</constant></term> -+ <listitem><para> -+ Requests the attachment of an item of type -+ <constant>KDBUS_ITEM_CGROUP</constant>. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ATTACH_CAPS</constant></term> -+ <listitem><para> -+ Requests the attachment of an item of type -+ <constant>KDBUS_ITEM_CAPS</constant>. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ATTACH_SECLABEL</constant></term> -+ <listitem><para> -+ Requests the attachment of an item of type -+ <constant>KDBUS_ITEM_SECLABEL</constant>. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ATTACH_AUDIT</constant></term> -+ <listitem><para> -+ Requests the attachment of an item of type -+ <constant>KDBUS_ITEM_AUDIT</constant>. -+ </para></listitem> -+ </varlistentry> -+ -+ <varlistentry> -+ <term><constant>KDBUS_ATTACH_CONN_DESCRIPTION</constant></term> -+ <listitem><para> -+ Requests the attachment of an item of type -+ <constant>KDBUS_ITEM_CONN_DESCRIPTION</constant>. -+ </para></listitem> -+ </varlistentry> -+ </variablelist> -+ -+ <para> -+ Please refer to -+ <citerefentry> -+ <refentrytitle>kdbus.item</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for detailed information about the layout and payload of items and -+ what metadata should be used to. -+ </para> -+ </refsect2> -+ </refsect1> -+ -+ <refsect1> -+ <title>The ioctl interface</title> -+ -+ <para> -+ As stated in the 'synopsis' section above, application developers are -+ strongly encouraged to use kdbus through one of the high-level D-Bus -+ abstraction libraries, rather than using the low-level API directly. -+ </para> -+ -+ <para> -+ kdbus on the kernel level exposes its functions exclusively through -+ <citerefentry> -+ <refentrytitle>ioctl</refentrytitle> -+ <manvolnum>2</manvolnum> -+ </citerefentry>, -+ employed on file descriptors returned by -+ <citerefentry> -+ <refentrytitle>open</refentrytitle> -+ <manvolnum>2</manvolnum> -+ </citerefentry> -+ on pseudo files exposed by -+ <citerefentry> -+ <refentrytitle>kdbus.fs</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry>. -+ </para> -+ <para> -+ Following is a list of all the ioctls, along with the command structs -+ they must be used with. -+ </para> -+ -+ <informaltable frame="none"> -+ <tgroup cols="3" colsep="1"> -+ <thead> -+ <row> -+ <entry>ioctl signature</entry> -+ <entry>command</entry> -+ <entry>transported struct</entry> -+ </row> -+ </thead> -+ <tbody> -+ <row> -+ <entry><constant>0x40189500</constant></entry> -+ <entry><constant>KDBUS_CMD_BUS_MAKE</constant></entry> -+ <entry><type>struct kdbus_cmd *</type></entry> -+ </row><row> -+ <entry><constant>0x40189510</constant></entry> -+ <entry><constant>KDBUS_CMD_ENDPOINT_MAKE</constant></entry> -+ <entry><type>struct kdbus_cmd *</type></entry> -+ </row><row> -+ <entry><constant>0xc0609580</constant></entry> -+ <entry><constant>KDBUS_CMD_HELLO</constant></entry> -+ <entry><type>struct kdbus_cmd_hello *</type></entry> -+ </row><row> -+ <entry><constant>0x40189582</constant></entry> -+ <entry><constant>KDBUS_CMD_BYEBYE</constant></entry> -+ <entry><type>struct kdbus_cmd *</type></entry> -+ </row><row> -+ <entry><constant>0x40389590</constant></entry> -+ <entry><constant>KDBUS_CMD_SEND</constant></entry> -+ <entry><type>struct kdbus_cmd_send *</type></entry> -+ </row><row> -+ <entry><constant>0x80409591</constant></entry> -+ <entry><constant>KDBUS_CMD_RECV</constant></entry> -+ <entry><type>struct kdbus_cmd_recv *</type></entry> -+ </row><row> -+ <entry><constant>0x40209583</constant></entry> -+ <entry><constant>KDBUS_CMD_FREE</constant></entry> -+ <entry><type>struct kdbus_cmd_free *</type></entry> -+ </row><row> -+ <entry><constant>0x401895a0</constant></entry> -+ <entry><constant>KDBUS_CMD_NAME_ACQUIRE</constant></entry> -+ <entry><type>struct kdbus_cmd *</type></entry> -+ </row><row> -+ <entry><constant>0x401895a1</constant></entry> -+ <entry><constant>KDBUS_CMD_NAME_RELEASE</constant></entry> -+ <entry><type>struct kdbus_cmd *</type></entry> -+ </row><row> -+ <entry><constant>0x80289586</constant></entry> -+ <entry><constant>KDBUS_CMD_LIST</constant></entry> -+ <entry><type>struct kdbus_cmd_list *</type></entry> -+ </row><row> -+ <entry><constant>0x80309584</constant></entry> -+ <entry><constant>KDBUS_CMD_CONN_INFO</constant></entry> -+ <entry><type>struct kdbus_cmd_info *</type></entry> -+ </row><row> -+ <entry><constant>0x40209551</constant></entry> -+ <entry><constant>KDBUS_CMD_UPDATE</constant></entry> -+ <entry><type>struct kdbus_cmd *</type></entry> -+ </row><row> -+ <entry><constant>0x80309585</constant></entry> -+ <entry><constant>KDBUS_CMD_BUS_CREATOR_INFO</constant></entry> -+ <entry><type>struct kdbus_cmd_info *</type></entry> -+ </row><row> -+ <entry><constant>0x40189511</constant></entry> -+ <entry><constant>KDBUS_CMD_ENDPOINT_UPDATE</constant></entry> -+ <entry><type>struct kdbus_cmd *</type></entry> -+ </row><row> -+ <entry><constant>0x402095b0</constant></entry> -+ <entry><constant>KDBUS_CMD_MATCH_ADD</constant></entry> -+ <entry><type>struct kdbus_cmd_match *</type></entry> -+ </row><row> -+ <entry><constant>0x402095b1</constant></entry> -+ <entry><constant>KDBUS_CMD_MATCH_REMOVE</constant></entry> -+ <entry><type>struct kdbus_cmd_match *</type></entry> -+ </row> -+ </tbody> -+ </tgroup> -+ </informaltable> -+ -+ <para> -+ Depending on the type of <emphasis>kdbusfs</emphasis> node that was -+ opened and what ioctls have been executed on a file descriptor before, -+ a different sub-set of ioctl commands is allowed. -+ </para> -+ -+ <itemizedlist> -+ <listitem> -+ <para> -+ On a file descriptor resulting from opening a -+ <emphasis>control node</emphasis>, only the -+ <constant>KDBUS_CMD_BUS_MAKE</constant> ioctl may be executed. -+ </para> -+ </listitem> -+ <listitem> -+ <para> -+ On a file descriptor resulting from opening a -+ <emphasis>bus endpoint node</emphasis>, only the -+ <constant>KDBUS_CMD_ENDPOINT_MAKE</constant> and -+ <constant>KDBUS_CMD_HELLO</constant> ioctls may be executed. -+ </para> -+ </listitem> -+ <listitem> -+ <para> -+ A file descriptor that was used to create a bus -+ (via <constant>KDBUS_CMD_BUS_MAKE</constant>) is called a -+ <emphasis>bus owner</emphasis> file descriptor. The bus will be -+ active as long as the file descriptor is kept open. -+ A bus owner file descriptor can not be used to -+ employ any further ioctls. As soon as -+ <citerefentry> -+ <refentrytitle>close</refentrytitle> -+ <manvolnum>2</manvolnum> -+ </citerefentry> -+ is called on it, the bus will be shut down, along will all associated -+ endpoints and connections. See -+ <citerefentry> -+ <refentrytitle>kdbus.bus</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more details. -+ </para> -+ </listitem> -+ <listitem> -+ <para> -+ A file descriptor that was used to create an endpoint -+ (via <constant>KDBUS_CMD_ENDPOINT_MAKE</constant>) is called an -+ <emphasis>endpoint owner</emphasis> file descriptor. The endpoint -+ will be active as long as the file descriptor is kept open. -+ An endpoint owner file descriptor can only be used -+ to update details of an endpoint through the -+ <constant>KDBUS_CMD_ENDPOINT_UPDATE</constant> ioctl. As soon as -+ <citerefentry> -+ <refentrytitle>close</refentrytitle> -+ <manvolnum>2</manvolnum> -+ </citerefentry> -+ is called on it, the endpoint will be removed from the bus, and all -+ connections that are connected to the bus through it are shut down. -+ See -+ <citerefentry> -+ <refentrytitle>kdbus.endpoint</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ for more details. -+ </para> -+ </listitem> -+ <listitem> -+ <para> -+ A file descriptor that was used to create a connection -+ (via <constant>KDBUS_CMD_HELLO</constant>) is called a -+ <emphasis>connection owner</emphasis> file descriptor. The connection -+ will be active as long as the file descriptor is kept open. -+ A connection owner file descriptor may be used to -+ issue any of the following ioctls. -+ </para> -+ -+ <itemizedlist> -+ <listitem><para> -+ <constant>KDBUS_CMD_UPDATE</constant> to tweak details of the -+ connection. See -+ <citerefentry> -+ <refentrytitle>kdbus.connection</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry>. -+ </para></listitem> -+ -+ <listitem><para> -+ <constant>KDBUS_CMD_BYEBYE</constant> to shut down a connection -+ without losing messages. See -+ <citerefentry> -+ <refentrytitle>kdbus.connection</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry>. -+ </para></listitem> -+ -+ <listitem><para> -+ <constant>KDBUS_CMD_FREE</constant> to free a slice of memory in -+ the pool. See -+ <citerefentry> -+ <refentrytitle>kdbus.pool</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry>. -+ </para></listitem> -+ -+ <listitem><para> -+ <constant>KDBUS_CMD_CONN_INFO</constant> to retrieve information -+ on other connections on the bus. See -+ <citerefentry> -+ <refentrytitle>kdbus.connection</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry>. -+ </para></listitem> -+ -+ <listitem><para> -+ <constant>KDBUS_CMD_BUS_CREATOR_INFO</constant> to retrieve -+ information on the bus creator. See -+ <citerefentry> -+ <refentrytitle>kdbus.connection</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry>. -+ </para></listitem> -+ -+ <listitem><para> -+ <constant>KDBUS_CMD_LIST</constant> to retrieve a list of -+ currently active well-known names and unique IDs on the bus. See -+ <citerefentry> -+ <refentrytitle>kdbus.name</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry>. -+ </para></listitem> -+ -+ <listitem><para> -+ <constant>KDBUS_CMD_SEND</constant> and -+ <constant>KDBUS_CMD_RECV</constant> to send or receive a message. -+ See -+ <citerefentry> -+ <refentrytitle>kdbus.message</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry>. -+ </para></listitem> -+ -+ <listitem><para> -+ <constant>KDBUS_CMD_NAME_ACQUIRE</constant> and -+ <constant>KDBUS_CMD_NAME_RELEASE</constant> to acquire or release -+ a well-known name on the bus. See -+ <citerefentry> -+ <refentrytitle>kdbus.name</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry>. -+ </para></listitem> -+ -+ <listitem><para> -+ <constant>KDBUS_CMD_MATCH_ADD</constant> and -+ <constant>KDBUS_CMD_MATCH_REMOVE</constant> to add or remove -+ a match for signal messages. See -+ <citerefentry> -+ <refentrytitle>kdbus.match</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry>. -+ </para></listitem> -+ </itemizedlist> -+ </listitem> -+ </itemizedlist> -+ -+ <para> -+ These ioctls, along with the structs they transport, are explained in -+ detail in the other documents linked to in the 'see also' section below. -+ </para> -+ </refsect1> -+ -+ <refsect1> -+ <title>See Also</title> -+ <simplelist type="inline"> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.bus</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.connection</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.endpoint</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.fs</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.item</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.message</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.name</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>kdbus.pool</refentrytitle> -+ <manvolnum>7</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>ioctl</refentrytitle> -+ <manvolnum>2</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>mmap</refentrytitle> -+ <manvolnum>2</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>open</refentrytitle> -+ <manvolnum>2</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <citerefentry> -+ <refentrytitle>close</refentrytitle> -+ <manvolnum>2</manvolnum> -+ </citerefentry> -+ </member> -+ <member> -+ <ulink url="http://freedesktop.org/wiki/Software/dbus">D-Bus</ulink> -+ </member> -+ </simplelist> -+ </refsect1> -+ -+</refentry> -diff --git a/Documentation/kdbus/stylesheet.xsl b/Documentation/kdbus/stylesheet.xsl -new file mode 100644 -index 000000000000..52565eac7d0d ---- /dev/null -+++ b/Documentation/kdbus/stylesheet.xsl -@@ -0,0 +1,16 @@ -+<?xml version="1.0" encoding="UTF-8"?> -+<stylesheet xmlns="http://www.w3.org/1999/XSL/Transform" version="1.0"> -+ <param name="chunk.quietly">1</param> -+ <param name="funcsynopsis.style">ansi</param> -+ <param name="funcsynopsis.tabular.threshold">80</param> -+ <param name="callout.graphics">0</param> -+ <param name="paper.type">A4</param> -+ <param name="generate.section.toc.level">2</param> -+ <param name="use.id.as.filename">1</param> -+ <param name="citerefentry.link">1</param> -+ <strip-space elements="*"/> -+ <template name="generate.citerefentry.link"> -+ <value-of select="refentrytitle"/> -+ <text>.html</text> -+ </template> -+</stylesheet> -diff --git a/Makefile b/Makefile -index 1100ff3c77e3..08c98188a37a 100644 ---- a/Makefile -+++ b/Makefile -@@ -1350,6 +1350,7 @@ $(help-board-dirs): help-%: - %docs: scripts_basic FORCE - $(Q)$(MAKE) $(build)=scripts build_docproc - $(Q)$(MAKE) $(build)=Documentation/DocBook $@ -+ $(Q)$(MAKE) $(build)=Documentation/kdbus $@ - - else # KBUILD_EXTMOD - --- -2.4.3 - - -From 33ce2b3d450428d1913bd4a0b2f5422c336f421b Mon Sep 17 00:00:00 2001 -From: Daniel Mack <daniel@zonque.org> -Date: Thu, 11 Sep 2014 18:38:06 +0200 -Subject: [PATCH 002/132] kdbus: add uapi header file - -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 definitions, enums and defines -for constants. - -The low-level kernel API of kdbus is exposed through ioctls, employed -on nodes exposed by kdbusfs. We've chosen a ioctl-based implementation -over syscalls for various reaons: - - * The ioctls kdbus offers are completely specific to nodes exposed by - kdbusfs and can not be applied to any other file descriptor in a - system. - - * The file descriptors derived from opening nodes in kdbusfs can only be - used for poll(), close() and the ioctls described in kdbus.h. - - * Not all systems will make use of kdbus eventually, and we want to - make as many parts of the kernel optional at build time. - - * We want to build the kdbus code as module, which is impossible to - do when implemented with syscalls. - - * The ioctl dispatching logic does not show up in our performance - graphs; its overhead is negligible. - - * For development, being able to build, load and unload a separate - module with a versioned name suffix is essential. - -Signed-off-by: Daniel Mack <daniel@zonque.org> -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Djalal Harouni <tixxdz@opendz.org> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - include/uapi/linux/Kbuild | 1 + - include/uapi/linux/kdbus.h | 979 +++++++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 980 insertions(+) - create mode 100644 include/uapi/linux/kdbus.h - -diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild -index 68ceb97c458c..ddc413e1959f 100644 ---- a/include/uapi/linux/Kbuild -+++ b/include/uapi/linux/Kbuild -@@ -214,6 +214,7 @@ header-y += ixjuser.h - header-y += jffs2.h - header-y += joystick.h - header-y += kcmp.h -+header-y += kdbus.h - header-y += kdev_t.h - header-y += kd.h - header-y += kernelcapi.h -diff --git a/include/uapi/linux/kdbus.h b/include/uapi/linux/kdbus.h -new file mode 100644 -index 000000000000..fc1d77dd7c93 ---- /dev/null -+++ b/include/uapi/linux/kdbus.h -@@ -0,0 +1,979 @@ -+/* -+ * 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_UAPI_H_ -+#define _KDBUS_UAPI_H_ -+ -+#include <linux/ioctl.h> -+#include <linux/types.h> -+ -+#define KDBUS_IOCTL_MAGIC 0x95 -+#define KDBUS_SRC_ID_KERNEL (0) -+#define KDBUS_DST_ID_NAME (0) -+#define KDBUS_MATCH_ID_ANY (~0ULL) -+#define KDBUS_DST_ID_BROADCAST (~0ULL) -+#define KDBUS_FLAG_NEGOTIATE (1ULL << 63) -+ -+/** -+ * struct kdbus_notify_id_change - name registry change message -+ * @id: New or former owner of the name -+ * @flags: flags field from KDBUS_HELLO_* -+ * -+ * Sent from kernel to userspace when the owner or activator of -+ * a well-known name changes. -+ * -+ * Attached to: -+ * KDBUS_ITEM_ID_ADD -+ * KDBUS_ITEM_ID_REMOVE -+ */ -+struct kdbus_notify_id_change { -+ __u64 id; -+ __u64 flags; -+} __attribute__((__aligned__(8))); -+ -+/** -+ * struct kdbus_notify_name_change - name registry change message -+ * @old_id: ID and flags of former owner of a name -+ * @new_id: ID and flags of new owner of a name -+ * @name: Well-known name -+ * -+ * Sent from kernel to userspace when the owner or activator of -+ * a well-known name changes. -+ * -+ * Attached to: -+ * KDBUS_ITEM_NAME_ADD -+ * KDBUS_ITEM_NAME_REMOVE -+ * KDBUS_ITEM_NAME_CHANGE -+ */ -+struct kdbus_notify_name_change { -+ struct kdbus_notify_id_change old_id; -+ struct kdbus_notify_id_change new_id; -+ char name[0]; -+} __attribute__((__aligned__(8))); -+ -+/** -+ * struct kdbus_creds - process credentials -+ * @uid: User ID -+ * @euid: Effective UID -+ * @suid: Saved UID -+ * @fsuid: Filesystem UID -+ * @gid: Group ID -+ * @egid: Effective GID -+ * @sgid: Saved GID -+ * @fsgid: Filesystem GID -+ * -+ * Attached to: -+ * KDBUS_ITEM_CREDS -+ */ -+struct kdbus_creds { -+ __u64 uid; -+ __u64 euid; -+ __u64 suid; -+ __u64 fsuid; -+ __u64 gid; -+ __u64 egid; -+ __u64 sgid; -+ __u64 fsgid; -+} __attribute__((__aligned__(8))); -+ -+/** -+ * struct kdbus_pids - process identifiers -+ * @pid: Process ID -+ * @tid: Thread ID -+ * @ppid: Parent process ID -+ * -+ * The PID and TID of a process. -+ * -+ * Attached to: -+ * KDBUS_ITEM_PIDS -+ */ -+struct kdbus_pids { -+ __u64 pid; -+ __u64 tid; -+ __u64 ppid; -+} __attribute__((__aligned__(8))); -+ -+/** -+ * struct kdbus_caps - process capabilities -+ * @last_cap: Highest currently known capability bit -+ * @caps: Variable number of 32-bit capabilities flags -+ * -+ * Contains a variable number of 32-bit capabilities flags. -+ * -+ * Attached to: -+ * KDBUS_ITEM_CAPS -+ */ -+struct kdbus_caps { -+ __u32 last_cap; -+ __u32 caps[0]; -+} __attribute__((__aligned__(8))); -+ -+/** -+ * struct kdbus_audit - audit information -+ * @sessionid: The audit session ID -+ * @loginuid: The audit login uid -+ * -+ * Attached to: -+ * KDBUS_ITEM_AUDIT -+ */ -+struct kdbus_audit { -+ __u32 sessionid; -+ __u32 loginuid; -+} __attribute__((__aligned__(8))); -+ -+/** -+ * struct kdbus_timestamp -+ * @seqnum: Global per-domain message sequence number -+ * @monotonic_ns: Monotonic timestamp, in nanoseconds -+ * @realtime_ns: Realtime timestamp, in nanoseconds -+ * -+ * Attached to: -+ * KDBUS_ITEM_TIMESTAMP -+ */ -+struct kdbus_timestamp { -+ __u64 seqnum; -+ __u64 monotonic_ns; -+ __u64 realtime_ns; -+} __attribute__((__aligned__(8))); -+ -+/** -+ * struct kdbus_vec - I/O vector for kdbus payload items -+ * @size: The size of the vector -+ * @address: Memory address of data buffer -+ * @offset: Offset in the in-message payload memory, -+ * relative to the message head -+ * -+ * Attached to: -+ * KDBUS_ITEM_PAYLOAD_VEC, KDBUS_ITEM_PAYLOAD_OFF -+ */ -+struct kdbus_vec { -+ __u64 size; -+ union { -+ __u64 address; -+ __u64 offset; -+ }; -+} __attribute__((__aligned__(8))); -+ -+/** -+ * struct kdbus_bloom_parameter - bus-wide bloom parameters -+ * @size: Size of the bit field in bytes (m / 8) -+ * @n_hash: Number of hash functions used (k) -+ */ -+struct kdbus_bloom_parameter { -+ __u64 size; -+ __u64 n_hash; -+} __attribute__((__aligned__(8))); -+ -+/** -+ * struct kdbus_bloom_filter - bloom filter containing n elements -+ * @generation: Generation of the element set in the filter -+ * @data: Bit field, multiple of 8 bytes -+ */ -+struct kdbus_bloom_filter { -+ __u64 generation; -+ __u64 data[0]; -+} __attribute__((__aligned__(8))); -+ -+/** -+ * struct kdbus_memfd - a kdbus memfd -+ * @start: The offset into the memfd where the segment starts -+ * @size: The size of the memfd segment -+ * @fd: The file descriptor number -+ * @__pad: Padding to ensure proper alignment and size -+ * -+ * Attached to: -+ * KDBUS_ITEM_PAYLOAD_MEMFD -+ */ -+struct kdbus_memfd { -+ __u64 start; -+ __u64 size; -+ int fd; -+ __u32 __pad; -+} __attribute__((__aligned__(8))); -+ -+/** -+ * struct kdbus_name - a registered well-known name with its flags -+ * @flags: Flags from KDBUS_NAME_* -+ * @name: Well-known name -+ * -+ * Attached to: -+ * KDBUS_ITEM_OWNED_NAME -+ */ -+struct kdbus_name { -+ __u64 flags; -+ char name[0]; -+} __attribute__((__aligned__(8))); -+ -+/** -+ * enum kdbus_policy_access_type - permissions of a policy record -+ * @_KDBUS_POLICY_ACCESS_NULL: Uninitialized/invalid -+ * @KDBUS_POLICY_ACCESS_USER: Grant access to a uid -+ * @KDBUS_POLICY_ACCESS_GROUP: Grant access to gid -+ * @KDBUS_POLICY_ACCESS_WORLD: World-accessible -+ */ -+enum kdbus_policy_access_type { -+ _KDBUS_POLICY_ACCESS_NULL, -+ KDBUS_POLICY_ACCESS_USER, -+ KDBUS_POLICY_ACCESS_GROUP, -+ KDBUS_POLICY_ACCESS_WORLD, -+}; -+ -+/** -+ * enum kdbus_policy_access_flags - mode flags -+ * @KDBUS_POLICY_OWN: Allow to own a well-known name -+ * Implies KDBUS_POLICY_TALK and KDBUS_POLICY_SEE -+ * @KDBUS_POLICY_TALK: Allow communication to a well-known name -+ * Implies KDBUS_POLICY_SEE -+ * @KDBUS_POLICY_SEE: Allow to see a well-known name -+ */ -+enum kdbus_policy_type { -+ KDBUS_POLICY_SEE = 0, -+ KDBUS_POLICY_TALK, -+ KDBUS_POLICY_OWN, -+}; -+ -+/** -+ * struct kdbus_policy_access - policy access item -+ * @type: One of KDBUS_POLICY_ACCESS_* types -+ * @access: Access to grant -+ * @id: For KDBUS_POLICY_ACCESS_USER, the uid -+ * For KDBUS_POLICY_ACCESS_GROUP, the gid -+ */ -+struct kdbus_policy_access { -+ __u64 type; /* USER, GROUP, WORLD */ -+ __u64 access; /* OWN, TALK, SEE */ -+ __u64 id; /* uid, gid, 0 */ -+} __attribute__((__aligned__(8))); -+ -+/** -+ * enum kdbus_attach_flags - flags for metadata attachments -+ * @KDBUS_ATTACH_TIMESTAMP: Timestamp -+ * @KDBUS_ATTACH_CREDS: Credentials -+ * @KDBUS_ATTACH_PIDS: PIDs -+ * @KDBUS_ATTACH_AUXGROUPS: Auxiliary groups -+ * @KDBUS_ATTACH_NAMES: Well-known names -+ * @KDBUS_ATTACH_TID_COMM: The "comm" process identifier of the TID -+ * @KDBUS_ATTACH_PID_COMM: The "comm" process identifier of the PID -+ * @KDBUS_ATTACH_EXE: The path of the executable -+ * @KDBUS_ATTACH_CMDLINE: The process command line -+ * @KDBUS_ATTACH_CGROUP: The croup membership -+ * @KDBUS_ATTACH_CAPS: The process capabilities -+ * @KDBUS_ATTACH_SECLABEL: The security label -+ * @KDBUS_ATTACH_AUDIT: The audit IDs -+ * @KDBUS_ATTACH_CONN_DESCRIPTION: The human-readable connection name -+ * @_KDBUS_ATTACH_ALL: All of the above -+ * @_KDBUS_ATTACH_ANY: Wildcard match to enable any kind of -+ * metatdata. -+ */ -+enum kdbus_attach_flags { -+ KDBUS_ATTACH_TIMESTAMP = 1ULL << 0, -+ KDBUS_ATTACH_CREDS = 1ULL << 1, -+ KDBUS_ATTACH_PIDS = 1ULL << 2, -+ KDBUS_ATTACH_AUXGROUPS = 1ULL << 3, -+ KDBUS_ATTACH_NAMES = 1ULL << 4, -+ KDBUS_ATTACH_TID_COMM = 1ULL << 5, -+ KDBUS_ATTACH_PID_COMM = 1ULL << 6, -+ KDBUS_ATTACH_EXE = 1ULL << 7, -+ KDBUS_ATTACH_CMDLINE = 1ULL << 8, -+ KDBUS_ATTACH_CGROUP = 1ULL << 9, -+ KDBUS_ATTACH_CAPS = 1ULL << 10, -+ KDBUS_ATTACH_SECLABEL = 1ULL << 11, -+ KDBUS_ATTACH_AUDIT = 1ULL << 12, -+ KDBUS_ATTACH_CONN_DESCRIPTION = 1ULL << 13, -+ _KDBUS_ATTACH_ALL = (1ULL << 14) - 1, -+ _KDBUS_ATTACH_ANY = ~0ULL -+}; -+ -+/** -+ * enum kdbus_item_type - item types to chain data in a list -+ * @_KDBUS_ITEM_NULL: Uninitialized/invalid -+ * @_KDBUS_ITEM_USER_BASE: Start of user items -+ * @KDBUS_ITEM_NEGOTIATE: Negotiate supported items -+ * @KDBUS_ITEM_PAYLOAD_VEC: Vector to data -+ * @KDBUS_ITEM_PAYLOAD_OFF: Data at returned offset to message head -+ * @KDBUS_ITEM_PAYLOAD_MEMFD: Data as sealed memfd -+ * @KDBUS_ITEM_FDS: Attached file descriptors -+ * @KDBUS_ITEM_CANCEL_FD: FD used to cancel a synchronous -+ * operation by writing to it from -+ * userspace -+ * @KDBUS_ITEM_BLOOM_PARAMETER: Bus-wide bloom parameters, used with -+ * KDBUS_CMD_BUS_MAKE, carries a -+ * struct kdbus_bloom_parameter -+ * @KDBUS_ITEM_BLOOM_FILTER: Bloom filter carried with a message, -+ * used to match against a bloom mask of a -+ * connection, carries a struct -+ * kdbus_bloom_filter -+ * @KDBUS_ITEM_BLOOM_MASK: Bloom mask used to match against a -+ * message'sbloom filter -+ * @KDBUS_ITEM_DST_NAME: Destination's well-known name -+ * @KDBUS_ITEM_MAKE_NAME: Name of domain, bus, endpoint -+ * @KDBUS_ITEM_ATTACH_FLAGS_SEND: Attach-flags, used for updating which -+ * metadata a connection opts in to send -+ * @KDBUS_ITEM_ATTACH_FLAGS_RECV: Attach-flags, used for updating which -+ * metadata a connection requests to -+ * receive for each reeceived message -+ * @KDBUS_ITEM_ID: Connection ID -+ * @KDBUS_ITEM_NAME: Well-know name with flags -+ * @_KDBUS_ITEM_ATTACH_BASE: Start of metadata attach items -+ * @KDBUS_ITEM_TIMESTAMP: Timestamp -+ * @KDBUS_ITEM_CREDS: Process credentials -+ * @KDBUS_ITEM_PIDS: Process identifiers -+ * @KDBUS_ITEM_AUXGROUPS: Auxiliary process groups -+ * @KDBUS_ITEM_OWNED_NAME: A name owned by the associated -+ * connection -+ * @KDBUS_ITEM_TID_COMM: Thread ID "comm" identifier -+ * (Don't trust this, see below.) -+ * @KDBUS_ITEM_PID_COMM: Process ID "comm" identifier -+ * (Don't trust this, see below.) -+ * @KDBUS_ITEM_EXE: The path of the executable -+ * (Don't trust this, see below.) -+ * @KDBUS_ITEM_CMDLINE: The process command line -+ * (Don't trust this, see below.) -+ * @KDBUS_ITEM_CGROUP: The croup membership -+ * @KDBUS_ITEM_CAPS: The process capabilities -+ * @KDBUS_ITEM_SECLABEL: The security label -+ * @KDBUS_ITEM_AUDIT: The audit IDs -+ * @KDBUS_ITEM_CONN_DESCRIPTION: The connection's human-readable name -+ * (debugging) -+ * @_KDBUS_ITEM_POLICY_BASE: Start of policy items -+ * @KDBUS_ITEM_POLICY_ACCESS: Policy access block -+ * @_KDBUS_ITEM_KERNEL_BASE: Start of kernel-generated message items -+ * @KDBUS_ITEM_NAME_ADD: Notification in kdbus_notify_name_change -+ * @KDBUS_ITEM_NAME_REMOVE: Notification in kdbus_notify_name_change -+ * @KDBUS_ITEM_NAME_CHANGE: Notification in kdbus_notify_name_change -+ * @KDBUS_ITEM_ID_ADD: Notification in kdbus_notify_id_change -+ * @KDBUS_ITEM_ID_REMOVE: Notification in kdbus_notify_id_change -+ * @KDBUS_ITEM_REPLY_TIMEOUT: Timeout has been reached -+ * @KDBUS_ITEM_REPLY_DEAD: Destination died -+ * -+ * N.B: The process and thread COMM fields, as well as the CMDLINE and -+ * EXE fields may be altered by unprivileged processes und should -+ * hence *not* used for security decisions. Peers should make use of -+ * these items only for informational purposes, such as generating log -+ * records. -+ */ -+enum kdbus_item_type { -+ _KDBUS_ITEM_NULL, -+ _KDBUS_ITEM_USER_BASE, -+ KDBUS_ITEM_NEGOTIATE = _KDBUS_ITEM_USER_BASE, -+ KDBUS_ITEM_PAYLOAD_VEC, -+ KDBUS_ITEM_PAYLOAD_OFF, -+ KDBUS_ITEM_PAYLOAD_MEMFD, -+ KDBUS_ITEM_FDS, -+ KDBUS_ITEM_CANCEL_FD, -+ KDBUS_ITEM_BLOOM_PARAMETER, -+ KDBUS_ITEM_BLOOM_FILTER, -+ KDBUS_ITEM_BLOOM_MASK, -+ KDBUS_ITEM_DST_NAME, -+ KDBUS_ITEM_MAKE_NAME, -+ KDBUS_ITEM_ATTACH_FLAGS_SEND, -+ KDBUS_ITEM_ATTACH_FLAGS_RECV, -+ KDBUS_ITEM_ID, -+ KDBUS_ITEM_NAME, -+ -+ /* keep these item types in sync with KDBUS_ATTACH_* flags */ -+ _KDBUS_ITEM_ATTACH_BASE = 0x1000, -+ KDBUS_ITEM_TIMESTAMP = _KDBUS_ITEM_ATTACH_BASE, -+ KDBUS_ITEM_CREDS, -+ KDBUS_ITEM_PIDS, -+ KDBUS_ITEM_AUXGROUPS, -+ KDBUS_ITEM_OWNED_NAME, -+ KDBUS_ITEM_TID_COMM, -+ KDBUS_ITEM_PID_COMM, -+ KDBUS_ITEM_EXE, -+ KDBUS_ITEM_CMDLINE, -+ KDBUS_ITEM_CGROUP, -+ KDBUS_ITEM_CAPS, -+ KDBUS_ITEM_SECLABEL, -+ KDBUS_ITEM_AUDIT, -+ KDBUS_ITEM_CONN_DESCRIPTION, -+ -+ _KDBUS_ITEM_POLICY_BASE = 0x2000, -+ KDBUS_ITEM_POLICY_ACCESS = _KDBUS_ITEM_POLICY_BASE, -+ -+ _KDBUS_ITEM_KERNEL_BASE = 0x8000, -+ KDBUS_ITEM_NAME_ADD = _KDBUS_ITEM_KERNEL_BASE, -+ KDBUS_ITEM_NAME_REMOVE, -+ KDBUS_ITEM_NAME_CHANGE, -+ KDBUS_ITEM_ID_ADD, -+ KDBUS_ITEM_ID_REMOVE, -+ KDBUS_ITEM_REPLY_TIMEOUT, -+ KDBUS_ITEM_REPLY_DEAD, -+}; -+ -+/** -+ * struct kdbus_item - chain of data blocks -+ * @size: Overall data record size -+ * @type: Kdbus_item type of data -+ * @data: Generic bytes -+ * @data32: Generic 32 bit array -+ * @data64: Generic 64 bit array -+ * @str: Generic string -+ * @id: Connection ID -+ * @vec: KDBUS_ITEM_PAYLOAD_VEC -+ * @creds: KDBUS_ITEM_CREDS -+ * @audit: KDBUS_ITEM_AUDIT -+ * @timestamp: KDBUS_ITEM_TIMESTAMP -+ * @name: KDBUS_ITEM_NAME -+ * @bloom_parameter: KDBUS_ITEM_BLOOM_PARAMETER -+ * @bloom_filter: KDBUS_ITEM_BLOOM_FILTER -+ * @memfd: KDBUS_ITEM_PAYLOAD_MEMFD -+ * @name_change: KDBUS_ITEM_NAME_ADD -+ * KDBUS_ITEM_NAME_REMOVE -+ * KDBUS_ITEM_NAME_CHANGE -+ * @id_change: KDBUS_ITEM_ID_ADD -+ * KDBUS_ITEM_ID_REMOVE -+ * @policy: KDBUS_ITEM_POLICY_ACCESS -+ */ -+struct kdbus_item { -+ __u64 size; -+ __u64 type; -+ union { -+ __u8 data[0]; -+ __u32 data32[0]; -+ __u64 data64[0]; -+ char str[0]; -+ -+ __u64 id; -+ struct kdbus_vec vec; -+ struct kdbus_creds creds; -+ struct kdbus_pids pids; -+ struct kdbus_audit audit; -+ struct kdbus_caps caps; -+ struct kdbus_timestamp timestamp; -+ struct kdbus_name name; -+ struct kdbus_bloom_parameter bloom_parameter; -+ struct kdbus_bloom_filter bloom_filter; -+ struct kdbus_memfd memfd; -+ int fds[0]; -+ struct kdbus_notify_name_change name_change; -+ struct kdbus_notify_id_change id_change; -+ struct kdbus_policy_access policy_access; -+ }; -+} __attribute__((__aligned__(8))); -+ -+/** -+ * enum kdbus_msg_flags - type of message -+ * @KDBUS_MSG_EXPECT_REPLY: Expect a reply message, used for -+ * method calls. The userspace-supplied -+ * cookie identifies the message and the -+ * respective reply carries the cookie -+ * in cookie_reply -+ * @KDBUS_MSG_NO_AUTO_START: Do not start a service if the addressed -+ * name is not currently active. This flag is -+ * not looked at by the kernel but only -+ * serves as hint for userspace implementations. -+ * @KDBUS_MSG_SIGNAL: Treat this message as signal -+ */ -+enum kdbus_msg_flags { -+ KDBUS_MSG_EXPECT_REPLY = 1ULL << 0, -+ KDBUS_MSG_NO_AUTO_START = 1ULL << 1, -+ KDBUS_MSG_SIGNAL = 1ULL << 2, -+}; -+ -+/** -+ * enum kdbus_payload_type - type of payload carried by message -+ * @KDBUS_PAYLOAD_KERNEL: Kernel-generated simple message -+ * @KDBUS_PAYLOAD_DBUS: D-Bus marshalling "DBusDBus" -+ * -+ * Any payload-type is accepted. Common types will get added here once -+ * established. -+ */ -+enum kdbus_payload_type { -+ KDBUS_PAYLOAD_KERNEL, -+ KDBUS_PAYLOAD_DBUS = 0x4442757344427573ULL, -+}; -+ -+/** -+ * struct kdbus_msg - the representation of a kdbus message -+ * @size: Total size of the message -+ * @flags: Message flags (KDBUS_MSG_*), userspace → kernel -+ * @priority: Message queue priority value -+ * @dst_id: 64-bit ID of the destination connection -+ * @src_id: 64-bit ID of the source connection -+ * @payload_type: Payload type (KDBUS_PAYLOAD_*) -+ * @cookie: Userspace-supplied cookie, for the connection -+ * to identify its messages -+ * @timeout_ns: The time to wait for a message reply from the peer. -+ * If there is no reply, and the send command is -+ * executed asynchronously, a kernel-generated message -+ * with an attached KDBUS_ITEM_REPLY_TIMEOUT item -+ * is sent to @src_id. For synchronously executed send -+ * command, the value denotes the maximum time the call -+ * blocks to wait for a reply. The timeout is expected in -+ * nanoseconds and as absolute CLOCK_MONOTONIC value. -+ * @cookie_reply: A reply to the requesting message with the same -+ * cookie. The requesting connection can match its -+ * request and the reply with this value -+ * @items: A list of kdbus_items containing the message payload -+ */ -+struct kdbus_msg { -+ __u64 size; -+ __u64 flags; -+ __s64 priority; -+ __u64 dst_id; -+ __u64 src_id; -+ __u64 payload_type; -+ __u64 cookie; -+ union { -+ __u64 timeout_ns; -+ __u64 cookie_reply; -+ }; -+ struct kdbus_item items[0]; -+} __attribute__((__aligned__(8))); -+ -+/** -+ * struct kdbus_msg_info - returned message container -+ * @offset: Offset of kdbus_msg slice in pool -+ * @msg_size: Copy of the kdbus_msg.size field -+ * @return_flags: Command return flags, kernel → userspace -+ */ -+struct kdbus_msg_info { -+ __u64 offset; -+ __u64 msg_size; -+ __u64 return_flags; -+} __attribute__((__aligned__(8))); -+ -+/** -+ * enum kdbus_send_flags - flags for sending messages -+ * @KDBUS_SEND_SYNC_REPLY: Wait for destination connection to -+ * reply to this message. The -+ * KDBUS_CMD_SEND ioctl() will block -+ * until the reply is received, and -+ * offset_reply in struct kdbus_msg will -+ * yield the offset in the sender's pool -+ * where the reply can be found. -+ * This flag is only valid if -+ * @KDBUS_MSG_EXPECT_REPLY is set as well. -+ */ -+enum kdbus_send_flags { -+ KDBUS_SEND_SYNC_REPLY = 1ULL << 0, -+}; -+ -+/** -+ * struct kdbus_cmd_send - send message -+ * @size: Overall size of this structure -+ * @flags: Flags to change send behavior (KDBUS_SEND_*) -+ * @return_flags: Command return flags, kernel → userspace -+ * @msg_address: Storage address of the kdbus_msg to send -+ * @reply: Storage for message reply if KDBUS_SEND_SYNC_REPLY -+ * was given -+ * @items: Additional items for this command -+ */ -+struct kdbus_cmd_send { -+ __u64 size; -+ __u64 flags; -+ __u64 return_flags; -+ __u64 msg_address; -+ struct kdbus_msg_info reply; -+ struct kdbus_item items[0]; -+} __attribute__((__aligned__(8))); -+ -+/** -+ * enum kdbus_recv_flags - flags for de-queuing messages -+ * @KDBUS_RECV_PEEK: Return the next queued message without -+ * actually de-queuing it, and without installing -+ * any file descriptors or other resources. It is -+ * usually used to determine the activating -+ * connection of a bus name. -+ * @KDBUS_RECV_DROP: Drop and free the next queued message and all -+ * its resources without actually receiving it. -+ * @KDBUS_RECV_USE_PRIORITY: Only de-queue messages with the specified or -+ * higher priority (lowest values); if not set, -+ * the priority value is ignored. -+ */ -+enum kdbus_recv_flags { -+ KDBUS_RECV_PEEK = 1ULL << 0, -+ KDBUS_RECV_DROP = 1ULL << 1, -+ KDBUS_RECV_USE_PRIORITY = 1ULL << 2, -+}; -+ -+/** -+ * enum kdbus_recv_return_flags - return flags for message receive commands -+ * @KDBUS_RECV_RETURN_INCOMPLETE_FDS: One or more file descriptors could not -+ * be installed. These descriptors in -+ * KDBUS_ITEM_FDS will carry the value -1. -+ * @KDBUS_RECV_RETURN_DROPPED_MSGS: There have been dropped messages since -+ * the last time a message was received. -+ * The 'dropped_msgs' counter contains the -+ * number of messages dropped pool -+ * overflows or other missed broadcasts. -+ */ -+enum kdbus_recv_return_flags { -+ KDBUS_RECV_RETURN_INCOMPLETE_FDS = 1ULL << 0, -+ KDBUS_RECV_RETURN_DROPPED_MSGS = 1ULL << 1, -+}; -+ -+/** -+ * struct kdbus_cmd_recv - struct to de-queue a buffered message -+ * @size: Overall size of this object -+ * @flags: KDBUS_RECV_* flags, userspace → kernel -+ * @return_flags: Command return flags, kernel → userspace -+ * @priority: Minimum priority of the messages to de-queue. Lowest -+ * values have the highest priority. -+ * @dropped_msgs: In case there were any dropped messages since the last -+ * time a message was received, this will be set to the -+ * number of lost messages and -+ * KDBUS_RECV_RETURN_DROPPED_MSGS will be set in -+ * 'return_flags'. This can only happen if the ioctl -+ * returns 0 or EAGAIN. -+ * @msg: Return storage for received message. -+ * @items: Additional items for this command. -+ * -+ * This struct is used with the KDBUS_CMD_RECV ioctl. -+ */ -+struct kdbus_cmd_recv { -+ __u64 size; -+ __u64 flags; -+ __u64 return_flags; -+ __s64 priority; -+ __u64 dropped_msgs; -+ struct kdbus_msg_info msg; -+ struct kdbus_item items[0]; -+} __attribute__((__aligned__(8))); -+ -+/** -+ * struct kdbus_cmd_free - struct to free a slice of memory in the pool -+ * @size: Overall size of this structure -+ * @flags: Flags for the free command, userspace → kernel -+ * @return_flags: Command return flags, kernel → userspace -+ * @offset: The offset of the memory slice, as returned by other -+ * ioctls -+ * @items: Additional items to modify the behavior -+ * -+ * This struct is used with the KDBUS_CMD_FREE ioctl. -+ */ -+struct kdbus_cmd_free { -+ __u64 size; -+ __u64 flags; -+ __u64 return_flags; -+ __u64 offset; -+ struct kdbus_item items[0]; -+} __attribute__((__aligned__(8))); -+ -+/** -+ * enum kdbus_hello_flags - flags for struct kdbus_cmd_hello -+ * @KDBUS_HELLO_ACCEPT_FD: The connection allows the reception of -+ * any passed file descriptors -+ * @KDBUS_HELLO_ACTIVATOR: Special-purpose connection which registers -+ * a well-know name for a process to be started -+ * when traffic arrives -+ * @KDBUS_HELLO_POLICY_HOLDER: Special-purpose connection which registers -+ * policy entries for a name. The provided name -+ * is not activated and not registered with the -+ * name database, it only allows unprivileged -+ * connections to acquire a name, talk or discover -+ * a service -+ * @KDBUS_HELLO_MONITOR: Special-purpose connection to monitor -+ * bus traffic -+ */ -+enum kdbus_hello_flags { -+ KDBUS_HELLO_ACCEPT_FD = 1ULL << 0, -+ KDBUS_HELLO_ACTIVATOR = 1ULL << 1, -+ KDBUS_HELLO_POLICY_HOLDER = 1ULL << 2, -+ KDBUS_HELLO_MONITOR = 1ULL << 3, -+}; -+ -+/** -+ * struct kdbus_cmd_hello - struct to say hello to kdbus -+ * @size: The total size of the structure -+ * @flags: Connection flags (KDBUS_HELLO_*), userspace → kernel -+ * @return_flags: Command return flags, kernel → userspace -+ * @attach_flags_send: Mask of metadata to attach to each message sent -+ * off by this connection (KDBUS_ATTACH_*) -+ * @attach_flags_recv: Mask of metadata to attach to each message receieved -+ * by the new connection (KDBUS_ATTACH_*) -+ * @bus_flags: The flags field copied verbatim from the original -+ * KDBUS_CMD_BUS_MAKE ioctl. It's intended to be useful -+ * to do negotiation of features of the payload that is -+ * transferred (kernel → userspace) -+ * @id: The ID of this connection (kernel → userspace) -+ * @pool_size: Size of the connection's buffer where the received -+ * messages are placed -+ * @offset: Pool offset where items are returned to report -+ * additional information about the bus and the newly -+ * created connection. -+ * @items_size: Size of buffer returned in the pool slice at @offset. -+ * @id128: Unique 128-bit ID of the bus (kernel → userspace) -+ * @items: A list of items -+ * -+ * This struct is used with the KDBUS_CMD_HELLO ioctl. -+ */ -+struct kdbus_cmd_hello { -+ __u64 size; -+ __u64 flags; -+ __u64 return_flags; -+ __u64 attach_flags_send; -+ __u64 attach_flags_recv; -+ __u64 bus_flags; -+ __u64 id; -+ __u64 pool_size; -+ __u64 offset; -+ __u64 items_size; -+ __u8 id128[16]; -+ struct kdbus_item items[0]; -+} __attribute__((__aligned__(8))); -+ -+/** -+ * struct kdbus_info - connection information -+ * @size: total size of the struct -+ * @id: 64bit object ID -+ * @flags: object creation flags -+ * @items: list of items -+ * -+ * Note that the user is responsible for freeing the allocated memory with -+ * the KDBUS_CMD_FREE ioctl. -+ */ -+struct kdbus_info { -+ __u64 size; -+ __u64 id; -+ __u64 flags; -+ struct kdbus_item items[0]; -+} __attribute__((__aligned__(8))); -+ -+/** -+ * enum kdbus_list_flags - what to include into the returned list -+ * @KDBUS_LIST_UNIQUE: active connections -+ * @KDBUS_LIST_ACTIVATORS: activator connections -+ * @KDBUS_LIST_NAMES: known well-known names -+ * @KDBUS_LIST_QUEUED: queued-up names -+ */ -+enum kdbus_list_flags { -+ KDBUS_LIST_UNIQUE = 1ULL << 0, -+ KDBUS_LIST_NAMES = 1ULL << 1, -+ KDBUS_LIST_ACTIVATORS = 1ULL << 2, -+ KDBUS_LIST_QUEUED = 1ULL << 3, -+}; -+ -+/** -+ * struct kdbus_cmd_list - list connections -+ * @size: overall size of this object -+ * @flags: flags for the query (KDBUS_LIST_*), userspace → kernel -+ * @return_flags: command return flags, kernel → userspace -+ * @offset: Offset in the caller's pool buffer where an array of -+ * kdbus_info objects is stored. -+ * The user must use KDBUS_CMD_FREE to free the -+ * allocated memory. -+ * @list_size: size of returned list in bytes -+ * @items: Items for the command. Reserved for future use. -+ * -+ * This structure is used with the KDBUS_CMD_LIST ioctl. -+ */ -+struct kdbus_cmd_list { -+ __u64 size; -+ __u64 flags; -+ __u64 return_flags; -+ __u64 offset; -+ __u64 list_size; -+ struct kdbus_item items[0]; -+} __attribute__((__aligned__(8))); -+ -+/** -+ * struct kdbus_cmd_info - struct used for KDBUS_CMD_CONN_INFO ioctl -+ * @size: The total size of the struct -+ * @flags: Flags for this ioctl, userspace → kernel -+ * @return_flags: Command return flags, kernel → userspace -+ * @id: The 64-bit ID of the connection. If set to zero, passing -+ * @name is required. kdbus will look up the name to -+ * determine the ID in this case. -+ * @attach_flags: Set of attach flags to specify the set of information -+ * to receive, userspace → kernel -+ * @offset: Returned offset in the caller's pool buffer where the -+ * kdbus_info struct result is stored. The user must -+ * use KDBUS_CMD_FREE to free the allocated memory. -+ * @info_size: Output buffer to report size of data at @offset. -+ * @items: The optional item list, containing the -+ * well-known name to look up as a KDBUS_ITEM_NAME. -+ * Only needed in case @id is zero. -+ * -+ * On success, the KDBUS_CMD_CONN_INFO ioctl will return 0 and @offset will -+ * tell the user the offset in the connection pool buffer at which to find the -+ * result in a struct kdbus_info. -+ */ -+struct kdbus_cmd_info { -+ __u64 size; -+ __u64 flags; -+ __u64 return_flags; -+ __u64 id; -+ __u64 attach_flags; -+ __u64 offset; -+ __u64 info_size; -+ struct kdbus_item items[0]; -+} __attribute__((__aligned__(8))); -+ -+/** -+ * enum kdbus_cmd_match_flags - flags to control the KDBUS_CMD_MATCH_ADD ioctl -+ * @KDBUS_MATCH_REPLACE: If entries with the supplied cookie already -+ * exists, remove them before installing the new -+ * matches. -+ */ -+enum kdbus_cmd_match_flags { -+ KDBUS_MATCH_REPLACE = 1ULL << 0, -+}; -+ -+/** -+ * struct kdbus_cmd_match - struct to add or remove matches -+ * @size: The total size of the struct -+ * @flags: Flags for match command (KDBUS_MATCH_*), -+ * userspace → kernel -+ * @return_flags: Command return flags, kernel → userspace -+ * @cookie: Userspace supplied cookie. When removing, the cookie -+ * identifies the match to remove -+ * @items: A list of items for additional information -+ * -+ * This structure is used with the KDBUS_CMD_MATCH_ADD and -+ * KDBUS_CMD_MATCH_REMOVE ioctl. -+ */ -+struct kdbus_cmd_match { -+ __u64 size; -+ __u64 flags; -+ __u64 return_flags; -+ __u64 cookie; -+ struct kdbus_item items[0]; -+} __attribute__((__aligned__(8))); -+ -+/** -+ * enum kdbus_make_flags - Flags for KDBUS_CMD_{BUS,ENDPOINT}_MAKE -+ * @KDBUS_MAKE_ACCESS_GROUP: Make the bus or endpoint node group-accessible -+ * @KDBUS_MAKE_ACCESS_WORLD: Make the bus or endpoint node world-accessible -+ */ -+enum kdbus_make_flags { -+ KDBUS_MAKE_ACCESS_GROUP = 1ULL << 0, -+ KDBUS_MAKE_ACCESS_WORLD = 1ULL << 1, -+}; -+ -+/** -+ * enum kdbus_name_flags - flags for KDBUS_CMD_NAME_ACQUIRE -+ * @KDBUS_NAME_REPLACE_EXISTING: Try to replace name of other connections -+ * @KDBUS_NAME_ALLOW_REPLACEMENT: Allow the replacement of the name -+ * @KDBUS_NAME_QUEUE: Name should be queued if busy -+ * @KDBUS_NAME_IN_QUEUE: Name is queued -+ * @KDBUS_NAME_ACTIVATOR: Name is owned by a activator connection -+ */ -+enum kdbus_name_flags { -+ KDBUS_NAME_REPLACE_EXISTING = 1ULL << 0, -+ KDBUS_NAME_ALLOW_REPLACEMENT = 1ULL << 1, -+ KDBUS_NAME_QUEUE = 1ULL << 2, -+ KDBUS_NAME_IN_QUEUE = 1ULL << 3, -+ KDBUS_NAME_ACTIVATOR = 1ULL << 4, -+}; -+ -+/** -+ * struct kdbus_cmd - generic ioctl payload -+ * @size: Overall size of this structure -+ * @flags: Flags for this ioctl, userspace → kernel -+ * @return_flags: Ioctl return flags, kernel → userspace -+ * @items: Additional items to modify the behavior -+ * -+ * This is a generic ioctl payload object. It's used by all ioctls that only -+ * take flags and items as input. -+ */ -+struct kdbus_cmd { -+ __u64 size; -+ __u64 flags; -+ __u64 return_flags; -+ struct kdbus_item items[0]; -+} __attribute__((__aligned__(8))); -+ -+/** -+ * Ioctl API -+ * -+ * KDBUS_CMD_BUS_MAKE: After opening the "control" node, this command -+ * creates a new bus with the specified -+ * name. The bus is immediately shut down and -+ * cleaned up when the opened file descriptor is -+ * closed. -+ * -+ * 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_ENDPOINT_UPDATE: Update the properties of a custom enpoint. Used -+ * to update the policy. -+ * -+ * KDBUS_CMD_HELLO: By opening the bus node, a connection is -+ * created. After a HELLO the opened connection -+ * becomes an active peer on the bus. -+ * KDBUS_CMD_UPDATE: Update the properties of a connection. Used to -+ * update the metadata subscription mask and -+ * policy. -+ * KDBUS_CMD_BYEBYE: Disconnect a connection. If there are no -+ * messages queued up in the connection's pool, -+ * the call succeeds, and the handle is rendered -+ * unusable. Otherwise, -EBUSY is returned without -+ * any further side-effects. -+ * KDBUS_CMD_FREE: Release the allocated memory in the receiver's -+ * pool. -+ * KDBUS_CMD_CONN_INFO: Retrieve credentials and properties of the -+ * initial creator of the connection. The data was -+ * stored at registration time and does not -+ * necessarily represent the connected process or -+ * the actual state of the process. -+ * KDBUS_CMD_BUS_CREATOR_INFO: Retrieve information of the creator of the bus -+ * a connection is attached to. -+ * -+ * KDBUS_CMD_SEND: Send a message and pass data from userspace to -+ * the kernel. -+ * KDBUS_CMD_RECV: Receive a message from the kernel which is -+ * placed in the receiver's pool. -+ * -+ * KDBUS_CMD_NAME_ACQUIRE: Request a well-known bus name to associate with -+ * the connection. Well-known names are used to -+ * address a peer on the bus. -+ * KDBUS_CMD_NAME_RELEASE: Release a well-known name the connection -+ * currently owns. -+ * KDBUS_CMD_LIST: Retrieve the list of all currently registered -+ * well-known and unique names. -+ * -+ * KDBUS_CMD_MATCH_ADD: Install a match which broadcast messages should -+ * be delivered to the connection. -+ * KDBUS_CMD_MATCH_REMOVE: Remove a current match for broadcast messages. -+ */ -+enum kdbus_ioctl_type { -+ /* bus owner (00-0f) */ -+ KDBUS_CMD_BUS_MAKE = _IOW(KDBUS_IOCTL_MAGIC, 0x00, -+ struct kdbus_cmd), -+ -+ /* endpoint owner (10-1f) */ -+ KDBUS_CMD_ENDPOINT_MAKE = _IOW(KDBUS_IOCTL_MAGIC, 0x10, -+ struct kdbus_cmd), -+ KDBUS_CMD_ENDPOINT_UPDATE = _IOW(KDBUS_IOCTL_MAGIC, 0x11, -+ struct kdbus_cmd), -+ -+ /* connection owner (80-ff) */ -+ KDBUS_CMD_HELLO = _IOWR(KDBUS_IOCTL_MAGIC, 0x80, -+ struct kdbus_cmd_hello), -+ KDBUS_CMD_UPDATE = _IOW(KDBUS_IOCTL_MAGIC, 0x81, -+ struct kdbus_cmd), -+ KDBUS_CMD_BYEBYE = _IOW(KDBUS_IOCTL_MAGIC, 0x82, -+ struct kdbus_cmd), -+ KDBUS_CMD_FREE = _IOW(KDBUS_IOCTL_MAGIC, 0x83, -+ struct kdbus_cmd_free), -+ KDBUS_CMD_CONN_INFO = _IOR(KDBUS_IOCTL_MAGIC, 0x84, -+ struct kdbus_cmd_info), -+ KDBUS_CMD_BUS_CREATOR_INFO = _IOR(KDBUS_IOCTL_MAGIC, 0x85, -+ struct kdbus_cmd_info), -+ KDBUS_CMD_LIST = _IOR(KDBUS_IOCTL_MAGIC, 0x86, -+ struct kdbus_cmd_list), -+ -+ KDBUS_CMD_SEND = _IOW(KDBUS_IOCTL_MAGIC, 0x90, -+ struct kdbus_cmd_send), -+ KDBUS_CMD_RECV = _IOR(KDBUS_IOCTL_MAGIC, 0x91, -+ struct kdbus_cmd_recv), -+ -+ KDBUS_CMD_NAME_ACQUIRE = _IOW(KDBUS_IOCTL_MAGIC, 0xa0, -+ struct kdbus_cmd), -+ KDBUS_CMD_NAME_RELEASE = _IOW(KDBUS_IOCTL_MAGIC, 0xa1, -+ struct kdbus_cmd), -+ -+ KDBUS_CMD_MATCH_ADD = _IOW(KDBUS_IOCTL_MAGIC, 0xb0, -+ struct kdbus_cmd_match), -+ KDBUS_CMD_MATCH_REMOVE = _IOW(KDBUS_IOCTL_MAGIC, 0xb1, -+ struct kdbus_cmd_match), -+}; -+ -+#endif /* _KDBUS_UAPI_H_ */ --- -2.4.3 - - -From aa92a46ea81cf1e84a7ae46d8921b8218e739384 Mon Sep 17 00:00:00 2001 -From: Daniel Mack <daniel@zonque.org> -Date: Thu, 11 Sep 2014 18:52:52 +0200 -Subject: [PATCH 003/132] kdbus: add driver skeleton, ioctl entry points and - utility functions - -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. - -Signed-off-by: Daniel Mack <daniel@zonque.org> -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Djalal Harouni <tixxdz@opendz.org> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - Documentation/ioctl/ioctl-number.txt | 1 + - ipc/kdbus/handle.c | 617 +++++++++++++++++++++++++++++++++++ - ipc/kdbus/handle.h | 85 +++++ - ipc/kdbus/limits.h | 64 ++++ - ipc/kdbus/main.c | 125 +++++++ - ipc/kdbus/util.c | 201 ++++++++++++ - ipc/kdbus/util.h | 74 +++++ - 7 files changed, 1167 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 - -diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt -index 8136e1fd30fd..54e091ebb862 100644 ---- a/Documentation/ioctl/ioctl-number.txt -+++ b/Documentation/ioctl/ioctl-number.txt -@@ -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:buk@buks.ipn.de> -diff --git a/ipc/kdbus/handle.c b/ipc/kdbus/handle.c -new file mode 100644 -index 000000000000..f72dbe513b4a ---- /dev/null -+++ b/ipc/kdbus/handle.c -@@ -0,0 +1,617 @@ -+/* -+ * Copyright (C) 2013-2015 Kay Sievers -+ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> -+ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> -+ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> -+ * Copyright (C) 2013-2015 Linux Foundation -+ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> -+ * -+ * 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/file.h> -+#include <linux/fs.h> -+#include <linux/idr.h> -+#include <linux/init.h> -+#include <linux/kdev_t.h> -+#include <linux/module.h> -+#include <linux/poll.h> -+#include <linux/rwsem.h> -+#include <linux/sched.h> -+#include <linux/sizes.h> -+#include <linux/slab.h> -+#include <linux/uaccess.h> -+#include <linux/syscalls.h> -+ -+#include "bus.h" -+#include "connection.h" -+#include "endpoint.h" -+#include "fs.h" -+#include "handle.h" -+#include "item.h" -+#include "match.h" -+#include "message.h" -+#include "names.h" -+#include "domain.h" -+#include "policy.h" -+ -+static int kdbus_args_verify(struct kdbus_args *args) -+{ -+ struct kdbus_item *item; -+ size_t i; -+ int ret; -+ -+ KDBUS_ITEMS_FOREACH(item, args->items, args->items_size) { -+ struct kdbus_arg *arg = NULL; -+ -+ if (!KDBUS_ITEM_VALID(item, args->items, args->items_size)) -+ return -EINVAL; -+ -+ for (i = 0; i < args->argc; ++i) -+ if (args->argv[i].type == item->type) -+ break; -+ if (i >= args->argc) -+ return -EINVAL; -+ -+ arg = &args->argv[i]; -+ -+ ret = kdbus_item_validate(item); -+ if (ret < 0) -+ return ret; -+ -+ if (arg->item && !arg->multiple) -+ return -EINVAL; -+ -+ arg->item = item; -+ } -+ -+ if (!KDBUS_ITEMS_END(item, args->items, args->items_size)) -+ return -EINVAL; -+ -+ for (i = 0; i < args->argc; ++i) -+ if (args->argv[i].mandatory && !args->argv[i].item) -+ return -EINVAL; -+ -+ return 0; -+} -+ -+static int kdbus_args_negotiate(struct kdbus_args *args) -+{ -+ struct kdbus_item __user *user; -+ struct kdbus_item *negotiation; -+ size_t i, j, num; -+ -+ /* -+ * If KDBUS_FLAG_NEGOTIATE is set, we overwrite the flags field with -+ * the set of supported flags. Furthermore, if an KDBUS_ITEM_NEGOTIATE -+ * item is passed, we iterate its payload (array of u64, each set to an -+ * item type) and clear all unsupported item-types to 0. -+ * The caller might do this recursively, if other flags or objects are -+ * embedded in the payload itself. -+ */ -+ -+ if (args->cmd->flags & KDBUS_FLAG_NEGOTIATE) { -+ if (put_user(args->allowed_flags & ~KDBUS_FLAG_NEGOTIATE, -+ &args->user->flags)) -+ return -EFAULT; -+ } -+ -+ if (args->argc < 1 || args->argv[0].type != KDBUS_ITEM_NEGOTIATE || -+ !args->argv[0].item) -+ return 0; -+ -+ negotiation = args->argv[0].item; -+ user = (struct kdbus_item __user *) -+ ((u8 __user *)args->user + -+ ((u8 *)negotiation - (u8 *)args->cmd)); -+ num = KDBUS_ITEM_PAYLOAD_SIZE(negotiation) / sizeof(u64); -+ -+ for (i = 0; i < num; ++i) { -+ for (j = 0; j < args->argc; ++j) -+ if (negotiation->data64[i] == args->argv[j].type) -+ break; -+ -+ if (j < args->argc) -+ continue; -+ -+ /* this item is not supported, clear it out */ -+ negotiation->data64[i] = 0; -+ if (put_user(negotiation->data64[i], &user->data64[i])) -+ return -EFAULT; -+ } -+ -+ return 0; -+} -+ -+/** -+ * __kdbus_args_parse() - parse payload of kdbus command -+ * @args: object to parse data into -+ * @argp: user-space location of command payload to parse -+ * @type_size: overall size of command payload to parse -+ * @items_offset: offset of items array in command payload -+ * @out: output variable to store pointer to copied payload -+ * -+ * This parses the ioctl payload at user-space location @argp into @args. @args -+ * must be pre-initialized by the caller to reflect the supported flags and -+ * items of this command. This parser will then copy the command payload into -+ * kernel-space, verify correctness and consistency and cache pointers to parsed -+ * items and other data in @args. -+ * -+ * If this function succeeded, you must call kdbus_args_clear() to release -+ * allocated resources before destroying @args. -+ * -+ * Return: On failure a negative error code is returned. Otherwise, 1 is -+ * returned if negotiation was requested, 0 if not. -+ */ -+int __kdbus_args_parse(struct kdbus_args *args, void __user *argp, -+ size_t type_size, size_t items_offset, void **out) -+{ -+ int ret; -+ -+ args->cmd = kdbus_memdup_user(argp, type_size, KDBUS_CMD_MAX_SIZE); -+ if (IS_ERR(args->cmd)) -+ return PTR_ERR(args->cmd); -+ -+ args->cmd->return_flags = 0; -+ args->user = argp; -+ args->items = (void *)((u8 *)args->cmd + items_offset); -+ args->items_size = args->cmd->size - items_offset; -+ -+ if (args->cmd->flags & ~args->allowed_flags) { -+ ret = -EINVAL; -+ goto error; -+ } -+ -+ ret = kdbus_args_verify(args); -+ if (ret < 0) -+ goto error; -+ -+ ret = kdbus_args_negotiate(args); -+ if (ret < 0) -+ goto error; -+ -+ *out = args->cmd; -+ return !!(args->cmd->flags & KDBUS_FLAG_NEGOTIATE); -+ -+error: -+ return kdbus_args_clear(args, ret); -+} -+ -+/** -+ * kdbus_args_clear() - release allocated command resources -+ * @args: object to release resources of -+ * @ret: return value of this command -+ * -+ * This frees all allocated resources on @args and copies the command result -+ * flags into user-space. @ret is usually returned unchanged by this function, -+ * so it can be used in the final 'return' statement of the command handler. -+ * -+ * Return: -EFAULT if return values cannot be copied into user-space, otherwise -+ * @ret is returned unchanged. -+ */ -+int kdbus_args_clear(struct kdbus_args *args, int ret) -+{ -+ if (!args) -+ return ret; -+ -+ if (!IS_ERR_OR_NULL(args->cmd)) { -+ if (put_user(args->cmd->return_flags, -+ &args->user->return_flags)) -+ ret = -EFAULT; -+ kfree(args->cmd); -+ args->cmd = NULL; -+ } -+ -+ return ret; -+} -+ -+/** -+ * enum kdbus_handle_type - type an handle can be of -+ * @KDBUS_HANDLE_NONE: no type set, yet -+ * @KDBUS_HANDLE_BUS_OWNER: bus owner -+ * @KDBUS_HANDLE_EP_OWNER: endpoint owner -+ * @KDBUS_HANDLE_CONNECTED: endpoint connection after HELLO -+ */ -+enum kdbus_handle_type { -+ KDBUS_HANDLE_NONE, -+ KDBUS_HANDLE_BUS_OWNER, -+ KDBUS_HANDLE_EP_OWNER, -+ KDBUS_HANDLE_CONNECTED, -+}; -+ -+/** -+ * struct kdbus_handle - handle to the kdbus system -+ * @rwlock: handle lock -+ * @type: type of this handle (KDBUS_HANDLE_*) -+ * @bus_owner: bus this handle owns -+ * @ep_owner: endpoint this handle owns -+ * @conn: connection this handle owns -+ * @privileged: Flag to mark a handle as privileged -+ */ -+struct kdbus_handle { -+ struct rw_semaphore rwlock; -+ -+ enum kdbus_handle_type type; -+ union { -+ struct kdbus_bus *bus_owner; -+ struct kdbus_ep *ep_owner; -+ struct kdbus_conn *conn; -+ }; -+ -+ bool privileged:1; -+}; -+ -+static int kdbus_handle_open(struct inode *inode, struct file *file) -+{ -+ struct kdbus_handle *handle; -+ struct kdbus_node *node; -+ int ret; -+ -+ node = kdbus_node_from_inode(inode); -+ if (!kdbus_node_acquire(node)) -+ return -ESHUTDOWN; -+ -+ handle = kzalloc(sizeof(*handle), GFP_KERNEL); -+ if (!handle) { -+ ret = -ENOMEM; -+ goto exit; -+ } -+ -+ init_rwsem(&handle->rwlock); -+ handle->type = KDBUS_HANDLE_NONE; -+ -+ if (node->type == KDBUS_NODE_ENDPOINT) { -+ struct kdbus_ep *ep = kdbus_ep_from_node(node); -+ struct kdbus_bus *bus = ep->bus; -+ -+ /* -+ * A connection is privileged if it is opened on an endpoint -+ * without custom policy and either: -+ * * the user has CAP_IPC_OWNER in the domain user namespace -+ * or -+ * * the callers euid matches the uid of the bus creator -+ */ -+ if (!ep->user && -+ (ns_capable(bus->domain->user_namespace, CAP_IPC_OWNER) || -+ uid_eq(file->f_cred->euid, bus->node.uid))) -+ handle->privileged = true; -+ } -+ -+ file->private_data = handle; -+ ret = 0; -+ -+exit: -+ kdbus_node_release(node); -+ return ret; -+} -+ -+static int kdbus_handle_release(struct inode *inode, struct file *file) -+{ -+ struct kdbus_handle *handle = file->private_data; -+ -+ switch (handle->type) { -+ case KDBUS_HANDLE_BUS_OWNER: -+ if (handle->bus_owner) { -+ kdbus_node_deactivate(&handle->bus_owner->node); -+ kdbus_bus_unref(handle->bus_owner); -+ } -+ break; -+ case KDBUS_HANDLE_EP_OWNER: -+ if (handle->ep_owner) { -+ kdbus_node_deactivate(&handle->ep_owner->node); -+ kdbus_ep_unref(handle->ep_owner); -+ } -+ break; -+ case KDBUS_HANDLE_CONNECTED: -+ kdbus_conn_disconnect(handle->conn, false); -+ kdbus_conn_unref(handle->conn); -+ break; -+ case KDBUS_HANDLE_NONE: -+ /* nothing to clean up */ -+ break; -+ } -+ -+ kfree(handle); -+ -+ return 0; -+} -+ -+static long kdbus_handle_ioctl_control(struct file *file, unsigned int cmd, -+ void __user *argp) -+{ -+ struct kdbus_handle *handle = file->private_data; -+ struct kdbus_node *node = file_inode(file)->i_private; -+ struct kdbus_domain *domain; -+ int ret = 0; -+ -+ if (!kdbus_node_acquire(node)) -+ return -ESHUTDOWN; -+ -+ /* -+ * The parent of control-nodes is always a domain, make sure to pin it -+ * so the parent is actually valid. -+ */ -+ domain = kdbus_domain_from_node(node->parent); -+ if (!kdbus_node_acquire(&domain->node)) { -+ kdbus_node_release(node); -+ return -ESHUTDOWN; -+ } -+ -+ switch (cmd) { -+ case KDBUS_CMD_BUS_MAKE: { -+ struct kdbus_bus *bus; -+ -+ bus = kdbus_cmd_bus_make(domain, argp); -+ if (IS_ERR_OR_NULL(bus)) { -+ ret = PTR_ERR_OR_ZERO(bus); -+ break; -+ } -+ -+ handle->type = KDBUS_HANDLE_BUS_OWNER; -+ handle->bus_owner = bus; -+ break; -+ } -+ -+ default: -+ ret = -EBADFD; -+ break; -+ } -+ -+ kdbus_node_release(&domain->node); -+ kdbus_node_release(node); -+ return ret; -+} -+ -+static long kdbus_handle_ioctl_ep(struct file *file, unsigned int cmd, -+ void __user *buf) -+{ -+ struct kdbus_handle *handle = file->private_data; -+ struct kdbus_node *node = file_inode(file)->i_private; -+ struct kdbus_ep *ep, *file_ep = kdbus_ep_from_node(node); -+ struct kdbus_conn *conn; -+ int ret = 0; -+ -+ if (!kdbus_node_acquire(node)) -+ return -ESHUTDOWN; -+ -+ switch (cmd) { -+ case KDBUS_CMD_ENDPOINT_MAKE: -+ /* creating custom endpoints is a privileged operation */ -+ if (!handle->privileged) { -+ ret = -EPERM; -+ break; -+ } -+ -+ ep = kdbus_cmd_ep_make(file_ep->bus, buf); -+ if (IS_ERR_OR_NULL(ep)) { -+ ret = PTR_ERR_OR_ZERO(ep); -+ break; -+ } -+ -+ handle->type = KDBUS_HANDLE_EP_OWNER; -+ handle->ep_owner = ep; -+ break; -+ -+ case KDBUS_CMD_HELLO: -+ conn = kdbus_cmd_hello(file_ep, handle->privileged, buf); -+ if (IS_ERR_OR_NULL(conn)) { -+ ret = PTR_ERR_OR_ZERO(conn); -+ break; -+ } -+ -+ handle->type = KDBUS_HANDLE_CONNECTED; -+ handle->conn = conn; -+ break; -+ -+ default: -+ ret = -EBADFD; -+ break; -+ } -+ -+ kdbus_node_release(node); -+ return ret; -+} -+ -+static long kdbus_handle_ioctl_ep_owner(struct file *file, unsigned int command, -+ void __user *buf) -+{ -+ struct kdbus_handle *handle = file->private_data; -+ struct kdbus_ep *ep = handle->ep_owner; -+ int ret; -+ -+ if (!kdbus_node_acquire(&ep->node)) -+ return -ESHUTDOWN; -+ -+ switch (command) { -+ case KDBUS_CMD_ENDPOINT_UPDATE: -+ ret = kdbus_cmd_ep_update(ep, buf); -+ break; -+ default: -+ ret = -EBADFD; -+ break; -+ } -+ -+ kdbus_node_release(&ep->node); -+ return ret; -+} -+ -+static long kdbus_handle_ioctl_connected(struct file *file, -+ unsigned int command, void __user *buf) -+{ -+ struct kdbus_handle *handle = file->private_data; -+ struct kdbus_conn *conn = handle->conn; -+ struct kdbus_conn *release_conn = NULL; -+ int ret; -+ -+ release_conn = conn; -+ ret = kdbus_conn_acquire(release_conn); -+ if (ret < 0) -+ return ret; -+ -+ switch (command) { -+ case KDBUS_CMD_BYEBYE: -+ /* -+ * BYEBYE is special; we must not acquire a connection when -+ * calling into kdbus_conn_disconnect() or we will deadlock, -+ * because kdbus_conn_disconnect() will wait for all acquired -+ * references to be dropped. -+ */ -+ kdbus_conn_release(release_conn); -+ release_conn = NULL; -+ ret = kdbus_cmd_byebye_unlocked(conn, buf); -+ break; -+ case KDBUS_CMD_NAME_ACQUIRE: -+ ret = kdbus_cmd_name_acquire(conn, buf); -+ break; -+ case KDBUS_CMD_NAME_RELEASE: -+ ret = kdbus_cmd_name_release(conn, buf); -+ break; -+ case KDBUS_CMD_LIST: -+ ret = kdbus_cmd_list(conn, buf); -+ break; -+ case KDBUS_CMD_CONN_INFO: -+ ret = kdbus_cmd_conn_info(conn, buf); -+ break; -+ case KDBUS_CMD_BUS_CREATOR_INFO: -+ ret = kdbus_cmd_bus_creator_info(conn, buf); -+ break; -+ case KDBUS_CMD_UPDATE: -+ ret = kdbus_cmd_update(conn, buf); -+ break; -+ case KDBUS_CMD_MATCH_ADD: -+ ret = kdbus_cmd_match_add(conn, buf); -+ break; -+ case KDBUS_CMD_MATCH_REMOVE: -+ ret = kdbus_cmd_match_remove(conn, buf); -+ break; -+ case KDBUS_CMD_SEND: -+ ret = kdbus_cmd_send(conn, file, buf); -+ break; -+ case KDBUS_CMD_RECV: -+ ret = kdbus_cmd_recv(conn, buf); -+ break; -+ case KDBUS_CMD_FREE: -+ ret = kdbus_cmd_free(conn, buf); -+ break; -+ default: -+ ret = -EBADFD; -+ break; -+ } -+ -+ kdbus_conn_release(release_conn); -+ return ret; -+} -+ -+static long kdbus_handle_ioctl(struct file *file, unsigned int cmd, -+ unsigned long arg) -+{ -+ struct kdbus_handle *handle = file->private_data; -+ struct kdbus_node *node = kdbus_node_from_inode(file_inode(file)); -+ void __user *argp = (void __user *)arg; -+ long ret = -EBADFD; -+ -+ switch (cmd) { -+ case KDBUS_CMD_BUS_MAKE: -+ case KDBUS_CMD_ENDPOINT_MAKE: -+ case KDBUS_CMD_HELLO: -+ /* bail out early if already typed */ -+ if (handle->type != KDBUS_HANDLE_NONE) -+ break; -+ -+ down_write(&handle->rwlock); -+ if (handle->type == KDBUS_HANDLE_NONE) { -+ if (node->type == KDBUS_NODE_CONTROL) -+ ret = kdbus_handle_ioctl_control(file, cmd, -+ argp); -+ else if (node->type == KDBUS_NODE_ENDPOINT) -+ ret = kdbus_handle_ioctl_ep(file, cmd, argp); -+ } -+ up_write(&handle->rwlock); -+ break; -+ -+ case KDBUS_CMD_ENDPOINT_UPDATE: -+ case KDBUS_CMD_BYEBYE: -+ case KDBUS_CMD_NAME_ACQUIRE: -+ case KDBUS_CMD_NAME_RELEASE: -+ case KDBUS_CMD_LIST: -+ case KDBUS_CMD_CONN_INFO: -+ case KDBUS_CMD_BUS_CREATOR_INFO: -+ case KDBUS_CMD_UPDATE: -+ case KDBUS_CMD_MATCH_ADD: -+ case KDBUS_CMD_MATCH_REMOVE: -+ case KDBUS_CMD_SEND: -+ case KDBUS_CMD_RECV: -+ case KDBUS_CMD_FREE: -+ down_read(&handle->rwlock); -+ if (handle->type == KDBUS_HANDLE_EP_OWNER) -+ ret = kdbus_handle_ioctl_ep_owner(file, cmd, argp); -+ else if (handle->type == KDBUS_HANDLE_CONNECTED) -+ ret = kdbus_handle_ioctl_connected(file, cmd, argp); -+ up_read(&handle->rwlock); -+ break; -+ default: -+ ret = -ENOTTY; -+ break; -+ } -+ -+ return ret < 0 ? ret : 0; -+} -+ -+static unsigned int kdbus_handle_poll(struct file *file, -+ struct poll_table_struct *wait) -+{ -+ struct kdbus_handle *handle = file->private_data; -+ unsigned int mask = POLLOUT | POLLWRNORM; -+ int ret; -+ -+ /* Only a connected endpoint can read/write data */ -+ down_read(&handle->rwlock); -+ if (handle->type != KDBUS_HANDLE_CONNECTED) { -+ up_read(&handle->rwlock); -+ return POLLERR | POLLHUP; -+ } -+ up_read(&handle->rwlock); -+ -+ ret = kdbus_conn_acquire(handle->conn); -+ if (ret < 0) -+ return POLLERR | POLLHUP; -+ -+ poll_wait(file, &handle->conn->wait, wait); -+ -+ if (!list_empty(&handle->conn->queue.msg_list) || -+ atomic_read(&handle->conn->lost_count) > 0) -+ mask |= POLLIN | POLLRDNORM; -+ -+ kdbus_conn_release(handle->conn); -+ -+ return mask; -+} -+ -+static int kdbus_handle_mmap(struct file *file, struct vm_area_struct *vma) -+{ -+ struct kdbus_handle *handle = file->private_data; -+ int ret = -EBADFD; -+ -+ if (down_read_trylock(&handle->rwlock)) { -+ if (handle->type == KDBUS_HANDLE_CONNECTED) -+ ret = kdbus_pool_mmap(handle->conn->pool, vma); -+ up_read(&handle->rwlock); -+ } -+ return ret; -+} -+ -+const struct file_operations kdbus_handle_ops = { -+ .owner = THIS_MODULE, -+ .open = kdbus_handle_open, -+ .release = kdbus_handle_release, -+ .poll = kdbus_handle_poll, -+ .llseek = noop_llseek, -+ .unlocked_ioctl = kdbus_handle_ioctl, -+ .mmap = kdbus_handle_mmap, -+#ifdef CONFIG_COMPAT -+ .compat_ioctl = kdbus_handle_ioctl, -+#endif -+}; -diff --git a/ipc/kdbus/handle.h b/ipc/kdbus/handle.h -new file mode 100644 -index 000000000000..93a372d554a2 ---- /dev/null -+++ b/ipc/kdbus/handle.h -@@ -0,0 +1,85 @@ -+/* -+ * Copyright (C) 2013-2015 Kay Sievers -+ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> -+ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> -+ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> -+ * Copyright (C) 2013-2015 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 -+ -+#include <linux/fs.h> -+#include <uapi/linux/kdbus.h> -+ -+extern const struct file_operations kdbus_handle_ops; -+ -+/** -+ * kdbus_arg - information and state of a single ioctl command item -+ * @type: item type -+ * @item: set by the parser to the first found item of this type -+ * @multiple: whether multiple items of this type are allowed -+ * @mandatory: whether at least one item of this type is required -+ * -+ * This structure describes a single item in an ioctl command payload. The -+ * caller has to pre-fill the type and flags, the parser will then use this -+ * information to verify the ioctl payload. @item is set by the parser to point -+ * to the first occurrence of the item. -+ */ -+struct kdbus_arg { -+ u64 type; -+ struct kdbus_item *item; -+ bool multiple : 1; -+ bool mandatory : 1; -+}; -+ -+/** -+ * kdbus_args - information and state of ioctl command parser -+ * @allowed_flags: set of flags this command supports -+ * @argc: number of items in @argv -+ * @argv: array of items this command supports -+ * @user: set by parser to user-space location of current command -+ * @cmd: set by parser to kernel copy of command payload -+ * @items: points to item array in @cmd -+ * @items_size: size of @items in bytes -+ * -+ * This structure is used to parse ioctl command payloads on each invocation. -+ * The ioctl handler has to pre-fill the flags and allowed items before passing -+ * the object to kdbus_args_parse(). The parser will copy the command payload -+ * into kernel-space and verify the correctness of the data. -+ */ -+struct kdbus_args { -+ u64 allowed_flags; -+ size_t argc; -+ struct kdbus_arg *argv; -+ -+ struct kdbus_cmd __user *user; -+ struct kdbus_cmd *cmd; -+ -+ struct kdbus_item *items; -+ size_t items_size; -+}; -+ -+int __kdbus_args_parse(struct kdbus_args *args, void __user *argp, -+ size_t type_size, size_t items_offset, void **out); -+int kdbus_args_clear(struct kdbus_args *args, int ret); -+ -+#define kdbus_args_parse(_args, _argp, _v) \ -+ ({ \ -+ BUILD_BUG_ON(offsetof(typeof(**(_v)), size) != \ -+ offsetof(struct kdbus_cmd, size)); \ -+ BUILD_BUG_ON(offsetof(typeof(**(_v)), flags) != \ -+ offsetof(struct kdbus_cmd, flags)); \ -+ BUILD_BUG_ON(offsetof(typeof(**(_v)), return_flags) != \ -+ offsetof(struct kdbus_cmd, return_flags)); \ -+ __kdbus_args_parse((_args), (_argp), sizeof(**(_v)), \ -+ offsetof(typeof(**(_v)), items), \ -+ (void **)(_v)); \ -+ }) -+ -+#endif -diff --git a/ipc/kdbus/limits.h b/ipc/kdbus/limits.h -new file mode 100644 -index 000000000000..6450f58cffcf ---- /dev/null -+++ b/ipc/kdbus/limits.h -@@ -0,0 +1,64 @@ -+/* -+ * Copyright (C) 2013-2015 Kay Sievers -+ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> -+ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> -+ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> -+ * Copyright (C) 2013-2015 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_DEFAULTS_H -+#define __KDBUS_DEFAULTS_H -+ -+#include <linux/kernel.h> -+ -+/* maximum size of message header and items */ -+#define KDBUS_MSG_MAX_SIZE SZ_8K -+ -+/* maximum number of message items */ -+#define KDBUS_MSG_MAX_ITEMS 128 -+ -+/* maximum number of memfd items per message */ -+#define KDBUS_MSG_MAX_MEMFD_ITEMS 16 -+ -+/* max size of ioctl command data */ -+#define KDBUS_CMD_MAX_SIZE SZ_32K -+ -+/* maximum number of inflight fds in a target queue per user */ -+#define KDBUS_CONN_MAX_FDS_PER_USER 16 -+ -+/* maximum message payload size */ -+#define KDBUS_MSG_MAX_PAYLOAD_VEC_SIZE SZ_2M -+ -+/* maximum size of bloom bit field in bytes */ -+#define KDBUS_BUS_BLOOM_MAX_SIZE SZ_4K -+ -+/* maximum length of well-known bus name */ -+#define KDBUS_NAME_MAX_LEN 255 -+ -+/* maximum length of bus, domain, ep name */ -+#define KDBUS_SYSNAME_MAX_LEN 63 -+ -+/* maximum number of matches per connection */ -+#define KDBUS_MATCH_MAX 256 -+ -+/* maximum number of queued messages from the same individual user */ -+#define KDBUS_CONN_MAX_MSGS 256 -+ -+/* maximum number of well-known names per connection */ -+#define KDBUS_CONN_MAX_NAMES 256 -+ -+/* maximum number of queued requests waiting for a reply */ -+#define KDBUS_CONN_MAX_REQUESTS_PENDING 128 -+ -+/* maximum number of connections per user in one domain */ -+#define KDBUS_USER_MAX_CONN 1024 -+ -+/* maximum number of buses per user in one domain */ -+#define KDBUS_USER_MAX_BUSES 16 -+ -+#endif -diff --git a/ipc/kdbus/main.c b/ipc/kdbus/main.c -new file mode 100644 -index 000000000000..785f529d98b7 ---- /dev/null -+++ b/ipc/kdbus/main.c -@@ -0,0 +1,125 @@ -+/* -+ * Copyright (C) 2013-2015 Kay Sievers -+ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> -+ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> -+ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> -+ * Copyright (C) 2013-2015 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. -+ */ -+ -+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -+#include <linux/fs.h> -+#include <linux/init.h> -+#include <linux/module.h> -+#include <linux/moduleparam.h> -+ -+#include "util.h" -+#include "fs.h" -+#include "handle.h" -+#include "metadata.h" -+#include "node.h" -+ -+/* -+ * This is a simplified outline of the internal kdbus object relations, for -+ * those interested in the inner life of the driver implementation. -+ * -+ * From a mount point's (domain's) perspective: -+ * -+ * struct kdbus_domain -+ * |» struct kdbus_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_user *user (pinned) -+ * | `» struct kdbus_queue_entry entries (many, embedded) -+ * | |» struct kdbus_pool_slice *slice (pinned) -+ * | |» struct kdbus_conn_reply *reply (owned) -+ * | '» struct kdbus_user *user (pinned) -+ * | -+ * '» struct kdbus_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) -+ */ -+ -+/* kdbus mount-point /sys/fs/kdbus */ -+static struct kobject *kdbus_dir; -+ -+/* global module option to apply a mask to exported metadata */ -+unsigned long long kdbus_meta_attach_mask = KDBUS_ATTACH_TIMESTAMP | -+ KDBUS_ATTACH_CREDS | -+ KDBUS_ATTACH_PIDS | -+ KDBUS_ATTACH_AUXGROUPS | -+ KDBUS_ATTACH_NAMES | -+ KDBUS_ATTACH_SECLABEL | -+ KDBUS_ATTACH_CONN_DESCRIPTION; -+MODULE_PARM_DESC(attach_flags_mask, "Attach-flags mask for exported metadata"); -+module_param_named(attach_flags_mask, kdbus_meta_attach_mask, ullong, 0644); -+ -+static int __init kdbus_init(void) -+{ -+ int ret; -+ -+ kdbus_dir = kobject_create_and_add(KBUILD_MODNAME, fs_kobj); -+ if (!kdbus_dir) -+ return -ENOMEM; -+ -+ ret = kdbus_fs_init(); -+ if (ret < 0) { -+ pr_err("cannot register filesystem: %d\n", ret); -+ goto exit_dir; -+ } -+ -+ pr_info("initialized\n"); -+ return 0; -+ -+exit_dir: -+ kobject_put(kdbus_dir); -+ return ret; -+} -+ -+static void __exit kdbus_exit(void) -+{ -+ kdbus_fs_exit(); -+ kobject_put(kdbus_dir); -+} -+ -+module_init(kdbus_init); -+module_exit(kdbus_exit); -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("D-Bus, powerful, easy to use interprocess communication"); -+MODULE_ALIAS_FS(KBUILD_MODNAME "fs"); -diff --git a/ipc/kdbus/util.c b/ipc/kdbus/util.c -new file mode 100644 -index 000000000000..eaa806a27997 ---- /dev/null -+++ b/ipc/kdbus/util.c -@@ -0,0 +1,201 @@ -+/* -+ * Copyright (C) 2013-2015 Kay Sievers -+ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> -+ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> -+ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> -+ * Copyright (C) 2013-2015 Linux Foundation -+ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> -+ * -+ * 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/capability.h> -+#include <linux/cred.h> -+#include <linux/ctype.h> -+#include <linux/err.h> -+#include <linux/file.h> -+#include <linux/slab.h> -+#include <linux/string.h> -+#include <linux/uaccess.h> -+#include <linux/uio.h> -+#include <linux/user_namespace.h> -+ -+#include "limits.h" -+#include "util.h" -+ -+/** -+ * kdbus_copy_from_user() - copy aligned data from user-space -+ * @dest: target buffer in kernel memory -+ * @user_ptr: user-provided source buffer -+ * @size: memory size to copy from user -+ * -+ * This copies @size bytes from @user_ptr into the kernel, just like -+ * copy_from_user() does. But we enforce an 8-byte alignment and reject any -+ * unaligned user-space pointers. -+ * -+ * Return: 0 on success, negative error code on failure. -+ */ -+int kdbus_copy_from_user(void *dest, void __user *user_ptr, size_t size) -+{ -+ if (!KDBUS_IS_ALIGNED8((uintptr_t)user_ptr)) -+ return -EFAULT; -+ -+ if (copy_from_user(dest, user_ptr, size)) -+ return -EFAULT; -+ -+ return 0; -+} -+ -+/** -+ * kdbus_memdup_user() - copy dynamically sized object from user-space -+ * @user_ptr: user-provided source buffer -+ * @sz_min: minimum object size -+ * @sz_max: maximum object size -+ * -+ * This copies a dynamically sized object from user-space into kernel-space. We -+ * require the object to have a 64bit size field at offset 0. We read it out -+ * first, allocate a suitably sized buffer and then copy all data. -+ * -+ * The @sz_min and @sz_max parameters define possible min and max object sizes -+ * so user-space cannot trigger un-bound kernel-space allocations. -+ * -+ * The same alignment-restrictions as described in kdbus_copy_from_user() apply. -+ * -+ * Return: pointer to dynamically allocated copy, or ERR_PTR() on failure. -+ */ -+void *kdbus_memdup_user(void __user *user_ptr, size_t sz_min, size_t sz_max) -+{ -+ void *ptr; -+ u64 size; -+ int ret; -+ -+ ret = kdbus_copy_from_user(&size, user_ptr, sizeof(size)); -+ if (ret < 0) -+ return ERR_PTR(ret); -+ -+ if (size < sz_min) -+ return ERR_PTR(-EINVAL); -+ -+ if (size > sz_max) -+ return ERR_PTR(-EMSGSIZE); -+ -+ ptr = memdup_user(user_ptr, size); -+ if (IS_ERR(ptr)) -+ return ptr; -+ -+ if (*(u64 *)ptr != size) { -+ kfree(ptr); -+ return ERR_PTR(-EINVAL); -+ } -+ -+ return ptr; -+} -+ -+/** -+ * kdbus_verify_uid_prefix() - verify UID prefix of a user-supplied name -+ * @name: user-supplied name to verify -+ * @user_ns: user-namespace to act in -+ * @kuid: Kernel internal uid of user -+ * -+ * This verifies that the user-supplied name @name has their UID as prefix. This -+ * is the default name-spacing policy we enforce on user-supplied names for -+ * public kdbus entities like buses and endpoints. -+ * -+ * The user must supply names prefixed with "<UID>-", whereas the UID is -+ * interpreted in the user-namespace of the domain. If the user fails to supply -+ * such a prefixed name, we reject it. -+ * -+ * Return: 0 on success, negative error code on failure -+ */ -+int kdbus_verify_uid_prefix(const char *name, struct user_namespace *user_ns, -+ kuid_t kuid) -+{ -+ uid_t uid; -+ char prefix[16]; -+ -+ /* -+ * The kuid must have a mapping into the userns of the domain -+ * otherwise do not allow creation of buses nor endpoints. -+ */ -+ uid = from_kuid(user_ns, kuid); -+ if (uid == (uid_t) -1) -+ return -EINVAL; -+ -+ snprintf(prefix, sizeof(prefix), "%u-", uid); -+ if (strncmp(name, prefix, strlen(prefix)) != 0) -+ return -EINVAL; -+ -+ return 0; -+} -+ -+/** -+ * kdbus_sanitize_attach_flags() - Sanitize attach flags from user-space -+ * @flags: Attach flags provided by userspace -+ * @attach_flags: A pointer where to store the valid attach flags -+ * -+ * Convert attach-flags provided by user-space into a valid mask. If the mask -+ * is invalid, an error is returned. The sanitized attach flags are stored in -+ * the output parameter. -+ * -+ * Return: 0 on success, negative error on failure. -+ */ -+int kdbus_sanitize_attach_flags(u64 flags, u64 *attach_flags) -+{ -+ /* 'any' degrades to 'all' for compatibility */ -+ if (flags == _KDBUS_ATTACH_ANY) -+ flags = _KDBUS_ATTACH_ALL; -+ -+ /* reject unknown attach flags */ -+ if (flags & ~_KDBUS_ATTACH_ALL) -+ return -EINVAL; -+ -+ *attach_flags = flags; -+ return 0; -+} -+ -+/** -+ * kdbus_kvec_set - helper utility to assemble kvec arrays -+ * @kvec: kvec entry to use -+ * @src: Source address to set in @kvec -+ * @len: Number of bytes in @src -+ * @total_len: Pointer to total length variable -+ * -+ * Set @src and @len in @kvec, and increase @total_len by @len. -+ */ -+void kdbus_kvec_set(struct kvec *kvec, void *src, size_t len, u64 *total_len) -+{ -+ kvec->iov_base = src; -+ kvec->iov_len = len; -+ *total_len += len; -+} -+ -+static const char * const zeros = "\0\0\0\0\0\0\0"; -+ -+/** -+ * kdbus_kvec_pad - conditionally write a padding kvec -+ * @kvec: kvec entry to use -+ * @len: Total length used for kvec array -+ * -+ * Check if the current total byte length of the array in @len is aligned to -+ * 8 bytes. If it isn't, fill @kvec with padding information and increase @len -+ * by the number of bytes stored in @kvec. -+ * -+ * Return: the number of added padding bytes. -+ */ -+size_t kdbus_kvec_pad(struct kvec *kvec, u64 *len) -+{ -+ size_t pad = KDBUS_ALIGN8(*len) - *len; -+ -+ if (!pad) -+ return 0; -+ -+ kvec->iov_base = (void *)zeros; -+ kvec->iov_len = pad; -+ -+ *len += pad; -+ -+ return pad; -+} -diff --git a/ipc/kdbus/util.h b/ipc/kdbus/util.h -new file mode 100644 -index 000000000000..9caadb337912 ---- /dev/null -+++ b/ipc/kdbus/util.h -@@ -0,0 +1,74 @@ -+/* -+ * Copyright (C) 2013-2015 Kay Sievers -+ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> -+ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> -+ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> -+ * Copyright (C) 2013-2015 Linux Foundation -+ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> -+ * -+ * 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_UTIL_H -+#define __KDBUS_UTIL_H -+ -+#include <linux/dcache.h> -+#include <linux/ioctl.h> -+ -+#include "kdbus.h" -+ -+/* all exported addresses are 64 bit */ -+#define KDBUS_PTR(addr) ((void __user *)(uintptr_t)(addr)) -+ -+/* all exported sizes are 64 bit and data aligned to 64 bit */ -+#define KDBUS_ALIGN8(s) ALIGN((s), 8) -+#define KDBUS_IS_ALIGNED8(s) (IS_ALIGNED(s, 8)) -+ -+/** -+ * kdbus_member_set_user - write a structure member to user memory -+ * @_s: Variable to copy from -+ * @_b: Buffer to write to -+ * @_t: Structure type -+ * @_m: Member name in the passed structure -+ * -+ * Return: the result of copy_to_user() -+ */ -+#define kdbus_member_set_user(_s, _b, _t, _m) \ -+({ \ -+ u64 __user *_sz = \ -+ (void __user *)((u8 __user *)(_b) + offsetof(_t, _m)); \ -+ copy_to_user(_sz, _s, sizeof(((_t *)0)->_m)); \ -+}) -+ -+/** -+ * kdbus_strhash - calculate a hash -+ * @str: String -+ * -+ * Return: hash value -+ */ -+static inline unsigned int kdbus_strhash(const char *str) -+{ -+ unsigned long hash = init_name_hash(); -+ -+ while (*str) -+ hash = partial_name_hash(*str++, hash); -+ -+ return end_name_hash(hash); -+} -+ -+int kdbus_verify_uid_prefix(const char *name, struct user_namespace *user_ns, -+ kuid_t kuid); -+int kdbus_sanitize_attach_flags(u64 flags, u64 *attach_flags); -+ -+int kdbus_copy_from_user(void *dest, void __user *user_ptr, size_t size); -+void *kdbus_memdup_user(void __user *user_ptr, size_t sz_min, size_t sz_max); -+ -+struct kvec; -+ -+void kdbus_kvec_set(struct kvec *kvec, void *src, size_t len, u64 *total_len); -+size_t kdbus_kvec_pad(struct kvec *kvec, u64 *len); -+ -+#endif --- -2.4.3 - - -From a03b602b14ea7cb497f44af6e344a53785df2753 Mon Sep 17 00:00:00 2001 -From: Daniel Mack <daniel@zonque.org> -Date: Thu, 11 Sep 2014 18:56:41 +0200 -Subject: [PATCH 004/132] kdbus: add connection pool implementation - -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. - -Signed-off-by: Daniel Mack <daniel@zonque.org> -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Djalal Harouni <tixxdz@opendz.org> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - ipc/kdbus/pool.c | 728 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ - ipc/kdbus/pool.h | 46 ++++ - 2 files changed, 774 insertions(+) - create mode 100644 ipc/kdbus/pool.c - create mode 100644 ipc/kdbus/pool.h - -diff --git a/ipc/kdbus/pool.c b/ipc/kdbus/pool.c -new file mode 100644 -index 000000000000..139bb77056b3 ---- /dev/null -+++ b/ipc/kdbus/pool.c -@@ -0,0 +1,728 @@ -+/* -+ * Copyright (C) 2013-2015 Kay Sievers -+ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> -+ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> -+ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> -+ * Copyright (C) 2013-2015 Linux Foundation -+ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> -+ * -+ * 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 <linux/uio.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 -+ * @accounted_size: Currently accounted memory in bytes -+ * @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_SEND are copied direcly by the -+ * sending process into the receiver's pool. -+ * -+ * Messages received with KDBUS_CMD_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_FREE. -+ */ -+struct kdbus_pool { -+ struct file *f; -+ size_t size; -+ size_t accounted_size; -+ 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 -+ * @accounted: Accounted as queue slice -+ * @ref_kernel: Kernel holds a reference -+ * @ref_user: Userspace holds a reference -+ * -+ * 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:1; -+ bool accounted:1; -+ bool ref_kernel:1; -+ bool ref_user:1; -+}; -+ -+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; -+ 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; -+ else -+ BUG(); -+ } -+ -+ 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 -+ * @accounted: Whether this slice should be accounted for -+ * -+ * The returned slice is used for kdbus_pool_slice_release() to -+ * free the allocated memory. If either @kvec or @iovec is non-NULL, the data -+ * will be copied from kernel or userspace memory into the new slice at -+ * offset 0. -+ * -+ * 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, bool accounted) -+{ -+ size_t slice_size = KDBUS_ALIGN8(size); -+ struct rb_node *n, *found = NULL; -+ struct kdbus_pool_slice *s; -+ int ret = 0; -+ -+ if (WARN_ON(!size)) -+ return ERR_PTR(-EINVAL); -+ -+ /* 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 = -EXFULL; -+ goto exit_unlock; -+ } -+ -+ /* no exact match, use the closest one */ -+ if (!n) { -+ struct kdbus_pool_slice *s_new; -+ -+ s = rb_entry(found, struct kdbus_pool_slice, rb_node); -+ -+ /* 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; -+ } -+ -+ /* move slice from free to the busy tree */ -+ rb_erase(found, &pool->slices_free); -+ kdbus_pool_add_busy_slice(pool, s); -+ -+ WARN_ON(s->ref_kernel || s->ref_user); -+ -+ s->ref_kernel = true; -+ s->free = false; -+ s->accounted = accounted; -+ if (accounted) -+ pool->accounted_size += s->size; -+ mutex_unlock(&pool->lock); -+ -+ return s; -+ -+exit_unlock: -+ mutex_unlock(&pool->lock); -+ return ERR_PTR(ret); -+} -+ -+static void __kdbus_pool_slice_release(struct kdbus_pool_slice *slice) -+{ -+ struct kdbus_pool *pool = slice->pool; -+ -+ /* don't free the slice if either has a reference */ -+ if (slice->ref_kernel || slice->ref_user) -+ return; -+ -+ if (WARN_ON(slice->free)) -+ return; -+ -+ rb_erase(&slice->rb_node, &pool->slices_busy); -+ -+ /* 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_release() - drop kernel-reference on allocated slice -+ * @slice: Slice allocated from the pool -+ * -+ * This releases the kernel-reference on the given slice. If the -+ * kernel-reference and the user-reference on a slice are dropped, the slice is -+ * returned to the pool. -+ * -+ * So far, we do not implement full ref-counting on slices. Each, kernel and -+ * user-space can have exactly one reference to a slice. If both are dropped at -+ * the same time, the slice is released. -+ */ -+void kdbus_pool_slice_release(struct kdbus_pool_slice *slice) -+{ -+ struct kdbus_pool *pool; -+ -+ if (!slice) -+ return; -+ -+ /* @slice may be freed, so keep local ptr to @pool */ -+ pool = slice->pool; -+ -+ mutex_lock(&pool->lock); -+ /* kernel must own a ref to @slice to drop it */ -+ WARN_ON(!slice->ref_kernel); -+ slice->ref_kernel = false; -+ /* no longer kernel-owned, de-account slice */ -+ if (slice->accounted && !WARN_ON(pool->accounted_size < slice->size)) -+ pool->accounted_size -= slice->size; -+ __kdbus_pool_slice_release(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 or not public. -+ */ -+int kdbus_pool_release_offset(struct kdbus_pool *pool, size_t off) -+{ -+ struct kdbus_pool_slice *slice; -+ int ret = 0; -+ -+ /* 'pool->size' is used as dummy offset for empty slices */ -+ if (off == pool->size) -+ return 0; -+ -+ mutex_lock(&pool->lock); -+ slice = kdbus_pool_find_slice(pool, off); -+ if (slice && slice->ref_user) { -+ slice->ref_user = false; -+ __kdbus_pool_slice_release(slice); -+ } else { -+ ret = -ENXIO; -+ } -+ mutex_unlock(&pool->lock); -+ -+ return ret; -+} -+ -+/** -+ * kdbus_pool_publish_empty() - publish empty slice to user-space -+ * @pool: pool to operate on -+ * @off: output storage for offset, or NULL -+ * @size: output storage for size, or NULL -+ * -+ * This is the same as kdbus_pool_slice_publish(), but uses a dummy slice with -+ * size 0. The returned offset points to the end of the pool and is never -+ * returned on real slices. -+ */ -+void kdbus_pool_publish_empty(struct kdbus_pool *pool, u64 *off, u64 *size) -+{ -+ if (off) -+ *off = pool->size; -+ if (size) -+ *size = 0; -+} -+ -+/** -+ * kdbus_pool_slice_publish() - publish slice to user-space -+ * @slice: The slice -+ * @out_offset: Output storage for offset, or NULL -+ * @out_size: Output storage for size, or NULL -+ * -+ * This prepares a slice to be published to user-space. -+ * -+ * This call combines the following operations: -+ * * the memory region is flushed so the user's memory view is consistent -+ * * the slice is marked as referenced by user-space, so user-space has to -+ * call KDBUS_CMD_FREE to release it -+ * * the offset and size of the slice are written to the given output -+ * arguments, if non-NULL -+ */ -+void kdbus_pool_slice_publish(struct kdbus_pool_slice *slice, -+ u64 *out_offset, u64 *out_size) -+{ -+ mutex_lock(&slice->pool->lock); -+ /* kernel must own a ref to @slice to gain a user-space ref */ -+ WARN_ON(!slice->ref_kernel); -+ slice->ref_user = true; -+ mutex_unlock(&slice->pool->lock); -+ -+ if (out_offset) -+ *out_offset = slice->off; -+ if (out_size) -+ *out_size = slice->size; -+} -+ -+/** -+ * kdbus_pool_slice_offset() - Get a slice's offset inside the pool -+ * @slice: Slice to return the offset of -+ * -+ * Return: The internal offset @slice inside the pool. -+ */ -+off_t kdbus_pool_slice_offset(const struct kdbus_pool_slice *slice) -+{ -+ return slice->off; -+} -+ -+/** -+ * kdbus_pool_slice_size() - get size of a pool slice -+ * @slice: slice to query -+ * -+ * Return: size of the given slice -+ */ -+size_t kdbus_pool_slice_size(const struct kdbus_pool_slice *slice) -+{ -+ return slice->size; -+} -+ -+/** -+ * 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, 0); -+ 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->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_accounted() - retrieve accounting information -+ * @pool: pool to query -+ * @size: output for overall pool size -+ * @acc: output for currently accounted size -+ * -+ * This returns accounting information of the pool. Note that the data might -+ * change after the function returns, as the pool lock is dropped. You need to -+ * protect the data via other means, if you need reliable accounting. -+ */ -+void kdbus_pool_accounted(struct kdbus_pool *pool, size_t *size, size_t *acc) -+{ -+ mutex_lock(&pool->lock); -+ if (size) -+ *size = pool->size; -+ if (acc) -+ *acc = pool->accounted_size; -+ mutex_unlock(&pool->lock); -+} -+ -+/** -+ * kdbus_pool_slice_copy_iovec() - copy user memory to a slice -+ * @slice: The slice to write to -+ * @off: Offset in the slice to write to -+ * @iov: iovec array, pointing to data to copy -+ * @iov_len: Number of elements in @iov -+ * @total_len: Total number of bytes described in members of @iov -+ * -+ * User memory referenced by @iov will be copied into @slice at offset @off. -+ * -+ * Return: the numbers of bytes copied, negative errno on failure. -+ */ -+ssize_t -+kdbus_pool_slice_copy_iovec(const struct kdbus_pool_slice *slice, loff_t off, -+ struct iovec *iov, size_t iov_len, size_t total_len) -+{ -+ struct iov_iter iter; -+ ssize_t len; -+ -+ if (WARN_ON(off + total_len > slice->size)) -+ return -EFAULT; -+ -+ off += slice->off; -+ iov_iter_init(&iter, WRITE, iov, iov_len, total_len); -+ len = vfs_iter_write(slice->pool->f, &iter, &off); -+ -+ return (len >= 0 && len != total_len) ? -EFAULT : len; -+} -+ -+/** -+ * kdbus_pool_slice_copy_kvec() - copy kernel memory to a slice -+ * @slice: The slice to write to -+ * @off: Offset in the slice to write to -+ * @kvec: kvec array, pointing to data to copy -+ * @kvec_len: Number of elements in @kvec -+ * @total_len: Total number of bytes described in members of @kvec -+ * -+ * Kernel memory referenced by @kvec will be copied into @slice at offset @off. -+ * -+ * Return: the numbers of bytes copied, negative errno on failure. -+ */ -+ssize_t kdbus_pool_slice_copy_kvec(const struct kdbus_pool_slice *slice, -+ loff_t off, struct kvec *kvec, -+ size_t kvec_len, size_t total_len) -+{ -+ struct iov_iter iter; -+ mm_segment_t old_fs; -+ ssize_t len; -+ -+ if (WARN_ON(off + total_len > slice->size)) -+ return -EFAULT; -+ -+ off += slice->off; -+ iov_iter_kvec(&iter, WRITE | ITER_KVEC, kvec, kvec_len, total_len); -+ -+ old_fs = get_fs(); -+ set_fs(get_ds()); -+ len = vfs_iter_write(slice->pool->f, &iter, &off); -+ set_fs(old_fs); -+ -+ return (len >= 0 && len != total_len) ? -EFAULT : len; -+} -+ -+/** -+ * kdbus_pool_slice_copy() - copy data from one slice into another -+ * @slice_dst: destination slice -+ * @slice_src: source slice -+ * -+ * Return: 0 on success, negative error number on failure. -+ */ -+int kdbus_pool_slice_copy(const struct kdbus_pool_slice *slice_dst, -+ const struct kdbus_pool_slice *slice_src) -+{ -+ struct file *f_src = slice_src->pool->f; -+ struct file *f_dst = slice_dst->pool->f; -+ struct inode *i_dst = file_inode(f_dst); -+ struct address_space *mapping_dst = f_dst->f_mapping; -+ const struct address_space_operations *aops = mapping_dst->a_ops; -+ unsigned long len = slice_src->size; -+ loff_t off_src = slice_src->off; -+ loff_t off_dst = slice_dst->off; -+ mm_segment_t old_fs; -+ int ret = 0; -+ -+ if (WARN_ON(slice_src->size != slice_dst->size) || -+ WARN_ON(slice_src->free || slice_dst->free)) -+ return -EINVAL; -+ -+ mutex_lock(&i_dst->i_mutex); -+ old_fs = get_fs(); -+ set_fs(get_ds()); -+ while (len > 0) { -+ unsigned long page_off; -+ unsigned long copy_len; -+ char __user *kaddr; -+ struct page *page; -+ ssize_t n_read; -+ void *fsdata; -+ long status; -+ -+ page_off = off_dst & (PAGE_CACHE_SIZE - 1); -+ copy_len = min_t(unsigned long, -+ PAGE_CACHE_SIZE - page_off, len); -+ -+ status = aops->write_begin(f_dst, mapping_dst, off_dst, -+ copy_len, 0, &page, &fsdata); -+ if (unlikely(status < 0)) { -+ ret = status; -+ break; -+ } -+ -+ kaddr = (char __force __user *)kmap(page) + page_off; -+ n_read = f_src->f_op->read(f_src, kaddr, copy_len, &off_src); -+ kunmap(page); -+ mark_page_accessed(page); -+ flush_dcache_page(page); -+ -+ if (unlikely(n_read != copy_len)) { -+ ret = -EFAULT; -+ break; -+ } -+ -+ status = aops->write_end(f_dst, mapping_dst, off_dst, -+ copy_len, copy_len, page, fsdata); -+ if (unlikely(status != copy_len)) { -+ ret = -EFAULT; -+ break; -+ } -+ -+ off_dst += copy_len; -+ len -= copy_len; -+ } -+ set_fs(old_fs); -+ mutex_unlock(&i_dst->i_mutex); -+ -+ return ret; -+} -+ -+/** -+ * 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); -+} -diff --git a/ipc/kdbus/pool.h b/ipc/kdbus/pool.h -new file mode 100644 -index 000000000000..a9038213aa4d ---- /dev/null -+++ b/ipc/kdbus/pool.h -@@ -0,0 +1,46 @@ -+/* -+ * Copyright (C) 2013-2015 Kay Sievers -+ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> -+ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> -+ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> -+ * Copyright (C) 2013-2015 Linux Foundation -+ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> -+ * -+ * 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_POOL_H -+#define __KDBUS_POOL_H -+ -+#include <linux/uio.h> -+ -+struct kdbus_pool; -+struct kdbus_pool_slice; -+ -+struct kdbus_pool *kdbus_pool_new(const char *name, size_t size); -+void kdbus_pool_free(struct kdbus_pool *pool); -+void kdbus_pool_accounted(struct kdbus_pool *pool, size_t *size, size_t *acc); -+int kdbus_pool_mmap(const struct kdbus_pool *pool, struct vm_area_struct *vma); -+int kdbus_pool_release_offset(struct kdbus_pool *pool, size_t off); -+void kdbus_pool_publish_empty(struct kdbus_pool *pool, u64 *off, u64 *size); -+ -+struct kdbus_pool_slice *kdbus_pool_slice_alloc(struct kdbus_pool *pool, -+ size_t size, bool accounted); -+void kdbus_pool_slice_release(struct kdbus_pool_slice *slice); -+void kdbus_pool_slice_publish(struct kdbus_pool_slice *slice, -+ u64 *out_offset, u64 *out_size); -+off_t kdbus_pool_slice_offset(const struct kdbus_pool_slice *slice); -+size_t kdbus_pool_slice_size(const struct kdbus_pool_slice *slice); -+int kdbus_pool_slice_copy(const struct kdbus_pool_slice *slice_dst, -+ const struct kdbus_pool_slice *slice_src); -+ssize_t kdbus_pool_slice_copy_kvec(const struct kdbus_pool_slice *slice, -+ loff_t off, struct kvec *kvec, -+ size_t kvec_count, size_t total_len); -+ssize_t kdbus_pool_slice_copy_iovec(const struct kdbus_pool_slice *slice, -+ loff_t off, struct iovec *iov, -+ size_t iov_count, size_t total_len); -+ -+#endif --- -2.4.3 - - -From 5fc8dd5c84fcca5af199e71e246be1bd87028a06 Mon Sep 17 00:00:00 2001 -From: Daniel Mack <daniel@zonque.org> -Date: Thu, 11 Sep 2014 18:57:24 +0200 -Subject: [PATCH 005/132] kdbus: add connection, queue handling and message - validation code - -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. - -Signed-off-by: Daniel Mack <daniel@zonque.org> -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Djalal Harouni <tixxdz@opendz.org> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - ipc/kdbus/connection.c | 2215 ++++++++++++++++++++++++++++++++++++++++++++++++ - ipc/kdbus/connection.h | 257 ++++++ - ipc/kdbus/item.c | 339 ++++++++ - ipc/kdbus/item.h | 64 ++ - ipc/kdbus/message.c | 616 ++++++++++++++ - ipc/kdbus/message.h | 133 +++ - ipc/kdbus/queue.c | 678 +++++++++++++++ - ipc/kdbus/queue.h | 92 ++ - ipc/kdbus/reply.c | 259 ++++++ - ipc/kdbus/reply.h | 68 ++ - ipc/kdbus/util.h | 2 +- - 11 files changed, 4722 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 - create mode 100644 ipc/kdbus/reply.c - create mode 100644 ipc/kdbus/reply.h - -diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c -new file mode 100644 -index 000000000000..e554f1a71aa1 ---- /dev/null -+++ b/ipc/kdbus/connection.c -@@ -0,0 +1,2215 @@ -+/* -+ * Copyright (C) 2013-2015 Kay Sievers -+ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> -+ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> -+ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> -+ * Copyright (C) 2013-2015 Linux Foundation -+ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> -+ * -+ * 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/fs_struct.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/path.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 <linux/uio.h> -+ -+#include "bus.h" -+#include "connection.h" -+#include "endpoint.h" -+#include "handle.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 "pool.h" -+#include "reply.h" -+#include "util.h" -+#include "queue.h" -+ -+#define KDBUS_CONN_ACTIVE_BIAS (INT_MIN + 2) -+#define KDBUS_CONN_ACTIVE_NEW (INT_MIN + 1) -+ -+static struct kdbus_conn *kdbus_conn_new(struct kdbus_ep *ep, bool privileged, -+ struct kdbus_cmd_hello *hello, -+ const char *name, -+ const struct kdbus_creds *creds, -+ const struct kdbus_pids *pids, -+ const char *seclabel, -+ const char *conn_description) -+{ -+#ifdef CONFIG_DEBUG_LOCK_ALLOC -+ static struct lock_class_key __key; -+#endif -+ struct kdbus_pool_slice *slice = NULL; -+ struct kdbus_bus *bus = ep->bus; -+ struct kdbus_conn *conn; -+ u64 attach_flags_send; -+ u64 attach_flags_recv; -+ u64 items_size = 0; -+ bool is_policy_holder; -+ bool is_activator; -+ bool is_monitor; -+ struct kvec kvec; -+ int ret; -+ -+ struct { -+ u64 size; -+ u64 type; -+ struct kdbus_bloom_parameter bloom; -+ } bloom_item; -+ -+ is_monitor = hello->flags & KDBUS_HELLO_MONITOR; -+ is_activator = hello->flags & KDBUS_HELLO_ACTIVATOR; -+ is_policy_holder = hello->flags & KDBUS_HELLO_POLICY_HOLDER; -+ -+ if (!hello->pool_size || !IS_ALIGNED(hello->pool_size, PAGE_SIZE)) -+ return ERR_PTR(-EINVAL); -+ if (is_monitor + is_activator + is_policy_holder > 1) -+ return ERR_PTR(-EINVAL); -+ if (name && !is_activator && !is_policy_holder) -+ return ERR_PTR(-EINVAL); -+ if (!name && (is_activator || is_policy_holder)) -+ return ERR_PTR(-EINVAL); -+ if (name && !kdbus_name_is_valid(name, true)) -+ return ERR_PTR(-EINVAL); -+ if (is_monitor && ep->user) -+ return ERR_PTR(-EOPNOTSUPP); -+ if (!privileged && (is_activator || is_policy_holder || is_monitor)) -+ return ERR_PTR(-EPERM); -+ if ((creds || pids || seclabel) && !privileged) -+ return ERR_PTR(-EPERM); -+ -+ ret = kdbus_sanitize_attach_flags(hello->attach_flags_send, -+ &attach_flags_send); -+ if (ret < 0) -+ return ERR_PTR(ret); -+ -+ ret = kdbus_sanitize_attach_flags(hello->attach_flags_recv, -+ &attach_flags_recv); -+ if (ret < 0) -+ return ERR_PTR(ret); -+ -+ /* The attach flags must always satisfy the bus requirements. */ -+ if (bus->attach_flags_req & ~attach_flags_send) -+ return ERR_PTR(-ECONNREFUSED); -+ -+ conn = kzalloc(sizeof(*conn), GFP_KERNEL); -+ if (!conn) -+ return ERR_PTR(-ENOMEM); -+ -+ kref_init(&conn->kref); -+ atomic_set(&conn->active, KDBUS_CONN_ACTIVE_NEW); -+#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->request_count, 0); -+ atomic_set(&conn->lost_count, 0); -+ INIT_DELAYED_WORK(&conn->work, kdbus_reply_list_scan_work); -+ conn->cred = get_current_cred(); -+ init_waitqueue_head(&conn->wait); -+ kdbus_queue_init(&conn->queue); -+ conn->privileged = privileged; -+ conn->ep = kdbus_ep_ref(ep); -+ conn->id = atomic64_inc_return(&bus->domain->last_id); -+ conn->flags = hello->flags; -+ atomic64_set(&conn->attach_flags_send, attach_flags_send); -+ atomic64_set(&conn->attach_flags_recv, attach_flags_recv); -+ INIT_LIST_HEAD(&conn->monitor_entry); -+ -+ if (conn_description) { -+ conn->description = kstrdup(conn_description, GFP_KERNEL); -+ if (!conn->description) { -+ ret = -ENOMEM; -+ goto exit_unref; -+ } -+ } -+ -+ conn->pool = kdbus_pool_new(conn->description, hello->pool_size); -+ if (IS_ERR(conn->pool)) { -+ ret = PTR_ERR(conn->pool); -+ conn->pool = NULL; -+ goto exit_unref; -+ } -+ -+ 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_unref; -+ } -+ -+ /* return properties of this connection to the caller */ -+ hello->bus_flags = bus->bus_flags; -+ hello->id = conn->id; -+ -+ BUILD_BUG_ON(sizeof(bus->id128) != sizeof(hello->id128)); -+ memcpy(hello->id128, bus->id128, sizeof(hello->id128)); -+ -+ conn->meta = kdbus_meta_proc_new(); -+ if (IS_ERR(conn->meta)) { -+ ret = PTR_ERR(conn->meta); -+ conn->meta = NULL; -+ goto exit_unref; -+ } -+ -+ /* privileged processes can impersonate somebody else */ -+ if (creds || pids || seclabel) { -+ ret = kdbus_meta_proc_fake(conn->meta, creds, pids, seclabel); -+ if (ret < 0) -+ goto exit_unref; -+ -+ conn->faked_meta = true; -+ } else { -+ ret = kdbus_meta_proc_collect(conn->meta, -+ KDBUS_ATTACH_CREDS | -+ KDBUS_ATTACH_PIDS | -+ KDBUS_ATTACH_AUXGROUPS | -+ 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; -+ } -+ -+ /* -+ * Account the connection against the current user (UID), or for -+ * custom endpoints use the anonymous user assigned to the endpoint. -+ * Note that limits are always accounted against the real UID, not -+ * the effective UID (cred->user always points to the accounting of -+ * cred->uid, not cred->euid). -+ */ -+ if (ep->user) { -+ conn->user = kdbus_user_ref(ep->user); -+ } else { -+ conn->user = kdbus_user_lookup(ep->bus->domain, current_uid()); -+ if (IS_ERR(conn->user)) { -+ ret = PTR_ERR(conn->user); -+ conn->user = NULL; -+ goto exit_unref; -+ } -+ } -+ -+ if (atomic_inc_return(&conn->user->connections) > KDBUS_USER_MAX_CONN) { -+ /* decremented by destructor as conn->user is valid */ -+ ret = -EMFILE; -+ goto exit_unref; -+ } -+ -+ bloom_item.size = sizeof(bloom_item); -+ bloom_item.type = KDBUS_ITEM_BLOOM_PARAMETER; -+ bloom_item.bloom = bus->bloom; -+ kdbus_kvec_set(&kvec, &bloom_item, bloom_item.size, &items_size); -+ -+ slice = kdbus_pool_slice_alloc(conn->pool, items_size, false); -+ if (IS_ERR(slice)) { -+ ret = PTR_ERR(slice); -+ slice = NULL; -+ goto exit_unref; -+ } -+ -+ ret = kdbus_pool_slice_copy_kvec(slice, 0, &kvec, 1, items_size); -+ if (ret < 0) -+ goto exit_unref; -+ -+ kdbus_pool_slice_publish(slice, &hello->offset, &hello->items_size); -+ kdbus_pool_slice_release(slice); -+ -+ return conn; -+ -+exit_unref: -+ kdbus_pool_slice_release(slice); -+ kdbus_conn_unref(conn); -+ return ERR_PTR(ret); -+} -+ -+static void __kdbus_conn_free(struct kref *kref) -+{ -+ struct kdbus_conn *conn = container_of(kref, struct kdbus_conn, kref); -+ -+ WARN_ON(kdbus_conn_active(conn)); -+ WARN_ON(delayed_work_pending(&conn->work)); -+ WARN_ON(!list_empty(&conn->queue.msg_list)); -+ WARN_ON(!list_empty(&conn->names_list)); -+ WARN_ON(!list_empty(&conn->names_queue_list)); -+ WARN_ON(!list_empty(&conn->reply_list)); -+ -+ if (conn->user) { -+ atomic_dec(&conn->user->connections); -+ kdbus_user_unref(conn->user); -+ } -+ -+ kdbus_meta_proc_unref(conn->meta); -+ kdbus_match_db_free(conn->match_db); -+ kdbus_pool_free(conn->pool); -+ kdbus_ep_unref(conn->ep); -+ put_cred(conn->cred); -+ kfree(conn->description); -+ kfree(conn->quota); -+ kfree(conn); -+} -+ -+/** -+ * kdbus_conn_ref() - take a connection reference -+ * @conn: Connection, may be %NULL -+ * -+ * Return: the connection itself -+ */ -+struct kdbus_conn *kdbus_conn_ref(struct kdbus_conn *conn) -+{ -+ if (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_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_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; -+ -+ if (!conn) -+ return; -+ -+#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); -+} -+ -+static int kdbus_conn_connect(struct kdbus_conn *conn, const char *name) -+{ -+ struct kdbus_ep *ep = conn->ep; -+ struct kdbus_bus *bus = ep->bus; -+ int ret; -+ -+ if (WARN_ON(atomic_read(&conn->active) != KDBUS_CONN_ACTIVE_NEW)) -+ return -EALREADY; -+ -+ /* make sure the ep-node is active while we add our connection */ -+ if (!kdbus_node_acquire(&ep->node)) -+ return -ESHUTDOWN; -+ -+ /* lock order: domain -> bus -> ep -> names -> conn */ -+ mutex_lock(&ep->lock); -+ down_write(&bus->conn_rwlock); -+ -+ /* link into monitor list */ -+ if (kdbus_conn_is_monitor(conn)) -+ list_add_tail(&conn->monitor_entry, &bus->monitors_list); -+ -+ /* link into bus and endpoint */ -+ list_add_tail(&conn->ep_entry, &ep->conn_list); -+ hash_add(bus->conn_hash, &conn->hentry, conn->id); -+ -+ /* enable lookups and acquire active ref */ -+ atomic_set(&conn->active, 1); -+#ifdef CONFIG_DEBUG_LOCK_ALLOC -+ rwsem_acquire_read(&conn->dep_map, 0, 1, _RET_IP_); -+#endif -+ -+ up_write(&bus->conn_rwlock); -+ mutex_unlock(&ep->lock); -+ -+ kdbus_node_release(&ep->node); -+ -+ /* -+ * Notify subscribers about the new active connection, unless it is -+ * a monitor. Monitors are invisible on the bus, can't be addressed -+ * directly, and won't cause any notifications. -+ */ -+ if (!kdbus_conn_is_monitor(conn)) { -+ ret = kdbus_notify_id_change(conn->ep->bus, KDBUS_ITEM_ID_ADD, -+ conn->id, conn->flags); -+ if (ret < 0) -+ goto exit_disconnect; -+ } -+ -+ if (kdbus_conn_is_activator(conn)) { -+ u64 flags = KDBUS_NAME_ACTIVATOR; -+ -+ if (WARN_ON(!name)) { -+ ret = -EINVAL; -+ goto exit_disconnect; -+ } -+ -+ ret = kdbus_name_acquire(bus->name_registry, conn, name, -+ flags, NULL); -+ if (ret < 0) -+ goto exit_disconnect; -+ } -+ -+ kdbus_conn_release(conn); -+ kdbus_notify_flush(bus); -+ return 0; -+ -+exit_disconnect: -+ kdbus_conn_release(conn); -+ kdbus_conn_disconnect(conn, false); -+ 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_queue_entry *entry, *tmp; -+ struct kdbus_bus *bus = conn->ep->bus; -+ struct kdbus_reply *r, *r_tmp; -+ struct kdbus_conn *c; -+ int i, v; -+ -+ mutex_lock(&conn->lock); -+ v = atomic_read(&conn->active); -+ if (v == KDBUS_CONN_ACTIVE_NEW) { -+ /* was never connected */ -+ mutex_unlock(&conn->lock); -+ return 0; -+ } -+ if (v < 0) { -+ /* already dead */ -+ mutex_unlock(&conn->lock); -+ return -ECONNRESET; -+ } -+ if (ensure_queue_empty && !list_empty(&conn->queue.msg_list)) { -+ /* still busy */ -+ 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); -+ kdbus_policy_remove_owner(&conn->ep->bus->policy_db, conn); -+ -+ /* lock order: domain -> bus -> ep -> names -> conn */ -+ mutex_lock(&conn->ep->lock); -+ down_write(&bus->conn_rwlock); -+ -+ /* remove from bus and endpoint */ -+ hash_del(&conn->hentry); -+ list_del(&conn->monitor_entry); -+ list_del(&conn->ep_entry); -+ -+ up_write(&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_release_all(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(bus, -+ entry->reply->reply_dst->id, -+ entry->reply->cookie); -+ kdbus_queue_entry_free(entry); -+ } -+ -+ list_for_each_entry_safe(r, r_tmp, &conn->reply_list, entry) -+ kdbus_reply_unlink(r); -+ mutex_unlock(&conn->lock); -+ -+ /* lock order: domain -> bus -> ep -> names -> conn */ -+ down_read(&bus->conn_rwlock); -+ hash_for_each(bus->conn_hash, i, c, hentry) { -+ mutex_lock(&c->lock); -+ list_for_each_entry_safe(r, r_tmp, &c->reply_list, entry) { -+ if (r->reply_src == conn) { -+ if (r->sync) { -+ kdbus_sync_reply_wakeup(r, -EPIPE); -+ kdbus_reply_unlink(r); -+ continue; -+ } -+ -+ /* send a 'connection dead' notification */ -+ kdbus_notify_reply_dead(bus, c->id, r->cookie); -+ kdbus_reply_unlink(r); -+ } -+ } -+ mutex_unlock(&c->lock); -+ } -+ up_read(&bus->conn_rwlock); -+ -+ if (!kdbus_conn_is_monitor(conn)) -+ kdbus_notify_id_change(bus, KDBUS_ITEM_ID_REMOVE, -+ conn->id, conn->flags); -+ -+ kdbus_notify_flush(bus); -+ -+ return 0; -+} -+ -+/** -+ * kdbus_conn_has_name() - check if a connection owns a name -+ * @conn: Connection -+ * @name: Well-know name to check for -+ * -+ * The caller must hold the registry lock of conn->ep->bus. -+ * -+ * 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; -+ -+ lockdep_assert_held(&conn->ep->bus->name_registry->rwlock); -+ -+ list_for_each_entry(e, &conn->names_list, conn_entry) -+ if (strcmp(e->name, name) == 0) -+ return true; -+ -+ return false; -+} -+ -+struct kdbus_quota { -+ uint32_t memory; -+ uint16_t msgs; -+ uint8_t fds; -+}; -+ -+/** -+ * kdbus_conn_quota_inc() - increase quota accounting -+ * @c: connection owning the quota tracking -+ * @u: user to account for (or NULL for kernel accounting) -+ * @memory: size of memory to account for -+ * @fds: number of FDs to account for -+ * -+ * This call manages the quotas on resource @c. That is, it's used if other -+ * users want to use the resources of connection @c, which so far only concerns -+ * the receive queue of the destination. -+ * -+ * This increases the quota-accounting for user @u by @memory bytes and @fds -+ * file descriptors. If the user has already reached the quota limits, this call -+ * will not do any accounting but return a negative error code indicating the -+ * failure. -+ * -+ * Return: 0 on success, negative error code on failure. -+ */ -+int kdbus_conn_quota_inc(struct kdbus_conn *c, struct kdbus_user *u, -+ size_t memory, size_t fds) -+{ -+ struct kdbus_quota *quota; -+ size_t available, accounted; -+ unsigned int id; -+ -+ /* -+ * Pool Layout: -+ * 50% of a pool is always owned by the connection. It is reserved for -+ * kernel queries, handling received messages and other tasks that are -+ * under control of the pool owner. The other 50% of the pool are used -+ * as incoming queue. -+ * As we optionally support user-space based policies, we need fair -+ * allocation schemes. Furthermore, resource utilization should be -+ * maximized, so only minimal resources stay reserved. However, we need -+ * to adapt to a dynamic number of users, as we cannot know how many -+ * users will talk to a connection. Therefore, the current allocations -+ * works like this: -+ * We limit the number of bytes in a destination's pool per sending -+ * user. The space available for a user is 33% of the unused pool space -+ * (whereas the space used by the user itself is also treated as -+ * 'unused'). This way, we favor users coming first, but keep enough -+ * pool space available for any following users. Given that messages are -+ * dequeued in FIFO order, this should balance nicely if the number of -+ * users grows. At the same time, this algorithm guarantees that the -+ * space available to a connection is reduced dynamically, the more -+ * concurrent users talk to a connection. -+ */ -+ -+ /* per user-accounting is expensive, so we keep state small */ -+ BUILD_BUG_ON(sizeof(quota->memory) != 4); -+ BUILD_BUG_ON(sizeof(quota->msgs) != 2); -+ BUILD_BUG_ON(sizeof(quota->fds) != 1); -+ BUILD_BUG_ON(KDBUS_CONN_MAX_MSGS > U16_MAX); -+ BUILD_BUG_ON(KDBUS_CONN_MAX_FDS_PER_USER > U8_MAX); -+ -+ id = u ? u->id : KDBUS_USER_KERNEL_ID; -+ if (id >= c->n_quota) { -+ unsigned int users; -+ -+ users = max(KDBUS_ALIGN8(id) + 8, id); -+ quota = krealloc(c->quota, users * sizeof(*quota), -+ GFP_KERNEL | __GFP_ZERO); -+ if (!quota) -+ return -ENOMEM; -+ -+ c->n_quota = users; -+ c->quota = quota; -+ } -+ -+ quota = &c->quota[id]; -+ kdbus_pool_accounted(c->pool, &available, &accounted); -+ -+ /* half the pool is _always_ reserved for the pool owner */ -+ available /= 2; -+ -+ /* -+ * Pool owner slices are un-accounted slices; they can claim more -+ * than 50% of the queue. However, the slice we're dealing with here -+ * belong to the incoming queue, hence they are 'accounted' slices -+ * to which the 50%-limit applies. -+ */ -+ if (available < accounted) -+ return -ENOBUFS; -+ -+ /* 1/3 of the remaining space (including your own memory) */ -+ available = (available - accounted + quota->memory) / 3; -+ -+ if (available < quota->memory || -+ available - quota->memory < memory || -+ quota->memory + memory > U32_MAX) -+ return -ENOBUFS; -+ if (quota->msgs >= KDBUS_CONN_MAX_MSGS) -+ return -ENOBUFS; -+ if (quota->fds + fds < quota->fds || -+ quota->fds + fds > KDBUS_CONN_MAX_FDS_PER_USER) -+ return -EMFILE; -+ -+ quota->memory += memory; -+ quota->fds += fds; -+ ++quota->msgs; -+ return 0; -+} -+ -+/** -+ * kdbus_conn_quota_dec() - decrease quota accounting -+ * @c: connection owning the quota tracking -+ * @u: user which was accounted for (or NULL for kernel accounting) -+ * @memory: size of memory which was accounted for -+ * @fds: number of FDs which were accounted for -+ * -+ * This does the reverse of kdbus_conn_quota_inc(). You have to release any -+ * accounted resources that you called kdbus_conn_quota_inc() for. However, you -+ * must not call kdbus_conn_quota_dec() if the accounting failed (that is, -+ * kdbus_conn_quota_inc() failed). -+ */ -+void kdbus_conn_quota_dec(struct kdbus_conn *c, struct kdbus_user *u, -+ size_t memory, size_t fds) -+{ -+ struct kdbus_quota *quota; -+ unsigned int id; -+ -+ id = u ? u->id : KDBUS_USER_KERNEL_ID; -+ if (WARN_ON(id >= c->n_quota)) -+ return; -+ -+ quota = &c->quota[id]; -+ -+ if (!WARN_ON(quota->msgs == 0)) -+ --quota->msgs; -+ if (!WARN_ON(quota->memory < memory)) -+ quota->memory -= memory; -+ if (!WARN_ON(quota->fds < fds)) -+ quota->fds -= fds; -+} -+ -+/** -+ * kdbus_conn_lost_message() - handle lost messages -+ * @c: connection that lost a message -+ * -+ * kdbus is reliable. That means, we try hard to never lose messages. However, -+ * memory is limited, so we cannot rely on transmissions to never fail. -+ * Therefore, we use quota-limits to let callers know if there unicast message -+ * cannot be transmitted to a peer. This works fine for unicasts, but for -+ * broadcasts we cannot make the caller handle the transmission failure. -+ * Instead, we must let the destination know that it couldn't receive a -+ * broadcast. -+ * As this is an unlikely scenario, we keep it simple. A single lost-counter -+ * remembers the number of lost messages since the last call to RECV. The next -+ * message retrieval will notify the connection that it lost messages since the -+ * last message retrieval and thus should resync its state. -+ */ -+void kdbus_conn_lost_message(struct kdbus_conn *c) -+{ -+ if (atomic_inc_return(&c->lost_count) == 1) -+ wake_up_interruptible(&c->wait); -+} -+ -+/* Callers should take the conn_dst lock */ -+static struct kdbus_queue_entry * -+kdbus_conn_entry_make(struct kdbus_conn *conn_dst, -+ const struct kdbus_kmsg *kmsg, -+ struct kdbus_user *user) -+{ -+ struct kdbus_queue_entry *entry; -+ -+ /* The remote connection was disconnected */ -+ if (!kdbus_conn_active(conn_dst)) -+ return ERR_PTR(-ECONNRESET); -+ -+ /* -+ * If the connection does not accept file descriptors but the message -+ * has some attached, refuse it. -+ * -+ * If this is a monitor connection, accept the message. In that -+ * case, all file descriptors will be set to -1 at receive time. -+ */ -+ if (!kdbus_conn_is_monitor(conn_dst) && -+ !(conn_dst->flags & KDBUS_HELLO_ACCEPT_FD) && -+ kmsg->res && kmsg->res->fds_count > 0) -+ return ERR_PTR(-ECOMM); -+ -+ entry = kdbus_queue_entry_new(conn_dst, kmsg, user); -+ 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_dst, -+ const struct kdbus_kmsg *kmsg, -+ struct kdbus_reply *reply_wake) -+{ -+ struct kdbus_queue_entry *entry; -+ int remote_ret; -+ int ret = 0; -+ -+ mutex_lock(&reply_wake->reply_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_dst, kmsg, -+ reply_wake->reply_src->user); -+ 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_sync_reply_wakeup(reply_wake, remote_ret); -+ kdbus_reply_unlink(reply_wake); -+ mutex_unlock(&reply_wake->reply_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 kmsg 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_reply *reply) -+{ -+ struct kdbus_queue_entry *entry; -+ int ret; -+ -+ kdbus_conn_lock2(conn_src, conn_dst); -+ -+ entry = kdbus_conn_entry_make(conn_dst, kmsg, -+ conn_src ? conn_src->user : NULL); -+ if (IS_ERR(entry)) { -+ ret = PTR_ERR(entry); -+ goto exit_unlock; -+ } -+ -+ if (reply) { -+ kdbus_reply_link(reply); -+ if (!reply->sync) -+ schedule_delayed_work(&conn_src->work, 0); -+ } -+ -+ kdbus_queue_entry_enqueue(entry, reply); -+ wake_up_interruptible(&conn_dst->wait); -+ -+ ret = 0; -+ -+exit_unlock: -+ kdbus_conn_unlock2(conn_src, conn_dst); -+ return ret; -+} -+ -+static int kdbus_conn_wait_reply(struct kdbus_conn *conn_src, -+ struct kdbus_cmd_send *cmd_send, -+ struct file *ioctl_file, -+ struct file *cancel_fd, -+ struct kdbus_reply *reply_wait, -+ ktime_t expire) -+{ -+ struct kdbus_queue_entry *entry; -+ struct poll_wqueues pwq = {}; -+ int ret; -+ -+ if (WARN_ON(!reply_wait)) -+ return -EIO; -+ -+ /* -+ * 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. -+ */ -+ -+ poll_initwait(&pwq); -+ poll_wait(ioctl_file, &conn_src->wait, &pwq.pt); -+ -+ for (;;) { -+ /* -+ * Any of the following conditions will stop our synchronously -+ * blocking SEND command: -+ * -+ * a) The origin sender closed its connection -+ * b) The remote peer answered, setting reply_wait->waiting = 0 -+ * c) The cancel FD was written to -+ * d) A signal was received -+ * e) The specified timeout was reached, and none of the above -+ * conditions kicked in. -+ */ -+ -+ /* -+ * We have already acquired an active reference when -+ * entering here, but another thread may call -+ * KDBUS_CMD_BYEBYE which does not acquire an active -+ * reference, therefore kdbus_conn_disconnect() will -+ * not wait for us. -+ */ -+ if (!kdbus_conn_active(conn_src)) { -+ ret = -ECONNRESET; -+ break; -+ } -+ -+ /* -+ * After the replying peer unset the waiting variable -+ * it will wake up us. -+ */ -+ if (!reply_wait->waiting) { -+ ret = reply_wait->err; -+ break; -+ } -+ -+ if (cancel_fd) { -+ unsigned int r; -+ -+ r = cancel_fd->f_op->poll(cancel_fd, &pwq.pt); -+ if (r & POLLIN) { -+ ret = -ECANCELED; -+ break; -+ } -+ } -+ -+ if (signal_pending(current)) { -+ ret = -EINTR; -+ break; -+ } -+ -+ if (!poll_schedule_timeout(&pwq, TASK_INTERRUPTIBLE, -+ &expire, 0)) { -+ ret = -ETIMEDOUT; -+ break; -+ } -+ -+ /* -+ * Reset the poll worker func, so the waitqueues are not -+ * added to the poll table again. We just reuse what we've -+ * collected earlier for further iterations. -+ */ -+ init_poll_funcptr(&pwq.pt, NULL); -+ } -+ -+ poll_freewait(&pwq); -+ -+ if (ret == -EINTR) { -+ /* -+ * 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_src->lock); -+ reply_wait->interrupted = true; -+ schedule_delayed_work(&conn_src->work, 0); -+ mutex_unlock(&conn_src->lock); -+ -+ return -ERESTARTSYS; -+ } -+ -+ mutex_lock(&conn_src->lock); -+ reply_wait->waiting = false; -+ entry = reply_wait->queue_entry; -+ if (entry) { -+ ret = kdbus_queue_entry_install(entry, -+ &cmd_send->reply.return_flags, -+ true); -+ kdbus_pool_slice_publish(entry->slice, &cmd_send->reply.offset, -+ &cmd_send->reply.msg_size); -+ kdbus_queue_entry_free(entry); -+ } -+ kdbus_reply_unlink(reply_wait); -+ mutex_unlock(&conn_src->lock); -+ -+ return ret; -+} -+ -+static int kdbus_pin_dst(struct kdbus_bus *bus, -+ struct kdbus_kmsg *kmsg, -+ struct kdbus_name_entry **out_name, -+ struct kdbus_conn **out_dst) -+{ -+ struct kdbus_msg_resources *res = kmsg->res; -+ struct kdbus_name_entry *name = NULL; -+ struct kdbus_conn *dst = NULL; -+ struct kdbus_msg *msg = &kmsg->msg; -+ int ret; -+ -+ if (WARN_ON(!res)) -+ return -EINVAL; -+ -+ lockdep_assert_held(&bus->name_registry->rwlock); -+ -+ if (!res->dst_name) { -+ dst = kdbus_bus_find_conn_by_id(bus, msg->dst_id); -+ if (!dst) -+ return -ENXIO; -+ -+ if (!kdbus_conn_is_ordinary(dst)) { -+ ret = -ENXIO; -+ goto error; -+ } -+ } else { -+ name = kdbus_name_lookup_unlocked(bus->name_registry, -+ res->dst_name); -+ if (!name) -+ 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->conn->id) -+ return -EREMCHG; -+ -+ if (!name->conn && name->activator) -+ dst = kdbus_conn_ref(name->activator); -+ else -+ dst = kdbus_conn_ref(name->conn); -+ -+ if ((msg->flags & KDBUS_MSG_NO_AUTO_START) && -+ kdbus_conn_is_activator(dst)) { -+ ret = -EADDRNOTAVAIL; -+ goto error; -+ } -+ -+ /* -+ * 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 an activator. -+ */ -+ kmsg->dst_name_id = name->name_id; -+ } -+ -+ *out_name = name; -+ *out_dst = dst; -+ return 0; -+ -+error: -+ kdbus_conn_unref(dst); -+ return ret; -+} -+ -+static int kdbus_conn_reply(struct kdbus_conn *src, struct kdbus_kmsg *kmsg) -+{ -+ struct kdbus_name_entry *name = NULL; -+ struct kdbus_reply *reply, *wake = NULL; -+ struct kdbus_conn *dst = NULL; -+ struct kdbus_bus *bus = src->ep->bus; -+ u64 attach; -+ int ret; -+ -+ if (WARN_ON(kmsg->msg.dst_id == KDBUS_DST_ID_BROADCAST) || -+ WARN_ON(kmsg->msg.flags & KDBUS_MSG_EXPECT_REPLY) || -+ WARN_ON(kmsg->msg.flags & KDBUS_MSG_SIGNAL)) -+ return -EINVAL; -+ -+ /* name-registry must be locked for lookup *and* collecting data */ -+ down_read(&bus->name_registry->rwlock); -+ -+ /* find and pin destination */ -+ -+ ret = kdbus_pin_dst(bus, kmsg, &name, &dst); -+ if (ret < 0) -+ goto exit; -+ -+ mutex_lock(&dst->lock); -+ reply = kdbus_reply_find(src, dst, kmsg->msg.cookie_reply); -+ if (reply) { -+ if (reply->sync) -+ wake = kdbus_reply_ref(reply); -+ kdbus_reply_unlink(reply); -+ } -+ mutex_unlock(&dst->lock); -+ -+ if (!reply) { -+ ret = -EPERM; -+ goto exit; -+ } -+ -+ /* attach metadata */ -+ -+ attach = kdbus_meta_calc_attach_flags(src, dst); -+ -+ if (!src->faked_meta) { -+ ret = kdbus_meta_proc_collect(kmsg->proc_meta, attach); -+ if (ret < 0) -+ goto exit; -+ } -+ -+ ret = kdbus_meta_conn_collect(kmsg->conn_meta, kmsg, src, attach); -+ if (ret < 0) -+ goto exit; -+ -+ /* send message */ -+ -+ kdbus_bus_eavesdrop(bus, src, kmsg); -+ -+ if (wake) -+ ret = kdbus_conn_entry_sync_attach(dst, kmsg, wake); -+ else -+ ret = kdbus_conn_entry_insert(src, dst, kmsg, NULL); -+ -+exit: -+ up_read(&bus->name_registry->rwlock); -+ kdbus_reply_unref(wake); -+ kdbus_conn_unref(dst); -+ return ret; -+} -+ -+static struct kdbus_reply *kdbus_conn_call(struct kdbus_conn *src, -+ struct kdbus_kmsg *kmsg, -+ ktime_t exp) -+{ -+ struct kdbus_name_entry *name = NULL; -+ struct kdbus_reply *wait = NULL; -+ struct kdbus_conn *dst = NULL; -+ struct kdbus_bus *bus = src->ep->bus; -+ u64 attach; -+ int ret; -+ -+ if (WARN_ON(kmsg->msg.dst_id == KDBUS_DST_ID_BROADCAST) || -+ WARN_ON(kmsg->msg.flags & KDBUS_MSG_SIGNAL) || -+ WARN_ON(!(kmsg->msg.flags & KDBUS_MSG_EXPECT_REPLY))) -+ return ERR_PTR(-EINVAL); -+ -+ /* resume previous wait-context, if available */ -+ -+ mutex_lock(&src->lock); -+ wait = kdbus_reply_find(NULL, src, kmsg->msg.cookie); -+ if (wait) { -+ if (wait->interrupted) { -+ kdbus_reply_ref(wait); -+ wait->interrupted = false; -+ } else { -+ wait = NULL; -+ } -+ } -+ mutex_unlock(&src->lock); -+ -+ if (wait) -+ return wait; -+ -+ if (ktime_compare(ktime_get(), exp) >= 0) -+ return ERR_PTR(-ETIMEDOUT); -+ -+ /* name-registry must be locked for lookup *and* collecting data */ -+ down_read(&bus->name_registry->rwlock); -+ -+ /* find and pin destination */ -+ -+ ret = kdbus_pin_dst(bus, kmsg, &name, &dst); -+ if (ret < 0) -+ goto exit; -+ -+ if (!kdbus_conn_policy_talk(src, current_cred(), dst)) { -+ ret = -EPERM; -+ goto exit; -+ } -+ -+ wait = kdbus_reply_new(dst, src, &kmsg->msg, name, true); -+ if (IS_ERR(wait)) { -+ ret = PTR_ERR(wait); -+ wait = NULL; -+ goto exit; -+ } -+ -+ /* attach metadata */ -+ -+ attach = kdbus_meta_calc_attach_flags(src, dst); -+ -+ if (!src->faked_meta) { -+ ret = kdbus_meta_proc_collect(kmsg->proc_meta, attach); -+ if (ret < 0) -+ goto exit; -+ } -+ -+ ret = kdbus_meta_conn_collect(kmsg->conn_meta, kmsg, src, attach); -+ if (ret < 0) -+ goto exit; -+ -+ /* send message */ -+ -+ kdbus_bus_eavesdrop(bus, src, kmsg); -+ -+ ret = kdbus_conn_entry_insert(src, dst, kmsg, wait); -+ if (ret < 0) -+ goto exit; -+ -+ ret = 0; -+ -+exit: -+ up_read(&bus->name_registry->rwlock); -+ if (ret < 0) { -+ kdbus_reply_unref(wait); -+ wait = ERR_PTR(ret); -+ } -+ kdbus_conn_unref(dst); -+ return wait; -+} -+ -+static int kdbus_conn_unicast(struct kdbus_conn *src, struct kdbus_kmsg *kmsg) -+{ -+ struct kdbus_name_entry *name = NULL; -+ struct kdbus_reply *wait = NULL; -+ struct kdbus_conn *dst = NULL; -+ struct kdbus_bus *bus = src->ep->bus; -+ bool is_signal = (kmsg->msg.flags & KDBUS_MSG_SIGNAL); -+ u64 attach; -+ int ret = 0; -+ -+ if (WARN_ON(kmsg->msg.dst_id == KDBUS_DST_ID_BROADCAST) || -+ WARN_ON(!(kmsg->msg.flags & KDBUS_MSG_EXPECT_REPLY) && -+ kmsg->msg.cookie_reply != 0)) -+ return -EINVAL; -+ -+ /* name-registry must be locked for lookup *and* collecting data */ -+ down_read(&bus->name_registry->rwlock); -+ -+ /* find and pin destination */ -+ -+ ret = kdbus_pin_dst(bus, kmsg, &name, &dst); -+ if (ret < 0) -+ goto exit; -+ -+ if (is_signal) { -+ /* like broadcasts we eavesdrop even if the msg is dropped */ -+ kdbus_bus_eavesdrop(bus, src, kmsg); -+ -+ /* drop silently if peer is not interested or not privileged */ -+ if (!kdbus_match_db_match_kmsg(dst->match_db, src, kmsg) || -+ !kdbus_conn_policy_talk(dst, NULL, src)) -+ goto exit; -+ } else if (!kdbus_conn_policy_talk(src, current_cred(), dst)) { -+ ret = -EPERM; -+ goto exit; -+ } else if (kmsg->msg.flags & KDBUS_MSG_EXPECT_REPLY) { -+ wait = kdbus_reply_new(dst, src, &kmsg->msg, name, false); -+ if (IS_ERR(wait)) { -+ ret = PTR_ERR(wait); -+ wait = NULL; -+ goto exit; -+ } -+ } -+ -+ /* attach metadata */ -+ -+ attach = kdbus_meta_calc_attach_flags(src, dst); -+ -+ if (!src->faked_meta) { -+ ret = kdbus_meta_proc_collect(kmsg->proc_meta, attach); -+ if (ret < 0 && !is_signal) -+ goto exit; -+ } -+ -+ ret = kdbus_meta_conn_collect(kmsg->conn_meta, kmsg, src, attach); -+ if (ret < 0 && !is_signal) -+ goto exit; -+ -+ /* send message */ -+ -+ if (!is_signal) -+ kdbus_bus_eavesdrop(bus, src, kmsg); -+ -+ ret = kdbus_conn_entry_insert(src, dst, kmsg, wait); -+ if (ret < 0 && !is_signal) -+ goto exit; -+ -+ /* signals are treated like broadcasts, recv-errors are ignored */ -+ ret = 0; -+ -+exit: -+ up_read(&bus->name_registry->rwlock); -+ kdbus_reply_unref(wait); -+ kdbus_conn_unref(dst); -+ return ret; -+} -+ -+/** -+ * 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 implementer connection is taking over/giving back a well-known name -+ * from/to an activator connection. -+ */ -+void kdbus_conn_move_messages(struct kdbus_conn *conn_dst, -+ struct kdbus_conn *conn_src, -+ u64 name_id) -+{ -+ struct kdbus_queue_entry *e, *e_tmp; -+ struct kdbus_reply *r, *r_tmp; -+ struct kdbus_bus *bus; -+ struct kdbus_conn *c; -+ LIST_HEAD(msg_list); -+ int i, ret = 0; -+ -+ if (WARN_ON(conn_src == conn_dst)) -+ return; -+ -+ bus = conn_src->ep->bus; -+ -+ /* lock order: domain -> bus -> ep -> names -> conn */ -+ down_read(&bus->conn_rwlock); -+ hash_for_each(bus->conn_hash, i, c, hentry) { -+ if (c == conn_src || c == conn_dst) -+ continue; -+ -+ mutex_lock(&c->lock); -+ list_for_each_entry_safe(r, r_tmp, &c->reply_list, entry) { -+ if (r->reply_src != conn_src) -+ continue; -+ -+ /* filter messages for a specific name */ -+ if (name_id > 0 && r->name_id != name_id) -+ continue; -+ -+ kdbus_conn_unref(r->reply_src); -+ r->reply_src = kdbus_conn_ref(conn_dst); -+ } -+ mutex_unlock(&c->lock); -+ } -+ up_read(&bus->conn_rwlock); -+ -+ kdbus_conn_lock2(conn_src, conn_dst); -+ list_for_each_entry_safe(e, e_tmp, &conn_src->queue.msg_list, entry) { -+ /* filter messages for a specific name */ -+ if (name_id > 0 && e->dst_name_id != name_id) -+ continue; -+ -+ if (!(conn_dst->flags & KDBUS_HELLO_ACCEPT_FD) && -+ e->msg_res && e->msg_res->fds_count > 0) { -+ kdbus_conn_lost_message(conn_dst); -+ kdbus_queue_entry_free(e); -+ continue; -+ } -+ -+ ret = kdbus_queue_entry_move(e, conn_dst); -+ if (ret < 0) { -+ kdbus_conn_lost_message(conn_dst); -+ kdbus_queue_entry_free(e); -+ continue; -+ } -+ } -+ kdbus_conn_unlock2(conn_src, conn_dst); -+ -+ /* wake up poll() */ -+ wake_up_interruptible(&conn_dst->wait); -+} -+ -+/* query the policy-database for all names of @whom */ -+static bool kdbus_conn_policy_query_all(struct kdbus_conn *conn, -+ const struct cred *conn_creds, -+ struct kdbus_policy_db *db, -+ struct kdbus_conn *whom, -+ unsigned int access) -+{ -+ struct kdbus_name_entry *ne; -+ bool pass = false; -+ int res; -+ -+ lockdep_assert_held(&conn->ep->bus->name_registry->rwlock); -+ -+ down_read(&db->entries_rwlock); -+ mutex_lock(&whom->lock); -+ -+ list_for_each_entry(ne, &whom->names_list, conn_entry) { -+ res = kdbus_policy_query_unlocked(db, conn_creds ? : conn->cred, -+ ne->name, -+ kdbus_strhash(ne->name)); -+ if (res >= (int)access) { -+ pass = true; -+ break; -+ } -+ } -+ -+ mutex_unlock(&whom->lock); -+ up_read(&db->entries_rwlock); -+ -+ return pass; -+} -+ -+/** -+ * kdbus_conn_policy_own_name() - verify a connection can own the given name -+ * @conn: Connection -+ * @conn_creds: Credentials of @conn to use for policy check -+ * @name: Name -+ * -+ * This verifies that @conn is allowed to acquire the well-known name @name. -+ * -+ * Return: true if allowed, false if not. -+ */ -+bool kdbus_conn_policy_own_name(struct kdbus_conn *conn, -+ const struct cred *conn_creds, -+ const char *name) -+{ -+ unsigned int hash = kdbus_strhash(name); -+ int res; -+ -+ if (!conn_creds) -+ conn_creds = conn->cred; -+ -+ if (conn->ep->user) { -+ res = kdbus_policy_query(&conn->ep->policy_db, conn_creds, -+ name, hash); -+ if (res < KDBUS_POLICY_OWN) -+ return false; -+ } -+ -+ if (conn->privileged) -+ return true; -+ -+ res = kdbus_policy_query(&conn->ep->bus->policy_db, conn_creds, -+ name, hash); -+ return res >= KDBUS_POLICY_OWN; -+} -+ -+/** -+ * kdbus_conn_policy_talk() - verify a connection can talk to a given peer -+ * @conn: Connection that tries to talk -+ * @conn_creds: Credentials of @conn to use for policy check -+ * @to: Connection that is talked to -+ * -+ * This verifies that @conn is allowed to talk to @to. -+ * -+ * Return: true if allowed, false if not. -+ */ -+bool kdbus_conn_policy_talk(struct kdbus_conn *conn, -+ const struct cred *conn_creds, -+ struct kdbus_conn *to) -+{ -+ if (!conn_creds) -+ conn_creds = conn->cred; -+ -+ if (conn->ep->user && -+ !kdbus_conn_policy_query_all(conn, conn_creds, &conn->ep->policy_db, -+ to, KDBUS_POLICY_TALK)) -+ return false; -+ -+ if (conn->privileged) -+ return true; -+ if (uid_eq(conn_creds->euid, to->cred->uid)) -+ return true; -+ -+ return kdbus_conn_policy_query_all(conn, conn_creds, -+ &conn->ep->bus->policy_db, to, -+ KDBUS_POLICY_TALK); -+} -+ -+/** -+ * kdbus_conn_policy_see_name_unlocked() - verify a connection can see a given -+ * name -+ * @conn: Connection -+ * @conn_creds: Credentials of @conn to use for policy check -+ * @name: Name -+ * -+ * This verifies that @conn is allowed to see the well-known name @name. Caller -+ * must hold policy-lock. -+ * -+ * Return: true if allowed, false if not. -+ */ -+bool kdbus_conn_policy_see_name_unlocked(struct kdbus_conn *conn, -+ const struct cred *conn_creds, -+ const char *name) -+{ -+ int res; -+ -+ /* -+ * By default, all names are visible on a bus. SEE policies can only be -+ * installed on custom endpoints, where by default no name is visible. -+ */ -+ if (!conn->ep->user) -+ return true; -+ -+ res = kdbus_policy_query_unlocked(&conn->ep->policy_db, -+ conn_creds ? : conn->cred, -+ name, kdbus_strhash(name)); -+ return res >= KDBUS_POLICY_SEE; -+} -+ -+static bool kdbus_conn_policy_see_name(struct kdbus_conn *conn, -+ const struct cred *conn_creds, -+ const char *name) -+{ -+ bool res; -+ -+ down_read(&conn->ep->policy_db.entries_rwlock); -+ res = kdbus_conn_policy_see_name_unlocked(conn, conn_creds, name); -+ up_read(&conn->ep->policy_db.entries_rwlock); -+ -+ return res; -+} -+ -+static bool kdbus_conn_policy_see(struct kdbus_conn *conn, -+ const struct cred *conn_creds, -+ struct kdbus_conn *whom) -+{ -+ /* -+ * By default, all names are visible on a bus, so a connection can -+ * always see other connections. SEE policies can only be installed on -+ * custom endpoints, where by default no name is visible and we hide -+ * peers from each other, unless you see at least _one_ name of the -+ * peer. -+ */ -+ return !conn->ep->user || -+ kdbus_conn_policy_query_all(conn, conn_creds, -+ &conn->ep->policy_db, whom, -+ KDBUS_POLICY_SEE); -+} -+ -+/** -+ * kdbus_conn_policy_see_notification() - verify a connection is allowed to -+ * receive a given kernel notification -+ * @conn: Connection -+ * @conn_creds: Credentials of @conn to use for policy check -+ * @kmsg: The message carrying the notification -+ * -+ * This checks whether @conn is allowed to see the kernel notification @kmsg. -+ * -+ * Return: true if allowed, false if not. -+ */ -+bool kdbus_conn_policy_see_notification(struct kdbus_conn *conn, -+ const struct cred *conn_creds, -+ const struct kdbus_kmsg *kmsg) -+{ -+ if (WARN_ON(kmsg->msg.src_id != KDBUS_SRC_ID_KERNEL)) -+ return false; -+ -+ /* -+ * Depending on the notification type, broadcasted kernel notifications -+ * have to be filtered: -+ * -+ * KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE}: This notification is forwarded -+ * to a peer if, and only if, that peer can see the name this -+ * notification is for. -+ * -+ * KDBUS_ITEM_ID_{ADD,REMOVE}: As new peers cannot have names, and all -+ * names are dropped before a peer is removed, those notifications -+ * cannot be seen on custom endpoints. Thus, we only pass them -+ * through on default endpoints. -+ */ -+ -+ switch (kmsg->notify_type) { -+ case KDBUS_ITEM_NAME_ADD: -+ case KDBUS_ITEM_NAME_REMOVE: -+ case KDBUS_ITEM_NAME_CHANGE: -+ return kdbus_conn_policy_see_name(conn, conn_creds, -+ kmsg->notify_name); -+ -+ case KDBUS_ITEM_ID_ADD: -+ case KDBUS_ITEM_ID_REMOVE: -+ return !conn->ep->user; -+ -+ default: -+ WARN(1, "Invalid type for notification broadcast: %llu\n", -+ (unsigned long long)kmsg->notify_type); -+ return false; -+ } -+} -+ -+/** -+ * kdbus_cmd_hello() - handle KDBUS_CMD_HELLO -+ * @ep: Endpoint to operate on -+ * @privileged: Whether the caller is privileged -+ * @argp: Command payload -+ * -+ * Return: Newly created connection on success, ERR_PTR on failure. -+ */ -+struct kdbus_conn *kdbus_cmd_hello(struct kdbus_ep *ep, bool privileged, -+ void __user *argp) -+{ -+ struct kdbus_cmd_hello *cmd; -+ struct kdbus_conn *c = NULL; -+ const char *item_name; -+ int ret; -+ -+ struct kdbus_arg argv[] = { -+ { .type = KDBUS_ITEM_NEGOTIATE }, -+ { .type = KDBUS_ITEM_NAME }, -+ { .type = KDBUS_ITEM_CREDS }, -+ { .type = KDBUS_ITEM_PIDS }, -+ { .type = KDBUS_ITEM_SECLABEL }, -+ { .type = KDBUS_ITEM_CONN_DESCRIPTION }, -+ { .type = KDBUS_ITEM_POLICY_ACCESS, .multiple = true }, -+ }; -+ struct kdbus_args args = { -+ .allowed_flags = KDBUS_FLAG_NEGOTIATE | -+ KDBUS_HELLO_ACCEPT_FD | -+ KDBUS_HELLO_ACTIVATOR | -+ KDBUS_HELLO_POLICY_HOLDER | -+ KDBUS_HELLO_MONITOR, -+ .argv = argv, -+ .argc = ARRAY_SIZE(argv), -+ }; -+ -+ ret = kdbus_args_parse(&args, argp, &cmd); -+ if (ret < 0) -+ return ERR_PTR(ret); -+ if (ret > 0) -+ return NULL; -+ -+ item_name = argv[1].item ? argv[1].item->str : NULL; -+ -+ c = kdbus_conn_new(ep, privileged, cmd, item_name, -+ argv[2].item ? &argv[2].item->creds : NULL, -+ argv[3].item ? &argv[3].item->pids : NULL, -+ argv[4].item ? argv[4].item->str : NULL, -+ argv[5].item ? argv[5].item->str : NULL); -+ if (IS_ERR(c)) { -+ ret = PTR_ERR(c); -+ c = NULL; -+ goto exit; -+ } -+ -+ ret = kdbus_conn_connect(c, item_name); -+ if (ret < 0) -+ goto exit; -+ -+ if (kdbus_conn_is_activator(c) || kdbus_conn_is_policy_holder(c)) { -+ ret = kdbus_conn_acquire(c); -+ if (ret < 0) -+ goto exit; -+ -+ ret = kdbus_policy_set(&c->ep->bus->policy_db, args.items, -+ args.items_size, 1, -+ kdbus_conn_is_policy_holder(c), c); -+ kdbus_conn_release(c); -+ if (ret < 0) -+ goto exit; -+ } -+ -+ if (copy_to_user(argp, cmd, sizeof(*cmd))) -+ ret = -EFAULT; -+ -+exit: -+ ret = kdbus_args_clear(&args, ret); -+ if (ret < 0) { -+ if (c) { -+ kdbus_conn_disconnect(c, false); -+ kdbus_conn_unref(c); -+ } -+ return ERR_PTR(ret); -+ } -+ return c; -+} -+ -+/** -+ * kdbus_cmd_byebye_unlocked() - handle KDBUS_CMD_BYEBYE -+ * @conn: connection to operate on -+ * @argp: command payload -+ * -+ * The caller must not hold any active reference to @conn or this will deadlock. -+ * -+ * Return: 0 on success, negative error code on failure. -+ */ -+int kdbus_cmd_byebye_unlocked(struct kdbus_conn *conn, void __user *argp) -+{ -+ struct kdbus_cmd *cmd; -+ int ret; -+ -+ struct kdbus_arg argv[] = { -+ { .type = KDBUS_ITEM_NEGOTIATE }, -+ }; -+ struct kdbus_args args = { -+ .allowed_flags = KDBUS_FLAG_NEGOTIATE, -+ .argv = argv, -+ .argc = ARRAY_SIZE(argv), -+ }; -+ -+ if (!kdbus_conn_is_ordinary(conn)) -+ return -EOPNOTSUPP; -+ -+ ret = kdbus_args_parse(&args, argp, &cmd); -+ if (ret != 0) -+ return ret; -+ -+ ret = kdbus_conn_disconnect(conn, true); -+ return kdbus_args_clear(&args, ret); -+} -+ -+/** -+ * kdbus_cmd_conn_info() - handle KDBUS_CMD_CONN_INFO -+ * @conn: connection to operate on -+ * @argp: command payload -+ * -+ * Return: 0 on success, negative error code on failure. -+ */ -+int kdbus_cmd_conn_info(struct kdbus_conn *conn, void __user *argp) -+{ -+ struct kdbus_meta_conn *conn_meta = NULL; -+ struct kdbus_pool_slice *slice = NULL; -+ struct kdbus_name_entry *entry = NULL; -+ struct kdbus_conn *owner_conn = NULL; -+ struct kdbus_info info = {}; -+ struct kdbus_cmd_info *cmd; -+ struct kdbus_bus *bus = conn->ep->bus; -+ struct kvec kvec; -+ size_t meta_size; -+ const char *name; -+ u64 attach_flags; -+ int ret; -+ -+ struct kdbus_arg argv[] = { -+ { .type = KDBUS_ITEM_NEGOTIATE }, -+ { .type = KDBUS_ITEM_NAME }, -+ }; -+ struct kdbus_args args = { -+ .allowed_flags = KDBUS_FLAG_NEGOTIATE, -+ .argv = argv, -+ .argc = ARRAY_SIZE(argv), -+ }; -+ -+ ret = kdbus_args_parse(&args, argp, &cmd); -+ if (ret != 0) -+ return ret; -+ -+ /* registry must be held throughout lookup *and* collecting data */ -+ down_read(&bus->name_registry->rwlock); -+ -+ ret = kdbus_sanitize_attach_flags(cmd->attach_flags, &attach_flags); -+ if (ret < 0) -+ goto exit; -+ -+ name = argv[1].item ? argv[1].item->str : NULL; -+ -+ if (name) { -+ entry = kdbus_name_lookup_unlocked(bus->name_registry, name); -+ if (!entry || !entry->conn || -+ !kdbus_conn_policy_see_name(conn, current_cred(), name) || -+ (cmd->id != 0 && entry->conn->id != cmd->id)) { -+ /* pretend a name doesn't exist if you cannot see it */ -+ ret = -ESRCH; -+ goto exit; -+ } -+ -+ owner_conn = kdbus_conn_ref(entry->conn); -+ } else if (cmd->id > 0) { -+ owner_conn = kdbus_bus_find_conn_by_id(bus, cmd->id); -+ if (!owner_conn || !kdbus_conn_policy_see(conn, current_cred(), -+ owner_conn)) { -+ /* pretend an id doesn't exist if you cannot see it */ -+ ret = -ENXIO; -+ goto exit; -+ } -+ } else { -+ ret = -EINVAL; -+ goto exit; -+ } -+ -+ info.id = owner_conn->id; -+ info.flags = owner_conn->flags; -+ kdbus_kvec_set(&kvec, &info, sizeof(info), &info.size); -+ -+ attach_flags &= atomic64_read(&owner_conn->attach_flags_send); -+ -+ conn_meta = kdbus_meta_conn_new(); -+ if (IS_ERR(conn_meta)) { -+ ret = PTR_ERR(conn_meta); -+ conn_meta = NULL; -+ goto exit; -+ } -+ -+ ret = kdbus_meta_conn_collect(conn_meta, NULL, owner_conn, -+ attach_flags); -+ if (ret < 0) -+ goto exit; -+ -+ ret = kdbus_meta_export_prepare(owner_conn->meta, conn_meta, -+ &attach_flags, &meta_size); -+ if (ret < 0) -+ goto exit; -+ -+ slice = kdbus_pool_slice_alloc(conn->pool, -+ info.size + meta_size, false); -+ if (IS_ERR(slice)) { -+ ret = PTR_ERR(slice); -+ slice = NULL; -+ goto exit; -+ } -+ -+ ret = kdbus_meta_export(owner_conn->meta, conn_meta, attach_flags, -+ slice, sizeof(info), &meta_size); -+ if (ret < 0) -+ goto exit; -+ -+ info.size += meta_size; -+ -+ ret = kdbus_pool_slice_copy_kvec(slice, 0, &kvec, 1, sizeof(info)); -+ if (ret < 0) -+ goto exit; -+ -+ kdbus_pool_slice_publish(slice, &cmd->offset, &cmd->info_size); -+ -+ if (kdbus_member_set_user(&cmd->offset, argp, typeof(*cmd), offset) || -+ kdbus_member_set_user(&cmd->info_size, argp, -+ typeof(*cmd), info_size)) { -+ ret = -EFAULT; -+ goto exit; -+ } -+ -+ ret = 0; -+ -+exit: -+ up_read(&bus->name_registry->rwlock); -+ kdbus_pool_slice_release(slice); -+ kdbus_meta_conn_unref(conn_meta); -+ kdbus_conn_unref(owner_conn); -+ return kdbus_args_clear(&args, ret); -+} -+ -+/** -+ * kdbus_cmd_update() - handle KDBUS_CMD_UPDATE -+ * @conn: connection to operate on -+ * @argp: command payload -+ * -+ * Return: 0 on success, negative error code on failure. -+ */ -+int kdbus_cmd_update(struct kdbus_conn *conn, void __user *argp) -+{ -+ struct kdbus_bus *bus = conn->ep->bus; -+ struct kdbus_item *item_policy; -+ u64 *item_attach_send = NULL; -+ u64 *item_attach_recv = NULL; -+ struct kdbus_cmd *cmd; -+ u64 attach_send; -+ u64 attach_recv; -+ int ret; -+ -+ struct kdbus_arg argv[] = { -+ { .type = KDBUS_ITEM_NEGOTIATE }, -+ { .type = KDBUS_ITEM_ATTACH_FLAGS_SEND }, -+ { .type = KDBUS_ITEM_ATTACH_FLAGS_RECV }, -+ { .type = KDBUS_ITEM_NAME, .multiple = true }, -+ { .type = KDBUS_ITEM_POLICY_ACCESS, .multiple = true }, -+ }; -+ struct kdbus_args args = { -+ .allowed_flags = KDBUS_FLAG_NEGOTIATE, -+ .argv = argv, -+ .argc = ARRAY_SIZE(argv), -+ }; -+ -+ ret = kdbus_args_parse(&args, argp, &cmd); -+ if (ret != 0) -+ return ret; -+ -+ item_attach_send = argv[1].item ? &argv[1].item->data64[0] : NULL; -+ item_attach_recv = argv[2].item ? &argv[2].item->data64[0] : NULL; -+ item_policy = argv[3].item ? : argv[4].item; -+ -+ if (item_attach_send) { -+ if (!kdbus_conn_is_ordinary(conn) && -+ !kdbus_conn_is_monitor(conn)) { -+ ret = -EOPNOTSUPP; -+ goto exit; -+ } -+ -+ ret = kdbus_sanitize_attach_flags(*item_attach_send, -+ &attach_send); -+ if (ret < 0) -+ goto exit; -+ -+ if (bus->attach_flags_req & ~attach_send) { -+ ret = -EINVAL; -+ goto exit; -+ } -+ } -+ -+ if (item_attach_recv) { -+ if (!kdbus_conn_is_ordinary(conn) && -+ !kdbus_conn_is_monitor(conn) && -+ !kdbus_conn_is_activator(conn)) { -+ ret = -EOPNOTSUPP; -+ goto exit; -+ } -+ -+ ret = kdbus_sanitize_attach_flags(*item_attach_recv, -+ &attach_recv); -+ if (ret < 0) -+ goto exit; -+ } -+ -+ if (item_policy && !kdbus_conn_is_policy_holder(conn)) { -+ ret = -EOPNOTSUPP; -+ goto exit; -+ } -+ -+ /* now that we verified the input, update the connection */ -+ -+ if (item_policy) { -+ ret = kdbus_policy_set(&conn->ep->bus->policy_db, cmd->items, -+ KDBUS_ITEMS_SIZE(cmd, items), -+ 1, true, conn); -+ if (ret < 0) -+ goto exit; -+ } -+ -+ if (item_attach_send) -+ atomic64_set(&conn->attach_flags_send, attach_send); -+ -+ if (item_attach_recv) -+ atomic64_set(&conn->attach_flags_recv, attach_recv); -+ -+exit: -+ return kdbus_args_clear(&args, ret); -+} -+ -+/** -+ * kdbus_cmd_send() - handle KDBUS_CMD_SEND -+ * @conn: connection to operate on -+ * @f: file this command was called on -+ * @argp: command payload -+ * -+ * Return: 0 on success, negative error code on failure. -+ */ -+int kdbus_cmd_send(struct kdbus_conn *conn, struct file *f, void __user *argp) -+{ -+ struct kdbus_cmd_send *cmd; -+ struct kdbus_kmsg *kmsg = NULL; -+ struct file *cancel_fd = NULL; -+ int ret; -+ -+ struct kdbus_arg argv[] = { -+ { .type = KDBUS_ITEM_NEGOTIATE }, -+ { .type = KDBUS_ITEM_CANCEL_FD }, -+ }; -+ struct kdbus_args args = { -+ .allowed_flags = KDBUS_FLAG_NEGOTIATE | -+ KDBUS_SEND_SYNC_REPLY, -+ .argv = argv, -+ .argc = ARRAY_SIZE(argv), -+ }; -+ -+ if (!kdbus_conn_is_ordinary(conn)) -+ return -EOPNOTSUPP; -+ -+ ret = kdbus_args_parse(&args, argp, &cmd); -+ if (ret != 0) -+ return ret; -+ -+ cmd->reply.return_flags = 0; -+ kdbus_pool_publish_empty(conn->pool, &cmd->reply.offset, -+ &cmd->reply.msg_size); -+ -+ if (argv[1].item) { -+ cancel_fd = fget(argv[1].item->fds[0]); -+ if (IS_ERR(cancel_fd)) { -+ ret = PTR_ERR(cancel_fd); -+ cancel_fd = NULL; -+ goto exit; -+ } -+ -+ if (!cancel_fd->f_op->poll) { -+ ret = -EINVAL; -+ goto exit; -+ } -+ } -+ -+ kmsg = kdbus_kmsg_new_from_cmd(conn, cmd); -+ if (IS_ERR(kmsg)) { -+ ret = PTR_ERR(kmsg); -+ kmsg = NULL; -+ goto exit; -+ } -+ -+ if (kmsg->msg.dst_id == KDBUS_DST_ID_BROADCAST) { -+ down_read(&conn->ep->bus->name_registry->rwlock); -+ kdbus_bus_broadcast(conn->ep->bus, conn, kmsg); -+ up_read(&conn->ep->bus->name_registry->rwlock); -+ } else if (cmd->flags & KDBUS_SEND_SYNC_REPLY) { -+ struct kdbus_reply *r; -+ ktime_t exp; -+ -+ exp = ns_to_ktime(kmsg->msg.timeout_ns); -+ r = kdbus_conn_call(conn, kmsg, exp); -+ if (IS_ERR(r)) { -+ ret = PTR_ERR(r); -+ goto exit; -+ } -+ -+ ret = kdbus_conn_wait_reply(conn, cmd, f, cancel_fd, r, exp); -+ kdbus_reply_unref(r); -+ if (ret < 0) -+ goto exit; -+ } else if ((kmsg->msg.flags & KDBUS_MSG_EXPECT_REPLY) || -+ kmsg->msg.cookie_reply == 0) { -+ ret = kdbus_conn_unicast(conn, kmsg); -+ if (ret < 0) -+ goto exit; -+ } else { -+ ret = kdbus_conn_reply(conn, kmsg); -+ if (ret < 0) -+ goto exit; -+ } -+ -+ if (kdbus_member_set_user(&cmd->reply, argp, typeof(*cmd), reply)) -+ ret = -EFAULT; -+ -+exit: -+ if (cancel_fd) -+ fput(cancel_fd); -+ kdbus_kmsg_free(kmsg); -+ return kdbus_args_clear(&args, ret); -+} -+ -+/** -+ * kdbus_cmd_recv() - handle KDBUS_CMD_RECV -+ * @conn: connection to operate on -+ * @argp: command payload -+ * -+ * Return: 0 on success, negative error code on failure. -+ */ -+int kdbus_cmd_recv(struct kdbus_conn *conn, void __user *argp) -+{ -+ struct kdbus_queue_entry *entry; -+ struct kdbus_cmd_recv *cmd; -+ int ret; -+ -+ struct kdbus_arg argv[] = { -+ { .type = KDBUS_ITEM_NEGOTIATE }, -+ }; -+ struct kdbus_args args = { -+ .allowed_flags = KDBUS_FLAG_NEGOTIATE | -+ KDBUS_RECV_PEEK | -+ KDBUS_RECV_DROP | -+ KDBUS_RECV_USE_PRIORITY, -+ .argv = argv, -+ .argc = ARRAY_SIZE(argv), -+ }; -+ -+ if (!kdbus_conn_is_ordinary(conn) && -+ !kdbus_conn_is_monitor(conn) && -+ !kdbus_conn_is_activator(conn)) -+ return -EOPNOTSUPP; -+ -+ ret = kdbus_args_parse(&args, argp, &cmd); -+ if (ret != 0) -+ return ret; -+ -+ cmd->dropped_msgs = 0; -+ cmd->msg.return_flags = 0; -+ kdbus_pool_publish_empty(conn->pool, &cmd->msg.offset, -+ &cmd->msg.msg_size); -+ -+ /* DROP+priority is not realiably, so prevent it */ -+ if ((cmd->flags & KDBUS_RECV_DROP) && -+ (cmd->flags & KDBUS_RECV_USE_PRIORITY)) { -+ ret = -EINVAL; -+ goto exit; -+ } -+ -+ mutex_lock(&conn->lock); -+ -+ entry = kdbus_queue_peek(&conn->queue, cmd->priority, -+ cmd->flags & KDBUS_RECV_USE_PRIORITY); -+ if (!entry) { -+ mutex_unlock(&conn->lock); -+ ret = -EAGAIN; -+ } else if (cmd->flags & KDBUS_RECV_DROP) { -+ struct kdbus_reply *reply = kdbus_reply_ref(entry->reply); -+ -+ kdbus_queue_entry_free(entry); -+ -+ mutex_unlock(&conn->lock); -+ -+ if (reply) { -+ mutex_lock(&reply->reply_dst->lock); -+ if (!list_empty(&reply->entry)) { -+ kdbus_reply_unlink(reply); -+ if (reply->sync) -+ kdbus_sync_reply_wakeup(reply, -EPIPE); -+ else -+ kdbus_notify_reply_dead(conn->ep->bus, -+ reply->reply_dst->id, -+ reply->cookie); -+ } -+ mutex_unlock(&reply->reply_dst->lock); -+ kdbus_notify_flush(conn->ep->bus); -+ } -+ -+ kdbus_reply_unref(reply); -+ } else { -+ bool install_fds; -+ -+ /* -+ * PEEK just returns the location of the next message. Do not -+ * install FDs nor memfds nor anything else. The only -+ * information of interest should be the message header and -+ * metadata. Any FD numbers in the payload is undefined for -+ * PEEK'ed messages. -+ * Also make sure to never install fds into a connection that -+ * has refused to receive any. Ordinary connections will not get -+ * messages with FDs queued (the receiver will get -ECOMM), but -+ * eavesdroppers might. -+ */ -+ install_fds = (conn->flags & KDBUS_HELLO_ACCEPT_FD) && -+ !(cmd->flags & KDBUS_RECV_PEEK); -+ -+ ret = kdbus_queue_entry_install(entry, -+ &cmd->msg.return_flags, -+ install_fds); -+ if (ret < 0) { -+ mutex_unlock(&conn->lock); -+ goto exit; -+ } -+ -+ kdbus_pool_slice_publish(entry->slice, &cmd->msg.offset, -+ &cmd->msg.msg_size); -+ -+ if (!(cmd->flags & KDBUS_RECV_PEEK)) -+ kdbus_queue_entry_free(entry); -+ -+ mutex_unlock(&conn->lock); -+ } -+ -+ cmd->dropped_msgs = atomic_xchg(&conn->lost_count, 0); -+ if (cmd->dropped_msgs > 0) -+ cmd->return_flags |= KDBUS_RECV_RETURN_DROPPED_MSGS; -+ -+ if (kdbus_member_set_user(&cmd->msg, argp, typeof(*cmd), msg) || -+ kdbus_member_set_user(&cmd->dropped_msgs, argp, typeof(*cmd), -+ dropped_msgs)) -+ ret = -EFAULT; -+ -+exit: -+ return kdbus_args_clear(&args, ret); -+} -+ -+/** -+ * kdbus_cmd_free() - handle KDBUS_CMD_FREE -+ * @conn: connection to operate on -+ * @argp: command payload -+ * -+ * Return: 0 on success, negative error code on failure. -+ */ -+int kdbus_cmd_free(struct kdbus_conn *conn, void __user *argp) -+{ -+ struct kdbus_cmd_free *cmd; -+ int ret; -+ -+ struct kdbus_arg argv[] = { -+ { .type = KDBUS_ITEM_NEGOTIATE }, -+ }; -+ struct kdbus_args args = { -+ .allowed_flags = KDBUS_FLAG_NEGOTIATE, -+ .argv = argv, -+ .argc = ARRAY_SIZE(argv), -+ }; -+ -+ if (!kdbus_conn_is_ordinary(conn) && -+ !kdbus_conn_is_monitor(conn) && -+ !kdbus_conn_is_activator(conn)) -+ return -EOPNOTSUPP; -+ -+ ret = kdbus_args_parse(&args, argp, &cmd); -+ if (ret != 0) -+ return ret; -+ -+ ret = kdbus_pool_release_offset(conn->pool, cmd->offset); -+ -+ return kdbus_args_clear(&args, ret); -+} -diff --git a/ipc/kdbus/connection.h b/ipc/kdbus/connection.h -new file mode 100644 -index 000000000000..d1ffe909cb31 ---- /dev/null -+++ b/ipc/kdbus/connection.h -@@ -0,0 +1,257 @@ -+/* -+ * Copyright (C) 2013-2015 Kay Sievers -+ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> -+ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> -+ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> -+ * Copyright (C) 2013-2015 Linux Foundation -+ * Copyright (C) 2014-2015 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. -+ */ -+ -+#ifndef __KDBUS_CONNECTION_H -+#define __KDBUS_CONNECTION_H -+ -+#include <linux/atomic.h> -+#include <linux/kref.h> -+#include <linux/lockdep.h> -+#include <linux/path.h> -+ -+#include "limits.h" -+#include "metadata.h" -+#include "pool.h" -+#include "queue.h" -+#include "util.h" -+ -+#define KDBUS_HELLO_SPECIAL_CONN (KDBUS_HELLO_ACTIVATOR | \ -+ KDBUS_HELLO_POLICY_HOLDER | \ -+ KDBUS_HELLO_MONITOR) -+ -+struct kdbus_quota; -+struct kdbus_kmsg; -+ -+/** -+ * struct kdbus_conn - connection to a bus -+ * @kref: Reference count -+ * @active: Active references to the connection -+ * @id: Connection ID -+ * @flags: KDBUS_HELLO_* flags -+ * @attach_flags_send: KDBUS_ATTACH_* flags for sending -+ * @attach_flags_recv: KDBUS_ATTACH_* flags for receiving -+ * @description: Human-readable connection description, used for -+ * debugging. This field is only set when the -+ * connection is created. -+ * @ep: The endpoint this connection belongs to -+ * @lock: Connection data lock -+ * @hentry: Entry in ID <-> connection map -+ * @ep_entry: Entry in endpoint -+ * @monitor_entry: Entry in monitor, if the connection is a monitor -+ * @reply_list: List of connections this connection should -+ * reply to -+ * @work: Delayed work to handle timeouts -+ * activator for -+ * @match_db: Subscription filter to broadcast messages -+ * @meta: Active connection creator's metadata/credentials, -+ * either from the handle or from HELLO -+ * @pool: The user's buffer to receive messages -+ * @user: Owner of the connection -+ * @cred: The credentials of the connection at creation time -+ * @name_count: Number of owned well-known names -+ * @request_count: Number of pending requests issued by this -+ * connection that are waiting for replies from -+ * other peers -+ * @lost_count: Number of lost broadcast messages -+ * @wait: Wake up this endpoint -+ * @queue: The message queue associated with this connection -+ * @quota: Array of per-user quota indexed by user->id -+ * @n_quota: Number of elements in quota array -+ * @activator_of: Well-known name entry this connection acts as an -+ * @names_list: List of well-known names -+ * @names_queue_list: Well-known names this connection waits for -+ * @privileged: Whether this connection is privileged on the bus -+ * @faked_meta: Whether the metadata was faked on HELLO -+ */ -+struct kdbus_conn { -+ struct kref kref; -+ atomic_t active; -+#ifdef CONFIG_DEBUG_LOCK_ALLOC -+ struct lockdep_map dep_map; -+#endif -+ u64 id; -+ u64 flags; -+ atomic64_t attach_flags_send; -+ atomic64_t attach_flags_recv; -+ const char *description; -+ struct kdbus_ep *ep; -+ struct mutex lock; -+ struct hlist_node hentry; -+ struct list_head ep_entry; -+ struct list_head monitor_entry; -+ struct list_head reply_list; -+ struct delayed_work work; -+ struct kdbus_match_db *match_db; -+ struct kdbus_meta_proc *meta; -+ struct kdbus_pool *pool; -+ struct kdbus_user *user; -+ const struct cred *cred; -+ atomic_t name_count; -+ atomic_t request_count; -+ atomic_t lost_count; -+ wait_queue_head_t wait; -+ struct kdbus_queue queue; -+ -+ struct kdbus_quota *quota; -+ unsigned int n_quota; -+ -+ /* protected by registry->rwlock */ -+ struct kdbus_name_entry *activator_of; -+ struct list_head names_list; -+ struct list_head names_queue_list; -+ -+ bool privileged:1; -+ bool faked_meta:1; -+}; -+ -+struct kdbus_conn *kdbus_conn_ref(struct kdbus_conn *conn); -+struct kdbus_conn *kdbus_conn_unref(struct kdbus_conn *conn); -+bool kdbus_conn_active(const struct kdbus_conn *conn); -+int kdbus_conn_acquire(struct kdbus_conn *conn); -+void kdbus_conn_release(struct kdbus_conn *conn); -+int kdbus_conn_disconnect(struct kdbus_conn *conn, bool ensure_queue_empty); -+bool kdbus_conn_has_name(struct kdbus_conn *conn, const char *name); -+int kdbus_conn_quota_inc(struct kdbus_conn *c, struct kdbus_user *u, -+ size_t memory, size_t fds); -+void kdbus_conn_quota_dec(struct kdbus_conn *c, struct kdbus_user *u, -+ size_t memory, size_t fds); -+void kdbus_conn_lost_message(struct kdbus_conn *c); -+int kdbus_conn_entry_insert(struct kdbus_conn *conn_src, -+ struct kdbus_conn *conn_dst, -+ const struct kdbus_kmsg *kmsg, -+ struct kdbus_reply *reply); -+void kdbus_conn_move_messages(struct kdbus_conn *conn_dst, -+ struct kdbus_conn *conn_src, -+ u64 name_id); -+ -+/* policy */ -+bool kdbus_conn_policy_own_name(struct kdbus_conn *conn, -+ const struct cred *conn_creds, -+ const char *name); -+bool kdbus_conn_policy_talk(struct kdbus_conn *conn, -+ const struct cred *conn_creds, -+ struct kdbus_conn *to); -+bool kdbus_conn_policy_see_name_unlocked(struct kdbus_conn *conn, -+ const struct cred *curr_creds, -+ const char *name); -+bool kdbus_conn_policy_see_notification(struct kdbus_conn *conn, -+ const struct cred *curr_creds, -+ const struct kdbus_kmsg *kmsg); -+ -+/* command dispatcher */ -+struct kdbus_conn *kdbus_cmd_hello(struct kdbus_ep *ep, bool privileged, -+ void __user *argp); -+int kdbus_cmd_byebye_unlocked(struct kdbus_conn *conn, void __user *argp); -+int kdbus_cmd_conn_info(struct kdbus_conn *conn, void __user *argp); -+int kdbus_cmd_update(struct kdbus_conn *conn, void __user *argp); -+int kdbus_cmd_send(struct kdbus_conn *conn, struct file *f, void __user *argp); -+int kdbus_cmd_recv(struct kdbus_conn *conn, void __user *argp); -+int kdbus_cmd_free(struct kdbus_conn *conn, void __user *argp); -+ -+/** -+ * kdbus_conn_is_ordinary() - Check if connection is ordinary -+ * @conn: The connection to check -+ * -+ * Return: Non-zero if the connection is an ordinary connection -+ */ -+static inline int kdbus_conn_is_ordinary(const struct kdbus_conn *conn) -+{ -+ return !(conn->flags & KDBUS_HELLO_SPECIAL_CONN); -+} -+ -+/** -+ * kdbus_conn_is_activator() - Check if connection is an activator -+ * @conn: The connection to check -+ * -+ * Return: Non-zero if the connection is an activator -+ */ -+static inline int kdbus_conn_is_activator(const struct kdbus_conn *conn) -+{ -+ return conn->flags & KDBUS_HELLO_ACTIVATOR; -+} -+ -+/** -+ * kdbus_conn_is_policy_holder() - Check if connection is a policy holder -+ * @conn: The connection to check -+ * -+ * Return: Non-zero if the connection is a policy holder -+ */ -+static inline int kdbus_conn_is_policy_holder(const struct kdbus_conn *conn) -+{ -+ return conn->flags & KDBUS_HELLO_POLICY_HOLDER; -+} -+ -+/** -+ * kdbus_conn_is_monitor() - Check if connection is a monitor -+ * @conn: The connection to check -+ * -+ * Return: Non-zero if the connection is a monitor -+ */ -+static inline int kdbus_conn_is_monitor(const struct kdbus_conn *conn) -+{ -+ return conn->flags & KDBUS_HELLO_MONITOR; -+} -+ -+/** -+ * kdbus_conn_lock2() - Lock two connections -+ * @a: connection A to lock or NULL -+ * @b: connection B to lock or NULL -+ * -+ * Lock two connections at once. As we need to have a stable locking order, we -+ * always lock the connection with lower memory address first. -+ */ -+static inline void kdbus_conn_lock2(struct kdbus_conn *a, struct kdbus_conn *b) -+{ -+ if (a < b) { -+ if (a) -+ mutex_lock(&a->lock); -+ if (b && b != a) -+ mutex_lock_nested(&b->lock, !!a); -+ } else { -+ if (b) -+ mutex_lock(&b->lock); -+ if (a && a != b) -+ mutex_lock_nested(&a->lock, !!b); -+ } -+} -+ -+/** -+ * kdbus_conn_unlock2() - Unlock two connections -+ * @a: connection A to unlock or NULL -+ * @b: connection B to unlock or NULL -+ * -+ * Unlock two connections at once. See kdbus_conn_lock2(). -+ */ -+static inline void kdbus_conn_unlock2(struct kdbus_conn *a, -+ struct kdbus_conn *b) -+{ -+ if (a) -+ mutex_unlock(&a->lock); -+ if (b && b != a) -+ mutex_unlock(&b->lock); -+} -+ -+/** -+ * kdbus_conn_assert_active() - lockdep assert on active lock -+ * @conn: connection that shall be active -+ * -+ * This verifies via lockdep that the caller holds an active reference to the -+ * given connection. -+ */ -+static inline void kdbus_conn_assert_active(struct kdbus_conn *conn) -+{ -+ lockdep_assert_held(conn); -+} -+ -+#endif -diff --git a/ipc/kdbus/item.c b/ipc/kdbus/item.c -new file mode 100644 -index 000000000000..745ad5495096 ---- /dev/null -+++ b/ipc/kdbus/item.c -@@ -0,0 +1,339 @@ -+/* -+ * Copyright (C) 2013-2015 Kay Sievers -+ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> -+ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> -+ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> -+ * Copyright (C) 2013-2015 Linux Foundation -+ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> -+ * -+ * 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/string.h> -+ -+#include "item.h" -+#include "limits.h" -+#include "util.h" -+ -+/* -+ * This verifies the string at position @str with size @size is properly -+ * zero-terminated and does not contain a 0-byte but at the end. -+ */ -+static bool kdbus_str_valid(const char *str, size_t size) -+{ -+ return size > 0 && memchr(str, '\0', size) == str + size - 1; -+} -+ -+/** -+ * kdbus_item_validate_name() - validate an item containing a name -+ * @item: Item to validate -+ * -+ * Return: zero on success or an negative error code on failure -+ */ -+int kdbus_item_validate_name(const struct kdbus_item *item) -+{ -+ const char *name = item->str; -+ unsigned int i; -+ size_t len; -+ -+ if (item->size < KDBUS_ITEM_HEADER_SIZE + 2) -+ return -EINVAL; -+ -+ if (item->size > KDBUS_ITEM_HEADER_SIZE + -+ KDBUS_SYSNAME_MAX_LEN + 1) -+ return -ENAMETOOLONG; -+ -+ if (!kdbus_str_valid(name, KDBUS_ITEM_PAYLOAD_SIZE(item))) -+ return -EINVAL; -+ -+ len = strlen(name); -+ if (len == 0) -+ return -EINVAL; -+ -+ for (i = 0; i < len; i++) { -+ if (isalpha(name[i])) -+ continue; -+ if (isdigit(name[i])) -+ continue; -+ if (name[i] == '_') -+ continue; -+ if (i > 0 && i + 1 < len && (name[i] == '-' || name[i] == '.')) -+ continue; -+ -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+/** -+ * kdbus_item_validate() - validate a single item -+ * @item: item to validate -+ * -+ * Return: 0 if item is valid, negative error code if not. -+ */ -+int kdbus_item_validate(const struct kdbus_item *item) -+{ -+ size_t payload_size = KDBUS_ITEM_PAYLOAD_SIZE(item); -+ size_t l; -+ int ret; -+ -+ BUILD_BUG_ON(KDBUS_ITEM_HEADER_SIZE != -+ sizeof(struct kdbus_item_header)); -+ -+ if (item->size < KDBUS_ITEM_HEADER_SIZE) -+ return -EINVAL; -+ -+ switch (item->type) { -+ case KDBUS_ITEM_NEGOTIATE: -+ if (payload_size % sizeof(u64) != 0) -+ return -EINVAL; -+ break; -+ -+ case KDBUS_ITEM_PAYLOAD_VEC: -+ if (payload_size != sizeof(struct kdbus_vec)) -+ return -EINVAL; -+ if (item->vec.size == 0 || item->vec.size > SIZE_MAX) -+ return -EINVAL; -+ break; -+ -+ case KDBUS_ITEM_PAYLOAD_OFF: -+ if (payload_size != sizeof(struct kdbus_vec)) -+ return -EINVAL; -+ if (item->vec.size == 0 || item->vec.size > SIZE_MAX) -+ return -EINVAL; -+ break; -+ -+ case KDBUS_ITEM_PAYLOAD_MEMFD: -+ if (payload_size != sizeof(struct kdbus_memfd)) -+ return -EINVAL; -+ if (item->memfd.size == 0 || item->memfd.size > SIZE_MAX) -+ return -EINVAL; -+ if (item->memfd.fd < 0) -+ return -EBADF; -+ break; -+ -+ case KDBUS_ITEM_FDS: -+ if (payload_size % sizeof(int) != 0) -+ return -EINVAL; -+ break; -+ -+ case KDBUS_ITEM_CANCEL_FD: -+ if (payload_size != sizeof(int)) -+ return -EINVAL; -+ break; -+ -+ case KDBUS_ITEM_BLOOM_PARAMETER: -+ if (payload_size != sizeof(struct kdbus_bloom_parameter)) -+ return -EINVAL; -+ break; -+ -+ case KDBUS_ITEM_BLOOM_FILTER: -+ /* followed by the bloom-mask, depends on the bloom-size */ -+ if (payload_size < sizeof(struct kdbus_bloom_filter)) -+ return -EINVAL; -+ break; -+ -+ case KDBUS_ITEM_BLOOM_MASK: -+ /* size depends on bloom-size of bus */ -+ break; -+ -+ case KDBUS_ITEM_CONN_DESCRIPTION: -+ case KDBUS_ITEM_MAKE_NAME: -+ ret = kdbus_item_validate_name(item); -+ if (ret < 0) -+ return ret; -+ break; -+ -+ case KDBUS_ITEM_ATTACH_FLAGS_SEND: -+ case KDBUS_ITEM_ATTACH_FLAGS_RECV: -+ case KDBUS_ITEM_ID: -+ if (payload_size != sizeof(u64)) -+ return -EINVAL; -+ break; -+ -+ case KDBUS_ITEM_TIMESTAMP: -+ if (payload_size != sizeof(struct kdbus_timestamp)) -+ return -EINVAL; -+ break; -+ -+ case KDBUS_ITEM_CREDS: -+ if (payload_size != sizeof(struct kdbus_creds)) -+ return -EINVAL; -+ break; -+ -+ case KDBUS_ITEM_AUXGROUPS: -+ if (payload_size % sizeof(u32) != 0) -+ return -EINVAL; -+ break; -+ -+ case KDBUS_ITEM_NAME: -+ case KDBUS_ITEM_DST_NAME: -+ case KDBUS_ITEM_PID_COMM: -+ case KDBUS_ITEM_TID_COMM: -+ case KDBUS_ITEM_EXE: -+ case KDBUS_ITEM_CMDLINE: -+ case KDBUS_ITEM_CGROUP: -+ case KDBUS_ITEM_SECLABEL: -+ if (!kdbus_str_valid(item->str, payload_size)) -+ return -EINVAL; -+ break; -+ -+ case KDBUS_ITEM_CAPS: -+ if (payload_size < sizeof(u32)) -+ return -EINVAL; -+ if (payload_size < sizeof(u32) + -+ 4 * CAP_TO_INDEX(item->caps.last_cap) * sizeof(u32)) -+ return -EINVAL; -+ break; -+ -+ case KDBUS_ITEM_AUDIT: -+ if (payload_size != sizeof(struct kdbus_audit)) -+ return -EINVAL; -+ break; -+ -+ case KDBUS_ITEM_POLICY_ACCESS: -+ if (payload_size != sizeof(struct kdbus_policy_access)) -+ return -EINVAL; -+ break; -+ -+ case KDBUS_ITEM_NAME_ADD: -+ case KDBUS_ITEM_NAME_REMOVE: -+ case KDBUS_ITEM_NAME_CHANGE: -+ if (payload_size < sizeof(struct kdbus_notify_name_change)) -+ return -EINVAL; -+ l = payload_size - offsetof(struct kdbus_notify_name_change, -+ name); -+ if (l > 0 && !kdbus_str_valid(item->name_change.name, l)) -+ return -EINVAL; -+ break; -+ -+ case KDBUS_ITEM_ID_ADD: -+ case KDBUS_ITEM_ID_REMOVE: -+ if (payload_size != sizeof(struct kdbus_notify_id_change)) -+ return -EINVAL; -+ break; -+ -+ case KDBUS_ITEM_REPLY_TIMEOUT: -+ case KDBUS_ITEM_REPLY_DEAD: -+ if (payload_size != 0) -+ return -EINVAL; -+ break; -+ -+ default: -+ break; -+ } -+ -+ return 0; -+} -+ -+/** -+ * kdbus_items_validate() - validate items passed by user-space -+ * @items: items to validate -+ * @items_size: number of items -+ * -+ * This verifies that the passed items pointer is consistent and valid. -+ * Furthermore, each item is checked for: -+ * - valid "size" value -+ * - payload is of expected type -+ * - payload is fully included in the item -+ * - string payloads are zero-terminated -+ * -+ * Return: 0 on success, negative error code on failure. -+ */ -+int kdbus_items_validate(const struct kdbus_item *items, size_t items_size) -+{ -+ const struct kdbus_item *item; -+ int ret; -+ -+ KDBUS_ITEMS_FOREACH(item, items, items_size) { -+ if (!KDBUS_ITEM_VALID(item, items, items_size)) -+ return -EINVAL; -+ -+ ret = kdbus_item_validate(item); -+ if (ret < 0) -+ return ret; -+ } -+ -+ if (!KDBUS_ITEMS_END(item, items, items_size)) -+ return -EINVAL; -+ -+ return 0; -+} -+ -+static struct kdbus_item *kdbus_items_get(const struct kdbus_item *items, -+ size_t items_size, -+ unsigned int item_type) -+{ -+ const struct kdbus_item *iter, *found = NULL; -+ -+ KDBUS_ITEMS_FOREACH(iter, items, items_size) { -+ if (iter->type == item_type) { -+ if (found) -+ return ERR_PTR(-EEXIST); -+ found = iter; -+ } -+ } -+ -+ return (struct kdbus_item *)found ? : ERR_PTR(-EBADMSG); -+} -+ -+/** -+ * kdbus_items_get_str() - get string from a list of items -+ * @items: The items to walk -+ * @items_size: The size of all items -+ * @item_type: The item type to look for -+ * -+ * This function walks a list of items and searches for items of type -+ * @item_type. If it finds exactly one such item, @str_ret will be set to -+ * the .str member of the item. -+ * -+ * Return: the string, if the item was found exactly once, ERR_PTR(-EEXIST) -+ * if the item was found more than once, and ERR_PTR(-EBADMSG) if there was -+ * no item of the given type. -+ */ -+const char *kdbus_items_get_str(const struct kdbus_item *items, -+ size_t items_size, -+ unsigned int item_type) -+{ -+ const struct kdbus_item *item; -+ -+ item = kdbus_items_get(items, items_size, item_type); -+ return IS_ERR(item) ? ERR_CAST(item) : item->str; -+} -+ -+/** -+ * kdbus_item_set() - Set item content -+ * @item: The item to modify -+ * @type: The item type to set (KDBUS_ITEM_*) -+ * @data: Data to copy to item->data, may be %NULL -+ * @len: Number of bytes in @data -+ * -+ * This sets type, size and data fields of an item. If @data is NULL, the data -+ * memory is cleared. -+ * -+ * Note that you must align your @data memory to 8 bytes. Trailing padding (in -+ * case @len is not 8byte aligned) is cleared by this call. -+ * -+ * Returns: Pointer to the following item. -+ */ -+struct kdbus_item *kdbus_item_set(struct kdbus_item *item, u64 type, -+ const void *data, size_t len) -+{ -+ item->type = type; -+ item->size = KDBUS_ITEM_HEADER_SIZE + len; -+ -+ if (data) { -+ memcpy(item->data, data, len); -+ memset(item->data + len, 0, KDBUS_ALIGN8(len) - len); -+ } else { -+ memset(item->data, 0, KDBUS_ALIGN8(len)); -+ } -+ -+ return KDBUS_ITEM_NEXT(item); -+} -diff --git a/ipc/kdbus/item.h b/ipc/kdbus/item.h -new file mode 100644 -index 000000000000..eeefd8beac3b ---- /dev/null -+++ b/ipc/kdbus/item.h -@@ -0,0 +1,64 @@ -+/* -+ * Copyright (C) 2013-2015 Kay Sievers -+ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> -+ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> -+ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> -+ * Copyright (C) 2013-2015 Linux Foundation -+ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> -+ * -+ * 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_ITEM_H -+#define __KDBUS_ITEM_H -+ -+#include <linux/kernel.h> -+#include <uapi/linux/kdbus.h> -+ -+#include "util.h" -+ -+/* generic access and iterators over a stream of items */ -+#define KDBUS_ITEM_NEXT(_i) (typeof(_i))(((u8 *)_i) + KDBUS_ALIGN8((_i)->size)) -+#define KDBUS_ITEMS_SIZE(_h, _is) ((_h)->size - offsetof(typeof(*_h), _is)) -+#define KDBUS_ITEM_HEADER_SIZE offsetof(struct kdbus_item, data) -+#define KDBUS_ITEM_SIZE(_s) KDBUS_ALIGN8(KDBUS_ITEM_HEADER_SIZE + (_s)) -+#define KDBUS_ITEM_PAYLOAD_SIZE(_i) ((_i)->size - KDBUS_ITEM_HEADER_SIZE) -+ -+#define KDBUS_ITEMS_FOREACH(_i, _is, _s) \ -+ for (_i = _is; \ -+ ((u8 *)(_i) < (u8 *)(_is) + (_s)) && \ -+ ((u8 *)(_i) >= (u8 *)(_is)); \ -+ _i = KDBUS_ITEM_NEXT(_i)) -+ -+#define KDBUS_ITEM_VALID(_i, _is, _s) \ -+ ((_i)->size >= KDBUS_ITEM_HEADER_SIZE && \ -+ (u8 *)(_i) + (_i)->size > (u8 *)(_i) && \ -+ (u8 *)(_i) + (_i)->size <= (u8 *)(_is) + (_s) && \ -+ (u8 *)(_i) >= (u8 *)(_is)) -+ -+#define KDBUS_ITEMS_END(_i, _is, _s) \ -+ ((u8 *)_i == ((u8 *)(_is) + KDBUS_ALIGN8(_s))) -+ -+/** -+ * struct kdbus_item_header - Describes the fix part of an item -+ * @size: The total size of the item -+ * @type: The item type, one of KDBUS_ITEM_* -+ */ -+struct kdbus_item_header { -+ u64 size; -+ u64 type; -+}; -+ -+int kdbus_item_validate_name(const struct kdbus_item *item); -+int kdbus_item_validate(const struct kdbus_item *item); -+int kdbus_items_validate(const struct kdbus_item *items, size_t items_size); -+const char *kdbus_items_get_str(const struct kdbus_item *items, -+ size_t items_size, -+ unsigned int item_type); -+struct kdbus_item *kdbus_item_set(struct kdbus_item *item, u64 type, -+ const void *data, size_t len); -+ -+#endif -diff --git a/ipc/kdbus/message.c b/ipc/kdbus/message.c -new file mode 100644 -index 000000000000..80960756a329 ---- /dev/null -+++ b/ipc/kdbus/message.c -@@ -0,0 +1,616 @@ -+/* -+ * Copyright (C) 2013-2015 Kay Sievers -+ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> -+ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> -+ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> -+ * Copyright (C) 2013-2015 Linux Foundation -+ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> -+ * -+ * 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/capability.h> -+#include <linux/cgroup.h> -+#include <linux/cred.h> -+#include <linux/file.h> -+#include <linux/init.h> -+#include <linux/module.h> -+#include <linux/mutex.h> -+#include <linux/sched.h> -+#include <linux/shmem_fs.h> -+#include <linux/sizes.h> -+#include <linux/slab.h> -+#include <linux/uaccess.h> -+#include <net/sock.h> -+ -+#include "bus.h" -+#include "connection.h" -+#include "domain.h" -+#include "endpoint.h" -+#include "handle.h" -+#include "item.h" -+#include "match.h" -+#include "message.h" -+#include "names.h" -+#include "policy.h" -+ -+#define KDBUS_KMSG_HEADER_SIZE offsetof(struct kdbus_kmsg, msg) -+ -+static struct kdbus_msg_resources *kdbus_msg_resources_new(void) -+{ -+ struct kdbus_msg_resources *r; -+ -+ r = kzalloc(sizeof(*r), GFP_KERNEL); -+ if (!r) -+ return ERR_PTR(-ENOMEM); -+ -+ kref_init(&r->kref); -+ -+ return r; -+} -+ -+static void __kdbus_msg_resources_free(struct kref *kref) -+{ -+ struct kdbus_msg_resources *r = -+ container_of(kref, struct kdbus_msg_resources, kref); -+ size_t i; -+ -+ for (i = 0; i < r->data_count; ++i) { -+ switch (r->data[i].type) { -+ case KDBUS_MSG_DATA_VEC: -+ /* nothing to do */ -+ break; -+ case KDBUS_MSG_DATA_MEMFD: -+ if (r->data[i].memfd.file) -+ fput(r->data[i].memfd.file); -+ break; -+ } -+ } -+ -+ for (i = 0; i < r->fds_count; i++) -+ if (r->fds[i]) -+ fput(r->fds[i]); -+ -+ kfree(r->dst_name); -+ kfree(r->data); -+ kfree(r->fds); -+ kfree(r); -+} -+ -+/** -+ * kdbus_msg_resources_ref() - Acquire reference to msg resources -+ * @r: resources to acquire ref to -+ * -+ * Return: The acquired resource -+ */ -+struct kdbus_msg_resources * -+kdbus_msg_resources_ref(struct kdbus_msg_resources *r) -+{ -+ if (r) -+ kref_get(&r->kref); -+ return r; -+} -+ -+/** -+ * kdbus_msg_resources_unref() - Drop reference to msg resources -+ * @r: resources to drop reference of -+ * -+ * Return: NULL -+ */ -+struct kdbus_msg_resources * -+kdbus_msg_resources_unref(struct kdbus_msg_resources *r) -+{ -+ if (r) -+ kref_put(&r->kref, __kdbus_msg_resources_free); -+ return NULL; -+} -+ -+/** -+ * kdbus_kmsg_free() - free allocated message -+ * @kmsg: Message -+ */ -+void kdbus_kmsg_free(struct kdbus_kmsg *kmsg) -+{ -+ if (!kmsg) -+ return; -+ -+ kdbus_msg_resources_unref(kmsg->res); -+ kdbus_meta_conn_unref(kmsg->conn_meta); -+ kdbus_meta_proc_unref(kmsg->proc_meta); -+ kfree(kmsg->iov); -+ kfree(kmsg); -+} -+ -+/** -+ * kdbus_kmsg_new() - allocate message -+ * @bus: Bus this message is allocated on -+ * @extra_size: Additional size to reserve for data -+ * -+ * Return: new kdbus_kmsg on success, ERR_PTR on failure. -+ */ -+struct kdbus_kmsg *kdbus_kmsg_new(struct kdbus_bus *bus, size_t extra_size) -+{ -+ struct kdbus_kmsg *m; -+ size_t size; -+ int ret; -+ -+ size = sizeof(struct kdbus_kmsg) + KDBUS_ITEM_SIZE(extra_size); -+ m = kzalloc(size, GFP_KERNEL); -+ if (!m) -+ return ERR_PTR(-ENOMEM); -+ -+ m->seq = atomic64_inc_return(&bus->domain->last_id); -+ m->msg.size = size - KDBUS_KMSG_HEADER_SIZE; -+ m->msg.items[0].size = KDBUS_ITEM_SIZE(extra_size); -+ -+ m->proc_meta = kdbus_meta_proc_new(); -+ if (IS_ERR(m->proc_meta)) { -+ ret = PTR_ERR(m->proc_meta); -+ m->proc_meta = NULL; -+ goto exit; -+ } -+ -+ m->conn_meta = kdbus_meta_conn_new(); -+ if (IS_ERR(m->conn_meta)) { -+ ret = PTR_ERR(m->conn_meta); -+ m->conn_meta = NULL; -+ goto exit; -+ } -+ -+ return m; -+ -+exit: -+ kdbus_kmsg_free(m); -+ return ERR_PTR(ret); -+} -+ -+static int kdbus_handle_check_file(struct file *file) -+{ -+ struct inode *inode = file_inode(file); -+ struct socket *sock; -+ -+ /* -+ * Don't allow file descriptors in the transport that themselves allow -+ * file descriptor queueing. This will eventually be allowed once both -+ * unix domain sockets and kdbus share a generic garbage collector. -+ */ -+ -+ if (file->f_op == &kdbus_handle_ops) -+ return -EOPNOTSUPP; -+ -+ if (!S_ISSOCK(inode->i_mode)) -+ return 0; -+ -+ if (file->f_mode & FMODE_PATH) -+ return 0; -+ -+ sock = SOCKET_I(inode); -+ if (sock->sk && sock->ops && sock->ops->family == PF_UNIX) -+ return -EOPNOTSUPP; -+ -+ return 0; -+} -+ -+static const char * const zeros = "\0\0\0\0\0\0\0"; -+ -+/* -+ * kdbus_msg_scan_items() - validate incoming data and prepare parsing -+ * @kmsg: Message -+ * @bus: Bus the message is sent over -+ * -+ * Return: 0 on success, negative errno on failure. -+ * -+ * Files references in MEMFD or FDS items are pinned. -+ * -+ * On errors, the caller should drop any taken reference with -+ * kdbus_kmsg_free() -+ */ -+static int kdbus_msg_scan_items(struct kdbus_kmsg *kmsg, -+ struct kdbus_bus *bus) -+{ -+ struct kdbus_msg_resources *res = kmsg->res; -+ const struct kdbus_msg *msg = &kmsg->msg; -+ const struct kdbus_item *item; -+ size_t n, n_vecs, n_memfds; -+ bool has_bloom = false; -+ bool has_name = false; -+ bool has_fds = false; -+ bool is_broadcast; -+ bool is_signal; -+ u64 vec_size; -+ -+ is_broadcast = (msg->dst_id == KDBUS_DST_ID_BROADCAST); -+ is_signal = !!(msg->flags & KDBUS_MSG_SIGNAL); -+ -+ /* count data payloads */ -+ n_vecs = 0; -+ n_memfds = 0; -+ KDBUS_ITEMS_FOREACH(item, msg->items, KDBUS_ITEMS_SIZE(msg, items)) { -+ switch (item->type) { -+ case KDBUS_ITEM_PAYLOAD_VEC: -+ ++n_vecs; -+ break; -+ case KDBUS_ITEM_PAYLOAD_MEMFD: -+ ++n_memfds; -+ if (item->memfd.size % 8) -+ ++n_vecs; -+ break; -+ default: -+ break; -+ } -+ } -+ -+ n = n_vecs + n_memfds; -+ if (n > 0) { -+ res->data = kcalloc(n, sizeof(*res->data), GFP_KERNEL); -+ if (!res->data) -+ return -ENOMEM; -+ } -+ -+ if (n_vecs > 0) { -+ kmsg->iov = kcalloc(n_vecs, sizeof(*kmsg->iov), GFP_KERNEL); -+ if (!kmsg->iov) -+ return -ENOMEM; -+ } -+ -+ /* import data payloads */ -+ n = 0; -+ vec_size = 0; -+ KDBUS_ITEMS_FOREACH(item, msg->items, KDBUS_ITEMS_SIZE(msg, items)) { -+ size_t payload_size = KDBUS_ITEM_PAYLOAD_SIZE(item); -+ struct iovec *iov = kmsg->iov + kmsg->iov_count; -+ -+ if (++n > KDBUS_MSG_MAX_ITEMS) -+ return -E2BIG; -+ -+ switch (item->type) { -+ case KDBUS_ITEM_PAYLOAD_VEC: { -+ struct kdbus_msg_data *d = res->data + res->data_count; -+ void __force __user *ptr = KDBUS_PTR(item->vec.address); -+ size_t size = item->vec.size; -+ -+ if (vec_size + size < vec_size) -+ return -EMSGSIZE; -+ if (vec_size + size > KDBUS_MSG_MAX_PAYLOAD_VEC_SIZE) -+ return -EMSGSIZE; -+ -+ d->type = KDBUS_MSG_DATA_VEC; -+ d->size = size; -+ -+ if (ptr) { -+ if (unlikely(!access_ok(VERIFY_READ, ptr, -+ size))) -+ return -EFAULT; -+ -+ d->vec.off = kmsg->pool_size; -+ iov->iov_base = ptr; -+ iov->iov_len = size; -+ } else { -+ d->vec.off = ~0ULL; -+ iov->iov_base = (char __user *)zeros; -+ iov->iov_len = size % 8; -+ } -+ -+ if (kmsg->pool_size + iov->iov_len < kmsg->pool_size) -+ return -EMSGSIZE; -+ -+ kmsg->pool_size += iov->iov_len; -+ ++kmsg->iov_count; -+ ++res->vec_count; -+ ++res->data_count; -+ vec_size += size; -+ -+ break; -+ } -+ -+ case KDBUS_ITEM_PAYLOAD_MEMFD: { -+ struct kdbus_msg_data *d = res->data + res->data_count; -+ u64 start = item->memfd.start; -+ u64 size = item->memfd.size; -+ size_t pad = size % 8; -+ int seals, mask; -+ struct file *f; -+ -+ if (kmsg->pool_size + size % 8 < kmsg->pool_size) -+ return -EMSGSIZE; -+ if (start + size < start) -+ return -EMSGSIZE; -+ -+ if (item->memfd.fd < 0) -+ return -EBADF; -+ -+ if (res->memfd_count >= KDBUS_MSG_MAX_MEMFD_ITEMS) -+ return -E2BIG; -+ -+ f = fget(item->memfd.fd); -+ if (!f) -+ return -EBADF; -+ -+ if (pad) { -+ iov->iov_base = (char __user *)zeros; -+ iov->iov_len = pad; -+ -+ kmsg->pool_size += pad; -+ ++kmsg->iov_count; -+ } -+ -+ ++res->data_count; -+ ++res->memfd_count; -+ -+ d->type = KDBUS_MSG_DATA_MEMFD; -+ d->size = size; -+ d->memfd.start = start; -+ d->memfd.file = f; -+ -+ /* -+ * We only accept a sealed memfd file whose content -+ * cannot be altered by the sender or anybody else -+ * while it is shared or in-flight. Other files need -+ * to be passed with KDBUS_MSG_FDS. -+ */ -+ seals = shmem_get_seals(f); -+ if (seals < 0) -+ return -EMEDIUMTYPE; -+ -+ mask = F_SEAL_SHRINK | F_SEAL_GROW | -+ F_SEAL_WRITE | F_SEAL_SEAL; -+ if ((seals & mask) != mask) -+ return -ETXTBSY; -+ -+ if (start + size > (u64)i_size_read(file_inode(f))) -+ return -EBADF; -+ -+ break; -+ } -+ -+ case KDBUS_ITEM_FDS: { -+ unsigned int i; -+ unsigned int fds_count = payload_size / sizeof(int); -+ -+ /* do not allow multiple fd arrays */ -+ if (has_fds) -+ return -EEXIST; -+ has_fds = true; -+ -+ /* Do not allow to broadcast file descriptors */ -+ if (is_broadcast) -+ return -ENOTUNIQ; -+ -+ if (fds_count > KDBUS_CONN_MAX_FDS_PER_USER) -+ return -EMFILE; -+ -+ res->fds = kcalloc(fds_count, sizeof(struct file *), -+ GFP_KERNEL); -+ if (!res->fds) -+ return -ENOMEM; -+ -+ for (i = 0; i < fds_count; i++) { -+ int fd = item->fds[i]; -+ int ret; -+ -+ /* -+ * Verify the fd and increment the usage count. -+ * Use fget_raw() to allow passing O_PATH fds. -+ */ -+ if (fd < 0) -+ return -EBADF; -+ -+ res->fds[i] = fget_raw(fd); -+ if (!res->fds[i]) -+ return -EBADF; -+ -+ res->fds_count++; -+ -+ ret = kdbus_handle_check_file(res->fds[i]); -+ if (ret < 0) -+ return ret; -+ } -+ -+ break; -+ } -+ -+ case KDBUS_ITEM_BLOOM_FILTER: { -+ u64 bloom_size; -+ -+ /* do not allow multiple bloom filters */ -+ if (has_bloom) -+ return -EEXIST; -+ has_bloom = true; -+ -+ bloom_size = payload_size - -+ offsetof(struct kdbus_bloom_filter, data); -+ -+ /* -+ * Allow only bloom filter sizes of a multiple of 64bit. -+ */ -+ if (!KDBUS_IS_ALIGNED8(bloom_size)) -+ return -EFAULT; -+ -+ /* do not allow mismatching bloom filter sizes */ -+ if (bloom_size != bus->bloom.size) -+ return -EDOM; -+ -+ kmsg->bloom_filter = &item->bloom_filter; -+ break; -+ } -+ -+ case KDBUS_ITEM_DST_NAME: -+ /* do not allow multiple names */ -+ if (has_name) -+ return -EEXIST; -+ has_name = true; -+ -+ if (!kdbus_name_is_valid(item->str, false)) -+ return -EINVAL; -+ -+ res->dst_name = kstrdup(item->str, GFP_KERNEL); -+ if (!res->dst_name) -+ return -ENOMEM; -+ break; -+ -+ default: -+ return -EINVAL; -+ } -+ } -+ -+ /* name is needed if no ID is given */ -+ if (msg->dst_id == KDBUS_DST_ID_NAME && !has_name) -+ return -EDESTADDRREQ; -+ -+ if (is_broadcast) { -+ /* Broadcasts can't take names */ -+ if (has_name) -+ return -EBADMSG; -+ -+ /* All broadcasts have to be signals */ -+ if (!is_signal) -+ return -EBADMSG; -+ -+ /* Timeouts are not allowed for broadcasts */ -+ if (msg->timeout_ns > 0) -+ return -ENOTUNIQ; -+ } -+ -+ /* -+ * Signal messages require a bloom filter, and bloom filters are -+ * only valid with signals. -+ */ -+ if (is_signal ^ has_bloom) -+ return -EBADMSG; -+ -+ return 0; -+} -+ -+/** -+ * kdbus_kmsg_new_from_cmd() - create kernel message from send payload -+ * @conn: Connection -+ * @cmd_send: Payload of KDBUS_CMD_SEND -+ * -+ * Return: a new kdbus_kmsg on success, ERR_PTR on failure. -+ */ -+struct kdbus_kmsg *kdbus_kmsg_new_from_cmd(struct kdbus_conn *conn, -+ struct kdbus_cmd_send *cmd_send) -+{ -+ struct kdbus_kmsg *m; -+ u64 size; -+ int ret; -+ -+ ret = kdbus_copy_from_user(&size, KDBUS_PTR(cmd_send->msg_address), -+ sizeof(size)); -+ if (ret < 0) -+ return ERR_PTR(ret); -+ -+ if (size < sizeof(struct kdbus_msg) || size > KDBUS_MSG_MAX_SIZE) -+ return ERR_PTR(-EINVAL); -+ -+ m = kmalloc(size + KDBUS_KMSG_HEADER_SIZE, GFP_KERNEL); -+ if (!m) -+ return ERR_PTR(-ENOMEM); -+ -+ memset(m, 0, KDBUS_KMSG_HEADER_SIZE); -+ m->seq = atomic64_inc_return(&conn->ep->bus->domain->last_id); -+ -+ m->proc_meta = kdbus_meta_proc_new(); -+ if (IS_ERR(m->proc_meta)) { -+ ret = PTR_ERR(m->proc_meta); -+ m->proc_meta = NULL; -+ goto exit_free; -+ } -+ -+ m->conn_meta = kdbus_meta_conn_new(); -+ if (IS_ERR(m->conn_meta)) { -+ ret = PTR_ERR(m->conn_meta); -+ m->conn_meta = NULL; -+ goto exit_free; -+ } -+ -+ if (copy_from_user(&m->msg, KDBUS_PTR(cmd_send->msg_address), size)) { -+ ret = -EFAULT; -+ goto exit_free; -+ } -+ -+ if (m->msg.size != size) { -+ ret = -EINVAL; -+ goto exit_free; -+ } -+ -+ if (m->msg.flags & ~(KDBUS_MSG_EXPECT_REPLY | -+ KDBUS_MSG_NO_AUTO_START | -+ KDBUS_MSG_SIGNAL)) { -+ ret = -EINVAL; -+ goto exit_free; -+ } -+ -+ ret = kdbus_items_validate(m->msg.items, -+ KDBUS_ITEMS_SIZE(&m->msg, items)); -+ if (ret < 0) -+ goto exit_free; -+ -+ m->res = kdbus_msg_resources_new(); -+ if (IS_ERR(m->res)) { -+ ret = PTR_ERR(m->res); -+ m->res = NULL; -+ goto exit_free; -+ } -+ -+ /* do not accept kernel-generated messages */ -+ if (m->msg.payload_type == KDBUS_PAYLOAD_KERNEL) { -+ ret = -EINVAL; -+ goto exit_free; -+ } -+ -+ if (m->msg.flags & KDBUS_MSG_EXPECT_REPLY) { -+ /* requests for replies need timeout and cookie */ -+ if (m->msg.timeout_ns == 0 || m->msg.cookie == 0) { -+ ret = -EINVAL; -+ goto exit_free; -+ } -+ -+ /* replies may not be expected for broadcasts */ -+ if (m->msg.dst_id == KDBUS_DST_ID_BROADCAST) { -+ ret = -ENOTUNIQ; -+ goto exit_free; -+ } -+ -+ /* replies may not be expected for signals */ -+ if (m->msg.flags & KDBUS_MSG_SIGNAL) { -+ ret = -EINVAL; -+ goto exit_free; -+ } -+ } else { -+ /* -+ * KDBUS_SEND_SYNC_REPLY is only valid together with -+ * KDBUS_MSG_EXPECT_REPLY -+ */ -+ if (cmd_send->flags & KDBUS_SEND_SYNC_REPLY) { -+ ret = -EINVAL; -+ goto exit_free; -+ } -+ -+ /* replies cannot be signals */ -+ if (m->msg.cookie_reply && (m->msg.flags & KDBUS_MSG_SIGNAL)) { -+ ret = -EINVAL; -+ goto exit_free; -+ } -+ } -+ -+ ret = kdbus_msg_scan_items(m, conn->ep->bus); -+ if (ret < 0) -+ goto exit_free; -+ -+ /* patch-in the source of this message */ -+ if (m->msg.src_id > 0 && m->msg.src_id != conn->id) { -+ ret = -EINVAL; -+ goto exit_free; -+ } -+ m->msg.src_id = conn->id; -+ -+ return m; -+ -+exit_free: -+ kdbus_kmsg_free(m); -+ return ERR_PTR(ret); -+} -diff --git a/ipc/kdbus/message.h b/ipc/kdbus/message.h -new file mode 100644 -index 000000000000..af4775850235 ---- /dev/null -+++ b/ipc/kdbus/message.h -@@ -0,0 +1,133 @@ -+/* -+ * Copyright (C) 2013-2015 Kay Sievers -+ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> -+ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> -+ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> -+ * Copyright (C) 2013-2015 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_MESSAGE_H -+#define __KDBUS_MESSAGE_H -+ -+#include "util.h" -+#include "metadata.h" -+ -+/** -+ * enum kdbus_msg_data_type - Type of kdbus_msg_data payloads -+ * @KDBUS_MSG_DATA_VEC: Data vector provided by user-space -+ * @KDBUS_MSG_DATA_MEMFD: Memfd payload -+ */ -+enum kdbus_msg_data_type { -+ KDBUS_MSG_DATA_VEC, -+ KDBUS_MSG_DATA_MEMFD, -+}; -+ -+/** -+ * struct kdbus_msg_data - Data payload as stored by messages -+ * @type: Type of payload (KDBUS_MSG_DATA_*) -+ * @size: Size of the described payload -+ * @off: The offset, relative to the vec slice -+ * @start: Offset inside the memfd -+ * @file: Backing file referenced by the memfd -+ */ -+struct kdbus_msg_data { -+ unsigned int type; -+ u64 size; -+ -+ union { -+ struct { -+ u64 off; -+ } vec; -+ struct { -+ u64 start; -+ struct file *file; -+ } memfd; -+ }; -+}; -+ -+/** -+ * struct kdbus_kmsg_resources - resources of a message -+ * @kref: Reference counter -+ * @dst_name: Short-cut to msg for faster lookup -+ * @fds: Array of file descriptors to pass -+ * @fds_count: Number of file descriptors to pass -+ * @data: Array of data payloads -+ * @vec_count: Number of VEC entries -+ * @memfd_count: Number of MEMFD entries in @data -+ * @data_count: Sum of @vec_count + @memfd_count -+ */ -+struct kdbus_msg_resources { -+ struct kref kref; -+ const char *dst_name; -+ -+ struct file **fds; -+ unsigned int fds_count; -+ -+ struct kdbus_msg_data *data; -+ size_t vec_count; -+ size_t memfd_count; -+ size_t data_count; -+}; -+ -+struct kdbus_msg_resources * -+kdbus_msg_resources_ref(struct kdbus_msg_resources *r); -+struct kdbus_msg_resources * -+kdbus_msg_resources_unref(struct kdbus_msg_resources *r); -+ -+/** -+ * struct kdbus_kmsg - internal message handling data -+ * @seq: Domain-global message sequence number -+ * @notify_type: Short-cut for faster lookup -+ * @notify_old_id: Short-cut for faster lookup -+ * @notify_new_id: Short-cut for faster lookup -+ * @notify_name: Short-cut for faster lookup -+ * @dst_name_id: Short-cut to msg for faster lookup -+ * @bloom_filter: Bloom filter to match message properties -+ * @bloom_generation: Generation of bloom element set -+ * @notify_entry: List of kernel-generated notifications -+ * @iov: Array of iovec, describing the payload to copy -+ * @iov_count: Number of array members in @iov -+ * @pool_size: Overall size of inlined data referenced by @iov -+ * @proc_meta: Appended SCM-like metadata of the sending process -+ * @conn_meta: Appended SCM-like metadata of the sending connection -+ * @res: Message resources -+ * @msg: Message from or to userspace -+ */ -+struct kdbus_kmsg { -+ u64 seq; -+ u64 notify_type; -+ u64 notify_old_id; -+ u64 notify_new_id; -+ const char *notify_name; -+ -+ u64 dst_name_id; -+ const struct kdbus_bloom_filter *bloom_filter; -+ u64 bloom_generation; -+ struct list_head notify_entry; -+ -+ struct iovec *iov; -+ size_t iov_count; -+ u64 pool_size; -+ -+ struct kdbus_meta_proc *proc_meta; -+ struct kdbus_meta_conn *conn_meta; -+ struct kdbus_msg_resources *res; -+ -+ /* variable size, must be the last member */ -+ struct kdbus_msg msg; -+}; -+ -+struct kdbus_bus; -+struct kdbus_conn; -+ -+struct kdbus_kmsg *kdbus_kmsg_new(struct kdbus_bus *bus, size_t extra_size); -+struct kdbus_kmsg *kdbus_kmsg_new_from_cmd(struct kdbus_conn *conn, -+ struct kdbus_cmd_send *cmd_send); -+void kdbus_kmsg_free(struct kdbus_kmsg *kmsg); -+ -+#endif -diff --git a/ipc/kdbus/queue.c b/ipc/kdbus/queue.c -new file mode 100644 -index 000000000000..a449464a3975 ---- /dev/null -+++ b/ipc/kdbus/queue.c -@@ -0,0 +1,678 @@ -+/* -+ * Copyright (C) 2013-2015 Kay Sievers -+ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> -+ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> -+ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> -+ * Copyright (C) 2013-2015 Linux Foundation -+ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> -+ * -+ * 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/sizes.h> -+#include <linux/slab.h> -+#include <linux/syscalls.h> -+#include <linux/uio.h> -+ -+#include "util.h" -+#include "domain.h" -+#include "connection.h" -+#include "item.h" -+#include "message.h" -+#include "metadata.h" -+#include "queue.h" -+#include "reply.h" -+ -+/** -+ * kdbus_queue_init() - initialize data structure related to a queue -+ * @queue: The queue to initialize -+ */ -+void kdbus_queue_init(struct kdbus_queue *queue) -+{ -+ INIT_LIST_HEAD(&queue->msg_list); -+ queue->msg_prio_queue = RB_ROOT; -+} -+ -+/** -+ * kdbus_queue_peek() - Retrieves an entry from a queue -+ * @queue: The queue -+ * @priority: The minimum priority of the entry to peek -+ * @use_priority: Boolean flag whether or not to peek by priority -+ * -+ * Look for a entry in a queue, either by priority, or the oldest one (FIFO). -+ * The entry is not freed, put off the queue's lists or anything else. -+ * -+ * Return: the peeked queue entry on success, NULL if no suitable msg is found -+ */ -+struct kdbus_queue_entry *kdbus_queue_peek(struct kdbus_queue *queue, -+ s64 priority, bool use_priority) -+{ -+ struct kdbus_queue_entry *e; -+ -+ if (list_empty(&queue->msg_list)) -+ return NULL; -+ -+ if (use_priority) { -+ /* get next entry with highest priority */ -+ e = rb_entry(queue->msg_prio_highest, -+ struct kdbus_queue_entry, prio_node); -+ -+ /* no entry with the requested priority */ -+ if (e->priority > priority) -+ return NULL; -+ } else { -+ /* ignore the priority, return the next entry in the entry */ -+ e = list_first_entry(&queue->msg_list, -+ struct kdbus_queue_entry, entry); -+ } -+ -+ return e; -+} -+ -+static void kdbus_queue_entry_link(struct kdbus_queue_entry *entry) -+{ -+ struct kdbus_queue *queue = &entry->conn->queue; -+ struct rb_node **n, *pn = NULL; -+ bool highest = true; -+ -+ lockdep_assert_held(&entry->conn->lock); -+ if (WARN_ON(!list_empty(&entry->entry))) -+ return; -+ -+ /* sort into priority entry tree */ -+ n = &queue->msg_prio_queue.rb_node; -+ while (*n) { -+ struct kdbus_queue_entry *e; -+ -+ pn = *n; -+ e = rb_entry(pn, struct kdbus_queue_entry, prio_node); -+ -+ /* existing node for this priority, add to its list */ -+ if (likely(entry->priority == e->priority)) { -+ list_add_tail(&entry->prio_entry, &e->prio_entry); -+ goto prio_done; -+ } -+ -+ if (entry->priority < e->priority) { -+ n = &pn->rb_left; -+ } else { -+ n = &pn->rb_right; -+ highest = false; -+ } -+ } -+ -+ /* cache highest-priority entry */ -+ if (highest) -+ queue->msg_prio_highest = &entry->prio_node; -+ -+ /* new node for this priority */ -+ rb_link_node(&entry->prio_node, pn, n); -+ rb_insert_color(&entry->prio_node, &queue->msg_prio_queue); -+ INIT_LIST_HEAD(&entry->prio_entry); -+ -+prio_done: -+ /* add to unsorted fifo list */ -+ list_add_tail(&entry->entry, &queue->msg_list); -+} -+ -+static void kdbus_queue_entry_unlink(struct kdbus_queue_entry *entry) -+{ -+ struct kdbus_queue *queue = &entry->conn->queue; -+ -+ lockdep_assert_held(&entry->conn->lock); -+ if (list_empty(&entry->entry)) -+ return; -+ -+ list_del_init(&entry->entry); -+ -+ if (list_empty(&entry->prio_entry)) { -+ /* -+ * Single entry for this priority, update cached -+ * highest-priority entry, remove the tree node. -+ */ -+ if (queue->msg_prio_highest == &entry->prio_node) -+ queue->msg_prio_highest = rb_next(&entry->prio_node); -+ -+ rb_erase(&entry->prio_node, &queue->msg_prio_queue); -+ } else { -+ struct kdbus_queue_entry *q; -+ -+ /* -+ * Multiple entries for this priority entry, get next one in -+ * the list. Update cached highest-priority entry, store the -+ * new one as the tree node. -+ */ -+ q = list_first_entry(&entry->prio_entry, -+ struct kdbus_queue_entry, prio_entry); -+ list_del(&entry->prio_entry); -+ -+ if (queue->msg_prio_highest == &entry->prio_node) -+ queue->msg_prio_highest = &q->prio_node; -+ -+ rb_replace_node(&entry->prio_node, &q->prio_node, -+ &queue->msg_prio_queue); -+ } -+} -+ -+/** -+ * kdbus_queue_entry_new() - allocate a queue entry -+ * @conn_dst: destination connection -+ * @kmsg: kmsg object the queue entry should track -+ * @user: user to account message on (or NULL for kernel messages) -+ * -+ * Allocates a queue entry based on a given kmsg and allocate space for -+ * the message payload and the requested metadata in the connection's pool. -+ * The entry is not actually added to the queue's lists at this point. -+ * -+ * Return: the allocated entry on success, or an ERR_PTR on failures. -+ */ -+struct kdbus_queue_entry *kdbus_queue_entry_new(struct kdbus_conn *conn_dst, -+ const struct kdbus_kmsg *kmsg, -+ struct kdbus_user *user) -+{ -+ struct kdbus_msg_resources *res = kmsg->res; -+ const struct kdbus_msg *msg = &kmsg->msg; -+ struct kdbus_queue_entry *entry; -+ size_t memfd_cnt = 0; -+ struct kvec kvec[2]; -+ size_t meta_size; -+ size_t msg_size; -+ u64 payload_off; -+ u64 size = 0; -+ int ret = 0; -+ -+ entry = kzalloc(sizeof(*entry), GFP_KERNEL); -+ if (!entry) -+ return ERR_PTR(-ENOMEM); -+ -+ INIT_LIST_HEAD(&entry->entry); -+ entry->priority = msg->priority; -+ entry->dst_name_id = kmsg->dst_name_id; -+ entry->msg_res = kdbus_msg_resources_ref(res); -+ entry->proc_meta = kdbus_meta_proc_ref(kmsg->proc_meta); -+ entry->conn_meta = kdbus_meta_conn_ref(kmsg->conn_meta); -+ entry->conn = kdbus_conn_ref(conn_dst); -+ -+ if (kmsg->msg.src_id == KDBUS_SRC_ID_KERNEL) -+ msg_size = msg->size; -+ else -+ msg_size = offsetof(struct kdbus_msg, items); -+ -+ /* sum up the size of the needed slice */ -+ size = msg_size; -+ -+ if (res) { -+ size += res->vec_count * -+ KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec)); -+ -+ if (res->memfd_count) { -+ entry->memfd_offset = -+ kcalloc(res->memfd_count, sizeof(size_t), -+ GFP_KERNEL); -+ if (!entry->memfd_offset) { -+ ret = -ENOMEM; -+ goto exit_free_entry; -+ } -+ -+ size += res->memfd_count * -+ KDBUS_ITEM_SIZE(sizeof(struct kdbus_memfd)); -+ } -+ -+ if (res->fds_count) -+ size += KDBUS_ITEM_SIZE(sizeof(int) * res->fds_count); -+ -+ if (res->dst_name) -+ size += KDBUS_ITEM_SIZE(strlen(res->dst_name) + 1); -+ } -+ -+ /* -+ * Remember the offset of the metadata part, so we can override -+ * this part later during kdbus_queue_entry_install(). -+ */ -+ entry->meta_offset = size; -+ -+ if (entry->proc_meta || entry->conn_meta) { -+ entry->attach_flags = -+ atomic64_read(&conn_dst->attach_flags_recv); -+ -+ ret = kdbus_meta_export_prepare(entry->proc_meta, -+ entry->conn_meta, -+ &entry->attach_flags, -+ &meta_size); -+ if (ret < 0) -+ goto exit_free_entry; -+ -+ size += meta_size; -+ } -+ -+ payload_off = size; -+ size += kmsg->pool_size; -+ size = KDBUS_ALIGN8(size); -+ -+ ret = kdbus_conn_quota_inc(conn_dst, user, size, -+ res ? res->fds_count : 0); -+ if (ret < 0) -+ goto exit_free_entry; -+ -+ entry->slice = kdbus_pool_slice_alloc(conn_dst->pool, size, true); -+ if (IS_ERR(entry->slice)) { -+ ret = PTR_ERR(entry->slice); -+ entry->slice = NULL; -+ kdbus_conn_quota_dec(conn_dst, user, size, -+ res ? res->fds_count : 0); -+ goto exit_free_entry; -+ } -+ -+ /* we accounted for exactly 'size' bytes, make sure it didn't grow */ -+ WARN_ON(kdbus_pool_slice_size(entry->slice) != size); -+ entry->user = kdbus_user_ref(user); -+ -+ /* copy message header */ -+ kvec[0].iov_base = (char *)msg; -+ kvec[0].iov_len = msg_size; -+ -+ ret = kdbus_pool_slice_copy_kvec(entry->slice, 0, kvec, 1, msg_size); -+ if (ret < 0) -+ goto exit_free_entry; -+ -+ /* 'size' will now track the write position */ -+ size = msg_size; -+ -+ /* create message payload items */ -+ if (res) { -+ size_t dst_name_len = 0; -+ unsigned int i; -+ size_t sz = 0; -+ -+ if (res->dst_name) { -+ dst_name_len = strlen(res->dst_name) + 1; -+ sz += KDBUS_ITEM_SIZE(dst_name_len); -+ } -+ -+ for (i = 0; i < res->data_count; ++i) { -+ struct kdbus_vec v; -+ struct kdbus_memfd m; -+ -+ switch (res->data[i].type) { -+ case KDBUS_MSG_DATA_VEC: -+ sz += KDBUS_ITEM_SIZE(sizeof(v)); -+ break; -+ -+ case KDBUS_MSG_DATA_MEMFD: -+ sz += KDBUS_ITEM_SIZE(sizeof(m)); -+ break; -+ } -+ } -+ -+ if (sz) { -+ struct kdbus_item *items, *item; -+ -+ items = kmalloc(sz, GFP_KERNEL); -+ if (!items) { -+ ret = -ENOMEM; -+ goto exit_free_entry; -+ } -+ -+ item = items; -+ -+ if (res->dst_name) -+ item = kdbus_item_set(item, KDBUS_ITEM_DST_NAME, -+ res->dst_name, -+ dst_name_len); -+ -+ for (i = 0; i < res->data_count; ++i) { -+ struct kdbus_msg_data *d = res->data + i; -+ struct kdbus_memfd m = {}; -+ struct kdbus_vec v = {}; -+ -+ switch (d->type) { -+ case KDBUS_MSG_DATA_VEC: -+ v.size = d->size; -+ v.offset = d->vec.off; -+ if (v.offset != ~0ULL) -+ v.offset += payload_off; -+ -+ item = kdbus_item_set(item, -+ KDBUS_ITEM_PAYLOAD_OFF, -+ &v, sizeof(v)); -+ break; -+ -+ case KDBUS_MSG_DATA_MEMFD: -+ /* -+ * Remember the location of memfds, so -+ * we can override the content from -+ * kdbus_queue_entry_install(). -+ */ -+ entry->memfd_offset[memfd_cnt++] = -+ msg_size + -+ (char *)item - (char *)items + -+ offsetof(struct kdbus_item, -+ memfd); -+ -+ item = kdbus_item_set(item, -+ KDBUS_ITEM_PAYLOAD_MEMFD, -+ &m, sizeof(m)); -+ break; -+ } -+ } -+ -+ kvec[0].iov_base = items; -+ kvec[0].iov_len = sz; -+ -+ ret = kdbus_pool_slice_copy_kvec(entry->slice, size, -+ kvec, 1, sz); -+ kfree(items); -+ -+ if (ret < 0) -+ goto exit_free_entry; -+ -+ size += sz; -+ } -+ -+ /* -+ * Remember the location of the FD part, so we can override the -+ * content in kdbus_queue_entry_install(). -+ */ -+ if (res->fds_count) { -+ entry->fds_offset = size; -+ size += KDBUS_ITEM_SIZE(sizeof(int) * res->fds_count); -+ } -+ } -+ -+ /* finally, copy over the actual message payload */ -+ if (kmsg->iov_count) { -+ ret = kdbus_pool_slice_copy_iovec(entry->slice, payload_off, -+ kmsg->iov, -+ kmsg->iov_count, -+ kmsg->pool_size); -+ if (ret < 0) -+ goto exit_free_entry; -+ } -+ -+ return entry; -+ -+exit_free_entry: -+ kdbus_queue_entry_free(entry); -+ return ERR_PTR(ret); -+} -+ -+/** -+ * kdbus_queue_entry_free() - free resources of an entry -+ * @entry: The entry to free -+ * -+ * Removes resources allocated by a queue entry, along with the entry itself. -+ * Note that the entry's slice is not freed at this point. -+ */ -+void kdbus_queue_entry_free(struct kdbus_queue_entry *entry) -+{ -+ if (!entry) -+ return; -+ -+ lockdep_assert_held(&entry->conn->lock); -+ -+ kdbus_queue_entry_unlink(entry); -+ kdbus_reply_unref(entry->reply); -+ -+ if (entry->slice) { -+ kdbus_conn_quota_dec(entry->conn, entry->user, -+ kdbus_pool_slice_size(entry->slice), -+ entry->msg_res ? -+ entry->msg_res->fds_count : 0); -+ kdbus_pool_slice_release(entry->slice); -+ kdbus_user_unref(entry->user); -+ } -+ -+ kdbus_msg_resources_unref(entry->msg_res); -+ kdbus_meta_conn_unref(entry->conn_meta); -+ kdbus_meta_proc_unref(entry->proc_meta); -+ kdbus_conn_unref(entry->conn); -+ kfree(entry->memfd_offset); -+ kfree(entry); -+} -+ -+/** -+ * kdbus_queue_entry_install() - install message components into the -+ * receiver's process -+ * @entry: The queue entry to install -+ * @return_flags: Pointer to store the return flags for userspace -+ * @install_fds: Whether or not to install associated file descriptors -+ * -+ * This function will create a slice to transport the message header, the -+ * metadata items and other items for information stored in @entry, and -+ * store it as entry->slice. -+ * -+ * If @install_fds is %true, file descriptors will as well be installed. -+ * This function must always be called from the task context of the receiver. -+ * -+ * Return: 0 on success. -+ */ -+int kdbus_queue_entry_install(struct kdbus_queue_entry *entry, -+ u64 *return_flags, bool install_fds) -+{ -+ u64 msg_size = entry->meta_offset; -+ struct kdbus_conn *conn_dst = entry->conn; -+ struct kdbus_msg_resources *res; -+ bool incomplete_fds = false; -+ struct kvec kvec[2]; -+ size_t memfds = 0; -+ int i, ret; -+ -+ lockdep_assert_held(&conn_dst->lock); -+ -+ if (entry->proc_meta || entry->conn_meta) { -+ size_t meta_size; -+ -+ ret = kdbus_meta_export(entry->proc_meta, -+ entry->conn_meta, -+ entry->attach_flags, -+ entry->slice, -+ entry->meta_offset, -+ &meta_size); -+ if (ret < 0) -+ return ret; -+ -+ msg_size += meta_size; -+ } -+ -+ /* Update message size at offset 0 */ -+ kvec[0].iov_base = &msg_size; -+ kvec[0].iov_len = sizeof(msg_size); -+ -+ ret = kdbus_pool_slice_copy_kvec(entry->slice, 0, kvec, 1, -+ sizeof(msg_size)); -+ if (ret < 0) -+ return ret; -+ -+ res = entry->msg_res; -+ -+ if (!res) -+ return 0; -+ -+ if (res->fds_count) { -+ struct kdbus_item_header hdr; -+ size_t off; -+ int *fds; -+ -+ fds = kmalloc_array(res->fds_count, sizeof(int), GFP_KERNEL); -+ if (!fds) -+ return -ENOMEM; -+ -+ for (i = 0; i < res->fds_count; i++) { -+ if (install_fds) { -+ fds[i] = get_unused_fd_flags(O_CLOEXEC); -+ if (fds[i] >= 0) -+ fd_install(fds[i], -+ get_file(res->fds[i])); -+ else -+ incomplete_fds = true; -+ } else { -+ fds[i] = -1; -+ } -+ } -+ -+ off = entry->fds_offset; -+ -+ hdr.type = KDBUS_ITEM_FDS; -+ hdr.size = KDBUS_ITEM_HEADER_SIZE + -+ sizeof(int) * res->fds_count; -+ -+ kvec[0].iov_base = &hdr; -+ kvec[0].iov_len = sizeof(hdr); -+ -+ kvec[1].iov_base = fds; -+ kvec[1].iov_len = sizeof(int) * res->fds_count; -+ -+ ret = kdbus_pool_slice_copy_kvec(entry->slice, off, -+ kvec, 2, hdr.size); -+ kfree(fds); -+ -+ if (ret < 0) -+ return ret; -+ } -+ -+ for (i = 0; i < res->data_count; ++i) { -+ struct kdbus_msg_data *d = res->data + i; -+ struct kdbus_memfd m; -+ -+ if (d->type != KDBUS_MSG_DATA_MEMFD) -+ continue; -+ -+ m.start = d->memfd.start; -+ m.size = d->size; -+ m.fd = -1; -+ -+ if (install_fds) { -+ m.fd = get_unused_fd_flags(O_CLOEXEC); -+ if (m.fd < 0) { -+ m.fd = -1; -+ incomplete_fds = true; -+ } else { -+ fd_install(m.fd, -+ get_file(d->memfd.file)); -+ } -+ } -+ -+ kvec[0].iov_base = &m; -+ kvec[0].iov_len = sizeof(m); -+ -+ ret = kdbus_pool_slice_copy_kvec(entry->slice, -+ entry->memfd_offset[memfds++], -+ kvec, 1, sizeof(m)); -+ if (ret < 0) -+ return ret; -+ } -+ -+ if (incomplete_fds) -+ *return_flags |= KDBUS_RECV_RETURN_INCOMPLETE_FDS; -+ -+ return 0; -+} -+ -+/** -+ * kdbus_queue_entry_enqueue() - enqueue an entry -+ * @entry: entry to enqueue -+ * @reply: reply to link to this entry (or NULL if none) -+ * -+ * This enqueues an unqueued entry into the message queue of the linked -+ * connection. It also binds a reply object to the entry so we can remember it -+ * when the message is moved. -+ * -+ * Once this call returns (and the connection lock is released), this entry can -+ * be dequeued by the target connection. Note that the entry will not be removed -+ * from the queue until it is destroyed. -+ */ -+void kdbus_queue_entry_enqueue(struct kdbus_queue_entry *entry, -+ struct kdbus_reply *reply) -+{ -+ lockdep_assert_held(&entry->conn->lock); -+ -+ if (WARN_ON(entry->reply) || WARN_ON(!list_empty(&entry->entry))) -+ return; -+ -+ entry->reply = kdbus_reply_ref(reply); -+ kdbus_queue_entry_link(entry); -+} -+ -+/** -+ * kdbus_queue_entry_move() - move queue entry -+ * @e: queue entry to move -+ * @dst: destination connection to queue the entry on -+ * -+ * This moves a queue entry onto a different connection. It allocates a new -+ * slice on the target connection and copies the message over. If the copy -+ * succeeded, we move the entry from @src to @dst. -+ * -+ * On failure, the entry is left untouched. -+ * -+ * The queue entry must be queued right now, and after the call succeeds it will -+ * be queued on the destination, but no longer on the source. -+ * -+ * The caller must hold the connection lock of the source *and* destination. -+ * -+ * Return: 0 on success, negative error code on failure. -+ */ -+int kdbus_queue_entry_move(struct kdbus_queue_entry *e, -+ struct kdbus_conn *dst) -+{ -+ struct kdbus_pool_slice *slice = NULL; -+ struct kdbus_conn *src = e->conn; -+ size_t size, fds; -+ int ret; -+ -+ lockdep_assert_held(&src->lock); -+ lockdep_assert_held(&dst->lock); -+ -+ if (WARN_ON(IS_ERR(e->user)) || WARN_ON(list_empty(&e->entry))) -+ return -EINVAL; -+ if (src == dst) -+ return 0; -+ -+ size = kdbus_pool_slice_size(e->slice); -+ fds = e->msg_res ? e->msg_res->fds_count : 0; -+ -+ ret = kdbus_conn_quota_inc(dst, e->user, size, fds); -+ if (ret < 0) -+ return ret; -+ -+ slice = kdbus_pool_slice_alloc(dst->pool, size, true); -+ if (IS_ERR(slice)) { -+ ret = PTR_ERR(slice); -+ slice = NULL; -+ goto error; -+ } -+ -+ ret = kdbus_pool_slice_copy(slice, e->slice); -+ if (ret < 0) -+ goto error; -+ -+ kdbus_queue_entry_unlink(e); -+ kdbus_conn_quota_dec(src, e->user, size, fds); -+ kdbus_pool_slice_release(e->slice); -+ kdbus_conn_unref(e->conn); -+ -+ e->slice = slice; -+ e->conn = kdbus_conn_ref(dst); -+ kdbus_queue_entry_link(e); -+ -+ return 0; -+ -+error: -+ kdbus_pool_slice_release(slice); -+ kdbus_conn_quota_dec(dst, e->user, size, fds); -+ return ret; -+} -diff --git a/ipc/kdbus/queue.h b/ipc/kdbus/queue.h -new file mode 100644 -index 000000000000..7f2db96fe308 ---- /dev/null -+++ b/ipc/kdbus/queue.h -@@ -0,0 +1,92 @@ -+/* -+ * Copyright (C) 2013-2015 Kay Sievers -+ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> -+ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> -+ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> -+ * Copyright (C) 2013-2015 Linux Foundation -+ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> -+ * -+ * 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_QUEUE_H -+#define __KDBUS_QUEUE_H -+ -+struct kdbus_user; -+ -+/** -+ * struct kdbus_queue - a connection's message queue -+ * @msg_list: List head for kdbus_queue_entry objects -+ * @msg_prio_queue: RB tree root for messages, sorted by priority -+ * @msg_prio_highest: Link to the RB node referencing the message with the -+ * highest priority in the tree. -+ */ -+struct kdbus_queue { -+ struct list_head msg_list; -+ struct rb_root msg_prio_queue; -+ struct rb_node *msg_prio_highest; -+}; -+ -+/** -+ * struct kdbus_queue_entry - messages waiting to be read -+ * @entry: Entry in the connection's list -+ * @prio_node: Entry in the priority queue tree -+ * @prio_entry: Queue tree node entry in the list of one priority -+ * @slice: Slice in the receiver's pool for the message -+ * @attach_flags: Attach flags used during slice allocation -+ * @meta_offset: Offset of first metadata item in slice -+ * @fds_offset: Offset of FD item in slice -+ * @memfd_offset: Array of slice-offsets for all memfd items -+ * @priority: Message priority -+ * @dst_name_id: The sequence number of the name this message is -+ * addressed to, 0 for messages sent to an ID -+ * @msg_res: Message resources -+ * @proc_meta: Process metadata, captured at message arrival -+ * @conn_meta: Connection metadata, captured at message arrival -+ * @reply: The reply block if a reply to this message is expected -+ * @user: User used for accounting -+ */ -+struct kdbus_queue_entry { -+ struct list_head entry; -+ struct rb_node prio_node; -+ struct list_head prio_entry; -+ -+ struct kdbus_pool_slice *slice; -+ -+ u64 attach_flags; -+ size_t meta_offset; -+ size_t fds_offset; -+ size_t *memfd_offset; -+ -+ s64 priority; -+ u64 dst_name_id; -+ -+ struct kdbus_msg_resources *msg_res; -+ struct kdbus_meta_proc *proc_meta; -+ struct kdbus_meta_conn *conn_meta; -+ struct kdbus_reply *reply; -+ struct kdbus_conn *conn; -+ struct kdbus_user *user; -+}; -+ -+struct kdbus_kmsg; -+ -+void kdbus_queue_init(struct kdbus_queue *queue); -+struct kdbus_queue_entry *kdbus_queue_peek(struct kdbus_queue *queue, -+ s64 priority, bool use_priority); -+ -+struct kdbus_queue_entry *kdbus_queue_entry_new(struct kdbus_conn *conn_dst, -+ const struct kdbus_kmsg *kmsg, -+ struct kdbus_user *user); -+void kdbus_queue_entry_free(struct kdbus_queue_entry *entry); -+int kdbus_queue_entry_install(struct kdbus_queue_entry *entry, -+ u64 *return_flags, bool install_fds); -+void kdbus_queue_entry_enqueue(struct kdbus_queue_entry *entry, -+ struct kdbus_reply *reply); -+int kdbus_queue_entry_move(struct kdbus_queue_entry *entry, -+ struct kdbus_conn *dst); -+ -+#endif /* __KDBUS_QUEUE_H */ -diff --git a/ipc/kdbus/reply.c b/ipc/kdbus/reply.c -new file mode 100644 -index 000000000000..6b3bd81bbb4d ---- /dev/null -+++ b/ipc/kdbus/reply.c -@@ -0,0 +1,259 @@ -+#include <linux/init.h> -+#include <linux/mm.h> -+#include <linux/module.h> -+#include <linux/mutex.h> -+#include <linux/slab.h> -+#include <linux/uio.h> -+ -+#include "bus.h" -+#include "connection.h" -+#include "endpoint.h" -+#include "message.h" -+#include "metadata.h" -+#include "names.h" -+#include "domain.h" -+#include "item.h" -+#include "notify.h" -+#include "policy.h" -+#include "reply.h" -+#include "util.h" -+ -+/** -+ * kdbus_reply_new() - Allocate and set up a new kdbus_reply object -+ * @reply_src: The connection a reply is expected from -+ * @reply_dst: The connection this reply object belongs to -+ * @msg: Message associated with the reply -+ * @name_entry: Name entry used to send the message -+ * @sync: Whether or not to make this reply synchronous -+ * -+ * Allocate and fill a new kdbus_reply object. -+ * -+ * Return: New kdbus_conn object on success, ERR_PTR on error. -+ */ -+struct kdbus_reply *kdbus_reply_new(struct kdbus_conn *reply_src, -+ struct kdbus_conn *reply_dst, -+ const struct kdbus_msg *msg, -+ struct kdbus_name_entry *name_entry, -+ bool sync) -+{ -+ struct kdbus_reply *r; -+ int ret = 0; -+ -+ if (atomic_inc_return(&reply_dst->request_count) > -+ KDBUS_CONN_MAX_REQUESTS_PENDING) { -+ ret = -EMLINK; -+ goto exit_dec_request_count; -+ } -+ -+ r = kzalloc(sizeof(*r), GFP_KERNEL); -+ if (!r) { -+ ret = -ENOMEM; -+ goto exit_dec_request_count; -+ } -+ -+ kref_init(&r->kref); -+ INIT_LIST_HEAD(&r->entry); -+ r->reply_src = kdbus_conn_ref(reply_src); -+ 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_request_count: -+ if (ret < 0) { -+ atomic_dec(&reply_dst->request_count); -+ return ERR_PTR(ret); -+ } -+ -+ return r; -+} -+ -+static void __kdbus_reply_free(struct kref *kref) -+{ -+ struct kdbus_reply *reply = -+ container_of(kref, struct kdbus_reply, kref); -+ -+ atomic_dec(&reply->reply_dst->request_count); -+ kdbus_conn_unref(reply->reply_src); -+ kdbus_conn_unref(reply->reply_dst); -+ kfree(reply); -+} -+ -+/** -+ * kdbus_reply_ref() - Increase reference on kdbus_reply -+ * @r: The reply, may be %NULL -+ * -+ * Return: The reply object with an extra reference -+ */ -+struct kdbus_reply *kdbus_reply_ref(struct kdbus_reply *r) -+{ -+ if (r) -+ kref_get(&r->kref); -+ return r; -+} -+ -+/** -+ * kdbus_reply_unref() - Decrease reference on kdbus_reply -+ * @r: The reply, may be %NULL -+ * -+ * Return: NULL -+ */ -+struct kdbus_reply *kdbus_reply_unref(struct kdbus_reply *r) -+{ -+ if (r) -+ kref_put(&r->kref, __kdbus_reply_free); -+ return NULL; -+} -+ -+/** -+ * kdbus_reply_link() - Link reply object into target connection -+ * @r: Reply to link -+ */ -+void kdbus_reply_link(struct kdbus_reply *r) -+{ -+ if (WARN_ON(!list_empty(&r->entry))) -+ return; -+ -+ list_add(&r->entry, &r->reply_dst->reply_list); -+ kdbus_reply_ref(r); -+} -+ -+/** -+ * kdbus_reply_unlink() - Unlink reply object from target connection -+ * @r: Reply to unlink -+ */ -+void kdbus_reply_unlink(struct kdbus_reply *r) -+{ -+ if (!list_empty(&r->entry)) { -+ list_del_init(&r->entry); -+ kdbus_reply_unref(r); -+ } -+} -+ -+/** -+ * kdbus_sync_reply_wakeup() - Wake a synchronously blocking reply -+ * @reply: The reply object -+ * @err: Error code to set on the remote side -+ * -+ * Remove the synchronous reply object from its connection reply_list, and -+ * wake up remote peer (method origin) with the appropriate synchronous reply -+ * code. -+ */ -+void kdbus_sync_reply_wakeup(struct kdbus_reply *reply, int err) -+{ -+ if (WARN_ON(!reply->sync)) -+ return; -+ -+ reply->waiting = false; -+ reply->err = err; -+ wake_up_interruptible(&reply->reply_dst->wait); -+} -+ -+/** -+ * kdbus_reply_find() - Find the corresponding reply object -+ * @replying: The replying connection or NULL -+ * @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 -+ * @replying to @reply_dst with the given cookie. -+ * -+ * Callers must take the @reply_dst lock. -+ * -+ * Return: the corresponding reply object or NULL if not found -+ */ -+struct kdbus_reply *kdbus_reply_find(struct kdbus_conn *replying, -+ struct kdbus_conn *reply_dst, -+ u64 cookie) -+{ -+ struct kdbus_reply *r, *reply = NULL; -+ -+ list_for_each_entry(r, &reply_dst->reply_list, entry) { -+ if (r->cookie == cookie && -+ (!replying || r->reply_src == replying)) { -+ reply = r; -+ break; -+ } -+ } -+ -+ return reply; -+} -+ -+/** -+ * kdbus_reply_list_scan_work() - Worker callback to scan the replies of a -+ * connection for exceeded timeouts -+ * @work: Work struct of the connection to scan -+ * -+ * Walk the list of replies stored with a connection and look for entries -+ * that have exceeded their timeout. If such an entry is found, a timeout -+ * notification is sent to the waiting peer, and the reply is removed from -+ * the list. -+ * -+ * The work is rescheduled to the nearest timeout found during the list -+ * iteration. -+ */ -+void kdbus_reply_list_scan_work(struct work_struct *work) -+{ -+ struct kdbus_conn *conn = -+ container_of(work, struct kdbus_conn, work.work); -+ struct kdbus_reply *reply, *reply_tmp; -+ u64 deadline = ~0ULL; -+ struct timespec64 ts; -+ u64 now; -+ -+ 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; -+ -+ WARN_ON(reply->reply_dst != conn); -+ -+ 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, conn->id, -+ reply->cookie); -+ -+ kdbus_reply_unlink(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); -+} -diff --git a/ipc/kdbus/reply.h b/ipc/kdbus/reply.h -new file mode 100644 -index 000000000000..68d52321a917 ---- /dev/null -+++ b/ipc/kdbus/reply.h -@@ -0,0 +1,68 @@ -+/* -+ * Copyright (C) 2013-2015 Kay Sievers -+ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> -+ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> -+ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> -+ * Copyright (C) 2013-2015 Linux Foundation -+ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> -+ * -+ * 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_REPLY_H -+#define __KDBUS_REPLY_H -+ -+/** -+ * struct kdbus_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_src: The connection the reply will be sent from -+ * @reply_dst: The connection the reply will be sent to -+ * @queue_entry: The queue entry 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_reply { -+ struct kref kref; -+ struct list_head entry; -+ struct kdbus_conn *reply_src; -+ 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; -+}; -+ -+struct kdbus_reply *kdbus_reply_new(struct kdbus_conn *reply_src, -+ struct kdbus_conn *reply_dst, -+ const struct kdbus_msg *msg, -+ struct kdbus_name_entry *name_entry, -+ bool sync); -+ -+struct kdbus_reply *kdbus_reply_ref(struct kdbus_reply *r); -+struct kdbus_reply *kdbus_reply_unref(struct kdbus_reply *r); -+ -+void kdbus_reply_link(struct kdbus_reply *r); -+void kdbus_reply_unlink(struct kdbus_reply *r); -+ -+struct kdbus_reply *kdbus_reply_find(struct kdbus_conn *replying, -+ struct kdbus_conn *reply_dst, -+ u64 cookie); -+ -+void kdbus_sync_reply_wakeup(struct kdbus_reply *reply, int err); -+void kdbus_reply_list_scan_work(struct work_struct *work); -+ -+#endif /* __KDBUS_REPLY_H */ -diff --git a/ipc/kdbus/util.h b/ipc/kdbus/util.h -index 9caadb337912..740b19880985 100644 ---- a/ipc/kdbus/util.h -+++ b/ipc/kdbus/util.h -@@ -18,7 +18,7 @@ - #include <linux/dcache.h> - #include <linux/ioctl.h> - --#include "kdbus.h" -+#include <uapi/linux/kdbus.h> - - /* all exported addresses are 64 bit */ - #define KDBUS_PTR(addr) ((void __user *)(uintptr_t)(addr)) --- -2.4.3 - - -From 2038ceb42847a5123f79d9fd0f80c41a15fb02de Mon Sep 17 00:00:00 2001 -From: Daniel Mack <daniel@zonque.org> -Date: Fri, 14 Nov 2014 09:59:08 +0100 -Subject: [PATCH 006/132] kdbus: add node and filesystem implementation - -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. - -Signed-off-by: Daniel Mack <daniel@zonque.org> -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Djalal Harouni <tixxdz@opendz.org> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - include/uapi/linux/magic.h | 2 + - ipc/kdbus/fs.c | 510 +++++++++++++++++++++++++ - ipc/kdbus/fs.h | 28 ++ - ipc/kdbus/node.c | 910 +++++++++++++++++++++++++++++++++++++++++++++ - ipc/kdbus/node.h | 84 +++++ - 5 files changed, 1534 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 - -diff --git a/include/uapi/linux/magic.h b/include/uapi/linux/magic.h -index 7d664ea85ebd..1cf05c066158 100644 ---- a/include/uapi/linux/magic.h -+++ b/include/uapi/linux/magic.h -@@ -74,4 +74,6 @@ - #define BTRFS_TEST_MAGIC 0x73727279 - #define NSFS_MAGIC 0x6e736673 - -+#define KDBUS_SUPER_MAGIC 0x44427573 -+ - #endif /* __LINUX_MAGIC_H__ */ -diff --git a/ipc/kdbus/fs.c b/ipc/kdbus/fs.c -new file mode 100644 -index 000000000000..d01f33baaa0d ---- /dev/null -+++ b/ipc/kdbus/fs.c -@@ -0,0 +1,510 @@ -+/* -+ * Copyright (C) 2013-2015 Kay Sievers -+ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> -+ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> -+ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> -+ * Copyright (C) 2013-2015 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/dcache.h> -+#include <linux/fs.h> -+#include <linux/fsnotify.h> -+#include <linux/init.h> -+#include <linux/ipc_namespace.h> -+#include <linux/magic.h> -+#include <linux/module.h> -+#include <linux/mount.h> -+#include <linux/mutex.h> -+#include <linux/namei.h> -+#include <linux/pagemap.h> -+#include <linux/sched.h> -+#include <linux/slab.h> -+ -+#include "bus.h" -+#include "domain.h" -+#include "endpoint.h" -+#include "fs.h" -+#include "handle.h" -+#include "node.h" -+ -+#define kdbus_node_from_dentry(_dentry) \ -+ ((struct kdbus_node *)(_dentry)->d_fsdata) -+ -+static struct inode *fs_inode_get(struct super_block *sb, -+ struct kdbus_node *node); -+ -+/* -+ * Directory Management -+ */ -+ -+static inline unsigned char kdbus_dt_type(struct kdbus_node *node) -+{ -+ switch (node->type) { -+ case KDBUS_NODE_DOMAIN: -+ case KDBUS_NODE_BUS: -+ return DT_DIR; -+ case KDBUS_NODE_CONTROL: -+ case KDBUS_NODE_ENDPOINT: -+ return DT_REG; -+ } -+ -+ return DT_UNKNOWN; -+} -+ -+static int fs_dir_fop_iterate(struct file *file, struct dir_context *ctx) -+{ -+ struct dentry *dentry = file->f_path.dentry; -+ struct kdbus_node *parent = kdbus_node_from_dentry(dentry); -+ struct kdbus_node *old, *next = file->private_data; -+ -+ /* -+ * kdbusfs directory iterator (modelled after sysfs/kernfs) -+ * When iterating kdbusfs directories, we iterate all children of the -+ * parent kdbus_node object. We use ctx->pos to store the hash of the -+ * child and file->private_data to store a reference to the next node -+ * object. If ctx->pos is not modified via llseek while you iterate a -+ * directory, then we use the file->private_data node pointer to -+ * directly access the next node in the tree. -+ * However, if you directly seek on the directory, we have to find the -+ * closest node to that position and cannot use our node pointer. This -+ * means iterating the rb-tree to find the closest match and start over -+ * from there. -+ * Note that hash values are not neccessarily unique. Therefore, llseek -+ * is not guaranteed to seek to the same node that you got when you -+ * retrieved the position. Seeking to 0, 1, 2 and >=INT_MAX is safe, -+ * though. We could use the inode-number as position, but this would -+ * require another rb-tree for fast access. Kernfs and others already -+ * ignore those conflicts, so we should be fine, too. -+ */ -+ -+ if (!dir_emit_dots(file, ctx)) -+ return 0; -+ -+ /* acquire @next; if deactivated, or seek detected, find next node */ -+ old = next; -+ if (next && ctx->pos == next->hash) { -+ if (kdbus_node_acquire(next)) -+ kdbus_node_ref(next); -+ else -+ next = kdbus_node_next_child(parent, next); -+ } else { -+ next = kdbus_node_find_closest(parent, ctx->pos); -+ } -+ kdbus_node_unref(old); -+ -+ while (next) { -+ /* emit @next */ -+ file->private_data = next; -+ ctx->pos = next->hash; -+ -+ kdbus_node_release(next); -+ -+ if (!dir_emit(ctx, next->name, strlen(next->name), next->id, -+ kdbus_dt_type(next))) -+ return 0; -+ -+ /* find next node after @next */ -+ old = next; -+ next = kdbus_node_next_child(parent, next); -+ kdbus_node_unref(old); -+ } -+ -+ file->private_data = NULL; -+ ctx->pos = INT_MAX; -+ -+ return 0; -+} -+ -+static loff_t fs_dir_fop_llseek(struct file *file, loff_t offset, int whence) -+{ -+ struct inode *inode = file_inode(file); -+ loff_t ret; -+ -+ /* protect f_off against fop_iterate */ -+ mutex_lock(&inode->i_mutex); -+ ret = generic_file_llseek(file, offset, whence); -+ mutex_unlock(&inode->i_mutex); -+ -+ return ret; -+} -+ -+static int fs_dir_fop_release(struct inode *inode, struct file *file) -+{ -+ kdbus_node_unref(file->private_data); -+ return 0; -+} -+ -+static const struct file_operations fs_dir_fops = { -+ .read = generic_read_dir, -+ .iterate = fs_dir_fop_iterate, -+ .llseek = fs_dir_fop_llseek, -+ .release = fs_dir_fop_release, -+}; -+ -+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; -+ -+ /* 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_splice_alias(inode, dentry); -+ -+ kdbus_node_release(node); -+ } -+ -+ kdbus_node_release(parent); -+ return dnew; -+} -+ -+static const struct inode_operations fs_dir_iops = { -+ .permission = generic_permission, -+ .lookup = fs_dir_iop_lookup, -+}; -+ -+/* -+ * Inode Management -+ */ -+ -+static const struct inode_operations fs_inode_iops = { -+ .permission = generic_permission, -+}; -+ -+static struct inode *fs_inode_get(struct super_block *sb, -+ struct kdbus_node *node) -+{ -+ struct inode *inode; -+ -+ inode = iget_locked(sb, node->id); -+ if (!inode) -+ return ERR_PTR(-ENOMEM); -+ if (!(inode->i_state & I_NEW)) -+ return inode; -+ -+ inode->i_private = kdbus_node_ref(node); -+ inode->i_mapping->a_ops = &empty_aops; -+ inode->i_mode = node->mode & S_IALLUGO; -+ inode->i_atime = inode->i_ctime = inode->i_mtime = CURRENT_TIME; -+ inode->i_uid = node->uid; -+ inode->i_gid = node->gid; -+ -+ switch (node->type) { -+ case KDBUS_NODE_DOMAIN: -+ case KDBUS_NODE_BUS: -+ inode->i_mode |= S_IFDIR; -+ inode->i_op = &fs_dir_iops; -+ inode->i_fop = &fs_dir_fops; -+ set_nlink(inode, 2); -+ break; -+ case KDBUS_NODE_CONTROL: -+ case KDBUS_NODE_ENDPOINT: -+ inode->i_mode |= S_IFREG; -+ inode->i_op = &fs_inode_iops; -+ inode->i_fop = &kdbus_handle_ops; -+ break; -+ } -+ -+ unlock_new_inode(inode); -+ -+ return inode; -+} -+ -+/* -+ * Superblock Management -+ */ -+ -+static int fs_super_dop_revalidate(struct dentry *dentry, unsigned int flags) -+{ -+ struct kdbus_node *node; -+ -+ /* Force lookup on negatives */ -+ if (!dentry->d_inode) -+ return 0; -+ -+ node = kdbus_node_from_dentry(dentry); -+ -+ /* see whether the node has been removed */ -+ if (!kdbus_node_is_active(node)) -+ return 0; -+ -+ return 1; -+} -+ -+static void fs_super_dop_release(struct dentry *dentry) -+{ -+ kdbus_node_unref(dentry->d_fsdata); -+} -+ -+static const struct dentry_operations fs_super_dops = { -+ .d_revalidate = fs_super_dop_revalidate, -+ .d_release = fs_super_dop_release, -+}; -+ -+static void fs_super_sop_evict_inode(struct inode *inode) -+{ -+ struct kdbus_node *node = kdbus_node_from_inode(inode); -+ -+ truncate_inode_pages_final(&inode->i_data); -+ clear_inode(inode); -+ kdbus_node_unref(node); -+} -+ -+static const struct super_operations fs_super_sops = { -+ .statfs = simple_statfs, -+ .drop_inode = generic_delete_inode, -+ .evict_inode = fs_super_sop_evict_inode, -+}; -+ -+static int fs_super_fill(struct super_block *sb) -+{ -+ struct kdbus_domain *domain = sb->s_fs_info; -+ struct inode *inode; -+ int ret; -+ -+ sb->s_blocksize = PAGE_CACHE_SIZE; -+ sb->s_blocksize_bits = PAGE_CACHE_SHIFT; -+ sb->s_magic = KDBUS_SUPER_MAGIC; -+ sb->s_maxbytes = MAX_LFS_FILESIZE; -+ sb->s_op = &fs_super_sops; -+ sb->s_time_gran = 1; -+ -+ inode = fs_inode_get(sb, &domain->node); -+ if (IS_ERR(inode)) -+ return PTR_ERR(inode); -+ -+ sb->s_root = d_make_root(inode); -+ if (!sb->s_root) { -+ /* d_make_root iput()s the inode on failure */ -+ return -ENOMEM; -+ } -+ -+ /* sb holds domain reference */ -+ sb->s_root->d_fsdata = &domain->node; -+ sb->s_d_op = &fs_super_dops; -+ -+ /* sb holds root reference */ -+ domain->dentry = sb->s_root; -+ -+ if (!kdbus_node_activate(&domain->node)) -+ return -ESHUTDOWN; -+ -+ ret = kdbus_domain_populate(domain, KDBUS_MAKE_ACCESS_WORLD); -+ if (ret < 0) -+ return ret; -+ -+ sb->s_flags |= MS_ACTIVE; -+ return 0; -+} -+ -+static void fs_super_kill(struct super_block *sb) -+{ -+ struct kdbus_domain *domain = sb->s_fs_info; -+ -+ if (domain) { -+ kdbus_node_deactivate(&domain->node); -+ domain->dentry = NULL; -+ } -+ -+ kill_anon_super(sb); -+ -+ if (domain) -+ kdbus_domain_unref(domain); -+} -+ -+static int fs_super_set(struct super_block *sb, void *data) -+{ -+ int ret; -+ -+ ret = set_anon_super(sb, data); -+ if (!ret) -+ sb->s_fs_info = data; -+ -+ return ret; -+} -+ -+static struct dentry *fs_super_mount(struct file_system_type *fs_type, -+ int flags, const char *dev_name, -+ void *data) -+{ -+ struct kdbus_domain *domain; -+ struct super_block *sb; -+ int ret; -+ -+ domain = kdbus_domain_new(KDBUS_MAKE_ACCESS_WORLD); -+ if (IS_ERR(domain)) -+ return ERR_CAST(domain); -+ -+ sb = sget(fs_type, NULL, fs_super_set, flags, domain); -+ if (IS_ERR(sb)) { -+ kdbus_node_deactivate(&domain->node); -+ kdbus_domain_unref(domain); -+ return ERR_CAST(sb); -+ } -+ -+ WARN_ON(sb->s_fs_info != domain); -+ WARN_ON(sb->s_root); -+ -+ ret = fs_super_fill(sb); -+ if (ret < 0) { -+ /* calls into ->kill_sb() when done */ -+ deactivate_locked_super(sb); -+ return ERR_PTR(ret); -+ } -+ -+ return dget(sb->s_root); -+} -+ -+static struct file_system_type fs_type = { -+ .name = KBUILD_MODNAME "fs", -+ .owner = THIS_MODULE, -+ .mount = fs_super_mount, -+ .kill_sb = fs_super_kill, -+ .fs_flags = FS_USERNS_MOUNT, -+}; -+ -+/** -+ * kdbus_fs_init() - register kdbus filesystem -+ * -+ * This registers a filesystem with the VFS layer. The filesystem is called -+ * `KBUILD_MODNAME "fs"', which usually resolves to `kdbusfs'. The nameing -+ * scheme allows to set KBUILD_MODNAME to "kdbus2" and you will get an -+ * independent filesystem for developers. -+ * -+ * Each mount of the kdbusfs filesystem has an kdbus_domain attached. -+ * Operations on this mount will only affect the attached domain. On each mount -+ * a new domain is automatically created and used for this mount exclusively. -+ * If you want to share a domain across multiple mounts, you need to bind-mount -+ * it. -+ * -+ * Mounts of kdbusfs (with a different domain each) are unrelated to each other -+ * and will never have any effect on any domain but their own. -+ * -+ * Return: 0 on success, negative error otherwise. -+ */ -+int kdbus_fs_init(void) -+{ -+ return register_filesystem(&fs_type); -+} -+ -+/** -+ * kdbus_fs_exit() - unregister kdbus filesystem -+ * -+ * This does the reverse to kdbus_fs_init(). It unregisters the kdbusfs -+ * filesystem from VFS and cleans up any allocated resources. -+ */ -+void kdbus_fs_exit(void) -+{ -+ unregister_filesystem(&fs_type); -+} -+ -+/* acquire domain of @node, making sure all ancestors are active */ -+static struct kdbus_domain *fs_acquire_domain(struct kdbus_node *node) -+{ -+ struct kdbus_domain *domain; -+ struct kdbus_node *iter; -+ -+ /* caller must guarantee that @node is linked */ -+ for (iter = node; iter->parent; iter = iter->parent) -+ if (!kdbus_node_is_active(iter->parent)) -+ return NULL; -+ -+ /* root nodes are always domains */ -+ if (WARN_ON(iter->type != KDBUS_NODE_DOMAIN)) -+ return NULL; -+ -+ domain = kdbus_domain_from_node(iter); -+ if (!kdbus_node_acquire(&domain->node)) -+ return NULL; -+ -+ return domain; -+} -+ -+/** -+ * kdbus_fs_flush() - flush dcache entries of a node -+ * @node: Node to flush entries of -+ * -+ * This flushes all VFS filesystem cache entries for a node and all its -+ * children. This should be called whenever a node is destroyed during -+ * runtime. It will flush the cache entries so the linked objects can be -+ * deallocated. -+ * -+ * This is a no-op if you call it on active nodes (they really should stay in -+ * cache) or on nodes with deactivated parents (flushing the parent is enough). -+ * Furthermore, there is no need to call it on nodes whose lifetime is bound to -+ * their parents'. In those cases, the parent-flush will always also flush the -+ * children. -+ */ -+void kdbus_fs_flush(struct kdbus_node *node) -+{ -+ struct dentry *dentry, *parent_dentry = NULL; -+ struct kdbus_domain *domain; -+ struct qstr name; -+ -+ /* active nodes should remain in cache */ -+ if (!kdbus_node_is_deactivated(node)) -+ return; -+ -+ /* nodes that were never linked were never instantiated */ -+ if (!node->parent) -+ return; -+ -+ /* acquire domain and verify all ancestors are active */ -+ domain = fs_acquire_domain(node); -+ if (!domain) -+ return; -+ -+ switch (node->type) { -+ case KDBUS_NODE_ENDPOINT: -+ if (WARN_ON(!node->parent || !node->parent->name)) -+ goto exit; -+ -+ name.name = node->parent->name; -+ name.len = strlen(node->parent->name); -+ parent_dentry = d_hash_and_lookup(domain->dentry, &name); -+ if (IS_ERR_OR_NULL(parent_dentry)) -+ goto exit; -+ -+ /* fallthrough */ -+ case KDBUS_NODE_BUS: -+ if (WARN_ON(!node->name)) -+ goto exit; -+ -+ name.name = node->name; -+ name.len = strlen(node->name); -+ dentry = d_hash_and_lookup(parent_dentry ? : domain->dentry, -+ &name); -+ if (!IS_ERR_OR_NULL(dentry)) { -+ d_invalidate(dentry); -+ dput(dentry); -+ } -+ -+ dput(parent_dentry); -+ break; -+ -+ default: -+ /* all other types are bound to their parent lifetime */ -+ break; -+ } -+ -+exit: -+ kdbus_node_release(&domain->node); -+} -diff --git a/ipc/kdbus/fs.h b/ipc/kdbus/fs.h -new file mode 100644 -index 000000000000..62f7d6abf11e ---- /dev/null -+++ b/ipc/kdbus/fs.h -@@ -0,0 +1,28 @@ -+/* -+ * Copyright (C) 2013-2015 Kay Sievers -+ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> -+ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> -+ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> -+ * Copyright (C) 2013-2015 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> -+ -+struct kdbus_node; -+ -+int kdbus_fs_init(void); -+void kdbus_fs_exit(void); -+void kdbus_fs_flush(struct kdbus_node *node); -+ -+#define kdbus_node_from_inode(_inode) \ -+ ((struct kdbus_node *)(_inode)->i_private) -+ -+#endif -diff --git a/ipc/kdbus/node.c b/ipc/kdbus/node.c -new file mode 100644 -index 000000000000..520df00e676a ---- /dev/null -+++ b/ipc/kdbus/node.c -@@ -0,0 +1,910 @@ -+/* -+ * Copyright (C) 2013-2015 Kay Sievers -+ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> -+ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> -+ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> -+ * Copyright (C) 2013-2015 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/atomic.h> -+#include <linux/fs.h> -+#include <linux/idr.h> -+#include <linux/kdev_t.h> -+#include <linux/rbtree.h> -+#include <linux/rwsem.h> -+#include <linux/sched.h> -+#include <linux/slab.h> -+#include <linux/wait.h> -+ -+#include "bus.h" -+#include "domain.h" -+#include "endpoint.h" -+#include "fs.h" -+#include "handle.h" -+#include "node.h" -+#include "util.h" -+ -+/** -+ * DOC: kdbus nodes -+ * -+ * Nodes unify lifetime management across exposed kdbus objects and provide a -+ * hierarchy. Each kdbus object, that might be exposed to user-space, has a -+ * kdbus_node object embedded and is linked into the hierarchy. Each node can -+ * have any number (0-n) of child nodes linked. Each child retains a reference -+ * to its parent node. For root-nodes, the parent is NULL. -+ * -+ * Each node object goes through a bunch of states during it's lifetime: -+ * * NEW -+ * * LINKED (can be skipped by NEW->FREED transition) -+ * * ACTIVE (can be skipped by LINKED->INACTIVE transition) -+ * * INACTIVE -+ * * DRAINED -+ * * FREED -+ * -+ * Each node is allocated by the caller and initialized via kdbus_node_init(). -+ * This never fails and sets the object into state NEW. From now on, ref-counts -+ * on the node manage its lifetime. During init, the ref-count is set to 1. Once -+ * it drops to 0, the node goes to state FREED and the node->free_cb() callback -+ * is called to deallocate any memory. -+ * -+ * After initializing a node, you usually link it into the hierarchy. You need -+ * to provide a parent node and a name. The node will be linked as child to the -+ * parent and a globally unique ID is assigned to the child. The name of the -+ * child must be unique for all children of this parent. Otherwise, linking the -+ * child will fail with -EEXIST. -+ * Note that the child is not marked active, yet. Admittedly, it prevents any -+ * other node from being linked with the same name (thus, it reserves that -+ * name), but any child-lookup (via name or unique ID) will never return this -+ * child unless it has been marked active. -+ * -+ * Once successfully linked, you can use kdbus_node_activate() to activate a -+ * child. This will mark the child active. This state can be skipped by directly -+ * deactivating the child via kdbus_node_deactivate() (see below). -+ * By activating a child, you enable any lookups on this child to succeed from -+ * now on. Furthermore, any code that got its hands on a reference to the node, -+ * can from now on "acquire" the node. -+ * -+ * Active References (or: 'acquiring' and 'releasing' a node) -+ * Additionally to normal object references, nodes support something we call -+ * "active references". An active reference can be acquired via -+ * kdbus_node_acquire() and released via kdbus_node_release(). A caller -+ * _must_ own a normal object reference whenever calling those functions. -+ * Unlike object references, acquiring an active reference can fail (by -+ * returning 'false' from kdbus_node_acquire()). An active reference can -+ * only be acquired if the node is marked active. If it is not marked -+ * active, yet, or if it was already deactivated, no more active references -+ * can be acquired, ever! -+ * Active references are used to track tasks working on a node. Whenever a -+ * task enters kernel-space to perform an action on a node, it acquires an -+ * active reference, performs the action and releases the reference again. -+ * While holding an active reference, the node is guaranteed to stay active. -+ * If the node is deactivated in parallel, the node is marked as -+ * deactivated, then we wait for all active references to be dropped, before -+ * we finally proceed with any cleanups. That is, if you hold an active -+ * reference to a node, any resources that are bound to the "active" state -+ * are guaranteed to stay accessible until you release your reference. -+ * -+ * Active-references are very similar to rw-locks, where acquiring a node is -+ * equal to try-read-lock and releasing to read-unlock. Deactivating a node -+ * means write-lock and never releasing it again. -+ * Unlike rw-locks, the 'active reference' concept is more versatile and -+ * avoids unusual rw-lock usage (never releasing a write-lock..). -+ * -+ * It is safe to acquire multiple active-references recursively. But you -+ * need to check the return value of kdbus_node_acquire() on _each_ call. It -+ * may stop granting references at _any_ time. -+ * -+ * You're free to perform any operations you want while holding an active -+ * reference, except sleeping for an indefinite period. Sleeping for a fixed -+ * amount of time is fine, but you usually should not wait on wait-queues -+ * without a timeout. -+ * For example, if you wait for I/O to happen, you should gather all data -+ * and schedule the I/O operation, then release your active reference and -+ * wait for it to complete. Then try to acquire a new reference. If it -+ * fails, perform any cleanup (the node is now dead). Otherwise, you can -+ * finish your operation. -+ * -+ * All nodes can be deactivated via kdbus_node_deactivate() at any time. You can -+ * call this multiple times, even in parallel or on nodes that were never -+ * linked, and it will just work. The only restriction is, you must not hold an -+ * active reference when calling kdbus_node_deactivate(). -+ * By deactivating a node, it is immediately marked inactive. Then, we wait for -+ * all active references to be released (called 'draining' the node). This -+ * shouldn't take very long as we don't perform long-lasting operations while -+ * holding an active reference. Note that once the node is marked inactive, no -+ * new active references can be acquired. -+ * Once all active references are dropped, the node is considered 'drained'. Now -+ * kdbus_node_deactivate() is called on each child of the node before we -+ * continue deactvating our node. That is, once all children are entirely -+ * deactivated, we call ->release_cb() of our node. ->release_cb() can release -+ * any resources on that node which are bound to the "active" state of a node. -+ * When done, we unlink the node from its parent rb-tree, mark it as -+ * 'released' and return. -+ * If kdbus_node_deactivate() is called multiple times (even in parallel), all -+ * but one caller will just wait until the node is fully deactivated. That is, -+ * one random caller of kdbus_node_deactivate() is selected to call -+ * ->release_cb() and cleanup the node. Only once all this is done, all other -+ * callers will return from kdbus_node_deactivate(). That is, it doesn't matter -+ * whether you're the selected caller or not, it will only return after -+ * everything is fully done. -+ * -+ * When a node is activated, we acquire a normal object reference to the node. -+ * This reference is dropped after deactivation is fully done (and only iff the -+ * node really was activated). This allows callers to link+activate a child node -+ * and then drop all refs. The node will be deactivated together with the -+ * parent, and then be freed when this reference is dropped. -+ * -+ * Currently, nodes provide a bunch of resources that external code can use -+ * directly. This includes: -+ * -+ * * node->waitq: Each node has its own wait-queue that is used to manage -+ * the 'active' state. When a node is deactivated, we wait on -+ * this queue until all active refs are dropped. Analogously, -+ * when you release an active reference on a deactivated -+ * node, and the active ref-count drops to 0, we wake up a -+ * single thread on this queue. Furthermore, once the -+ * ->release_cb() callback finished, we wake up all waiters. -+ * The node-owner is free to re-use this wait-queue for other -+ * purposes. As node-management uses this queue only during -+ * deactivation, it is usually totally fine to re-use the -+ * queue for other, preferably low-overhead, use-cases. -+ * -+ * * node->type: This field defines the type of the owner of this node. It -+ * must be set during node initialization and must remain -+ * constant. The node management never looks at this value, -+ * but external users might use to gain access to the owner -+ * object of a node. -+ * It is totally up to the owner of the node to define what -+ * their type means. Usually it means you can access the -+ * parent structure via container_of(), as long as you hold an -+ * active reference to the node. -+ * -+ * * node->free_cb: callback after all references are dropped -+ * node->release_cb: callback during node deactivation -+ * These fields must be set by the node owner during -+ * node initialization. They must remain constant. If -+ * NULL, they're skipped. -+ * -+ * * node->mode: filesystem access modes -+ * node->uid: filesystem owner uid -+ * node->gid: filesystem owner gid -+ * These fields must be set by the node owner during node -+ * initialization. They must remain constant and may be -+ * accessed by other callers to properly initialize -+ * filesystem nodes. -+ * -+ * * node->id: This is an unsigned 32bit integer allocated by an IDR. It is -+ * always kept as small as possible during allocation and is -+ * globally unique across all nodes allocated by this module. 0 -+ * is reserved as "not assigned" and is the default. -+ * The ID is assigned during kdbus_node_link() and is kept until -+ * the object is freed. Thus, the ID surpasses the active -+ * lifetime of a node. As long as you hold an object reference -+ * to a node (and the node was linked once), the ID is valid and -+ * unique. -+ * -+ * * node->name: name of this node -+ * node->hash: 31bit hash-value of @name (range [2..INT_MAX-1]) -+ * These values follow the same lifetime rules as node->id. -+ * They're initialized when the node is linked and then remain -+ * constant until the last object reference is dropped. -+ * Unlike the id, the name is only unique across all siblings -+ * and only until the node is deactivated. Currently, the name -+ * is even unique if linked but not activated, yet. This might -+ * change in the future, though. Code should not rely on this. -+ * -+ * * node->lock: lock to protect node->children, node->rb, node->parent -+ * * node->parent: Reference to parent node. This is set during LINK time -+ * and is dropped during destruction. You must not access -+ * it unless you hold an active reference to the node or if -+ * you know the node is dead. -+ * * node->children: rb-tree of all linked children of this node. You must -+ * not access this directly, but use one of the iterator -+ * or lookup helpers. -+ */ -+ -+/* -+ * Bias values track states of "active references". They're all negative. If a -+ * node is active, its active-ref-counter is >=0 and tracks all active -+ * references. Once a node is deactivaed, we subtract NODE_BIAS. This means, the -+ * counter is now negative but still counts the active references. Once it drops -+ * to exactly NODE_BIAS, we know all active references were dropped. Exactly one -+ * thread will change it to NODE_RELEASE now, perform cleanup and then put it -+ * into NODE_DRAINED. Once drained, all other threads that tried deactivating -+ * the node will now be woken up (thus, they wait until the node is fully done). -+ * The initial state during node-setup is NODE_NEW. If a node is directly -+ * deactivated without having ever been active, it is put into -+ * NODE_RELEASE_DIRECT instead of NODE_BIAS. This tracks this one-bit state -+ * across node-deactivation. The task putting it into NODE_RELEASE now knows -+ * whether the node was active before or not. -+ * -+ * Some archs implement atomic_sub(v) with atomic_add(-v), so reserve INT_MIN -+ * to avoid overflows if multiplied by -1. -+ */ -+#define KDBUS_NODE_BIAS (INT_MIN + 5) -+#define KDBUS_NODE_RELEASE_DIRECT (KDBUS_NODE_BIAS - 1) -+#define KDBUS_NODE_RELEASE (KDBUS_NODE_BIAS - 2) -+#define KDBUS_NODE_DRAINED (KDBUS_NODE_BIAS - 3) -+#define KDBUS_NODE_NEW (KDBUS_NODE_BIAS - 4) -+ -+/* global unique ID mapping for kdbus nodes */ -+static DEFINE_IDR(kdbus_node_idr); -+static DECLARE_RWSEM(kdbus_node_idr_lock); -+ -+/** -+ * kdbus_node_name_hash() - hash a name -+ * @name: The string to hash -+ * -+ * This computes the hash of @name. It is guaranteed to be in the range -+ * [2..INT_MAX-1]. The values 1, 2 and INT_MAX are unused as they are reserved -+ * for the filesystem code. -+ * -+ * Return: hash value of the passed string -+ */ -+static unsigned int kdbus_node_name_hash(const char *name) -+{ -+ unsigned int hash; -+ -+ /* reserve hash numbers 0, 1 and >=INT_MAX for magic directories */ -+ hash = kdbus_strhash(name) & INT_MAX; -+ if (hash < 2) -+ hash += 2; -+ if (hash >= INT_MAX) -+ hash = INT_MAX - 1; -+ -+ return hash; -+} -+ -+/** -+ * kdbus_node_name_compare() - compare a name with a node's name -+ * @hash: hash of the string to compare the node with -+ * @name: name to compare the node with -+ * @node: node to compare the name with -+ * -+ * Return: 0 if @name and @hash exactly match the information in @node, or -+ * an integer less than or greater than zero if @name is found, respectively, -+ * to be less than or be greater than the string stored in @node. -+ */ -+static int kdbus_node_name_compare(unsigned int hash, const char *name, -+ const struct kdbus_node *node) -+{ -+ if (hash != node->hash) -+ return hash - node->hash; -+ -+ return strcmp(name, node->name); -+} -+ -+/** -+ * kdbus_node_init() - initialize a kdbus_node -+ * @node: Pointer to the node to initialize -+ * @type: The type the node will have (KDBUS_NODE_*) -+ * -+ * The caller is responsible of allocating @node and initializating it to zero. -+ * Once this call returns, you must use the node_ref() and node_unref() -+ * functions to manage this node. -+ */ -+void kdbus_node_init(struct kdbus_node *node, unsigned int type) -+{ -+ atomic_set(&node->refcnt, 1); -+ mutex_init(&node->lock); -+ node->id = 0; -+ node->type = type; -+ RB_CLEAR_NODE(&node->rb); -+ node->children = RB_ROOT; -+ init_waitqueue_head(&node->waitq); -+ atomic_set(&node->active, KDBUS_NODE_NEW); -+} -+ -+/** -+ * kdbus_node_link() - link a node into the nodes system -+ * @node: Pointer to the node to initialize -+ * @parent: Pointer to a parent node, may be %NULL -+ * @name: The name of the node (or NULL if root node) -+ * -+ * This links a node into the hierarchy. This must not be called multiple times. -+ * If @parent is NULL, the node becomes a new root node. -+ * -+ * This call will fail if @name is not unique across all its siblings or if no -+ * ID could be allocated. You must not activate a node if linking failed! It is -+ * safe to deactivate it, though. -+ * -+ * Once you linked a node, you must call kdbus_node_deactivate() before you drop -+ * the last reference (even if you never activate the node). -+ * -+ * Return: 0 on success. negative error otherwise. -+ */ -+int kdbus_node_link(struct kdbus_node *node, struct kdbus_node *parent, -+ const char *name) -+{ -+ int ret; -+ -+ if (WARN_ON(node->type != KDBUS_NODE_DOMAIN && !parent)) -+ return -EINVAL; -+ -+ if (WARN_ON(parent && !name)) -+ return -EINVAL; -+ -+ if (name) { -+ node->name = kstrdup(name, GFP_KERNEL); -+ if (!node->name) -+ return -ENOMEM; -+ -+ node->hash = kdbus_node_name_hash(name); -+ } -+ -+ down_write(&kdbus_node_idr_lock); -+ ret = idr_alloc(&kdbus_node_idr, node, 1, 0, GFP_KERNEL); -+ if (ret >= 0) -+ node->id = ret; -+ up_write(&kdbus_node_idr_lock); -+ -+ if (ret < 0) -+ return ret; -+ -+ ret = 0; -+ -+ if (parent) { -+ struct rb_node **n, *prev; -+ -+ if (!kdbus_node_acquire(parent)) -+ return -ESHUTDOWN; -+ -+ mutex_lock(&parent->lock); -+ -+ n = &parent->children.rb_node; -+ prev = NULL; -+ -+ while (*n) { -+ struct kdbus_node *pos; -+ int result; -+ -+ pos = kdbus_node_from_rb(*n); -+ prev = *n; -+ result = kdbus_node_name_compare(node->hash, -+ node->name, -+ pos); -+ if (result == 0) { -+ ret = -EEXIST; -+ goto exit_unlock; -+ } -+ -+ if (result < 0) -+ n = &pos->rb.rb_left; -+ else -+ n = &pos->rb.rb_right; -+ } -+ -+ /* add new node and rebalance the tree */ -+ rb_link_node(&node->rb, prev, n); -+ rb_insert_color(&node->rb, &parent->children); -+ node->parent = kdbus_node_ref(parent); -+ -+exit_unlock: -+ mutex_unlock(&parent->lock); -+ kdbus_node_release(parent); -+ } -+ -+ return ret; -+} -+ -+/** -+ * kdbus_node_ref() - Acquire object reference -+ * @node: node to acquire reference to (or NULL) -+ * -+ * This acquires a new reference to @node. You must already own a reference when -+ * calling this! -+ * If @node is NULL, this is a no-op. -+ * -+ * Return: @node is returned -+ */ -+struct kdbus_node *kdbus_node_ref(struct kdbus_node *node) -+{ -+ if (node) -+ atomic_inc(&node->refcnt); -+ return node; -+} -+ -+/** -+ * kdbus_node_unref() - Drop object reference -+ * @node: node to drop reference to (or NULL) -+ * -+ * This drops an object reference to @node. You must not access the node if you -+ * no longer own a reference. -+ * If the ref-count drops to 0, the object will be destroyed (->free_cb will be -+ * called). -+ * -+ * If you linked or activated the node, you must deactivate the node before you -+ * drop your last reference! If you didn't link or activate the node, you can -+ * drop any reference you want. -+ * -+ * Note that this calls into ->free_cb() and thus _might_ sleep. The ->free_cb() -+ * callbacks must not acquire any outer locks, though. So you can safely drop -+ * references while holding locks. -+ * -+ * If @node is NULL, this is a no-op. -+ * -+ * Return: This always returns NULL -+ */ -+struct kdbus_node *kdbus_node_unref(struct kdbus_node *node) -+{ -+ if (node && atomic_dec_and_test(&node->refcnt)) { -+ struct kdbus_node safe = *node; -+ -+ WARN_ON(atomic_read(&node->active) != KDBUS_NODE_DRAINED); -+ WARN_ON(!RB_EMPTY_NODE(&node->rb)); -+ -+ if (node->free_cb) -+ node->free_cb(node); -+ -+ down_write(&kdbus_node_idr_lock); -+ if (safe.id > 0) -+ idr_remove(&kdbus_node_idr, safe.id); -+ /* drop caches after last node to not leak memory on unload */ -+ if (idr_is_empty(&kdbus_node_idr)) { -+ idr_destroy(&kdbus_node_idr); -+ idr_init(&kdbus_node_idr); -+ } -+ up_write(&kdbus_node_idr_lock); -+ -+ kfree(safe.name); -+ -+ /* -+ * kdbusfs relies on the parent to be available even after the -+ * node was deactivated and unlinked. Therefore, we pin it -+ * until a node is destroyed. -+ */ -+ kdbus_node_unref(safe.parent); -+ } -+ -+ return NULL; -+} -+ -+/** -+ * kdbus_node_is_active() - test whether a node is active -+ * @node: node to test -+ * -+ * This checks whether @node is active. That means, @node was linked and -+ * activated by the node owner and hasn't been deactivated, yet. If, and only -+ * if, a node is active, kdbus_node_acquire() will be able to acquire active -+ * references. -+ * -+ * Note that this function does not give any lifetime guarantees. After this -+ * call returns, the node might be deactivated immediately. Normally, what you -+ * want is to acquire a real active reference via kdbus_node_acquire(). -+ * -+ * Return: true if @node is active, false otherwise -+ */ -+bool kdbus_node_is_active(struct kdbus_node *node) -+{ -+ return atomic_read(&node->active) >= 0; -+} -+ -+/** -+ * kdbus_node_is_deactivated() - test whether a node was already deactivated -+ * @node: node to test -+ * -+ * This checks whether kdbus_node_deactivate() was called on @node. Note that -+ * this might be true even if you never deactivated the node directly, but only -+ * one of its ancestors. -+ * -+ * Note that even if this returns 'false', the node might get deactivated -+ * immediately after the call returns. -+ * -+ * Return: true if @node was already deactivated, false if not -+ */ -+bool kdbus_node_is_deactivated(struct kdbus_node *node) -+{ -+ int v; -+ -+ v = atomic_read(&node->active); -+ return v != KDBUS_NODE_NEW && v < 0; -+} -+ -+/** -+ * kdbus_node_activate() - activate a node -+ * @node: node to activate -+ * -+ * This marks @node as active if, and only if, the node wasn't activated nor -+ * deactivated, yet, and the parent is still active. Any but the first call to -+ * kdbus_node_activate() is a no-op. -+ * If you called kdbus_node_deactivate() before, then even the first call to -+ * kdbus_node_activate() will be a no-op. -+ * -+ * This call doesn't give any lifetime guarantees. The node might get -+ * deactivated immediately after this call returns. Or the parent might already -+ * be deactivated, which will make this call a no-op. -+ * -+ * If this call successfully activated a node, it will take an object reference -+ * to it. This reference is dropped after the node is deactivated. Therefore, -+ * the object owner can safely drop their reference to @node iff they know that -+ * its parent node will get deactivated at some point. Once the parent node is -+ * deactivated, it will deactivate all its child and thus drop this reference -+ * again. -+ * -+ * Return: True if this call successfully activated the node, otherwise false. -+ * Note that this might return false, even if the node is still active -+ * (eg., if you called this a second time). -+ */ -+bool kdbus_node_activate(struct kdbus_node *node) -+{ -+ bool res = false; -+ -+ mutex_lock(&node->lock); -+ if (atomic_read(&node->active) == KDBUS_NODE_NEW) { -+ atomic_sub(KDBUS_NODE_NEW, &node->active); -+ /* activated nodes have ref +1 */ -+ kdbus_node_ref(node); -+ res = true; -+ } -+ mutex_unlock(&node->lock); -+ -+ return res; -+} -+ -+/** -+ * kdbus_node_deactivate() - deactivate a node -+ * @node: The node to deactivate. -+ * -+ * This function recursively deactivates this node and all its children. It -+ * returns only once all children and the node itself were recursively disabled -+ * (even if you call this function multiple times in parallel). -+ * -+ * It is safe to call this function on _any_ node that was initialized _any_ -+ * number of times. -+ * -+ * This call may sleep, as it waits for all active references to be dropped. -+ */ -+void kdbus_node_deactivate(struct kdbus_node *node) -+{ -+ struct kdbus_node *pos, *child; -+ struct rb_node *rb; -+ int v_pre, v_post; -+ -+ pos = node; -+ -+ /* -+ * To avoid recursion, we perform back-tracking while deactivating -+ * nodes. For each node we enter, we first mark the active-counter as -+ * deactivated by adding BIAS. If the node as children, we set the first -+ * child as current position and start over. If the node has no -+ * children, we drain the node by waiting for all active refs to be -+ * dropped and then releasing the node. -+ * -+ * After the node is released, we set its parent as current position -+ * and start over. If the current position was the initial node, we're -+ * done. -+ * -+ * Note that this function can be called in parallel by multiple -+ * callers. We make sure that each node is only released once, and any -+ * racing caller will wait until the other thread fully released that -+ * node. -+ */ -+ -+ for (;;) { -+ /* -+ * Add BIAS to node->active to mark it as inactive. If it was -+ * never active before, immediately mark it as RELEASE_INACTIVE -+ * so we remember this state. -+ * We cannot remember v_pre as we might iterate into the -+ * children, overwriting v_pre, before we can release our node. -+ */ -+ mutex_lock(&pos->lock); -+ v_pre = atomic_read(&pos->active); -+ if (v_pre >= 0) -+ atomic_add_return(KDBUS_NODE_BIAS, &pos->active); -+ else if (v_pre == KDBUS_NODE_NEW) -+ atomic_set(&pos->active, KDBUS_NODE_RELEASE_DIRECT); -+ mutex_unlock(&pos->lock); -+ -+ /* wait until all active references were dropped */ -+ wait_event(pos->waitq, -+ atomic_read(&pos->active) <= KDBUS_NODE_BIAS); -+ -+ mutex_lock(&pos->lock); -+ /* recurse into first child if any */ -+ rb = rb_first(&pos->children); -+ if (rb) { -+ child = kdbus_node_ref(kdbus_node_from_rb(rb)); -+ mutex_unlock(&pos->lock); -+ pos = child; -+ continue; -+ } -+ -+ /* mark object as RELEASE */ -+ v_post = atomic_read(&pos->active); -+ if (v_post == KDBUS_NODE_BIAS || -+ v_post == KDBUS_NODE_RELEASE_DIRECT) -+ atomic_set(&pos->active, KDBUS_NODE_RELEASE); -+ mutex_unlock(&pos->lock); -+ -+ /* -+ * If this is the thread that marked the object as RELEASE, we -+ * perform the actual release. Otherwise, we wait until the -+ * release is done and the node is marked as DRAINED. -+ */ -+ if (v_post == KDBUS_NODE_BIAS || -+ v_post == KDBUS_NODE_RELEASE_DIRECT) { -+ if (pos->release_cb) -+ pos->release_cb(pos, v_post == KDBUS_NODE_BIAS); -+ -+ if (pos->parent) { -+ mutex_lock(&pos->parent->lock); -+ if (!RB_EMPTY_NODE(&pos->rb)) { -+ rb_erase(&pos->rb, -+ &pos->parent->children); -+ RB_CLEAR_NODE(&pos->rb); -+ } -+ mutex_unlock(&pos->parent->lock); -+ } -+ -+ /* mark as DRAINED */ -+ atomic_set(&pos->active, KDBUS_NODE_DRAINED); -+ wake_up_all(&pos->waitq); -+ -+ /* drop VFS cache */ -+ kdbus_fs_flush(pos); -+ -+ /* -+ * If the node was activated and somone subtracted BIAS -+ * from it to deactivate it, we, and only us, are -+ * responsible to release the extra ref-count that was -+ * taken once in kdbus_node_activate(). -+ * If the node was never activated, no-one ever -+ * subtracted BIAS, but instead skipped that state and -+ * immediately went to NODE_RELEASE_DIRECT. In that case -+ * we must not drop the reference. -+ */ -+ if (v_post == KDBUS_NODE_BIAS) -+ kdbus_node_unref(pos); -+ } else { -+ /* wait until object is DRAINED */ -+ wait_event(pos->waitq, -+ atomic_read(&pos->active) == KDBUS_NODE_DRAINED); -+ } -+ -+ /* -+ * We're done with the current node. Continue on its parent -+ * again, which will try deactivating its next child, or itself -+ * if no child is left. -+ * If we've reached our initial node again, we are done and -+ * can safely return. -+ */ -+ if (pos == node) -+ break; -+ -+ child = pos; -+ pos = pos->parent; -+ kdbus_node_unref(child); -+ } -+} -+ -+/** -+ * kdbus_node_acquire() - Acquire an active ref on a node -+ * @node: The node -+ * -+ * This acquires an active-reference to @node. This will only succeed if the -+ * node is active. You must release this active reference via -+ * kdbus_node_release() again. -+ * -+ * See the introduction to "active references" for more details. -+ * -+ * Return: %true if @node was non-NULL and active -+ */ -+bool kdbus_node_acquire(struct kdbus_node *node) -+{ -+ return node && atomic_inc_unless_negative(&node->active); -+} -+ -+/** -+ * kdbus_node_release() - Release an active ref on a node -+ * @node: The node -+ * -+ * This releases an active reference that was previously acquired via -+ * kdbus_node_acquire(). See kdbus_node_acquire() for details. -+ */ -+void kdbus_node_release(struct kdbus_node *node) -+{ -+ if (node && atomic_dec_return(&node->active) == KDBUS_NODE_BIAS) -+ wake_up(&node->waitq); -+} -+ -+/** -+ * kdbus_node_find_child() - Find child by name -+ * @node: parent node to search through -+ * @name: name of child node -+ * -+ * This searches through all children of @node for a child-node with name @name. -+ * If not found, or if the child is deactivated, NULL is returned. Otherwise, -+ * the child is acquired and a new reference is returned. -+ * -+ * If you're done with the child, you need to release it and drop your -+ * reference. -+ * -+ * This function does not acquire the parent node. However, if the parent was -+ * already deactivated, then kdbus_node_deactivate() will, at some point, also -+ * deactivate the child. Therefore, we can rely on the explicit ordering during -+ * deactivation. -+ * -+ * Return: Reference to acquired child node, or NULL if not found / not active. -+ */ -+struct kdbus_node *kdbus_node_find_child(struct kdbus_node *node, -+ const char *name) -+{ -+ struct kdbus_node *child; -+ struct rb_node *rb; -+ unsigned int hash; -+ int ret; -+ -+ hash = kdbus_node_name_hash(name); -+ -+ mutex_lock(&node->lock); -+ rb = node->children.rb_node; -+ while (rb) { -+ child = kdbus_node_from_rb(rb); -+ ret = kdbus_node_name_compare(hash, name, child); -+ if (ret < 0) -+ rb = rb->rb_left; -+ else if (ret > 0) -+ rb = rb->rb_right; -+ else -+ break; -+ } -+ if (rb && kdbus_node_acquire(child)) -+ kdbus_node_ref(child); -+ else -+ child = NULL; -+ mutex_unlock(&node->lock); -+ -+ return child; -+} -+ -+static struct kdbus_node *node_find_closest_unlocked(struct kdbus_node *node, -+ unsigned int hash, -+ const char *name) -+{ -+ struct kdbus_node *n, *pos = NULL; -+ struct rb_node *rb; -+ int res; -+ -+ /* -+ * Find the closest child with ``node->hash >= hash'', or, if @name is -+ * valid, ``node->name >= name'' (where '>=' is the lex. order). -+ */ -+ -+ rb = node->children.rb_node; -+ while (rb) { -+ n = kdbus_node_from_rb(rb); -+ -+ if (name) -+ res = kdbus_node_name_compare(hash, name, n); -+ else -+ res = hash - n->hash; -+ -+ if (res <= 0) { -+ rb = rb->rb_left; -+ pos = n; -+ } else { /* ``hash > n->hash'', ``name > n->name'' */ -+ rb = rb->rb_right; -+ } -+ } -+ -+ return pos; -+} -+ -+/** -+ * kdbus_node_find_closest() - Find closest child-match -+ * @node: parent node to search through -+ * @hash: hash value to find closest match for -+ * -+ * Find the closest child of @node with a hash greater than or equal to @hash. -+ * The closest match is the left-most child of @node with this property. Which -+ * means, it is the first child with that hash returned by -+ * kdbus_node_next_child(), if you'd iterate the whole parent node. -+ * -+ * Return: Reference to acquired child, or NULL if none found. -+ */ -+struct kdbus_node *kdbus_node_find_closest(struct kdbus_node *node, -+ unsigned int hash) -+{ -+ struct kdbus_node *child; -+ struct rb_node *rb; -+ -+ mutex_lock(&node->lock); -+ -+ child = node_find_closest_unlocked(node, hash, NULL); -+ while (child && !kdbus_node_acquire(child)) { -+ rb = rb_next(&child->rb); -+ if (rb) -+ child = kdbus_node_from_rb(rb); -+ else -+ child = NULL; -+ } -+ kdbus_node_ref(child); -+ -+ mutex_unlock(&node->lock); -+ -+ return child; -+} -+ -+/** -+ * kdbus_node_next_child() - Acquire next child -+ * @node: parent node -+ * @prev: previous child-node position or NULL -+ * -+ * This function returns a reference to the next active child of @node, after -+ * the passed position @prev. If @prev is NULL, a reference to the first active -+ * child is returned. If no more active children are found, NULL is returned. -+ * -+ * This function acquires the next child it returns. If you're done with the -+ * returned pointer, you need to release _and_ unref it. -+ * -+ * The passed in pointer @prev is not modified by this function, and it does -+ * *not* have to be active. If @prev was acquired via different means, or if it -+ * was unlinked from its parent before you pass it in, then this iterator will -+ * still return the next active child (it will have to search through the -+ * rb-tree based on the node-name, though). -+ * However, @prev must not be linked to a different parent than @node! -+ * -+ * Return: Reference to next acquired child, or NULL if at the end. -+ */ -+struct kdbus_node *kdbus_node_next_child(struct kdbus_node *node, -+ struct kdbus_node *prev) -+{ -+ struct kdbus_node *pos = NULL; -+ struct rb_node *rb; -+ -+ mutex_lock(&node->lock); -+ -+ if (!prev) { -+ /* -+ * New iteration; find first node in rb-tree and try to acquire -+ * it. If we got it, directly return it as first element. -+ * Otherwise, the loop below will find the next active node. -+ */ -+ rb = rb_first(&node->children); -+ if (!rb) -+ goto exit; -+ pos = kdbus_node_from_rb(rb); -+ if (kdbus_node_acquire(pos)) -+ goto exit; -+ } else if (RB_EMPTY_NODE(&prev->rb)) { -+ /* -+ * The current iterator is no longer linked to the rb-tree. Use -+ * its hash value and name to find the next _higher_ node and -+ * acquire it. If we got it, return it as next element. -+ * Otherwise, the loop below will find the next active node. -+ */ -+ pos = node_find_closest_unlocked(node, prev->hash, prev->name); -+ if (!pos) -+ goto exit; -+ if (kdbus_node_acquire(pos)) -+ goto exit; -+ } else { -+ /* -+ * The current iterator is still linked to the parent. Set it -+ * as current position and use the loop below to find the next -+ * active element. -+ */ -+ pos = prev; -+ } -+ -+ /* @pos was already returned or is inactive; find next active node */ -+ do { -+ rb = rb_next(&pos->rb); -+ if (rb) -+ pos = kdbus_node_from_rb(rb); -+ else -+ pos = NULL; -+ } while (pos && !kdbus_node_acquire(pos)); -+ -+exit: -+ /* @pos is NULL or acquired. Take ref if non-NULL and return it */ -+ kdbus_node_ref(pos); -+ mutex_unlock(&node->lock); -+ return pos; -+} -diff --git a/ipc/kdbus/node.h b/ipc/kdbus/node.h -new file mode 100644 -index 000000000000..be125ce4fd58 ---- /dev/null -+++ b/ipc/kdbus/node.h -@@ -0,0 +1,84 @@ -+/* -+ * Copyright (C) 2013-2015 Kay Sievers -+ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> -+ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> -+ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> -+ * Copyright (C) 2013-2015 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_NODE_H -+#define __KDBUS_NODE_H -+ -+#include <linux/atomic.h> -+#include <linux/kernel.h> -+#include <linux/mutex.h> -+#include <linux/wait.h> -+ -+struct kdbus_node; -+ -+enum kdbus_node_type { -+ KDBUS_NODE_DOMAIN, -+ KDBUS_NODE_CONTROL, -+ KDBUS_NODE_BUS, -+ KDBUS_NODE_ENDPOINT, -+}; -+ -+typedef void (*kdbus_node_free_t) (struct kdbus_node *node); -+typedef void (*kdbus_node_release_t) (struct kdbus_node *node, bool was_active); -+ -+struct kdbus_node { -+ atomic_t refcnt; -+ atomic_t active; -+ wait_queue_head_t waitq; -+ -+ /* static members */ -+ unsigned int type; -+ kdbus_node_free_t free_cb; -+ kdbus_node_release_t release_cb; -+ umode_t mode; -+ kuid_t uid; -+ kgid_t gid; -+ -+ /* valid once linked */ -+ char *name; -+ unsigned int hash; -+ unsigned int id; -+ struct kdbus_node *parent; /* may be NULL */ -+ -+ /* valid iff active */ -+ struct mutex lock; -+ struct rb_node rb; -+ struct rb_root children; -+}; -+ -+#define kdbus_node_from_rb(_node) rb_entry((_node), struct kdbus_node, rb) -+ -+void kdbus_node_init(struct kdbus_node *node, unsigned int type); -+ -+int kdbus_node_link(struct kdbus_node *node, struct kdbus_node *parent, -+ const char *name); -+ -+struct kdbus_node *kdbus_node_ref(struct kdbus_node *node); -+struct kdbus_node *kdbus_node_unref(struct kdbus_node *node); -+ -+bool kdbus_node_is_active(struct kdbus_node *node); -+bool kdbus_node_is_deactivated(struct kdbus_node *node); -+bool kdbus_node_activate(struct kdbus_node *node); -+void kdbus_node_deactivate(struct kdbus_node *node); -+ -+bool kdbus_node_acquire(struct kdbus_node *node); -+void kdbus_node_release(struct kdbus_node *node); -+ -+struct kdbus_node *kdbus_node_find_child(struct kdbus_node *node, -+ const char *name); -+struct kdbus_node *kdbus_node_find_closest(struct kdbus_node *node, -+ unsigned int hash); -+struct kdbus_node *kdbus_node_next_child(struct kdbus_node *node, -+ struct kdbus_node *prev); -+ -+#endif --- -2.4.3 - - -From 5deea83646aa5f3c707292499b4cce03d2525e30 Mon Sep 17 00:00:00 2001 -From: Daniel Mack <daniel@zonque.org> -Date: Thu, 11 Sep 2014 18:58:45 +0200 -Subject: [PATCH 007/132] kdbus: add code to gather metadata - -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. - -In traditional D-Bus, userspace tasks like polkit or journald make a -live lookup in procfs and sysfs to gain information about a sending -task. This is racy, of course, as in a a connection-less system like -D-Bus, the originating peer can go away immediately after sending the -message. As we're moving D-Bus prmitives into the kernel, we have to -provide the same semantics here, and inform the receiving peer on the -live credentials of the sending peer. - -Metadata is collected at the following times. - - * When a bus is created (KDBUS_CMD_MAKE), information about the - calling task is collected. This data is returned by the kernel - via the KDBUS_CMD_BUS_CREATOR_INFO call. - - * When a connection is created (KDBUS_CMD_HELLO), information about - the calling task is collected. Alternatively, a privileged - connection may provide 'faked' information about credentials, - PIDs and security labels which will be stored instead. This data - is returned by the kernel as information on a connection - (KDBUS_CMD_CONN_INFO). Only metadata that a connection allowed to - be sent (by setting its bit in attach_flags_send) will be exported - in this way. - - * When a message is sent (KDBUS_CMD_SEND), information about the - sending task and the sending connection are collected. This - metadata will be attached to the message when it arrives in the - receiver's pool. If the connection sending the message installed - faked credentials (see kdbus.connection(7)), the message will not - be augmented by any information about the currently sending task. - -Which metadata items are actually delivered depends on the following -sets and masks: - - (a) the system-wide kmod creds mask - (module parameter 'attach_flags_mask') - - (b) the per-connection send creds mask, set by the connecting client - - (c) the per-connection receive creds mask, set by the connecting client - - (d) the per-bus minimal creds mask, set by the bus creator - - (e) the per-bus owner creds mask, set by the bus creator - - (f) the mask specified when querying creds of a bus peer - - (g) the mask specified when querying creds of a bus owner - -With the following rules: - - [1] The creds attached to messages are determined as a & b & c. - - [2] When connecting to a bus (KDBUS_CMD_HELLO), and ~b & d != 0, - the call will fail with, -1, and errno is set to ECONNREFUSED. - - [3] When querying creds of a bus peer, the creds returned - are a & b & f. - - [4] When querying creds of a bus owner, the creds returned - are a & e & g. - -See kdbus.metadata(7) and kdbus.item(7) for more details on which -metadata can currently be attached to messages. - -Signed-off-by: Daniel Mack <daniel@zonque.org> -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Djalal Harouni <tixxdz@opendz.org> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - ipc/kdbus/metadata.c | 1164 ++++++++++++++++++++++++++++++++++++++++++++++++++ - ipc/kdbus/metadata.h | 57 +++ - 2 files changed, 1221 insertions(+) - create mode 100644 ipc/kdbus/metadata.c - create mode 100644 ipc/kdbus/metadata.h - -diff --git a/ipc/kdbus/metadata.c b/ipc/kdbus/metadata.c -new file mode 100644 -index 000000000000..06e0a54a276a ---- /dev/null -+++ b/ipc/kdbus/metadata.c -@@ -0,0 +1,1164 @@ -+/* -+ * Copyright (C) 2013-2015 Kay Sievers -+ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> -+ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> -+ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> -+ * Copyright (C) 2013-2015 Linux Foundation -+ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> -+ * -+ * 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/fs_struct.h> -+#include <linux/init.h> -+#include <linux/kref.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/uidgid.h> -+#include <linux/uio.h> -+#include <linux/user_namespace.h> -+#include <linux/version.h> -+ -+#include "bus.h" -+#include "connection.h" -+#include "endpoint.h" -+#include "item.h" -+#include "message.h" -+#include "metadata.h" -+#include "names.h" -+ -+/** -+ * struct kdbus_meta_proc - Process metadata -+ * @kref: Reference counting -+ * @lock: Object lock -+ * @collected: Bitmask of collected items -+ * @valid: Bitmask of collected and valid items -+ * @uid: UID of process -+ * @euid: EUID of process -+ * @suid: SUID of process -+ * @fsuid: FSUID of process -+ * @gid: GID of process -+ * @egid: EGID of process -+ * @sgid: SGID of process -+ * @fsgid: FSGID of process -+ * @pid: PID of process -+ * @tgid: TGID of process -+ * @ppid: PPID of process -+ * @auxgrps: Auxiliary groups -+ * @n_auxgrps: Number of items in @auxgrps -+ * @tid_comm: TID comm line -+ * @pid_comm: PID comm line -+ * @exe_path: Executable path -+ * @root_path: Root-FS path -+ * @cmdline: Command-line -+ * @cgroup: Full cgroup path -+ * @caps: Capabilities -+ * @caps_namespace: User-namespace of @caps -+ * @seclabel: Seclabel -+ * @audit_loginuid: Audit login-UID -+ * @audit_sessionid: Audit session-ID -+ */ -+struct kdbus_meta_proc { -+ struct kref kref; -+ struct mutex lock; -+ u64 collected; -+ u64 valid; -+ -+ /* KDBUS_ITEM_CREDS */ -+ kuid_t uid, euid, suid, fsuid; -+ kgid_t gid, egid, sgid, fsgid; -+ -+ /* KDBUS_ITEM_PIDS */ -+ struct pid *pid; -+ struct pid *tgid; -+ struct pid *ppid; -+ -+ /* KDBUS_ITEM_AUXGROUPS */ -+ kgid_t *auxgrps; -+ size_t n_auxgrps; -+ -+ /* KDBUS_ITEM_TID_COMM */ -+ char tid_comm[TASK_COMM_LEN]; -+ /* KDBUS_ITEM_PID_COMM */ -+ char pid_comm[TASK_COMM_LEN]; -+ -+ /* KDBUS_ITEM_EXE */ -+ struct path exe_path; -+ struct path root_path; -+ -+ /* KDBUS_ITEM_CMDLINE */ -+ char *cmdline; -+ -+ /* KDBUS_ITEM_CGROUP */ -+ char *cgroup; -+ -+ /* KDBUS_ITEM_CAPS */ -+ struct caps { -+ /* binary compatible to kdbus_caps */ -+ u32 last_cap; -+ struct { -+ u32 caps[_KERNEL_CAPABILITY_U32S]; -+ } set[4]; -+ } caps; -+ struct user_namespace *caps_namespace; -+ -+ /* KDBUS_ITEM_SECLABEL */ -+ char *seclabel; -+ -+ /* KDBUS_ITEM_AUDIT */ -+ kuid_t audit_loginuid; -+ unsigned int audit_sessionid; -+}; -+ -+/** -+ * struct kdbus_meta_conn -+ * @kref: Reference counting -+ * @lock: Object lock -+ * @collected: Bitmask of collected items -+ * @valid: Bitmask of collected and valid items -+ * @ts: Timestamp values -+ * @owned_names_items: Serialized items for owned names -+ * @owned_names_size: Size of @owned_names_items -+ * @conn_description: Connection description -+ */ -+struct kdbus_meta_conn { -+ struct kref kref; -+ struct mutex lock; -+ u64 collected; -+ u64 valid; -+ -+ /* KDBUS_ITEM_TIMESTAMP */ -+ struct kdbus_timestamp ts; -+ -+ /* KDBUS_ITEM_OWNED_NAME */ -+ struct kdbus_item *owned_names_items; -+ size_t owned_names_size; -+ -+ /* KDBUS_ITEM_CONN_DESCRIPTION */ -+ char *conn_description; -+}; -+ -+/** -+ * kdbus_meta_proc_new() - Create process metadata object -+ * -+ * Return: Pointer to new object on success, ERR_PTR on failure. -+ */ -+struct kdbus_meta_proc *kdbus_meta_proc_new(void) -+{ -+ struct kdbus_meta_proc *mp; -+ -+ mp = kzalloc(sizeof(*mp), GFP_KERNEL); -+ if (!mp) -+ return ERR_PTR(-ENOMEM); -+ -+ kref_init(&mp->kref); -+ mutex_init(&mp->lock); -+ -+ return mp; -+} -+ -+static void kdbus_meta_proc_free(struct kref *kref) -+{ -+ struct kdbus_meta_proc *mp = container_of(kref, struct kdbus_meta_proc, -+ kref); -+ -+ path_put(&mp->exe_path); -+ path_put(&mp->root_path); -+ put_user_ns(mp->caps_namespace); -+ put_pid(mp->ppid); -+ put_pid(mp->tgid); -+ put_pid(mp->pid); -+ -+ kfree(mp->seclabel); -+ kfree(mp->auxgrps); -+ kfree(mp->cmdline); -+ kfree(mp->cgroup); -+ kfree(mp); -+} -+ -+/** -+ * kdbus_meta_proc_ref() - Gain reference -+ * @mp: Process metadata object -+ * -+ * Return: @mp is returned -+ */ -+struct kdbus_meta_proc *kdbus_meta_proc_ref(struct kdbus_meta_proc *mp) -+{ -+ if (mp) -+ kref_get(&mp->kref); -+ return mp; -+} -+ -+/** -+ * kdbus_meta_proc_unref() - Drop reference -+ * @mp: Process metadata object -+ * -+ * Return: NULL -+ */ -+struct kdbus_meta_proc *kdbus_meta_proc_unref(struct kdbus_meta_proc *mp) -+{ -+ if (mp) -+ kref_put(&mp->kref, kdbus_meta_proc_free); -+ return NULL; -+} -+ -+static void kdbus_meta_proc_collect_creds(struct kdbus_meta_proc *mp) -+{ -+ mp->uid = current_uid(); -+ mp->euid = current_euid(); -+ mp->suid = current_suid(); -+ mp->fsuid = current_fsuid(); -+ -+ mp->gid = current_gid(); -+ mp->egid = current_egid(); -+ mp->sgid = current_sgid(); -+ mp->fsgid = current_fsgid(); -+ -+ mp->valid |= KDBUS_ATTACH_CREDS; -+} -+ -+static void kdbus_meta_proc_collect_pids(struct kdbus_meta_proc *mp) -+{ -+ struct task_struct *parent; -+ -+ mp->pid = get_pid(task_pid(current)); -+ mp->tgid = get_pid(task_tgid(current)); -+ -+ rcu_read_lock(); -+ parent = rcu_dereference(current->real_parent); -+ mp->ppid = get_pid(task_tgid(parent)); -+ rcu_read_unlock(); -+ -+ mp->valid |= KDBUS_ATTACH_PIDS; -+} -+ -+static int kdbus_meta_proc_collect_auxgroups(struct kdbus_meta_proc *mp) -+{ -+ struct group_info *info; -+ size_t i; -+ -+ info = get_current_groups(); -+ -+ if (info->ngroups > 0) { -+ mp->auxgrps = kmalloc_array(info->ngroups, sizeof(kgid_t), -+ GFP_KERNEL); -+ if (!mp->auxgrps) { -+ put_group_info(info); -+ return -ENOMEM; -+ } -+ -+ for (i = 0; i < info->ngroups; i++) -+ mp->auxgrps[i] = GROUP_AT(info, i); -+ } -+ -+ mp->n_auxgrps = info->ngroups; -+ put_group_info(info); -+ mp->valid |= KDBUS_ATTACH_AUXGROUPS; -+ -+ return 0; -+} -+ -+static void kdbus_meta_proc_collect_tid_comm(struct kdbus_meta_proc *mp) -+{ -+ get_task_comm(mp->tid_comm, current); -+ mp->valid |= KDBUS_ATTACH_TID_COMM; -+} -+ -+static void kdbus_meta_proc_collect_pid_comm(struct kdbus_meta_proc *mp) -+{ -+ get_task_comm(mp->pid_comm, current->group_leader); -+ mp->valid |= KDBUS_ATTACH_PID_COMM; -+} -+ -+static void kdbus_meta_proc_collect_exe(struct kdbus_meta_proc *mp) -+{ -+ struct mm_struct *mm; -+ -+ mm = get_task_mm(current); -+ if (!mm) -+ return; -+ -+ down_read(&mm->mmap_sem); -+ if (mm->exe_file) { -+ mp->exe_path = mm->exe_file->f_path; -+ path_get(&mp->exe_path); -+ get_fs_root(current->fs, &mp->root_path); -+ mp->valid |= KDBUS_ATTACH_EXE; -+ } -+ up_read(&mm->mmap_sem); -+ -+ mmput(mm); -+} -+ -+static int kdbus_meta_proc_collect_cmdline(struct kdbus_meta_proc *mp) -+{ -+ struct mm_struct *mm; -+ char *cmdline; -+ -+ mm = get_task_mm(current); -+ if (!mm) -+ return 0; -+ -+ if (!mm->arg_end) { -+ mmput(mm); -+ return 0; -+ } -+ -+ cmdline = strndup_user((const char __user *)mm->arg_start, -+ mm->arg_end - mm->arg_start); -+ mmput(mm); -+ -+ if (IS_ERR(cmdline)) -+ return PTR_ERR(cmdline); -+ -+ mp->cmdline = cmdline; -+ mp->valid |= KDBUS_ATTACH_CMDLINE; -+ -+ return 0; -+} -+ -+static int kdbus_meta_proc_collect_cgroup(struct kdbus_meta_proc *mp) -+{ -+#ifdef CONFIG_CGROUPS -+ void *page; -+ char *s; -+ -+ page = (void *)__get_free_page(GFP_TEMPORARY); -+ if (!page) -+ return -ENOMEM; -+ -+ s = task_cgroup_path(current, page, PAGE_SIZE); -+ if (s) { -+ mp->cgroup = kstrdup(s, GFP_KERNEL); -+ if (!mp->cgroup) { -+ free_page((unsigned long)page); -+ return -ENOMEM; -+ } -+ } -+ -+ free_page((unsigned long)page); -+ mp->valid |= KDBUS_ATTACH_CGROUP; -+#endif -+ -+ return 0; -+} -+ -+static void kdbus_meta_proc_collect_caps(struct kdbus_meta_proc *mp) -+{ -+ const struct cred *c = current_cred(); -+ int i; -+ -+ /* ABI: "last_cap" equals /proc/sys/kernel/cap_last_cap */ -+ mp->caps.last_cap = CAP_LAST_CAP; -+ mp->caps_namespace = get_user_ns(current_user_ns()); -+ -+ CAP_FOR_EACH_U32(i) { -+ mp->caps.set[0].caps[i] = c->cap_inheritable.cap[i]; -+ mp->caps.set[1].caps[i] = c->cap_permitted.cap[i]; -+ mp->caps.set[2].caps[i] = c->cap_effective.cap[i]; -+ mp->caps.set[3].caps[i] = c->cap_bset.cap[i]; -+ } -+ -+ /* clear unused bits */ -+ for (i = 0; i < 4; i++) -+ mp->caps.set[i].caps[CAP_TO_INDEX(CAP_LAST_CAP)] &= -+ CAP_LAST_U32_VALID_MASK; -+ -+ mp->valid |= KDBUS_ATTACH_CAPS; -+} -+ -+static int kdbus_meta_proc_collect_seclabel(struct kdbus_meta_proc *mp) -+{ -+#ifdef CONFIG_SECURITY -+ char *ctx = NULL; -+ u32 sid, len; -+ int ret; -+ -+ security_task_getsecid(current, &sid); -+ ret = security_secid_to_secctx(sid, &ctx, &len); -+ if (ret < 0) { -+ /* -+ * EOPNOTSUPP means no security module is active, -+ * lets skip adding the seclabel then. This effectively -+ * drops the SECLABEL item. -+ */ -+ return (ret == -EOPNOTSUPP) ? 0 : ret; -+ } -+ -+ mp->seclabel = kstrdup(ctx, GFP_KERNEL); -+ security_release_secctx(ctx, len); -+ if (!mp->seclabel) -+ return -ENOMEM; -+ -+ mp->valid |= KDBUS_ATTACH_SECLABEL; -+#endif -+ -+ return 0; -+} -+ -+static void kdbus_meta_proc_collect_audit(struct kdbus_meta_proc *mp) -+{ -+#ifdef CONFIG_AUDITSYSCALL -+ mp->audit_loginuid = audit_get_loginuid(current); -+ mp->audit_sessionid = audit_get_sessionid(current); -+ mp->valid |= KDBUS_ATTACH_AUDIT; -+#endif -+} -+ -+/** -+ * kdbus_meta_proc_collect() - Collect process metadata -+ * @mp: Process metadata object -+ * @what: Attach flags to collect -+ * -+ * This collects process metadata from current and saves it in @mp. -+ * -+ * Return: 0 on success, negative error code on failure. -+ */ -+int kdbus_meta_proc_collect(struct kdbus_meta_proc *mp, u64 what) -+{ -+ int ret; -+ -+ if (!mp || !(what & (KDBUS_ATTACH_CREDS | -+ KDBUS_ATTACH_PIDS | -+ KDBUS_ATTACH_AUXGROUPS | -+ 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))) -+ return 0; -+ -+ mutex_lock(&mp->lock); -+ -+ if ((what & KDBUS_ATTACH_CREDS) && -+ !(mp->collected & KDBUS_ATTACH_CREDS)) { -+ kdbus_meta_proc_collect_creds(mp); -+ mp->collected |= KDBUS_ATTACH_CREDS; -+ } -+ -+ if ((what & KDBUS_ATTACH_PIDS) && -+ !(mp->collected & KDBUS_ATTACH_PIDS)) { -+ kdbus_meta_proc_collect_pids(mp); -+ mp->collected |= KDBUS_ATTACH_PIDS; -+ } -+ -+ if ((what & KDBUS_ATTACH_AUXGROUPS) && -+ !(mp->collected & KDBUS_ATTACH_AUXGROUPS)) { -+ ret = kdbus_meta_proc_collect_auxgroups(mp); -+ if (ret < 0) -+ goto exit_unlock; -+ mp->collected |= KDBUS_ATTACH_AUXGROUPS; -+ } -+ -+ if ((what & KDBUS_ATTACH_TID_COMM) && -+ !(mp->collected & KDBUS_ATTACH_TID_COMM)) { -+ kdbus_meta_proc_collect_tid_comm(mp); -+ mp->collected |= KDBUS_ATTACH_TID_COMM; -+ } -+ -+ if ((what & KDBUS_ATTACH_PID_COMM) && -+ !(mp->collected & KDBUS_ATTACH_PID_COMM)) { -+ kdbus_meta_proc_collect_pid_comm(mp); -+ mp->collected |= KDBUS_ATTACH_PID_COMM; -+ } -+ -+ if ((what & KDBUS_ATTACH_EXE) && -+ !(mp->collected & KDBUS_ATTACH_EXE)) { -+ kdbus_meta_proc_collect_exe(mp); -+ mp->collected |= KDBUS_ATTACH_EXE; -+ } -+ -+ if ((what & KDBUS_ATTACH_CMDLINE) && -+ !(mp->collected & KDBUS_ATTACH_CMDLINE)) { -+ ret = kdbus_meta_proc_collect_cmdline(mp); -+ if (ret < 0) -+ goto exit_unlock; -+ mp->collected |= KDBUS_ATTACH_CMDLINE; -+ } -+ -+ if ((what & KDBUS_ATTACH_CGROUP) && -+ !(mp->collected & KDBUS_ATTACH_CGROUP)) { -+ ret = kdbus_meta_proc_collect_cgroup(mp); -+ if (ret < 0) -+ goto exit_unlock; -+ mp->collected |= KDBUS_ATTACH_CGROUP; -+ } -+ -+ if ((what & KDBUS_ATTACH_CAPS) && -+ !(mp->collected & KDBUS_ATTACH_CAPS)) { -+ kdbus_meta_proc_collect_caps(mp); -+ mp->collected |= KDBUS_ATTACH_CAPS; -+ } -+ -+ if ((what & KDBUS_ATTACH_SECLABEL) && -+ !(mp->collected & KDBUS_ATTACH_SECLABEL)) { -+ ret = kdbus_meta_proc_collect_seclabel(mp); -+ if (ret < 0) -+ goto exit_unlock; -+ mp->collected |= KDBUS_ATTACH_SECLABEL; -+ } -+ -+ if ((what & KDBUS_ATTACH_AUDIT) && -+ !(mp->collected & KDBUS_ATTACH_AUDIT)) { -+ kdbus_meta_proc_collect_audit(mp); -+ mp->collected |= KDBUS_ATTACH_AUDIT; -+ } -+ -+ ret = 0; -+ -+exit_unlock: -+ mutex_unlock(&mp->lock); -+ return ret; -+} -+ -+/** -+ * kdbus_meta_proc_fake() - Fill process metadata from faked credentials -+ * @mp: Metadata -+ * @creds: Creds to set, may be %NULL -+ * @pids: PIDs to set, may be %NULL -+ * @seclabel: Seclabel to set, may be %NULL -+ * -+ * This function takes information stored in @creds, @pids and @seclabel and -+ * resolves them to kernel-representations, if possible. A call to this function -+ * is considered an alternative to calling kdbus_meta_add_current(), which -+ * derives the same information from the 'current' task. -+ * -+ * This call uses the current task's namespaces to resolve the given -+ * information. -+ * -+ * Return: 0 on success, negative error number otherwise. -+ */ -+int kdbus_meta_proc_fake(struct kdbus_meta_proc *mp, -+ const struct kdbus_creds *creds, -+ const struct kdbus_pids *pids, -+ const char *seclabel) -+{ -+ int ret; -+ -+ if (!mp) -+ return 0; -+ -+ mutex_lock(&mp->lock); -+ -+ if (creds && !(mp->collected & KDBUS_ATTACH_CREDS)) { -+ struct user_namespace *ns = current_user_ns(); -+ -+ mp->uid = make_kuid(ns, creds->uid); -+ mp->euid = make_kuid(ns, creds->euid); -+ mp->suid = make_kuid(ns, creds->suid); -+ mp->fsuid = make_kuid(ns, creds->fsuid); -+ -+ mp->gid = make_kgid(ns, creds->gid); -+ mp->egid = make_kgid(ns, creds->egid); -+ mp->sgid = make_kgid(ns, creds->sgid); -+ mp->fsgid = make_kgid(ns, creds->fsgid); -+ -+ if ((creds->uid != (uid_t)-1 && !uid_valid(mp->uid)) || -+ (creds->euid != (uid_t)-1 && !uid_valid(mp->euid)) || -+ (creds->suid != (uid_t)-1 && !uid_valid(mp->suid)) || -+ (creds->fsuid != (uid_t)-1 && !uid_valid(mp->fsuid)) || -+ (creds->gid != (gid_t)-1 && !gid_valid(mp->gid)) || -+ (creds->egid != (gid_t)-1 && !gid_valid(mp->egid)) || -+ (creds->sgid != (gid_t)-1 && !gid_valid(mp->sgid)) || -+ (creds->fsgid != (gid_t)-1 && !gid_valid(mp->fsgid))) { -+ ret = -EINVAL; -+ goto exit_unlock; -+ } -+ -+ mp->valid |= KDBUS_ATTACH_CREDS; -+ mp->collected |= KDBUS_ATTACH_CREDS; -+ } -+ -+ if (pids && !(mp->collected & KDBUS_ATTACH_PIDS)) { -+ mp->pid = get_pid(find_vpid(pids->tid)); -+ mp->tgid = get_pid(find_vpid(pids->pid)); -+ mp->ppid = get_pid(find_vpid(pids->ppid)); -+ -+ if ((pids->tid != 0 && !mp->pid) || -+ (pids->pid != 0 && !mp->tgid) || -+ (pids->ppid != 0 && !mp->ppid)) { -+ put_pid(mp->pid); -+ put_pid(mp->tgid); -+ put_pid(mp->ppid); -+ mp->pid = NULL; -+ mp->tgid = NULL; -+ mp->ppid = NULL; -+ ret = -EINVAL; -+ goto exit_unlock; -+ } -+ -+ mp->valid |= KDBUS_ATTACH_PIDS; -+ mp->collected |= KDBUS_ATTACH_PIDS; -+ } -+ -+ if (seclabel && !(mp->collected & KDBUS_ATTACH_SECLABEL)) { -+ mp->seclabel = kstrdup(seclabel, GFP_KERNEL); -+ if (!mp->seclabel) { -+ ret = -ENOMEM; -+ goto exit_unlock; -+ } -+ -+ mp->valid |= KDBUS_ATTACH_SECLABEL; -+ mp->collected |= KDBUS_ATTACH_SECLABEL; -+ } -+ -+ ret = 0; -+ -+exit_unlock: -+ mutex_unlock(&mp->lock); -+ return ret; -+} -+ -+/** -+ * kdbus_meta_conn_new() - Create connection metadata object -+ * -+ * Return: Pointer to new object on success, ERR_PTR on failure. -+ */ -+struct kdbus_meta_conn *kdbus_meta_conn_new(void) -+{ -+ struct kdbus_meta_conn *mc; -+ -+ mc = kzalloc(sizeof(*mc), GFP_KERNEL); -+ if (!mc) -+ return ERR_PTR(-ENOMEM); -+ -+ kref_init(&mc->kref); -+ mutex_init(&mc->lock); -+ -+ return mc; -+} -+ -+static void kdbus_meta_conn_free(struct kref *kref) -+{ -+ struct kdbus_meta_conn *mc = -+ container_of(kref, struct kdbus_meta_conn, kref); -+ -+ kfree(mc->conn_description); -+ kfree(mc->owned_names_items); -+ kfree(mc); -+} -+ -+/** -+ * kdbus_meta_conn_ref() - Gain reference -+ * @mc: Connection metadata object -+ */ -+struct kdbus_meta_conn *kdbus_meta_conn_ref(struct kdbus_meta_conn *mc) -+{ -+ if (mc) -+ kref_get(&mc->kref); -+ return mc; -+} -+ -+/** -+ * kdbus_meta_conn_unref() - Drop reference -+ * @mc: Connection metadata object -+ */ -+struct kdbus_meta_conn *kdbus_meta_conn_unref(struct kdbus_meta_conn *mc) -+{ -+ if (mc) -+ kref_put(&mc->kref, kdbus_meta_conn_free); -+ return NULL; -+} -+ -+static void kdbus_meta_conn_collect_timestamp(struct kdbus_meta_conn *mc, -+ struct kdbus_kmsg *kmsg) -+{ -+ struct timespec ts; -+ -+ ktime_get_ts(&ts); -+ mc->ts.monotonic_ns = timespec_to_ns(&ts); -+ -+ ktime_get_real_ts(&ts); -+ mc->ts.realtime_ns = timespec_to_ns(&ts); -+ -+ if (kmsg) -+ mc->ts.seqnum = kmsg->seq; -+ -+ mc->valid |= KDBUS_ATTACH_TIMESTAMP; -+} -+ -+static int kdbus_meta_conn_collect_names(struct kdbus_meta_conn *mc, -+ struct kdbus_conn *conn) -+{ -+ const struct kdbus_name_entry *e; -+ struct kdbus_item *item; -+ size_t slen, size; -+ -+ lockdep_assert_held(&conn->ep->bus->name_registry->rwlock); -+ -+ size = 0; -+ list_for_each_entry(e, &conn->names_list, conn_entry) -+ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_name) + -+ strlen(e->name) + 1); -+ -+ if (!size) -+ return 0; -+ -+ item = kmalloc(size, GFP_KERNEL); -+ if (!item) -+ return -ENOMEM; -+ -+ mc->owned_names_items = item; -+ mc->owned_names_size = size; -+ -+ list_for_each_entry(e, &conn->names_list, conn_entry) { -+ slen = strlen(e->name) + 1; -+ kdbus_item_set(item, KDBUS_ITEM_OWNED_NAME, NULL, -+ sizeof(struct kdbus_name) + slen); -+ item->name.flags = e->flags; -+ memcpy(item->name.name, e->name, slen); -+ item = KDBUS_ITEM_NEXT(item); -+ } -+ -+ /* sanity check: the buffer should be completely written now */ -+ WARN_ON((u8 *)item != (u8 *)mc->owned_names_items + size); -+ -+ mc->valid |= KDBUS_ATTACH_NAMES; -+ return 0; -+} -+ -+static int kdbus_meta_conn_collect_description(struct kdbus_meta_conn *mc, -+ struct kdbus_conn *conn) -+{ -+ if (!conn->description) -+ return 0; -+ -+ mc->conn_description = kstrdup(conn->description, GFP_KERNEL); -+ if (!mc->conn_description) -+ return -ENOMEM; -+ -+ mc->valid |= KDBUS_ATTACH_CONN_DESCRIPTION; -+ return 0; -+} -+ -+/** -+ * kdbus_meta_conn_collect() - Collect connection metadata -+ * @mc: Message metadata object -+ * @kmsg: Kmsg to collect data from -+ * @conn: Connection to collect data from -+ * @what: Attach flags to collect -+ * -+ * This collects connection metadata from @kmsg and @conn and saves it in @mc. -+ * -+ * If KDBUS_ATTACH_NAMES is set in @what and @conn is non-NULL, the caller must -+ * hold the name-registry read-lock of conn->ep->bus->registry. -+ * -+ * Return: 0 on success, negative error code on failure. -+ */ -+int kdbus_meta_conn_collect(struct kdbus_meta_conn *mc, -+ struct kdbus_kmsg *kmsg, -+ struct kdbus_conn *conn, -+ u64 what) -+{ -+ int ret; -+ -+ if (!mc || !(what & (KDBUS_ATTACH_TIMESTAMP | -+ KDBUS_ATTACH_NAMES | -+ KDBUS_ATTACH_CONN_DESCRIPTION))) -+ return 0; -+ -+ mutex_lock(&mc->lock); -+ -+ if (kmsg && (what & KDBUS_ATTACH_TIMESTAMP) && -+ !(mc->collected & KDBUS_ATTACH_TIMESTAMP)) { -+ kdbus_meta_conn_collect_timestamp(mc, kmsg); -+ mc->collected |= KDBUS_ATTACH_TIMESTAMP; -+ } -+ -+ if (conn && (what & KDBUS_ATTACH_NAMES) && -+ !(mc->collected & KDBUS_ATTACH_NAMES)) { -+ ret = kdbus_meta_conn_collect_names(mc, conn); -+ if (ret < 0) -+ goto exit_unlock; -+ mc->collected |= KDBUS_ATTACH_NAMES; -+ } -+ -+ if (conn && (what & KDBUS_ATTACH_CONN_DESCRIPTION) && -+ !(mc->collected & KDBUS_ATTACH_CONN_DESCRIPTION)) { -+ ret = kdbus_meta_conn_collect_description(mc, conn); -+ if (ret < 0) -+ goto exit_unlock; -+ mc->collected |= KDBUS_ATTACH_CONN_DESCRIPTION; -+ } -+ -+ ret = 0; -+ -+exit_unlock: -+ mutex_unlock(&mc->lock); -+ return ret; -+} -+ -+/* -+ * kdbus_meta_export_prepare() - Prepare metadata for export -+ * @mp: Process metadata, or NULL -+ * @mc: Connection metadata, or NULL -+ * @mask: Pointer to mask of KDBUS_ATTACH_* flags to export -+ * @sz: Pointer to return the size needed by the metadata -+ * -+ * Does a conservative calculation of how much space metadata information -+ * will take up during export. It is 'conservative' because for string -+ * translations in namespaces, it will use the kernel namespaces, which is -+ * the longest possible version. -+ * -+ * The actual size consumed by kdbus_meta_export() may hence vary from the -+ * one reported here, but it is guaranteed never to be greater. -+ * -+ * Return: 0 on success, negative error number otherwise. -+ */ -+int kdbus_meta_export_prepare(struct kdbus_meta_proc *mp, -+ struct kdbus_meta_conn *mc, -+ u64 *mask, size_t *sz) -+{ -+ char *exe_pathname = NULL; -+ void *exe_page = NULL; -+ size_t size = 0; -+ u64 valid = 0; -+ int ret = 0; -+ -+ if (mp) { -+ mutex_lock(&mp->lock); -+ valid |= mp->valid; -+ mutex_unlock(&mp->lock); -+ } -+ -+ if (mc) { -+ mutex_lock(&mc->lock); -+ valid |= mc->valid; -+ mutex_unlock(&mc->lock); -+ } -+ -+ *mask &= valid; -+ *mask &= kdbus_meta_attach_mask; -+ -+ if (!*mask) -+ goto exit; -+ -+ /* process metadata */ -+ -+ if (mp && (*mask & KDBUS_ATTACH_CREDS)) -+ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_creds)); -+ -+ if (mp && (*mask & KDBUS_ATTACH_PIDS)) -+ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_pids)); -+ -+ if (mp && (*mask & KDBUS_ATTACH_AUXGROUPS)) -+ size += KDBUS_ITEM_SIZE(mp->n_auxgrps * sizeof(u64)); -+ -+ if (mp && (*mask & KDBUS_ATTACH_TID_COMM)) -+ size += KDBUS_ITEM_SIZE(strlen(mp->tid_comm) + 1); -+ -+ if (mp && (*mask & KDBUS_ATTACH_PID_COMM)) -+ size += KDBUS_ITEM_SIZE(strlen(mp->pid_comm) + 1); -+ -+ if (mp && (*mask & KDBUS_ATTACH_EXE)) { -+ exe_page = (void *)__get_free_page(GFP_TEMPORARY); -+ if (!exe_page) { -+ ret = -ENOMEM; -+ goto exit; -+ } -+ -+ exe_pathname = d_path(&mp->exe_path, exe_page, PAGE_SIZE); -+ if (IS_ERR(exe_pathname)) { -+ ret = PTR_ERR(exe_pathname); -+ goto exit; -+ } -+ -+ size += KDBUS_ITEM_SIZE(strlen(exe_pathname) + 1); -+ free_page((unsigned long)exe_page); -+ } -+ -+ if (mp && (*mask & KDBUS_ATTACH_CMDLINE)) -+ size += KDBUS_ITEM_SIZE(strlen(mp->cmdline) + 1); -+ -+ if (mp && (*mask & KDBUS_ATTACH_CGROUP)) -+ size += KDBUS_ITEM_SIZE(strlen(mp->cgroup) + 1); -+ -+ if (mp && (*mask & KDBUS_ATTACH_CAPS)) -+ size += KDBUS_ITEM_SIZE(sizeof(mp->caps)); -+ -+ if (mp && (*mask & KDBUS_ATTACH_SECLABEL)) -+ size += KDBUS_ITEM_SIZE(strlen(mp->seclabel) + 1); -+ -+ if (mp && (*mask & KDBUS_ATTACH_AUDIT)) -+ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_audit)); -+ -+ /* connection metadata */ -+ -+ if (mc && (*mask & KDBUS_ATTACH_NAMES)) -+ size += mc->owned_names_size; -+ -+ if (mc && (*mask & KDBUS_ATTACH_CONN_DESCRIPTION)) -+ size += KDBUS_ITEM_SIZE(strlen(mc->conn_description) + 1); -+ -+ if (mc && (*mask & KDBUS_ATTACH_TIMESTAMP)) -+ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_timestamp)); -+ -+exit: -+ *sz = size; -+ -+ return ret; -+} -+ -+static int kdbus_meta_push_kvec(struct kvec *kvec, -+ struct kdbus_item_header *hdr, -+ u64 type, void *payload, -+ size_t payload_size, u64 *size) -+{ -+ hdr->type = type; -+ hdr->size = KDBUS_ITEM_HEADER_SIZE + payload_size; -+ kdbus_kvec_set(kvec++, hdr, sizeof(*hdr), size); -+ kdbus_kvec_set(kvec++, payload, payload_size, size); -+ return 2 + !!kdbus_kvec_pad(kvec++, size); -+} -+ -+/* This is equivalent to from_kuid_munged(), but maps INVALID_UID to itself */ -+static uid_t kdbus_from_kuid_keep(kuid_t uid) -+{ -+ return uid_valid(uid) ? -+ from_kuid_munged(current_user_ns(), uid) : ((uid_t)-1); -+} -+ -+/* This is equivalent to from_kgid_munged(), but maps INVALID_GID to itself */ -+static gid_t kdbus_from_kgid_keep(kgid_t gid) -+{ -+ return gid_valid(gid) ? -+ from_kgid_munged(current_user_ns(), gid) : ((gid_t)-1); -+} -+ -+/** -+ * kdbus_meta_export() - export information from metadata into a slice -+ * @mp: Process metadata, or NULL -+ * @mc: Connection metadata, or NULL -+ * @mask: Mask of KDBUS_ATTACH_* flags to export -+ * @slice: The slice to export to -+ * @offset: The offset inside @slice to write to -+ * @real_size: The real size the metadata consumed -+ * -+ * This function exports information from metadata into @slice at offset -+ * @offset inside that slice. Only information that is requested in @mask -+ * and that has been collected before is exported. -+ * -+ * In order to make sure not to write out of bounds, @mask must be the same -+ * value that was previously returned from kdbus_meta_export_prepare(). The -+ * function will, however, not necessarily write as many bytes as returned by -+ * kdbus_meta_export_prepare(); depending on the namespaces in question, it -+ * might use up less than that. -+ * -+ * All information will be translated using the current namespaces. -+ * -+ * Return: 0 on success, negative error number otherwise. -+ */ -+int kdbus_meta_export(struct kdbus_meta_proc *mp, -+ struct kdbus_meta_conn *mc, -+ u64 mask, -+ struct kdbus_pool_slice *slice, -+ off_t offset, -+ size_t *real_size) -+{ -+ struct user_namespace *user_ns = current_user_ns(); -+ struct kdbus_item_header item_hdr[13], *hdr; -+ char *exe_pathname = NULL; -+ struct kdbus_creds creds; -+ struct kdbus_pids pids; -+ void *exe_page = NULL; -+ struct kvec kvec[40]; -+ u64 *auxgrps = NULL; -+ size_t cnt = 0; -+ u64 size = 0; -+ int ret = 0; -+ -+ hdr = &item_hdr[0]; -+ -+ /* -+ * TODO: We currently have no sane way of translating a set of caps -+ * between different user namespaces. Until that changes, we have -+ * to drop such items. -+ */ -+ if (mp && mp->caps_namespace != user_ns) -+ mask &= ~KDBUS_ATTACH_CAPS; -+ -+ if (mask == 0) { -+ *real_size = 0; -+ return 0; -+ } -+ -+ /* process metadata */ -+ -+ if (mp && (mask & KDBUS_ATTACH_CREDS)) { -+ creds.uid = kdbus_from_kuid_keep(mp->uid); -+ creds.euid = kdbus_from_kuid_keep(mp->euid); -+ creds.suid = kdbus_from_kuid_keep(mp->suid); -+ creds.fsuid = kdbus_from_kuid_keep(mp->fsuid); -+ creds.gid = kdbus_from_kgid_keep(mp->gid); -+ creds.egid = kdbus_from_kgid_keep(mp->egid); -+ creds.sgid = kdbus_from_kgid_keep(mp->sgid); -+ creds.fsgid = kdbus_from_kgid_keep(mp->fsgid); -+ -+ cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, KDBUS_ITEM_CREDS, -+ &creds, sizeof(creds), &size); -+ } -+ -+ if (mp && (mask & KDBUS_ATTACH_PIDS)) { -+ pids.pid = pid_vnr(mp->tgid); -+ pids.tid = pid_vnr(mp->pid); -+ pids.ppid = pid_vnr(mp->ppid); -+ -+ cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, KDBUS_ITEM_PIDS, -+ &pids, sizeof(pids), &size); -+ } -+ -+ if (mp && (mask & KDBUS_ATTACH_AUXGROUPS)) { -+ size_t payload_size = mp->n_auxgrps * sizeof(u64); -+ int i; -+ -+ auxgrps = kmalloc(payload_size, GFP_KERNEL); -+ if (!auxgrps) { -+ ret = -ENOMEM; -+ goto exit; -+ } -+ -+ for (i = 0; i < mp->n_auxgrps; i++) -+ auxgrps[i] = from_kgid_munged(user_ns, mp->auxgrps[i]); -+ -+ cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, -+ KDBUS_ITEM_AUXGROUPS, -+ auxgrps, payload_size, &size); -+ } -+ -+ if (mp && (mask & KDBUS_ATTACH_TID_COMM)) -+ cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, -+ KDBUS_ITEM_TID_COMM, mp->tid_comm, -+ strlen(mp->tid_comm) + 1, &size); -+ -+ if (mp && (mask & KDBUS_ATTACH_PID_COMM)) -+ cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, -+ KDBUS_ITEM_PID_COMM, mp->pid_comm, -+ strlen(mp->pid_comm) + 1, &size); -+ -+ if (mp && (mask & KDBUS_ATTACH_EXE)) { -+ struct path p; -+ -+ /* -+ * TODO: We need access to __d_path() so we can write the path -+ * relative to conn->root_path. Once upstream, we need -+ * EXPORT_SYMBOL(__d_path) or an equivalent of d_path() that -+ * takes the root path directly. Until then, we drop this item -+ * if the root-paths differ. -+ */ -+ -+ get_fs_root(current->fs, &p); -+ if (path_equal(&p, &mp->root_path)) { -+ exe_page = (void *)__get_free_page(GFP_TEMPORARY); -+ if (!exe_page) { -+ path_put(&p); -+ ret = -ENOMEM; -+ goto exit; -+ } -+ -+ exe_pathname = d_path(&mp->exe_path, exe_page, -+ PAGE_SIZE); -+ if (IS_ERR(exe_pathname)) { -+ path_put(&p); -+ ret = PTR_ERR(exe_pathname); -+ goto exit; -+ } -+ -+ cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, -+ KDBUS_ITEM_EXE, -+ exe_pathname, -+ strlen(exe_pathname) + 1, -+ &size); -+ } -+ path_put(&p); -+ } -+ -+ if (mp && (mask & KDBUS_ATTACH_CMDLINE)) -+ cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, -+ KDBUS_ITEM_CMDLINE, mp->cmdline, -+ strlen(mp->cmdline) + 1, &size); -+ -+ if (mp && (mask & KDBUS_ATTACH_CGROUP)) -+ cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, -+ KDBUS_ITEM_CGROUP, mp->cgroup, -+ strlen(mp->cgroup) + 1, &size); -+ -+ if (mp && (mask & KDBUS_ATTACH_CAPS)) -+ cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, -+ KDBUS_ITEM_CAPS, &mp->caps, -+ sizeof(mp->caps), &size); -+ -+ if (mp && (mask & KDBUS_ATTACH_SECLABEL)) -+ cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, -+ KDBUS_ITEM_SECLABEL, mp->seclabel, -+ strlen(mp->seclabel) + 1, &size); -+ -+ if (mp && (mask & KDBUS_ATTACH_AUDIT)) { -+ struct kdbus_audit a = { -+ .loginuid = from_kuid(user_ns, mp->audit_loginuid), -+ .sessionid = mp->audit_sessionid, -+ }; -+ -+ cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, KDBUS_ITEM_AUDIT, -+ &a, sizeof(a), &size); -+ } -+ -+ /* connection metadata */ -+ -+ if (mc && (mask & KDBUS_ATTACH_NAMES)) -+ kdbus_kvec_set(&kvec[cnt++], mc->owned_names_items, -+ mc->owned_names_size, &size); -+ -+ if (mc && (mask & KDBUS_ATTACH_CONN_DESCRIPTION)) -+ cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, -+ KDBUS_ITEM_CONN_DESCRIPTION, -+ mc->conn_description, -+ strlen(mc->conn_description) + 1, -+ &size); -+ -+ if (mc && (mask & KDBUS_ATTACH_TIMESTAMP)) -+ cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, -+ KDBUS_ITEM_TIMESTAMP, &mc->ts, -+ sizeof(mc->ts), &size); -+ -+ ret = kdbus_pool_slice_copy_kvec(slice, offset, kvec, cnt, size); -+ *real_size = size; -+ -+exit: -+ kfree(auxgrps); -+ -+ if (exe_page) -+ free_page((unsigned long)exe_page); -+ -+ return ret; -+} -+ -+/** -+ * kdbus_meta_calc_attach_flags() - calculate attach flags for a sender -+ * and a receiver -+ * @sender: Sending connection -+ * @receiver: Receiving connection -+ * -+ * Return: the attach flags both the sender and the receiver have opted-in -+ * for. -+ */ -+u64 kdbus_meta_calc_attach_flags(const struct kdbus_conn *sender, -+ const struct kdbus_conn *receiver) -+{ -+ return atomic64_read(&sender->attach_flags_send) & -+ atomic64_read(&receiver->attach_flags_recv); -+} -diff --git a/ipc/kdbus/metadata.h b/ipc/kdbus/metadata.h -new file mode 100644 -index 000000000000..42c942b34d2c ---- /dev/null -+++ b/ipc/kdbus/metadata.h -@@ -0,0 +1,57 @@ -+/* -+ * Copyright (C) 2013-2015 Kay Sievers -+ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> -+ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> -+ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> -+ * Copyright (C) 2013-2015 Linux Foundation -+ * Copyright (C) 2014-2015 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. -+ */ -+ -+#ifndef __KDBUS_METADATA_H -+#define __KDBUS_METADATA_H -+ -+#include <linux/kernel.h> -+ -+struct kdbus_conn; -+struct kdbus_kmsg; -+struct kdbus_pool_slice; -+ -+struct kdbus_meta_proc; -+struct kdbus_meta_conn; -+ -+extern unsigned long long kdbus_meta_attach_mask; -+ -+struct kdbus_meta_proc *kdbus_meta_proc_new(void); -+struct kdbus_meta_proc *kdbus_meta_proc_ref(struct kdbus_meta_proc *mp); -+struct kdbus_meta_proc *kdbus_meta_proc_unref(struct kdbus_meta_proc *mp); -+int kdbus_meta_proc_collect(struct kdbus_meta_proc *mp, u64 what); -+int kdbus_meta_proc_fake(struct kdbus_meta_proc *mp, -+ const struct kdbus_creds *creds, -+ const struct kdbus_pids *pids, -+ const char *seclabel); -+ -+struct kdbus_meta_conn *kdbus_meta_conn_new(void); -+struct kdbus_meta_conn *kdbus_meta_conn_ref(struct kdbus_meta_conn *mc); -+struct kdbus_meta_conn *kdbus_meta_conn_unref(struct kdbus_meta_conn *mc); -+int kdbus_meta_conn_collect(struct kdbus_meta_conn *mc, -+ struct kdbus_kmsg *kmsg, -+ struct kdbus_conn *conn, -+ u64 what); -+ -+int kdbus_meta_export_prepare(struct kdbus_meta_proc *mp, -+ struct kdbus_meta_conn *mc, -+ u64 *mask, size_t *sz); -+int kdbus_meta_export(struct kdbus_meta_proc *mp, -+ struct kdbus_meta_conn *mc, -+ u64 mask, -+ struct kdbus_pool_slice *slice, -+ off_t offset, size_t *real_size); -+u64 kdbus_meta_calc_attach_flags(const struct kdbus_conn *sender, -+ const struct kdbus_conn *receiver); -+ -+#endif --- -2.4.3 - - -From d0b41f61f10c0844e6b9283be5a1cb49f099369f Mon Sep 17 00:00:00 2001 -From: Daniel Mack <daniel@zonque.org> -Date: Thu, 11 Sep 2014 18:59:16 +0200 -Subject: [PATCH 008/132] kdbus: add code for notifications and matches - -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. - -Signed-off-by: Daniel Mack <daniel@zonque.org> -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Djalal Harouni <tixxdz@opendz.org> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - ipc/kdbus/match.c | 559 +++++++++++++++++++++++++++++++++++++++++++++++++++++ - ipc/kdbus/match.h | 35 ++++ - ipc/kdbus/notify.c | 248 ++++++++++++++++++++++++ - ipc/kdbus/notify.h | 30 +++ - 4 files changed, 872 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 - -diff --git a/ipc/kdbus/match.c b/ipc/kdbus/match.c -new file mode 100644 -index 000000000000..30cec1ca819f ---- /dev/null -+++ b/ipc/kdbus/match.c -@@ -0,0 +1,559 @@ -+/* -+ * Copyright (C) 2013-2015 Kay Sievers -+ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> -+ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> -+ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> -+ * Copyright (C) 2013-2015 Linux Foundation -+ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> -+ * -+ * 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 "handle.h" -+#include "item.h" -+#include "match.h" -+#include "message.h" -+#include "names.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) -+{ -+ if (!rule) -+ return; -+ -+ 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; -+ -+ if (!entry) -+ return; -+ -+ 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; -+ -+ if (!mdb) -+ return; -+ -+ list_for_each_entry_safe(entry, tmp, &mdb->entries_list, list_entry) -+ kdbus_match_entry_free(entry); -+ -+ 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; -+ -+ if (conn_src) -+ lockdep_assert_held(&conn_src->ep->bus->name_registry->rwlock); -+ -+ /* -+ * 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) { -+ /* 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; -+ } -+ } else { -+ /* 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; -+ } -+ } -+ } -+ -+ 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. -+ * -+ * The caller must hold the registry lock of conn_src->ep->bus, in case conn_src -+ * is non-NULL. -+ * -+ * 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, -+ u64 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 : -EBADSLT; -+} -+ -+/** -+ * kdbus_cmd_match_add() - handle KDBUS_CMD_MATCH_ADD -+ * @conn: connection to operate on -+ * @argp: command payload -+ * -+ * 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 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 error code on failure. -+ */ -+int kdbus_cmd_match_add(struct kdbus_conn *conn, void __user *argp) -+{ -+ struct kdbus_match_db *mdb = conn->match_db; -+ struct kdbus_match_entry *entry = NULL; -+ struct kdbus_cmd_match *cmd; -+ struct kdbus_item *item; -+ int ret; -+ -+ struct kdbus_arg argv[] = { -+ { .type = KDBUS_ITEM_NEGOTIATE }, -+ { .type = KDBUS_ITEM_BLOOM_MASK, .multiple = true }, -+ { .type = KDBUS_ITEM_NAME, .multiple = true }, -+ { .type = KDBUS_ITEM_ID, .multiple = true }, -+ { .type = KDBUS_ITEM_NAME_ADD, .multiple = true }, -+ { .type = KDBUS_ITEM_NAME_REMOVE, .multiple = true }, -+ { .type = KDBUS_ITEM_NAME_CHANGE, .multiple = true }, -+ { .type = KDBUS_ITEM_ID_ADD, .multiple = true }, -+ { .type = KDBUS_ITEM_ID_REMOVE, .multiple = true }, -+ }; -+ struct kdbus_args args = { -+ .allowed_flags = KDBUS_FLAG_NEGOTIATE | -+ KDBUS_MATCH_REPLACE, -+ .argv = argv, -+ .argc = ARRAY_SIZE(argv), -+ }; -+ -+ if (!kdbus_conn_is_ordinary(conn)) -+ return -EOPNOTSUPP; -+ -+ ret = kdbus_args_parse(&args, argp, &cmd); -+ if (ret != 0) -+ return ret; -+ -+ entry = kzalloc(sizeof(*entry), GFP_KERNEL); -+ if (!entry) { -+ ret = -ENOMEM; -+ goto exit; -+ } -+ -+ 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; -+ goto exit; -+ } -+ -+ rule->type = item->type; -+ INIT_LIST_HEAD(&rule->rules_entry); -+ -+ switch (item->type) { -+ 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; -+ } -+ -+ rule->bloom_mask.generations = generations; -+ break; -+ } -+ -+ case KDBUS_ITEM_NAME: -+ 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; -+ -+ 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; -+ } -+ -+ if (ret < 0) { -+ kdbus_match_rule_free(rule); -+ goto exit; -+ } -+ -+ 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; -+ } else { -+ list_add_tail(&entry->list_entry, &mdb->entries_list); -+ entry = NULL; -+ } -+ -+ up_write(&mdb->mdb_rwlock); -+ -+exit: -+ kdbus_match_entry_free(entry); -+ return kdbus_args_clear(&args, ret); -+} -+ -+/** -+ * kdbus_cmd_match_remove() - handle KDBUS_CMD_MATCH_REMOVE -+ * @conn: connection to operate on -+ * @argp: command payload -+ * -+ * Return: 0 on success, negative error code on failure. -+ */ -+int kdbus_cmd_match_remove(struct kdbus_conn *conn, void __user *argp) -+{ -+ struct kdbus_cmd_match *cmd; -+ int ret; -+ -+ struct kdbus_arg argv[] = { -+ { .type = KDBUS_ITEM_NEGOTIATE }, -+ }; -+ struct kdbus_args args = { -+ .allowed_flags = KDBUS_FLAG_NEGOTIATE, -+ .argv = argv, -+ .argc = ARRAY_SIZE(argv), -+ }; -+ -+ if (!kdbus_conn_is_ordinary(conn)) -+ return -EOPNOTSUPP; -+ -+ ret = kdbus_args_parse(&args, argp, &cmd); -+ if (ret != 0) -+ return ret; -+ -+ down_write(&conn->match_db->mdb_rwlock); -+ ret = kdbus_match_db_remove_unlocked(conn->match_db, cmd->cookie); -+ up_write(&conn->match_db->mdb_rwlock); -+ -+ return kdbus_args_clear(&args, ret); -+} -diff --git a/ipc/kdbus/match.h b/ipc/kdbus/match.h -new file mode 100644 -index 000000000000..ea4292938deb ---- /dev/null -+++ b/ipc/kdbus/match.h -@@ -0,0 +1,35 @@ -+/* -+ * Copyright (C) 2013-2015 Kay Sievers -+ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> -+ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> -+ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> -+ * Copyright (C) 2013-2015 Linux Foundation -+ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> -+ * -+ * 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); -+ -+int kdbus_cmd_match_add(struct kdbus_conn *conn, void __user *argp); -+int kdbus_cmd_match_remove(struct kdbus_conn *conn, void __user *argp); -+ -+#endif -diff --git a/ipc/kdbus/notify.c b/ipc/kdbus/notify.c -new file mode 100644 -index 000000000000..e4a454222f09 ---- /dev/null -+++ b/ipc/kdbus/notify.c -@@ -0,0 +1,248 @@ -+/* -+ * Copyright (C) 2013-2015 Kay Sievers -+ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> -+ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> -+ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> -+ * Copyright (C) 2013-2015 Linux Foundation -+ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> -+ * -+ * 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/module.h> -+#include <linux/mutex.h> -+#include <linux/spinlock.h> -+#include <linux/sched.h> -+#include <linux/slab.h> -+ -+#include "bus.h" -+#include "connection.h" -+#include "domain.h" -+#include "endpoint.h" -+#include "item.h" -+#include "message.h" -+#include "notify.h" -+ -+static inline void kdbus_notify_add_tail(struct kdbus_kmsg *kmsg, -+ struct kdbus_bus *bus) -+{ -+ spin_lock(&bus->notify_lock); -+ list_add_tail(&kmsg->notify_entry, &bus->notify_list); -+ spin_unlock(&bus->notify_lock); -+} -+ -+static int kdbus_notify_reply(struct kdbus_bus *bus, u64 id, -+ u64 cookie, u64 msg_type) -+{ -+ struct kdbus_kmsg *kmsg = NULL; -+ -+ WARN_ON(id == 0); -+ -+ kmsg = kdbus_kmsg_new(bus, 0); -+ if (IS_ERR(kmsg)) -+ return PTR_ERR(kmsg); -+ -+ /* -+ * a kernel-generated notification can only contain one -+ * struct kdbus_item, so make a shortcut here for -+ * faster lookup in the match db. -+ */ -+ kmsg->notify_type = msg_type; -+ kmsg->msg.flags = KDBUS_MSG_SIGNAL; -+ kmsg->msg.dst_id = id; -+ kmsg->msg.src_id = KDBUS_SRC_ID_KERNEL; -+ kmsg->msg.payload_type = KDBUS_PAYLOAD_KERNEL; -+ kmsg->msg.cookie_reply = cookie; -+ kmsg->msg.items[0].type = msg_type; -+ -+ kdbus_notify_add_tail(kmsg, bus); -+ -+ return 0; -+} -+ -+/** -+ * kdbus_notify_reply_timeout() - queue a timeout reply -+ * @bus: Bus which queues the messages -+ * @id: The destination's connection ID -+ * @cookie: The cookie to set in the reply. -+ * -+ * Queues a message that has a KDBUS_ITEM_REPLY_TIMEOUT item attached. -+ * -+ * Return: 0 on success, negative errno on failure. -+ */ -+int kdbus_notify_reply_timeout(struct kdbus_bus *bus, u64 id, u64 cookie) -+{ -+ return kdbus_notify_reply(bus, id, cookie, KDBUS_ITEM_REPLY_TIMEOUT); -+} -+ -+/** -+ * kdbus_notify_reply_dead() - queue a 'dead' reply -+ * @bus: Bus which queues the messages -+ * @id: The destination's connection ID -+ * @cookie: The cookie to set in the reply. -+ * -+ * Queues a message that has a KDBUS_ITEM_REPLY_DEAD item attached. -+ * -+ * Return: 0 on success, negative errno on failure. -+ */ -+int kdbus_notify_reply_dead(struct kdbus_bus *bus, u64 id, u64 cookie) -+{ -+ return kdbus_notify_reply(bus, id, cookie, KDBUS_ITEM_REPLY_DEAD); -+} -+ -+/** -+ * kdbus_notify_name_change() - queue a notification about a name owner change -+ * @bus: Bus which queues the messages -+ * @type: The type if the notification; KDBUS_ITEM_NAME_ADD, -+ * KDBUS_ITEM_NAME_CHANGE or KDBUS_ITEM_NAME_REMOVE -+ * @old_id: The id of the connection that used to own the name -+ * @new_id: The id of the new owner connection -+ * @old_flags: The flags to pass in the KDBUS_ITEM flags field for -+ * the old owner -+ * @new_flags: The flags to pass in the KDBUS_ITEM flags field for -+ * the new owner -+ * @name: The name that was removed or assigned to a new owner -+ * -+ * Return: 0 on success, negative errno on failure. -+ */ -+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) -+{ -+ struct kdbus_kmsg *kmsg = NULL; -+ size_t name_len, extra_size; -+ -+ name_len = strlen(name) + 1; -+ extra_size = sizeof(struct kdbus_notify_name_change) + name_len; -+ kmsg = kdbus_kmsg_new(bus, extra_size); -+ if (IS_ERR(kmsg)) -+ return PTR_ERR(kmsg); -+ -+ kmsg->msg.flags = KDBUS_MSG_SIGNAL; -+ kmsg->msg.dst_id = KDBUS_DST_ID_BROADCAST; -+ kmsg->msg.src_id = KDBUS_SRC_ID_KERNEL; -+ kmsg->msg.payload_type = KDBUS_PAYLOAD_KERNEL; -+ kmsg->notify_type = type; -+ kmsg->notify_old_id = old_id; -+ kmsg->notify_new_id = new_id; -+ kmsg->msg.items[0].type = type; -+ kmsg->msg.items[0].name_change.old_id.id = old_id; -+ kmsg->msg.items[0].name_change.old_id.flags = old_flags; -+ kmsg->msg.items[0].name_change.new_id.id = new_id; -+ kmsg->msg.items[0].name_change.new_id.flags = new_flags; -+ memcpy(kmsg->msg.items[0].name_change.name, name, name_len); -+ kmsg->notify_name = kmsg->msg.items[0].name_change.name; -+ -+ kdbus_notify_add_tail(kmsg, bus); -+ -+ return 0; -+} -+ -+/** -+ * kdbus_notify_id_change() - queue a notification about a unique ID change -+ * @bus: Bus which queues the messages -+ * @type: The type if the notification; KDBUS_ITEM_ID_ADD or -+ * KDBUS_ITEM_ID_REMOVE -+ * @id: The id of the connection that was added or removed -+ * @flags: The flags to pass in the KDBUS_ITEM flags field -+ * -+ * Return: 0 on success, negative errno on failure. -+ */ -+int kdbus_notify_id_change(struct kdbus_bus *bus, u64 type, u64 id, u64 flags) -+{ -+ struct kdbus_kmsg *kmsg = NULL; -+ -+ kmsg = kdbus_kmsg_new(bus, sizeof(struct kdbus_notify_id_change)); -+ if (IS_ERR(kmsg)) -+ return PTR_ERR(kmsg); -+ -+ kmsg->msg.flags = KDBUS_MSG_SIGNAL; -+ kmsg->msg.dst_id = KDBUS_DST_ID_BROADCAST; -+ kmsg->msg.src_id = KDBUS_SRC_ID_KERNEL; -+ kmsg->msg.payload_type = KDBUS_PAYLOAD_KERNEL; -+ kmsg->notify_type = type; -+ -+ switch (type) { -+ case KDBUS_ITEM_ID_ADD: -+ kmsg->notify_new_id = id; -+ break; -+ -+ case KDBUS_ITEM_ID_REMOVE: -+ kmsg->notify_old_id = id; -+ break; -+ -+ default: -+ BUG(); -+ } -+ -+ kmsg->msg.items[0].type = type; -+ kmsg->msg.items[0].id_change.id = id; -+ kmsg->msg.items[0].id_change.flags = flags; -+ -+ kdbus_notify_add_tail(kmsg, bus); -+ -+ return 0; -+} -+ -+/** -+ * kdbus_notify_flush() - send a list of collected messages -+ * @bus: Bus which queues the messages -+ * -+ * The list is empty after sending the messages. -+ */ -+void kdbus_notify_flush(struct kdbus_bus *bus) -+{ -+ LIST_HEAD(notify_list); -+ struct kdbus_kmsg *kmsg, *tmp; -+ -+ mutex_lock(&bus->notify_flush_lock); -+ down_read(&bus->name_registry->rwlock); -+ -+ spin_lock(&bus->notify_lock); -+ list_splice_init(&bus->notify_list, ¬ify_list); -+ spin_unlock(&bus->notify_lock); -+ -+ list_for_each_entry_safe(kmsg, tmp, ¬ify_list, notify_entry) { -+ kdbus_meta_conn_collect(kmsg->conn_meta, kmsg, NULL, -+ KDBUS_ATTACH_TIMESTAMP); -+ -+ if (kmsg->msg.dst_id != KDBUS_DST_ID_BROADCAST) { -+ struct kdbus_conn *conn; -+ -+ conn = kdbus_bus_find_conn_by_id(bus, kmsg->msg.dst_id); -+ if (conn) { -+ kdbus_bus_eavesdrop(bus, NULL, kmsg); -+ kdbus_conn_entry_insert(NULL, conn, kmsg, NULL); -+ kdbus_conn_unref(conn); -+ } -+ } else { -+ kdbus_bus_broadcast(bus, NULL, kmsg); -+ } -+ -+ list_del(&kmsg->notify_entry); -+ kdbus_kmsg_free(kmsg); -+ } -+ -+ up_read(&bus->name_registry->rwlock); -+ mutex_unlock(&bus->notify_flush_lock); -+} -+ -+/** -+ * kdbus_notify_free() - free a list of collected messages -+ * @bus: Bus which queues the messages -+ */ -+void kdbus_notify_free(struct kdbus_bus *bus) -+{ -+ struct kdbus_kmsg *kmsg, *tmp; -+ -+ list_for_each_entry_safe(kmsg, tmp, &bus->notify_list, notify_entry) { -+ list_del(&kmsg->notify_entry); -+ kdbus_kmsg_free(kmsg); -+ } -+} -diff --git a/ipc/kdbus/notify.h b/ipc/kdbus/notify.h -new file mode 100644 -index 000000000000..03df464cb735 ---- /dev/null -+++ b/ipc/kdbus/notify.h -@@ -0,0 +1,30 @@ -+/* -+ * Copyright (C) 2013-2015 Kay Sievers -+ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> -+ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> -+ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> -+ * Copyright (C) 2013-2015 Linux Foundation -+ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> -+ * -+ * 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 --- -2.4.3 - - -From 5e6c4f5ab4e46539339964986574f18e52758c7b Mon Sep 17 00:00:00 2001 -From: Daniel Mack <daniel@zonque.org> -Date: Thu, 11 Sep 2014 18:59:39 +0200 -Subject: [PATCH 009/132] kdbus: add code for buses, domains and endpoints - -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 are isolated from 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 /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. - -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 kdbus(7), kdbus.bus(7), kdbus.endpoint(7) and kdbus.fs(7) -for more details. - -Signed-off-by: Daniel Mack <daniel@zonque.org> -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Djalal Harouni <tixxdz@opendz.org> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - ipc/kdbus/bus.c | 560 +++++++++++++++++++++++++++++++++++++++++++++++++++ - ipc/kdbus/bus.h | 101 ++++++++++ - ipc/kdbus/domain.c | 296 +++++++++++++++++++++++++++ - ipc/kdbus/domain.h | 77 +++++++ - ipc/kdbus/endpoint.c | 275 +++++++++++++++++++++++++ - ipc/kdbus/endpoint.h | 67 ++++++ - 6 files changed, 1376 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 - -diff --git a/ipc/kdbus/bus.c b/ipc/kdbus/bus.c -new file mode 100644 -index 000000000000..9d0679eb59f6 ---- /dev/null -+++ b/ipc/kdbus/bus.c -@@ -0,0 +1,560 @@ -+/* -+ * Copyright (C) 2013-2015 Kay Sievers -+ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> -+ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> -+ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> -+ * Copyright (C) 2013-2015 Linux Foundation -+ * Copyright (C) 2014-2015 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/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 <linux/uio.h> -+ -+#include "bus.h" -+#include "notify.h" -+#include "connection.h" -+#include "domain.h" -+#include "endpoint.h" -+#include "handle.h" -+#include "item.h" -+#include "match.h" -+#include "message.h" -+#include "metadata.h" -+#include "names.h" -+#include "policy.h" -+#include "util.h" -+ -+static void kdbus_bus_free(struct kdbus_node *node) -+{ -+ struct kdbus_bus *bus = container_of(node, struct kdbus_bus, node); -+ -+ WARN_ON(!list_empty(&bus->monitors_list)); -+ WARN_ON(!hash_empty(bus->conn_hash)); -+ -+ kdbus_notify_free(bus); -+ -+ kdbus_user_unref(bus->creator); -+ kdbus_name_registry_free(bus->name_registry); -+ kdbus_domain_unref(bus->domain); -+ kdbus_policy_db_clear(&bus->policy_db); -+ kdbus_meta_proc_unref(bus->creator_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->creator->buses); -+} -+ -+static struct kdbus_bus *kdbus_bus_new(struct kdbus_domain *domain, -+ const char *name, -+ struct kdbus_bloom_parameter *bloom, -+ const u64 *pattach_owner, -+ const u64 *pattach_recv, -+ u64 flags, kuid_t uid, kgid_t gid) -+{ -+ struct kdbus_bus *b; -+ u64 attach_owner; -+ u64 attach_recv; -+ int ret; -+ -+ if (bloom->size < 8 || bloom->size > KDBUS_BUS_BLOOM_MAX_SIZE || -+ !KDBUS_IS_ALIGNED8(bloom->size) || bloom->n_hash < 1) -+ return ERR_PTR(-EINVAL); -+ -+ ret = kdbus_sanitize_attach_flags(pattach_recv ? *pattach_recv : 0, -+ &attach_recv); -+ if (ret < 0) -+ return ERR_PTR(ret); -+ -+ ret = kdbus_sanitize_attach_flags(pattach_owner ? *pattach_owner : 0, -+ &attach_owner); -+ if (ret < 0) -+ return ERR_PTR(ret); -+ -+ ret = kdbus_verify_uid_prefix(name, domain->user_namespace, uid); -+ if (ret < 0) -+ return ERR_PTR(ret); -+ -+ 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; -+ -+ if (flags & (KDBUS_MAKE_ACCESS_GROUP | KDBUS_MAKE_ACCESS_WORLD)) -+ b->node.mode |= S_IRGRP | S_IXGRP; -+ if (flags & KDBUS_MAKE_ACCESS_WORLD) -+ b->node.mode |= S_IROTH | S_IXOTH; -+ -+ b->id = atomic64_inc_return(&domain->last_id); -+ b->bus_flags = flags; -+ b->attach_flags_req = attach_recv; -+ b->attach_flags_owner = attach_owner; -+ generate_random_uuid(b->id128); -+ b->bloom = *bloom; -+ b->domain = kdbus_domain_ref(domain); -+ -+ kdbus_policy_db_init(&b->policy_db); -+ -+ 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); -+ -+ ret = kdbus_node_link(&b->node, &domain->node, name); -+ if (ret < 0) -+ goto exit_unref; -+ -+ /* cache the metadata/credentials of the creator */ -+ b->creator_meta = kdbus_meta_proc_new(); -+ if (IS_ERR(b->creator_meta)) { -+ ret = PTR_ERR(b->creator_meta); -+ b->creator_meta = NULL; -+ goto exit_unref; -+ } -+ -+ ret = kdbus_meta_proc_collect(b->creator_meta, -+ KDBUS_ATTACH_CREDS | -+ KDBUS_ATTACH_PIDS | -+ KDBUS_ATTACH_AUXGROUPS | -+ 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; -+ } -+ -+ /* -+ * Bus-limits of the creator are accounted on its real UID, just like -+ * all other per-user limits. -+ */ -+ b->creator = kdbus_user_lookup(domain, current_uid()); -+ if (IS_ERR(b->creator)) { -+ ret = PTR_ERR(b->creator); -+ b->creator = 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_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 let the message -+ * pass. -+ * -+ * The caller must hold the name-registry lock of @bus. -+ */ -+void kdbus_bus_broadcast(struct kdbus_bus *bus, -+ struct kdbus_conn *conn_src, -+ struct kdbus_kmsg *kmsg) -+{ -+ struct kdbus_conn *conn_dst; -+ unsigned int i; -+ int ret; -+ -+ lockdep_assert_held(&bus->name_registry->rwlock); -+ -+ /* -+ * Make sure broadcast are queued on monitors before we send it out to -+ * anyone else. Otherwise, connections might react to broadcasts before -+ * the monitor gets the broadcast queued. In the worst case, the -+ * monitor sees a reaction to the broadcast before the broadcast itself. -+ * We don't give ordering guarantees across connections (and monitors -+ * can re-construct order via sequence numbers), but we should at least -+ * try to avoid re-ordering for monitors. -+ */ -+ kdbus_bus_eavesdrop(bus, conn_src, kmsg); -+ -+ down_read(&bus->conn_rwlock); -+ hash_for_each(bus->conn_hash, i, conn_dst, hentry) { -+ if (conn_dst->id == kmsg->msg.src_id) -+ continue; -+ if (!kdbus_conn_is_ordinary(conn_dst)) -+ continue; -+ -+ /* -+ * Check if there is a match for the kmsg object in -+ * the destination connection match db -+ */ -+ if (!kdbus_match_db_match_kmsg(conn_dst->match_db, conn_src, -+ kmsg)) -+ continue; -+ -+ if (conn_src) { -+ u64 attach_flags; -+ -+ /* -+ * Anyone can send broadcasts, as they have no -+ * destination. But a receiver needs TALK access to -+ * the sender in order to receive broadcasts. -+ */ -+ if (!kdbus_conn_policy_talk(conn_dst, NULL, conn_src)) -+ continue; -+ -+ attach_flags = kdbus_meta_calc_attach_flags(conn_src, -+ conn_dst); -+ -+ /* -+ * Keep sending messages even if we cannot acquire the -+ * requested metadata. It's up to the receiver to drop -+ * messages that lack expected metadata. -+ */ -+ if (!conn_src->faked_meta) -+ kdbus_meta_proc_collect(kmsg->proc_meta, -+ attach_flags); -+ kdbus_meta_conn_collect(kmsg->conn_meta, kmsg, conn_src, -+ attach_flags); -+ } else { -+ /* -+ * Check if there is a policy db that prevents the -+ * destination connection from receiving this kernel -+ * notification -+ */ -+ if (!kdbus_conn_policy_see_notification(conn_dst, NULL, -+ kmsg)) -+ continue; -+ } -+ -+ ret = kdbus_conn_entry_insert(conn_src, conn_dst, kmsg, NULL); -+ if (ret < 0) -+ kdbus_conn_lost_message(conn_dst); -+ } -+ up_read(&bus->conn_rwlock); -+} -+ -+/** -+ * kdbus_bus_eavesdrop() - send a message to all subscribed monitors -+ * @bus: The bus the monitors are connected to -+ * @conn_src: The source connection, may be %NULL for kernel notifications -+ * @kmsg: The message to send. -+ * -+ * Send @kmsg to all monitors that are currently active on the bus. Monitors -+ * must still have matches installed in order to let the message pass. -+ * -+ * The caller must hold the name-registry lock of @bus. -+ */ -+void kdbus_bus_eavesdrop(struct kdbus_bus *bus, -+ struct kdbus_conn *conn_src, -+ struct kdbus_kmsg *kmsg) -+{ -+ struct kdbus_conn *conn_dst; -+ int ret; -+ -+ /* -+ * Monitor connections get all messages; ignore possible errors -+ * when sending messages to monitor connections. -+ */ -+ -+ lockdep_assert_held(&bus->name_registry->rwlock); -+ -+ down_read(&bus->conn_rwlock); -+ list_for_each_entry(conn_dst, &bus->monitors_list, monitor_entry) { -+ /* -+ * Collect metadata requested by the destination connection. -+ * Ignore errors, as receivers need to check metadata -+ * availability, anyway. So it's still better to send messages -+ * that lack data, than to skip it entirely. -+ */ -+ if (conn_src) { -+ u64 attach_flags; -+ -+ attach_flags = kdbus_meta_calc_attach_flags(conn_src, -+ conn_dst); -+ if (!conn_src->faked_meta) -+ kdbus_meta_proc_collect(kmsg->proc_meta, -+ attach_flags); -+ kdbus_meta_conn_collect(kmsg->conn_meta, kmsg, conn_src, -+ attach_flags); -+ } -+ -+ ret = kdbus_conn_entry_insert(conn_src, conn_dst, kmsg, NULL); -+ if (ret < 0) -+ kdbus_conn_lost_message(conn_dst); -+ } -+ up_read(&bus->conn_rwlock); -+} -+ -+/** -+ * kdbus_cmd_bus_make() - handle KDBUS_CMD_BUS_MAKE -+ * @domain: domain to operate on -+ * @argp: command payload -+ * -+ * Return: Newly created bus on success, ERR_PTR on failure. -+ */ -+struct kdbus_bus *kdbus_cmd_bus_make(struct kdbus_domain *domain, -+ void __user *argp) -+{ -+ struct kdbus_bus *bus = NULL; -+ struct kdbus_cmd *cmd; -+ struct kdbus_ep *ep = NULL; -+ int ret; -+ -+ struct kdbus_arg argv[] = { -+ { .type = KDBUS_ITEM_NEGOTIATE }, -+ { .type = KDBUS_ITEM_MAKE_NAME, .mandatory = true }, -+ { .type = KDBUS_ITEM_BLOOM_PARAMETER, .mandatory = true }, -+ { .type = KDBUS_ITEM_ATTACH_FLAGS_SEND }, -+ { .type = KDBUS_ITEM_ATTACH_FLAGS_RECV }, -+ }; -+ struct kdbus_args args = { -+ .allowed_flags = KDBUS_FLAG_NEGOTIATE | -+ KDBUS_MAKE_ACCESS_GROUP | -+ KDBUS_MAKE_ACCESS_WORLD, -+ .argv = argv, -+ .argc = ARRAY_SIZE(argv), -+ }; -+ -+ ret = kdbus_args_parse(&args, argp, &cmd); -+ if (ret < 0) -+ return ERR_PTR(ret); -+ if (ret > 0) -+ return NULL; -+ -+ bus = kdbus_bus_new(domain, -+ argv[1].item->str, &argv[2].item->bloom_parameter, -+ argv[3].item ? argv[3].item->data64 : NULL, -+ argv[4].item ? argv[4].item->data64 : NULL, -+ cmd->flags, current_euid(), current_egid()); -+ if (IS_ERR(bus)) { -+ ret = PTR_ERR(bus); -+ bus = NULL; -+ goto exit; -+ } -+ -+ if (atomic_inc_return(&bus->creator->buses) > KDBUS_USER_MAX_BUSES) { -+ atomic_dec(&bus->creator->buses); -+ ret = -EMFILE; -+ goto exit; -+ } -+ -+ if (!kdbus_node_activate(&bus->node)) { -+ atomic_dec(&bus->creator->buses); -+ ret = -ESHUTDOWN; -+ goto exit; -+ } -+ -+ ep = kdbus_ep_new(bus, "bus", cmd->flags, bus->node.uid, bus->node.gid, -+ false); -+ if (IS_ERR(ep)) { -+ ret = PTR_ERR(ep); -+ ep = NULL; -+ goto exit; -+ } -+ -+ if (!kdbus_node_activate(&ep->node)) { -+ ret = -ESHUTDOWN; -+ goto exit; -+ } -+ -+ /* -+ * Drop our own reference, effectively causing the endpoint to be -+ * deactivated and released when the parent bus is. -+ */ -+ ep = kdbus_ep_unref(ep); -+ -+exit: -+ ret = kdbus_args_clear(&args, ret); -+ if (ret < 0) { -+ if (ep) { -+ kdbus_node_deactivate(&ep->node); -+ kdbus_ep_unref(ep); -+ } -+ if (bus) { -+ kdbus_node_deactivate(&bus->node); -+ kdbus_bus_unref(bus); -+ } -+ return ERR_PTR(ret); -+ } -+ return bus; -+} -+ -+/** -+ * kdbus_cmd_bus_creator_info() - handle KDBUS_CMD_BUS_CREATOR_INFO -+ * @conn: connection to operate on -+ * @argp: command payload -+ * -+ * Return: 0 on success, negative error code on failure. -+ */ -+int kdbus_cmd_bus_creator_info(struct kdbus_conn *conn, void __user *argp) -+{ -+ struct kdbus_cmd_info *cmd; -+ struct kdbus_bus *bus = conn->ep->bus; -+ struct kdbus_pool_slice *slice = NULL; -+ struct kdbus_item_header item_hdr; -+ struct kdbus_info info = {}; -+ size_t meta_size, name_len; -+ struct kvec kvec[5]; -+ u64 hdr_size = 0; -+ u64 attach_flags; -+ size_t cnt = 0; -+ int ret; -+ -+ struct kdbus_arg argv[] = { -+ { .type = KDBUS_ITEM_NEGOTIATE }, -+ }; -+ struct kdbus_args args = { -+ .allowed_flags = KDBUS_FLAG_NEGOTIATE, -+ .argv = argv, -+ .argc = ARRAY_SIZE(argv), -+ }; -+ -+ ret = kdbus_args_parse(&args, argp, &cmd); -+ if (ret != 0) -+ return ret; -+ -+ ret = kdbus_sanitize_attach_flags(cmd->attach_flags, &attach_flags); -+ if (ret < 0) -+ goto exit; -+ -+ attach_flags &= bus->attach_flags_owner; -+ -+ ret = kdbus_meta_export_prepare(bus->creator_meta, NULL, -+ &attach_flags, &meta_size); -+ if (ret < 0) -+ goto exit; -+ -+ name_len = strlen(bus->node.name) + 1; -+ info.id = bus->id; -+ info.flags = bus->bus_flags; -+ item_hdr.type = KDBUS_ITEM_MAKE_NAME; -+ item_hdr.size = KDBUS_ITEM_HEADER_SIZE + name_len; -+ -+ kdbus_kvec_set(&kvec[cnt++], &info, sizeof(info), &hdr_size); -+ kdbus_kvec_set(&kvec[cnt++], &item_hdr, sizeof(item_hdr), &hdr_size); -+ kdbus_kvec_set(&kvec[cnt++], bus->node.name, name_len, &hdr_size); -+ cnt += !!kdbus_kvec_pad(&kvec[cnt], &hdr_size); -+ -+ slice = kdbus_pool_slice_alloc(conn->pool, hdr_size + meta_size, false); -+ if (IS_ERR(slice)) { -+ ret = PTR_ERR(slice); -+ slice = NULL; -+ goto exit; -+ } -+ -+ ret = kdbus_meta_export(bus->creator_meta, NULL, attach_flags, -+ slice, hdr_size, &meta_size); -+ if (ret < 0) -+ goto exit; -+ -+ info.size = hdr_size + meta_size; -+ -+ ret = kdbus_pool_slice_copy_kvec(slice, 0, kvec, cnt, hdr_size); -+ if (ret < 0) -+ goto exit; -+ -+ kdbus_pool_slice_publish(slice, &cmd->offset, &cmd->info_size); -+ -+ if (kdbus_member_set_user(&cmd->offset, argp, typeof(*cmd), offset) || -+ kdbus_member_set_user(&cmd->info_size, argp, -+ typeof(*cmd), info_size)) -+ ret = -EFAULT; -+ -+exit: -+ kdbus_pool_slice_release(slice); -+ -+ return kdbus_args_clear(&args, ret); -+} -diff --git a/ipc/kdbus/bus.h b/ipc/kdbus/bus.h -new file mode 100644 -index 000000000000..5bea5ef768f1 ---- /dev/null -+++ b/ipc/kdbus/bus.h -@@ -0,0 +1,101 @@ -+/* -+ * Copyright (C) 2013-2015 Kay Sievers -+ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> -+ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> -+ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> -+ * Copyright (C) 2013-2015 Linux Foundation -+ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> -+ * -+ * 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_BUS_H -+#define __KDBUS_BUS_H -+ -+#include <linux/hashtable.h> -+#include <linux/list.h> -+#include <linux/mutex.h> -+#include <linux/rwsem.h> -+#include <linux/spinlock.h> -+#include <uapi/linux/kdbus.h> -+ -+#include "metadata.h" -+#include "names.h" -+#include "node.h" -+#include "policy.h" -+ -+struct kdbus_conn; -+struct kdbus_domain; -+struct kdbus_kmsg; -+struct kdbus_user; -+ -+/** -+ * struct kdbus_bus - bus in a domain -+ * @node: kdbus_node -+ * @id: ID of this bus in the domain -+ * @bus_flags: Simple pass-through flags from userspace to userspace -+ * @attach_flags_req: KDBUS_ATTACH_* flags required by connecting peers -+ * @attach_flags_owner: KDBUS_ATTACH_* flags of bus creator that other -+ * connections can see or query -+ * @id128: Unique random 128 bit ID of this bus -+ * @bloom: Bloom parameters -+ * @domain: Domain of this bus -+ * @creator: Creator of the bus -+ * @creator_meta: Meta information about the bus creator -+ * @policy_db: Policy database for this bus -+ * @name_registry: Name registry of this bus -+ * @conn_rwlock: Read/Write lock for all lists of child connections -+ * @conn_hash: Map of connection IDs -+ * @monitors_list: Connections that monitor this bus -+ * @notify_list: List of pending kernel-generated messages -+ * @notify_lock: Notification list lock -+ * @notify_flush_lock: Notification flushing lock -+ */ -+struct kdbus_bus { -+ struct kdbus_node node; -+ -+ /* static */ -+ u64 id; -+ u64 bus_flags; -+ u64 attach_flags_req; -+ u64 attach_flags_owner; -+ u8 id128[16]; -+ struct kdbus_bloom_parameter bloom; -+ struct kdbus_domain *domain; -+ struct kdbus_user *creator; -+ struct kdbus_meta_proc *creator_meta; -+ -+ /* protected by own locks */ -+ struct kdbus_policy_db policy_db; -+ struct kdbus_name_registry *name_registry; -+ -+ /* protected by conn_rwlock */ -+ struct rw_semaphore conn_rwlock; -+ DECLARE_HASHTABLE(conn_hash, 8); -+ struct list_head monitors_list; -+ -+ /* protected by notify_lock */ -+ struct list_head notify_list; -+ spinlock_t notify_lock; -+ struct mutex notify_flush_lock; -+}; -+ -+struct kdbus_bus *kdbus_bus_ref(struct kdbus_bus *bus); -+struct kdbus_bus *kdbus_bus_unref(struct kdbus_bus *bus); -+ -+struct kdbus_conn *kdbus_bus_find_conn_by_id(struct kdbus_bus *bus, u64 id); -+void kdbus_bus_broadcast(struct kdbus_bus *bus, -+ struct kdbus_conn *conn_src, -+ struct kdbus_kmsg *kmsg); -+void kdbus_bus_eavesdrop(struct kdbus_bus *bus, -+ struct kdbus_conn *conn_src, -+ struct kdbus_kmsg *kmsg); -+ -+struct kdbus_bus *kdbus_cmd_bus_make(struct kdbus_domain *domain, -+ void __user *argp); -+int kdbus_cmd_bus_creator_info(struct kdbus_conn *conn, void __user *argp); -+ -+#endif -diff --git a/ipc/kdbus/domain.c b/ipc/kdbus/domain.c -new file mode 100644 -index 000000000000..ac9f760c150d ---- /dev/null -+++ b/ipc/kdbus/domain.c -@@ -0,0 +1,296 @@ -+/* -+ * Copyright (C) 2013-2015 Kay Sievers -+ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> -+ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> -+ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> -+ * Copyright (C) 2013-2015 Linux Foundation -+ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> -+ * -+ * 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/idr.h> -+#include <linux/init.h> -+#include <linux/module.h> -+#include <linux/sched.h> -+#include <linux/sizes.h> -+#include <linux/slab.h> -+#include <linux/uaccess.h> -+ -+#include "bus.h" -+#include "domain.h" -+#include "handle.h" -+#include "item.h" -+#include "limits.h" -+#include "util.h" -+ -+static void kdbus_domain_control_free(struct kdbus_node *node) -+{ -+ kfree(node); -+} -+ -+static struct kdbus_node *kdbus_domain_control_new(struct kdbus_domain *domain, -+ unsigned int access) -+{ -+ struct kdbus_node *node; -+ int ret; -+ -+ node = kzalloc(sizeof(*node), GFP_KERNEL); -+ if (!node) -+ return ERR_PTR(-ENOMEM); -+ -+ kdbus_node_init(node, KDBUS_NODE_CONTROL); -+ -+ node->free_cb = kdbus_domain_control_free; -+ node->mode = domain->node.mode; -+ node->mode = S_IRUSR | S_IWUSR; -+ if (access & (KDBUS_MAKE_ACCESS_GROUP | KDBUS_MAKE_ACCESS_WORLD)) -+ node->mode |= S_IRGRP | S_IWGRP; -+ if (access & KDBUS_MAKE_ACCESS_WORLD) -+ node->mode |= S_IROTH | S_IWOTH; -+ -+ ret = kdbus_node_link(node, &domain->node, "control"); -+ if (ret < 0) -+ goto exit_free; -+ -+ return node; -+ -+exit_free: -+ kdbus_node_deactivate(node); -+ kdbus_node_unref(node); -+ return ERR_PTR(ret); -+} -+ -+static void kdbus_domain_free(struct kdbus_node *node) -+{ -+ struct kdbus_domain *domain = -+ container_of(node, struct kdbus_domain, node); -+ -+ put_user_ns(domain->user_namespace); -+ ida_destroy(&domain->user_ida); -+ idr_destroy(&domain->user_idr); -+ kfree(domain); -+} -+ -+/** -+ * kdbus_domain_new() - create a new domain -+ * @access: The access mode for this node (KDBUS_MAKE_ACCESS_*) -+ * -+ * Return: a new kdbus_domain on success, ERR_PTR on failure -+ */ -+struct kdbus_domain *kdbus_domain_new(unsigned int access) -+{ -+ struct kdbus_domain *d; -+ int ret; -+ -+ d = kzalloc(sizeof(*d), GFP_KERNEL); -+ if (!d) -+ return ERR_PTR(-ENOMEM); -+ -+ kdbus_node_init(&d->node, KDBUS_NODE_DOMAIN); -+ -+ d->node.free_cb = kdbus_domain_free; -+ d->node.mode = S_IRUSR | S_IXUSR; -+ if (access & (KDBUS_MAKE_ACCESS_GROUP | KDBUS_MAKE_ACCESS_WORLD)) -+ d->node.mode |= S_IRGRP | S_IXGRP; -+ if (access & KDBUS_MAKE_ACCESS_WORLD) -+ d->node.mode |= S_IROTH | S_IXOTH; -+ -+ mutex_init(&d->lock); -+ idr_init(&d->user_idr); -+ ida_init(&d->user_ida); -+ -+ /* Pin user namespace so we can guarantee domain-unique bus * names. */ -+ d->user_namespace = get_user_ns(current_user_ns()); -+ -+ ret = kdbus_node_link(&d->node, NULL, NULL); -+ if (ret < 0) -+ goto exit_unref; -+ -+ return d; -+ -+exit_unref: -+ kdbus_node_deactivate(&d->node); -+ kdbus_node_unref(&d->node); -+ return ERR_PTR(ret); -+} -+ -+/** -+ * kdbus_domain_ref() - take a domain reference -+ * @domain: Domain -+ * -+ * Return: the domain itself -+ */ -+struct kdbus_domain *kdbus_domain_ref(struct kdbus_domain *domain) -+{ -+ if (domain) -+ kdbus_node_ref(&domain->node); -+ return domain; -+} -+ -+/** -+ * kdbus_domain_unref() - drop a domain reference -+ * @domain: Domain -+ * -+ * When the last reference is dropped, the domain internal structure -+ * is freed. -+ * -+ * Return: NULL -+ */ -+struct kdbus_domain *kdbus_domain_unref(struct kdbus_domain *domain) -+{ -+ if (domain) -+ kdbus_node_unref(&domain->node); -+ return NULL; -+} -+ -+/** -+ * kdbus_domain_populate() - populate static domain nodes -+ * @domain: domain to populate -+ * @access: KDBUS_MAKE_ACCESS_* access restrictions for new nodes -+ * -+ * Allocate and activate static sub-nodes of the given domain. This will fail if -+ * you call it on a non-active node or if the domain was already populated. -+ * -+ * Return: 0 on success, negative error code on failure. -+ */ -+int kdbus_domain_populate(struct kdbus_domain *domain, unsigned int access) -+{ -+ struct kdbus_node *control; -+ -+ /* -+ * Create a control-node for this domain. We drop our own reference -+ * immediately, effectively causing the node to be deactivated and -+ * released when the parent domain is. -+ */ -+ control = kdbus_domain_control_new(domain, access); -+ if (IS_ERR(control)) -+ return PTR_ERR(control); -+ -+ kdbus_node_activate(control); -+ kdbus_node_unref(control); -+ return 0; -+} -+ -+/** -+ * kdbus_user_lookup() - lookup a kdbus_user object -+ * @domain: domain of the user -+ * @uid: uid of the user; INVALID_UID for an anon user -+ * -+ * Lookup the kdbus user accounting object for the given domain. If INVALID_UID -+ * is passed, a new anonymous user is created which is private to the caller. -+ * -+ * Return: The user object is returned, ERR_PTR on failure. -+ */ -+struct kdbus_user *kdbus_user_lookup(struct kdbus_domain *domain, kuid_t uid) -+{ -+ struct kdbus_user *u = NULL, *old = NULL; -+ int ret; -+ -+ mutex_lock(&domain->lock); -+ -+ if (uid_valid(uid)) { -+ old = idr_find(&domain->user_idr, __kuid_val(uid)); -+ /* -+ * If the object is about to be destroyed, ignore it and -+ * replace the slot in the IDR later on. -+ */ -+ if (old && kref_get_unless_zero(&old->kref)) { -+ mutex_unlock(&domain->lock); -+ return old; -+ } -+ } -+ -+ u = kzalloc(sizeof(*u), GFP_KERNEL); -+ if (!u) { -+ ret = -ENOMEM; -+ goto exit; -+ } -+ -+ kref_init(&u->kref); -+ u->domain = kdbus_domain_ref(domain); -+ u->uid = uid; -+ atomic_set(&u->buses, 0); -+ atomic_set(&u->connections, 0); -+ -+ if (uid_valid(uid)) { -+ if (old) { -+ idr_replace(&domain->user_idr, u, __kuid_val(uid)); -+ old->uid = INVALID_UID; /* mark old as removed */ -+ } else { -+ ret = idr_alloc(&domain->user_idr, u, __kuid_val(uid), -+ __kuid_val(uid) + 1, GFP_KERNEL); -+ if (ret < 0) -+ goto exit; -+ } -+ } -+ -+ /* -+ * Allocate the smallest possible index for this user; used -+ * in arrays for accounting user quota in receiver queues. -+ */ -+ ret = ida_simple_get(&domain->user_ida, 1, 0, GFP_KERNEL); -+ if (ret < 0) -+ goto exit; -+ -+ u->id = ret; -+ mutex_unlock(&domain->lock); -+ return u; -+ -+exit: -+ if (u) { -+ if (uid_valid(u->uid)) -+ idr_remove(&domain->user_idr, __kuid_val(u->uid)); -+ kdbus_domain_unref(u->domain); -+ kfree(u); -+ } -+ mutex_unlock(&domain->lock); -+ return ERR_PTR(ret); -+} -+ -+static void __kdbus_user_free(struct kref *kref) -+{ -+ struct kdbus_user *user = container_of(kref, struct kdbus_user, kref); -+ -+ WARN_ON(atomic_read(&user->buses) > 0); -+ WARN_ON(atomic_read(&user->connections) > 0); -+ -+ mutex_lock(&user->domain->lock); -+ ida_simple_remove(&user->domain->user_ida, user->id); -+ if (uid_valid(user->uid)) -+ idr_remove(&user->domain->user_idr, __kuid_val(user->uid)); -+ mutex_unlock(&user->domain->lock); -+ -+ kdbus_domain_unref(user->domain); -+ kfree(user); -+} -+ -+/** -+ * kdbus_user_ref() - take a user reference -+ * @u: User -+ * -+ * Return: @u is returned -+ */ -+struct kdbus_user *kdbus_user_ref(struct kdbus_user *u) -+{ -+ if (u) -+ kref_get(&u->kref); -+ return u; -+} -+ -+/** -+ * kdbus_user_unref() - drop a user reference -+ * @u: User -+ * -+ * Return: NULL -+ */ -+struct kdbus_user *kdbus_user_unref(struct kdbus_user *u) -+{ -+ if (u) -+ kref_put(&u->kref, __kdbus_user_free); -+ return NULL; -+} -diff --git a/ipc/kdbus/domain.h b/ipc/kdbus/domain.h -new file mode 100644 -index 000000000000..447a2bd4d972 ---- /dev/null -+++ b/ipc/kdbus/domain.h -@@ -0,0 +1,77 @@ -+/* -+ * Copyright (C) 2013-2015 Kay Sievers -+ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> -+ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> -+ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> -+ * Copyright (C) 2013-2015 Linux Foundation -+ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> -+ * -+ * 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_DOMAIN_H -+#define __KDBUS_DOMAIN_H -+ -+#include <linux/fs.h> -+#include <linux/idr.h> -+#include <linux/kref.h> -+#include <linux/user_namespace.h> -+ -+#include "node.h" -+ -+/** -+ * struct kdbus_domain - domain for buses -+ * @node: Underlying API node -+ * @lock: Domain data lock -+ * @last_id: Last used object id -+ * @user_idr: Set of all users indexed by UID -+ * @user_ida: Set of all users to compute small indices -+ * @user_namespace: User namespace, pinned at creation time -+ * @dentry: Root dentry of VFS mount (don't use outside of kdbusfs) -+ */ -+struct kdbus_domain { -+ struct kdbus_node node; -+ struct mutex lock; -+ atomic64_t last_id; -+ struct idr user_idr; -+ struct ida user_ida; -+ struct user_namespace *user_namespace; -+ struct dentry *dentry; -+}; -+ -+/** -+ * struct kdbus_user - resource accounting for users -+ * @kref: Reference counter -+ * @domain: Domain of the user -+ * @id: Index of this user -+ * @uid: UID of the user -+ * @buses: Number of buses the user has created -+ * @connections: Number of connections the user has created -+ */ -+struct kdbus_user { -+ struct kref kref; -+ struct kdbus_domain *domain; -+ unsigned int id; -+ kuid_t uid; -+ atomic_t buses; -+ atomic_t connections; -+}; -+ -+#define kdbus_domain_from_node(_node) \ -+ container_of((_node), struct kdbus_domain, node) -+ -+struct kdbus_domain *kdbus_domain_new(unsigned int access); -+struct kdbus_domain *kdbus_domain_ref(struct kdbus_domain *domain); -+struct kdbus_domain *kdbus_domain_unref(struct kdbus_domain *domain); -+int kdbus_domain_populate(struct kdbus_domain *domain, unsigned int access); -+ -+#define KDBUS_USER_KERNEL_ID 0 /* ID 0 is reserved for kernel accounting */ -+ -+struct kdbus_user *kdbus_user_lookup(struct kdbus_domain *domain, kuid_t uid); -+struct kdbus_user *kdbus_user_ref(struct kdbus_user *u); -+struct kdbus_user *kdbus_user_unref(struct kdbus_user *u); -+ -+#endif -diff --git a/ipc/kdbus/endpoint.c b/ipc/kdbus/endpoint.c -new file mode 100644 -index 000000000000..174d274b113e ---- /dev/null -+++ b/ipc/kdbus/endpoint.c -@@ -0,0 +1,275 @@ -+/* -+ * Copyright (C) 2013-2015 Kay Sievers -+ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> -+ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> -+ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> -+ * Copyright (C) 2013-2015 Linux Foundation -+ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> -+ * -+ * 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/idr.h> -+#include <linux/init.h> -+#include <linux/module.h> -+#include <linux/sched.h> -+#include <linux/sizes.h> -+#include <linux/slab.h> -+#include <linux/uaccess.h> -+#include <linux/uio.h> -+ -+#include "bus.h" -+#include "connection.h" -+#include "domain.h" -+#include "endpoint.h" -+#include "handle.h" -+#include "item.h" -+#include "message.h" -+#include "policy.h" -+ -+static void kdbus_ep_free(struct kdbus_node *node) -+{ -+ struct kdbus_ep *ep = container_of(node, struct kdbus_ep, node); -+ -+ WARN_ON(!list_empty(&ep->conn_list)); -+ -+ kdbus_policy_db_clear(&ep->policy_db); -+ kdbus_bus_unref(ep->bus); -+ kdbus_user_unref(ep->user); -+ kfree(ep); -+} -+ -+static void kdbus_ep_release(struct kdbus_node *node, bool was_active) -+{ -+ struct kdbus_ep *ep = container_of(node, struct kdbus_ep, node); -+ -+ /* disconnect all connections to this endpoint */ -+ for (;;) { -+ struct kdbus_conn *conn; -+ -+ mutex_lock(&ep->lock); -+ conn = list_first_entry_or_null(&ep->conn_list, -+ struct kdbus_conn, -+ ep_entry); -+ if (!conn) { -+ mutex_unlock(&ep->lock); -+ break; -+ } -+ -+ /* take reference, release lock, disconnect without lock */ -+ kdbus_conn_ref(conn); -+ mutex_unlock(&ep->lock); -+ -+ kdbus_conn_disconnect(conn, false); -+ kdbus_conn_unref(conn); -+ } -+} -+ -+/** -+ * kdbus_ep_new() - create a new endpoint -+ * @bus: The bus this endpoint will be created for -+ * @name: The name of the endpoint -+ * @access: The access flags for this node (KDBUS_MAKE_ACCESS_*) -+ * @uid: The uid of the node -+ * @gid: The gid of the node -+ * @is_custom: Whether this is a custom endpoint -+ * -+ * This function will create a new enpoint with the given -+ * name and properties for a given bus. -+ * -+ * Return: a new kdbus_ep on success, ERR_PTR on failure. -+ */ -+struct kdbus_ep *kdbus_ep_new(struct kdbus_bus *bus, const char *name, -+ unsigned int access, kuid_t uid, kgid_t gid, -+ bool is_custom) -+{ -+ struct kdbus_ep *e; -+ int ret; -+ -+ /* -+ * Validate only custom endpoints names, default endpoints -+ * with a "bus" name are created when the bus is created -+ */ -+ if (is_custom) { -+ ret = kdbus_verify_uid_prefix(name, bus->domain->user_namespace, -+ uid); -+ if (ret < 0) -+ return ERR_PTR(ret); -+ } -+ -+ e = kzalloc(sizeof(*e), GFP_KERNEL); -+ if (!e) -+ return ERR_PTR(-ENOMEM); -+ -+ kdbus_node_init(&e->node, KDBUS_NODE_ENDPOINT); -+ -+ e->node.free_cb = kdbus_ep_free; -+ e->node.release_cb = kdbus_ep_release; -+ e->node.uid = uid; -+ e->node.gid = gid; -+ e->node.mode = S_IRUSR | S_IWUSR; -+ if (access & (KDBUS_MAKE_ACCESS_GROUP | KDBUS_MAKE_ACCESS_WORLD)) -+ e->node.mode |= S_IRGRP | S_IWGRP; -+ if (access & KDBUS_MAKE_ACCESS_WORLD) -+ e->node.mode |= S_IROTH | S_IWOTH; -+ -+ mutex_init(&e->lock); -+ INIT_LIST_HEAD(&e->conn_list); -+ kdbus_policy_db_init(&e->policy_db); -+ e->bus = kdbus_bus_ref(bus); -+ -+ ret = kdbus_node_link(&e->node, &bus->node, name); -+ if (ret < 0) -+ goto exit_unref; -+ -+ /* -+ * Transactions on custom endpoints are never accounted on the global -+ * user limits. Instead, for each custom endpoint, we create a custom, -+ * unique user, which all transactions are accounted on. Regardless of -+ * the user using that endpoint, it is always accounted on the same -+ * user-object. This budget is not shared with ordinary users on -+ * non-custom endpoints. -+ */ -+ if (is_custom) { -+ e->user = kdbus_user_lookup(bus->domain, INVALID_UID); -+ if (IS_ERR(e->user)) { -+ ret = PTR_ERR(e->user); -+ e->user = NULL; -+ goto exit_unref; -+ } -+ } -+ -+ return e; -+ -+exit_unref: -+ kdbus_node_deactivate(&e->node); -+ kdbus_node_unref(&e->node); -+ return ERR_PTR(ret); -+} -+ -+/** -+ * kdbus_ep_ref() - increase the reference counter of a kdbus_ep -+ * @ep: The endpoint to reference -+ * -+ * Every user of an endpoint, except for its creator, must add a reference to -+ * the kdbus_ep instance using this function. -+ * -+ * Return: the ep itself -+ */ -+struct kdbus_ep *kdbus_ep_ref(struct kdbus_ep *ep) -+{ -+ if (ep) -+ kdbus_node_ref(&ep->node); -+ return ep; -+} -+ -+/** -+ * kdbus_ep_unref() - decrease the reference counter of a kdbus_ep -+ * @ep: The ep to unref -+ * -+ * Release a reference. If the reference count drops to 0, the ep will be -+ * freed. -+ * -+ * Return: NULL -+ */ -+struct kdbus_ep *kdbus_ep_unref(struct kdbus_ep *ep) -+{ -+ if (ep) -+ kdbus_node_unref(&ep->node); -+ return NULL; -+} -+ -+/** -+ * kdbus_cmd_ep_make() - handle KDBUS_CMD_ENDPOINT_MAKE -+ * @bus: bus to operate on -+ * @argp: command payload -+ * -+ * Return: Newly created endpoint on success, ERR_PTR on failure. -+ */ -+struct kdbus_ep *kdbus_cmd_ep_make(struct kdbus_bus *bus, void __user *argp) -+{ -+ const char *item_make_name; -+ struct kdbus_ep *ep = NULL; -+ struct kdbus_cmd *cmd; -+ int ret; -+ -+ struct kdbus_arg argv[] = { -+ { .type = KDBUS_ITEM_NEGOTIATE }, -+ { .type = KDBUS_ITEM_MAKE_NAME, .mandatory = true }, -+ }; -+ struct kdbus_args args = { -+ .allowed_flags = KDBUS_FLAG_NEGOTIATE | -+ KDBUS_MAKE_ACCESS_GROUP | -+ KDBUS_MAKE_ACCESS_WORLD, -+ .argv = argv, -+ .argc = ARRAY_SIZE(argv), -+ }; -+ -+ ret = kdbus_args_parse(&args, argp, &cmd); -+ if (ret < 0) -+ return ERR_PTR(ret); -+ if (ret > 0) -+ return NULL; -+ -+ item_make_name = argv[1].item->str; -+ -+ ep = kdbus_ep_new(bus, item_make_name, cmd->flags, -+ current_euid(), current_egid(), true); -+ if (IS_ERR(ep)) { -+ ret = PTR_ERR(ep); -+ ep = NULL; -+ goto exit; -+ } -+ -+ if (!kdbus_node_activate(&ep->node)) { -+ ret = -ESHUTDOWN; -+ goto exit; -+ } -+ -+exit: -+ ret = kdbus_args_clear(&args, ret); -+ if (ret < 0) { -+ if (ep) { -+ kdbus_node_deactivate(&ep->node); -+ kdbus_ep_unref(ep); -+ } -+ return ERR_PTR(ret); -+ } -+ return ep; -+} -+ -+/** -+ * kdbus_cmd_ep_update() - handle KDBUS_CMD_ENDPOINT_UPDATE -+ * @ep: endpoint to operate on -+ * @argp: command payload -+ * -+ * Return: Newly created endpoint on success, ERR_PTR on failure. -+ */ -+int kdbus_cmd_ep_update(struct kdbus_ep *ep, void __user *argp) -+{ -+ struct kdbus_cmd *cmd; -+ int ret; -+ -+ struct kdbus_arg argv[] = { -+ { .type = KDBUS_ITEM_NEGOTIATE }, -+ { .type = KDBUS_ITEM_NAME, .multiple = true }, -+ { .type = KDBUS_ITEM_POLICY_ACCESS, .multiple = true }, -+ }; -+ struct kdbus_args args = { -+ .allowed_flags = KDBUS_FLAG_NEGOTIATE, -+ .argv = argv, -+ .argc = ARRAY_SIZE(argv), -+ }; -+ -+ ret = kdbus_args_parse(&args, argp, &cmd); -+ if (ret != 0) -+ return ret; -+ -+ ret = kdbus_policy_set(&ep->policy_db, args.items, args.items_size, -+ 0, true, ep); -+ return kdbus_args_clear(&args, ret); -+} -diff --git a/ipc/kdbus/endpoint.h b/ipc/kdbus/endpoint.h -new file mode 100644 -index 000000000000..d31954bfba2c ---- /dev/null -+++ b/ipc/kdbus/endpoint.h -@@ -0,0 +1,67 @@ -+/* -+ * Copyright (C) 2013-2015 Kay Sievers -+ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> -+ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> -+ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> -+ * Copyright (C) 2013-2015 Linux Foundation -+ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> -+ * -+ * 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_ENDPOINT_H -+#define __KDBUS_ENDPOINT_H -+ -+#include <linux/list.h> -+#include <linux/mutex.h> -+#include <linux/uidgid.h> -+#include "node.h" -+#include "policy.h" -+ -+struct kdbus_bus; -+struct kdbus_user; -+ -+/** -+ * struct kdbus_ep - enpoint to access a bus -+ * @node: The kdbus node -+ * @lock: Endpoint data lock -+ * @bus: Bus behind this endpoint -+ * @user: Custom enpoints account against an anonymous user -+ * @policy_db: Uploaded policy -+ * @conn_list: Connections of this endpoint -+ * -+ * An enpoint offers access to a bus; the default endpoint node name is "bus". -+ * Additional custom endpoints to the same bus can be created and they can -+ * carry their own policies/filters. -+ */ -+struct kdbus_ep { -+ struct kdbus_node node; -+ struct mutex lock; -+ -+ /* static */ -+ struct kdbus_bus *bus; -+ struct kdbus_user *user; -+ -+ /* protected by own locks */ -+ struct kdbus_policy_db policy_db; -+ -+ /* protected by ep->lock */ -+ struct list_head conn_list; -+}; -+ -+#define kdbus_ep_from_node(_node) \ -+ container_of((_node), struct kdbus_ep, node) -+ -+struct kdbus_ep *kdbus_ep_new(struct kdbus_bus *bus, const char *name, -+ unsigned int access, kuid_t uid, kgid_t gid, -+ bool policy); -+struct kdbus_ep *kdbus_ep_ref(struct kdbus_ep *ep); -+struct kdbus_ep *kdbus_ep_unref(struct kdbus_ep *ep); -+ -+struct kdbus_ep *kdbus_cmd_ep_make(struct kdbus_bus *bus, void __user *argp); -+int kdbus_cmd_ep_update(struct kdbus_ep *ep, void __user *argp); -+ -+#endif --- -2.4.3 - - -From 29dc02b6af35f3de8d14f54fcced86854f2d4ba9 Mon Sep 17 00:00:00 2001 -From: Daniel Mack <daniel@zonque.org> -Date: Thu, 11 Sep 2014 19:00:00 +0200 -Subject: [PATCH 010/132] kdbus: add name registry implementation - -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. - -Signed-off-by: Daniel Mack <daniel@zonque.org> -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Djalal Harouni <tixxdz@opendz.org> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - ipc/kdbus/names.c | 772 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ - ipc/kdbus/names.h | 74 ++++++ - 2 files changed, 846 insertions(+) - create mode 100644 ipc/kdbus/names.c - create mode 100644 ipc/kdbus/names.h - -diff --git a/ipc/kdbus/names.c b/ipc/kdbus/names.c -new file mode 100644 -index 000000000000..657008e1bb37 ---- /dev/null -+++ b/ipc/kdbus/names.c -@@ -0,0 +1,772 @@ -+/* -+ * Copyright (C) 2013-2015 Kay Sievers -+ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> -+ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> -+ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> -+ * Copyright (C) 2013-2015 Linux Foundation -+ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> -+ * -+ * 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 <linux/uio.h> -+ -+#include "bus.h" -+#include "connection.h" -+#include "endpoint.h" -+#include "handle.h" -+#include "item.h" -+#include "names.h" -+#include "notify.h" -+#include "policy.h" -+ -+struct kdbus_name_pending { -+ u64 flags; -+ struct kdbus_conn *conn; -+ struct kdbus_name_entry *name; -+ struct list_head conn_entry; -+ struct list_head name_entry; -+}; -+ -+static int kdbus_name_pending_new(struct kdbus_name_entry *e, -+ struct kdbus_conn *conn, u64 flags) -+{ -+ struct kdbus_name_pending *p; -+ -+ kdbus_conn_assert_active(conn); -+ -+ p = kmalloc(sizeof(*p), GFP_KERNEL); -+ if (!p) -+ return -ENOMEM; -+ -+ p->flags = flags; -+ p->conn = conn; -+ p->name = e; -+ list_add_tail(&p->conn_entry, &conn->names_queue_list); -+ list_add_tail(&p->name_entry, &e->queue); -+ -+ return 0; -+} -+ -+static void kdbus_name_pending_free(struct kdbus_name_pending *p) -+{ -+ if (!p) -+ return; -+ -+ list_del(&p->name_entry); -+ list_del(&p->conn_entry); -+ kfree(p); -+} -+ -+static struct kdbus_name_entry * -+kdbus_name_entry_new(struct kdbus_name_registry *r, u32 hash, const char *name) -+{ -+ struct kdbus_name_entry *e; -+ size_t namelen; -+ -+ namelen = strlen(name); -+ -+ e = kmalloc(sizeof(*e) + namelen + 1, GFP_KERNEL); -+ if (!e) -+ return ERR_PTR(-ENOMEM); -+ -+ e->name_id = ++r->name_seq_last; -+ e->flags = 0; -+ e->conn = NULL; -+ e->activator = NULL; -+ INIT_LIST_HEAD(&e->queue); -+ INIT_LIST_HEAD(&e->conn_entry); -+ hash_add(r->entries_hash, &e->hentry, hash); -+ memcpy(e->name, name, namelen + 1); -+ -+ return e; -+} -+ -+static void kdbus_name_entry_free(struct kdbus_name_entry *e) -+{ -+ if (!e) -+ return; -+ -+ WARN_ON(!list_empty(&e->conn_entry)); -+ WARN_ON(!list_empty(&e->queue)); -+ WARN_ON(e->activator); -+ WARN_ON(e->conn); -+ -+ hash_del(&e->hentry); -+ kfree(e); -+} -+ -+static void kdbus_name_entry_set_owner(struct kdbus_name_entry *e, -+ struct kdbus_conn *conn, u64 flags) -+{ -+ WARN_ON(e->conn); -+ -+ e->conn = kdbus_conn_ref(conn); -+ e->flags = flags; -+ atomic_inc(&conn->name_count); -+ list_add_tail(&e->conn_entry, &e->conn->names_list); -+} -+ -+static void kdbus_name_entry_remove_owner(struct kdbus_name_entry *e) -+{ -+ WARN_ON(!e->conn); -+ -+ list_del_init(&e->conn_entry); -+ atomic_dec(&e->conn->name_count); -+ e->flags = 0; -+ e->conn = kdbus_conn_unref(e->conn); -+} -+ -+static void kdbus_name_entry_replace_owner(struct kdbus_name_entry *e, -+ struct kdbus_conn *conn, u64 flags) -+{ -+ if (WARN_ON(!e->conn) || WARN_ON(conn == e->conn)) -+ return; -+ -+ kdbus_notify_name_change(conn->ep->bus, KDBUS_ITEM_NAME_CHANGE, -+ e->conn->id, conn->id, -+ e->flags, flags, e->name); -+ kdbus_name_entry_remove_owner(e); -+ kdbus_name_entry_set_owner(e, conn, flags); -+} -+ -+/** -+ * 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_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 = kmalloc(sizeof(*r), GFP_KERNEL); -+ if (!r) -+ return ERR_PTR(-ENOMEM); -+ -+ hash_init(r->entries_hash); -+ init_rwsem(&r->rwlock); -+ r->name_seq_last = 0; -+ -+ return r; -+} -+ -+/** -+ * 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) -+{ -+ if (!reg) -+ return; -+ -+ WARN_ON(!hash_empty(reg->entries_hash)); -+ kfree(reg); -+} -+ -+static struct kdbus_name_entry * -+kdbus_name_find(struct kdbus_name_registry *reg, u32 hash, const char *name) -+{ -+ struct kdbus_name_entry *e; -+ -+ lockdep_assert_held(®->rwlock); -+ -+ hash_for_each_possible(reg->entries_hash, e, hentry, hash) -+ if (strcmp(e->name, name) == 0) -+ return e; -+ -+ return NULL; -+} -+ -+/** -+ * kdbus_name_lookup_unlocked() - lookup name in registry -+ * @reg: name registry -+ * @name: name to lookup -+ * -+ * This looks up @name in the given name-registry and returns the -+ * kdbus_name_entry object. The caller must hold the registry-lock and must not -+ * access the returned object after releasing the lock. -+ * -+ * Return: Pointer to name-entry, or NULL if not found. -+ */ -+struct kdbus_name_entry * -+kdbus_name_lookup_unlocked(struct kdbus_name_registry *reg, const char *name) -+{ -+ return kdbus_name_find(reg, kdbus_strhash(name), name); -+} -+ -+/** -+ * 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_*) -+ * @return_flags: Pointer to return flags for the acquired name -+ * (KDBUS_NAME_*), may be %NULL -+ * -+ * 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, u64 *return_flags) -+{ -+ struct kdbus_name_entry *e; -+ u64 rflags = 0; -+ int ret = 0; -+ u32 hash; -+ -+ kdbus_conn_assert_active(conn); -+ -+ down_write(®->rwlock); -+ -+ if (!kdbus_conn_policy_own_name(conn, current_cred(), name)) { -+ ret = -EPERM; -+ goto exit_unlock; -+ } -+ -+ hash = kdbus_strhash(name); -+ e = kdbus_name_find(reg, hash, name); -+ if (!e) { -+ /* claim new name */ -+ -+ if (conn->activator_of) { -+ ret = -EINVAL; -+ goto exit_unlock; -+ } -+ -+ e = kdbus_name_entry_new(reg, hash, name); -+ if (IS_ERR(e)) { -+ ret = PTR_ERR(e); -+ goto exit_unlock; -+ } -+ -+ if (kdbus_conn_is_activator(conn)) { -+ e->activator = kdbus_conn_ref(conn); -+ conn->activator_of = e; -+ } -+ -+ kdbus_name_entry_set_owner(e, conn, flags); -+ kdbus_notify_name_change(e->conn->ep->bus, KDBUS_ITEM_NAME_ADD, -+ 0, e->conn->id, 0, e->flags, e->name); -+ } else if (e->conn == conn || e == conn->activator_of) { -+ /* connection already owns that name */ -+ ret = -EALREADY; -+ } else if (kdbus_conn_is_activator(conn)) { -+ /* activator claims existing name */ -+ -+ if (conn->activator_of) { -+ ret = -EINVAL; /* multiple names not allowed */ -+ } else if (e->activator) { -+ ret = -EEXIST; /* only one activator per name */ -+ } else { -+ e->activator = kdbus_conn_ref(conn); -+ conn->activator_of = e; -+ } -+ } else if (e->flags & KDBUS_NAME_ACTIVATOR) { -+ /* claim name of an activator */ -+ -+ kdbus_conn_move_messages(conn, e->activator, 0); -+ kdbus_name_entry_replace_owner(e, conn, flags); -+ } else if ((flags & KDBUS_NAME_REPLACE_EXISTING) && -+ (e->flags & KDBUS_NAME_ALLOW_REPLACEMENT)) { -+ /* claim name of a previous owner */ -+ -+ if (e->flags & KDBUS_NAME_QUEUE) { -+ /* move owner back to queue if they asked for it */ -+ ret = kdbus_name_pending_new(e, e->conn, e->flags); -+ if (ret < 0) -+ goto exit_unlock; -+ } -+ -+ kdbus_name_entry_replace_owner(e, conn, flags); -+ } else if (flags & KDBUS_NAME_QUEUE) { -+ /* add to waiting-queue of the name */ -+ -+ ret = kdbus_name_pending_new(e, conn, flags); -+ if (ret >= 0) -+ /* tell the caller that we queued it */ -+ rflags |= KDBUS_NAME_IN_QUEUE; -+ } else { -+ /* the name is busy, return a failure */ -+ ret = -EEXIST; -+ } -+ -+ if (ret == 0 && return_flags) -+ *return_flags = rflags; -+ -+exit_unlock: -+ up_write(®->rwlock); -+ kdbus_notify_flush(conn->ep->bus); -+ return ret; -+} -+ -+static void kdbus_name_release_unlocked(struct kdbus_name_registry *reg, -+ struct kdbus_name_entry *e) -+{ -+ struct kdbus_name_pending *p; -+ -+ lockdep_assert_held(®->rwlock); -+ -+ p = list_first_entry_or_null(&e->queue, struct kdbus_name_pending, -+ name_entry); -+ -+ if (p) { -+ /* give it to first active waiter in the queue */ -+ kdbus_name_entry_replace_owner(e, p->conn, p->flags); -+ kdbus_name_pending_free(p); -+ } else if (e->activator && e->activator != e->conn) { -+ /* hand it back to an active activator connection */ -+ kdbus_conn_move_messages(e->activator, e->conn, e->name_id); -+ kdbus_name_entry_replace_owner(e, e->activator, -+ KDBUS_NAME_ACTIVATOR); -+ } else { -+ /* release the name */ -+ kdbus_notify_name_change(e->conn->ep->bus, -+ KDBUS_ITEM_NAME_REMOVE, -+ e->conn->id, 0, e->flags, 0, e->name); -+ kdbus_name_entry_remove_owner(e); -+ kdbus_name_entry_free(e); -+ } -+} -+ -+static int kdbus_name_release(struct kdbus_name_registry *reg, -+ struct kdbus_conn *conn, -+ const char *name) -+{ -+ struct kdbus_name_pending *p; -+ struct kdbus_name_entry *e; -+ int ret = 0; -+ -+ down_write(®->rwlock); -+ e = kdbus_name_find(reg, kdbus_strhash(name), name); -+ if (!e) { -+ ret = -ESRCH; -+ } else if (e->conn == conn) { -+ kdbus_name_release_unlocked(reg, e); -+ } else { -+ ret = -EADDRINUSE; -+ list_for_each_entry(p, &e->queue, name_entry) { -+ if (p->conn == conn) { -+ kdbus_name_pending_free(p); -+ ret = 0; -+ break; -+ } -+ } -+ } -+ up_write(®->rwlock); -+ -+ kdbus_notify_flush(conn->ep->bus); -+ return ret; -+} -+ -+/** -+ * kdbus_name_release_all() - remove all name entries of a given connection -+ * @reg: name registry -+ * @conn: connection -+ */ -+void kdbus_name_release_all(struct kdbus_name_registry *reg, -+ struct kdbus_conn *conn) -+{ -+ struct kdbus_name_pending *p; -+ struct kdbus_conn *activator = NULL; -+ struct kdbus_name_entry *e; -+ -+ down_write(®->rwlock); -+ -+ if (kdbus_conn_is_activator(conn)) { -+ activator = conn->activator_of->activator; -+ conn->activator_of->activator = NULL; -+ } -+ -+ while ((p = list_first_entry_or_null(&conn->names_queue_list, -+ struct kdbus_name_pending, -+ conn_entry))) -+ kdbus_name_pending_free(p); -+ while ((e = list_first_entry_or_null(&conn->names_list, -+ struct kdbus_name_entry, -+ conn_entry))) -+ kdbus_name_release_unlocked(reg, e); -+ -+ up_write(®->rwlock); -+ -+ kdbus_conn_unref(activator); -+ kdbus_notify_flush(conn->ep->bus); -+} -+ -+/** -+ * kdbus_cmd_name_acquire() - handle KDBUS_CMD_NAME_ACQUIRE -+ * @conn: connection to operate on -+ * @argp: command payload -+ * -+ * Return: 0 on success, negative error code on failure. -+ */ -+int kdbus_cmd_name_acquire(struct kdbus_conn *conn, void __user *argp) -+{ -+ const char *item_name; -+ struct kdbus_cmd *cmd; -+ int ret; -+ -+ struct kdbus_arg argv[] = { -+ { .type = KDBUS_ITEM_NEGOTIATE }, -+ { .type = KDBUS_ITEM_NAME, .mandatory = true }, -+ }; -+ struct kdbus_args args = { -+ .allowed_flags = KDBUS_FLAG_NEGOTIATE | -+ KDBUS_NAME_REPLACE_EXISTING | -+ KDBUS_NAME_ALLOW_REPLACEMENT | -+ KDBUS_NAME_QUEUE, -+ .argv = argv, -+ .argc = ARRAY_SIZE(argv), -+ }; -+ -+ if (!kdbus_conn_is_ordinary(conn)) -+ return -EOPNOTSUPP; -+ -+ ret = kdbus_args_parse(&args, argp, &cmd); -+ if (ret != 0) -+ return ret; -+ -+ item_name = argv[1].item->str; -+ if (!kdbus_name_is_valid(item_name, false)) { -+ ret = -EINVAL; -+ goto exit; -+ } -+ -+ /* -+ * 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 exit_dec; -+ } -+ -+ ret = kdbus_name_acquire(conn->ep->bus->name_registry, conn, item_name, -+ cmd->flags, &cmd->return_flags); -+ if (ret < 0) -+ goto exit_dec; -+ -+exit_dec: -+ atomic_dec(&conn->name_count); -+exit: -+ return kdbus_args_clear(&args, ret); -+} -+ -+/** -+ * kdbus_cmd_name_release() - handle KDBUS_CMD_NAME_RELEASE -+ * @conn: connection to operate on -+ * @argp: command payload -+ * -+ * Return: 0 on success, negative error code on failure. -+ */ -+int kdbus_cmd_name_release(struct kdbus_conn *conn, void __user *argp) -+{ -+ struct kdbus_cmd *cmd; -+ int ret; -+ -+ struct kdbus_arg argv[] = { -+ { .type = KDBUS_ITEM_NEGOTIATE }, -+ { .type = KDBUS_ITEM_NAME, .mandatory = true }, -+ }; -+ struct kdbus_args args = { -+ .allowed_flags = KDBUS_FLAG_NEGOTIATE, -+ .argv = argv, -+ .argc = ARRAY_SIZE(argv), -+ }; -+ -+ if (!kdbus_conn_is_ordinary(conn)) -+ return -EOPNOTSUPP; -+ -+ ret = kdbus_args_parse(&args, argp, &cmd); -+ if (ret != 0) -+ return ret; -+ -+ ret = kdbus_name_release(conn->ep->bus->name_registry, conn, -+ argv[1].item->str); -+ return kdbus_args_clear(&args, ret); -+} -+ -+static int kdbus_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) -+{ -+ struct kvec kvec[4]; -+ size_t cnt = 0; -+ int ret; -+ -+ /* info header */ -+ struct kdbus_info info = { -+ .size = 0, -+ .id = c->id, -+ .flags = c->flags, -+ }; -+ -+ /* fake the header of a kdbus_name item */ -+ struct { -+ u64 size; -+ u64 type; -+ u64 flags; -+ } h = {}; -+ -+ if (e && !kdbus_conn_policy_see_name_unlocked(conn, current_cred(), -+ e->name)) -+ return 0; -+ -+ kdbus_kvec_set(&kvec[cnt++], &info, sizeof(info), &info.size); -+ -+ /* append name */ -+ if (e) { -+ size_t slen = strlen(e->name) + 1; -+ -+ h.size = offsetof(struct kdbus_item, name.name) + slen; -+ h.type = KDBUS_ITEM_OWNED_NAME; -+ h.flags = e->flags; -+ -+ kdbus_kvec_set(&kvec[cnt++], &h, sizeof(h), &info.size); -+ kdbus_kvec_set(&kvec[cnt++], e->name, slen, &info.size); -+ cnt += !!kdbus_kvec_pad(&kvec[cnt], &info.size); -+ } -+ -+ if (write) { -+ ret = kdbus_pool_slice_copy_kvec(slice, *pos, kvec, -+ cnt, info.size); -+ if (ret < 0) -+ return ret; -+ } -+ -+ *pos += info.size; -+ return 0; -+} -+ -+static int kdbus_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 monitors */ -+ if (kdbus_conn_is_monitor(c)) -+ continue; -+ -+ /* skip activators */ -+ if (!(flags & KDBUS_LIST_ACTIVATORS) && -+ kdbus_conn_is_activator(c)) -+ continue; -+ -+ /* all names the connection owns */ -+ if (flags & (KDBUS_LIST_NAMES | KDBUS_LIST_ACTIVATORS)) { -+ struct kdbus_name_entry *e; -+ -+ list_for_each_entry(e, &c->names_list, conn_entry) { -+ struct kdbus_conn *a = e->activator; -+ -+ if ((flags & KDBUS_LIST_ACTIVATORS) && -+ a && a != c) { -+ ret = kdbus_list_write(conn, a, slice, -+ &p, e, write); -+ if (ret < 0) { -+ mutex_unlock(&c->lock); -+ return ret; -+ } -+ -+ added = true; -+ } -+ -+ if (flags & KDBUS_LIST_NAMES || -+ kdbus_conn_is_activator(c)) { -+ ret = kdbus_list_write(conn, c, slice, -+ &p, e, write); -+ if (ret < 0) { -+ mutex_unlock(&c->lock); -+ return ret; -+ } -+ -+ added = true; -+ } -+ } -+ } -+ -+ /* queue of names the connection is currently waiting for */ -+ if (flags & KDBUS_LIST_QUEUED) { -+ struct kdbus_name_pending *q; -+ -+ list_for_each_entry(q, &c->names_queue_list, -+ conn_entry) { -+ ret = kdbus_list_write(conn, c, slice, &p, -+ q->name, write); -+ if (ret < 0) { -+ mutex_unlock(&c->lock); -+ return ret; -+ } -+ -+ added = true; -+ } -+ } -+ -+ /* nothing added so far, just add the unique ID */ -+ if (!added && flags & KDBUS_LIST_UNIQUE) { -+ ret = kdbus_list_write(conn, c, slice, &p, NULL, write); -+ if (ret < 0) -+ return ret; -+ } -+ } -+ -+ *pos = p; -+ return 0; -+} -+ -+/** -+ * kdbus_cmd_list() - handle KDBUS_CMD_LIST -+ * @conn: connection to operate on -+ * @argp: command payload -+ * -+ * Return: 0 on success, negative error code on failure. -+ */ -+int kdbus_cmd_list(struct kdbus_conn *conn, void __user *argp) -+{ -+ struct kdbus_name_registry *reg = conn->ep->bus->name_registry; -+ struct kdbus_pool_slice *slice = NULL; -+ struct kdbus_cmd_list *cmd; -+ size_t pos, size; -+ int ret; -+ -+ struct kdbus_arg argv[] = { -+ { .type = KDBUS_ITEM_NEGOTIATE }, -+ }; -+ struct kdbus_args args = { -+ .allowed_flags = KDBUS_FLAG_NEGOTIATE | -+ KDBUS_LIST_UNIQUE | -+ KDBUS_LIST_NAMES | -+ KDBUS_LIST_ACTIVATORS | -+ KDBUS_LIST_QUEUED, -+ .argv = argv, -+ .argc = ARRAY_SIZE(argv), -+ }; -+ -+ ret = kdbus_args_parse(&args, argp, &cmd); -+ if (ret != 0) -+ return ret; -+ -+ /* lock order: domain -> bus -> ep -> names -> conn */ -+ down_read(®->rwlock); -+ down_read(&conn->ep->bus->conn_rwlock); -+ down_read(&conn->ep->policy_db.entries_rwlock); -+ -+ /* size of records */ -+ size = 0; -+ ret = kdbus_list_all(conn, cmd->flags, NULL, &size, false); -+ if (ret < 0) -+ goto exit_unlock; -+ -+ if (size == 0) { -+ kdbus_pool_publish_empty(conn->pool, &cmd->offset, -+ &cmd->list_size); -+ } else { -+ slice = kdbus_pool_slice_alloc(conn->pool, size, false); -+ if (IS_ERR(slice)) { -+ ret = PTR_ERR(slice); -+ slice = NULL; -+ goto exit_unlock; -+ } -+ -+ /* copy the records */ -+ pos = 0; -+ ret = kdbus_list_all(conn, cmd->flags, slice, &pos, true); -+ if (ret < 0) -+ goto exit_unlock; -+ -+ WARN_ON(pos != size); -+ kdbus_pool_slice_publish(slice, &cmd->offset, &cmd->list_size); -+ } -+ -+ if (kdbus_member_set_user(&cmd->offset, argp, typeof(*cmd), offset) || -+ kdbus_member_set_user(&cmd->list_size, argp, -+ typeof(*cmd), list_size)) -+ ret = -EFAULT; -+ -+exit_unlock: -+ up_read(&conn->ep->policy_db.entries_rwlock); -+ up_read(&conn->ep->bus->conn_rwlock); -+ up_read(®->rwlock); -+ kdbus_pool_slice_release(slice); -+ return kdbus_args_clear(&args, ret); -+} -diff --git a/ipc/kdbus/names.h b/ipc/kdbus/names.h -new file mode 100644 -index 000000000000..3dd2589293e0 ---- /dev/null -+++ b/ipc/kdbus/names.h -@@ -0,0 +1,74 @@ -+/* -+ * Copyright (C) 2013-2015 Kay Sievers -+ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> -+ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> -+ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> -+ * Copyright (C) 2013-2015 Linux Foundation -+ * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> -+ * -+ * 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_NAMES_H -+#define __KDBUS_NAMES_H -+ -+#include <linux/hashtable.h> -+#include <linux/rwsem.h> -+ -+/** -+ * struct kdbus_name_registry - names registered for a bus -+ * @entries_hash: Map of entries -+ * @lock: Registry data lock -+ * @name_seq_last: Last used sequence number to assign to a name entry -+ */ -+struct kdbus_name_registry { -+ DECLARE_HASHTABLE(entries_hash, 8); -+ struct rw_semaphore rwlock; -+ u64 name_seq_last; -+}; -+ -+/** -+ * struct kdbus_name_entry - well-know name entry -+ * @name_id: Sequence number of name entry to be able to uniquely -+ * identify a name over its registration lifetime -+ * @flags: KDBUS_NAME_* flags -+ * @conn: Connection owning the name -+ * @activator: Connection of the activator queuing incoming messages -+ * @queue: List of queued connections -+ * @conn_entry: Entry in connection -+ * @hentry: Entry in registry map -+ * @name: The well-known name -+ */ -+struct kdbus_name_entry { -+ u64 name_id; -+ u64 flags; -+ struct kdbus_conn *conn; -+ struct kdbus_conn *activator; -+ struct list_head queue; -+ struct list_head conn_entry; -+ struct hlist_node hentry; -+ char name[]; -+}; -+ -+bool kdbus_name_is_valid(const char *p, bool allow_wildcard); -+ -+struct kdbus_name_registry *kdbus_name_registry_new(void); -+void kdbus_name_registry_free(struct kdbus_name_registry *reg); -+ -+struct kdbus_name_entry * -+kdbus_name_lookup_unlocked(struct kdbus_name_registry *reg, const char *name); -+ -+int kdbus_name_acquire(struct kdbus_name_registry *reg, -+ struct kdbus_conn *conn, const char *name, -+ u64 flags, u64 *return_flags); -+void kdbus_name_release_all(struct kdbus_name_registry *reg, -+ struct kdbus_conn *conn); -+ -+int kdbus_cmd_name_acquire(struct kdbus_conn *conn, void __user *argp); -+int kdbus_cmd_name_release(struct kdbus_conn *conn, void __user *argp); -+int kdbus_cmd_list(struct kdbus_conn *conn, void __user *argp); -+ -+#endif --- -2.4.3 - - -From 6773306168261072584de23c4e95ee49c3cfd7f7 Mon Sep 17 00:00:00 2001 -From: Daniel Mack <daniel@zonque.org> -Date: Thu, 11 Sep 2014 19:00:43 +0200 -Subject: [PATCH 011/132] kdbus: add policy database implementation - -This patch adds the policy database implementation. - -A policy database restricts 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 kdbus.policy(7) for more details. - -Signed-off-by: Daniel Mack <daniel@zonque.org> -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Djalal Harouni <tixxdz@opendz.org> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - ipc/kdbus/policy.c | 489 +++++++++++++++++++++++++++++++++++++++++++++++++++++ - ipc/kdbus/policy.h | 51 ++++++ - 2 files changed, 540 insertions(+) - create mode 100644 ipc/kdbus/policy.c - create mode 100644 ipc/kdbus/policy.h - -diff --git a/ipc/kdbus/policy.c b/ipc/kdbus/policy.c -new file mode 100644 -index 000000000000..dd7fffaafa84 ---- /dev/null -+++ b/ipc/kdbus/policy.c -@@ -0,0 +1,489 @@ -+/* -+ * Copyright (C) 2013-2015 Kay Sievers -+ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> -+ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> -+ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> -+ * Copyright (C) 2013-2015 Linux Foundation -+ * Copyright (C) 2014-2015 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/dcache.h> -+#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_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 unsigned int kdbus_strnhash(const char *str, size_t len) -+{ -+ unsigned long hash = init_name_hash(); -+ -+ while (len--) -+ hash = partial_name_hash(*str++, hash); -+ -+ return end_name_hash(hash); -+} -+ -+static const struct kdbus_policy_db_entry * -+kdbus_policy_lookup(struct kdbus_policy_db *db, const char *name, u32 hash) -+{ -+ struct kdbus_policy_db_entry *e; -+ const char *dot; -+ size_t len; -+ -+ /* find exact match */ -+ hash_for_each_possible(db->entries_hash, e, hentry, hash) -+ if (strcmp(e->name, name) == 0 && !e->wildcard) -+ return e; -+ -+ /* find wildcard match */ -+ -+ dot = strrchr(name, '.'); -+ if (!dot) -+ return NULL; -+ -+ len = dot - name; -+ hash = kdbus_strnhash(name, len); -+ -+ hash_for_each_possible(db->entries_hash, e, hentry, hash) -+ if (e->wildcard && !strncmp(e->name, name, len) && -+ !e->name[len]) -+ return e; -+ -+ return NULL; -+} -+ -+/** -+ * 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_entry *e; -+ struct hlist_node *tmp; -+ unsigned int i; -+ -+ /* 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); -+} -+ -+/** -+ * 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); -+ init_rwsem(&db->entries_rwlock); -+} -+ -+/** -+ * kdbus_policy_query_unlocked() - Query the policy database -+ * @db: Policy database -+ * @cred: Credentials to test against -+ * @name: Name to query -+ * @hash: Hash value of @name -+ * -+ * Same as kdbus_policy_query() but requires the caller to lock the policy -+ * database against concurrent writes. -+ * -+ * Return: The highest KDBUS_POLICY_* access type found, or -EPERM if none. -+ */ -+int kdbus_policy_query_unlocked(struct kdbus_policy_db *db, -+ const struct cred *cred, const char *name, -+ unsigned int hash) -+{ -+ struct kdbus_policy_db_entry_access *a; -+ const struct kdbus_policy_db_entry *e; -+ int i, highest = -EPERM; -+ -+ e = kdbus_policy_lookup(db, name, hash); -+ if (!e) -+ return -EPERM; -+ -+ list_for_each_entry(a, &e->access_list, list) { -+ if ((int)a->access <= highest) -+ continue; -+ -+ switch (a->type) { -+ case KDBUS_POLICY_ACCESS_USER: -+ if (uid_eq(cred->euid, a->uid)) -+ highest = a->access; -+ break; -+ case KDBUS_POLICY_ACCESS_GROUP: -+ if (gid_eq(cred->egid, a->gid)) { -+ highest = a->access; -+ break; -+ } -+ -+ for (i = 0; i < cred->group_info->ngroups; i++) { -+ kgid_t gid = GROUP_AT(cred->group_info, i); -+ -+ if (gid_eq(gid, a->gid)) { -+ highest = a->access; -+ break; -+ } -+ } -+ -+ break; -+ case KDBUS_POLICY_ACCESS_WORLD: -+ highest = a->access; -+ break; -+ } -+ -+ /* OWN is the highest possible policy */ -+ if (highest >= KDBUS_POLICY_OWN) -+ break; -+ } -+ -+ return highest; -+} -+ -+/** -+ * kdbus_policy_query() - Query the policy database -+ * @db: Policy database -+ * @cred: Credentials to test against -+ * @name: Name to query -+ * @hash: Hash value of @name -+ * -+ * Query the policy database @db for the access rights of @cred to the name -+ * @name. The access rights of @cred are returned, or -EPERM if no access is -+ * granted. -+ * -+ * This call effectively searches for the highest access-right granted to -+ * @cred. The caller should really cache those as policy lookups are rather -+ * expensive. -+ * -+ * Return: The highest KDBUS_POLICY_* access type found, or -EPERM if none. -+ */ -+int kdbus_policy_query(struct kdbus_policy_db *db, const struct cred *cred, -+ const char *name, unsigned int hash) -+{ -+ int ret; -+ -+ down_read(&db->entries_rwlock); -+ ret = kdbus_policy_query_unlocked(db, cred, name, hash); -+ up_read(&db->entries_rwlock); -+ -+ return ret; -+} -+ -+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); -+ up_write(&db->entries_rwlock); -+} -+ -+/* -+ * 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: -+ 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. -+ * -+ * Callers to this function must make sur that the owner is a custom -+ * endpoint, or if the endpoint is a default endpoint, then it must be -+ * either a policy holder or an activator. -+ * -+ * 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; -+ -+ /* 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_strhash(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); -+ } -+ -+restore: -+ /* if we failed, flush all entries we added so far */ -+ 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_strhash(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; -+} -diff --git a/ipc/kdbus/policy.h b/ipc/kdbus/policy.h -new file mode 100644 -index 000000000000..15dd7bc12068 ---- /dev/null -+++ b/ipc/kdbus/policy.h -@@ -0,0 +1,51 @@ -+/* -+ * Copyright (C) 2013-2015 Kay Sievers -+ * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> -+ * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> -+ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> -+ * Copyright (C) 2013-2015 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_POLICY_H -+#define __KDBUS_POLICY_H -+ -+#include <linux/hashtable.h> -+#include <linux/rwsem.h> -+ -+struct kdbus_conn; -+struct kdbus_item; -+ -+/** -+ * struct kdbus_policy_db - policy database -+ * @entries_hash: Hashtable of entries -+ * @entries_rwlock: Mutex to protect the database's access entries -+ */ -+struct kdbus_policy_db { -+ DECLARE_HASHTABLE(entries_hash, 6); -+ struct rw_semaphore entries_rwlock; -+}; -+ -+void kdbus_policy_db_init(struct kdbus_policy_db *db); -+void kdbus_policy_db_clear(struct kdbus_policy_db *db); -+ -+int kdbus_policy_query_unlocked(struct kdbus_policy_db *db, -+ const struct cred *cred, const char *name, -+ unsigned int hash); -+int kdbus_policy_query(struct kdbus_policy_db *db, const struct cred *cred, -+ const char *name, unsigned int hash); -+ -+void kdbus_policy_remove_owner(struct kdbus_policy_db *db, -+ const void *owner); -+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); -+ -+#endif --- -2.4.3 - - -From 9f086b571fbbdb566bd99240e3138f77ec419b75 Mon Sep 17 00:00:00 2001 -From: Daniel Mack <daniel@zonque.org> -Date: Thu, 11 Sep 2014 18:48:06 +0200 -Subject: [PATCH 012/132] kdbus: add Makefile, Kconfig and MAINTAINERS entry - -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. - -Signed-off-by: Daniel Mack <daniel@zonque.org> -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Djalal Harouni <tixxdz@opendz.org> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - MAINTAINERS | 13 +++++++++++++ - init/Kconfig | 12 ++++++++++++ - ipc/Makefile | 2 +- - ipc/kdbus/Makefile | 22 ++++++++++++++++++++++ - 4 files changed, 48 insertions(+), 1 deletion(-) - create mode 100644 ipc/kdbus/Makefile - -diff --git a/MAINTAINERS b/MAINTAINERS -index 6239a305dff0..e924246fb545 100644 ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -5503,6 +5503,19 @@ S: Maintained - F: Documentation/kbuild/kconfig-language.txt - F: scripts/kconfig/ - -+KDBUS -+M: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -+M: Daniel Mack <daniel@zonque.org> -+M: David Herrmann <dh.herrmann@googlemail.com> -+M: Djalal Harouni <tixxdz@opendz.org> -+L: linux-kernel@vger.kernel.org -+S: Maintained -+F: ipc/kdbus/* -+F: samples/kdbus/* -+F: Documentation/kdbus/* -+F: include/uapi/linux/kdbus.h -+F: tools/testing/selftests/kdbus/ -+ - KDUMP - M: Vivek Goyal <vgoyal@redhat.com> - M: Haren Myneni <hbabu@us.ibm.com> -diff --git a/init/Kconfig b/init/Kconfig -index f5dbc6d4261b..a7b462e7d647 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -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 -diff --git a/ipc/Makefile b/ipc/Makefile -index 86c7300ecdf5..68ec4167d11b 100644 ---- a/ipc/Makefile -+++ b/ipc/Makefile -@@ -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/ -diff --git a/ipc/kdbus/Makefile b/ipc/kdbus/Makefile -new file mode 100644 -index 000000000000..7ee9271e1449 ---- /dev/null -+++ b/ipc/kdbus/Makefile -@@ -0,0 +1,22 @@ -+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 \ -+ reply.o \ -+ queue.o \ -+ util.o -+ -+obj-$(CONFIG_KDBUS) += kdbus.o --- -2.4.3 - - -From 2d41f81385089e16aa7ab260ce6819febbee5830 Mon Sep 17 00:00:00 2001 -From: Daniel Mack <daniel@zonque.org> -Date: Thu, 26 Feb 2015 21:06:38 +0100 -Subject: [PATCH 013/132] kdbus: add walk-through user space example - -Provide a walk-through example that explains how to use the low-level -ioctl API that kdbus offers. This example is meant to be useful for -developers who want to gain a in-depth understanding of how the kdbus -API works by reading a well-documented real-world example. - -This program computes prime-numbers based on the sieve of Eratosthenes. -The master sets up a shared memory region and spawns workers which clear -out the non-primes. The master reacts to keyboard input and to -client-requests to control what each worker does. Note that this is in -no way meant as efficient way to compute primes. It should only serve as -example how a master/worker concept can be implemented with kdbus used -as control messages. - -The main process is called the 'master'. It creates a new, private bus -which will be used between the master and its workers to communicate. -The master then spawns a fixed number of workers. Whenever a worker dies -(detected via SIGCHLD), the master spawns a new worker. When done, the -master waits for all workers to exit, prints a status report and exits -itself. - -The master process does *not* keep track of its workers. Instead, this -example implements a PULL model. That is, the master acquires a -well-known name on the bus which each worker uses to request tasks from -the master. If there are no more tasks, the master will return an empty -task-list, which casues a worker to exit immediately. - -As tasks can be computationally expensive, we support cancellation. -Whenever the master process is interrupted, it will drop its well-known -name on the bus. This causes kdbus to broadcast a name-change -notification. The workers check for broadcast messages regularly and -will exit if they receive one. - -Signed-off-by: Daniel Mack <daniel@zonque.org> -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Djalal Harouni <tixxdz@opendz.org> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - samples/Makefile | 3 +- - samples/kdbus/.gitignore | 1 + - samples/kdbus/Makefile | 10 + - samples/kdbus/kdbus-api.h | 114 ++++ - samples/kdbus/kdbus-workers.c | 1326 +++++++++++++++++++++++++++++++++++++++++ - 5 files changed, 1453 insertions(+), 1 deletion(-) - create mode 100644 samples/kdbus/.gitignore - create mode 100644 samples/kdbus/Makefile - create mode 100644 samples/kdbus/kdbus-api.h - create mode 100644 samples/kdbus/kdbus-workers.c - -diff --git a/samples/Makefile b/samples/Makefile -index f00257bcc5a7..f0ad51e5b342 100644 ---- a/samples/Makefile -+++ b/samples/Makefile -@@ -1,4 +1,5 @@ - # Makefile for Linux samples code - - obj-$(CONFIG_SAMPLES) += kobject/ kprobes/ trace_events/ livepatch/ \ -- hw_breakpoint/ kfifo/ kdb/ hidraw/ rpmsg/ seccomp/ -+ hw_breakpoint/ kfifo/ kdb/ kdbus/ hidraw/ rpmsg/ \ -+ seccomp/ -diff --git a/samples/kdbus/.gitignore b/samples/kdbus/.gitignore -new file mode 100644 -index 000000000000..ee07d9857086 ---- /dev/null -+++ b/samples/kdbus/.gitignore -@@ -0,0 +1 @@ -+kdbus-workers -diff --git a/samples/kdbus/Makefile b/samples/kdbus/Makefile -new file mode 100644 -index 000000000000..d009025369f4 ---- /dev/null -+++ b/samples/kdbus/Makefile -@@ -0,0 +1,10 @@ -+# kbuild trick to avoid linker error. Can be omitted if a module is built. -+obj- := dummy.o -+ -+hostprogs-y += kdbus-workers -+ -+always := $(hostprogs-y) -+ -+HOSTCFLAGS_kdbus-workers.o += \ -+ -I$(objtree)/usr/include/ \ -+ -I$(objtree)/include/uapi/ -diff --git a/samples/kdbus/kdbus-api.h b/samples/kdbus/kdbus-api.h -new file mode 100644 -index 000000000000..5ed5907c5cb4 ---- /dev/null -+++ b/samples/kdbus/kdbus-api.h -@@ -0,0 +1,114 @@ -+#ifndef KDBUS_API_H -+#define KDBUS_API_H -+ -+#include <sys/ioctl.h> -+#include <linux/kdbus.h> -+ -+#define KDBUS_ALIGN8(l) (((l) + 7) & ~7) -+#define KDBUS_ITEM_HEADER_SIZE offsetof(struct kdbus_item, data) -+#define KDBUS_ITEM_SIZE(s) KDBUS_ALIGN8((s) + KDBUS_ITEM_HEADER_SIZE) -+#define KDBUS_ITEM_NEXT(item) \ -+ (typeof(item))(((uint8_t *)item) + KDBUS_ALIGN8((item)->size)) -+#define KDBUS_FOREACH(iter, first, _size) \ -+ for (iter = (first); \ -+ ((uint8_t *)(iter) < (uint8_t *)(first) + (_size)) && \ -+ ((uint8_t *)(iter) >= (uint8_t *)(first)); \ -+ iter = (void*)(((uint8_t *)iter) + KDBUS_ALIGN8((iter)->size))) -+ -+static inline int kdbus_cmd_bus_make(int control_fd, struct kdbus_cmd *cmd) -+{ -+ int ret = ioctl(control_fd, KDBUS_CMD_BUS_MAKE, cmd); -+ return (ret < 0) ? (errno > 0 ? -errno : -EINVAL) : 0; -+} -+ -+static inline int kdbus_cmd_endpoint_make(int bus_fd, struct kdbus_cmd *cmd) -+{ -+ int ret = ioctl(bus_fd, KDBUS_CMD_ENDPOINT_MAKE, cmd); -+ return (ret < 0) ? (errno > 0 ? -errno : -EINVAL) : 0; -+} -+ -+static inline int kdbus_cmd_endpoint_update(int ep_fd, struct kdbus_cmd *cmd) -+{ -+ int ret = ioctl(ep_fd, KDBUS_CMD_ENDPOINT_UPDATE, cmd); -+ return (ret < 0) ? (errno > 0 ? -errno : -EINVAL) : 0; -+} -+ -+static inline int kdbus_cmd_hello(int bus_fd, struct kdbus_cmd_hello *cmd) -+{ -+ int ret = ioctl(bus_fd, KDBUS_CMD_HELLO, cmd); -+ return (ret < 0) ? (errno > 0 ? -errno : -EINVAL) : 0; -+} -+ -+static inline int kdbus_cmd_update(int fd, struct kdbus_cmd *cmd) -+{ -+ int ret = ioctl(fd, KDBUS_CMD_UPDATE, cmd); -+ return (ret < 0) ? (errno > 0 ? -errno : -EINVAL) : 0; -+} -+ -+static inline int kdbus_cmd_byebye(int conn_fd, struct kdbus_cmd *cmd) -+{ -+ int ret = ioctl(conn_fd, KDBUS_CMD_BYEBYE, cmd); -+ return (ret < 0) ? (errno > 0 ? -errno : -EINVAL) : 0; -+} -+ -+static inline int kdbus_cmd_free(int conn_fd, struct kdbus_cmd_free *cmd) -+{ -+ int ret = ioctl(conn_fd, KDBUS_CMD_FREE, cmd); -+ return (ret < 0) ? (errno > 0 ? -errno : -EINVAL) : 0; -+} -+ -+static inline int kdbus_cmd_conn_info(int conn_fd, struct kdbus_cmd_info *cmd) -+{ -+ int ret = ioctl(conn_fd, KDBUS_CMD_CONN_INFO, cmd); -+ return (ret < 0) ? (errno > 0 ? -errno : -EINVAL) : 0; -+} -+ -+static inline int kdbus_cmd_bus_creator_info(int conn_fd, struct kdbus_cmd_info *cmd) -+{ -+ int ret = ioctl(conn_fd, KDBUS_CMD_BUS_CREATOR_INFO, cmd); -+ return (ret < 0) ? (errno > 0 ? -errno : -EINVAL) : 0; -+} -+ -+static inline int kdbus_cmd_list(int fd, struct kdbus_cmd_list *cmd) -+{ -+ int ret = ioctl(fd, KDBUS_CMD_LIST, cmd); -+ return (ret < 0) ? (errno > 0 ? -errno : -EINVAL) : 0; -+} -+ -+static inline int kdbus_cmd_send(int conn_fd, struct kdbus_cmd_send *cmd) -+{ -+ int ret = ioctl(conn_fd, KDBUS_CMD_SEND, cmd); -+ return (ret < 0) ? (errno > 0 ? -errno : -EINVAL) : 0; -+} -+ -+static inline int kdbus_cmd_recv(int conn_fd, struct kdbus_cmd_recv *cmd) -+{ -+ int ret = ioctl(conn_fd, KDBUS_CMD_RECV, cmd); -+ return (ret < 0) ? (errno > 0 ? -errno : -EINVAL) : 0; -+} -+ -+static inline int kdbus_cmd_name_acquire(int conn_fd, struct kdbus_cmd *cmd) -+{ -+ int ret = ioctl(conn_fd, KDBUS_CMD_NAME_ACQUIRE, cmd); -+ return (ret < 0) ? (errno > 0 ? -errno : -EINVAL) : 0; -+} -+ -+static inline int kdbus_cmd_name_release(int conn_fd, struct kdbus_cmd *cmd) -+{ -+ int ret = ioctl(conn_fd, KDBUS_CMD_NAME_RELEASE, cmd); -+ return (ret < 0) ? (errno > 0 ? -errno : -EINVAL) : 0; -+} -+ -+static inline int kdbus_cmd_match_add(int conn_fd, struct kdbus_cmd_match *cmd) -+{ -+ int ret = ioctl(conn_fd, KDBUS_CMD_MATCH_ADD, cmd); -+ return (ret < 0) ? (errno > 0 ? -errno : -EINVAL) : 0; -+} -+ -+static inline int kdbus_cmd_match_remove(int conn_fd, struct kdbus_cmd_match *cmd) -+{ -+ int ret = ioctl(conn_fd, KDBUS_CMD_MATCH_REMOVE, cmd); -+ return (ret < 0) ? (errno > 0 ? -errno : -EINVAL) : 0; -+} -+ -+#endif /* KDBUS_API_H */ -diff --git a/samples/kdbus/kdbus-workers.c b/samples/kdbus/kdbus-workers.c -new file mode 100644 -index 000000000000..d1d8f7a7697b ---- /dev/null -+++ b/samples/kdbus/kdbus-workers.c -@@ -0,0 +1,1326 @@ -+/* -+ * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> -+ * -+ * 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. -+ */ -+ -+/* -+ * Example: Workers -+ * This program computes prime-numbers based on the sieve of Eratosthenes. The -+ * master sets up a shared memory region and spawns workers which clear out the -+ * non-primes. The master reacts to keyboard input and to client-requests to -+ * control what each worker does. Note that this is in no way meant as efficient -+ * way to compute primes. It should only serve as example how a master/worker -+ * concept can be implemented with kdbus used as control messages. -+ * -+ * The main process is called the 'master'. It creates a new, private bus which -+ * will be used between the master and its workers to communicate. The master -+ * then spawns a fixed number of workers. Whenever a worker dies (detected via -+ * SIGCHLD), the master spawns a new worker. When done, the master waits for all -+ * workers to exit, prints a status report and exits itself. -+ * -+ * The master process does *not* keep track of its workers. Instead, this -+ * example implements a PULL model. That is, the master acquires a well-known -+ * name on the bus which each worker uses to request tasks from the master. If -+ * there are no more tasks, the master will return an empty task-list, which -+ * casues a worker to exit immediately. -+ * -+ * As tasks can be computationally expensive, we support cancellation. Whenever -+ * the master process is interrupted, it will drop its well-known name on the -+ * bus. This causes kdbus to broadcast a name-change notification. The workers -+ * check for broadcast messages regularly and will exit if they receive one. -+ * -+ * This example exists of 4 objects: -+ * * master: The master object contains the context of the master process. This -+ * process manages the prime-context, spawns workers and assigns -+ * prime-ranges to each worker to compute. -+ * The master itself does not do any prime-computations itself. -+ * * child: The child object contains the context of a worker. It inherits the -+ * prime context from its parent (the master) and then creates a new -+ * bus context to request prime-ranges to compute. -+ * * prime: The "prime" object is used to abstract how we compute primes. When -+ * allocated, it prepares a memory region to hold 1 bit for each -+ * natural number up to a fixed maximum ('MAX_PRIMES'). -+ * The memory region is backed by a memfd which we share between -+ * processes. Each worker now gets assigned a range of natural -+ * numbers which it clears multiples of off the memory region. The -+ * master process is responsible of distributing all natural numbers -+ * up to the fixed maximum to its workers. -+ * * bus: The bus object is an abstraction of the kdbus API. It is pretty -+ * straightfoward and only manages the connection-fd plus the -+ * memory-mapped pool in a single object. -+ * -+ * This example is in reversed order, which should make it easier to read -+ * top-down, but requires some forward-declarations. Just ignore those. -+ */ -+ -+#include <ctype.h> -+#include <errno.h> -+#include <fcntl.h> -+#include <linux/memfd.h> -+#include <signal.h> -+#include <stdbool.h> -+#include <stddef.h> -+#include <stdint.h> -+#include <stdio.h> -+#include <stdlib.h> -+#include <string.h> -+#include <sys/mman.h> -+#include <sys/poll.h> -+#include <sys/signalfd.h> -+#include <sys/syscall.h> -+#include <sys/time.h> -+#include <sys/wait.h> -+#include <time.h> -+#include <unistd.h> -+#include "kdbus-api.h" -+ -+/* FORWARD DECLARATIONS */ -+ -+#define POOL_SIZE (16 * 1024 * 1024) -+#define MAX_PRIMES (2UL << 24) -+#define WORKER_COUNT (16) -+#define PRIME_STEPS (65536 * 4) -+ -+static const char *arg_busname = "example-workers"; -+static const char *arg_modname = "kdbus"; -+static const char *arg_master = "org.freedesktop.master"; -+ -+static int err_assert(int r_errno, const char *msg, const char *func, int line, -+ const char *file) -+{ -+ r_errno = (r_errno != 0) ? -abs(r_errno) : -EFAULT; -+ if (r_errno < 0) { -+ errno = -r_errno; -+ fprintf(stderr, "ERR: %s: %m (%s:%d in %s)\n", -+ msg, func, line, file); -+ } -+ return r_errno; -+} -+ -+#define err_r(_r, _msg) err_assert((_r), (_msg), __func__, __LINE__, __FILE__) -+#define err(_msg) err_r(errno, (_msg)) -+ -+struct prime; -+struct bus; -+struct master; -+struct child; -+ -+struct prime { -+ int fd; -+ uint8_t *area; -+ size_t max; -+ size_t done; -+ size_t status; -+}; -+ -+static int prime_new(struct prime **out); -+static void prime_free(struct prime *p); -+static bool prime_done(struct prime *p); -+static void prime_consume(struct prime *p, size_t amount); -+static int prime_run(struct prime *p, struct bus *cancel, size_t number); -+static void prime_print(struct prime *p); -+ -+struct bus { -+ int fd; -+ uint8_t *pool; -+}; -+ -+static int bus_open_connection(struct bus **out, uid_t uid, const char *name, -+ uint64_t recv_flags); -+static void bus_close_connection(struct bus *b); -+static void bus_poool_free_slice(struct bus *b, uint64_t offset); -+static int bus_acquire_name(struct bus *b, const char *name); -+static int bus_install_name_loss_match(struct bus *b, const char *name); -+static int bus_poll(struct bus *b); -+static int bus_make(uid_t uid, const char *name); -+ -+struct master { -+ size_t n_workers; -+ size_t max_workers; -+ -+ int signal_fd; -+ int control_fd; -+ -+ struct prime *prime; -+ struct bus *bus; -+}; -+ -+static int master_new(struct master **out); -+static void master_free(struct master *m); -+static int master_run(struct master *m); -+static int master_poll(struct master *m); -+static int master_handle_stdin(struct master *m); -+static int master_handle_signal(struct master *m); -+static int master_handle_bus(struct master *m); -+static int master_reply(struct master *m, const struct kdbus_msg *msg); -+static int master_waitpid(struct master *m); -+static int master_spawn(struct master *m); -+ -+struct child { -+ struct bus *bus; -+ struct prime *prime; -+}; -+ -+static int child_new(struct child **out, struct prime *p); -+static void child_free(struct child *c); -+static int child_run(struct child *c); -+ -+/* END OF FORWARD DECLARATIONS */ -+ -+/* -+ * This is the main entrypoint of this example. It is pretty straightforward. We -+ * create a master object, run the computation, print a status report and then -+ * exit. Nothing particularly interesting here, so lets look into the master -+ * object... -+ */ -+int main(int argc, char **argv) -+{ -+ struct master *m = NULL; -+ int r; -+ -+ r = master_new(&m); -+ if (r < 0) -+ goto out; -+ -+ r = master_run(m); -+ if (r < 0) -+ goto out; -+ -+ if (0) -+ prime_print(m->prime); -+ -+out: -+ master_free(m); -+ if (r < 0 && r != -EINTR) -+ fprintf(stderr, "failed\n"); -+ else -+ fprintf(stderr, "done\n"); -+ return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; -+} -+ -+/* -+ * ...this will allocate a new master context. It keeps track of the current -+ * number of children/workers that are running, manages a signalfd to track -+ * SIGCHLD, and creates a private kdbus bus. Afterwards, it opens its connection -+ * to the bus and acquires a well known-name (arg_master). -+ */ -+static int master_new(struct master **out) -+{ -+ struct master *m; -+ sigset_t smask; -+ int r; -+ -+ m = calloc(1, sizeof(*m)); -+ if (!m) -+ return err("cannot allocate master"); -+ -+ m->max_workers = WORKER_COUNT; -+ m->signal_fd = -1; -+ m->control_fd = -1; -+ -+ /* Block SIGINT and SIGCHLD signals */ -+ sigemptyset(&smask); -+ sigaddset(&smask, SIGINT); -+ sigaddset(&smask, SIGCHLD); -+ sigprocmask(SIG_BLOCK, &smask, NULL); -+ -+ m->signal_fd = signalfd(-1, &smask, SFD_CLOEXEC); -+ if (m->signal_fd < 0) { -+ r = err("cannot create signalfd"); -+ goto error; -+ } -+ -+ r = prime_new(&m->prime); -+ if (r < 0) -+ goto error; -+ -+ m->control_fd = bus_make(getuid(), arg_busname); -+ if (m->control_fd < 0) { -+ r = m->control_fd; -+ goto error; -+ } -+ -+ /* -+ * Open a bus connection for the master, and require each received -+ * message to have a metadata item of type KDBUS_ITEM_PIDS attached. -+ * The current UID is needed to compute the name of the bus node to -+ * connect to. -+ */ -+ r = bus_open_connection(&m->bus, getuid(), -+ arg_busname, KDBUS_ATTACH_PIDS); -+ if (r < 0) -+ goto error; -+ -+ /* -+ * Acquire a well-known name on the bus, so children can address -+ * messages to the master using KDBUS_DST_ID_NAME as destination-ID -+ * of messages. -+ */ -+ r = bus_acquire_name(m->bus, arg_master); -+ if (r < 0) -+ goto error; -+ -+ *out = m; -+ return 0; -+ -+error: -+ master_free(m); -+ return r; -+} -+ -+/* pretty straightforward destructor of a master object */ -+static void master_free(struct master *m) -+{ -+ if (!m) -+ return; -+ -+ bus_close_connection(m->bus); -+ if (m->control_fd >= 0) -+ close(m->control_fd); -+ prime_free(m->prime); -+ if (m->signal_fd >= 0) -+ close(m->signal_fd); -+ free(m); -+} -+ -+static int master_run(struct master *m) -+{ -+ int res, r = 0; -+ -+ while (!prime_done(m->prime)) { -+ while (m->n_workers < m->max_workers) { -+ r = master_spawn(m); -+ if (r < 0) -+ break; -+ } -+ -+ r = master_poll(m); -+ if (r < 0) -+ break; -+ } -+ -+ if (r < 0) { -+ bus_close_connection(m->bus); -+ m->bus = NULL; -+ } -+ -+ while (m->n_workers > 0) { -+ res = master_poll(m); -+ if (res < 0) { -+ if (m->bus) { -+ bus_close_connection(m->bus); -+ m->bus = NULL; -+ } -+ r = res; -+ } -+ } -+ -+ return r == -EINTR ? 0 : r; -+} -+ -+static int master_poll(struct master *m) -+{ -+ struct pollfd fds[3] = {}; -+ int r = 0, n = 0; -+ -+ /* -+ * Add stdin, the eventfd and the connection owner file descriptor to -+ * the pollfd table, and handle incoming traffic on the latter in -+ * master_handle_bus(). -+ */ -+ fds[n].fd = STDIN_FILENO; -+ fds[n++].events = POLLIN; -+ fds[n].fd = m->signal_fd; -+ fds[n++].events = POLLIN; -+ if (m->bus) { -+ fds[n].fd = m->bus->fd; -+ fds[n++].events = POLLIN; -+ } -+ -+ r = poll(fds, n, -1); -+ if (r < 0) -+ return err("poll() failed"); -+ -+ if (fds[0].revents & POLLIN) -+ r = master_handle_stdin(m); -+ else if (fds[0].revents) -+ r = err("ERR/HUP on stdin"); -+ if (r < 0) -+ return r; -+ -+ if (fds[1].revents & POLLIN) -+ r = master_handle_signal(m); -+ else if (fds[1].revents) -+ r = err("ERR/HUP on signalfd"); -+ if (r < 0) -+ return r; -+ -+ if (fds[2].revents & POLLIN) -+ r = master_handle_bus(m); -+ else if (fds[2].revents) -+ r = err("ERR/HUP on bus"); -+ -+ return r; -+} -+ -+static int master_handle_stdin(struct master *m) -+{ -+ char buf[128]; -+ ssize_t l; -+ int r = 0; -+ -+ l = read(STDIN_FILENO, buf, sizeof(buf)); -+ if (l < 0) -+ return err("cannot read stdin"); -+ if (l == 0) -+ return err_r(-EINVAL, "EOF on stdin"); -+ -+ while (l-- > 0) { -+ switch (buf[l]) { -+ case 'q': -+ /* quit */ -+ r = -EINTR; -+ break; -+ case '\n': -+ case ' ': -+ /* ignore */ -+ break; -+ default: -+ if (isgraph(buf[l])) -+ fprintf(stderr, "invalid input '%c'\n", buf[l]); -+ else -+ fprintf(stderr, "invalid input 0x%x\n", buf[l]); -+ break; -+ } -+ } -+ -+ return r; -+} -+ -+static int master_handle_signal(struct master *m) -+{ -+ struct signalfd_siginfo val; -+ ssize_t l; -+ -+ l = read(m->signal_fd, &val, sizeof(val)); -+ if (l < 0) -+ return err("cannot read signalfd"); -+ if (l != sizeof(val)) -+ return err_r(-EINVAL, "invalid data from signalfd"); -+ -+ switch (val.ssi_signo) { -+ case SIGCHLD: -+ return master_waitpid(m); -+ case SIGINT: -+ return err_r(-EINTR, "interrupted"); -+ default: -+ return err_r(-EINVAL, "caught invalid signal"); -+ } -+} -+ -+static int master_handle_bus(struct master *m) -+{ -+ struct kdbus_cmd_recv recv = { .size = sizeof(recv) }; -+ const struct kdbus_msg *msg = NULL; -+ const struct kdbus_item *item; -+ const struct kdbus_vec *vec = NULL; -+ int r = 0; -+ -+ /* -+ * To receive a message, the KDBUS_CMD_RECV ioctl is used. -+ * It takes an argument of type 'struct kdbus_cmd_recv', which -+ * will contain information on the received message when the call -+ * returns. See kdbus.message(7). -+ */ -+ r = kdbus_cmd_recv(m->bus->fd, &recv); -+ /* -+ * EAGAIN is returned when there is no message waiting on this -+ * connection. This is not an error - simply bail out. -+ */ -+ if (r == -EAGAIN) -+ return 0; -+ if (r < 0) -+ return err_r(r, "cannot receive message"); -+ -+ /* -+ * Messages received by a connection are stored inside the connection's -+ * pool, at an offset that has been returned in the 'recv' command -+ * struct above. The value describes the relative offset from the -+ * start address of the pool. A message is described with -+ * 'struct kdbus_msg'. See kdbus.message(7). -+ */ -+ msg = (void *)(m->bus->pool + recv.msg.offset); -+ -+ /* -+ * A messages describes its actual payload in an array of items. -+ * KDBUS_FOREACH() is a simple iterator that walks such an array. -+ * struct kdbus_msg has a field to denote its total size, which is -+ * needed to determine the number of items in the array. -+ */ -+ KDBUS_FOREACH(item, msg->items, -+ msg->size - offsetof(struct kdbus_msg, items)) { -+ /* -+ * An item of type PAYLOAD_OFF describes in-line memory -+ * stored in the pool at a described offset. That offset is -+ * relative to the start address of the message header. -+ * This example program only expects one single item of that -+ * type, remembers the struct kdbus_vec member of the item -+ * when it sees it, and bails out if there is more than one -+ * of them. -+ */ -+ if (item->type == KDBUS_ITEM_PAYLOAD_OFF) { -+ if (vec) { -+ r = err_r(-EEXIST, -+ "message with multiple vecs"); -+ break; -+ } -+ vec = &item->vec; -+ if (vec->size != 1) { -+ r = err_r(-EINVAL, "invalid message size"); -+ break; -+ } -+ -+ /* -+ * MEMFDs are transported as items of type PAYLOAD_MEMFD. -+ * If such an item is attached, a new file descriptor was -+ * installed into the task when KDBUS_CMD_RECV was called, and -+ * its number is stored in item->memfd.fd. -+ * Implementers *must* handle this item type and close the -+ * file descriptor when no longer needed in order to prevent -+ * file descriptor exhaustion. This example program just bails -+ * out with an error in this case, as memfds are not expected -+ * in this context. -+ */ -+ } else if (item->type == KDBUS_ITEM_PAYLOAD_MEMFD) { -+ r = err_r(-EINVAL, "message with memfd"); -+ break; -+ } -+ } -+ if (r < 0) -+ goto exit; -+ if (!vec) { -+ r = err_r(-EINVAL, "empty message"); -+ goto exit; -+ } -+ -+ switch (*((const uint8_t *)msg + vec->offset)) { -+ case 'r': { -+ r = master_reply(m, msg); -+ break; -+ } -+ default: -+ r = err_r(-EINVAL, "invalid message type"); -+ break; -+ } -+ -+exit: -+ /* -+ * We are done with the memory slice that was given to us through -+ * recv.msg.offset. Tell the kernel it can use it for other content -+ * in the future. See kdbus.pool(7). -+ */ -+ bus_poool_free_slice(m->bus, recv.msg.offset); -+ return r; -+} -+ -+static int master_reply(struct master *m, const struct kdbus_msg *msg) -+{ -+ struct kdbus_cmd_send cmd; -+ struct kdbus_item *item; -+ struct kdbus_msg *reply; -+ size_t size, status, p[2]; -+ int r; -+ -+ /* -+ * This functions sends a message over kdbus. To do this, it uses the -+ * KDBUS_CMD_SEND ioctl, which takes a command struct argument of type -+ * 'struct kdbus_cmd_send'. This struct stores a pointer to the actual -+ * message to send. See kdbus.message(7). -+ */ -+ p[0] = m->prime->done; -+ p[1] = prime_done(m->prime) ? 0 : PRIME_STEPS; -+ -+ size = sizeof(*reply); -+ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec)); -+ -+ /* Prepare the message to send */ -+ reply = alloca(size); -+ memset(reply, 0, size); -+ reply->size = size; -+ -+ /* Each message has a cookie that can be used to send replies */ -+ reply->cookie = 1; -+ -+ /* The payload_type is arbitrary, but it must be non-zero */ -+ reply->payload_type = 0xdeadbeef; -+ -+ /* -+ * We are sending a reply. Let the kernel know the cookie of the -+ * message we are replying to. -+ */ -+ reply->cookie_reply = msg->cookie; -+ -+ /* -+ * Messages can either be directed to a well-known name (stored as -+ * string) or to a unique name (stored as number). This example does -+ * the latter. If the message would be directed to a well-known name -+ * instead, the message's dst_id field would be set to -+ * KDBUS_DST_ID_NAME, and the name would be attaches in an item of type -+ * KDBUS_ITEM_DST_NAME. See below for an example, and also refer to -+ * kdbus.message(7). -+ */ -+ reply->dst_id = msg->src_id; -+ -+ /* Our message has exactly one item to store its payload */ -+ item = reply->items; -+ item->type = KDBUS_ITEM_PAYLOAD_VEC; -+ item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_vec); -+ item->vec.address = (uintptr_t)p; -+ item->vec.size = sizeof(p); -+ -+ /* -+ * Now prepare the command struct, and reference the message we want -+ * to send. -+ */ -+ memset(&cmd, 0, sizeof(cmd)); -+ cmd.size = sizeof(cmd); -+ cmd.msg_address = (uintptr_t)reply; -+ -+ /* -+ * Finally, employ the command on the connection owner -+ * file descriptor. -+ */ -+ r = kdbus_cmd_send(m->bus->fd, &cmd); -+ if (r < 0) -+ return err_r(r, "cannot send reply"); -+ -+ if (p[1]) { -+ prime_consume(m->prime, p[1]); -+ status = m->prime->done * 10000 / m->prime->max; -+ if (status != m->prime->status) { -+ m->prime->status = status; -+ fprintf(stderr, "status: %7.3lf%%\n", -+ (double)status / 100); -+ } -+ } -+ -+ return 0; -+} -+ -+static int master_waitpid(struct master *m) -+{ -+ pid_t pid; -+ int r; -+ -+ while ((pid = waitpid(-1, &r, WNOHANG)) > 0) { -+ if (m->n_workers > 0) -+ --m->n_workers; -+ if (!WIFEXITED(r)) -+ r = err_r(-EINVAL, "child died unexpectedly"); -+ else if (WEXITSTATUS(r) != 0) -+ r = err_r(-WEXITSTATUS(r), "child failed"); -+ } -+ -+ return r; -+} -+ -+static int master_spawn(struct master *m) -+{ -+ struct child *c = NULL; -+ struct prime *p = NULL; -+ pid_t pid; -+ int r; -+ -+ /* Spawn off one child and call child_run() inside it */ -+ -+ pid = fork(); -+ if (pid < 0) -+ return err("cannot fork"); -+ if (pid > 0) { -+ /* parent */ -+ ++m->n_workers; -+ return 0; -+ } -+ -+ /* child */ -+ -+ p = m->prime; -+ m->prime = NULL; -+ master_free(m); -+ -+ r = child_new(&c, p); -+ if (r < 0) -+ goto exit; -+ -+ r = child_run(c); -+ -+exit: -+ child_free(c); -+ exit(abs(r)); -+} -+ -+static int child_new(struct child **out, struct prime *p) -+{ -+ struct child *c; -+ int r; -+ -+ c = calloc(1, sizeof(*c)); -+ if (!c) -+ return err("cannot allocate child"); -+ -+ c->prime = p; -+ -+ /* -+ * Open a connection to the bus and require each received message to -+ * carry a list of the well-known names the sendind connection currently -+ * owns. The current UID is needed in order to determine the name of the -+ * bus node to connect to. -+ */ -+ r = bus_open_connection(&c->bus, getuid(), -+ arg_busname, KDBUS_ATTACH_NAMES); -+ if (r < 0) -+ goto error; -+ -+ /* -+ * Install a kdbus match so the child's connection gets notified when -+ * the master loses its well-known name. -+ */ -+ r = bus_install_name_loss_match(c->bus, arg_master); -+ if (r < 0) -+ goto error; -+ -+ *out = c; -+ return 0; -+ -+error: -+ child_free(c); -+ return r; -+} -+ -+static void child_free(struct child *c) -+{ -+ if (!c) -+ return; -+ -+ bus_close_connection(c->bus); -+ prime_free(c->prime); -+ free(c); -+} -+ -+static int child_run(struct child *c) -+{ -+ struct kdbus_cmd_send cmd; -+ struct kdbus_item *item; -+ struct kdbus_vec *vec = NULL; -+ struct kdbus_msg *msg; -+ struct timespec spec; -+ size_t n, steps, size; -+ int r = 0; -+ -+ /* -+ * Let's send a message to the master and ask for work. To do this, -+ * we use the KDBUS_CMD_SEND ioctl, which takes an argument of type -+ * 'struct kdbus_cmd_send'. This struct stores a pointer to the actual -+ * message to send. See kdbus.message(7). -+ */ -+ size = sizeof(*msg); -+ size += KDBUS_ITEM_SIZE(strlen(arg_master) + 1); -+ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec)); -+ -+ msg = alloca(size); -+ memset(msg, 0, size); -+ msg->size = size; -+ -+ /* -+ * Tell the kernel that we expect a reply to this message. This means -+ * that -+ * -+ * a) The remote peer will gain temporary permission to talk to us -+ * even if it would not be allowed to normally. -+ * -+ * b) A timeout value is required. -+ * -+ * For asynchronous send commands, if no reply is received, we will -+ * get a kernel notification with an item of type -+ * KDBUS_ITEM_REPLY_TIMEOUT attached. -+ * -+ * For synchronous send commands (which this example does), the -+ * ioctl will block until a reply is received or the timeout is -+ * exceeded. -+ */ -+ msg->flags = KDBUS_MSG_EXPECT_REPLY; -+ -+ /* Set our cookie. Replies must use this cookie to send their reply. */ -+ msg->cookie = 1; -+ -+ /* The payload_type is arbitrary, but it must be non-zero */ -+ msg->payload_type = 0xdeadbeef; -+ -+ /* -+ * We are sending our message to the current owner of a well-known -+ * name. This makes an item of type KDBUS_ITEM_DST_NAME mandatory. -+ */ -+ msg->dst_id = KDBUS_DST_ID_NAME; -+ -+ /* -+ * Set the reply timeout to 5 seconds. Timeouts are always set in -+ * absolute timestamps, based con CLOCK_MONOTONIC. See kdbus.message(7). -+ */ -+ clock_gettime(CLOCK_MONOTONIC_COARSE, &spec); -+ msg->timeout_ns += (5 + spec.tv_sec) * 1000ULL * 1000ULL * 1000ULL; -+ msg->timeout_ns += spec.tv_nsec; -+ -+ /* -+ * Fill the appended items. First, set the well-known name of the -+ * destination we want to talk to. -+ */ -+ item = msg->items; -+ item->type = KDBUS_ITEM_DST_NAME; -+ item->size = KDBUS_ITEM_HEADER_SIZE + strlen(arg_master) + 1; -+ strcpy(item->str, arg_master); -+ -+ /* -+ * The 2nd item contains a vector to memory we want to send. It -+ * can be content of any type. In our case, we're sending a one-byte -+ * string only. The memory referenced by this item will be copied into -+ * the pool of the receveiver connection, and does not need to be -+ * valid after the command is employed. -+ */ -+ item = KDBUS_ITEM_NEXT(item); -+ item->type = KDBUS_ITEM_PAYLOAD_VEC; -+ item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_vec); -+ item->vec.address = (uintptr_t)"r"; -+ item->vec.size = 1; -+ -+ /* Set up the command struct and reference the message we prepared */ -+ memset(&cmd, 0, sizeof(cmd)); -+ cmd.size = sizeof(cmd); -+ cmd.msg_address = (uintptr_t)msg; -+ -+ /* -+ * The send commands knows a mode in which it will block until a -+ * reply to a message is received. This example uses that mode. -+ * The pool offset to the received reply will be stored in the command -+ * struct after the send command returned. See below. -+ */ -+ cmd.flags = KDBUS_SEND_SYNC_REPLY; -+ -+ /* -+ * Finally, employ the command on the connection owner -+ * file descriptor. -+ */ -+ r = kdbus_cmd_send(c->bus->fd, &cmd); -+ if (r == -ESRCH || r == -EPIPE || r == -ECONNRESET) -+ return 0; -+ if (r < 0) -+ return err_r(r, "cannot send request to master"); -+ -+ /* -+ * The command was sent with the KDBUS_SEND_SYNC_REPLY flag set, -+ * and returned successfully, which means that cmd.reply.offset now -+ * points to a message inside our connection's pool where the reply -+ * is found. This is equivalent to receiving the reply with -+ * KDBUS_CMD_RECV, but it doesn't require waiting for the reply with -+ * poll() and also saves the ioctl to receive the message. -+ */ -+ msg = (void *)(c->bus->pool + cmd.reply.offset); -+ -+ /* -+ * A messages describes its actual payload in an array of items. -+ * KDBUS_FOREACH() is a simple iterator that walks such an array. -+ * struct kdbus_msg has a field to denote its total size, which is -+ * needed to determine the number of items in the array. -+ */ -+ KDBUS_FOREACH(item, msg->items, -+ msg->size - offsetof(struct kdbus_msg, items)) { -+ /* -+ * An item of type PAYLOAD_OFF describes in-line memory -+ * stored in the pool at a described offset. That offset is -+ * relative to the start address of the message header. -+ * This example program only expects one single item of that -+ * type, remembers the struct kdbus_vec member of the item -+ * when it sees it, and bails out if there is more than one -+ * of them. -+ */ -+ if (item->type == KDBUS_ITEM_PAYLOAD_OFF) { -+ if (vec) { -+ r = err_r(-EEXIST, -+ "message with multiple vecs"); -+ break; -+ } -+ vec = &item->vec; -+ if (vec->size != 2 * sizeof(size_t)) { -+ r = err_r(-EINVAL, "invalid message size"); -+ break; -+ } -+ /* -+ * MEMFDs are transported as items of type PAYLOAD_MEMFD. -+ * If such an item is attached, a new file descriptor was -+ * installed into the task when KDBUS_CMD_RECV was called, and -+ * its number is stored in item->memfd.fd. -+ * Implementers *must* handle this item type close the -+ * file descriptor when no longer needed in order to prevent -+ * file descriptor exhaustion. This example program just bails -+ * out with an error in this case, as memfds are not expected -+ * in this context. -+ */ -+ } else if (item->type == KDBUS_ITEM_PAYLOAD_MEMFD) { -+ r = err_r(-EINVAL, "message with memfd"); -+ break; -+ } -+ } -+ if (r < 0) -+ goto exit; -+ if (!vec) { -+ r = err_r(-EINVAL, "empty message"); -+ goto exit; -+ } -+ -+ n = ((size_t *)((const uint8_t *)msg + vec->offset))[0]; -+ steps = ((size_t *)((const uint8_t *)msg + vec->offset))[1]; -+ -+ while (steps-- > 0) { -+ ++n; -+ r = prime_run(c->prime, c->bus, n); -+ if (r < 0) -+ break; -+ r = bus_poll(c->bus); -+ if (r != 0) { -+ r = r < 0 ? r : -EINTR; -+ break; -+ } -+ } -+ -+exit: -+ /* -+ * We are done with the memory slice that was given to us through -+ * cmd.reply.offset. Tell the kernel it can use it for other content -+ * in the future. See kdbus.pool(7). -+ */ -+ bus_poool_free_slice(c->bus, cmd.reply.offset); -+ return r; -+} -+ -+/* -+ * Prime Computation -+ * -+ */ -+ -+static int prime_new(struct prime **out) -+{ -+ struct prime *p; -+ int r; -+ -+ p = calloc(1, sizeof(*p)); -+ if (!p) -+ return err("cannot allocate prime memory"); -+ -+ p->fd = -1; -+ p->area = MAP_FAILED; -+ p->max = MAX_PRIMES; -+ -+ /* -+ * Prepare and map a memfd to store the bit-fields for the number -+ * ranges we want to perform the prime detection on. -+ */ -+ p->fd = syscall(__NR_memfd_create, "prime-area", MFD_CLOEXEC); -+ if (p->fd < 0) { -+ r = err("cannot create memfd"); -+ goto error; -+ } -+ -+ r = ftruncate(p->fd, p->max / 8 + 1); -+ if (r < 0) { -+ r = err("cannot ftruncate area"); -+ goto error; -+ } -+ -+ p->area = mmap(NULL, p->max / 8 + 1, PROT_READ | PROT_WRITE, -+ MAP_SHARED, p->fd, 0); -+ if (p->area == MAP_FAILED) { -+ r = err("cannot mmap memfd"); -+ goto error; -+ } -+ -+ *out = p; -+ return 0; -+ -+error: -+ prime_free(p); -+ return r; -+} -+ -+static void prime_free(struct prime *p) -+{ -+ if (!p) -+ return; -+ -+ if (p->area != MAP_FAILED) -+ munmap(p->area, p->max / 8 + 1); -+ if (p->fd >= 0) -+ close(p->fd); -+ free(p); -+} -+ -+static bool prime_done(struct prime *p) -+{ -+ return p->done >= p->max; -+} -+ -+static void prime_consume(struct prime *p, size_t amount) -+{ -+ p->done += amount; -+} -+ -+static int prime_run(struct prime *p, struct bus *cancel, size_t number) -+{ -+ size_t i, n = 0; -+ int r; -+ -+ if (number < 2 || number > 65535) -+ return 0; -+ -+ for (i = number * number; -+ i < p->max && i > number; -+ i += number) { -+ p->area[i / 8] |= 1 << (i % 8); -+ -+ if (!(++n % (1 << 20))) { -+ r = bus_poll(cancel); -+ if (r != 0) -+ return r < 0 ? r : -EINTR; -+ } -+ } -+ -+ return 0; -+} -+ -+static void prime_print(struct prime *p) -+{ -+ size_t i, l = 0; -+ -+ fprintf(stderr, "PRIMES:"); -+ for (i = 0; i < p->max; ++i) { -+ if (!(p->area[i / 8] & (1 << (i % 8)))) -+ fprintf(stderr, "%c%7zu", !(l++ % 16) ? '\n' : ' ', i); -+ } -+ fprintf(stderr, "\nEND\n"); -+} -+ -+static int bus_open_connection(struct bus **out, uid_t uid, const char *name, -+ uint64_t recv_flags) -+{ -+ struct kdbus_cmd_hello hello; -+ char path[128]; -+ struct bus *b; -+ int r; -+ -+ /* -+ * The 'bus' object is our representation of a kdbus connection which -+ * stores two details: the connection owner file descriptor, and the -+ * mmap()ed memory of its associated pool. See kdbus.connection(7) and -+ * kdbus.pool(7). -+ */ -+ b = calloc(1, sizeof(*b)); -+ if (!b) -+ return err("cannot allocate bus memory"); -+ -+ b->fd = -1; -+ b->pool = MAP_FAILED; -+ -+ /* Compute the name of the bus node to connect to. */ -+ snprintf(path, sizeof(path), "/sys/fs/%s/%lu-%s/bus", -+ arg_modname, (unsigned long)uid, name); -+ b->fd = open(path, O_RDWR | O_CLOEXEC); -+ if (b->fd < 0) { -+ r = err("cannot open bus"); -+ goto error; -+ } -+ -+ /* -+ * To make a connection to the bus, the KDBUS_CMD_HELLO ioctl is used. -+ * It takes an argument of type 'struct kdbus_cmd_hello'. -+ */ -+ memset(&hello, 0, sizeof(hello)); -+ hello.size = sizeof(hello); -+ -+ /* -+ * Specify a mask of metadata attach flags, describing metadata items -+ * that this new connection allows to be sent. -+ */ -+ hello.attach_flags_send = _KDBUS_ATTACH_ALL; -+ -+ /* -+ * Specify a mask of metadata attach flags, describing metadata items -+ * that this new connection wants to be receive along with each message. -+ */ -+ hello.attach_flags_recv = recv_flags; -+ -+ /* -+ * A connection may choose the size of its pool, but the number has to -+ * comply with two rules: a) it must be greater than 0, and b) it must -+ * be a mulitple of PAGE_SIZE. See kdbus.pool(7). -+ */ -+ hello.pool_size = POOL_SIZE; -+ -+ /* -+ * Now employ the command on the file descriptor opened above. -+ * This command will turn the file descriptor into a connection-owner -+ * file descriptor that controls the life-time of the connection; once -+ * it's closed, the connection is shut down. -+ */ -+ r = kdbus_cmd_hello(b->fd, &hello); -+ if (r < 0) { -+ err_r(r, "HELLO failed"); -+ goto error; -+ } -+ -+ bus_poool_free_slice(b, hello.offset); -+ -+ /* -+ * Map the pool of the connection. Its size has been set in the -+ * command struct above. See kdbus.pool(7). -+ */ -+ b->pool = mmap(NULL, POOL_SIZE, PROT_READ, MAP_SHARED, b->fd, 0); -+ if (b->pool == MAP_FAILED) { -+ r = err("cannot mmap pool"); -+ goto error; -+ } -+ -+ *out = b; -+ return 0; -+ -+error: -+ bus_close_connection(b); -+ return r; -+} -+ -+static void bus_close_connection(struct bus *b) -+{ -+ if (!b) -+ return; -+ -+ /* -+ * A bus connection is closed by simply calling close() on the -+ * connection owner file descriptor. The unique name and all owned -+ * well-known names of the conneciton will disappear. -+ * See kdbus.connection(7). -+ */ -+ if (b->pool != MAP_FAILED) -+ munmap(b->pool, POOL_SIZE); -+ if (b->fd >= 0) -+ close(b->fd); -+ free(b); -+} -+ -+static void bus_poool_free_slice(struct bus *b, uint64_t offset) -+{ -+ struct kdbus_cmd_free cmd = { -+ .size = sizeof(cmd), -+ .offset = offset, -+ }; -+ int r; -+ -+ /* -+ * Once we're done with a piece of pool memory that was returned -+ * by a command, we have to call the KDBUS_CMD_FREE ioctl on it so it -+ * can be reused. The command takes an argument of type -+ * 'struct kdbus_cmd_free', in which the pool offset of the slice to -+ * free is stored. The ioctl is employed on the connection owner -+ * file descriptor. See kdbus.pool(7), -+ */ -+ r = kdbus_cmd_free(b->fd, &cmd); -+ if (r < 0) -+ err_r(r, "cannot free pool slice"); -+} -+ -+static int bus_acquire_name(struct bus *b, const char *name) -+{ -+ struct kdbus_item *item; -+ struct kdbus_cmd *cmd; -+ size_t size; -+ int r; -+ -+ /* -+ * This function acquires a well-known name on the bus through the -+ * KDBUS_CMD_NAME_ACQUIRE ioctl. This ioctl takes an argument of type -+ * 'struct kdbus_cmd', which is assembled below. See kdbus.name(7). -+ */ -+ size = sizeof(*cmd); -+ size += KDBUS_ITEM_SIZE(strlen(name) + 1); -+ -+ cmd = alloca(size); -+ memset(cmd, 0, size); -+ cmd->size = size; -+ -+ /* -+ * The command requires an item of type KDBUS_ITEM_NAME, and its -+ * content must be a valid bus name. -+ */ -+ item = cmd->items; -+ item->type = KDBUS_ITEM_NAME; -+ item->size = KDBUS_ITEM_HEADER_SIZE + strlen(name) + 1; -+ strcpy(item->str, name); -+ -+ /* -+ * Employ the command on the connection owner file descriptor. -+ */ -+ r = kdbus_cmd_name_acquire(b->fd, cmd); -+ if (r < 0) -+ return err_r(r, "cannot acquire name"); -+ -+ return 0; -+} -+ -+static int bus_install_name_loss_match(struct bus *b, const char *name) -+{ -+ struct kdbus_cmd_match *match; -+ struct kdbus_item *item; -+ size_t size; -+ int r; -+ -+ /* -+ * In order to install a match for signal messages, we have to -+ * assemble a 'struct kdbus_cmd_match' and use it along with the -+ * KDBUS_CMD_MATCH_ADD ioctl. See kdbus.match(7). -+ */ -+ size = sizeof(*match); -+ size += KDBUS_ITEM_SIZE(sizeof(item->name_change) + strlen(name) + 1); -+ -+ match = alloca(size); -+ memset(match, 0, size); -+ match->size = size; -+ -+ /* -+ * A match is comprised of many 'rules', each of which describes a -+ * mandatory detail of the message. All rules of a match must be -+ * satified in order to make a message pass. -+ */ -+ item = match->items; -+ -+ /* -+ * In this case, we're interested in notifications that inform us -+ * about a well-known name being removed from the bus. -+ */ -+ item->type = KDBUS_ITEM_NAME_REMOVE; -+ item->size = KDBUS_ITEM_HEADER_SIZE + -+ sizeof(item->name_change) + strlen(name) + 1; -+ -+ /* -+ * We could limit the match further and require a specific unique-ID -+ * to be the new or the old owner of the name. In this case, however, -+ * we don't, and allow 'any' id. -+ */ -+ item->name_change.old_id.id = KDBUS_MATCH_ID_ANY; -+ item->name_change.new_id.id = KDBUS_MATCH_ID_ANY; -+ -+ /* Copy in the well-known name we're interested in */ -+ strcpy(item->name_change.name, name); -+ -+ /* -+ * Add the match through the KDBUS_CMD_MATCH_ADD ioctl, employed on -+ * the connection owner fd. -+ */ -+ r = kdbus_cmd_match_add(b->fd, match); -+ if (r < 0) -+ return err_r(r, "cannot add match"); -+ -+ return 0; -+} -+ -+static int bus_poll(struct bus *b) -+{ -+ struct pollfd fds[1] = {}; -+ int r; -+ -+ /* -+ * A connection endpoint supports poll() and will wake-up the -+ * task with POLLIN set once a message has arrived. -+ */ -+ fds[0].fd = b->fd; -+ fds[0].events = POLLIN; -+ r = poll(fds, sizeof(fds) / sizeof(*fds), 0); -+ if (r < 0) -+ return err("cannot poll bus"); -+ return !!(fds[0].revents & POLLIN); -+} -+ -+static int bus_make(uid_t uid, const char *name) -+{ -+ struct kdbus_item *item; -+ struct kdbus_cmd *make; -+ char path[128], busname[128]; -+ size_t size; -+ int r, fd; -+ -+ /* -+ * Compute the full path to the 'control' node. 'arg_modname' may be -+ * set to a different value than 'kdbus' for development purposes. -+ * The 'control' node is the primary entry point to kdbus that must be -+ * used in order to create a bus. See kdbus(7) and kdbus.bus(7). -+ */ -+ snprintf(path, sizeof(path), "/sys/fs/%s/control", arg_modname); -+ -+ /* -+ * Compute the bus name. A valid bus name must always be prefixed with -+ * the EUID of the currently running process in order to avoid name -+ * conflicts. See kdbus.bus(7). -+ */ -+ snprintf(busname, sizeof(busname), "%lu-%s", (unsigned long)uid, name); -+ -+ fd = open(path, O_RDWR | O_CLOEXEC); -+ if (fd < 0) -+ return err("cannot open control file"); -+ -+ /* -+ * The KDBUS_CMD_BUS_MAKE ioctl takes an argument of type -+ * 'struct kdbus_cmd', and expects at least two items attached to -+ * it: one to decribe the bloom parameters to be propagated to -+ * connections of the bus, and the name of the bus that was computed -+ * above. Assemble this struct now, and fill it with values. -+ */ -+ size = sizeof(*make); -+ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_bloom_parameter)); -+ size += KDBUS_ITEM_SIZE(strlen(busname) + 1); -+ -+ make = alloca(size); -+ memset(make, 0, size); -+ make->size = size; -+ -+ /* -+ * Each item has a 'type' and 'size' field, and must be stored at an -+ * 8-byte aligned address. The KDBUS_ITEM_NEXT macro is used to advance -+ * the pointer. See kdbus.item(7) for more details. -+ */ -+ item = make->items; -+ item->type = KDBUS_ITEM_BLOOM_PARAMETER; -+ item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(item->bloom_parameter); -+ item->bloom_parameter.size = 8; -+ item->bloom_parameter.n_hash = 1; -+ -+ /* The name of the new bus is stored in the next item. */ -+ item = KDBUS_ITEM_NEXT(item); -+ item->type = KDBUS_ITEM_MAKE_NAME; -+ item->size = KDBUS_ITEM_HEADER_SIZE + strlen(busname) + 1; -+ strcpy(item->str, busname); -+ -+ /* -+ * Now create the bus via the KDBUS_CMD_BUS_MAKE ioctl and return the -+ * fd that was used back to the caller of this function. This fd is now -+ * called a 'bus owner file descriptor', and it controls the life-time -+ * of the newly created bus; once the file descriptor is closed, the -+ * bus goes away, and all connections are shut down. See kdbus.bus(7). -+ */ -+ r = kdbus_cmd_bus_make(fd, make); -+ if (r < 0) { -+ err_r(r, "cannot make bus"); -+ close(fd); -+ return r; -+ } -+ -+ return fd; -+} --- -2.4.3 - - -From b7270dd9f7d48c1f2ef20a48eeb5f73afcdae21d Mon Sep 17 00:00:00 2001 -From: Daniel Mack <daniel@zonque.org> -Date: Sat, 13 Sep 2014 23:15:02 +0200 -Subject: [PATCH 014/132] kdbus: add selftests - -This patch adds an extensive test suite for kdbus that checks the most -important code paths in the driver. The idea is to extend the test -suite over time. - -Also, this code can serve as another example for how to use the kernel -API from userspace. - -The code in the kdbus test suite makes use of the ioctl wrappers -provided by samples/kdbus/kdbus-api.h. - -Signed-off-by: Daniel Mack <daniel@zonque.org> -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Djalal Harouni <tixxdz@opendz.org> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - tools/testing/selftests/Makefile | 1 + - tools/testing/selftests/kdbus/.gitignore | 3 + - tools/testing/selftests/kdbus/Makefile | 46 + - tools/testing/selftests/kdbus/kdbus-enum.c | 94 ++ - tools/testing/selftests/kdbus/kdbus-enum.h | 14 + - tools/testing/selftests/kdbus/kdbus-test.c | 923 ++++++++++++ - tools/testing/selftests/kdbus/kdbus-test.h | 85 ++ - tools/testing/selftests/kdbus/kdbus-util.c | 1615 +++++++++++++++++++++ - tools/testing/selftests/kdbus/kdbus-util.h | 222 +++ - tools/testing/selftests/kdbus/test-activator.c | 318 ++++ - tools/testing/selftests/kdbus/test-attach-flags.c | 750 ++++++++++ - tools/testing/selftests/kdbus/test-benchmark.c | 451 ++++++ - tools/testing/selftests/kdbus/test-bus.c | 175 +++ - tools/testing/selftests/kdbus/test-chat.c | 122 ++ - tools/testing/selftests/kdbus/test-connection.c | 616 ++++++++ - tools/testing/selftests/kdbus/test-daemon.c | 65 + - tools/testing/selftests/kdbus/test-endpoint.c | 341 +++++ - tools/testing/selftests/kdbus/test-fd.c | 789 ++++++++++ - tools/testing/selftests/kdbus/test-free.c | 64 + - tools/testing/selftests/kdbus/test-match.c | 441 ++++++ - tools/testing/selftests/kdbus/test-message.c | 731 ++++++++++ - tools/testing/selftests/kdbus/test-metadata-ns.c | 506 +++++++ - tools/testing/selftests/kdbus/test-monitor.c | 176 +++ - tools/testing/selftests/kdbus/test-names.c | 194 +++ - tools/testing/selftests/kdbus/test-policy-ns.c | 632 ++++++++ - tools/testing/selftests/kdbus/test-policy-priv.c | 1269 ++++++++++++++++ - tools/testing/selftests/kdbus/test-policy.c | 80 + - tools/testing/selftests/kdbus/test-sync.c | 369 +++++ - tools/testing/selftests/kdbus/test-timeout.c | 99 ++ - 29 files changed, 11191 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-attach-flags.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-sync.c - create mode 100644 tools/testing/selftests/kdbus/test-timeout.c - -diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile -index 4e511221a0c1..7b51cceae9dd 100644 ---- a/tools/testing/selftests/Makefile -+++ b/tools/testing/selftests/Makefile -@@ -5,6 +5,7 @@ TARGETS += exec - TARGETS += firmware - TARGETS += ftrace - TARGETS += futex - TARGETS += kcmp -+TARGETS += kdbus - TARGETS += membarrier - TARGETS += memfd -diff --git a/tools/testing/selftests/kdbus/.gitignore b/tools/testing/selftests/kdbus/.gitignore -new file mode 100644 -index 000000000000..7b421f76c888 ---- /dev/null -+++ b/tools/testing/selftests/kdbus/.gitignore -@@ -0,0 +1,3 @@ -+*.7 -+manpage.* -+*.proc -diff --git a/tools/testing/selftests/kdbus/Makefile b/tools/testing/selftests/kdbus/Makefile -new file mode 100644 -index 000000000000..f6cfab26f315 ---- /dev/null -+++ b/tools/testing/selftests/kdbus/Makefile -@@ -0,0 +1,46 @@ -+CFLAGS += -I../../../../usr/include/ -+CFLAGS += -I../../../../samples/kdbus/ -+CFLAGS += -I../../../../include/uapi/ -+CFLAGS += -std=gnu99 -+CFLAGS += -DKBUILD_MODNAME=\"kdbus\" -D_GNU_SOURCE -+LDLIBS = -pthread -lcap -lm -+ -+OBJS= \ -+ kdbus-enum.o \ -+ kdbus-util.o \ -+ kdbus-test.o \ -+ kdbus-test.o \ -+ test-activator.o \ -+ test-attach-flags.o \ -+ test-benchmark.o \ -+ test-bus.o \ -+ test-chat.o \ -+ test-connection.o \ -+ test-daemon.o \ -+ test-endpoint.o \ -+ test-fd.o \ -+ test-free.o \ -+ test-match.o \ -+ test-message.o \ -+ test-metadata-ns.o \ -+ test-monitor.o \ -+ test-names.o \ -+ test-policy.o \ -+ test-policy-ns.o \ -+ test-policy-priv.o \ -+ test-sync.o \ -+ test-timeout.o -+ -+all: kdbus-test -+ -+%.o: %.c -+ gcc $(CFLAGS) -c $< -o $@ -+ -+kdbus-test: $(OBJS) -+ gcc $(CFLAGS) $^ $(LDLIBS) -o $@ -+ -+run_tests: -+ ./kdbus-test --tap -+ -+clean: -+ rm -f *.o kdbus-test -diff --git a/tools/testing/selftests/kdbus/kdbus-enum.c b/tools/testing/selftests/kdbus/kdbus-enum.c -new file mode 100644 -index 000000000000..4f1e5797895f ---- /dev/null -+++ b/tools/testing/selftests/kdbus/kdbus-enum.c -@@ -0,0 +1,94 @@ -+/* -+ * Copyright (C) 2013-2015 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. -+ */ -+ -+#include <stdio.h> -+#include <string.h> -+#include <fcntl.h> -+#include <stdlib.h> -+#include <stddef.h> -+#include <unistd.h> -+#include <stdint.h> -+#include <errno.h> -+ -+#include "kdbus-util.h" -+#include "kdbus-enum.h" -+ -+struct kdbus_enum_table { -+ long long id; -+ const char *name; -+}; -+ -+#define TABLE(what) static struct kdbus_enum_table kdbus_table_##what[] -+#define ENUM(_id) { .id = _id, .name = STRINGIFY(_id) } -+#define LOOKUP(what) \ -+ const char *enum_##what(long long id) \ -+ { \ -+ for (size_t i = 0; i < ELEMENTSOF(kdbus_table_##what); i++) \ -+ if (id == kdbus_table_##what[i].id) \ -+ return kdbus_table_##what[i].name; \ -+ return "UNKNOWN"; \ -+ } -+ -+TABLE(CMD) = { -+ ENUM(KDBUS_CMD_BUS_MAKE), -+ ENUM(KDBUS_CMD_ENDPOINT_MAKE), -+ ENUM(KDBUS_CMD_HELLO), -+ ENUM(KDBUS_CMD_SEND), -+ ENUM(KDBUS_CMD_RECV), -+ ENUM(KDBUS_CMD_LIST), -+ ENUM(KDBUS_CMD_NAME_RELEASE), -+ ENUM(KDBUS_CMD_CONN_INFO), -+ ENUM(KDBUS_CMD_MATCH_ADD), -+ ENUM(KDBUS_CMD_MATCH_REMOVE), -+}; -+LOOKUP(CMD); -+ -+TABLE(MSG) = { -+ ENUM(_KDBUS_ITEM_NULL), -+ ENUM(KDBUS_ITEM_PAYLOAD_VEC), -+ ENUM(KDBUS_ITEM_PAYLOAD_OFF), -+ ENUM(KDBUS_ITEM_PAYLOAD_MEMFD), -+ ENUM(KDBUS_ITEM_FDS), -+ ENUM(KDBUS_ITEM_BLOOM_PARAMETER), -+ ENUM(KDBUS_ITEM_BLOOM_FILTER), -+ ENUM(KDBUS_ITEM_DST_NAME), -+ ENUM(KDBUS_ITEM_MAKE_NAME), -+ ENUM(KDBUS_ITEM_ATTACH_FLAGS_SEND), -+ ENUM(KDBUS_ITEM_ATTACH_FLAGS_RECV), -+ ENUM(KDBUS_ITEM_ID), -+ ENUM(KDBUS_ITEM_NAME), -+ ENUM(KDBUS_ITEM_TIMESTAMP), -+ ENUM(KDBUS_ITEM_CREDS), -+ ENUM(KDBUS_ITEM_PIDS), -+ ENUM(KDBUS_ITEM_AUXGROUPS), -+ ENUM(KDBUS_ITEM_OWNED_NAME), -+ ENUM(KDBUS_ITEM_TID_COMM), -+ ENUM(KDBUS_ITEM_PID_COMM), -+ ENUM(KDBUS_ITEM_EXE), -+ ENUM(KDBUS_ITEM_CMDLINE), -+ ENUM(KDBUS_ITEM_CGROUP), -+ ENUM(KDBUS_ITEM_CAPS), -+ ENUM(KDBUS_ITEM_SECLABEL), -+ ENUM(KDBUS_ITEM_AUDIT), -+ ENUM(KDBUS_ITEM_CONN_DESCRIPTION), -+ ENUM(KDBUS_ITEM_NAME_ADD), -+ ENUM(KDBUS_ITEM_NAME_REMOVE), -+ ENUM(KDBUS_ITEM_NAME_CHANGE), -+ ENUM(KDBUS_ITEM_ID_ADD), -+ ENUM(KDBUS_ITEM_ID_REMOVE), -+ ENUM(KDBUS_ITEM_REPLY_TIMEOUT), -+ ENUM(KDBUS_ITEM_REPLY_DEAD), -+}; -+LOOKUP(MSG); -+ -+TABLE(PAYLOAD) = { -+ ENUM(KDBUS_PAYLOAD_KERNEL), -+ ENUM(KDBUS_PAYLOAD_DBUS), -+}; -+LOOKUP(PAYLOAD); -diff --git a/tools/testing/selftests/kdbus/kdbus-enum.h b/tools/testing/selftests/kdbus/kdbus-enum.h -new file mode 100644 -index 000000000000..a67cec3512a7 ---- /dev/null -+++ b/tools/testing/selftests/kdbus/kdbus-enum.h -@@ -0,0 +1,14 @@ -+/* -+ * Copyright (C) 2013-2015 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); -diff --git a/tools/testing/selftests/kdbus/kdbus-test.c b/tools/testing/selftests/kdbus/kdbus-test.c -new file mode 100644 -index 000000000000..a43674ccdeb0 ---- /dev/null -+++ b/tools/testing/selftests/kdbus/kdbus-test.c -@@ -0,0 +1,923 @@ -+#include <errno.h> -+#include <stdio.h> -+#include <string.h> -+#include <fcntl.h> -+#include <stdlib.h> -+#include <stddef.h> -+#include <time.h> -+#include <unistd.h> -+#include <stdint.h> -+#include <assert.h> -+#include <getopt.h> -+#include <stdbool.h> -+#include <signal.h> -+#include <sys/mount.h> -+#include <sys/prctl.h> -+#include <sys/wait.h> -+#include <sys/syscall.h> -+#include <sys/eventfd.h> -+#include <linux/sched.h> -+ -+#include "kdbus-util.h" -+#include "kdbus-enum.h" -+#include "kdbus-test.h" -+ -+enum { -+ TEST_CREATE_BUS = 1 << 0, -+ TEST_CREATE_CONN = 1 << 1, -+}; -+ -+struct kdbus_test { -+ const char *name; -+ const char *desc; -+ int (*func)(struct kdbus_test_env *env); -+ unsigned int flags; -+}; -+ -+struct kdbus_test_args { -+ bool mntns; -+ bool pidns; -+ bool userns; -+ char *uid_map; -+ char *gid_map; -+ int loop; -+ int wait; -+ int fork; -+ int tap_output; -+ char *module; -+ char *root; -+ char *test; -+ char *busname; -+ char *mask_param_path; -+}; -+ -+static const struct kdbus_test tests[] = { -+ { -+ .name = "bus-make", -+ .desc = "bus make functions", -+ .func = kdbus_test_bus_make, -+ .flags = 0, -+ }, -+ { -+ .name = "hello", -+ .desc = "the HELLO command", -+ .func = kdbus_test_hello, -+ .flags = TEST_CREATE_BUS, -+ }, -+ { -+ .name = "byebye", -+ .desc = "the BYEBYE command", -+ .func = kdbus_test_byebye, -+ .flags = TEST_CREATE_BUS | TEST_CREATE_CONN, -+ }, -+ { -+ .name = "chat", -+ .desc = "a chat pattern", -+ .func = kdbus_test_chat, -+ .flags = TEST_CREATE_BUS, -+ }, -+ { -+ .name = "daemon", -+ .desc = "a simple daemon", -+ .func = kdbus_test_daemon, -+ .flags = TEST_CREATE_BUS | TEST_CREATE_CONN, -+ }, -+ { -+ .name = "fd-passing", -+ .desc = "file descriptor passing", -+ .func = kdbus_test_fd_passing, -+ .flags = TEST_CREATE_BUS, -+ }, -+ { -+ .name = "endpoint", -+ .desc = "custom endpoint", -+ .func = kdbus_test_custom_endpoint, -+ .flags = TEST_CREATE_BUS | TEST_CREATE_CONN, -+ }, -+ { -+ .name = "monitor", -+ .desc = "monitor functionality", -+ .func = kdbus_test_monitor, -+ .flags = TEST_CREATE_BUS | TEST_CREATE_CONN, -+ }, -+ { -+ .name = "name-basics", -+ .desc = "basic name registry functions", -+ .func = kdbus_test_name_basic, -+ .flags = TEST_CREATE_BUS | TEST_CREATE_CONN, -+ }, -+ { -+ .name = "name-conflict", -+ .desc = "name registry conflict details", -+ .func = kdbus_test_name_conflict, -+ .flags = TEST_CREATE_BUS | TEST_CREATE_CONN, -+ }, -+ { -+ .name = "name-queue", -+ .desc = "queuing of names", -+ .func = kdbus_test_name_queue, -+ .flags = TEST_CREATE_BUS | TEST_CREATE_CONN, -+ }, -+ { -+ .name = "message-basic", -+ .desc = "basic message handling", -+ .func = kdbus_test_message_basic, -+ .flags = TEST_CREATE_BUS | TEST_CREATE_CONN, -+ }, -+ { -+ .name = "message-prio", -+ .desc = "handling of messages with priority", -+ .func = kdbus_test_message_prio, -+ .flags = TEST_CREATE_BUS, -+ }, -+ { -+ .name = "message-quota", -+ .desc = "message quotas are enforced", -+ .func = kdbus_test_message_quota, -+ .flags = TEST_CREATE_BUS, -+ }, -+ { -+ .name = "memory-access", -+ .desc = "memory access", -+ .func = kdbus_test_memory_access, -+ .flags = TEST_CREATE_BUS, -+ }, -+ { -+ .name = "timeout", -+ .desc = "timeout", -+ .func = kdbus_test_timeout, -+ .flags = TEST_CREATE_BUS, -+ }, -+ { -+ .name = "sync-byebye", -+ .desc = "synchronous replies vs. BYEBYE", -+ .func = kdbus_test_sync_byebye, -+ .flags = TEST_CREATE_BUS, -+ }, -+ { -+ .name = "sync-reply", -+ .desc = "synchronous replies", -+ .func = kdbus_test_sync_reply, -+ .flags = TEST_CREATE_BUS, -+ }, -+ { -+ .name = "message-free", -+ .desc = "freeing of memory", -+ .func = kdbus_test_free, -+ .flags = TEST_CREATE_BUS | TEST_CREATE_CONN, -+ }, -+ { -+ .name = "connection-info", -+ .desc = "retrieving connection information", -+ .func = kdbus_test_conn_info, -+ .flags = TEST_CREATE_BUS | TEST_CREATE_CONN, -+ }, -+ { -+ .name = "connection-update", -+ .desc = "updating connection information", -+ .func = kdbus_test_conn_update, -+ .flags = TEST_CREATE_BUS | TEST_CREATE_CONN, -+ }, -+ { -+ .name = "writable-pool", -+ .desc = "verifying pools are never writable", -+ .func = kdbus_test_writable_pool, -+ .flags = TEST_CREATE_BUS, -+ }, -+ { -+ .name = "policy", -+ .desc = "policy", -+ .func = kdbus_test_policy, -+ .flags = TEST_CREATE_BUS, -+ }, -+ { -+ .name = "policy-priv", -+ .desc = "unprivileged bus access", -+ .func = kdbus_test_policy_priv, -+ .flags = TEST_CREATE_BUS, -+ }, -+ { -+ .name = "policy-ns", -+ .desc = "policy in user namespaces", -+ .func = kdbus_test_policy_ns, -+ .flags = TEST_CREATE_BUS, -+ }, -+ { -+ .name = "metadata-ns", -+ .desc = "metadata in different namespaces", -+ .func = kdbus_test_metadata_ns, -+ .flags = TEST_CREATE_BUS | TEST_CREATE_CONN, -+ }, -+ { -+ .name = "match-id-add", -+ .desc = "adding of matches by id", -+ .func = kdbus_test_match_id_add, -+ .flags = TEST_CREATE_BUS | TEST_CREATE_CONN, -+ }, -+ { -+ .name = "match-id-remove", -+ .desc = "removing of matches by id", -+ .func = kdbus_test_match_id_remove, -+ .flags = TEST_CREATE_BUS | TEST_CREATE_CONN, -+ }, -+ { -+ .name = "match-replace", -+ .desc = "replace of matches with the same cookie", -+ .func = kdbus_test_match_replace, -+ .flags = TEST_CREATE_BUS | TEST_CREATE_CONN, -+ }, -+ { -+ .name = "match-name-add", -+ .desc = "adding of matches by name", -+ .func = kdbus_test_match_name_add, -+ .flags = TEST_CREATE_BUS | TEST_CREATE_CONN, -+ }, -+ { -+ .name = "match-name-remove", -+ .desc = "removing of matches by name", -+ .func = kdbus_test_match_name_remove, -+ .flags = TEST_CREATE_BUS | TEST_CREATE_CONN, -+ }, -+ { -+ .name = "match-name-change", -+ .desc = "matching for name changes", -+ .func = kdbus_test_match_name_change, -+ .flags = TEST_CREATE_BUS | TEST_CREATE_CONN, -+ }, -+ { -+ .name = "match-bloom", -+ .desc = "matching with bloom filters", -+ .func = kdbus_test_match_bloom, -+ .flags = TEST_CREATE_BUS | TEST_CREATE_CONN, -+ }, -+ { -+ .name = "activator", -+ .desc = "activator connections", -+ .func = kdbus_test_activator, -+ .flags = TEST_CREATE_BUS | TEST_CREATE_CONN, -+ }, -+ { -+ .name = "benchmark", -+ .desc = "benchmark", -+ .func = kdbus_test_benchmark, -+ .flags = TEST_CREATE_BUS, -+ }, -+ { -+ .name = "benchmark-nomemfds", -+ .desc = "benchmark without using memfds", -+ .func = kdbus_test_benchmark_nomemfds, -+ .flags = TEST_CREATE_BUS, -+ }, -+ { -+ .name = "benchmark-uds", -+ .desc = "benchmark comparison to UDS", -+ .func = kdbus_test_benchmark_uds, -+ .flags = TEST_CREATE_BUS, -+ }, -+ { -+ /* Last test */ -+ .name = "attach-flags", -+ .desc = "attach flags mask", -+ .func = kdbus_test_attach_flags, -+ .flags = 0, -+ }, -+}; -+ -+#define N_TESTS ((int) (sizeof(tests) / sizeof(tests[0]))) -+ -+static int test_prepare_env(const struct kdbus_test *t, -+ const struct kdbus_test_args *args, -+ struct kdbus_test_env *env) -+{ -+ if (t->flags & TEST_CREATE_BUS) { -+ char *s; -+ char *n = NULL; -+ int ret; -+ -+ asprintf(&s, "%s/control", args->root); -+ -+ env->control_fd = open(s, O_RDWR); -+ free(s); -+ ASSERT_RETURN(env->control_fd >= 0); -+ -+ if (!args->busname) { -+ n = unique_name("test-bus"); -+ ASSERT_RETURN(n); -+ } -+ -+ ret = kdbus_create_bus(env->control_fd, -+ args->busname ?: n, -+ _KDBUS_ATTACH_ALL, -+ _KDBUS_ATTACH_ALL, &s); -+ free(n); -+ ASSERT_RETURN(ret == 0); -+ -+ asprintf(&env->buspath, "%s/%s/bus", args->root, s); -+ free(s); -+ } -+ -+ if (t->flags & TEST_CREATE_CONN) { -+ env->conn = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(env->conn); -+ } -+ -+ env->root = args->root; -+ env->module = args->module; -+ env->mask_param_path = args->mask_param_path; -+ -+ return 0; -+} -+ -+void test_unprepare_env(const struct kdbus_test *t, struct kdbus_test_env *env) -+{ -+ if (env->conn) { -+ kdbus_conn_free(env->conn); -+ env->conn = NULL; -+ } -+ -+ if (env->control_fd >= 0) { -+ close(env->control_fd); -+ env->control_fd = -1; -+ } -+ -+ if (env->buspath) { -+ free(env->buspath); -+ env->buspath = NULL; -+ } -+} -+ -+static int test_run(const struct kdbus_test *t, -+ const struct kdbus_test_args *kdbus_args, -+ int wait) -+{ -+ int ret; -+ struct kdbus_test_env env = {}; -+ -+ ret = test_prepare_env(t, kdbus_args, &env); -+ if (ret != TEST_OK) -+ return ret; -+ -+ if (wait > 0) { -+ printf("Sleeping %d seconds before running test ...\n", wait); -+ sleep(wait); -+ } -+ -+ ret = t->func(&env); -+ test_unprepare_env(t, &env); -+ return ret; -+} -+ -+static int test_run_forked(const struct kdbus_test *t, -+ const struct kdbus_test_args *kdbus_args, -+ int wait) -+{ -+ int ret; -+ pid_t pid; -+ -+ pid = fork(); -+ if (pid < 0) { -+ return TEST_ERR; -+ } else if (pid == 0) { -+ ret = test_run(t, kdbus_args, wait); -+ _exit(ret); -+ } -+ -+ pid = waitpid(pid, &ret, 0); -+ if (pid <= 0) -+ return TEST_ERR; -+ else if (!WIFEXITED(ret)) -+ return TEST_ERR; -+ else -+ return WEXITSTATUS(ret); -+} -+ -+static void print_test_result(int ret) -+{ -+ switch (ret) { -+ case TEST_OK: -+ printf("OK"); -+ break; -+ case TEST_SKIP: -+ printf("SKIPPED"); -+ break; -+ case TEST_ERR: -+ printf("ERROR"); -+ break; -+ } -+} -+ -+static int start_all_tests(struct kdbus_test_args *kdbus_args) -+{ -+ int ret; -+ unsigned int fail_cnt = 0; -+ unsigned int skip_cnt = 0; -+ unsigned int ok_cnt = 0; -+ unsigned int i; -+ -+ if (kdbus_args->tap_output) { -+ printf("1..%d\n", N_TESTS); -+ fflush(stdout); -+ } -+ -+ kdbus_util_verbose = false; -+ -+ for (i = 0; i < N_TESTS; i++) { -+ const struct kdbus_test *t = tests + i; -+ -+ if (!kdbus_args->tap_output) { -+ unsigned int n; -+ -+ printf("Testing %s (%s) ", t->desc, t->name); -+ for (n = 0; n < 60 - strlen(t->desc) - strlen(t->name); n++) -+ printf("."); -+ printf(" "); -+ } -+ -+ ret = test_run_forked(t, kdbus_args, 0); -+ switch (ret) { -+ case TEST_OK: -+ ok_cnt++; -+ break; -+ case TEST_SKIP: -+ skip_cnt++; -+ break; -+ case TEST_ERR: -+ fail_cnt++; -+ break; -+ } -+ -+ if (kdbus_args->tap_output) { -+ printf("%sok %d - %s%s (%s)\n", -+ (ret == TEST_ERR) ? "not " : "", i + 1, -+ (ret == TEST_SKIP) ? "# SKIP " : "", -+ t->desc, t->name); -+ fflush(stdout); -+ } else { -+ print_test_result(ret); -+ printf("\n"); -+ } -+ } -+ -+ if (kdbus_args->tap_output) -+ printf("Failed %d/%d tests, %.2f%% okay\n", fail_cnt, N_TESTS, -+ 100.0 - (fail_cnt * 100.0) / ((float) N_TESTS)); -+ else -+ printf("\nSUMMARY: %u tests passed, %u skipped, %u failed\n", -+ ok_cnt, skip_cnt, fail_cnt); -+ -+ return fail_cnt > 0 ? TEST_ERR : TEST_OK; -+} -+ -+static int start_one_test(struct kdbus_test_args *kdbus_args) -+{ -+ int i, ret; -+ bool test_found = false; -+ -+ for (i = 0; i < N_TESTS; i++) { -+ const struct kdbus_test *t = tests + i; -+ -+ if (strcmp(t->name, kdbus_args->test)) -+ continue; -+ -+ do { -+ test_found = true; -+ if (kdbus_args->fork) -+ ret = test_run_forked(t, kdbus_args, -+ kdbus_args->wait); -+ else -+ ret = test_run(t, kdbus_args, -+ kdbus_args->wait); -+ -+ printf("Testing %s: ", t->desc); -+ print_test_result(ret); -+ printf("\n"); -+ -+ if (ret != TEST_OK) -+ break; -+ } while (kdbus_args->loop); -+ -+ return ret; -+ } -+ -+ if (!test_found) { -+ printf("Unknown test-id '%s'\n", kdbus_args->test); -+ return TEST_ERR; -+ } -+ -+ return TEST_OK; -+} -+ -+static void usage(const char *argv0) -+{ -+ unsigned int i, j; -+ -+ printf("Usage: %s [options]\n" -+ "Options:\n" -+ "\t-a, --tap Output test results in TAP format\n" -+ "\t-m, --module <module> Kdbus module name\n" -+ "\t-x, --loop Run in a loop\n" -+ "\t-f, --fork Fork before running a test\n" -+ "\t-h, --help Print this help\n" -+ "\t-r, --root <root> Toplevel of the kdbus hierarchy\n" -+ "\t-t, --test <test-id> Run one specific test only, in verbose mode\n" -+ "\t-b, --bus <busname> Instead of generating a random bus name, take <busname>.\n" -+ "\t-w, --wait <secs> Wait <secs> before actually starting test\n" -+ "\t --mntns New mount namespace\n" -+ "\t --pidns New PID namespace\n" -+ "\t --userns New user namespace\n" -+ "\t --uidmap uid_map UID map for user namespace\n" -+ "\t --gidmap gid_map GID map for user namespace\n" -+ "\n", argv0); -+ -+ printf("By default, all test are run once, and a summary is printed.\n" -+ "Available tests for --test:\n\n"); -+ -+ for (i = 0; i < N_TESTS; i++) { -+ const struct kdbus_test *t = tests + i; -+ -+ printf("\t%s", t->name); -+ -+ for (j = 0; j < 24 - strlen(t->name); j++) -+ printf(" "); -+ -+ printf("Test %s\n", t->desc); -+ } -+ -+ printf("\n"); -+ printf("Note that some tests may, if run specifically by --test, " -+ "behave differently, and not terminate by themselves.\n"); -+ -+ exit(EXIT_FAILURE); -+} -+ -+void print_kdbus_test_args(struct kdbus_test_args *args) -+{ -+ if (args->userns || args->pidns || args->mntns) -+ printf("# Starting tests in new %s%s%s namespaces%s\n", -+ args->mntns ? "MOUNT " : "", -+ args->pidns ? "PID " : "", -+ args->userns ? "USER " : "", -+ args->mntns ? ", kdbusfs will be remounted" : ""); -+ else -+ printf("# Starting tests in the same namespaces\n"); -+} -+ -+void print_metadata_support(void) -+{ -+ bool no_meta_audit, no_meta_cgroups, no_meta_seclabel; -+ -+ /* -+ * KDBUS_ATTACH_CGROUP, KDBUS_ATTACH_AUDIT and -+ * KDBUS_ATTACH_SECLABEL -+ */ -+ no_meta_audit = !config_auditsyscall_is_enabled(); -+ no_meta_cgroups = !config_cgroups_is_enabled(); -+ no_meta_seclabel = !config_security_is_enabled(); -+ -+ if (no_meta_audit | no_meta_cgroups | no_meta_seclabel) -+ printf("# Starting tests without %s%s%s metadata support\n", -+ no_meta_audit ? "AUDIT " : "", -+ no_meta_cgroups ? "CGROUP " : "", -+ no_meta_seclabel ? "SECLABEL " : ""); -+ else -+ printf("# Starting tests with full metadata support\n"); -+} -+ -+int run_tests(struct kdbus_test_args *kdbus_args) -+{ -+ int ret; -+ static char control[4096]; -+ -+ snprintf(control, sizeof(control), "%s/control", kdbus_args->root); -+ -+ if (access(control, W_OK) < 0) { -+ printf("Unable to locate control node at '%s'.\n", -+ control); -+ return TEST_ERR; -+ } -+ -+ if (kdbus_args->test) { -+ ret = start_one_test(kdbus_args); -+ } else { -+ do { -+ ret = start_all_tests(kdbus_args); -+ if (ret != TEST_OK) -+ break; -+ } while (kdbus_args->loop); -+ } -+ -+ return ret; -+} -+ -+static void nop_handler(int sig) {} -+ -+static int test_prepare_mounts(struct kdbus_test_args *kdbus_args) -+{ -+ int ret; -+ char kdbusfs[64] = {'\0'}; -+ -+ snprintf(kdbusfs, sizeof(kdbusfs), "%sfs", kdbus_args->module); -+ -+ /* make current mount slave */ -+ ret = mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL); -+ if (ret < 0) { -+ ret = -errno; -+ printf("error mount() root: %d (%m)\n", ret); -+ return ret; -+ } -+ -+ /* Remount procfs since we need it in our tests */ -+ if (kdbus_args->pidns) { -+ ret = mount("proc", "/proc", "proc", -+ MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL); -+ if (ret < 0) { -+ ret = -errno; -+ printf("error mount() /proc : %d (%m)\n", ret); -+ return ret; -+ } -+ } -+ -+ /* Remount kdbusfs */ -+ ret = mount(kdbusfs, kdbus_args->root, kdbusfs, -+ MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL); -+ if (ret < 0) { -+ ret = -errno; -+ printf("error mount() %s :%d (%m)\n", kdbusfs, ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+int run_tests_in_namespaces(struct kdbus_test_args *kdbus_args) -+{ -+ int ret; -+ int efd = -1; -+ int status; -+ pid_t pid, rpid; -+ struct sigaction oldsa; -+ struct sigaction sa = { -+ .sa_handler = nop_handler, -+ .sa_flags = SA_NOCLDSTOP, -+ }; -+ -+ efd = eventfd(0, EFD_CLOEXEC); -+ if (efd < 0) { -+ ret = -errno; -+ printf("eventfd() failed: %d (%m)\n", ret); -+ return TEST_ERR; -+ } -+ -+ ret = sigaction(SIGCHLD, &sa, &oldsa); -+ if (ret < 0) { -+ ret = -errno; -+ printf("sigaction() failed: %d (%m)\n", ret); -+ return TEST_ERR; -+ } -+ -+ /* setup namespaces */ -+ pid = syscall(__NR_clone, SIGCHLD| -+ (kdbus_args->userns ? CLONE_NEWUSER : 0) | -+ (kdbus_args->mntns ? CLONE_NEWNS : 0) | -+ (kdbus_args->pidns ? CLONE_NEWPID : 0), NULL); -+ if (pid < 0) { -+ printf("clone() failed: %d (%m)\n", -errno); -+ return TEST_ERR; -+ } -+ -+ if (pid == 0) { -+ eventfd_t event_status = 0; -+ -+ ret = prctl(PR_SET_PDEATHSIG, SIGKILL); -+ if (ret < 0) { -+ ret = -errno; -+ printf("error prctl(): %d (%m)\n", ret); -+ _exit(TEST_ERR); -+ } -+ -+ /* reset sighandlers of childs */ -+ ret = sigaction(SIGCHLD, &oldsa, NULL); -+ if (ret < 0) { -+ ret = -errno; -+ printf("sigaction() failed: %d (%m)\n", ret); -+ _exit(TEST_ERR); -+ } -+ -+ ret = eventfd_read(efd, &event_status); -+ if (ret < 0 || event_status != 1) { -+ printf("error eventfd_read()\n"); -+ _exit(TEST_ERR); -+ } -+ -+ if (kdbus_args->mntns) { -+ ret = test_prepare_mounts(kdbus_args); -+ if (ret < 0) { -+ printf("error preparing mounts\n"); -+ _exit(TEST_ERR); -+ } -+ } -+ -+ ret = run_tests(kdbus_args); -+ _exit(ret); -+ } -+ -+ /* Setup userns mapping */ -+ if (kdbus_args->userns) { -+ ret = userns_map_uid_gid(pid, kdbus_args->uid_map, -+ kdbus_args->gid_map); -+ if (ret < 0) { -+ printf("error mapping uid and gid in userns\n"); -+ eventfd_write(efd, 2); -+ return TEST_ERR; -+ } -+ } -+ -+ ret = eventfd_write(efd, 1); -+ if (ret < 0) { -+ ret = -errno; -+ printf("error eventfd_write(): %d (%m)\n", ret); -+ return TEST_ERR; -+ } -+ -+ rpid = waitpid(pid, &status, 0); -+ ASSERT_RETURN_VAL(rpid == pid, TEST_ERR); -+ -+ close(efd); -+ -+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) -+ return TEST_ERR; -+ -+ return TEST_OK; -+} -+ -+int start_tests(struct kdbus_test_args *kdbus_args) -+{ -+ int ret; -+ bool namespaces; -+ uint64_t kdbus_param_mask; -+ static char fspath[4096], parampath[4096]; -+ -+ namespaces = (kdbus_args->mntns || kdbus_args->pidns || -+ kdbus_args->userns); -+ -+ /* for pidns we need mntns set */ -+ if (kdbus_args->pidns && !kdbus_args->mntns) { -+ printf("Failed: please set both pid and mnt namesapces\n"); -+ return TEST_ERR; -+ } -+ -+ if (kdbus_args->userns) { -+ if (!config_user_ns_is_enabled()) { -+ printf("User namespace not supported\n"); -+ return TEST_ERR; -+ } -+ -+ if (!kdbus_args->uid_map || !kdbus_args->gid_map) { -+ printf("Failed: please specify uid or gid mapping\n"); -+ return TEST_ERR; -+ } -+ } -+ -+ print_kdbus_test_args(kdbus_args); -+ print_metadata_support(); -+ -+ /* setup kdbus paths */ -+ if (!kdbus_args->module) -+ kdbus_args->module = "kdbus"; -+ -+ if (!kdbus_args->root) { -+ snprintf(fspath, sizeof(fspath), "/sys/fs/%s", -+ kdbus_args->module); -+ kdbus_args->root = fspath; -+ } -+ -+ snprintf(parampath, sizeof(parampath), -+ "/sys/module/%s/parameters/attach_flags_mask", -+ kdbus_args->module); -+ kdbus_args->mask_param_path = parampath; -+ -+ ret = kdbus_sysfs_get_parameter_mask(kdbus_args->mask_param_path, -+ &kdbus_param_mask); -+ if (ret < 0) -+ return TEST_ERR; -+ -+ printf("# Starting tests with an attach_flags_mask=0x%llx\n", -+ (unsigned long long)kdbus_param_mask); -+ -+ /* Start tests */ -+ if (namespaces) -+ ret = run_tests_in_namespaces(kdbus_args); -+ else -+ ret = run_tests(kdbus_args); -+ -+ return ret; -+} -+ -+int main(int argc, char *argv[]) -+{ -+ int t, ret = 0; -+ struct kdbus_test_args *kdbus_args; -+ enum { -+ ARG_MNTNS = 0x100, -+ ARG_PIDNS, -+ ARG_USERNS, -+ ARG_UIDMAP, -+ ARG_GIDMAP, -+ }; -+ -+ kdbus_args = malloc(sizeof(*kdbus_args)); -+ if (!kdbus_args) { -+ printf("unable to malloc() kdbus_args\n"); -+ return EXIT_FAILURE; -+ } -+ -+ memset(kdbus_args, 0, sizeof(*kdbus_args)); -+ -+ static const struct option options[] = { -+ { "loop", no_argument, NULL, 'x' }, -+ { "help", no_argument, NULL, 'h' }, -+ { "root", required_argument, NULL, 'r' }, -+ { "test", required_argument, NULL, 't' }, -+ { "bus", required_argument, NULL, 'b' }, -+ { "wait", required_argument, NULL, 'w' }, -+ { "fork", no_argument, NULL, 'f' }, -+ { "module", required_argument, NULL, 'm' }, -+ { "tap", no_argument, NULL, 'a' }, -+ { "mntns", no_argument, NULL, ARG_MNTNS }, -+ { "pidns", no_argument, NULL, ARG_PIDNS }, -+ { "userns", no_argument, NULL, ARG_USERNS }, -+ { "uidmap", required_argument, NULL, ARG_UIDMAP }, -+ { "gidmap", required_argument, NULL, ARG_GIDMAP }, -+ {} -+ }; -+ -+ srand(time(NULL)); -+ -+ while ((t = getopt_long(argc, argv, "hxfm:r:t:b:w:a", options, NULL)) >= 0) { -+ switch (t) { -+ case 'x': -+ kdbus_args->loop = 1; -+ break; -+ -+ case 'm': -+ kdbus_args->module = optarg; -+ break; -+ -+ case 'r': -+ kdbus_args->root = optarg; -+ break; -+ -+ case 't': -+ kdbus_args->test = optarg; -+ break; -+ -+ case 'b': -+ kdbus_args->busname = optarg; -+ break; -+ -+ case 'w': -+ kdbus_args->wait = strtol(optarg, NULL, 10); -+ break; -+ -+ case 'f': -+ kdbus_args->fork = 1; -+ break; -+ -+ case 'a': -+ kdbus_args->tap_output = 1; -+ break; -+ -+ case ARG_MNTNS: -+ kdbus_args->mntns = true; -+ break; -+ -+ case ARG_PIDNS: -+ kdbus_args->pidns = true; -+ break; -+ -+ case ARG_USERNS: -+ kdbus_args->userns = true; -+ break; -+ -+ case ARG_UIDMAP: -+ kdbus_args->uid_map = optarg; -+ break; -+ -+ case ARG_GIDMAP: -+ kdbus_args->gid_map = optarg; -+ break; -+ -+ default: -+ case 'h': -+ usage(argv[0]); -+ } -+ } -+ -+ ret = start_tests(kdbus_args); -+ if (ret == TEST_ERR) -+ return EXIT_FAILURE; -+ -+ free(kdbus_args); -+ -+ return 0; -+} -diff --git a/tools/testing/selftests/kdbus/kdbus-test.h b/tools/testing/selftests/kdbus/kdbus-test.h -new file mode 100644 -index 000000000000..647331883763 ---- /dev/null -+++ b/tools/testing/selftests/kdbus/kdbus-test.h -@@ -0,0 +1,85 @@ -+#ifndef _TEST_KDBUS_H_ -+#define _TEST_KDBUS_H_ -+ -+struct kdbus_test_env { -+ char *buspath; -+ const char *root; -+ const char *module; -+ const char *mask_param_path; -+ int control_fd; -+ struct kdbus_conn *conn; -+}; -+ -+enum { -+ TEST_OK, -+ TEST_SKIP, -+ TEST_ERR, -+}; -+ -+#define ASSERT_RETURN_VAL(cond, val) \ -+ if (!(cond)) { \ -+ fprintf(stderr, "Assertion '%s' failed in %s(), %s:%d\n", \ -+ #cond, __func__, __FILE__, __LINE__); \ -+ return val; \ -+ } -+ -+#define ASSERT_EXIT_VAL(cond, val) \ -+ if (!(cond)) { \ -+ fprintf(stderr, "Assertion '%s' failed in %s(), %s:%d\n", \ -+ #cond, __func__, __FILE__, __LINE__); \ -+ _exit(val); \ -+ } -+ -+#define ASSERT_BREAK(cond) \ -+ if (!(cond)) { \ -+ fprintf(stderr, "Assertion '%s' failed in %s(), %s:%d\n", \ -+ #cond, __func__, __FILE__, __LINE__); \ -+ break; \ -+ } -+ -+#define ASSERT_RETURN(cond) \ -+ ASSERT_RETURN_VAL(cond, TEST_ERR) -+ -+#define ASSERT_EXIT(cond) \ -+ ASSERT_EXIT_VAL(cond, EXIT_FAILURE) -+ -+int kdbus_test_activator(struct kdbus_test_env *env); -+int kdbus_test_attach_flags(struct kdbus_test_env *env); -+int kdbus_test_benchmark(struct kdbus_test_env *env); -+int kdbus_test_benchmark_nomemfds(struct kdbus_test_env *env); -+int kdbus_test_benchmark_uds(struct kdbus_test_env *env); -+int kdbus_test_bus_make(struct kdbus_test_env *env); -+int kdbus_test_byebye(struct kdbus_test_env *env); -+int kdbus_test_chat(struct kdbus_test_env *env); -+int kdbus_test_conn_info(struct kdbus_test_env *env); -+int kdbus_test_conn_update(struct kdbus_test_env *env); -+int kdbus_test_daemon(struct kdbus_test_env *env); -+int kdbus_test_custom_endpoint(struct kdbus_test_env *env); -+int kdbus_test_fd_passing(struct kdbus_test_env *env); -+int kdbus_test_free(struct kdbus_test_env *env); -+int kdbus_test_hello(struct kdbus_test_env *env); -+int kdbus_test_match_bloom(struct kdbus_test_env *env); -+int kdbus_test_match_id_add(struct kdbus_test_env *env); -+int kdbus_test_match_id_remove(struct kdbus_test_env *env); -+int kdbus_test_match_replace(struct kdbus_test_env *env); -+int kdbus_test_match_name_add(struct kdbus_test_env *env); -+int kdbus_test_match_name_change(struct kdbus_test_env *env); -+int kdbus_test_match_name_remove(struct kdbus_test_env *env); -+int kdbus_test_message_basic(struct kdbus_test_env *env); -+int kdbus_test_message_prio(struct kdbus_test_env *env); -+int kdbus_test_message_quota(struct kdbus_test_env *env); -+int kdbus_test_memory_access(struct kdbus_test_env *env); -+int kdbus_test_metadata_ns(struct kdbus_test_env *env); -+int kdbus_test_monitor(struct kdbus_test_env *env); -+int kdbus_test_name_basic(struct kdbus_test_env *env); -+int kdbus_test_name_conflict(struct kdbus_test_env *env); -+int kdbus_test_name_queue(struct kdbus_test_env *env); -+int kdbus_test_policy(struct kdbus_test_env *env); -+int kdbus_test_policy_ns(struct kdbus_test_env *env); -+int kdbus_test_policy_priv(struct kdbus_test_env *env); -+int kdbus_test_sync_byebye(struct kdbus_test_env *env); -+int kdbus_test_sync_reply(struct kdbus_test_env *env); -+int kdbus_test_timeout(struct kdbus_test_env *env); -+int kdbus_test_writable_pool(struct kdbus_test_env *env); -+ -+#endif /* _TEST_KDBUS_H_ */ -diff --git a/tools/testing/selftests/kdbus/kdbus-util.c b/tools/testing/selftests/kdbus/kdbus-util.c -new file mode 100644 -index 000000000000..4b376ecfdbed ---- /dev/null -+++ b/tools/testing/selftests/kdbus/kdbus-util.c -@@ -0,0 +1,1615 @@ -+/* -+ * Copyright (C) 2013-2015 Daniel Mack -+ * Copyright (C) 2013-2015 Kay Sievers -+ * Copyright (C) 2014-2015 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 <stdio.h> -+#include <stdarg.h> -+#include <string.h> -+#include <time.h> -+#include <inttypes.h> -+#include <fcntl.h> -+#include <stdlib.h> -+#include <stddef.h> -+#include <unistd.h> -+#include <stdint.h> -+#include <stdbool.h> -+#include <errno.h> -+#include <assert.h> -+#include <poll.h> -+#include <grp.h> -+#include <sys/capability.h> -+#include <sys/mman.h> -+#include <sys/stat.h> -+#include <sys/time.h> -+#include <linux/unistd.h> -+#include <linux/memfd.h> -+ -+#ifndef __NR_memfd_create -+ #ifdef __x86_64__ -+ #define __NR_memfd_create 319 -+ #elif defined __arm__ -+ #define __NR_memfd_create 385 -+ #else -+ #define __NR_memfd_create 356 -+ #endif -+#endif -+ -+#include "kdbus-api.h" -+#include "kdbus-util.h" -+#include "kdbus-enum.h" -+ -+#ifndef F_ADD_SEALS -+#define F_LINUX_SPECIFIC_BASE 1024 -+#define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9) -+#define F_GET_SEALS (F_LINUX_SPECIFIC_BASE + 10) -+ -+#define F_SEAL_SEAL 0x0001 /* prevent further seals from being set */ -+#define F_SEAL_SHRINK 0x0002 /* prevent file from shrinking */ -+#define F_SEAL_GROW 0x0004 /* prevent file from growing */ -+#define F_SEAL_WRITE 0x0008 /* prevent writes */ -+#endif -+ -+int kdbus_util_verbose = true; -+ -+int kdbus_sysfs_get_parameter_mask(const char *path, uint64_t *mask) -+{ -+ int ret; -+ FILE *file; -+ unsigned long long value; -+ -+ file = fopen(path, "r"); -+ if (!file) { -+ ret = -errno; -+ kdbus_printf("--- error fopen(): %d (%m)\n", ret); -+ return ret; -+ } -+ -+ ret = fscanf(file, "%llu", &value); -+ if (ret != 1) { -+ if (ferror(file)) -+ ret = -errno; -+ else -+ ret = -EIO; -+ -+ kdbus_printf("--- error fscanf(): %d\n", ret); -+ fclose(file); -+ return ret; -+ } -+ -+ *mask = (uint64_t)value; -+ -+ fclose(file); -+ -+ return 0; -+} -+ -+int kdbus_sysfs_set_parameter_mask(const char *path, uint64_t mask) -+{ -+ int ret; -+ FILE *file; -+ -+ file = fopen(path, "w"); -+ if (!file) { -+ ret = -errno; -+ kdbus_printf("--- error open(): %d (%m)\n", ret); -+ return ret; -+ } -+ -+ ret = fprintf(file, "%llu", (unsigned long long)mask); -+ if (ret <= 0) { -+ ret = -EIO; -+ kdbus_printf("--- error fprintf(): %d\n", ret); -+ } -+ -+ fclose(file); -+ -+ return ret > 0 ? 0 : ret; -+} -+ -+int kdbus_create_bus(int control_fd, const char *name, -+ uint64_t req_meta, uint64_t owner_meta, -+ char **path) -+{ -+ struct { -+ struct kdbus_cmd cmd; -+ -+ /* bloom size item */ -+ struct { -+ uint64_t size; -+ uint64_t type; -+ struct kdbus_bloom_parameter bloom; -+ } bp; -+ -+ /* required and owner metadata items */ -+ struct { -+ uint64_t size; -+ uint64_t type; -+ uint64_t flags; -+ } attach[2]; -+ -+ /* name item */ -+ struct { -+ uint64_t size; -+ uint64_t type; -+ char str[64]; -+ } name; -+ } bus_make; -+ int ret; -+ -+ memset(&bus_make, 0, sizeof(bus_make)); -+ bus_make.bp.size = sizeof(bus_make.bp); -+ bus_make.bp.type = KDBUS_ITEM_BLOOM_PARAMETER; -+ bus_make.bp.bloom.size = 64; -+ bus_make.bp.bloom.n_hash = 1; -+ -+ snprintf(bus_make.name.str, sizeof(bus_make.name.str), -+ "%u-%s", getuid(), name); -+ -+ bus_make.attach[0].type = KDBUS_ITEM_ATTACH_FLAGS_RECV; -+ bus_make.attach[0].size = sizeof(bus_make.attach[0]); -+ bus_make.attach[0].flags = req_meta; -+ -+ bus_make.attach[1].type = KDBUS_ITEM_ATTACH_FLAGS_SEND; -+ bus_make.attach[1].size = sizeof(bus_make.attach[0]); -+ bus_make.attach[1].flags = owner_meta; -+ -+ bus_make.name.type = KDBUS_ITEM_MAKE_NAME; -+ bus_make.name.size = KDBUS_ITEM_HEADER_SIZE + -+ strlen(bus_make.name.str) + 1; -+ -+ bus_make.cmd.flags = KDBUS_MAKE_ACCESS_WORLD; -+ bus_make.cmd.size = sizeof(bus_make.cmd) + -+ bus_make.bp.size + -+ bus_make.attach[0].size + -+ bus_make.attach[1].size + -+ bus_make.name.size; -+ -+ kdbus_printf("Creating bus with name >%s< on control fd %d ...\n", -+ name, control_fd); -+ -+ ret = kdbus_cmd_bus_make(control_fd, &bus_make.cmd); -+ if (ret < 0) { -+ kdbus_printf("--- error when making bus: %d (%m)\n", ret); -+ return ret; -+ } -+ -+ if (ret == 0 && path) -+ *path = strdup(bus_make.name.str); -+ -+ return ret; -+} -+ -+struct kdbus_conn * -+kdbus_hello(const char *path, uint64_t flags, -+ const struct kdbus_item *item, size_t item_size) -+{ -+ struct kdbus_cmd_free cmd_free = {}; -+ int fd, ret; -+ struct { -+ struct kdbus_cmd_hello hello; -+ -+ struct { -+ uint64_t size; -+ uint64_t type; -+ char str[16]; -+ } conn_name; -+ -+ uint8_t extra_items[item_size]; -+ } h; -+ struct kdbus_conn *conn; -+ -+ memset(&h, 0, sizeof(h)); -+ -+ if (item_size > 0) -+ memcpy(h.extra_items, item, item_size); -+ -+ kdbus_printf("-- opening bus connection %s\n", path); -+ fd = open(path, O_RDWR|O_CLOEXEC); -+ if (fd < 0) { -+ kdbus_printf("--- error %d (%m)\n", fd); -+ return NULL; -+ } -+ -+ h.hello.flags = flags | KDBUS_HELLO_ACCEPT_FD; -+ h.hello.attach_flags_send = _KDBUS_ATTACH_ALL; -+ h.hello.attach_flags_recv = _KDBUS_ATTACH_ALL; -+ h.conn_name.type = KDBUS_ITEM_CONN_DESCRIPTION; -+ strcpy(h.conn_name.str, "this-is-my-name"); -+ h.conn_name.size = KDBUS_ITEM_HEADER_SIZE + strlen(h.conn_name.str) + 1; -+ -+ h.hello.size = sizeof(h); -+ h.hello.pool_size = POOL_SIZE; -+ -+ ret = kdbus_cmd_hello(fd, (struct kdbus_cmd_hello *) &h.hello); -+ if (ret < 0) { -+ kdbus_printf("--- error when saying hello: %d (%m)\n", ret); -+ return NULL; -+ } -+ kdbus_printf("-- Our peer ID for %s: %llu -- bus uuid: '%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x'\n", -+ path, (unsigned long long)h.hello.id, -+ h.hello.id128[0], h.hello.id128[1], h.hello.id128[2], -+ h.hello.id128[3], h.hello.id128[4], h.hello.id128[5], -+ h.hello.id128[6], h.hello.id128[7], h.hello.id128[8], -+ h.hello.id128[9], h.hello.id128[10], h.hello.id128[11], -+ h.hello.id128[12], h.hello.id128[13], h.hello.id128[14], -+ h.hello.id128[15]); -+ -+ cmd_free.size = sizeof(cmd_free); -+ cmd_free.offset = h.hello.offset; -+ kdbus_cmd_free(fd, &cmd_free); -+ -+ conn = malloc(sizeof(*conn)); -+ if (!conn) { -+ kdbus_printf("unable to malloc()!?\n"); -+ return NULL; -+ } -+ -+ conn->buf = mmap(NULL, POOL_SIZE, PROT_READ, MAP_SHARED, fd, 0); -+ if (conn->buf == MAP_FAILED) { -+ free(conn); -+ close(fd); -+ kdbus_printf("--- error mmap (%m)\n"); -+ return NULL; -+ } -+ -+ conn->fd = fd; -+ conn->id = h.hello.id; -+ return conn; -+} -+ -+struct kdbus_conn * -+kdbus_hello_registrar(const char *path, const char *name, -+ const struct kdbus_policy_access *access, -+ size_t num_access, uint64_t flags) -+{ -+ struct kdbus_item *item, *items; -+ size_t i, size; -+ -+ size = KDBUS_ITEM_SIZE(strlen(name) + 1) + -+ num_access * KDBUS_ITEM_SIZE(sizeof(*access)); -+ -+ items = alloca(size); -+ -+ item = items; -+ item->size = KDBUS_ITEM_HEADER_SIZE + strlen(name) + 1; -+ item->type = KDBUS_ITEM_NAME; -+ strcpy(item->str, name); -+ item = KDBUS_ITEM_NEXT(item); -+ -+ for (i = 0; i < num_access; i++) { -+ item->size = KDBUS_ITEM_HEADER_SIZE + -+ sizeof(struct kdbus_policy_access); -+ item->type = KDBUS_ITEM_POLICY_ACCESS; -+ -+ item->policy_access.type = access[i].type; -+ item->policy_access.access = access[i].access; -+ item->policy_access.id = access[i].id; -+ -+ item = KDBUS_ITEM_NEXT(item); -+ } -+ -+ return kdbus_hello(path, flags, items, size); -+} -+ -+struct kdbus_conn *kdbus_hello_activator(const char *path, const char *name, -+ const struct kdbus_policy_access *access, -+ size_t num_access) -+{ -+ return kdbus_hello_registrar(path, name, access, num_access, -+ KDBUS_HELLO_ACTIVATOR); -+} -+ -+bool kdbus_item_in_message(struct kdbus_msg *msg, uint64_t type) -+{ -+ const struct kdbus_item *item; -+ -+ KDBUS_ITEM_FOREACH(item, msg, items) -+ if (item->type == type) -+ return true; -+ -+ return false; -+} -+ -+int kdbus_bus_creator_info(struct kdbus_conn *conn, -+ uint64_t flags, -+ uint64_t *offset) -+{ -+ struct kdbus_cmd_info *cmd; -+ size_t size = sizeof(*cmd); -+ int ret; -+ -+ cmd = alloca(size); -+ memset(cmd, 0, size); -+ cmd->size = size; -+ cmd->attach_flags = flags; -+ -+ ret = kdbus_cmd_bus_creator_info(conn->fd, cmd); -+ if (ret < 0) { -+ kdbus_printf("--- error when requesting info: %d (%m)\n", ret); -+ return ret; -+ } -+ -+ if (offset) -+ *offset = cmd->offset; -+ else -+ kdbus_free(conn, cmd->offset); -+ -+ return 0; -+} -+ -+int kdbus_conn_info(struct kdbus_conn *conn, uint64_t id, -+ const char *name, uint64_t flags, -+ uint64_t *offset) -+{ -+ struct kdbus_cmd_info *cmd; -+ size_t size = sizeof(*cmd); -+ struct kdbus_info *info; -+ int ret; -+ -+ if (name) -+ size += KDBUS_ITEM_HEADER_SIZE + strlen(name) + 1; -+ -+ cmd = alloca(size); -+ memset(cmd, 0, size); -+ cmd->size = size; -+ cmd->attach_flags = flags; -+ -+ if (name) { -+ cmd->items[0].size = KDBUS_ITEM_HEADER_SIZE + strlen(name) + 1; -+ cmd->items[0].type = KDBUS_ITEM_NAME; -+ strcpy(cmd->items[0].str, name); -+ } else { -+ cmd->id = id; -+ } -+ -+ ret = kdbus_cmd_conn_info(conn->fd, cmd); -+ if (ret < 0) { -+ kdbus_printf("--- error when requesting info: %d (%m)\n", ret); -+ return ret; -+ } -+ -+ info = (struct kdbus_info *) (conn->buf + cmd->offset); -+ if (info->size != cmd->info_size) { -+ kdbus_printf("%s(): size mismatch: %d != %d\n", __func__, -+ (int) info->size, (int) cmd->info_size); -+ return -EIO; -+ } -+ -+ if (offset) -+ *offset = cmd->offset; -+ else -+ kdbus_free(conn, cmd->offset); -+ -+ return 0; -+} -+ -+void kdbus_conn_free(struct kdbus_conn *conn) -+{ -+ if (!conn) -+ return; -+ -+ if (conn->buf) -+ munmap(conn->buf, POOL_SIZE); -+ -+ if (conn->fd >= 0) -+ close(conn->fd); -+ -+ free(conn); -+} -+ -+int sys_memfd_create(const char *name, __u64 size) -+{ -+ int ret, fd; -+ -+ ret = syscall(__NR_memfd_create, name, MFD_ALLOW_SEALING); -+ if (ret < 0) -+ return ret; -+ -+ fd = ret; -+ -+ ret = ftruncate(fd, size); -+ if (ret < 0) { -+ close(fd); -+ return ret; -+ } -+ -+ return fd; -+} -+ -+int sys_memfd_seal_set(int fd) -+{ -+ return fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | -+ F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL); -+} -+ -+off_t sys_memfd_get_size(int fd, off_t *size) -+{ -+ struct stat stat; -+ int ret; -+ -+ ret = fstat(fd, &stat); -+ if (ret < 0) { -+ kdbus_printf("stat() failed: %m\n"); -+ return ret; -+ } -+ -+ *size = stat.st_size; -+ return 0; -+} -+ -+static int __kdbus_msg_send(const struct kdbus_conn *conn, -+ const char *name, -+ uint64_t cookie, -+ uint64_t flags, -+ uint64_t timeout, -+ int64_t priority, -+ uint64_t dst_id, -+ uint64_t cmd_flags, -+ int cancel_fd) -+{ -+ struct kdbus_cmd_send *cmd; -+ struct kdbus_msg *msg; -+ const char ref1[1024 * 128 + 3] = "0123456789_0"; -+ const char ref2[] = "0123456789_1"; -+ struct kdbus_item *item; -+ struct timespec now; -+ uint64_t size; -+ int memfd = -1; -+ int ret; -+ -+ size = sizeof(*msg); -+ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec)); -+ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec)); -+ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec)); -+ -+ if (dst_id == KDBUS_DST_ID_BROADCAST) -+ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_bloom_filter)) + 64; -+ else { -+ memfd = sys_memfd_create("my-name-is-nice", 1024 * 1024); -+ if (memfd < 0) { -+ kdbus_printf("failed to create memfd: %m\n"); -+ return memfd; -+ } -+ -+ if (write(memfd, "kdbus memfd 1234567", 19) != 19) { -+ ret = -errno; -+ kdbus_printf("writing to memfd failed: %m\n"); -+ return ret; -+ } -+ -+ ret = sys_memfd_seal_set(memfd); -+ if (ret < 0) { -+ ret = -errno; -+ kdbus_printf("memfd sealing failed: %m\n"); -+ return ret; -+ } -+ -+ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_memfd)); -+ } -+ -+ if (name) -+ size += KDBUS_ITEM_SIZE(strlen(name) + 1); -+ -+ msg = malloc(size); -+ if (!msg) { -+ ret = -errno; -+ kdbus_printf("unable to malloc()!?\n"); -+ return ret; -+ } -+ -+ if (dst_id == KDBUS_DST_ID_BROADCAST) -+ flags |= KDBUS_MSG_SIGNAL; -+ -+ memset(msg, 0, size); -+ msg->flags = flags; -+ msg->priority = priority; -+ msg->size = size; -+ msg->src_id = conn->id; -+ msg->dst_id = name ? 0 : dst_id; -+ msg->cookie = cookie; -+ msg->payload_type = KDBUS_PAYLOAD_DBUS; -+ -+ if (timeout) { -+ ret = clock_gettime(CLOCK_MONOTONIC_COARSE, &now); -+ if (ret < 0) -+ return ret; -+ -+ msg->timeout_ns = now.tv_sec * 1000000000ULL + -+ now.tv_nsec + timeout; -+ } -+ -+ item = msg->items; -+ -+ if (name) { -+ item->type = KDBUS_ITEM_DST_NAME; -+ item->size = KDBUS_ITEM_HEADER_SIZE + strlen(name) + 1; -+ strcpy(item->str, name); -+ item = KDBUS_ITEM_NEXT(item); -+ } -+ -+ item->type = KDBUS_ITEM_PAYLOAD_VEC; -+ item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_vec); -+ item->vec.address = (uintptr_t)&ref1; -+ item->vec.size = sizeof(ref1); -+ item = KDBUS_ITEM_NEXT(item); -+ -+ /* data padding for ref1 */ -+ item->type = KDBUS_ITEM_PAYLOAD_VEC; -+ item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_vec); -+ item->vec.address = (uintptr_t)NULL; -+ item->vec.size = KDBUS_ALIGN8(sizeof(ref1)) - sizeof(ref1); -+ item = KDBUS_ITEM_NEXT(item); -+ -+ item->type = KDBUS_ITEM_PAYLOAD_VEC; -+ item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_vec); -+ item->vec.address = (uintptr_t)&ref2; -+ item->vec.size = sizeof(ref2); -+ item = KDBUS_ITEM_NEXT(item); -+ -+ if (dst_id == KDBUS_DST_ID_BROADCAST) { -+ item->type = KDBUS_ITEM_BLOOM_FILTER; -+ item->size = KDBUS_ITEM_SIZE(sizeof(struct kdbus_bloom_filter)) + 64; -+ item->bloom_filter.generation = 0; -+ } else { -+ item->type = KDBUS_ITEM_PAYLOAD_MEMFD; -+ item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_memfd); -+ item->memfd.size = 16; -+ item->memfd.fd = memfd; -+ } -+ item = KDBUS_ITEM_NEXT(item); -+ -+ size = sizeof(*cmd); -+ if (cancel_fd != -1) -+ size += KDBUS_ITEM_SIZE(sizeof(cancel_fd)); -+ -+ cmd = malloc(size); -+ cmd->size = size; -+ cmd->flags = cmd_flags; -+ cmd->msg_address = (uintptr_t)msg; -+ -+ item = cmd->items; -+ -+ if (cancel_fd != -1) { -+ item->type = KDBUS_ITEM_CANCEL_FD; -+ item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(cancel_fd); -+ item->fds[0] = cancel_fd; -+ item = KDBUS_ITEM_NEXT(item); -+ } -+ -+ ret = kdbus_cmd_send(conn->fd, cmd); -+ if (memfd >= 0) -+ close(memfd); -+ -+ if (ret < 0) { -+ kdbus_printf("error sending message: %d (%m)\n", ret); -+ return ret; -+ } -+ -+ if (cmd_flags & KDBUS_SEND_SYNC_REPLY) { -+ struct kdbus_msg *reply; -+ -+ kdbus_printf("SYNC REPLY @offset %llu:\n", cmd->reply.offset); -+ reply = (struct kdbus_msg *)(conn->buf + cmd->reply.offset); -+ kdbus_msg_dump(conn, reply); -+ -+ kdbus_msg_free(reply); -+ -+ ret = kdbus_free(conn, cmd->reply.offset); -+ if (ret < 0) -+ return ret; -+ } -+ -+ free(msg); -+ free(cmd); -+ -+ return 0; -+} -+ -+int kdbus_msg_send(const struct kdbus_conn *conn, const char *name, -+ uint64_t cookie, uint64_t flags, uint64_t timeout, -+ int64_t priority, uint64_t dst_id) -+{ -+ return __kdbus_msg_send(conn, name, cookie, flags, timeout, priority, -+ dst_id, 0, -1); -+} -+ -+int kdbus_msg_send_sync(const struct kdbus_conn *conn, const char *name, -+ uint64_t cookie, uint64_t flags, uint64_t timeout, -+ int64_t priority, uint64_t dst_id, int cancel_fd) -+{ -+ return __kdbus_msg_send(conn, name, cookie, flags, timeout, priority, -+ dst_id, KDBUS_SEND_SYNC_REPLY, cancel_fd); -+} -+ -+int kdbus_msg_send_reply(const struct kdbus_conn *conn, -+ uint64_t reply_cookie, -+ uint64_t dst_id) -+{ -+ struct kdbus_cmd_send cmd = {}; -+ struct kdbus_msg *msg; -+ const char ref1[1024 * 128 + 3] = "0123456789_0"; -+ struct kdbus_item *item; -+ uint64_t size; -+ int ret; -+ -+ size = sizeof(struct kdbus_msg); -+ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec)); -+ -+ msg = malloc(size); -+ if (!msg) { -+ kdbus_printf("unable to malloc()!?\n"); -+ return -ENOMEM; -+ } -+ -+ memset(msg, 0, size); -+ msg->size = size; -+ msg->src_id = conn->id; -+ msg->dst_id = dst_id; -+ msg->cookie_reply = reply_cookie; -+ msg->payload_type = KDBUS_PAYLOAD_DBUS; -+ -+ item = msg->items; -+ -+ item->type = KDBUS_ITEM_PAYLOAD_VEC; -+ item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_vec); -+ item->vec.address = (uintptr_t)&ref1; -+ item->vec.size = sizeof(ref1); -+ item = KDBUS_ITEM_NEXT(item); -+ -+ cmd.size = sizeof(cmd); -+ cmd.msg_address = (uintptr_t)msg; -+ -+ ret = kdbus_cmd_send(conn->fd, &cmd); -+ if (ret < 0) -+ kdbus_printf("error sending message: %d (%m)\n", ret); -+ -+ free(msg); -+ -+ return ret; -+} -+ -+static char *msg_id(uint64_t id, char *buf) -+{ -+ if (id == 0) -+ return "KERNEL"; -+ if (id == ~0ULL) -+ return "BROADCAST"; -+ sprintf(buf, "%llu", (unsigned long long)id); -+ return buf; -+} -+ -+int kdbus_msg_dump(const struct kdbus_conn *conn, const struct kdbus_msg *msg) -+{ -+ const struct kdbus_item *item = msg->items; -+ char buf_src[32]; -+ char buf_dst[32]; -+ uint64_t timeout = 0; -+ uint64_t cookie_reply = 0; -+ int ret = 0; -+ -+ if (msg->flags & KDBUS_MSG_EXPECT_REPLY) -+ timeout = msg->timeout_ns; -+ else -+ cookie_reply = msg->cookie_reply; -+ -+ kdbus_printf("MESSAGE: %s (%llu bytes) flags=0x%08llx, %s → %s, " -+ "cookie=%llu, timeout=%llu cookie_reply=%llu priority=%lli\n", -+ enum_PAYLOAD(msg->payload_type), (unsigned long long)msg->size, -+ (unsigned long long)msg->flags, -+ msg_id(msg->src_id, buf_src), msg_id(msg->dst_id, buf_dst), -+ (unsigned long long)msg->cookie, (unsigned long long)timeout, -+ (unsigned long long)cookie_reply, (long long)msg->priority); -+ -+ KDBUS_ITEM_FOREACH(item, msg, items) { -+ if (item->size < KDBUS_ITEM_HEADER_SIZE) { -+ kdbus_printf(" +%s (%llu bytes) invalid data record\n", -+ enum_MSG(item->type), item->size); -+ ret = -EINVAL; -+ break; -+ } -+ -+ switch (item->type) { -+ case KDBUS_ITEM_PAYLOAD_OFF: { -+ char *s; -+ -+ if (item->vec.offset == ~0ULL) -+ s = "[\\0-bytes]"; -+ else -+ s = (char *)msg + item->vec.offset; -+ -+ kdbus_printf(" +%s (%llu bytes) off=%llu size=%llu '%s'\n", -+ enum_MSG(item->type), item->size, -+ (unsigned long long)item->vec.offset, -+ (unsigned long long)item->vec.size, s); -+ break; -+ } -+ -+ case KDBUS_ITEM_FDS: { -+ int i, n = (item->size - KDBUS_ITEM_HEADER_SIZE) / -+ sizeof(int); -+ -+ kdbus_printf(" +%s (%llu bytes, %d fds)\n", -+ enum_MSG(item->type), item->size, n); -+ -+ for (i = 0; i < n; i++) -+ kdbus_printf(" fd[%d] = %d\n", -+ i, item->fds[i]); -+ -+ break; -+ } -+ -+ case KDBUS_ITEM_PAYLOAD_MEMFD: { -+ char *buf; -+ off_t size; -+ -+ buf = mmap(NULL, item->memfd.size, PROT_READ, -+ MAP_PRIVATE, item->memfd.fd, 0); -+ if (buf == MAP_FAILED) { -+ kdbus_printf("mmap() fd=%i size=%llu failed: %m\n", -+ item->memfd.fd, item->memfd.size); -+ break; -+ } -+ -+ if (sys_memfd_get_size(item->memfd.fd, &size) < 0) { -+ kdbus_printf("KDBUS_CMD_MEMFD_SIZE_GET failed: %m\n"); -+ break; -+ } -+ -+ kdbus_printf(" +%s (%llu bytes) fd=%i size=%llu filesize=%llu '%s'\n", -+ enum_MSG(item->type), item->size, item->memfd.fd, -+ (unsigned long long)item->memfd.size, -+ (unsigned long long)size, buf); -+ munmap(buf, item->memfd.size); -+ break; -+ } -+ -+ case KDBUS_ITEM_CREDS: -+ kdbus_printf(" +%s (%llu bytes) uid=%lld, euid=%lld, suid=%lld, fsuid=%lld, " -+ "gid=%lld, egid=%lld, sgid=%lld, fsgid=%lld\n", -+ enum_MSG(item->type), item->size, -+ item->creds.uid, item->creds.euid, -+ item->creds.suid, item->creds.fsuid, -+ item->creds.gid, item->creds.egid, -+ item->creds.sgid, item->creds.fsgid); -+ break; -+ -+ case KDBUS_ITEM_PIDS: -+ kdbus_printf(" +%s (%llu bytes) pid=%lld, tid=%lld, ppid=%lld\n", -+ enum_MSG(item->type), item->size, -+ item->pids.pid, item->pids.tid, -+ item->pids.ppid); -+ break; -+ -+ case KDBUS_ITEM_AUXGROUPS: { -+ int i, n; -+ -+ kdbus_printf(" +%s (%llu bytes)\n", -+ enum_MSG(item->type), item->size); -+ n = (item->size - KDBUS_ITEM_HEADER_SIZE) / -+ sizeof(uint64_t); -+ -+ for (i = 0; i < n; i++) -+ kdbus_printf(" gid[%d] = %lld\n", -+ i, item->data64[i]); -+ break; -+ } -+ -+ case KDBUS_ITEM_NAME: -+ case KDBUS_ITEM_PID_COMM: -+ case KDBUS_ITEM_TID_COMM: -+ case KDBUS_ITEM_EXE: -+ case KDBUS_ITEM_CGROUP: -+ case KDBUS_ITEM_SECLABEL: -+ case KDBUS_ITEM_DST_NAME: -+ case KDBUS_ITEM_CONN_DESCRIPTION: -+ kdbus_printf(" +%s (%llu bytes) '%s' (%zu)\n", -+ enum_MSG(item->type), item->size, -+ item->str, strlen(item->str)); -+ break; -+ -+ case KDBUS_ITEM_OWNED_NAME: { -+ kdbus_printf(" +%s (%llu bytes) '%s' (%zu) flags=0x%08llx\n", -+ enum_MSG(item->type), item->size, -+ item->name.name, strlen(item->name.name), -+ item->name.flags); -+ break; -+ } -+ -+ case KDBUS_ITEM_CMDLINE: { -+ size_t size = item->size - KDBUS_ITEM_HEADER_SIZE; -+ const char *str = item->str; -+ int count = 0; -+ -+ kdbus_printf(" +%s (%llu bytes) ", -+ enum_MSG(item->type), item->size); -+ while (size) { -+ kdbus_printf("'%s' ", str); -+ size -= strlen(str) + 1; -+ str += strlen(str) + 1; -+ count++; -+ } -+ -+ kdbus_printf("(%d string%s)\n", -+ count, (count == 1) ? "" : "s"); -+ break; -+ } -+ -+ case KDBUS_ITEM_AUDIT: -+ kdbus_printf(" +%s (%llu bytes) loginuid=%u sessionid=%u\n", -+ enum_MSG(item->type), item->size, -+ item->audit.loginuid, item->audit.sessionid); -+ break; -+ -+ case KDBUS_ITEM_CAPS: { -+ const uint32_t *cap; -+ int n, i; -+ -+ kdbus_printf(" +%s (%llu bytes) len=%llu bytes, last_cap %d\n", -+ enum_MSG(item->type), item->size, -+ (unsigned long long)item->size - -+ KDBUS_ITEM_HEADER_SIZE, -+ (int) item->caps.last_cap); -+ -+ cap = item->caps.caps; -+ n = (item->size - offsetof(struct kdbus_item, caps.caps)) -+ / 4 / sizeof(uint32_t); -+ -+ kdbus_printf(" CapInh="); -+ for (i = 0; i < n; i++) -+ kdbus_printf("%08x", cap[(0 * n) + (n - i - 1)]); -+ -+ kdbus_printf(" CapPrm="); -+ for (i = 0; i < n; i++) -+ kdbus_printf("%08x", cap[(1 * n) + (n - i - 1)]); -+ -+ kdbus_printf(" CapEff="); -+ for (i = 0; i < n; i++) -+ kdbus_printf("%08x", cap[(2 * n) + (n - i - 1)]); -+ -+ kdbus_printf(" CapBnd="); -+ for (i = 0; i < n; i++) -+ kdbus_printf("%08x", cap[(3 * n) + (n - i - 1)]); -+ kdbus_printf("\n"); -+ break; -+ } -+ -+ case KDBUS_ITEM_TIMESTAMP: -+ kdbus_printf(" +%s (%llu bytes) seq=%llu realtime=%lluns monotonic=%lluns\n", -+ enum_MSG(item->type), item->size, -+ (unsigned long long)item->timestamp.seqnum, -+ (unsigned long long)item->timestamp.realtime_ns, -+ (unsigned long long)item->timestamp.monotonic_ns); -+ break; -+ -+ case KDBUS_ITEM_REPLY_TIMEOUT: -+ kdbus_printf(" +%s (%llu bytes) cookie=%llu\n", -+ enum_MSG(item->type), item->size, -+ msg->cookie_reply); -+ break; -+ -+ case KDBUS_ITEM_NAME_ADD: -+ case KDBUS_ITEM_NAME_REMOVE: -+ case KDBUS_ITEM_NAME_CHANGE: -+ kdbus_printf(" +%s (%llu bytes) '%s', old id=%lld, now id=%lld, old_flags=0x%llx new_flags=0x%llx\n", -+ enum_MSG(item->type), -+ (unsigned long long) item->size, -+ item->name_change.name, -+ item->name_change.old_id.id, -+ item->name_change.new_id.id, -+ item->name_change.old_id.flags, -+ item->name_change.new_id.flags); -+ break; -+ -+ case KDBUS_ITEM_ID_ADD: -+ case KDBUS_ITEM_ID_REMOVE: -+ kdbus_printf(" +%s (%llu bytes) id=%llu flags=%llu\n", -+ enum_MSG(item->type), -+ (unsigned long long) item->size, -+ (unsigned long long) item->id_change.id, -+ (unsigned long long) item->id_change.flags); -+ break; -+ -+ default: -+ kdbus_printf(" +%s (%llu bytes)\n", -+ enum_MSG(item->type), item->size); -+ break; -+ } -+ } -+ -+ if ((char *)item - ((char *)msg + msg->size) >= 8) { -+ kdbus_printf("invalid padding at end of message\n"); -+ ret = -EINVAL; -+ } -+ -+ kdbus_printf("\n"); -+ -+ return ret; -+} -+ -+void kdbus_msg_free(struct kdbus_msg *msg) -+{ -+ const struct kdbus_item *item; -+ int nfds, i; -+ -+ if (!msg) -+ return; -+ -+ KDBUS_ITEM_FOREACH(item, msg, items) { -+ switch (item->type) { -+ /* close all memfds */ -+ case KDBUS_ITEM_PAYLOAD_MEMFD: -+ close(item->memfd.fd); -+ break; -+ case KDBUS_ITEM_FDS: -+ nfds = (item->size - KDBUS_ITEM_HEADER_SIZE) / -+ sizeof(int); -+ -+ for (i = 0; i < nfds; i++) -+ close(item->fds[i]); -+ -+ break; -+ } -+ } -+} -+ -+int kdbus_msg_recv(struct kdbus_conn *conn, -+ struct kdbus_msg **msg_out, -+ uint64_t *offset) -+{ -+ struct kdbus_cmd_recv recv = { .size = sizeof(recv) }; -+ struct kdbus_msg *msg; -+ int ret; -+ -+ ret = kdbus_cmd_recv(conn->fd, &recv); -+ if (ret < 0) -+ return ret; -+ -+ msg = (struct kdbus_msg *)(conn->buf + recv.msg.offset); -+ ret = kdbus_msg_dump(conn, msg); -+ if (ret < 0) { -+ kdbus_msg_free(msg); -+ return ret; -+ } -+ -+ if (msg_out) { -+ *msg_out = msg; -+ -+ if (offset) -+ *offset = recv.msg.offset; -+ } else { -+ kdbus_msg_free(msg); -+ -+ ret = kdbus_free(conn, recv.msg.offset); -+ if (ret < 0) -+ return ret; -+ } -+ -+ return 0; -+} -+ -+/* -+ * Returns: 0 on success, negative errno on failure. -+ * -+ * We must return -ETIMEDOUT, -ECONNREST, -EAGAIN and other errors. -+ * We must return the result of kdbus_msg_recv() -+ */ -+int kdbus_msg_recv_poll(struct kdbus_conn *conn, -+ int timeout_ms, -+ struct kdbus_msg **msg_out, -+ uint64_t *offset) -+{ -+ int ret; -+ -+ do { -+ struct timeval before, after, diff; -+ struct pollfd fd; -+ -+ fd.fd = conn->fd; -+ fd.events = POLLIN | POLLPRI | POLLHUP; -+ fd.revents = 0; -+ -+ gettimeofday(&before, NULL); -+ ret = poll(&fd, 1, timeout_ms); -+ gettimeofday(&after, NULL); -+ -+ if (ret == 0) { -+ ret = -ETIMEDOUT; -+ break; -+ } -+ -+ if (ret > 0) { -+ if (fd.revents & POLLIN) -+ ret = kdbus_msg_recv(conn, msg_out, offset); -+ -+ if (fd.revents & (POLLHUP | POLLERR)) -+ ret = -ECONNRESET; -+ } -+ -+ if (ret == 0 || ret != -EAGAIN) -+ break; -+ -+ timersub(&after, &before, &diff); -+ timeout_ms -= diff.tv_sec * 1000UL + -+ diff.tv_usec / 1000UL; -+ } while (timeout_ms > 0); -+ -+ return ret; -+} -+ -+int kdbus_free(const struct kdbus_conn *conn, uint64_t offset) -+{ -+ struct kdbus_cmd_free cmd_free = {}; -+ int ret; -+ -+ cmd_free.size = sizeof(cmd_free); -+ cmd_free.offset = offset; -+ cmd_free.flags = 0; -+ -+ ret = kdbus_cmd_free(conn->fd, &cmd_free); -+ if (ret < 0) { -+ kdbus_printf("KDBUS_CMD_FREE failed: %d (%m)\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+int kdbus_name_acquire(struct kdbus_conn *conn, -+ const char *name, uint64_t *flags) -+{ -+ struct kdbus_cmd *cmd_name; -+ size_t name_len = strlen(name) + 1; -+ uint64_t size = sizeof(*cmd_name) + KDBUS_ITEM_SIZE(name_len); -+ struct kdbus_item *item; -+ int ret; -+ -+ cmd_name = alloca(size); -+ -+ memset(cmd_name, 0, size); -+ -+ item = cmd_name->items; -+ item->size = KDBUS_ITEM_HEADER_SIZE + name_len; -+ item->type = KDBUS_ITEM_NAME; -+ strcpy(item->str, name); -+ -+ cmd_name->size = size; -+ if (flags) -+ cmd_name->flags = *flags; -+ -+ ret = kdbus_cmd_name_acquire(conn->fd, cmd_name); -+ if (ret < 0) { -+ kdbus_printf("error aquiring name: %s\n", strerror(-ret)); -+ return ret; -+ } -+ -+ kdbus_printf("%s(): flags after call: 0x%llx\n", __func__, -+ cmd_name->return_flags); -+ -+ if (flags) -+ *flags = cmd_name->return_flags; -+ -+ return 0; -+} -+ -+int kdbus_name_release(struct kdbus_conn *conn, const char *name) -+{ -+ struct kdbus_cmd *cmd_name; -+ size_t name_len = strlen(name) + 1; -+ uint64_t size = sizeof(*cmd_name) + KDBUS_ITEM_SIZE(name_len); -+ struct kdbus_item *item; -+ int ret; -+ -+ cmd_name = alloca(size); -+ -+ memset(cmd_name, 0, size); -+ -+ item = cmd_name->items; -+ item->size = KDBUS_ITEM_HEADER_SIZE + name_len; -+ item->type = KDBUS_ITEM_NAME; -+ strcpy(item->str, name); -+ -+ cmd_name->size = size; -+ -+ kdbus_printf("conn %lld giving up name '%s'\n", -+ (unsigned long long) conn->id, name); -+ -+ ret = kdbus_cmd_name_release(conn->fd, cmd_name); -+ if (ret < 0) { -+ kdbus_printf("error releasing name: %s\n", strerror(-ret)); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+int kdbus_list(struct kdbus_conn *conn, uint64_t flags) -+{ -+ struct kdbus_cmd_list cmd_list = {}; -+ struct kdbus_info *list, *name; -+ int ret; -+ -+ cmd_list.size = sizeof(cmd_list); -+ cmd_list.flags = flags; -+ -+ ret = kdbus_cmd_list(conn->fd, &cmd_list); -+ if (ret < 0) { -+ kdbus_printf("error listing names: %d (%m)\n", ret); -+ return ret; -+ } -+ -+ kdbus_printf("REGISTRY:\n"); -+ list = (struct kdbus_info *)(conn->buf + cmd_list.offset); -+ -+ KDBUS_FOREACH(name, list, cmd_list.list_size) { -+ uint64_t flags = 0; -+ struct kdbus_item *item; -+ const char *n = "MISSING-NAME"; -+ -+ if (name->size == sizeof(struct kdbus_cmd)) -+ continue; -+ -+ KDBUS_ITEM_FOREACH(item, name, items) -+ if (item->type == KDBUS_ITEM_OWNED_NAME) { -+ n = item->name.name; -+ flags = item->name.flags; -+ } -+ -+ kdbus_printf("%8llu flags=0x%08llx conn=0x%08llx '%s'\n", -+ name->id, (unsigned long long) flags, -+ name->flags, n); -+ } -+ kdbus_printf("\n"); -+ -+ ret = kdbus_free(conn, cmd_list.offset); -+ -+ return ret; -+} -+ -+int kdbus_conn_update_attach_flags(struct kdbus_conn *conn, -+ uint64_t attach_flags_send, -+ uint64_t attach_flags_recv) -+{ -+ int ret; -+ size_t size; -+ struct kdbus_cmd *update; -+ struct kdbus_item *item; -+ -+ size = sizeof(struct kdbus_cmd); -+ size += KDBUS_ITEM_SIZE(sizeof(uint64_t)) * 2; -+ -+ update = malloc(size); -+ if (!update) { -+ kdbus_printf("error malloc: %m\n"); -+ return -ENOMEM; -+ } -+ -+ memset(update, 0, size); -+ update->size = size; -+ -+ item = update->items; -+ -+ item->type = KDBUS_ITEM_ATTACH_FLAGS_SEND; -+ item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(uint64_t); -+ item->data64[0] = attach_flags_send; -+ item = KDBUS_ITEM_NEXT(item); -+ -+ item->type = KDBUS_ITEM_ATTACH_FLAGS_RECV; -+ item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(uint64_t); -+ item->data64[0] = attach_flags_recv; -+ item = KDBUS_ITEM_NEXT(item); -+ -+ ret = kdbus_cmd_update(conn->fd, update); -+ if (ret < 0) -+ kdbus_printf("error conn update: %d (%m)\n", ret); -+ -+ free(update); -+ -+ return ret; -+} -+ -+int kdbus_conn_update_policy(struct kdbus_conn *conn, const char *name, -+ const struct kdbus_policy_access *access, -+ size_t num_access) -+{ -+ struct kdbus_cmd *update; -+ struct kdbus_item *item; -+ size_t i, size; -+ int ret; -+ -+ size = sizeof(struct kdbus_cmd); -+ size += KDBUS_ITEM_SIZE(strlen(name) + 1); -+ size += num_access * KDBUS_ITEM_SIZE(sizeof(struct kdbus_policy_access)); -+ -+ update = malloc(size); -+ if (!update) { -+ kdbus_printf("error malloc: %m\n"); -+ return -ENOMEM; -+ } -+ -+ memset(update, 0, size); -+ update->size = size; -+ -+ item = update->items; -+ -+ item->type = KDBUS_ITEM_NAME; -+ item->size = KDBUS_ITEM_HEADER_SIZE + strlen(name) + 1; -+ strcpy(item->str, name); -+ item = KDBUS_ITEM_NEXT(item); -+ -+ for (i = 0; i < num_access; i++) { -+ item->size = KDBUS_ITEM_HEADER_SIZE + -+ sizeof(struct kdbus_policy_access); -+ item->type = KDBUS_ITEM_POLICY_ACCESS; -+ -+ item->policy_access.type = access[i].type; -+ item->policy_access.access = access[i].access; -+ item->policy_access.id = access[i].id; -+ -+ item = KDBUS_ITEM_NEXT(item); -+ } -+ -+ ret = kdbus_cmd_update(conn->fd, update); -+ if (ret < 0) -+ kdbus_printf("error conn update: %d (%m)\n", ret); -+ -+ free(update); -+ -+ return ret; -+} -+ -+int kdbus_add_match_id(struct kdbus_conn *conn, uint64_t cookie, -+ uint64_t type, uint64_t id) -+{ -+ struct { -+ struct kdbus_cmd_match cmd; -+ struct { -+ uint64_t size; -+ uint64_t type; -+ struct kdbus_notify_id_change chg; -+ } item; -+ } buf; -+ int ret; -+ -+ memset(&buf, 0, sizeof(buf)); -+ -+ buf.cmd.size = sizeof(buf); -+ buf.cmd.cookie = cookie; -+ buf.item.size = sizeof(buf.item); -+ buf.item.type = type; -+ buf.item.chg.id = id; -+ -+ ret = kdbus_cmd_match_add(conn->fd, &buf.cmd); -+ if (ret < 0) -+ kdbus_printf("--- error adding conn match: %d (%m)\n", ret); -+ -+ return ret; -+} -+ -+int kdbus_add_match_empty(struct kdbus_conn *conn) -+{ -+ struct { -+ struct kdbus_cmd_match cmd; -+ struct kdbus_item item; -+ } buf; -+ int ret; -+ -+ memset(&buf, 0, sizeof(buf)); -+ -+ buf.item.size = sizeof(uint64_t) * 3; -+ buf.item.type = KDBUS_ITEM_ID; -+ buf.item.id = KDBUS_MATCH_ID_ANY; -+ -+ buf.cmd.size = sizeof(buf.cmd) + buf.item.size; -+ -+ ret = kdbus_cmd_match_add(conn->fd, &buf.cmd); -+ if (ret < 0) -+ kdbus_printf("--- error adding conn match: %d (%m)\n", ret); -+ -+ return ret; -+} -+ -+static int all_ids_are_mapped(const char *path) -+{ -+ int ret; -+ FILE *file; -+ uint32_t inside_id, length; -+ -+ file = fopen(path, "r"); -+ if (!file) { -+ ret = -errno; -+ kdbus_printf("error fopen() %s: %d (%m)\n", -+ path, ret); -+ return ret; -+ } -+ -+ ret = fscanf(file, "%u\t%*u\t%u", &inside_id, &length); -+ if (ret != 2) { -+ if (ferror(file)) -+ ret = -errno; -+ else -+ ret = -EIO; -+ -+ kdbus_printf("--- error fscanf(): %d\n", ret); -+ fclose(file); -+ return ret; -+ } -+ -+ fclose(file); -+ -+ /* -+ * If length is 4294967295 which means the invalid uid -+ * (uid_t) -1 then we are able to map all uid/gids -+ */ -+ if (inside_id == 0 && length == (uid_t) -1) -+ return 1; -+ -+ return 0; -+} -+ -+int all_uids_gids_are_mapped() -+{ -+ int ret; -+ -+ ret = all_ids_are_mapped("/proc/self/uid_map"); -+ if (ret <= 0) { -+ kdbus_printf("--- error not all uids are mapped\n"); -+ return 0; -+ } -+ -+ ret = all_ids_are_mapped("/proc/self/gid_map"); -+ if (ret <= 0) { -+ kdbus_printf("--- error not all gids are mapped\n"); -+ return 0; -+ } -+ -+ return 1; -+} -+ -+int drop_privileges(uid_t uid, gid_t gid) -+{ -+ int ret; -+ -+ ret = setgroups(0, NULL); -+ if (ret < 0) { -+ ret = -errno; -+ kdbus_printf("error setgroups: %d (%m)\n", ret); -+ return ret; -+ } -+ -+ ret = setresgid(gid, gid, gid); -+ if (ret < 0) { -+ ret = -errno; -+ kdbus_printf("error setresgid: %d (%m)\n", ret); -+ return ret; -+ } -+ -+ ret = setresuid(uid, uid, uid); -+ if (ret < 0) { -+ ret = -errno; -+ kdbus_printf("error setresuid: %d (%m)\n", ret); -+ return ret; -+ } -+ -+ return ret; -+} -+ -+uint64_t now(clockid_t clock) -+{ -+ struct timespec spec; -+ -+ clock_gettime(clock, &spec); -+ return spec.tv_sec * 1000ULL * 1000ULL * 1000ULL + spec.tv_nsec; -+} -+ -+char *unique_name(const char *prefix) -+{ -+ unsigned int i; -+ uint64_t u_now; -+ char n[17]; -+ char *str; -+ int r; -+ -+ /* -+ * This returns a random string which is guaranteed to be -+ * globally unique across all calls to unique_name(). We -+ * compose the string as: -+ * <prefix>-<random>-<time> -+ * With: -+ * <prefix>: string provided by the caller -+ * <random>: a random alpha string of 16 characters -+ * <time>: the current time in micro-seconds since last boot -+ * -+ * The <random> part makes the string always look vastly different, -+ * the <time> part makes sure no two calls return the same string. -+ */ -+ -+ u_now = now(CLOCK_MONOTONIC); -+ -+ for (i = 0; i < sizeof(n) - 1; ++i) -+ n[i] = 'a' + (rand() % ('z' - 'a')); -+ n[sizeof(n) - 1] = 0; -+ -+ r = asprintf(&str, "%s-%s-%" PRIu64, prefix, n, u_now); -+ if (r < 0) -+ return NULL; -+ -+ return str; -+} -+ -+static int do_userns_map_id(pid_t pid, -+ const char *map_file, -+ const char *map_id) -+{ -+ int ret; -+ int fd; -+ char *map; -+ unsigned int i; -+ -+ map = strndupa(map_id, strlen(map_id)); -+ if (!map) { -+ ret = -errno; -+ kdbus_printf("error strndupa %s: %d (%m)\n", -+ map_file, ret); -+ return ret; -+ } -+ -+ for (i = 0; i < strlen(map); i++) -+ if (map[i] == ',') -+ map[i] = '\n'; -+ -+ fd = open(map_file, O_RDWR); -+ if (fd < 0) { -+ ret = -errno; -+ kdbus_printf("error open %s: %d (%m)\n", -+ map_file, ret); -+ return ret; -+ } -+ -+ ret = write(fd, map, strlen(map)); -+ if (ret < 0) { -+ ret = -errno; -+ kdbus_printf("error write to %s: %d (%m)\n", -+ map_file, ret); -+ goto out; -+ } -+ -+ ret = 0; -+ -+out: -+ close(fd); -+ return ret; -+} -+ -+int userns_map_uid_gid(pid_t pid, -+ const char *map_uid, -+ const char *map_gid) -+{ -+ int fd, ret; -+ char file_id[128] = {'\0'}; -+ -+ snprintf(file_id, sizeof(file_id), "/proc/%ld/uid_map", -+ (long) pid); -+ -+ ret = do_userns_map_id(pid, file_id, map_uid); -+ if (ret < 0) -+ return ret; -+ -+ snprintf(file_id, sizeof(file_id), "/proc/%ld/setgroups", -+ (long) pid); -+ -+ fd = open(file_id, O_WRONLY); -+ if (fd >= 0) { -+ write(fd, "deny\n", 5); -+ close(fd); -+ } -+ -+ snprintf(file_id, sizeof(file_id), "/proc/%ld/gid_map", -+ (long) pid); -+ -+ return do_userns_map_id(pid, file_id, map_gid); -+} -+ -+static int do_cap_get_flag(cap_t caps, cap_value_t cap) -+{ -+ int ret; -+ cap_flag_value_t flag_set; -+ -+ ret = cap_get_flag(caps, cap, CAP_EFFECTIVE, &flag_set); -+ if (ret < 0) { -+ ret = -errno; -+ kdbus_printf("error cap_get_flag(): %d (%m)\n", ret); -+ return ret; -+ } -+ -+ return (flag_set == CAP_SET); -+} -+ -+/* -+ * Returns: -+ * 1 in case all the requested effective capabilities are set. -+ * 0 in case we do not have the requested capabilities. This value -+ * will be used to abort tests with TEST_SKIP -+ * Negative errno on failure. -+ * -+ * Terminate args with a negative value. -+ */ -+int test_is_capable(int cap, ...) -+{ -+ int ret; -+ va_list ap; -+ cap_t caps; -+ -+ caps = cap_get_proc(); -+ if (!cap) { -+ ret = -errno; -+ kdbus_printf("error cap_get_proc(): %d (%m)\n", ret); -+ return ret; -+ } -+ -+ ret = do_cap_get_flag(caps, (cap_value_t)cap); -+ if (ret <= 0) -+ goto out; -+ -+ va_start(ap, cap); -+ while ((cap = va_arg(ap, int)) > 0) { -+ ret = do_cap_get_flag(caps, (cap_value_t)cap); -+ if (ret <= 0) -+ break; -+ } -+ va_end(ap); -+ -+out: -+ cap_free(caps); -+ return ret; -+} -+ -+int config_user_ns_is_enabled(void) -+{ -+ return (access("/proc/self/uid_map", F_OK) == 0); -+} -+ -+int config_auditsyscall_is_enabled(void) -+{ -+ return (access("/proc/self/loginuid", F_OK) == 0); -+} -+ -+int config_cgroups_is_enabled(void) -+{ -+ return (access("/proc/self/cgroup", F_OK) == 0); -+} -+ -+int config_security_is_enabled(void) -+{ -+ int fd; -+ int ret; -+ char buf[128]; -+ -+ /* CONFIG_SECURITY is disabled */ -+ if (access("/proc/self/attr/current", F_OK) != 0) -+ return 0; -+ -+ /* -+ * Now only if read() fails with -EINVAL then we assume -+ * that SECLABEL and LSM are disabled -+ */ -+ fd = open("/proc/self/attr/current", O_RDONLY|O_CLOEXEC); -+ if (fd < 0) -+ return 1; -+ -+ ret = read(fd, buf, sizeof(buf)); -+ if (ret == -1 && errno == EINVAL) -+ ret = 0; -+ else -+ ret = 1; -+ -+ close(fd); -+ -+ return ret; -+} -diff --git a/tools/testing/selftests/kdbus/kdbus-util.h b/tools/testing/selftests/kdbus/kdbus-util.h -new file mode 100644 -index 000000000000..50ff07140bdd ---- /dev/null -+++ b/tools/testing/selftests/kdbus/kdbus-util.h -@@ -0,0 +1,222 @@ -+/* -+ * Copyright (C) 2013-2015 Kay Sievers -+ * Copyright (C) 2013-2015 Daniel Mack -+ * -+ * 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 -+ -+#define BIT(X) (1 << (X)) -+ -+#include <time.h> -+#include <stdbool.h> -+#include <linux/kdbus.h> -+ -+#define _STRINGIFY(x) #x -+#define STRINGIFY(x) _STRINGIFY(x) -+#define ELEMENTSOF(x) (sizeof(x)/sizeof((x)[0])) -+ -+#define KDBUS_PTR(addr) ((void *)(uintptr_t)(addr)) -+ -+#define KDBUS_ALIGN8(l) (((l) + 7) & ~7) -+#define KDBUS_ITEM_HEADER_SIZE offsetof(struct kdbus_item, data) -+#define KDBUS_ITEM_SIZE(s) KDBUS_ALIGN8((s) + KDBUS_ITEM_HEADER_SIZE) -+ -+#define KDBUS_ITEM_NEXT(item) \ -+ (typeof(item))(((uint8_t *)item) + KDBUS_ALIGN8((item)->size)) -+#define KDBUS_ITEM_FOREACH(item, head, first) \ -+ for (item = (head)->first; \ -+ ((uint8_t *)(item) < (uint8_t *)(head) + (head)->size) && \ -+ ((uint8_t *)(item) >= (uint8_t *)(head)); \ -+ item = KDBUS_ITEM_NEXT(item)) -+#define KDBUS_FOREACH(iter, first, _size) \ -+ for (iter = (first); \ -+ ((uint8_t *)(iter) < (uint8_t *)(first) + (_size)) && \ -+ ((uint8_t *)(iter) >= (uint8_t *)(first)); \ -+ iter = (void*)(((uint8_t *)iter) + KDBUS_ALIGN8((iter)->size))) -+ -+ -+#define _KDBUS_ATTACH_BITS_SET_NR (__builtin_popcountll(_KDBUS_ATTACH_ALL)) -+ -+/* Sum of KDBUS_ITEM_* that reflects _KDBUS_ATTACH_ALL */ -+#define KDBUS_ATTACH_ITEMS_TYPE_SUM \ -+ ((((_KDBUS_ATTACH_BITS_SET_NR - 1) * \ -+ ((_KDBUS_ATTACH_BITS_SET_NR - 1) + 1)) / 2 ) + \ -+ (_KDBUS_ITEM_ATTACH_BASE * _KDBUS_ATTACH_BITS_SET_NR)) -+ -+ -+#define POOL_SIZE (16 * 1024LU * 1024LU) -+ -+#define UNPRIV_UID 65534 -+#define UNPRIV_GID 65534 -+ -+/* Dump as user of process, useful for user namespace testing */ -+#define SUID_DUMP_USER 1 -+ -+extern int kdbus_util_verbose; -+ -+#define kdbus_printf(X...) \ -+ if (kdbus_util_verbose) \ -+ printf(X) -+ -+#define RUN_UNPRIVILEGED(child_uid, child_gid, _child_, _parent_) ({ \ -+ pid_t pid, rpid; \ -+ int ret; \ -+ \ -+ pid = fork(); \ -+ if (pid == 0) { \ -+ ret = drop_privileges(child_uid, child_gid); \ -+ ASSERT_EXIT_VAL(ret == 0, ret); \ -+ \ -+ _child_; \ -+ _exit(0); \ -+ } else if (pid > 0) { \ -+ _parent_; \ -+ rpid = waitpid(pid, &ret, 0); \ -+ ASSERT_RETURN(rpid == pid); \ -+ ASSERT_RETURN(WIFEXITED(ret)); \ -+ ASSERT_RETURN(WEXITSTATUS(ret) == 0); \ -+ ret = TEST_OK; \ -+ } else { \ -+ ret = pid; \ -+ } \ -+ \ -+ ret; \ -+ }) -+ -+#define RUN_UNPRIVILEGED_CONN(_var_, _bus_, _code_) \ -+ RUN_UNPRIVILEGED(UNPRIV_UID, UNPRIV_GID, ({ \ -+ struct kdbus_conn *_var_; \ -+ _var_ = kdbus_hello(_bus_, 0, NULL, 0); \ -+ ASSERT_EXIT(_var_); \ -+ _code_; \ -+ kdbus_conn_free(_var_); \ -+ }), ({ 0; })) -+ -+#define RUN_CLONE_CHILD(clone_ret, flags, _setup_, _child_body_, \ -+ _parent_setup_, _parent_body_) ({ \ -+ pid_t pid, rpid; \ -+ int ret; \ -+ int efd = -1; \ -+ \ -+ _setup_; \ -+ efd = eventfd(0, EFD_CLOEXEC); \ -+ ASSERT_RETURN(efd >= 0); \ -+ *clone_ret = 0; \ -+ pid = syscall(__NR_clone, flags, NULL); \ -+ if (pid == 0) { \ -+ eventfd_t event_status = 0; \ -+ ret = prctl(PR_SET_PDEATHSIG, SIGKILL); \ -+ ASSERT_EXIT(ret == 0); \ -+ ret = eventfd_read(efd, &event_status); \ -+ if (ret < 0 || event_status != 1) { \ -+ kdbus_printf("error eventfd_read()\n"); \ -+ _exit(EXIT_FAILURE); \ -+ } \ -+ _child_body_; \ -+ _exit(0); \ -+ } else if (pid > 0) { \ -+ _parent_setup_; \ -+ ret = eventfd_write(efd, 1); \ -+ ASSERT_RETURN(ret >= 0); \ -+ _parent_body_; \ -+ rpid = waitpid(pid, &ret, 0); \ -+ ASSERT_RETURN(rpid == pid); \ -+ ASSERT_RETURN(WIFEXITED(ret)); \ -+ ASSERT_RETURN(WEXITSTATUS(ret) == 0); \ -+ ret = TEST_OK; \ -+ } else { \ -+ ret = -errno; \ -+ *clone_ret = -errno; \ -+ } \ -+ close(efd); \ -+ ret; \ -+}) -+ -+/* Enums for parent if it should drop privs or not */ -+enum kdbus_drop_parent { -+ DO_NOT_DROP, -+ DROP_SAME_UNPRIV, -+ DROP_OTHER_UNPRIV, -+}; -+ -+struct kdbus_conn { -+ int fd; -+ uint64_t id; -+ unsigned char *buf; -+}; -+ -+int kdbus_sysfs_get_parameter_mask(const char *path, uint64_t *mask); -+int kdbus_sysfs_set_parameter_mask(const char *path, uint64_t mask); -+ -+int sys_memfd_create(const char *name, __u64 size); -+int sys_memfd_seal_set(int fd); -+off_t sys_memfd_get_size(int fd, off_t *size); -+ -+int kdbus_list(struct kdbus_conn *conn, uint64_t flags); -+int kdbus_name_release(struct kdbus_conn *conn, const char *name); -+int kdbus_name_acquire(struct kdbus_conn *conn, const char *name, -+ uint64_t *flags); -+void kdbus_msg_free(struct kdbus_msg *msg); -+int kdbus_msg_recv(struct kdbus_conn *conn, -+ struct kdbus_msg **msg, uint64_t *offset); -+int kdbus_msg_recv_poll(struct kdbus_conn *conn, int timeout_ms, -+ struct kdbus_msg **msg_out, uint64_t *offset); -+int kdbus_free(const struct kdbus_conn *conn, uint64_t offset); -+int kdbus_msg_dump(const struct kdbus_conn *conn, -+ const struct kdbus_msg *msg); -+int kdbus_create_bus(int control_fd, const char *name, -+ uint64_t req_meta, uint64_t owner_meta, -+ char **path); -+int kdbus_msg_send(const struct kdbus_conn *conn, const char *name, -+ uint64_t cookie, uint64_t flags, uint64_t timeout, -+ int64_t priority, uint64_t dst_id); -+int kdbus_msg_send_sync(const struct kdbus_conn *conn, const char *name, -+ uint64_t cookie, uint64_t flags, uint64_t timeout, -+ int64_t priority, uint64_t dst_id, int cancel_fd); -+int kdbus_msg_send_reply(const struct kdbus_conn *conn, -+ uint64_t reply_cookie, -+ uint64_t dst_id); -+struct kdbus_conn *kdbus_hello(const char *path, uint64_t hello_flags, -+ const struct kdbus_item *item, -+ size_t item_size); -+struct kdbus_conn *kdbus_hello_registrar(const char *path, const char *name, -+ const struct kdbus_policy_access *access, -+ size_t num_access, uint64_t flags); -+struct kdbus_conn *kdbus_hello_activator(const char *path, const char *name, -+ const struct kdbus_policy_access *access, -+ size_t num_access); -+bool kdbus_item_in_message(struct kdbus_msg *msg, uint64_t type); -+int kdbus_bus_creator_info(struct kdbus_conn *conn, -+ uint64_t flags, -+ uint64_t *offset); -+int kdbus_conn_info(struct kdbus_conn *conn, uint64_t id, -+ const char *name, uint64_t flags, uint64_t *offset); -+void kdbus_conn_free(struct kdbus_conn *conn); -+int kdbus_conn_update_attach_flags(struct kdbus_conn *conn, -+ uint64_t attach_flags_send, -+ uint64_t attach_flags_recv); -+int kdbus_conn_update_policy(struct kdbus_conn *conn, const char *name, -+ const struct kdbus_policy_access *access, -+ size_t num_access); -+ -+int kdbus_add_match_id(struct kdbus_conn *conn, uint64_t cookie, -+ uint64_t type, uint64_t id); -+int kdbus_add_match_empty(struct kdbus_conn *conn); -+ -+int all_uids_gids_are_mapped(); -+int drop_privileges(uid_t uid, gid_t gid); -+uint64_t now(clockid_t clock); -+char *unique_name(const char *prefix); -+ -+int userns_map_uid_gid(pid_t pid, -+ const char *map_uid, -+ const char *map_gid); -+int test_is_capable(int cap, ...); -+int config_user_ns_is_enabled(void); -+int config_auditsyscall_is_enabled(void); -+int config_cgroups_is_enabled(void); -+int config_security_is_enabled(void); -diff --git a/tools/testing/selftests/kdbus/test-activator.c b/tools/testing/selftests/kdbus/test-activator.c -new file mode 100644 -index 000000000000..3d1b76370ce8 ---- /dev/null -+++ b/tools/testing/selftests/kdbus/test-activator.c -@@ -0,0 +1,318 @@ -+#include <stdio.h> -+#include <string.h> -+#include <time.h> -+#include <fcntl.h> -+#include <stdlib.h> -+#include <stdbool.h> -+#include <stddef.h> -+#include <unistd.h> -+#include <stdint.h> -+#include <errno.h> -+#include <assert.h> -+#include <poll.h> -+#include <sys/capability.h> -+#include <sys/types.h> -+#include <sys/wait.h> -+ -+#include "kdbus-test.h" -+#include "kdbus-util.h" -+#include "kdbus-enum.h" -+ -+static int kdbus_starter_poll(struct kdbus_conn *conn) -+{ -+ int ret; -+ struct pollfd fd; -+ -+ fd.fd = conn->fd; -+ fd.events = POLLIN | POLLPRI | POLLHUP; -+ fd.revents = 0; -+ -+ ret = poll(&fd, 1, 100); -+ if (ret == 0) -+ return -ETIMEDOUT; -+ else if (ret > 0) { -+ if (fd.revents & POLLIN) -+ return 0; -+ -+ if (fd.revents & (POLLHUP | POLLERR)) -+ ret = -ECONNRESET; -+ } -+ -+ return ret; -+} -+ -+/* Ensure that kdbus activator logic is safe */ -+static int kdbus_priv_activator(struct kdbus_test_env *env) -+{ -+ int ret; -+ struct kdbus_msg *msg = NULL; -+ uint64_t cookie = 0xdeadbeef; -+ uint64_t flags = KDBUS_NAME_REPLACE_EXISTING; -+ struct kdbus_conn *activator; -+ struct kdbus_conn *service; -+ struct kdbus_conn *client; -+ struct kdbus_conn *holder; -+ struct kdbus_policy_access *access; -+ -+ access = (struct kdbus_policy_access[]){ -+ { -+ .type = KDBUS_POLICY_ACCESS_USER, -+ .id = getuid(), -+ .access = KDBUS_POLICY_OWN, -+ }, -+ { -+ .type = KDBUS_POLICY_ACCESS_USER, -+ .id = getuid(), -+ .access = KDBUS_POLICY_TALK, -+ }, -+ }; -+ -+ activator = kdbus_hello_activator(env->buspath, "foo.priv.activator", -+ access, 2); -+ ASSERT_RETURN(activator); -+ -+ service = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(service); -+ -+ client = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(client); -+ -+ /* -+ * Make sure that other users can't TALK to the activator -+ */ -+ -+ ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ -+ /* Try to talk using the ID */ -+ ret = kdbus_msg_send(unpriv, NULL, 0xdeadbeef, 0, 0, -+ 0, activator->id); -+ ASSERT_EXIT(ret == -ENXIO); -+ -+ /* Try to talk to the name */ -+ ret = kdbus_msg_send(unpriv, "foo.priv.activator", -+ 0xdeadbeef, 0, 0, 0, -+ KDBUS_DST_ID_NAME); -+ ASSERT_EXIT(ret == -EPERM); -+ })); -+ ASSERT_RETURN(ret >= 0); -+ -+ /* -+ * Make sure that we did not receive anything, so the -+ * service will not be started automatically -+ */ -+ -+ ret = kdbus_starter_poll(activator); -+ ASSERT_RETURN(ret == -ETIMEDOUT); -+ -+ /* -+ * Now try to emulate the starter/service logic and -+ * acquire the name. -+ */ -+ -+ cookie++; -+ ret = kdbus_msg_send(service, "foo.priv.activator", cookie, -+ 0, 0, 0, KDBUS_DST_ID_NAME); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_starter_poll(activator); -+ ASSERT_RETURN(ret == 0); -+ -+ /* Policies are still checked, access denied */ -+ -+ ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ -+ ret = kdbus_name_acquire(unpriv, "foo.priv.activator", -+ &flags); -+ ASSERT_RETURN(ret == -EPERM); -+ })); -+ ASSERT_RETURN(ret >= 0); -+ -+ ret = kdbus_name_acquire(service, "foo.priv.activator", -+ &flags); -+ ASSERT_RETURN(ret == 0); -+ -+ /* We read our previous starter message */ -+ -+ ret = kdbus_msg_recv_poll(service, 100, NULL, NULL); -+ ASSERT_RETURN(ret == 0); -+ -+ /* Try to talk, we still fail */ -+ -+ cookie++; -+ ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ -+ /* Try to talk to the name */ -+ ret = kdbus_msg_send(unpriv, "foo.priv.activator", -+ cookie, 0, 0, 0, -+ KDBUS_DST_ID_NAME); -+ ASSERT_EXIT(ret == -EPERM); -+ })); -+ ASSERT_RETURN(ret >= 0); -+ -+ /* Still nothing to read */ -+ -+ ret = kdbus_msg_recv_poll(service, 100, NULL, NULL); -+ ASSERT_RETURN(ret == -ETIMEDOUT); -+ -+ /* We receive every thing now */ -+ -+ cookie++; -+ ret = kdbus_msg_send(client, "foo.priv.activator", cookie, -+ 0, 0, 0, KDBUS_DST_ID_NAME); -+ ASSERT_RETURN(ret == 0); -+ ret = kdbus_msg_recv_poll(service, 100, &msg, NULL); -+ ASSERT_RETURN(ret == 0 && msg->cookie == cookie); -+ -+ kdbus_msg_free(msg); -+ -+ /* Policies default to deny TALK now */ -+ kdbus_conn_free(activator); -+ -+ cookie++; -+ ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ -+ /* Try to talk to the name */ -+ ret = kdbus_msg_send(unpriv, "foo.priv.activator", -+ cookie, 0, 0, 0, -+ KDBUS_DST_ID_NAME); -+ ASSERT_EXIT(ret == -EPERM); -+ })); -+ ASSERT_RETURN(ret >= 0); -+ -+ ret = kdbus_msg_recv_poll(service, 100, NULL, NULL); -+ ASSERT_RETURN(ret == -ETIMEDOUT); -+ -+ /* Same user is able to TALK */ -+ cookie++; -+ ret = kdbus_msg_send(client, "foo.priv.activator", cookie, -+ 0, 0, 0, KDBUS_DST_ID_NAME); -+ ASSERT_RETURN(ret == 0); -+ ret = kdbus_msg_recv_poll(service, 100, &msg, NULL); -+ ASSERT_RETURN(ret == 0 && msg->cookie == cookie); -+ -+ kdbus_msg_free(msg); -+ -+ access = (struct kdbus_policy_access []){ -+ { -+ .type = KDBUS_POLICY_ACCESS_WORLD, -+ .id = getuid(), -+ .access = KDBUS_POLICY_TALK, -+ }, -+ }; -+ -+ holder = kdbus_hello_registrar(env->buspath, "foo.priv.activator", -+ access, 1, KDBUS_HELLO_POLICY_HOLDER); -+ ASSERT_RETURN(holder); -+ -+ /* Now we are able to TALK to the name */ -+ -+ cookie++; -+ ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ -+ /* Try to talk to the name */ -+ ret = kdbus_msg_send(unpriv, "foo.priv.activator", -+ cookie, 0, 0, 0, -+ KDBUS_DST_ID_NAME); -+ ASSERT_EXIT(ret == 0); -+ })); -+ ASSERT_RETURN(ret >= 0); -+ -+ ret = kdbus_msg_recv_poll(service, 100, NULL, NULL); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ -+ ret = kdbus_name_acquire(unpriv, "foo.priv.activator", -+ &flags); -+ ASSERT_RETURN(ret == -EPERM); -+ })); -+ ASSERT_RETURN(ret >= 0); -+ -+ kdbus_conn_free(service); -+ kdbus_conn_free(client); -+ kdbus_conn_free(holder); -+ -+ return 0; -+} -+ -+int kdbus_test_activator(struct kdbus_test_env *env) -+{ -+ int ret; -+ struct kdbus_conn *activator; -+ struct pollfd fds[2]; -+ bool activator_done = false; -+ struct kdbus_policy_access access[2]; -+ -+ access[0].type = KDBUS_POLICY_ACCESS_USER; -+ access[0].id = getuid(); -+ access[0].access = KDBUS_POLICY_OWN; -+ -+ access[1].type = KDBUS_POLICY_ACCESS_WORLD; -+ access[1].access = KDBUS_POLICY_TALK; -+ -+ activator = kdbus_hello_activator(env->buspath, "foo.test.activator", -+ access, 2); -+ ASSERT_RETURN(activator); -+ -+ ret = kdbus_add_match_empty(env->conn); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_list(env->conn, KDBUS_LIST_NAMES | -+ KDBUS_LIST_UNIQUE | -+ KDBUS_LIST_ACTIVATORS | -+ KDBUS_LIST_QUEUED); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_msg_send(env->conn, "foo.test.activator", 0xdeafbeef, -+ 0, 0, 0, KDBUS_DST_ID_NAME); -+ ASSERT_RETURN(ret == 0); -+ -+ fds[0].fd = activator->fd; -+ fds[1].fd = env->conn->fd; -+ -+ kdbus_printf("-- entering poll loop ...\n"); -+ -+ for (;;) { -+ int i, nfds = sizeof(fds) / sizeof(fds[0]); -+ -+ for (i = 0; i < nfds; i++) { -+ fds[i].events = POLLIN | POLLPRI; -+ fds[i].revents = 0; -+ } -+ -+ ret = poll(fds, nfds, 3000); -+ ASSERT_RETURN(ret >= 0); -+ -+ ret = kdbus_list(env->conn, KDBUS_LIST_NAMES); -+ ASSERT_RETURN(ret == 0); -+ -+ if ((fds[0].revents & POLLIN) && !activator_done) { -+ uint64_t flags = KDBUS_NAME_REPLACE_EXISTING; -+ -+ kdbus_printf("Starter was called back!\n"); -+ -+ ret = kdbus_name_acquire(env->conn, -+ "foo.test.activator", &flags); -+ ASSERT_RETURN(ret == 0); -+ -+ activator_done = true; -+ } -+ -+ if (fds[1].revents & POLLIN) { -+ kdbus_msg_recv(env->conn, NULL, NULL); -+ break; -+ } -+ } -+ -+ /* Check if all uids/gids are mapped */ -+ if (!all_uids_gids_are_mapped()) -+ return TEST_SKIP; -+ -+ /* Check now capabilities, so we run the previous tests */ -+ ret = test_is_capable(CAP_SETUID, CAP_SETGID, -1); -+ ASSERT_RETURN(ret >= 0); -+ -+ if (!ret) -+ return TEST_SKIP; -+ -+ ret = kdbus_priv_activator(env); -+ ASSERT_RETURN(ret == 0); -+ -+ kdbus_conn_free(activator); -+ -+ return TEST_OK; -+} -diff --git a/tools/testing/selftests/kdbus/test-attach-flags.c b/tools/testing/selftests/kdbus/test-attach-flags.c -new file mode 100644 -index 000000000000..deee7c332f25 ---- /dev/null -+++ b/tools/testing/selftests/kdbus/test-attach-flags.c -@@ -0,0 +1,750 @@ -+#include <stdio.h> -+#include <string.h> -+#include <stdlib.h> -+#include <stdbool.h> -+#include <stddef.h> -+#include <fcntl.h> -+#include <unistd.h> -+#include <stdint.h> -+#include <errno.h> -+#include <assert.h> -+#include <sys/capability.h> -+#include <sys/mman.h> -+#include <sys/stat.h> -+#include <sys/types.h> -+#include <linux/unistd.h> -+ -+#include "kdbus-api.h" -+#include "kdbus-test.h" -+#include "kdbus-util.h" -+#include "kdbus-enum.h" -+ -+/* -+ * Should be the sum of the currently supported and compiled-in -+ * KDBUS_ITEMS_* that reflect KDBUS_ATTACH_* flags. -+ */ -+static unsigned int KDBUS_TEST_ITEMS_SUM = KDBUS_ATTACH_ITEMS_TYPE_SUM; -+ -+static struct kdbus_conn *__kdbus_hello(const char *path, uint64_t flags, -+ uint64_t attach_flags_send, -+ uint64_t attach_flags_recv) -+{ -+ struct kdbus_cmd_free cmd_free = {}; -+ int ret, fd; -+ struct kdbus_conn *conn; -+ struct { -+ struct kdbus_cmd_hello hello; -+ -+ struct { -+ uint64_t size; -+ uint64_t type; -+ char str[16]; -+ } conn_name; -+ -+ uint8_t extra_items[0]; -+ } h; -+ -+ memset(&h, 0, sizeof(h)); -+ -+ kdbus_printf("-- opening bus connection %s\n", path); -+ fd = open(path, O_RDWR|O_CLOEXEC); -+ if (fd < 0) { -+ kdbus_printf("--- error %d (%m)\n", fd); -+ return NULL; -+ } -+ -+ h.hello.flags = flags | KDBUS_HELLO_ACCEPT_FD; -+ h.hello.attach_flags_send = attach_flags_send; -+ h.hello.attach_flags_recv = attach_flags_recv; -+ h.conn_name.type = KDBUS_ITEM_CONN_DESCRIPTION; -+ strcpy(h.conn_name.str, "this-is-my-name"); -+ h.conn_name.size = KDBUS_ITEM_HEADER_SIZE + strlen(h.conn_name.str) + 1; -+ -+ h.hello.size = sizeof(h); -+ h.hello.pool_size = POOL_SIZE; -+ -+ ret = kdbus_cmd_hello(fd, (struct kdbus_cmd_hello *) &h.hello); -+ if (ret < 0) { -+ kdbus_printf("--- error when saying hello: %d (%m)\n", ret); -+ return NULL; -+ } -+ -+ kdbus_printf("-- New connection ID : %llu\n", -+ (unsigned long long)h.hello.id); -+ -+ cmd_free.size = sizeof(cmd_free); -+ cmd_free.offset = h.hello.offset; -+ ret = kdbus_cmd_free(fd, &cmd_free); -+ if (ret < 0) -+ return NULL; -+ -+ conn = malloc(sizeof(*conn)); -+ if (!conn) { -+ kdbus_printf("unable to malloc()!?\n"); -+ return NULL; -+ } -+ -+ conn->buf = mmap(NULL, POOL_SIZE, PROT_READ, MAP_SHARED, fd, 0); -+ if (conn->buf == MAP_FAILED) { -+ ret = -errno; -+ free(conn); -+ close(fd); -+ kdbus_printf("--- error mmap: %d (%m)\n", ret); -+ return NULL; -+ } -+ -+ conn->fd = fd; -+ conn->id = h.hello.id; -+ return conn; -+} -+ -+static int kdbus_test_peers_creation(struct kdbus_test_env *env) -+{ -+ int ret; -+ int control_fd; -+ char *path; -+ char *busname; -+ char buspath[2048]; -+ char control_path[2048]; -+ uint64_t attach_flags_mask; -+ struct kdbus_conn *conn; -+ -+ snprintf(control_path, sizeof(control_path), -+ "%s/control", env->root); -+ -+ /* -+ * Set kdbus system-wide mask to 0, this has nothing -+ * to do with the following tests, bus and connection -+ * creation nor connection update, but we do it so we are -+ * sure that everything work as expected -+ */ -+ -+ attach_flags_mask = 0; -+ ret = kdbus_sysfs_set_parameter_mask(env->mask_param_path, -+ attach_flags_mask); -+ ASSERT_RETURN(ret == 0); -+ -+ -+ /* -+ * Create bus with a full set of ATTACH flags -+ */ -+ -+ control_fd = open(control_path, O_RDWR); -+ ASSERT_RETURN(control_fd >= 0); -+ -+ busname = unique_name("test-peers-creation-bus"); -+ ASSERT_RETURN(busname); -+ -+ ret = kdbus_create_bus(control_fd, busname, _KDBUS_ATTACH_ALL, -+ 0, &path); -+ ASSERT_RETURN(ret == 0); -+ -+ snprintf(buspath, sizeof(buspath), "%s/%s/bus", env->root, path); -+ -+ /* -+ * Create a connection with an empty send attach flags, or -+ * with just KDBUS_ATTACH_CREDS, this should fail -+ */ -+ conn = __kdbus_hello(buspath, 0, 0, 0); -+ ASSERT_RETURN(conn == NULL); -+ ASSERT_RETURN(errno == ECONNREFUSED); -+ -+ conn = __kdbus_hello(buspath, 0, KDBUS_ATTACH_CREDS, -+ _KDBUS_ATTACH_ALL); -+ ASSERT_RETURN(conn == NULL); -+ ASSERT_RETURN(errno == ECONNREFUSED); -+ -+ conn = __kdbus_hello(buspath, 0, _KDBUS_ATTACH_ALL, 0); -+ ASSERT_RETURN(conn); -+ -+ /* Try to cut back some send attach flags */ -+ ret = kdbus_conn_update_attach_flags(conn, -+ KDBUS_ATTACH_CREDS| -+ KDBUS_ATTACH_PIDS, -+ _KDBUS_ATTACH_ALL); -+ ASSERT_RETURN(ret == -EINVAL); -+ -+ ret = kdbus_conn_update_attach_flags(conn, -+ _KDBUS_ATTACH_ALL, 0); -+ ASSERT_RETURN(ret == 0); -+ -+ kdbus_conn_free(conn); -+ free(path); -+ free(busname); -+ close(control_fd); -+ -+ -+ /* Test a new bus with KDBUS_ATTACH_PIDS */ -+ -+ control_fd = open(control_path, O_RDWR); -+ ASSERT_RETURN(control_fd >= 0); -+ -+ busname = unique_name("test-peer-flags-bus"); -+ ASSERT_RETURN(busname); -+ -+ ret = kdbus_create_bus(control_fd, busname, KDBUS_ATTACH_PIDS, -+ 0, &path); -+ ASSERT_RETURN(ret == 0); -+ -+ snprintf(buspath, sizeof(buspath), "%s/%s/bus", env->root, path); -+ -+ /* -+ * Create a connection with an empty send attach flags, or -+ * all flags except KDBUS_ATTACH_PIDS -+ */ -+ conn = __kdbus_hello(buspath, 0, 0, 0); -+ ASSERT_RETURN(conn == NULL); -+ ASSERT_RETURN(errno == ECONNREFUSED); -+ -+ conn = __kdbus_hello(buspath, 0, -+ _KDBUS_ATTACH_ALL & ~KDBUS_ATTACH_PIDS, -+ _KDBUS_ATTACH_ALL); -+ ASSERT_RETURN(conn == NULL); -+ ASSERT_RETURN(errno == ECONNREFUSED); -+ -+ /* The following should succeed */ -+ conn = __kdbus_hello(buspath, 0, KDBUS_ATTACH_PIDS, 0); -+ ASSERT_RETURN(conn); -+ kdbus_conn_free(conn); -+ -+ conn = __kdbus_hello(buspath, 0, _KDBUS_ATTACH_ALL, 0); -+ ASSERT_RETURN(conn); -+ -+ ret = kdbus_conn_update_attach_flags(conn, -+ _KDBUS_ATTACH_ALL & -+ ~KDBUS_ATTACH_PIDS, -+ _KDBUS_ATTACH_ALL); -+ ASSERT_RETURN(ret == -EINVAL); -+ -+ ret = kdbus_conn_update_attach_flags(conn, 0, -+ _KDBUS_ATTACH_ALL); -+ ASSERT_RETURN(ret == -EINVAL); -+ -+ /* Now we want only KDBUS_ATTACH_PIDS */ -+ ret = kdbus_conn_update_attach_flags(conn, -+ KDBUS_ATTACH_PIDS, 0); -+ ASSERT_RETURN(ret == 0); -+ -+ kdbus_conn_free(conn); -+ free(path); -+ free(busname); -+ close(control_fd); -+ -+ -+ /* -+ * Create bus with 0 as ATTACH flags, the bus does not -+ * require any attach flags -+ */ -+ -+ control_fd = open(control_path, O_RDWR); -+ ASSERT_RETURN(control_fd >= 0); -+ -+ busname = unique_name("test-peer-flags-bus"); -+ ASSERT_RETURN(busname); -+ -+ ret = kdbus_create_bus(control_fd, busname, 0, 0, &path); -+ ASSERT_RETURN(ret == 0); -+ -+ snprintf(buspath, sizeof(buspath), "%s/%s/bus", env->root, path); -+ -+ /* Bus is open it does not require any send attach flags */ -+ conn = __kdbus_hello(buspath, 0, 0, 0); -+ ASSERT_RETURN(conn); -+ kdbus_conn_free(conn); -+ -+ conn = __kdbus_hello(buspath, 0, _KDBUS_ATTACH_ALL, 0); -+ ASSERT_RETURN(conn); -+ -+ ret = kdbus_conn_update_attach_flags(conn, 0, 0); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_conn_update_attach_flags(conn, KDBUS_ATTACH_CREDS, 0); -+ ASSERT_RETURN(ret == 0); -+ -+ kdbus_conn_free(conn); -+ free(path); -+ free(busname); -+ close(control_fd); -+ -+ return 0; -+} -+ -+static int kdbus_test_peers_info(struct kdbus_test_env *env) -+{ -+ int ret; -+ int control_fd; -+ char *path; -+ char *busname; -+ unsigned int i = 0; -+ uint64_t offset = 0; -+ char buspath[2048]; -+ char control_path[2048]; -+ uint64_t attach_flags_mask; -+ struct kdbus_item *item; -+ struct kdbus_info *info; -+ struct kdbus_conn *conn; -+ struct kdbus_conn *reader; -+ unsigned long long attach_count = 0; -+ -+ snprintf(control_path, sizeof(control_path), -+ "%s/control", env->root); -+ -+ attach_flags_mask = 0; -+ ret = kdbus_sysfs_set_parameter_mask(env->mask_param_path, -+ attach_flags_mask); -+ ASSERT_RETURN(ret == 0); -+ -+ control_fd = open(control_path, O_RDWR); -+ ASSERT_RETURN(control_fd >= 0); -+ -+ busname = unique_name("test-peers-info-bus"); -+ ASSERT_RETURN(busname); -+ -+ ret = kdbus_create_bus(control_fd, busname, _KDBUS_ATTACH_ALL, -+ 0, &path); -+ ASSERT_RETURN(ret == 0); -+ -+ snprintf(buspath, sizeof(buspath), "%s/%s/bus", env->root, path); -+ -+ /* Create connections with the appropriate flags */ -+ conn = __kdbus_hello(buspath, 0, _KDBUS_ATTACH_ALL, 0); -+ ASSERT_RETURN(conn); -+ -+ reader = __kdbus_hello(buspath, 0, _KDBUS_ATTACH_ALL, 0); -+ ASSERT_RETURN(reader); -+ -+ ret = kdbus_conn_info(reader, conn->id, NULL, -+ _KDBUS_ATTACH_ALL, &offset); -+ ASSERT_RETURN(ret == 0); -+ -+ info = (struct kdbus_info *)(reader->buf + offset); -+ ASSERT_RETURN(info->id == conn->id); -+ -+ /* all attach flags are masked, no metadata */ -+ KDBUS_ITEM_FOREACH(item, info, items) -+ i++; -+ -+ ASSERT_RETURN(i == 0); -+ -+ kdbus_free(reader, offset); -+ -+ /* Set the mask to _KDBUS_ATTACH_ANY */ -+ attach_flags_mask = _KDBUS_ATTACH_ANY; -+ ret = kdbus_sysfs_set_parameter_mask(env->mask_param_path, -+ attach_flags_mask); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_conn_info(reader, conn->id, NULL, -+ _KDBUS_ATTACH_ALL, &offset); -+ ASSERT_RETURN(ret == 0); -+ -+ info = (struct kdbus_info *)(reader->buf + offset); -+ ASSERT_RETURN(info->id == conn->id); -+ -+ attach_count = 0; -+ KDBUS_ITEM_FOREACH(item, info, items) -+ attach_count += item->type; -+ -+ /* -+ * All flags have been returned except for: -+ * KDBUS_ITEM_TIMESTAMP and -+ * KDBUS_ITEM_OWNED_NAME we do not own any name. -+ */ -+ ASSERT_RETURN(attach_count == (KDBUS_TEST_ITEMS_SUM - -+ KDBUS_ITEM_OWNED_NAME - -+ KDBUS_ITEM_TIMESTAMP)); -+ -+ kdbus_free(reader, offset); -+ -+ /* Request only OWNED names */ -+ ret = kdbus_conn_info(reader, conn->id, NULL, -+ KDBUS_ATTACH_NAMES, &offset); -+ ASSERT_RETURN(ret == 0); -+ -+ info = (struct kdbus_info *)(reader->buf + offset); -+ ASSERT_RETURN(info->id == conn->id); -+ -+ attach_count = 0; -+ KDBUS_ITEM_FOREACH(item, info, items) -+ attach_count += item->type; -+ -+ /* we should not get any metadata since we do not own names */ -+ ASSERT_RETURN(attach_count == 0); -+ -+ kdbus_free(reader, offset); -+ -+ kdbus_conn_free(conn); -+ kdbus_conn_free(reader); -+ -+ return 0; -+} -+ -+/** -+ * @kdbus_mask_param: kdbus module mask parameter (system-wide) -+ * @requested_meta: The bus owner metadata that we want -+ * @expected_items: The returned KDBUS_ITEMS_* sum. Used to -+ * validate the returned metadata items -+ */ -+static int kdbus_cmp_bus_creator_metadata(struct kdbus_test_env *env, -+ struct kdbus_conn *conn, -+ uint64_t kdbus_mask_param, -+ uint64_t requested_meta, -+ unsigned long expected_items) -+{ -+ int ret; -+ uint64_t offset = 0; -+ struct kdbus_info *info; -+ struct kdbus_item *item; -+ unsigned long attach_count = 0; -+ -+ ret = kdbus_sysfs_set_parameter_mask(env->mask_param_path, -+ kdbus_mask_param); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_bus_creator_info(conn, requested_meta, &offset); -+ ASSERT_RETURN(ret == 0); -+ -+ info = (struct kdbus_info *)(conn->buf + offset); -+ -+ KDBUS_ITEM_FOREACH(item, info, items) -+ attach_count += item->type; -+ -+ ASSERT_RETURN(attach_count == expected_items); -+ -+ ret = kdbus_free(conn, offset); -+ ASSERT_RETURN(ret == 0); -+ -+ return 0; -+} -+ -+static int kdbus_test_bus_creator_info(struct kdbus_test_env *env) -+{ -+ int ret; -+ int control_fd; -+ char *path; -+ char *busname; -+ char buspath[2048]; -+ char control_path[2048]; -+ uint64_t attach_flags_mask; -+ struct kdbus_conn *conn; -+ unsigned long expected_items = 0; -+ -+ snprintf(control_path, sizeof(control_path), -+ "%s/control", env->root); -+ -+ control_fd = open(control_path, O_RDWR); -+ ASSERT_RETURN(control_fd >= 0); -+ -+ busname = unique_name("test-peers-info-bus"); -+ ASSERT_RETURN(busname); -+ -+ /* -+ * Now the bus allows us to see all its KDBUS_ATTACH_* -+ * items -+ */ -+ ret = kdbus_create_bus(control_fd, busname, 0, -+ _KDBUS_ATTACH_ALL, &path); -+ ASSERT_RETURN(ret == 0); -+ -+ snprintf(buspath, sizeof(buspath), "%s/%s/bus", env->root, path); -+ -+ conn = __kdbus_hello(buspath, 0, 0, 0); -+ ASSERT_RETURN(conn); -+ -+ /* -+ * Start with a kdbus module mask set to _KDBUS_ATTACH_ANY -+ */ -+ attach_flags_mask = _KDBUS_ATTACH_ANY; -+ -+ /* -+ * All flags will be returned except for: -+ * KDBUS_ITEM_TIMESTAMP -+ * KDBUS_ITEM_OWNED_NAME -+ * KDBUS_ITEM_CONN_DESCRIPTION -+ * -+ * An extra flags is always returned KDBUS_ITEM_MAKE_NAME -+ * which contains the bus name -+ */ -+ expected_items = KDBUS_TEST_ITEMS_SUM + KDBUS_ITEM_MAKE_NAME; -+ expected_items -= KDBUS_ITEM_TIMESTAMP + -+ KDBUS_ITEM_OWNED_NAME + -+ KDBUS_ITEM_CONN_DESCRIPTION; -+ ret = kdbus_cmp_bus_creator_metadata(env, conn, -+ attach_flags_mask, -+ _KDBUS_ATTACH_ALL, -+ expected_items); -+ ASSERT_RETURN(ret == 0); -+ -+ /* -+ * We should have: -+ * KDBUS_ITEM_PIDS + KDBUS_ITEM_CREDS + KDBUS_ITEM_MAKE_NAME -+ */ -+ expected_items = KDBUS_ITEM_PIDS + KDBUS_ITEM_CREDS + -+ KDBUS_ITEM_MAKE_NAME; -+ ret = kdbus_cmp_bus_creator_metadata(env, conn, -+ attach_flags_mask, -+ KDBUS_ATTACH_PIDS | -+ KDBUS_ATTACH_CREDS, -+ expected_items); -+ ASSERT_RETURN(ret == 0); -+ -+ /* KDBUS_ITEM_MAKE_NAME is always returned */ -+ expected_items = KDBUS_ITEM_MAKE_NAME; -+ ret = kdbus_cmp_bus_creator_metadata(env, conn, -+ attach_flags_mask, -+ 0, expected_items); -+ ASSERT_RETURN(ret == 0); -+ -+ /* -+ * Restrict kdbus system-wide mask to KDBUS_ATTACH_PIDS -+ */ -+ -+ attach_flags_mask = KDBUS_ATTACH_PIDS; -+ -+ /* -+ * We should have: -+ * KDBUS_ITEM_PIDS + KDBUS_ITEM_MAKE_NAME -+ */ -+ expected_items = KDBUS_ITEM_PIDS + KDBUS_ITEM_MAKE_NAME; -+ ret = kdbus_cmp_bus_creator_metadata(env, conn, -+ attach_flags_mask, -+ _KDBUS_ATTACH_ALL, -+ expected_items); -+ ASSERT_RETURN(ret == 0); -+ -+ -+ /* system-wide mask to 0 */ -+ attach_flags_mask = 0; -+ -+ /* we should only see: KDBUS_ITEM_MAKE_NAME */ -+ expected_items = KDBUS_ITEM_MAKE_NAME; -+ ret = kdbus_cmp_bus_creator_metadata(env, conn, -+ attach_flags_mask, -+ _KDBUS_ATTACH_ALL, -+ expected_items); -+ ASSERT_RETURN(ret == 0); -+ -+ kdbus_conn_free(conn); -+ free(path); -+ free(busname); -+ close(control_fd); -+ -+ -+ /* -+ * A new bus that hides all its owner metadata -+ */ -+ -+ control_fd = open(control_path, O_RDWR); -+ ASSERT_RETURN(control_fd >= 0); -+ -+ busname = unique_name("test-peers-info-bus"); -+ ASSERT_RETURN(busname); -+ -+ ret = kdbus_create_bus(control_fd, busname, 0, 0, &path); -+ ASSERT_RETURN(ret == 0); -+ -+ snprintf(buspath, sizeof(buspath), "%s/%s/bus", env->root, path); -+ -+ conn = __kdbus_hello(buspath, 0, 0, 0); -+ ASSERT_RETURN(conn); -+ -+ /* -+ * Start with a kdbus module mask set to _KDBUS_ATTACH_ANY -+ */ -+ attach_flags_mask = _KDBUS_ATTACH_ANY; -+ -+ /* -+ * We only get the KDBUS_ITEM_MAKE_NAME -+ */ -+ expected_items = KDBUS_ITEM_MAKE_NAME; -+ ret = kdbus_cmp_bus_creator_metadata(env, conn, -+ attach_flags_mask, -+ _KDBUS_ATTACH_ALL, -+ expected_items); -+ ASSERT_RETURN(ret == 0); -+ -+ /* -+ * We still get only kdbus_ITEM_MAKE_NAME -+ */ -+ attach_flags_mask = 0; -+ expected_items = KDBUS_ITEM_MAKE_NAME; -+ ret = kdbus_cmp_bus_creator_metadata(env, conn, -+ attach_flags_mask, -+ _KDBUS_ATTACH_ALL, -+ expected_items); -+ ASSERT_RETURN(ret == 0); -+ -+ kdbus_conn_free(conn); -+ free(path); -+ free(busname); -+ close(control_fd); -+ -+ -+ /* -+ * A new bus that shows only the PID and CREDS metadata -+ * of the bus owner. -+ */ -+ control_fd = open(control_path, O_RDWR); -+ ASSERT_RETURN(control_fd >= 0); -+ -+ busname = unique_name("test-peers-info-bus"); -+ ASSERT_RETURN(busname); -+ -+ ret = kdbus_create_bus(control_fd, busname, 0, -+ KDBUS_ATTACH_PIDS| -+ KDBUS_ATTACH_CREDS, &path); -+ ASSERT_RETURN(ret == 0); -+ -+ snprintf(buspath, sizeof(buspath), "%s/%s/bus", env->root, path); -+ -+ conn = __kdbus_hello(buspath, 0, 0, 0); -+ ASSERT_RETURN(conn); -+ -+ /* -+ * Start with a kdbus module mask set to _KDBUS_ATTACH_ANY -+ */ -+ attach_flags_mask = _KDBUS_ATTACH_ANY; -+ -+ /* -+ * We should have: -+ * KDBUS_ITEM_PIDS + KDBUS_ITEM_CREDS + KDBUS_ITEM_MAKE_NAME -+ */ -+ expected_items = KDBUS_ITEM_PIDS + KDBUS_ITEM_CREDS + -+ KDBUS_ITEM_MAKE_NAME; -+ ret = kdbus_cmp_bus_creator_metadata(env, conn, -+ attach_flags_mask, -+ _KDBUS_ATTACH_ALL, -+ expected_items); -+ ASSERT_RETURN(ret == 0); -+ -+ expected_items = KDBUS_ITEM_CREDS + KDBUS_ITEM_MAKE_NAME; -+ ret = kdbus_cmp_bus_creator_metadata(env, conn, -+ attach_flags_mask, -+ KDBUS_ATTACH_CREDS, -+ expected_items); -+ ASSERT_RETURN(ret == 0); -+ -+ /* KDBUS_ITEM_MAKE_NAME is always returned */ -+ expected_items = KDBUS_ITEM_MAKE_NAME; -+ ret = kdbus_cmp_bus_creator_metadata(env, conn, -+ attach_flags_mask, -+ 0, expected_items); -+ ASSERT_RETURN(ret == 0); -+ -+ /* -+ * Restrict kdbus system-wide mask to KDBUS_ATTACH_PIDS -+ */ -+ -+ attach_flags_mask = KDBUS_ATTACH_PIDS; -+ /* -+ * We should have: -+ * KDBUS_ITEM_PIDS + KDBUS_ITEM_MAKE_NAME -+ */ -+ expected_items = KDBUS_ITEM_PIDS + KDBUS_ITEM_MAKE_NAME; -+ ret = kdbus_cmp_bus_creator_metadata(env, conn, -+ attach_flags_mask, -+ _KDBUS_ATTACH_ALL, -+ expected_items); -+ ASSERT_RETURN(ret == 0); -+ -+ /* No KDBUS_ATTACH_CREDS */ -+ expected_items = KDBUS_ITEM_MAKE_NAME; -+ ret = kdbus_cmp_bus_creator_metadata(env, conn, -+ attach_flags_mask, -+ KDBUS_ATTACH_CREDS, -+ expected_items); -+ ASSERT_RETURN(ret == 0); -+ -+ /* system-wide mask to 0 */ -+ attach_flags_mask = 0; -+ -+ /* we should only see: KDBUS_ITEM_MAKE_NAME */ -+ expected_items = KDBUS_ITEM_MAKE_NAME; -+ ret = kdbus_cmp_bus_creator_metadata(env, conn, -+ attach_flags_mask, -+ _KDBUS_ATTACH_ALL, -+ expected_items); -+ ASSERT_RETURN(ret == 0); -+ -+ -+ kdbus_conn_free(conn); -+ free(path); -+ free(busname); -+ close(control_fd); -+ -+ return 0; -+} -+ -+int kdbus_test_attach_flags(struct kdbus_test_env *env) -+{ -+ int ret; -+ uint64_t flags_mask; -+ uint64_t old_kdbus_flags_mask; -+ -+ /* We need CAP_DAC_OVERRIDE to overwrite the kdbus mask */ -+ ret = test_is_capable(CAP_DAC_OVERRIDE, -1); -+ ASSERT_RETURN(ret >= 0); -+ -+ /* no enough privileges, SKIP test */ -+ if (!ret) -+ return TEST_SKIP; -+ -+ /* -+ * We need to be able to write to -+ * "/sys/module/kdbus/parameters/attach_flags_mask" -+ * perhaps we are unprvileged/privileged in its userns -+ */ -+ ret = access(env->mask_param_path, W_OK); -+ if (ret < 0) { -+ kdbus_printf("--- access() '%s' failed: %d (%m)\n", -+ env->mask_param_path, -errno); -+ return TEST_SKIP; -+ } -+ -+ ret = kdbus_sysfs_get_parameter_mask(env->mask_param_path, -+ &old_kdbus_flags_mask); -+ ASSERT_RETURN(ret == 0); -+ -+ /* setup the right KDBUS_TEST_ITEMS_SUM */ -+ if (!config_auditsyscall_is_enabled()) -+ KDBUS_TEST_ITEMS_SUM -= KDBUS_ITEM_AUDIT; -+ -+ if (!config_cgroups_is_enabled()) -+ KDBUS_TEST_ITEMS_SUM -= KDBUS_ITEM_CGROUP; -+ -+ if (!config_security_is_enabled()) -+ KDBUS_TEST_ITEMS_SUM -= KDBUS_ITEM_SECLABEL; -+ -+ /* -+ * Test the connection creation attach flags -+ */ -+ ret = kdbus_test_peers_creation(env); -+ /* Restore previous kdbus mask */ -+ kdbus_sysfs_set_parameter_mask(env->mask_param_path, -+ old_kdbus_flags_mask); -+ ASSERT_RETURN(ret == 0); -+ -+ /* -+ * Test the CONN_INFO attach flags -+ */ -+ ret = kdbus_test_peers_info(env); -+ /* Restore previous kdbus mask */ -+ kdbus_sysfs_set_parameter_mask(env->mask_param_path, -+ old_kdbus_flags_mask); -+ ASSERT_RETURN(ret == 0); -+ -+ /* -+ * Test the Bus creator info and its attach flags -+ */ -+ ret = kdbus_test_bus_creator_info(env); -+ /* Restore previous kdbus mask */ -+ kdbus_sysfs_set_parameter_mask(env->mask_param_path, -+ old_kdbus_flags_mask); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_sysfs_get_parameter_mask(env->mask_param_path, -+ &flags_mask); -+ ASSERT_RETURN(ret == 0 && old_kdbus_flags_mask == flags_mask); -+ -+ return TEST_OK; -+} -diff --git a/tools/testing/selftests/kdbus/test-benchmark.c b/tools/testing/selftests/kdbus/test-benchmark.c -new file mode 100644 -index 000000000000..8a9744b00508 ---- /dev/null -+++ b/tools/testing/selftests/kdbus/test-benchmark.c -@@ -0,0 +1,451 @@ -+#include <stdio.h> -+#include <string.h> -+#include <time.h> -+#include <fcntl.h> -+#include <locale.h> -+#include <stdlib.h> -+#include <stddef.h> -+#include <unistd.h> -+#include <stdint.h> -+#include <stdbool.h> -+#include <errno.h> -+#include <assert.h> -+#include <poll.h> -+#include <sys/time.h> -+#include <sys/mman.h> -+#include <sys/socket.h> -+#include <math.h> -+ -+#include "kdbus-api.h" -+#include "kdbus-test.h" -+#include "kdbus-util.h" -+#include "kdbus-enum.h" -+ -+#define SERVICE_NAME "foo.bar.echo" -+ -+/* -+ * To have a banchmark comparison with unix socket, set: -+ * user_memfd = false; -+ * compare_uds = true; -+ * attach_none = true; do not attached metadata -+ */ -+ -+static bool use_memfd = true; /* transmit memfd? */ -+static bool compare_uds = false; /* unix-socket comparison? */ -+static bool attach_none = false; /* clear attach-flags? */ -+static char stress_payload[8192]; -+ -+struct stats { -+ uint64_t count; -+ uint64_t latency_acc; -+ uint64_t latency_low; -+ uint64_t latency_high; -+ uint64_t latency_avg; -+ uint64_t latency_ssquares; -+}; -+ -+static struct stats stats; -+ -+static void reset_stats(void) -+{ -+ stats.count = 0; -+ stats.latency_acc = 0; -+ stats.latency_low = UINT64_MAX; -+ stats.latency_high = 0; -+ stats.latency_avg = 0; -+ stats.latency_ssquares = 0; -+} -+ -+static void dump_stats(bool is_uds) -+{ -+ if (stats.count > 0) { -+ kdbus_printf("stats %s: %'llu packets processed, latency (nsecs) min/max/avg/dev %'7llu // %'7llu // %'7llu // %'7.f\n", -+ is_uds ? " (UNIX)" : "(KDBUS)", -+ (unsigned long long) stats.count, -+ (unsigned long long) stats.latency_low, -+ (unsigned long long) stats.latency_high, -+ (unsigned long long) stats.latency_avg, -+ sqrt(stats.latency_ssquares / stats.count)); -+ } else { -+ kdbus_printf("*** no packets received. bus stuck?\n"); -+ } -+} -+ -+static void add_stats(uint64_t prev) -+{ -+ uint64_t diff, latency_avg_prev; -+ -+ diff = now(CLOCK_THREAD_CPUTIME_ID) - prev; -+ -+ stats.count++; -+ stats.latency_acc += diff; -+ -+ /* see Welford62 */ -+ latency_avg_prev = stats.latency_avg; -+ stats.latency_avg = stats.latency_acc / stats.count; -+ stats.latency_ssquares += (diff - latency_avg_prev) * (diff - stats.latency_avg); -+ -+ if (stats.latency_low > diff) -+ stats.latency_low = diff; -+ -+ if (stats.latency_high < diff) -+ stats.latency_high = diff; -+} -+ -+static int setup_simple_kdbus_msg(struct kdbus_conn *conn, -+ uint64_t dst_id, -+ struct kdbus_msg **msg_out) -+{ -+ struct kdbus_msg *msg; -+ struct kdbus_item *item; -+ uint64_t size; -+ -+ size = sizeof(struct kdbus_msg); -+ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec)); -+ -+ msg = malloc(size); -+ ASSERT_RETURN_VAL(msg, -ENOMEM); -+ -+ memset(msg, 0, size); -+ msg->size = size; -+ msg->src_id = conn->id; -+ msg->dst_id = dst_id; -+ msg->payload_type = KDBUS_PAYLOAD_DBUS; -+ -+ item = msg->items; -+ -+ item->type = KDBUS_ITEM_PAYLOAD_VEC; -+ item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_vec); -+ item->vec.address = (uintptr_t) stress_payload; -+ item->vec.size = sizeof(stress_payload); -+ item = KDBUS_ITEM_NEXT(item); -+ -+ *msg_out = msg; -+ -+ return 0; -+} -+ -+static int setup_memfd_kdbus_msg(struct kdbus_conn *conn, -+ uint64_t dst_id, -+ off_t *memfd_item_offset, -+ struct kdbus_msg **msg_out) -+{ -+ struct kdbus_msg *msg; -+ struct kdbus_item *item; -+ uint64_t size; -+ -+ size = sizeof(struct kdbus_msg); -+ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec)); -+ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_memfd)); -+ -+ msg = malloc(size); -+ ASSERT_RETURN_VAL(msg, -ENOMEM); -+ -+ memset(msg, 0, size); -+ msg->size = size; -+ msg->src_id = conn->id; -+ msg->dst_id = dst_id; -+ msg->payload_type = KDBUS_PAYLOAD_DBUS; -+ -+ item = msg->items; -+ -+ item->type = KDBUS_ITEM_PAYLOAD_VEC; -+ item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_vec); -+ item->vec.address = (uintptr_t) stress_payload; -+ item->vec.size = sizeof(stress_payload); -+ item = KDBUS_ITEM_NEXT(item); -+ -+ item->type = KDBUS_ITEM_PAYLOAD_MEMFD; -+ item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_memfd); -+ item->memfd.size = sizeof(uint64_t); -+ -+ *memfd_item_offset = (unsigned char *)item - (unsigned char *)msg; -+ *msg_out = msg; -+ -+ return 0; -+} -+ -+static int -+send_echo_request(struct kdbus_conn *conn, uint64_t dst_id, -+ void *kdbus_msg, off_t memfd_item_offset) -+{ -+ struct kdbus_cmd_send cmd = {}; -+ int memfd = -1; -+ int ret; -+ -+ if (use_memfd) { -+ uint64_t now_ns = now(CLOCK_THREAD_CPUTIME_ID); -+ struct kdbus_item *item = memfd_item_offset + kdbus_msg; -+ memfd = sys_memfd_create("memfd-name", 0); -+ ASSERT_RETURN_VAL(memfd >= 0, memfd); -+ -+ ret = write(memfd, &now_ns, sizeof(now_ns)); -+ ASSERT_RETURN_VAL(ret == sizeof(now_ns), -EAGAIN); -+ -+ ret = sys_memfd_seal_set(memfd); -+ ASSERT_RETURN_VAL(ret == 0, -errno); -+ -+ item->memfd.fd = memfd; -+ } -+ -+ cmd.size = sizeof(cmd); -+ cmd.msg_address = (uintptr_t)kdbus_msg; -+ -+ ret = kdbus_cmd_send(conn->fd, &cmd); -+ ASSERT_RETURN_VAL(ret == 0, ret); -+ -+ close(memfd); -+ -+ return 0; -+} -+ -+static int -+handle_echo_reply(struct kdbus_conn *conn, uint64_t send_ns) -+{ -+ int ret; -+ struct kdbus_cmd_recv recv = { .size = sizeof(recv) }; -+ struct kdbus_msg *msg; -+ const struct kdbus_item *item; -+ bool has_memfd = false; -+ -+ ret = kdbus_cmd_recv(conn->fd, &recv); -+ if (ret == -EAGAIN) -+ return ret; -+ -+ ASSERT_RETURN_VAL(ret == 0, ret); -+ -+ if (!use_memfd) -+ goto out; -+ -+ msg = (struct kdbus_msg *)(conn->buf + recv.msg.offset); -+ -+ KDBUS_ITEM_FOREACH(item, msg, items) { -+ switch (item->type) { -+ case KDBUS_ITEM_PAYLOAD_MEMFD: { -+ char *buf; -+ -+ buf = mmap(NULL, item->memfd.size, PROT_READ, -+ MAP_PRIVATE, item->memfd.fd, 0); -+ ASSERT_RETURN_VAL(buf != MAP_FAILED, -EINVAL); -+ ASSERT_RETURN_VAL(item->memfd.size == sizeof(uint64_t), -+ -EINVAL); -+ -+ add_stats(*(uint64_t*)buf); -+ munmap(buf, item->memfd.size); -+ close(item->memfd.fd); -+ has_memfd = true; -+ break; -+ } -+ -+ case KDBUS_ITEM_PAYLOAD_OFF: -+ /* ignore */ -+ break; -+ } -+ } -+ -+out: -+ if (!has_memfd) -+ add_stats(send_ns); -+ -+ ret = kdbus_free(conn, recv.msg.offset); -+ ASSERT_RETURN_VAL(ret == 0, -errno); -+ -+ return 0; -+} -+ -+static int benchmark(struct kdbus_test_env *env) -+{ -+ static char buf[sizeof(stress_payload)]; -+ struct kdbus_msg *kdbus_msg = NULL; -+ off_t memfd_cached_offset = 0; -+ int ret; -+ struct kdbus_conn *conn_a, *conn_b; -+ struct pollfd fds[2]; -+ uint64_t start, send_ns, now_ns, diff; -+ unsigned int i; -+ int uds[2]; -+ -+ setlocale(LC_ALL, ""); -+ -+ for (i = 0; i < sizeof(stress_payload); i++) -+ stress_payload[i] = i; -+ -+ /* setup kdbus pair */ -+ -+ conn_a = kdbus_hello(env->buspath, 0, NULL, 0); -+ conn_b = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(conn_a && conn_b); -+ -+ ret = kdbus_add_match_empty(conn_a); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_add_match_empty(conn_b); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_name_acquire(conn_a, SERVICE_NAME, NULL); -+ ASSERT_RETURN(ret == 0); -+ -+ if (attach_none) { -+ ret = kdbus_conn_update_attach_flags(conn_a, -+ _KDBUS_ATTACH_ALL, -+ 0); -+ ASSERT_RETURN(ret == 0); -+ } -+ -+ /* setup UDS pair */ -+ -+ ret = socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK, 0, uds); -+ ASSERT_RETURN(ret == 0); -+ -+ /* setup a kdbus msg now */ -+ if (use_memfd) { -+ ret = setup_memfd_kdbus_msg(conn_b, conn_a->id, -+ &memfd_cached_offset, -+ &kdbus_msg); -+ ASSERT_RETURN(ret == 0); -+ } else { -+ ret = setup_simple_kdbus_msg(conn_b, conn_a->id, &kdbus_msg); -+ ASSERT_RETURN(ret == 0); -+ } -+ -+ /* start benchmark */ -+ -+ kdbus_printf("-- entering poll loop ...\n"); -+ -+ do { -+ /* run kdbus benchmark */ -+ fds[0].fd = conn_a->fd; -+ fds[1].fd = conn_b->fd; -+ -+ /* cancel any pending message */ -+ handle_echo_reply(conn_a, 0); -+ -+ start = now(CLOCK_THREAD_CPUTIME_ID); -+ reset_stats(); -+ -+ send_ns = now(CLOCK_THREAD_CPUTIME_ID); -+ ret = send_echo_request(conn_b, conn_a->id, -+ kdbus_msg, memfd_cached_offset); -+ ASSERT_RETURN(ret == 0); -+ -+ while (1) { -+ unsigned int nfds = sizeof(fds) / sizeof(fds[0]); -+ unsigned int i; -+ -+ for (i = 0; i < nfds; i++) { -+ fds[i].events = POLLIN | POLLPRI | POLLHUP; -+ fds[i].revents = 0; -+ } -+ -+ ret = poll(fds, nfds, 10); -+ if (ret < 0) -+ break; -+ -+ if (fds[0].revents & POLLIN) { -+ ret = handle_echo_reply(conn_a, send_ns); -+ ASSERT_RETURN(ret == 0); -+ -+ send_ns = now(CLOCK_THREAD_CPUTIME_ID); -+ ret = send_echo_request(conn_b, conn_a->id, -+ kdbus_msg, -+ memfd_cached_offset); -+ ASSERT_RETURN(ret == 0); -+ } -+ -+ now_ns = now(CLOCK_THREAD_CPUTIME_ID); -+ diff = now_ns - start; -+ if (diff > 1000000000ULL) { -+ start = now_ns; -+ -+ dump_stats(false); -+ break; -+ } -+ } -+ -+ if (!compare_uds) -+ continue; -+ -+ /* run unix-socket benchmark as comparison */ -+ -+ fds[0].fd = uds[0]; -+ fds[1].fd = uds[1]; -+ -+ /* cancel any pendign message */ -+ read(uds[1], buf, sizeof(buf)); -+ -+ start = now(CLOCK_THREAD_CPUTIME_ID); -+ reset_stats(); -+ -+ send_ns = now(CLOCK_THREAD_CPUTIME_ID); -+ ret = write(uds[0], stress_payload, sizeof(stress_payload)); -+ ASSERT_RETURN(ret == sizeof(stress_payload)); -+ -+ while (1) { -+ unsigned int nfds = sizeof(fds) / sizeof(fds[0]); -+ unsigned int i; -+ -+ for (i = 0; i < nfds; i++) { -+ fds[i].events = POLLIN | POLLPRI | POLLHUP; -+ fds[i].revents = 0; -+ } -+ -+ ret = poll(fds, nfds, 10); -+ if (ret < 0) -+ break; -+ -+ if (fds[1].revents & POLLIN) { -+ ret = read(uds[1], buf, sizeof(buf)); -+ ASSERT_RETURN(ret == sizeof(buf)); -+ -+ add_stats(send_ns); -+ -+ send_ns = now(CLOCK_THREAD_CPUTIME_ID); -+ ret = write(uds[0], buf, sizeof(buf)); -+ ASSERT_RETURN(ret == sizeof(buf)); -+ } -+ -+ now_ns = now(CLOCK_THREAD_CPUTIME_ID); -+ diff = now_ns - start; -+ if (diff > 1000000000ULL) { -+ start = now_ns; -+ -+ dump_stats(true); -+ break; -+ } -+ } -+ -+ } while (kdbus_util_verbose); -+ -+ kdbus_printf("-- closing bus connections\n"); -+ -+ free(kdbus_msg); -+ -+ kdbus_conn_free(conn_a); -+ kdbus_conn_free(conn_b); -+ -+ return (stats.count > 1) ? TEST_OK : TEST_ERR; -+} -+ -+int kdbus_test_benchmark(struct kdbus_test_env *env) -+{ -+ use_memfd = true; -+ attach_none = false; -+ compare_uds = false; -+ return benchmark(env); -+} -+ -+int kdbus_test_benchmark_nomemfds(struct kdbus_test_env *env) -+{ -+ use_memfd = false; -+ attach_none = false; -+ compare_uds = false; -+ return benchmark(env); -+} -+ -+int kdbus_test_benchmark_uds(struct kdbus_test_env *env) -+{ -+ use_memfd = false; -+ attach_none = true; -+ compare_uds = true; -+ return benchmark(env); -+} -diff --git a/tools/testing/selftests/kdbus/test-bus.c b/tools/testing/selftests/kdbus/test-bus.c -new file mode 100644 -index 000000000000..762fb30397d4 ---- /dev/null -+++ b/tools/testing/selftests/kdbus/test-bus.c -@@ -0,0 +1,175 @@ -+#include <stdio.h> -+#include <string.h> -+#include <fcntl.h> -+#include <stdlib.h> -+#include <stddef.h> -+#include <unistd.h> -+#include <stdint.h> -+#include <errno.h> -+#include <assert.h> -+#include <limits.h> -+#include <sys/mman.h> -+#include <stdbool.h> -+ -+#include "kdbus-api.h" -+#include "kdbus-util.h" -+#include "kdbus-enum.h" -+#include "kdbus-test.h" -+ -+static struct kdbus_item *kdbus_get_item(struct kdbus_info *info, -+ uint64_t type) -+{ -+ struct kdbus_item *item; -+ -+ KDBUS_ITEM_FOREACH(item, info, items) -+ if (item->type == type) -+ return item; -+ -+ return NULL; -+} -+ -+static int test_bus_creator_info(const char *bus_path) -+{ -+ int ret; -+ uint64_t offset; -+ struct kdbus_conn *conn; -+ struct kdbus_info *info; -+ struct kdbus_item *item; -+ char *tmp, *busname; -+ -+ /* extract the bus-name from @bus_path */ -+ tmp = strdup(bus_path); -+ ASSERT_RETURN(tmp); -+ busname = strrchr(tmp, '/'); -+ ASSERT_RETURN(busname); -+ *busname = 0; -+ busname = strrchr(tmp, '/'); -+ ASSERT_RETURN(busname); -+ ++busname; -+ -+ conn = kdbus_hello(bus_path, 0, NULL, 0); -+ ASSERT_RETURN(conn); -+ -+ ret = kdbus_bus_creator_info(conn, _KDBUS_ATTACH_ALL, &offset); -+ ASSERT_RETURN(ret == 0); -+ -+ info = (struct kdbus_info *)(conn->buf + offset); -+ -+ item = kdbus_get_item(info, KDBUS_ITEM_MAKE_NAME); -+ ASSERT_RETURN(item); -+ ASSERT_RETURN(!strcmp(item->str, busname)); -+ -+ ret = kdbus_free(conn, offset); -+ ASSERT_RETURN_VAL(ret == 0, ret); -+ -+ free(tmp); -+ kdbus_conn_free(conn); -+ return 0; -+} -+ -+int kdbus_test_bus_make(struct kdbus_test_env *env) -+{ -+ struct { -+ struct kdbus_cmd cmd; -+ -+ /* bloom size item */ -+ struct { -+ uint64_t size; -+ uint64_t type; -+ struct kdbus_bloom_parameter bloom; -+ } bs; -+ -+ /* name item */ -+ uint64_t n_size; -+ uint64_t n_type; -+ char name[64]; -+ } bus_make; -+ char s[PATH_MAX], *name; -+ int ret, control_fd2; -+ uid_t uid; -+ -+ name = unique_name(""); -+ ASSERT_RETURN(name); -+ -+ snprintf(s, sizeof(s), "%s/control", env->root); -+ env->control_fd = open(s, O_RDWR|O_CLOEXEC); -+ ASSERT_RETURN(env->control_fd >= 0); -+ -+ control_fd2 = open(s, O_RDWR|O_CLOEXEC); -+ ASSERT_RETURN(control_fd2 >= 0); -+ -+ memset(&bus_make, 0, sizeof(bus_make)); -+ -+ bus_make.bs.size = sizeof(bus_make.bs); -+ bus_make.bs.type = KDBUS_ITEM_BLOOM_PARAMETER; -+ bus_make.bs.bloom.size = 64; -+ bus_make.bs.bloom.n_hash = 1; -+ -+ bus_make.n_type = KDBUS_ITEM_MAKE_NAME; -+ -+ uid = getuid(); -+ -+ /* missing uid prefix */ -+ snprintf(bus_make.name, sizeof(bus_make.name), "foo"); -+ bus_make.n_size = KDBUS_ITEM_HEADER_SIZE + strlen(bus_make.name) + 1; -+ bus_make.cmd.size = sizeof(struct kdbus_cmd) + -+ sizeof(bus_make.bs) + bus_make.n_size; -+ ret = kdbus_cmd_bus_make(env->control_fd, &bus_make.cmd); -+ ASSERT_RETURN(ret == -EINVAL); -+ -+ /* non alphanumeric character */ -+ snprintf(bus_make.name, sizeof(bus_make.name), "%u-blah@123", uid); -+ bus_make.n_size = KDBUS_ITEM_HEADER_SIZE + strlen(bus_make.name) + 1; -+ bus_make.cmd.size = sizeof(struct kdbus_cmd) + -+ sizeof(bus_make.bs) + bus_make.n_size; -+ ret = kdbus_cmd_bus_make(env->control_fd, &bus_make.cmd); -+ ASSERT_RETURN(ret == -EINVAL); -+ -+ /* '-' at the end */ -+ snprintf(bus_make.name, sizeof(bus_make.name), "%u-blah-", uid); -+ bus_make.n_size = KDBUS_ITEM_HEADER_SIZE + strlen(bus_make.name) + 1; -+ bus_make.cmd.size = sizeof(struct kdbus_cmd) + -+ sizeof(bus_make.bs) + bus_make.n_size; -+ ret = kdbus_cmd_bus_make(env->control_fd, &bus_make.cmd); -+ ASSERT_RETURN(ret == -EINVAL); -+ -+ /* create a new bus */ -+ snprintf(bus_make.name, sizeof(bus_make.name), "%u-%s-1", uid, name); -+ bus_make.n_size = KDBUS_ITEM_HEADER_SIZE + strlen(bus_make.name) + 1; -+ bus_make.cmd.size = sizeof(struct kdbus_cmd) + -+ sizeof(bus_make.bs) + bus_make.n_size; -+ ret = kdbus_cmd_bus_make(env->control_fd, &bus_make.cmd); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_cmd_bus_make(control_fd2, &bus_make.cmd); -+ ASSERT_RETURN(ret == -EEXIST); -+ -+ snprintf(s, sizeof(s), "%s/%u-%s-1/bus", env->root, uid, name); -+ ASSERT_RETURN(access(s, F_OK) == 0); -+ -+ ret = test_bus_creator_info(s); -+ ASSERT_RETURN(ret == 0); -+ -+ /* can't use the same fd for bus make twice, even though a different -+ * bus name is used -+ */ -+ snprintf(bus_make.name, sizeof(bus_make.name), "%u-%s-2", uid, name); -+ bus_make.n_size = KDBUS_ITEM_HEADER_SIZE + strlen(bus_make.name) + 1; -+ bus_make.cmd.size = sizeof(struct kdbus_cmd) + -+ sizeof(bus_make.bs) + bus_make.n_size; -+ ret = kdbus_cmd_bus_make(env->control_fd, &bus_make.cmd); -+ ASSERT_RETURN(ret == -EBADFD); -+ -+ /* create a new bus, with different fd and different bus name */ -+ snprintf(bus_make.name, sizeof(bus_make.name), "%u-%s-2", uid, name); -+ bus_make.n_size = KDBUS_ITEM_HEADER_SIZE + strlen(bus_make.name) + 1; -+ bus_make.cmd.size = sizeof(struct kdbus_cmd) + -+ sizeof(bus_make.bs) + bus_make.n_size; -+ ret = kdbus_cmd_bus_make(control_fd2, &bus_make.cmd); -+ ASSERT_RETURN(ret == 0); -+ -+ close(control_fd2); -+ free(name); -+ -+ return TEST_OK; -+} -diff --git a/tools/testing/selftests/kdbus/test-chat.c b/tools/testing/selftests/kdbus/test-chat.c -new file mode 100644 -index 000000000000..71a92d8b7c85 ---- /dev/null -+++ b/tools/testing/selftests/kdbus/test-chat.c -@@ -0,0 +1,122 @@ -+#include <stdio.h> -+#include <string.h> -+#include <time.h> -+#include <fcntl.h> -+#include <stdlib.h> -+#include <stddef.h> -+#include <unistd.h> -+#include <stdint.h> -+#include <errno.h> -+#include <assert.h> -+#include <poll.h> -+#include <stdbool.h> -+ -+#include "kdbus-test.h" -+#include "kdbus-util.h" -+#include "kdbus-enum.h" -+ -+int kdbus_test_chat(struct kdbus_test_env *env) -+{ -+ int ret, cookie; -+ struct kdbus_conn *conn_a, *conn_b; -+ struct pollfd fds[2]; -+ uint64_t flags; -+ int count; -+ -+ conn_a = kdbus_hello(env->buspath, 0, NULL, 0); -+ conn_b = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(conn_a && conn_b); -+ -+ flags = KDBUS_NAME_ALLOW_REPLACEMENT; -+ ret = kdbus_name_acquire(conn_a, "foo.bar.test", &flags); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_name_acquire(conn_a, "foo.bar.baz", NULL); -+ ASSERT_RETURN(ret == 0); -+ -+ flags = KDBUS_NAME_QUEUE; -+ ret = kdbus_name_acquire(conn_b, "foo.bar.baz", &flags); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_name_acquire(conn_a, "foo.bar.double", NULL); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_name_acquire(conn_a, "foo.bar.double", NULL); -+ ASSERT_RETURN(ret == -EALREADY); -+ -+ ret = kdbus_name_release(conn_a, "foo.bar.double"); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_name_release(conn_a, "foo.bar.double"); -+ ASSERT_RETURN(ret == -ESRCH); -+ -+ ret = kdbus_list(conn_b, KDBUS_LIST_UNIQUE | -+ KDBUS_LIST_NAMES | -+ KDBUS_LIST_QUEUED | -+ KDBUS_LIST_ACTIVATORS); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_add_match_empty(conn_a); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_add_match_empty(conn_b); -+ ASSERT_RETURN(ret == 0); -+ -+ cookie = 0; -+ ret = kdbus_msg_send(conn_b, NULL, 0xc0000000 | cookie, 0, 0, 0, -+ KDBUS_DST_ID_BROADCAST); -+ ASSERT_RETURN(ret == 0); -+ -+ fds[0].fd = conn_a->fd; -+ fds[1].fd = conn_b->fd; -+ -+ kdbus_printf("-- entering poll loop ...\n"); -+ -+ for (count = 0;; count++) { -+ int i, nfds = sizeof(fds) / sizeof(fds[0]); -+ -+ for (i = 0; i < nfds; i++) { -+ fds[i].events = POLLIN | POLLPRI | POLLHUP; -+ fds[i].revents = 0; -+ } -+ -+ ret = poll(fds, nfds, 3000); -+ ASSERT_RETURN(ret >= 0); -+ -+ if (fds[0].revents & POLLIN) { -+ if (count > 2) -+ kdbus_name_release(conn_a, "foo.bar.baz"); -+ -+ ret = kdbus_msg_recv(conn_a, NULL, NULL); -+ ASSERT_RETURN(ret == 0); -+ ret = kdbus_msg_send(conn_a, NULL, -+ 0xc0000000 | cookie++, -+ 0, 0, 0, conn_b->id); -+ ASSERT_RETURN(ret == 0); -+ } -+ -+ if (fds[1].revents & POLLIN) { -+ ret = kdbus_msg_recv(conn_b, NULL, NULL); -+ ASSERT_RETURN(ret == 0); -+ ret = kdbus_msg_send(conn_b, NULL, -+ 0xc0000000 | cookie++, -+ 0, 0, 0, conn_a->id); -+ ASSERT_RETURN(ret == 0); -+ } -+ -+ ret = kdbus_list(conn_b, KDBUS_LIST_UNIQUE | -+ KDBUS_LIST_NAMES | -+ KDBUS_LIST_QUEUED | -+ KDBUS_LIST_ACTIVATORS); -+ ASSERT_RETURN(ret == 0); -+ -+ if (count > 10) -+ break; -+ } -+ -+ kdbus_printf("-- closing bus connections\n"); -+ kdbus_conn_free(conn_a); -+ kdbus_conn_free(conn_b); -+ -+ return TEST_OK; -+} -diff --git a/tools/testing/selftests/kdbus/test-connection.c b/tools/testing/selftests/kdbus/test-connection.c -new file mode 100644 -index 000000000000..5c2bf3511daa ---- /dev/null -+++ b/tools/testing/selftests/kdbus/test-connection.c -@@ -0,0 +1,616 @@ -+#include <stdio.h> -+#include <string.h> -+#include <fcntl.h> -+#include <stdlib.h> -+#include <stddef.h> -+#include <unistd.h> -+#include <stdint.h> -+#include <errno.h> -+#include <assert.h> -+#include <limits.h> -+#include <sys/types.h> -+#include <sys/capability.h> -+#include <sys/mman.h> -+#include <sys/syscall.h> -+#include <sys/wait.h> -+#include <stdbool.h> -+ -+#include "kdbus-api.h" -+#include "kdbus-util.h" -+#include "kdbus-enum.h" -+#include "kdbus-test.h" -+ -+int kdbus_test_hello(struct kdbus_test_env *env) -+{ -+ struct kdbus_cmd_free cmd_free = {}; -+ struct kdbus_cmd_hello hello; -+ int fd, ret; -+ -+ memset(&hello, 0, sizeof(hello)); -+ -+ fd = open(env->buspath, O_RDWR|O_CLOEXEC); -+ ASSERT_RETURN(fd >= 0); -+ -+ hello.flags = KDBUS_HELLO_ACCEPT_FD; -+ hello.attach_flags_send = _KDBUS_ATTACH_ALL; -+ hello.attach_flags_recv = _KDBUS_ATTACH_ALL; -+ hello.size = sizeof(struct kdbus_cmd_hello); -+ hello.pool_size = POOL_SIZE; -+ -+ /* an unaligned hello must result in -EFAULT */ -+ ret = kdbus_cmd_hello(fd, (struct kdbus_cmd_hello *) ((char *) &hello + 1)); -+ ASSERT_RETURN(ret == -EFAULT); -+ -+ /* a size of 0 must return EMSGSIZE */ -+ hello.size = 1; -+ hello.flags = KDBUS_HELLO_ACCEPT_FD; -+ hello.attach_flags_send = _KDBUS_ATTACH_ALL; -+ ret = kdbus_cmd_hello(fd, &hello); -+ ASSERT_RETURN(ret == -EINVAL); -+ -+ hello.size = sizeof(struct kdbus_cmd_hello); -+ -+ /* check faulty flags */ -+ hello.flags = 1ULL << 32; -+ hello.attach_flags_send = _KDBUS_ATTACH_ALL; -+ ret = kdbus_cmd_hello(fd, &hello); -+ ASSERT_RETURN(ret == -EINVAL); -+ -+ /* check for faulty pool sizes */ -+ hello.pool_size = 0; -+ hello.flags = KDBUS_HELLO_ACCEPT_FD; -+ hello.attach_flags_send = _KDBUS_ATTACH_ALL; -+ ret = kdbus_cmd_hello(fd, &hello); -+ ASSERT_RETURN(ret == -EINVAL); -+ -+ hello.pool_size = 4097; -+ hello.attach_flags_send = _KDBUS_ATTACH_ALL; -+ ret = kdbus_cmd_hello(fd, &hello); -+ ASSERT_RETURN(ret == -EINVAL); -+ -+ hello.pool_size = POOL_SIZE; -+ -+ /* -+ * The connection created by the core requires ALL meta flags -+ * to be sent. An attempt to send less than that should result in -+ * -ECONNREFUSED. -+ */ -+ hello.attach_flags_send = _KDBUS_ATTACH_ALL & ~KDBUS_ATTACH_TIMESTAMP; -+ ret = kdbus_cmd_hello(fd, &hello); -+ ASSERT_RETURN(ret == -ECONNREFUSED); -+ -+ hello.attach_flags_send = _KDBUS_ATTACH_ALL; -+ hello.offset = (__u64)-1; -+ -+ /* success test */ -+ ret = kdbus_cmd_hello(fd, &hello); -+ ASSERT_RETURN(ret == 0); -+ -+ /* The kernel should have returned some items */ -+ ASSERT_RETURN(hello.offset != (__u64)-1); -+ cmd_free.size = sizeof(cmd_free); -+ cmd_free.offset = hello.offset; -+ ret = kdbus_cmd_free(fd, &cmd_free); -+ ASSERT_RETURN(ret >= 0); -+ -+ close(fd); -+ -+ fd = open(env->buspath, O_RDWR|O_CLOEXEC); -+ ASSERT_RETURN(fd >= 0); -+ -+ /* no ACTIVATOR flag without a name */ -+ hello.flags = KDBUS_HELLO_ACTIVATOR; -+ ret = kdbus_cmd_hello(fd, &hello); -+ ASSERT_RETURN(ret == -EINVAL); -+ -+ close(fd); -+ -+ return TEST_OK; -+} -+ -+int kdbus_test_byebye(struct kdbus_test_env *env) -+{ -+ struct kdbus_conn *conn; -+ struct kdbus_cmd_recv cmd_recv = { .size = sizeof(cmd_recv) }; -+ struct kdbus_cmd cmd_byebye = { .size = sizeof(cmd_byebye) }; -+ int ret; -+ -+ /* create a 2nd connection */ -+ conn = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(conn != NULL); -+ -+ ret = kdbus_add_match_empty(conn); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_add_match_empty(env->conn); -+ ASSERT_RETURN(ret == 0); -+ -+ /* send over 1st connection */ -+ ret = kdbus_msg_send(env->conn, NULL, 0, 0, 0, 0, -+ KDBUS_DST_ID_BROADCAST); -+ ASSERT_RETURN(ret == 0); -+ -+ /* say byebye on the 2nd, which must fail */ -+ ret = kdbus_cmd_byebye(conn->fd, &cmd_byebye); -+ ASSERT_RETURN(ret == -EBUSY); -+ -+ /* receive the message */ -+ ret = kdbus_cmd_recv(conn->fd, &cmd_recv); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_free(conn, cmd_recv.msg.offset); -+ ASSERT_RETURN(ret == 0); -+ -+ /* and try again */ -+ ret = kdbus_cmd_byebye(conn->fd, &cmd_byebye); -+ ASSERT_RETURN(ret == 0); -+ -+ /* a 2nd try should result in -ECONNRESET */ -+ ret = kdbus_cmd_byebye(conn->fd, &cmd_byebye); -+ ASSERT_RETURN(ret == -ECONNRESET); -+ -+ kdbus_conn_free(conn); -+ -+ return TEST_OK; -+} -+ -+/* Get only the first item */ -+static struct kdbus_item *kdbus_get_item(struct kdbus_info *info, -+ uint64_t type) -+{ -+ struct kdbus_item *item; -+ -+ KDBUS_ITEM_FOREACH(item, info, items) -+ if (item->type == type) -+ return item; -+ -+ return NULL; -+} -+ -+static unsigned int kdbus_count_item(struct kdbus_info *info, -+ uint64_t type) -+{ -+ unsigned int i = 0; -+ const struct kdbus_item *item; -+ -+ KDBUS_ITEM_FOREACH(item, info, items) -+ if (item->type == type) -+ i++; -+ -+ return i; -+} -+ -+static int kdbus_fuzz_conn_info(struct kdbus_test_env *env, int capable) -+{ -+ int ret; -+ unsigned int cnt = 0; -+ uint64_t offset = 0; -+ uint64_t kdbus_flags_mask; -+ struct kdbus_info *info; -+ struct kdbus_conn *conn; -+ struct kdbus_conn *privileged; -+ const struct kdbus_item *item; -+ uint64_t valid_flags_set; -+ uint64_t invalid_flags_set; -+ uint64_t valid_flags = KDBUS_ATTACH_NAMES | -+ KDBUS_ATTACH_CREDS | -+ KDBUS_ATTACH_PIDS | -+ KDBUS_ATTACH_CONN_DESCRIPTION; -+ -+ uint64_t invalid_flags = KDBUS_ATTACH_NAMES | -+ KDBUS_ATTACH_CREDS | -+ KDBUS_ATTACH_PIDS | -+ KDBUS_ATTACH_CAPS | -+ KDBUS_ATTACH_CGROUP | -+ KDBUS_ATTACH_CONN_DESCRIPTION; -+ -+ struct kdbus_creds cached_creds; -+ uid_t ruid, euid, suid; -+ gid_t rgid, egid, sgid; -+ -+ getresuid(&ruid, &euid, &suid); -+ getresgid(&rgid, &egid, &sgid); -+ -+ cached_creds.uid = ruid; -+ cached_creds.euid = euid; -+ cached_creds.suid = suid; -+ cached_creds.fsuid = ruid; -+ -+ cached_creds.gid = rgid; -+ cached_creds.egid = egid; -+ cached_creds.sgid = sgid; -+ cached_creds.fsgid = rgid; -+ -+ struct kdbus_pids cached_pids = { -+ .pid = getpid(), -+ .tid = syscall(SYS_gettid), -+ .ppid = getppid(), -+ }; -+ -+ ret = kdbus_sysfs_get_parameter_mask(env->mask_param_path, -+ &kdbus_flags_mask); -+ ASSERT_RETURN(ret == 0); -+ -+ valid_flags_set = valid_flags & kdbus_flags_mask; -+ invalid_flags_set = invalid_flags & kdbus_flags_mask; -+ -+ ret = kdbus_conn_info(env->conn, env->conn->id, NULL, -+ valid_flags, &offset); -+ ASSERT_RETURN(ret == 0); -+ -+ info = (struct kdbus_info *)(env->conn->buf + offset); -+ ASSERT_RETURN(info->id == env->conn->id); -+ -+ /* We do not have any well-known name */ -+ item = kdbus_get_item(info, KDBUS_ITEM_NAME); -+ ASSERT_RETURN(item == NULL); -+ -+ item = kdbus_get_item(info, KDBUS_ITEM_CONN_DESCRIPTION); -+ if (valid_flags_set & KDBUS_ATTACH_CONN_DESCRIPTION) { -+ ASSERT_RETURN(item); -+ } else { -+ ASSERT_RETURN(item == NULL); -+ } -+ -+ kdbus_free(env->conn, offset); -+ -+ conn = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(conn); -+ -+ privileged = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(privileged); -+ -+ ret = kdbus_conn_info(conn, conn->id, NULL, valid_flags, &offset); -+ ASSERT_RETURN(ret == 0); -+ -+ info = (struct kdbus_info *)(conn->buf + offset); -+ ASSERT_RETURN(info->id == conn->id); -+ -+ /* We do not have any well-known name */ -+ item = kdbus_get_item(info, KDBUS_ITEM_NAME); -+ ASSERT_RETURN(item == NULL); -+ -+ cnt = kdbus_count_item(info, KDBUS_ITEM_CREDS); -+ if (valid_flags_set & KDBUS_ATTACH_CREDS) { -+ ASSERT_RETURN(cnt == 1); -+ -+ item = kdbus_get_item(info, KDBUS_ITEM_CREDS); -+ ASSERT_RETURN(item); -+ -+ /* Compare received items with cached creds */ -+ ASSERT_RETURN(memcmp(&item->creds, &cached_creds, -+ sizeof(struct kdbus_creds)) == 0); -+ } else { -+ ASSERT_RETURN(cnt == 0); -+ } -+ -+ item = kdbus_get_item(info, KDBUS_ITEM_PIDS); -+ if (valid_flags_set & KDBUS_ATTACH_PIDS) { -+ ASSERT_RETURN(item); -+ -+ /* Compare item->pids with cached PIDs */ -+ ASSERT_RETURN(item->pids.pid == cached_pids.pid && -+ item->pids.tid == cached_pids.tid && -+ item->pids.ppid == cached_pids.ppid); -+ } else { -+ ASSERT_RETURN(item == NULL); -+ } -+ -+ /* We did not request KDBUS_ITEM_CAPS */ -+ item = kdbus_get_item(info, KDBUS_ITEM_CAPS); -+ ASSERT_RETURN(item == NULL); -+ -+ kdbus_free(conn, offset); -+ -+ ret = kdbus_name_acquire(conn, "com.example.a", NULL); -+ ASSERT_RETURN(ret >= 0); -+ -+ ret = kdbus_conn_info(conn, conn->id, NULL, valid_flags, &offset); -+ ASSERT_RETURN(ret == 0); -+ -+ info = (struct kdbus_info *)(conn->buf + offset); -+ ASSERT_RETURN(info->id == conn->id); -+ -+ item = kdbus_get_item(info, KDBUS_ITEM_OWNED_NAME); -+ if (valid_flags_set & KDBUS_ATTACH_NAMES) { -+ ASSERT_RETURN(item && !strcmp(item->name.name, "com.example.a")); -+ } else { -+ ASSERT_RETURN(item == NULL); -+ } -+ -+ kdbus_free(conn, offset); -+ -+ ret = kdbus_conn_info(conn, 0, "com.example.a", valid_flags, &offset); -+ ASSERT_RETURN(ret == 0); -+ -+ info = (struct kdbus_info *)(conn->buf + offset); -+ ASSERT_RETURN(info->id == conn->id); -+ -+ kdbus_free(conn, offset); -+ -+ /* does not have the necessary caps to drop to unprivileged */ -+ if (!capable) -+ goto continue_test; -+ -+ ret = RUN_UNPRIVILEGED(UNPRIV_UID, UNPRIV_GID, ({ -+ ret = kdbus_conn_info(conn, conn->id, NULL, -+ valid_flags, &offset); -+ ASSERT_EXIT(ret == 0); -+ -+ info = (struct kdbus_info *)(conn->buf + offset); -+ ASSERT_EXIT(info->id == conn->id); -+ -+ if (valid_flags_set & KDBUS_ATTACH_NAMES) { -+ item = kdbus_get_item(info, KDBUS_ITEM_OWNED_NAME); -+ ASSERT_EXIT(item && -+ strcmp(item->name.name, -+ "com.example.a") == 0); -+ } -+ -+ if (valid_flags_set & KDBUS_ATTACH_CREDS) { -+ item = kdbus_get_item(info, KDBUS_ITEM_CREDS); -+ ASSERT_EXIT(item); -+ -+ /* Compare received items with cached creds */ -+ ASSERT_EXIT(memcmp(&item->creds, &cached_creds, -+ sizeof(struct kdbus_creds)) == 0); -+ } -+ -+ if (valid_flags_set & KDBUS_ATTACH_PIDS) { -+ item = kdbus_get_item(info, KDBUS_ITEM_PIDS); -+ ASSERT_EXIT(item); -+ -+ /* -+ * Compare item->pids with cached pids of -+ * privileged one. -+ * -+ * cmd_info will always return cached pids. -+ */ -+ ASSERT_EXIT(item->pids.pid == cached_pids.pid && -+ item->pids.tid == cached_pids.tid); -+ } -+ -+ kdbus_free(conn, offset); -+ -+ /* -+ * Use invalid_flags and make sure that userspace -+ * do not play with us. -+ */ -+ ret = kdbus_conn_info(conn, conn->id, NULL, -+ invalid_flags, &offset); -+ ASSERT_EXIT(ret == 0); -+ -+ /* -+ * Make sure that we return only one creds item and -+ * it points to the cached creds. -+ */ -+ cnt = kdbus_count_item(info, KDBUS_ITEM_CREDS); -+ if (invalid_flags_set & KDBUS_ATTACH_CREDS) { -+ ASSERT_EXIT(cnt == 1); -+ -+ item = kdbus_get_item(info, KDBUS_ITEM_CREDS); -+ ASSERT_EXIT(item); -+ -+ /* Compare received items with cached creds */ -+ ASSERT_EXIT(memcmp(&item->creds, &cached_creds, -+ sizeof(struct kdbus_creds)) == 0); -+ } else { -+ ASSERT_EXIT(cnt == 0); -+ } -+ -+ if (invalid_flags_set & KDBUS_ATTACH_PIDS) { -+ cnt = kdbus_count_item(info, KDBUS_ITEM_PIDS); -+ ASSERT_EXIT(cnt == 1); -+ -+ item = kdbus_get_item(info, KDBUS_ITEM_PIDS); -+ ASSERT_EXIT(item); -+ -+ /* Compare item->pids with cached pids */ -+ ASSERT_EXIT(item->pids.pid == cached_pids.pid && -+ item->pids.tid == cached_pids.tid); -+ } -+ -+ cnt = kdbus_count_item(info, KDBUS_ITEM_CGROUP); -+ if (invalid_flags_set & KDBUS_ATTACH_CGROUP) { -+ ASSERT_EXIT(cnt == 1); -+ } else { -+ ASSERT_EXIT(cnt == 0); -+ } -+ -+ cnt = kdbus_count_item(info, KDBUS_ITEM_CAPS); -+ if (invalid_flags_set & KDBUS_ATTACH_CAPS) { -+ ASSERT_EXIT(cnt == 1); -+ } else { -+ ASSERT_EXIT(cnt == 0); -+ } -+ -+ kdbus_free(conn, offset); -+ }), -+ ({ 0; })); -+ ASSERT_RETURN(ret == 0); -+ -+continue_test: -+ -+ /* A second name */ -+ ret = kdbus_name_acquire(conn, "com.example.b", NULL); -+ ASSERT_RETURN(ret >= 0); -+ -+ ret = kdbus_conn_info(conn, conn->id, NULL, valid_flags, &offset); -+ ASSERT_RETURN(ret == 0); -+ -+ info = (struct kdbus_info *)(conn->buf + offset); -+ ASSERT_RETURN(info->id == conn->id); -+ -+ cnt = kdbus_count_item(info, KDBUS_ITEM_OWNED_NAME); -+ if (valid_flags_set & KDBUS_ATTACH_NAMES) { -+ ASSERT_RETURN(cnt == 2); -+ } else { -+ ASSERT_RETURN(cnt == 0); -+ } -+ -+ kdbus_free(conn, offset); -+ -+ ASSERT_RETURN(ret == 0); -+ -+ return 0; -+} -+ -+int kdbus_test_conn_info(struct kdbus_test_env *env) -+{ -+ int ret; -+ int have_caps; -+ struct { -+ struct kdbus_cmd_info cmd_info; -+ -+ struct { -+ uint64_t size; -+ uint64_t type; -+ char str[64]; -+ } name; -+ } buf; -+ -+ buf.cmd_info.size = sizeof(struct kdbus_cmd_info); -+ buf.cmd_info.flags = 0; -+ buf.cmd_info.attach_flags = 0; -+ buf.cmd_info.id = env->conn->id; -+ -+ ret = kdbus_conn_info(env->conn, env->conn->id, NULL, 0, NULL); -+ ASSERT_RETURN(ret == 0); -+ -+ /* try to pass a name that is longer than the buffer's size */ -+ buf.name.size = KDBUS_ITEM_HEADER_SIZE + 1; -+ buf.name.type = KDBUS_ITEM_NAME; -+ strcpy(buf.name.str, "foo.bar.bla"); -+ -+ buf.cmd_info.id = 0; -+ buf.cmd_info.size = sizeof(buf.cmd_info) + buf.name.size; -+ ret = kdbus_cmd_conn_info(env->conn->fd, (struct kdbus_cmd_info *) &buf); -+ ASSERT_RETURN(ret == -EINVAL); -+ -+ /* Pass a non existent name */ -+ ret = kdbus_conn_info(env->conn, 0, "non.existent.name", 0, NULL); -+ ASSERT_RETURN(ret == -ESRCH); -+ -+ if (!all_uids_gids_are_mapped()) -+ return TEST_SKIP; -+ -+ /* Test for caps here, so we run the previous test */ -+ have_caps = test_is_capable(CAP_SETUID, CAP_SETGID, -1); -+ ASSERT_RETURN(have_caps >= 0); -+ -+ ret = kdbus_fuzz_conn_info(env, have_caps); -+ ASSERT_RETURN(ret == 0); -+ -+ /* Now if we have skipped some tests then let the user know */ -+ if (!have_caps) -+ return TEST_SKIP; -+ -+ return TEST_OK; -+} -+ -+int kdbus_test_conn_update(struct kdbus_test_env *env) -+{ -+ struct kdbus_conn *conn; -+ struct kdbus_msg *msg; -+ int found = 0; -+ int ret; -+ -+ /* -+ * kdbus_hello() sets all attach flags. Receive a message by this -+ * connection, and make sure a timestamp item (just to pick one) is -+ * present. -+ */ -+ conn = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(conn); -+ -+ ret = kdbus_msg_send(env->conn, NULL, 0x12345678, 0, 0, 0, conn->id); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_msg_recv(conn, &msg, NULL); -+ ASSERT_RETURN(ret == 0); -+ -+ found = kdbus_item_in_message(msg, KDBUS_ITEM_TIMESTAMP); -+ ASSERT_RETURN(found == 1); -+ -+ kdbus_msg_free(msg); -+ -+ /* -+ * Now, modify the attach flags and repeat the action. The item must -+ * now be missing. -+ */ -+ found = 0; -+ -+ ret = kdbus_conn_update_attach_flags(conn, -+ _KDBUS_ATTACH_ALL, -+ _KDBUS_ATTACH_ALL & -+ ~KDBUS_ATTACH_TIMESTAMP); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_msg_send(env->conn, NULL, 0x12345678, 0, 0, 0, conn->id); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_msg_recv(conn, &msg, NULL); -+ ASSERT_RETURN(ret == 0); -+ -+ found = kdbus_item_in_message(msg, KDBUS_ITEM_TIMESTAMP); -+ ASSERT_RETURN(found == 0); -+ -+ /* Provide a bogus attach_flags value */ -+ ret = kdbus_conn_update_attach_flags(conn, -+ _KDBUS_ATTACH_ALL + 1, -+ _KDBUS_ATTACH_ALL); -+ ASSERT_RETURN(ret == -EINVAL); -+ -+ kdbus_msg_free(msg); -+ -+ kdbus_conn_free(conn); -+ -+ return TEST_OK; -+} -+ -+int kdbus_test_writable_pool(struct kdbus_test_env *env) -+{ -+ struct kdbus_cmd_free cmd_free = {}; -+ struct kdbus_cmd_hello hello; -+ int fd, ret; -+ void *map; -+ -+ fd = open(env->buspath, O_RDWR | O_CLOEXEC); -+ ASSERT_RETURN(fd >= 0); -+ -+ memset(&hello, 0, sizeof(hello)); -+ hello.flags = KDBUS_HELLO_ACCEPT_FD; -+ hello.attach_flags_send = _KDBUS_ATTACH_ALL; -+ hello.attach_flags_recv = _KDBUS_ATTACH_ALL; -+ hello.size = sizeof(struct kdbus_cmd_hello); -+ hello.pool_size = POOL_SIZE; -+ hello.offset = (__u64)-1; -+ -+ /* success test */ -+ ret = kdbus_cmd_hello(fd, &hello); -+ ASSERT_RETURN(ret == 0); -+ -+ /* The kernel should have returned some items */ -+ ASSERT_RETURN(hello.offset != (__u64)-1); -+ cmd_free.size = sizeof(cmd_free); -+ cmd_free.offset = hello.offset; -+ ret = kdbus_cmd_free(fd, &cmd_free); -+ ASSERT_RETURN(ret >= 0); -+ -+ /* pools cannot be mapped writable */ -+ map = mmap(NULL, POOL_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); -+ ASSERT_RETURN(map == MAP_FAILED); -+ -+ /* pools can always be mapped readable */ -+ map = mmap(NULL, POOL_SIZE, PROT_READ, MAP_SHARED, fd, 0); -+ ASSERT_RETURN(map != MAP_FAILED); -+ -+ /* make sure we cannot change protection masks to writable */ -+ ret = mprotect(map, POOL_SIZE, PROT_READ | PROT_WRITE); -+ ASSERT_RETURN(ret < 0); -+ -+ munmap(map, POOL_SIZE); -+ close(fd); -+ -+ return TEST_OK; -+} -diff --git a/tools/testing/selftests/kdbus/test-daemon.c b/tools/testing/selftests/kdbus/test-daemon.c -new file mode 100644 -index 000000000000..8bc2386190d9 ---- /dev/null -+++ b/tools/testing/selftests/kdbus/test-daemon.c -@@ -0,0 +1,65 @@ -+#include <stdio.h> -+#include <string.h> -+#include <time.h> -+#include <fcntl.h> -+#include <stdlib.h> -+#include <stddef.h> -+#include <unistd.h> -+#include <stdint.h> -+#include <errno.h> -+#include <assert.h> -+#include <poll.h> -+#include <stdbool.h> -+ -+#include "kdbus-test.h" -+#include "kdbus-util.h" -+#include "kdbus-enum.h" -+ -+int kdbus_test_daemon(struct kdbus_test_env *env) -+{ -+ struct pollfd fds[2]; -+ int count; -+ int ret; -+ -+ /* This test doesn't make any sense in non-interactive mode */ -+ if (!kdbus_util_verbose) -+ return TEST_OK; -+ -+ printf("Created connection %llu on bus '%s'\n", -+ (unsigned long long) env->conn->id, env->buspath); -+ -+ ret = kdbus_name_acquire(env->conn, "com.example.kdbus-test", NULL); -+ ASSERT_RETURN(ret == 0); -+ printf(" Aquired name: com.example.kdbus-test\n"); -+ -+ fds[0].fd = env->conn->fd; -+ fds[1].fd = STDIN_FILENO; -+ -+ printf("Monitoring connections:\n"); -+ -+ for (count = 0;; count++) { -+ int i, nfds = sizeof(fds) / sizeof(fds[0]); -+ -+ for (i = 0; i < nfds; i++) { -+ fds[i].events = POLLIN | POLLPRI | POLLHUP; -+ fds[i].revents = 0; -+ } -+ -+ ret = poll(fds, nfds, -1); -+ if (ret <= 0) -+ break; -+ -+ if (fds[0].revents & POLLIN) { -+ ret = kdbus_msg_recv(env->conn, NULL, NULL); -+ ASSERT_RETURN(ret == 0); -+ } -+ -+ /* stdin */ -+ if (fds[1].revents & POLLIN) -+ break; -+ } -+ -+ printf("Closing bus connection\n"); -+ -+ return TEST_OK; -+} -diff --git a/tools/testing/selftests/kdbus/test-endpoint.c b/tools/testing/selftests/kdbus/test-endpoint.c -new file mode 100644 -index 000000000000..dcc6ab91c4e6 ---- /dev/null -+++ b/tools/testing/selftests/kdbus/test-endpoint.c -@@ -0,0 +1,341 @@ -+#include <stdio.h> -+#include <string.h> -+#include <fcntl.h> -+#include <stdlib.h> -+#include <stddef.h> -+#include <unistd.h> -+#include <stdint.h> -+#include <errno.h> -+#include <assert.h> -+#include <libgen.h> -+#include <sys/capability.h> -+#include <sys/wait.h> -+#include <stdbool.h> -+ -+#include "kdbus-api.h" -+#include "kdbus-util.h" -+#include "kdbus-enum.h" -+#include "kdbus-test.h" -+ -+#define KDBUS_SYSNAME_MAX_LEN 63 -+ -+static int install_name_add_match(struct kdbus_conn *conn, const char *name) -+{ -+ struct { -+ struct kdbus_cmd_match cmd; -+ struct { -+ uint64_t size; -+ uint64_t type; -+ struct kdbus_notify_name_change chg; -+ } item; -+ char name[64]; -+ } buf; -+ int ret; -+ -+ /* install the match rule */ -+ memset(&buf, 0, sizeof(buf)); -+ buf.item.type = KDBUS_ITEM_NAME_ADD; -+ buf.item.chg.old_id.id = KDBUS_MATCH_ID_ANY; -+ buf.item.chg.new_id.id = KDBUS_MATCH_ID_ANY; -+ strncpy(buf.name, name, sizeof(buf.name) - 1); -+ buf.item.size = sizeof(buf.item) + strlen(buf.name) + 1; -+ buf.cmd.size = sizeof(buf.cmd) + buf.item.size; -+ -+ ret = kdbus_cmd_match_add(conn->fd, &buf.cmd); -+ if (ret < 0) -+ return ret; -+ -+ return 0; -+} -+ -+static int create_endpoint(const char *buspath, uid_t uid, const char *name, -+ uint64_t flags) -+{ -+ struct { -+ struct kdbus_cmd cmd; -+ -+ /* name item */ -+ struct { -+ uint64_t size; -+ uint64_t type; -+ /* max should be KDBUS_SYSNAME_MAX_LEN */ -+ char str[128]; -+ } name; -+ } ep_make; -+ int fd, ret; -+ -+ fd = open(buspath, O_RDWR); -+ if (fd < 0) -+ return fd; -+ -+ memset(&ep_make, 0, sizeof(ep_make)); -+ -+ snprintf(ep_make.name.str, -+ /* Use the KDBUS_SYSNAME_MAX_LEN or sizeof(str) */ -+ KDBUS_SYSNAME_MAX_LEN > strlen(name) ? -+ KDBUS_SYSNAME_MAX_LEN : sizeof(ep_make.name.str), -+ "%u-%s", uid, name); -+ -+ ep_make.name.type = KDBUS_ITEM_MAKE_NAME; -+ ep_make.name.size = KDBUS_ITEM_HEADER_SIZE + -+ strlen(ep_make.name.str) + 1; -+ -+ ep_make.cmd.flags = flags; -+ ep_make.cmd.size = sizeof(ep_make.cmd) + ep_make.name.size; -+ -+ ret = kdbus_cmd_endpoint_make(fd, &ep_make.cmd); -+ if (ret < 0) { -+ kdbus_printf("error creating endpoint: %d (%m)\n", ret); -+ return ret; -+ } -+ -+ return fd; -+} -+ -+static int unpriv_test_custom_ep(const char *buspath) -+{ -+ int ret, ep_fd1, ep_fd2; -+ char *ep1, *ep2, *tmp1, *tmp2; -+ -+ tmp1 = strdup(buspath); -+ tmp2 = strdup(buspath); -+ ASSERT_RETURN(tmp1 && tmp2); -+ -+ ret = asprintf(&ep1, "%s/%u-%s", dirname(tmp1), getuid(), "apps1"); -+ ASSERT_RETURN(ret >= 0); -+ -+ ret = asprintf(&ep2, "%s/%u-%s", dirname(tmp2), getuid(), "apps2"); -+ ASSERT_RETURN(ret >= 0); -+ -+ free(tmp1); -+ free(tmp2); -+ -+ /* endpoint only accessible to current uid */ -+ ep_fd1 = create_endpoint(buspath, getuid(), "apps1", 0); -+ ASSERT_RETURN(ep_fd1 >= 0); -+ -+ /* endpoint world accessible */ -+ ep_fd2 = create_endpoint(buspath, getuid(), "apps2", -+ KDBUS_MAKE_ACCESS_WORLD); -+ ASSERT_RETURN(ep_fd2 >= 0); -+ -+ ret = RUN_UNPRIVILEGED(UNPRIV_UID, UNPRIV_UID, ({ -+ int ep_fd; -+ struct kdbus_conn *ep_conn; -+ -+ /* -+ * Make sure that we are not able to create custom -+ * endpoints -+ */ -+ ep_fd = create_endpoint(buspath, getuid(), -+ "unpriv_costum_ep", 0); -+ ASSERT_EXIT(ep_fd == -EPERM); -+ -+ /* -+ * Endpoint "apps1" only accessible to same users, -+ * that own the endpoint. Access denied by VFS -+ */ -+ ep_conn = kdbus_hello(ep1, 0, NULL, 0); -+ ASSERT_EXIT(!ep_conn && errno == EACCES); -+ -+ /* Endpoint "apps2" world accessible */ -+ ep_conn = kdbus_hello(ep2, 0, NULL, 0); -+ ASSERT_EXIT(ep_conn); -+ -+ kdbus_conn_free(ep_conn); -+ -+ _exit(EXIT_SUCCESS); -+ }), -+ ({ 0; })); -+ ASSERT_RETURN(ret == 0); -+ -+ close(ep_fd1); -+ close(ep_fd2); -+ free(ep1); -+ free(ep2); -+ -+ return 0; -+} -+ -+static int update_endpoint(int fd, const char *name) -+{ -+ int len = strlen(name) + 1; -+ struct { -+ struct kdbus_cmd cmd; -+ -+ /* name item */ -+ struct { -+ uint64_t size; -+ uint64_t type; -+ char str[KDBUS_ALIGN8(len)]; -+ } name; -+ -+ struct { -+ uint64_t size; -+ uint64_t type; -+ struct kdbus_policy_access access; -+ } access; -+ } ep_update; -+ int ret; -+ -+ memset(&ep_update, 0, sizeof(ep_update)); -+ -+ ep_update.name.size = KDBUS_ITEM_HEADER_SIZE + len; -+ ep_update.name.type = KDBUS_ITEM_NAME; -+ strncpy(ep_update.name.str, name, sizeof(ep_update.name.str) - 1); -+ -+ ep_update.access.size = sizeof(ep_update.access); -+ ep_update.access.type = KDBUS_ITEM_POLICY_ACCESS; -+ ep_update.access.access.type = KDBUS_POLICY_ACCESS_WORLD; -+ ep_update.access.access.access = KDBUS_POLICY_SEE; -+ -+ ep_update.cmd.size = sizeof(ep_update); -+ -+ ret = kdbus_cmd_endpoint_update(fd, &ep_update.cmd); -+ if (ret < 0) { -+ kdbus_printf("error updating endpoint: %d (%m)\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+int kdbus_test_custom_endpoint(struct kdbus_test_env *env) -+{ -+ char *ep, *tmp; -+ int ret, ep_fd; -+ struct kdbus_msg *msg; -+ struct kdbus_conn *ep_conn; -+ struct kdbus_conn *reader; -+ const char *name = "foo.bar.baz"; -+ const char *epname = "foo"; -+ char fake_ep[KDBUS_SYSNAME_MAX_LEN + 1] = {'\0'}; -+ -+ memset(fake_ep, 'X', sizeof(fake_ep) - 1); -+ -+ /* Try to create a custom endpoint with a long name */ -+ ret = create_endpoint(env->buspath, getuid(), fake_ep, 0); -+ ASSERT_RETURN(ret == -ENAMETOOLONG); -+ -+ /* Try to create a custom endpoint with a different uid */ -+ ret = create_endpoint(env->buspath, getuid() + 1, "foobar", 0); -+ ASSERT_RETURN(ret == -EINVAL); -+ -+ /* create a custom endpoint, and open a connection on it */ -+ ep_fd = create_endpoint(env->buspath, getuid(), "foo", 0); -+ ASSERT_RETURN(ep_fd >= 0); -+ -+ tmp = strdup(env->buspath); -+ ASSERT_RETURN(tmp); -+ -+ ret = asprintf(&ep, "%s/%u-%s", dirname(tmp), getuid(), epname); -+ free(tmp); -+ ASSERT_RETURN(ret >= 0); -+ -+ /* Register a connection that listen to broadcasts */ -+ reader = kdbus_hello(ep, 0, NULL, 0); -+ ASSERT_RETURN(reader); -+ -+ /* Register to kernel signals */ -+ ret = kdbus_add_match_id(reader, 0x1, KDBUS_ITEM_ID_ADD, -+ KDBUS_MATCH_ID_ANY); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_add_match_id(reader, 0x2, KDBUS_ITEM_ID_REMOVE, -+ KDBUS_MATCH_ID_ANY); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = install_name_add_match(reader, name); -+ ASSERT_RETURN(ret == 0); -+ -+ /* Monitor connections are not supported on custom endpoints */ -+ ep_conn = kdbus_hello(ep, KDBUS_HELLO_MONITOR, NULL, 0); -+ ASSERT_RETURN(!ep_conn && errno == EOPNOTSUPP); -+ -+ ep_conn = kdbus_hello(ep, 0, NULL, 0); -+ ASSERT_RETURN(ep_conn); -+ -+ /* -+ * Add a name add match on the endpoint connection, acquire name from -+ * the unfiltered connection, and make sure the filtered connection -+ * did not get the notification on the name owner change. Also, the -+ * endpoint connection may not be able to call conn_info, neither on -+ * the name nor on the ID. -+ */ -+ ret = install_name_add_match(ep_conn, name); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_name_acquire(env->conn, name, NULL); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_msg_recv(ep_conn, NULL, NULL); -+ ASSERT_RETURN(ret == -EAGAIN); -+ -+ ret = kdbus_conn_info(ep_conn, 0, name, 0, NULL); -+ ASSERT_RETURN(ret == -ESRCH); -+ -+ ret = kdbus_conn_info(ep_conn, 0, "random.crappy.name", 0, NULL); -+ ASSERT_RETURN(ret == -ESRCH); -+ -+ ret = kdbus_conn_info(ep_conn, env->conn->id, NULL, 0, NULL); -+ ASSERT_RETURN(ret == -ENXIO); -+ -+ ret = kdbus_conn_info(ep_conn, 0x0fffffffffffffffULL, NULL, 0, NULL); -+ ASSERT_RETURN(ret == -ENXIO); -+ -+ /* Check that the reader did not receive anything */ -+ ret = kdbus_msg_recv(reader, NULL, NULL); -+ ASSERT_RETURN(ret == -EAGAIN); -+ -+ /* -+ * Release the name again, update the custom endpoint policy, -+ * and try again. This time, the connection on the custom endpoint -+ * should have gotten it. -+ */ -+ ret = kdbus_name_release(env->conn, name); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = update_endpoint(ep_fd, name); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_name_acquire(env->conn, name, NULL); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_msg_recv(ep_conn, &msg, NULL); -+ ASSERT_RETURN(ret == 0); -+ ASSERT_RETURN(msg->items[0].type == KDBUS_ITEM_NAME_ADD); -+ ASSERT_RETURN(msg->items[0].name_change.old_id.id == 0); -+ ASSERT_RETURN(msg->items[0].name_change.new_id.id == env->conn->id); -+ ASSERT_RETURN(strcmp(msg->items[0].name_change.name, name) == 0); -+ kdbus_msg_free(msg); -+ -+ ret = kdbus_msg_recv(reader, &msg, NULL); -+ ASSERT_RETURN(ret == 0); -+ ASSERT_RETURN(strcmp(msg->items[0].name_change.name, name) == 0); -+ -+ kdbus_msg_free(msg); -+ -+ ret = kdbus_conn_info(ep_conn, 0, name, 0, NULL); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_conn_info(ep_conn, env->conn->id, NULL, 0, NULL); -+ ASSERT_RETURN(ret == 0); -+ -+ /* If we have privileges test custom endpoints */ -+ ret = test_is_capable(CAP_SETUID, CAP_SETGID, -1); -+ ASSERT_RETURN(ret >= 0); -+ -+ /* -+ * All uids/gids are mapped and we have the necessary caps -+ */ -+ if (ret && all_uids_gids_are_mapped()) { -+ ret = unpriv_test_custom_ep(env->buspath); -+ ASSERT_RETURN(ret == 0); -+ } -+ -+ kdbus_conn_free(reader); -+ kdbus_conn_free(ep_conn); -+ close(ep_fd); -+ -+ return TEST_OK; -+} -diff --git a/tools/testing/selftests/kdbus/test-fd.c b/tools/testing/selftests/kdbus/test-fd.c -new file mode 100644 -index 000000000000..2ae0f5ae8fd0 ---- /dev/null -+++ b/tools/testing/selftests/kdbus/test-fd.c -@@ -0,0 +1,789 @@ -+#include <stdio.h> -+#include <string.h> -+#include <time.h> -+#include <fcntl.h> -+#include <stdlib.h> -+#include <stdbool.h> -+#include <stddef.h> -+#include <unistd.h> -+#include <stdint.h> -+#include <errno.h> -+#include <assert.h> -+#include <sys/types.h> -+#include <sys/mman.h> -+#include <sys/socket.h> -+#include <sys/wait.h> -+ -+#include "kdbus-api.h" -+#include "kdbus-test.h" -+#include "kdbus-util.h" -+#include "kdbus-enum.h" -+ -+#define KDBUS_MSG_MAX_ITEMS 128 -+#define KDBUS_USER_MAX_CONN 256 -+ -+/* maximum number of inflight fds in a target queue per user */ -+#define KDBUS_CONN_MAX_FDS_PER_USER 16 -+ -+/* maximum number of memfd items per message */ -+#define KDBUS_MSG_MAX_MEMFD_ITEMS 16 -+ -+static int make_msg_payload_dbus(uint64_t src_id, uint64_t dst_id, -+ uint64_t msg_size, -+ struct kdbus_msg **msg_dbus) -+{ -+ struct kdbus_msg *msg; -+ -+ msg = malloc(msg_size); -+ ASSERT_RETURN_VAL(msg, -ENOMEM); -+ -+ memset(msg, 0, msg_size); -+ msg->size = msg_size; -+ msg->src_id = src_id; -+ msg->dst_id = dst_id; -+ msg->payload_type = KDBUS_PAYLOAD_DBUS; -+ -+ *msg_dbus = msg; -+ -+ return 0; -+} -+ -+static void make_item_memfds(struct kdbus_item *item, -+ int *memfds, size_t memfd_size) -+{ -+ size_t i; -+ -+ for (i = 0; i < memfd_size; i++) { -+ item->type = KDBUS_ITEM_PAYLOAD_MEMFD; -+ item->size = KDBUS_ITEM_HEADER_SIZE + -+ sizeof(struct kdbus_memfd); -+ item->memfd.fd = memfds[i]; -+ item->memfd.size = sizeof(uint64_t); /* const size */ -+ item = KDBUS_ITEM_NEXT(item); -+ } -+} -+ -+static void make_item_fds(struct kdbus_item *item, -+ int *fd_array, size_t fd_size) -+{ -+ size_t i; -+ item->type = KDBUS_ITEM_FDS; -+ item->size = KDBUS_ITEM_HEADER_SIZE + (sizeof(int) * fd_size); -+ -+ for (i = 0; i < fd_size; i++) -+ item->fds[i] = fd_array[i]; -+} -+ -+static int memfd_write(const char *name, void *buf, size_t bufsize) -+{ -+ ssize_t ret; -+ int memfd; -+ -+ memfd = sys_memfd_create(name, 0); -+ ASSERT_RETURN_VAL(memfd >= 0, memfd); -+ -+ ret = write(memfd, buf, bufsize); -+ ASSERT_RETURN_VAL(ret == (ssize_t)bufsize, -EAGAIN); -+ -+ ret = sys_memfd_seal_set(memfd); -+ ASSERT_RETURN_VAL(ret == 0, -errno); -+ -+ return memfd; -+} -+ -+static int send_memfds(struct kdbus_conn *conn, uint64_t dst_id, -+ int *memfds_array, size_t memfd_count) -+{ -+ struct kdbus_cmd_send cmd = {}; -+ struct kdbus_item *item; -+ struct kdbus_msg *msg; -+ uint64_t size; -+ int ret; -+ -+ size = sizeof(struct kdbus_msg); -+ size += memfd_count * KDBUS_ITEM_SIZE(sizeof(struct kdbus_memfd)); -+ -+ if (dst_id == KDBUS_DST_ID_BROADCAST) -+ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_bloom_filter)) + 64; -+ -+ ret = make_msg_payload_dbus(conn->id, dst_id, size, &msg); -+ ASSERT_RETURN_VAL(ret == 0, ret); -+ -+ item = msg->items; -+ -+ if (dst_id == KDBUS_DST_ID_BROADCAST) { -+ item->type = KDBUS_ITEM_BLOOM_FILTER; -+ item->size = KDBUS_ITEM_SIZE(sizeof(struct kdbus_bloom_filter)) + 64; -+ item = KDBUS_ITEM_NEXT(item); -+ -+ msg->flags |= KDBUS_MSG_SIGNAL; -+ } -+ -+ make_item_memfds(item, memfds_array, memfd_count); -+ -+ cmd.size = sizeof(cmd); -+ cmd.msg_address = (uintptr_t)msg; -+ -+ ret = kdbus_cmd_send(conn->fd, &cmd); -+ if (ret < 0) { -+ kdbus_printf("error sending message: %d (%m)\n", ret); -+ return ret; -+ } -+ -+ free(msg); -+ return 0; -+} -+ -+static int send_fds(struct kdbus_conn *conn, uint64_t dst_id, -+ int *fd_array, size_t fd_count) -+{ -+ struct kdbus_cmd_send cmd = {}; -+ struct kdbus_item *item; -+ struct kdbus_msg *msg; -+ uint64_t size; -+ int ret; -+ -+ size = sizeof(struct kdbus_msg); -+ size += KDBUS_ITEM_SIZE(sizeof(int) * fd_count); -+ -+ if (dst_id == KDBUS_DST_ID_BROADCAST) -+ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_bloom_filter)) + 64; -+ -+ ret = make_msg_payload_dbus(conn->id, dst_id, size, &msg); -+ ASSERT_RETURN_VAL(ret == 0, ret); -+ -+ item = msg->items; -+ -+ if (dst_id == KDBUS_DST_ID_BROADCAST) { -+ item->type = KDBUS_ITEM_BLOOM_FILTER; -+ item->size = KDBUS_ITEM_SIZE(sizeof(struct kdbus_bloom_filter)) + 64; -+ item = KDBUS_ITEM_NEXT(item); -+ -+ msg->flags |= KDBUS_MSG_SIGNAL; -+ } -+ -+ make_item_fds(item, fd_array, fd_count); -+ -+ cmd.size = sizeof(cmd); -+ cmd.msg_address = (uintptr_t)msg; -+ -+ ret = kdbus_cmd_send(conn->fd, &cmd); -+ if (ret < 0) { -+ kdbus_printf("error sending message: %d (%m)\n", ret); -+ return ret; -+ } -+ -+ free(msg); -+ return ret; -+} -+ -+static int send_fds_memfds(struct kdbus_conn *conn, uint64_t dst_id, -+ int *fds_array, size_t fd_count, -+ int *memfds_array, size_t memfd_count) -+{ -+ struct kdbus_cmd_send cmd = {}; -+ struct kdbus_item *item; -+ struct kdbus_msg *msg; -+ uint64_t size; -+ int ret; -+ -+ size = sizeof(struct kdbus_msg); -+ size += memfd_count * KDBUS_ITEM_SIZE(sizeof(struct kdbus_memfd)); -+ size += KDBUS_ITEM_SIZE(sizeof(int) * fd_count); -+ -+ ret = make_msg_payload_dbus(conn->id, dst_id, size, &msg); -+ ASSERT_RETURN_VAL(ret == 0, ret); -+ -+ item = msg->items; -+ -+ make_item_fds(item, fds_array, fd_count); -+ item = KDBUS_ITEM_NEXT(item); -+ make_item_memfds(item, memfds_array, memfd_count); -+ -+ cmd.size = sizeof(cmd); -+ cmd.msg_address = (uintptr_t)msg; -+ -+ ret = kdbus_cmd_send(conn->fd, &cmd); -+ if (ret < 0) { -+ kdbus_printf("error sending message: %d (%m)\n", ret); -+ return ret; -+ } -+ -+ free(msg); -+ return ret; -+} -+ -+/* Return the number of received fds */ -+static unsigned int kdbus_item_get_nfds(struct kdbus_msg *msg) -+{ -+ unsigned int fds = 0; -+ const struct kdbus_item *item; -+ -+ KDBUS_ITEM_FOREACH(item, msg, items) { -+ switch (item->type) { -+ case KDBUS_ITEM_FDS: { -+ fds += (item->size - KDBUS_ITEM_HEADER_SIZE) / -+ sizeof(int); -+ break; -+ } -+ -+ case KDBUS_ITEM_PAYLOAD_MEMFD: -+ fds++; -+ break; -+ -+ default: -+ break; -+ } -+ } -+ -+ return fds; -+} -+ -+static struct kdbus_msg * -+get_kdbus_msg_with_fd(struct kdbus_conn *conn_src, -+ uint64_t dst_id, uint64_t cookie, int fd) -+{ -+ int ret; -+ uint64_t size; -+ struct kdbus_item *item; -+ struct kdbus_msg *msg; -+ -+ size = sizeof(struct kdbus_msg); -+ if (fd >= 0) -+ size += KDBUS_ITEM_SIZE(sizeof(int)); -+ -+ ret = make_msg_payload_dbus(conn_src->id, dst_id, size, &msg); -+ ASSERT_RETURN_VAL(ret == 0, NULL); -+ -+ msg->cookie = cookie; -+ -+ if (fd >= 0) { -+ item = msg->items; -+ -+ make_item_fds(item, (int *)&fd, 1); -+ } -+ -+ return msg; -+} -+ -+static int kdbus_test_no_fds(struct kdbus_test_env *env, -+ int *fds, int *memfd) -+{ -+ pid_t pid; -+ int ret, status; -+ uint64_t cookie; -+ int connfd1, connfd2; -+ struct kdbus_msg *msg, *msg_sync_reply; -+ struct kdbus_cmd_hello hello; -+ struct kdbus_conn *conn_src, *conn_dst, *conn_dummy; -+ struct kdbus_cmd_send cmd = {}; -+ struct kdbus_cmd_free cmd_free = {}; -+ -+ conn_src = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(conn_src); -+ -+ connfd1 = open(env->buspath, O_RDWR|O_CLOEXEC); -+ ASSERT_RETURN(connfd1 >= 0); -+ -+ connfd2 = open(env->buspath, O_RDWR|O_CLOEXEC); -+ ASSERT_RETURN(connfd2 >= 0); -+ -+ /* -+ * Create connections without KDBUS_HELLO_ACCEPT_FD -+ * to test if send fd operations are blocked -+ */ -+ conn_dst = malloc(sizeof(*conn_dst)); -+ ASSERT_RETURN(conn_dst); -+ -+ conn_dummy = malloc(sizeof(*conn_dummy)); -+ ASSERT_RETURN(conn_dummy); -+ -+ memset(&hello, 0, sizeof(hello)); -+ hello.size = sizeof(struct kdbus_cmd_hello); -+ hello.pool_size = POOL_SIZE; -+ hello.attach_flags_send = _KDBUS_ATTACH_ALL; -+ -+ ret = kdbus_cmd_hello(connfd1, &hello); -+ ASSERT_RETURN(ret == 0); -+ -+ cmd_free.size = sizeof(cmd_free); -+ cmd_free.offset = hello.offset; -+ ret = kdbus_cmd_free(connfd1, &cmd_free); -+ ASSERT_RETURN(ret >= 0); -+ -+ conn_dst->fd = connfd1; -+ conn_dst->id = hello.id; -+ -+ memset(&hello, 0, sizeof(hello)); -+ hello.size = sizeof(struct kdbus_cmd_hello); -+ hello.pool_size = POOL_SIZE; -+ hello.attach_flags_send = _KDBUS_ATTACH_ALL; -+ -+ ret = kdbus_cmd_hello(connfd2, &hello); -+ ASSERT_RETURN(ret == 0); -+ -+ cmd_free.size = sizeof(cmd_free); -+ cmd_free.offset = hello.offset; -+ ret = kdbus_cmd_free(connfd2, &cmd_free); -+ ASSERT_RETURN(ret >= 0); -+ -+ conn_dummy->fd = connfd2; -+ conn_dummy->id = hello.id; -+ -+ conn_dst->buf = mmap(NULL, POOL_SIZE, PROT_READ, -+ MAP_SHARED, connfd1, 0); -+ ASSERT_RETURN(conn_dst->buf != MAP_FAILED); -+ -+ conn_dummy->buf = mmap(NULL, POOL_SIZE, PROT_READ, -+ MAP_SHARED, connfd2, 0); -+ ASSERT_RETURN(conn_dummy->buf != MAP_FAILED); -+ -+ /* -+ * Send fds to connection that do not accept fd passing -+ */ -+ ret = send_fds(conn_src, conn_dst->id, fds, 1); -+ ASSERT_RETURN(ret == -ECOMM); -+ -+ /* -+ * memfd are kdbus payload -+ */ -+ ret = send_memfds(conn_src, conn_dst->id, memfd, 1); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_msg_recv_poll(conn_dst, 100, NULL, NULL); -+ ASSERT_RETURN(ret == 0); -+ -+ cookie = time(NULL); -+ -+ pid = fork(); -+ ASSERT_RETURN_VAL(pid >= 0, pid); -+ -+ if (pid == 0) { -+ struct timespec now; -+ -+ /* -+ * A sync send/reply to a connection that do not -+ * accept fds should fail if it contains an fd -+ */ -+ msg_sync_reply = get_kdbus_msg_with_fd(conn_dst, -+ conn_dummy->id, -+ cookie, fds[0]); -+ ASSERT_EXIT(msg_sync_reply); -+ -+ ret = clock_gettime(CLOCK_MONOTONIC_COARSE, &now); -+ ASSERT_EXIT(ret == 0); -+ -+ msg_sync_reply->timeout_ns = now.tv_sec * 1000000000ULL + -+ now.tv_nsec + 100000000ULL; -+ msg_sync_reply->flags = KDBUS_MSG_EXPECT_REPLY; -+ -+ memset(&cmd, 0, sizeof(cmd)); -+ cmd.size = sizeof(cmd); -+ cmd.msg_address = (uintptr_t)msg_sync_reply; -+ cmd.flags = KDBUS_SEND_SYNC_REPLY; -+ -+ ret = kdbus_cmd_send(conn_dst->fd, &cmd); -+ ASSERT_EXIT(ret == -ECOMM); -+ -+ /* -+ * Now send a normal message, but the sync reply -+ * will fail since it contains an fd that the -+ * original sender do not want. -+ * -+ * The original sender will fail with -ETIMEDOUT -+ */ -+ cookie++; -+ ret = kdbus_msg_send_sync(conn_dst, NULL, cookie, -+ KDBUS_MSG_EXPECT_REPLY, -+ 5000000000ULL, 0, conn_src->id, -1); -+ ASSERT_EXIT(ret == -EREMOTEIO); -+ -+ cookie++; -+ ret = kdbus_msg_recv_poll(conn_dst, 100, &msg, NULL); -+ ASSERT_EXIT(ret == 0); -+ ASSERT_EXIT(msg->cookie == cookie); -+ -+ free(msg_sync_reply); -+ kdbus_msg_free(msg); -+ -+ _exit(EXIT_SUCCESS); -+ } -+ -+ ret = kdbus_msg_recv_poll(conn_dummy, 100, NULL, NULL); -+ ASSERT_RETURN(ret == -ETIMEDOUT); -+ -+ cookie++; -+ ret = kdbus_msg_recv_poll(conn_src, 100, &msg, NULL); -+ ASSERT_RETURN(ret == 0 && msg->cookie == cookie); -+ -+ kdbus_msg_free(msg); -+ -+ /* -+ * Try to reply with a kdbus connection handle, this should -+ * fail with -EOPNOTSUPP -+ */ -+ msg_sync_reply = get_kdbus_msg_with_fd(conn_src, -+ conn_dst->id, -+ cookie, conn_dst->fd); -+ ASSERT_RETURN(msg_sync_reply); -+ -+ msg_sync_reply->cookie_reply = cookie; -+ -+ memset(&cmd, 0, sizeof(cmd)); -+ cmd.size = sizeof(cmd); -+ cmd.msg_address = (uintptr_t)msg_sync_reply; -+ -+ ret = kdbus_cmd_send(conn_src->fd, &cmd); -+ ASSERT_RETURN(ret == -EOPNOTSUPP); -+ -+ free(msg_sync_reply); -+ -+ /* -+ * Try to reply with a normal fd, this should fail even -+ * if the response is a sync reply -+ * -+ * From the sender view we fail with -ECOMM -+ */ -+ msg_sync_reply = get_kdbus_msg_with_fd(conn_src, -+ conn_dst->id, -+ cookie, fds[0]); -+ ASSERT_RETURN(msg_sync_reply); -+ -+ msg_sync_reply->cookie_reply = cookie; -+ -+ memset(&cmd, 0, sizeof(cmd)); -+ cmd.size = sizeof(cmd); -+ cmd.msg_address = (uintptr_t)msg_sync_reply; -+ -+ ret = kdbus_cmd_send(conn_src->fd, &cmd); -+ ASSERT_RETURN(ret == -ECOMM); -+ -+ free(msg_sync_reply); -+ -+ /* -+ * Resend another normal message and check if the queue -+ * is clear -+ */ -+ cookie++; -+ ret = kdbus_msg_send(conn_src, NULL, cookie, 0, 0, 0, -+ conn_dst->id); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = waitpid(pid, &status, 0); -+ ASSERT_RETURN_VAL(ret >= 0, ret); -+ -+ kdbus_conn_free(conn_dummy); -+ kdbus_conn_free(conn_dst); -+ kdbus_conn_free(conn_src); -+ -+ return (status == EXIT_SUCCESS) ? TEST_OK : TEST_ERR; -+} -+ -+static int kdbus_send_multiple_fds(struct kdbus_conn *conn_src, -+ struct kdbus_conn *conn_dst) -+{ -+ int ret, i; -+ unsigned int nfds; -+ int fds[KDBUS_CONN_MAX_FDS_PER_USER + 1]; -+ int memfds[KDBUS_MSG_MAX_ITEMS + 1]; -+ struct kdbus_msg *msg; -+ uint64_t dummy_value; -+ -+ dummy_value = time(NULL); -+ -+ for (i = 0; i < KDBUS_CONN_MAX_FDS_PER_USER + 1; i++) { -+ fds[i] = open("/dev/null", O_RDWR|O_CLOEXEC); -+ ASSERT_RETURN_VAL(fds[i] >= 0, -errno); -+ } -+ -+ /* Send KDBUS_CONN_MAX_FDS_PER_USER with one more fd */ -+ ret = send_fds(conn_src, conn_dst->id, fds, -+ KDBUS_CONN_MAX_FDS_PER_USER + 1); -+ ASSERT_RETURN(ret == -EMFILE); -+ -+ /* Retry with the correct KDBUS_CONN_MAX_FDS_PER_USER */ -+ ret = send_fds(conn_src, conn_dst->id, fds, -+ KDBUS_CONN_MAX_FDS_PER_USER); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_msg_recv(conn_dst, &msg, NULL); -+ ASSERT_RETURN(ret == 0); -+ -+ /* Check we got the right number of fds */ -+ nfds = kdbus_item_get_nfds(msg); -+ ASSERT_RETURN(nfds == KDBUS_CONN_MAX_FDS_PER_USER); -+ -+ kdbus_msg_free(msg); -+ -+ for (i = 0; i < KDBUS_MSG_MAX_ITEMS + 1; i++, dummy_value++) { -+ memfds[i] = memfd_write("memfd-name", -+ &dummy_value, -+ sizeof(dummy_value)); -+ ASSERT_RETURN_VAL(memfds[i] >= 0, memfds[i]); -+ } -+ -+ /* Send KDBUS_MSG_MAX_ITEMS with one more memfd */ -+ ret = send_memfds(conn_src, conn_dst->id, -+ memfds, KDBUS_MSG_MAX_ITEMS + 1); -+ ASSERT_RETURN(ret == -E2BIG); -+ -+ ret = send_memfds(conn_src, conn_dst->id, -+ memfds, KDBUS_MSG_MAX_MEMFD_ITEMS + 1); -+ ASSERT_RETURN(ret == -E2BIG); -+ -+ /* Retry with the correct KDBUS_MSG_MAX_ITEMS */ -+ ret = send_memfds(conn_src, conn_dst->id, -+ memfds, KDBUS_MSG_MAX_MEMFD_ITEMS); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_msg_recv(conn_dst, &msg, NULL); -+ ASSERT_RETURN(ret == 0); -+ -+ /* Check we got the right number of fds */ -+ nfds = kdbus_item_get_nfds(msg); -+ ASSERT_RETURN(nfds == KDBUS_MSG_MAX_MEMFD_ITEMS); -+ -+ kdbus_msg_free(msg); -+ -+ -+ /* -+ * Combine multiple KDBUS_CONN_MAX_FDS_PER_USER+1 fds and -+ * 10 memfds -+ */ -+ ret = send_fds_memfds(conn_src, conn_dst->id, -+ fds, KDBUS_CONN_MAX_FDS_PER_USER + 1, -+ memfds, 10); -+ ASSERT_RETURN(ret == -EMFILE); -+ -+ ret = kdbus_msg_recv(conn_dst, NULL, NULL); -+ ASSERT_RETURN(ret == -EAGAIN); -+ -+ /* -+ * Combine multiple KDBUS_CONN_MAX_FDS_PER_USER fds and -+ * (128 - 1) + 1 memfds, all fds take one item, while each -+ * memfd takes one item -+ */ -+ ret = send_fds_memfds(conn_src, conn_dst->id, -+ fds, KDBUS_CONN_MAX_FDS_PER_USER, -+ memfds, (KDBUS_MSG_MAX_ITEMS - 1) + 1); -+ ASSERT_RETURN(ret == -E2BIG); -+ -+ ret = send_fds_memfds(conn_src, conn_dst->id, -+ fds, KDBUS_CONN_MAX_FDS_PER_USER, -+ memfds, KDBUS_MSG_MAX_MEMFD_ITEMS + 1); -+ ASSERT_RETURN(ret == -E2BIG); -+ -+ ret = kdbus_msg_recv(conn_dst, NULL, NULL); -+ ASSERT_RETURN(ret == -EAGAIN); -+ -+ /* -+ * Send KDBUS_CONN_MAX_FDS_PER_USER fds + -+ * KDBUS_MSG_MAX_MEMFD_ITEMS memfds -+ */ -+ ret = send_fds_memfds(conn_src, conn_dst->id, -+ fds, KDBUS_CONN_MAX_FDS_PER_USER, -+ memfds, KDBUS_MSG_MAX_MEMFD_ITEMS); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_msg_recv(conn_dst, &msg, NULL); -+ ASSERT_RETURN(ret == 0); -+ -+ /* Check we got the right number of fds */ -+ nfds = kdbus_item_get_nfds(msg); -+ ASSERT_RETURN(nfds == KDBUS_CONN_MAX_FDS_PER_USER + -+ KDBUS_MSG_MAX_MEMFD_ITEMS); -+ -+ kdbus_msg_free(msg); -+ -+ -+ /* -+ * Re-send fds + memfds, close them, but do not receive them -+ * and try to queue more -+ */ -+ ret = send_fds_memfds(conn_src, conn_dst->id, -+ fds, KDBUS_CONN_MAX_FDS_PER_USER, -+ memfds, KDBUS_MSG_MAX_MEMFD_ITEMS); -+ ASSERT_RETURN(ret == 0); -+ -+ /* close old references and get a new ones */ -+ for (i = 0; i < KDBUS_CONN_MAX_FDS_PER_USER + 1; i++) { -+ close(fds[i]); -+ fds[i] = open("/dev/null", O_RDWR|O_CLOEXEC); -+ ASSERT_RETURN_VAL(fds[i] >= 0, -errno); -+ } -+ -+ /* should fail since we have already fds in the queue */ -+ ret = send_fds(conn_src, conn_dst->id, fds, -+ KDBUS_CONN_MAX_FDS_PER_USER); -+ ASSERT_RETURN(ret == -EMFILE); -+ -+ /* This should succeed */ -+ ret = send_memfds(conn_src, conn_dst->id, -+ memfds, KDBUS_MSG_MAX_MEMFD_ITEMS); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_msg_recv(conn_dst, &msg, NULL); -+ ASSERT_RETURN(ret == 0); -+ -+ nfds = kdbus_item_get_nfds(msg); -+ ASSERT_RETURN(nfds == KDBUS_CONN_MAX_FDS_PER_USER + -+ KDBUS_MSG_MAX_MEMFD_ITEMS); -+ -+ kdbus_msg_free(msg); -+ -+ ret = kdbus_msg_recv(conn_dst, &msg, NULL); -+ ASSERT_RETURN(ret == 0); -+ -+ nfds = kdbus_item_get_nfds(msg); -+ ASSERT_RETURN(nfds == KDBUS_MSG_MAX_MEMFD_ITEMS); -+ -+ kdbus_msg_free(msg); -+ -+ ret = kdbus_msg_recv(conn_dst, NULL, NULL); -+ ASSERT_RETURN(ret == -EAGAIN); -+ -+ for (i = 0; i < KDBUS_CONN_MAX_FDS_PER_USER + 1; i++) -+ close(fds[i]); -+ -+ for (i = 0; i < KDBUS_MSG_MAX_ITEMS + 1; i++) -+ close(memfds[i]); -+ -+ return 0; -+} -+ -+int kdbus_test_fd_passing(struct kdbus_test_env *env) -+{ -+ struct kdbus_conn *conn_src, *conn_dst; -+ const char *str = "stackenblocken"; -+ const struct kdbus_item *item; -+ struct kdbus_msg *msg; -+ unsigned int i; -+ uint64_t now; -+ int fds_conn[2]; -+ int sock_pair[2]; -+ int fds[2]; -+ int memfd; -+ int ret; -+ -+ now = (uint64_t) time(NULL); -+ -+ /* create two connections */ -+ conn_src = kdbus_hello(env->buspath, 0, NULL, 0); -+ conn_dst = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(conn_src && conn_dst); -+ -+ fds_conn[0] = conn_src->fd; -+ fds_conn[1] = conn_dst->fd; -+ -+ ret = socketpair(AF_UNIX, SOCK_STREAM, 0, sock_pair); -+ ASSERT_RETURN(ret == 0); -+ -+ /* Setup memfd */ -+ memfd = memfd_write("memfd-name", &now, sizeof(now)); -+ ASSERT_RETURN(memfd >= 0); -+ -+ /* Setup pipes */ -+ ret = pipe(fds); -+ ASSERT_RETURN(ret == 0); -+ -+ i = write(fds[1], str, strlen(str)); -+ ASSERT_RETURN(i == strlen(str)); -+ -+ /* -+ * Try to ass the handle of a connection as message payload. -+ * This must fail. -+ */ -+ ret = send_fds(conn_src, conn_dst->id, fds_conn, 2); -+ ASSERT_RETURN(ret == -ENOTSUP); -+ -+ ret = send_fds(conn_dst, conn_src->id, fds_conn, 2); -+ ASSERT_RETURN(ret == -ENOTSUP); -+ -+ ret = send_fds(conn_src, conn_dst->id, sock_pair, 2); -+ ASSERT_RETURN(ret == -ENOTSUP); -+ -+ /* -+ * Send fds and memfds to connection that do not accept fds -+ */ -+ ret = kdbus_test_no_fds(env, fds, (int *)&memfd); -+ ASSERT_RETURN(ret == 0); -+ -+ /* Try to broadcast file descriptors. This must fail. */ -+ ret = send_fds(conn_src, KDBUS_DST_ID_BROADCAST, fds, 1); -+ ASSERT_RETURN(ret == -ENOTUNIQ); -+ -+ /* Try to broadcast memfd. This must succeed. */ -+ ret = send_memfds(conn_src, KDBUS_DST_ID_BROADCAST, (int *)&memfd, 1); -+ ASSERT_RETURN(ret == 0); -+ -+ /* Open code this loop */ -+loop_send_fds: -+ -+ /* -+ * Send the read end of the pipe and close it. -+ */ -+ ret = send_fds(conn_src, conn_dst->id, fds, 1); -+ ASSERT_RETURN(ret == 0); -+ close(fds[0]); -+ -+ ret = kdbus_msg_recv(conn_dst, &msg, NULL); -+ ASSERT_RETURN(ret == 0); -+ -+ KDBUS_ITEM_FOREACH(item, msg, items) { -+ if (item->type == KDBUS_ITEM_FDS) { -+ char tmp[14]; -+ int nfds = (item->size - KDBUS_ITEM_HEADER_SIZE) / -+ sizeof(int); -+ ASSERT_RETURN(nfds == 1); -+ -+ i = read(item->fds[0], tmp, sizeof(tmp)); -+ if (i != 0) { -+ ASSERT_RETURN(i == sizeof(tmp)); -+ ASSERT_RETURN(memcmp(tmp, str, sizeof(tmp)) == 0); -+ -+ /* Write EOF */ -+ close(fds[1]); -+ -+ /* -+ * Resend the read end of the pipe, -+ * the receiver still holds a reference -+ * to it... -+ */ -+ goto loop_send_fds; -+ } -+ -+ /* Got EOF */ -+ -+ /* -+ * Close the last reference to the read end -+ * of the pipe, other references are -+ * automatically closed just after send. -+ */ -+ close(item->fds[0]); -+ } -+ } -+ -+ /* -+ * Try to resend the read end of the pipe. Must fail with -+ * -EBADF since both the sender and receiver closed their -+ * references to it. We assume the above since sender and -+ * receiver are on the same process. -+ */ -+ ret = send_fds(conn_src, conn_dst->id, fds, 1); -+ ASSERT_RETURN(ret == -EBADF); -+ -+ /* Then we clear out received any data... */ -+ kdbus_msg_free(msg); -+ -+ ret = kdbus_send_multiple_fds(conn_src, conn_dst); -+ ASSERT_RETURN(ret == 0); -+ -+ close(sock_pair[0]); -+ close(sock_pair[1]); -+ close(memfd); -+ -+ kdbus_conn_free(conn_src); -+ kdbus_conn_free(conn_dst); -+ -+ return TEST_OK; -+} -diff --git a/tools/testing/selftests/kdbus/test-free.c b/tools/testing/selftests/kdbus/test-free.c -new file mode 100644 -index 000000000000..f666da3e87cc ---- /dev/null -+++ b/tools/testing/selftests/kdbus/test-free.c -@@ -0,0 +1,64 @@ -+#include <stdio.h> -+#include <string.h> -+#include <fcntl.h> -+#include <stdlib.h> -+#include <stddef.h> -+#include <unistd.h> -+#include <stdint.h> -+#include <errno.h> -+#include <assert.h> -+#include <stdbool.h> -+ -+#include "kdbus-api.h" -+#include "kdbus-util.h" -+#include "kdbus-enum.h" -+#include "kdbus-test.h" -+ -+static int sample_ioctl_call(struct kdbus_test_env *env) -+{ -+ int ret; -+ struct kdbus_cmd_list cmd_list = { -+ .flags = KDBUS_LIST_QUEUED, -+ .size = sizeof(cmd_list), -+ }; -+ -+ ret = kdbus_cmd_list(env->conn->fd, &cmd_list); -+ ASSERT_RETURN(ret == 0); -+ -+ /* DON'T FREE THIS SLICE OF MEMORY! */ -+ -+ return TEST_OK; -+} -+ -+int kdbus_test_free(struct kdbus_test_env *env) -+{ -+ int ret; -+ struct kdbus_cmd_free cmd_free = {}; -+ -+ /* free an unallocated buffer */ -+ cmd_free.size = sizeof(cmd_free); -+ cmd_free.flags = 0; -+ cmd_free.offset = 0; -+ ret = kdbus_cmd_free(env->conn->fd, &cmd_free); -+ ASSERT_RETURN(ret == -ENXIO); -+ -+ /* free a buffer out of the pool's bounds */ -+ cmd_free.size = sizeof(cmd_free); -+ cmd_free.offset = POOL_SIZE + 1; -+ ret = kdbus_cmd_free(env->conn->fd, &cmd_free); -+ ASSERT_RETURN(ret == -ENXIO); -+ -+ /* -+ * The user application is responsible for freeing the allocated -+ * memory with the KDBUS_CMD_FREE ioctl, so let's test what happens -+ * if we forget about it. -+ */ -+ -+ ret = sample_ioctl_call(env); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = sample_ioctl_call(env); -+ ASSERT_RETURN(ret == 0); -+ -+ return TEST_OK; -+} -diff --git a/tools/testing/selftests/kdbus/test-match.c b/tools/testing/selftests/kdbus/test-match.c -new file mode 100644 -index 000000000000..2360dc1d76a4 ---- /dev/null -+++ b/tools/testing/selftests/kdbus/test-match.c -@@ -0,0 +1,441 @@ -+#include <stdio.h> -+#include <string.h> -+#include <fcntl.h> -+#include <stdlib.h> -+#include <stddef.h> -+#include <unistd.h> -+#include <stdint.h> -+#include <errno.h> -+#include <assert.h> -+#include <stdbool.h> -+ -+#include "kdbus-api.h" -+#include "kdbus-util.h" -+#include "kdbus-enum.h" -+#include "kdbus-test.h" -+ -+int kdbus_test_match_id_add(struct kdbus_test_env *env) -+{ -+ struct { -+ struct kdbus_cmd_match cmd; -+ struct { -+ uint64_t size; -+ uint64_t type; -+ struct kdbus_notify_id_change chg; -+ } item; -+ } buf; -+ struct kdbus_conn *conn; -+ struct kdbus_msg *msg; -+ int ret; -+ -+ memset(&buf, 0, sizeof(buf)); -+ -+ buf.cmd.size = sizeof(buf); -+ buf.cmd.cookie = 0xdeafbeefdeaddead; -+ buf.item.size = sizeof(buf.item); -+ buf.item.type = KDBUS_ITEM_ID_ADD; -+ buf.item.chg.id = KDBUS_MATCH_ID_ANY; -+ -+ /* match on id add */ -+ ret = kdbus_cmd_match_add(env->conn->fd, &buf.cmd); -+ ASSERT_RETURN(ret == 0); -+ -+ /* create 2nd connection */ -+ conn = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(conn != NULL); -+ -+ /* 1st connection should have received a notification */ -+ ret = kdbus_msg_recv(env->conn, &msg, NULL); -+ ASSERT_RETURN(ret == 0); -+ -+ ASSERT_RETURN(msg->items[0].type == KDBUS_ITEM_ID_ADD); -+ ASSERT_RETURN(msg->items[0].id_change.id == conn->id); -+ -+ kdbus_conn_free(conn); -+ -+ return TEST_OK; -+} -+ -+int kdbus_test_match_id_remove(struct kdbus_test_env *env) -+{ -+ struct { -+ struct kdbus_cmd_match cmd; -+ struct { -+ uint64_t size; -+ uint64_t type; -+ struct kdbus_notify_id_change chg; -+ } item; -+ } buf; -+ struct kdbus_conn *conn; -+ struct kdbus_msg *msg; -+ size_t id; -+ int ret; -+ -+ /* create 2nd connection */ -+ conn = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(conn != NULL); -+ id = conn->id; -+ -+ memset(&buf, 0, sizeof(buf)); -+ buf.cmd.size = sizeof(buf); -+ buf.cmd.cookie = 0xdeafbeefdeaddead; -+ buf.item.size = sizeof(buf.item); -+ buf.item.type = KDBUS_ITEM_ID_REMOVE; -+ buf.item.chg.id = id; -+ -+ /* register match on 2nd connection */ -+ ret = kdbus_cmd_match_add(env->conn->fd, &buf.cmd); -+ ASSERT_RETURN(ret == 0); -+ -+ /* remove 2nd connection again */ -+ kdbus_conn_free(conn); -+ -+ /* 1st connection should have received a notification */ -+ ret = kdbus_msg_recv(env->conn, &msg, NULL); -+ ASSERT_RETURN(ret == 0); -+ -+ ASSERT_RETURN(msg->items[0].type == KDBUS_ITEM_ID_REMOVE); -+ ASSERT_RETURN(msg->items[0].id_change.id == id); -+ -+ return TEST_OK; -+} -+ -+int kdbus_test_match_replace(struct kdbus_test_env *env) -+{ -+ struct { -+ struct kdbus_cmd_match cmd; -+ struct { -+ uint64_t size; -+ uint64_t type; -+ struct kdbus_notify_id_change chg; -+ } item; -+ } buf; -+ struct kdbus_conn *conn; -+ struct kdbus_msg *msg; -+ size_t id; -+ int ret; -+ -+ /* add a match to id_add */ -+ ASSERT_RETURN(kdbus_test_match_id_add(env) == TEST_OK); -+ -+ /* do a replace of the match from id_add to id_remove */ -+ memset(&buf, 0, sizeof(buf)); -+ -+ buf.cmd.size = sizeof(buf); -+ buf.cmd.cookie = 0xdeafbeefdeaddead; -+ buf.cmd.flags = KDBUS_MATCH_REPLACE; -+ buf.item.size = sizeof(buf.item); -+ buf.item.type = KDBUS_ITEM_ID_REMOVE; -+ buf.item.chg.id = KDBUS_MATCH_ID_ANY; -+ -+ ret = kdbus_cmd_match_add(env->conn->fd, &buf.cmd); -+ -+ /* create 2nd connection */ -+ conn = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(conn != NULL); -+ id = conn->id; -+ -+ /* 1st connection should _not_ have received a notification */ -+ ret = kdbus_msg_recv(env->conn, &msg, NULL); -+ ASSERT_RETURN(ret != 0); -+ -+ /* remove 2nd connection */ -+ kdbus_conn_free(conn); -+ -+ /* 1st connection should _now_ have received a notification */ -+ ret = kdbus_msg_recv(env->conn, &msg, NULL); -+ ASSERT_RETURN(ret == 0); -+ -+ ASSERT_RETURN(msg->items[0].type == KDBUS_ITEM_ID_REMOVE); -+ ASSERT_RETURN(msg->items[0].id_change.id == id); -+ -+ return TEST_OK; -+} -+ -+int kdbus_test_match_name_add(struct kdbus_test_env *env) -+{ -+ struct { -+ struct kdbus_cmd_match cmd; -+ struct { -+ uint64_t size; -+ uint64_t type; -+ struct kdbus_notify_name_change chg; -+ } item; -+ char name[64]; -+ } buf; -+ struct kdbus_msg *msg; -+ char *name; -+ int ret; -+ -+ name = "foo.bla.blaz"; -+ -+ /* install the match rule */ -+ memset(&buf, 0, sizeof(buf)); -+ buf.item.type = KDBUS_ITEM_NAME_ADD; -+ buf.item.chg.old_id.id = KDBUS_MATCH_ID_ANY; -+ buf.item.chg.new_id.id = KDBUS_MATCH_ID_ANY; -+ strncpy(buf.name, name, sizeof(buf.name) - 1); -+ buf.item.size = sizeof(buf.item) + strlen(buf.name) + 1; -+ buf.cmd.size = sizeof(buf.cmd) + buf.item.size; -+ -+ ret = kdbus_cmd_match_add(env->conn->fd, &buf.cmd); -+ ASSERT_RETURN(ret == 0); -+ -+ /* acquire the name */ -+ ret = kdbus_name_acquire(env->conn, name, NULL); -+ ASSERT_RETURN(ret == 0); -+ -+ /* we should have received a notification */ -+ ret = kdbus_msg_recv(env->conn, &msg, NULL); -+ ASSERT_RETURN(ret == 0); -+ -+ ASSERT_RETURN(msg->items[0].type == KDBUS_ITEM_NAME_ADD); -+ ASSERT_RETURN(msg->items[0].name_change.old_id.id == 0); -+ ASSERT_RETURN(msg->items[0].name_change.new_id.id == env->conn->id); -+ ASSERT_RETURN(strcmp(msg->items[0].name_change.name, name) == 0); -+ -+ return TEST_OK; -+} -+ -+int kdbus_test_match_name_remove(struct kdbus_test_env *env) -+{ -+ struct { -+ struct kdbus_cmd_match cmd; -+ struct { -+ uint64_t size; -+ uint64_t type; -+ struct kdbus_notify_name_change chg; -+ } item; -+ char name[64]; -+ } buf; -+ struct kdbus_msg *msg; -+ char *name; -+ int ret; -+ -+ name = "foo.bla.blaz"; -+ -+ /* acquire the name */ -+ ret = kdbus_name_acquire(env->conn, name, NULL); -+ ASSERT_RETURN(ret == 0); -+ -+ /* install the match rule */ -+ memset(&buf, 0, sizeof(buf)); -+ buf.item.type = KDBUS_ITEM_NAME_REMOVE; -+ buf.item.chg.old_id.id = KDBUS_MATCH_ID_ANY; -+ buf.item.chg.new_id.id = KDBUS_MATCH_ID_ANY; -+ strncpy(buf.name, name, sizeof(buf.name) - 1); -+ buf.item.size = sizeof(buf.item) + strlen(buf.name) + 1; -+ buf.cmd.size = sizeof(buf.cmd) + buf.item.size; -+ -+ ret = kdbus_cmd_match_add(env->conn->fd, &buf.cmd); -+ ASSERT_RETURN(ret == 0); -+ -+ /* release the name again */ -+ kdbus_name_release(env->conn, name); -+ ASSERT_RETURN(ret == 0); -+ -+ /* we should have received a notification */ -+ ret = kdbus_msg_recv(env->conn, &msg, NULL); -+ ASSERT_RETURN(ret == 0); -+ -+ ASSERT_RETURN(msg->items[0].type == KDBUS_ITEM_NAME_REMOVE); -+ ASSERT_RETURN(msg->items[0].name_change.old_id.id == env->conn->id); -+ ASSERT_RETURN(msg->items[0].name_change.new_id.id == 0); -+ ASSERT_RETURN(strcmp(msg->items[0].name_change.name, name) == 0); -+ -+ return TEST_OK; -+} -+ -+int kdbus_test_match_name_change(struct kdbus_test_env *env) -+{ -+ struct { -+ struct kdbus_cmd_match cmd; -+ struct { -+ uint64_t size; -+ uint64_t type; -+ struct kdbus_notify_name_change chg; -+ } item; -+ char name[64]; -+ } buf; -+ struct kdbus_conn *conn; -+ struct kdbus_msg *msg; -+ uint64_t flags; -+ char *name = "foo.bla.baz"; -+ int ret; -+ -+ /* acquire the name */ -+ ret = kdbus_name_acquire(env->conn, name, NULL); -+ ASSERT_RETURN(ret == 0); -+ -+ /* install the match rule */ -+ memset(&buf, 0, sizeof(buf)); -+ buf.item.type = KDBUS_ITEM_NAME_CHANGE; -+ buf.item.chg.old_id.id = KDBUS_MATCH_ID_ANY; -+ buf.item.chg.new_id.id = KDBUS_MATCH_ID_ANY; -+ strncpy(buf.name, name, sizeof(buf.name) - 1); -+ buf.item.size = sizeof(buf.item) + strlen(buf.name) + 1; -+ buf.cmd.size = sizeof(buf.cmd) + buf.item.size; -+ -+ ret = kdbus_cmd_match_add(env->conn->fd, &buf.cmd); -+ ASSERT_RETURN(ret == 0); -+ -+ /* create a 2nd connection */ -+ conn = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(conn != NULL); -+ -+ /* allow the new connection to own the same name */ -+ /* queue the 2nd connection as waiting owner */ -+ flags = KDBUS_NAME_QUEUE; -+ ret = kdbus_name_acquire(conn, name, &flags); -+ ASSERT_RETURN(ret == 0); -+ ASSERT_RETURN(flags & KDBUS_NAME_IN_QUEUE); -+ -+ /* release name from 1st connection */ -+ ret = kdbus_name_release(env->conn, name); -+ ASSERT_RETURN(ret == 0); -+ -+ /* we should have received a notification */ -+ ret = kdbus_msg_recv(env->conn, &msg, NULL); -+ ASSERT_RETURN(ret == 0); -+ -+ ASSERT_RETURN(msg->items[0].type == KDBUS_ITEM_NAME_CHANGE); -+ ASSERT_RETURN(msg->items[0].name_change.old_id.id == env->conn->id); -+ ASSERT_RETURN(msg->items[0].name_change.new_id.id == conn->id); -+ ASSERT_RETURN(strcmp(msg->items[0].name_change.name, name) == 0); -+ -+ kdbus_conn_free(conn); -+ -+ return TEST_OK; -+} -+ -+static int send_bloom_filter(const struct kdbus_conn *conn, -+ uint64_t cookie, -+ const uint8_t *filter, -+ size_t filter_size, -+ uint64_t filter_generation) -+{ -+ struct kdbus_cmd_send cmd = {}; -+ struct kdbus_msg *msg; -+ struct kdbus_item *item; -+ uint64_t size; -+ int ret; -+ -+ size = sizeof(struct kdbus_msg); -+ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_bloom_filter)) + filter_size; -+ -+ msg = alloca(size); -+ -+ memset(msg, 0, size); -+ msg->size = size; -+ msg->src_id = conn->id; -+ msg->dst_id = KDBUS_DST_ID_BROADCAST; -+ msg->flags = KDBUS_MSG_SIGNAL; -+ msg->payload_type = KDBUS_PAYLOAD_DBUS; -+ msg->cookie = cookie; -+ -+ item = msg->items; -+ item->type = KDBUS_ITEM_BLOOM_FILTER; -+ item->size = KDBUS_ITEM_SIZE(sizeof(struct kdbus_bloom_filter)) + -+ filter_size; -+ -+ item->bloom_filter.generation = filter_generation; -+ memcpy(item->bloom_filter.data, filter, filter_size); -+ -+ cmd.size = sizeof(cmd); -+ cmd.msg_address = (uintptr_t)msg; -+ -+ ret = kdbus_cmd_send(conn->fd, &cmd); -+ if (ret < 0) { -+ kdbus_printf("error sending message: %d (%m)\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+int kdbus_test_match_bloom(struct kdbus_test_env *env) -+{ -+ struct { -+ struct kdbus_cmd_match cmd; -+ struct { -+ uint64_t size; -+ uint64_t type; -+ uint8_t data_gen0[64]; -+ uint8_t data_gen1[64]; -+ } item; -+ } buf; -+ struct kdbus_conn *conn; -+ struct kdbus_msg *msg; -+ uint64_t cookie = 0xf000f00f; -+ uint8_t filter[64]; -+ int ret; -+ -+ /* install the match rule */ -+ memset(&buf, 0, sizeof(buf)); -+ buf.cmd.size = sizeof(buf); -+ -+ buf.item.size = sizeof(buf.item); -+ buf.item.type = KDBUS_ITEM_BLOOM_MASK; -+ buf.item.data_gen0[0] = 0x55; -+ buf.item.data_gen0[63] = 0x80; -+ -+ buf.item.data_gen1[1] = 0xaa; -+ buf.item.data_gen1[9] = 0x02; -+ -+ ret = kdbus_cmd_match_add(env->conn->fd, &buf.cmd); -+ ASSERT_RETURN(ret == 0); -+ -+ /* create a 2nd connection */ -+ conn = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(conn != NULL); -+ -+ /* a message with a 0'ed out filter must not reach the other peer */ -+ memset(filter, 0, sizeof(filter)); -+ ret = send_bloom_filter(conn, ++cookie, filter, sizeof(filter), 0); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_msg_recv(env->conn, &msg, NULL); -+ ASSERT_RETURN(ret == -EAGAIN); -+ -+ /* now set the filter to the connection's mask and expect success */ -+ filter[0] = 0x55; -+ filter[63] = 0x80; -+ ret = send_bloom_filter(conn, ++cookie, filter, sizeof(filter), 0); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_msg_recv(env->conn, &msg, NULL); -+ ASSERT_RETURN(ret == 0); -+ ASSERT_RETURN(msg->cookie == cookie); -+ -+ /* broaden the filter and try again. this should also succeed. */ -+ filter[0] = 0xff; -+ filter[8] = 0xff; -+ filter[63] = 0xff; -+ ret = send_bloom_filter(conn, ++cookie, filter, sizeof(filter), 0); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_msg_recv(env->conn, &msg, NULL); -+ ASSERT_RETURN(ret == 0); -+ ASSERT_RETURN(msg->cookie == cookie); -+ -+ /* the same filter must not match against bloom generation 1 */ -+ ret = send_bloom_filter(conn, ++cookie, filter, sizeof(filter), 1); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_msg_recv(env->conn, &msg, NULL); -+ ASSERT_RETURN(ret == -EAGAIN); -+ -+ /* set a different filter and try again */ -+ filter[1] = 0xaa; -+ filter[9] = 0x02; -+ ret = send_bloom_filter(conn, ++cookie, filter, sizeof(filter), 1); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_msg_recv(env->conn, &msg, NULL); -+ ASSERT_RETURN(ret == 0); -+ ASSERT_RETURN(msg->cookie == cookie); -+ -+ kdbus_conn_free(conn); -+ -+ return TEST_OK; -+} -diff --git a/tools/testing/selftests/kdbus/test-message.c b/tools/testing/selftests/kdbus/test-message.c -new file mode 100644 -index 000000000000..f1615dafb7f1 ---- /dev/null -+++ b/tools/testing/selftests/kdbus/test-message.c -@@ -0,0 +1,731 @@ -+#include <stdio.h> -+#include <string.h> -+#include <fcntl.h> -+#include <stdlib.h> -+#include <stddef.h> -+#include <unistd.h> -+#include <stdint.h> -+#include <errno.h> -+#include <assert.h> -+#include <time.h> -+#include <stdbool.h> -+#include <sys/eventfd.h> -+#include <sys/types.h> -+#include <sys/wait.h> -+ -+#include "kdbus-api.h" -+#include "kdbus-util.h" -+#include "kdbus-enum.h" -+#include "kdbus-test.h" -+ -+/* maximum number of queued messages from the same individual user */ -+#define KDBUS_CONN_MAX_MSGS 256 -+ -+/* maximum number of queued requests waiting for a reply */ -+#define KDBUS_CONN_MAX_REQUESTS_PENDING 128 -+ -+/* maximum message payload size */ -+#define KDBUS_MSG_MAX_PAYLOAD_VEC_SIZE (2 * 1024UL * 1024UL) -+ -+int kdbus_test_message_basic(struct kdbus_test_env *env) -+{ -+ struct kdbus_conn *conn; -+ struct kdbus_conn *sender; -+ struct kdbus_msg *msg; -+ uint64_t cookie = 0x1234abcd5678eeff; -+ uint64_t offset; -+ int ret; -+ -+ sender = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(sender != NULL); -+ -+ /* create a 2nd connection */ -+ conn = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(conn != NULL); -+ -+ ret = kdbus_add_match_empty(conn); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_add_match_empty(sender); -+ ASSERT_RETURN(ret == 0); -+ -+ /* send over 1st connection */ -+ ret = kdbus_msg_send(sender, NULL, cookie, 0, 0, 0, -+ KDBUS_DST_ID_BROADCAST); -+ ASSERT_RETURN(ret == 0); -+ -+ /* Make sure that we do not get our own broadcasts */ -+ ret = kdbus_msg_recv(sender, NULL, NULL); -+ ASSERT_RETURN(ret == -EAGAIN); -+ -+ /* ... and receive on the 2nd */ -+ ret = kdbus_msg_recv_poll(conn, 100, &msg, &offset); -+ ASSERT_RETURN(ret == 0); -+ ASSERT_RETURN(msg->cookie == cookie); -+ -+ kdbus_msg_free(msg); -+ -+ /* Msgs that expect a reply must have timeout and cookie */ -+ ret = kdbus_msg_send(sender, NULL, 0, KDBUS_MSG_EXPECT_REPLY, -+ 0, 0, conn->id); -+ ASSERT_RETURN(ret == -EINVAL); -+ -+ /* Faked replies with a valid reply cookie are rejected */ -+ ret = kdbus_msg_send_reply(conn, time(NULL) ^ cookie, sender->id); -+ ASSERT_RETURN(ret == -EPERM); -+ -+ ret = kdbus_free(conn, offset); -+ ASSERT_RETURN(ret == 0); -+ -+ kdbus_conn_free(sender); -+ kdbus_conn_free(conn); -+ -+ return TEST_OK; -+} -+ -+static int msg_recv_prio(struct kdbus_conn *conn, -+ int64_t requested_prio, -+ int64_t expected_prio) -+{ -+ struct kdbus_cmd_recv recv = { -+ .size = sizeof(recv), -+ .flags = KDBUS_RECV_USE_PRIORITY, -+ .priority = requested_prio, -+ }; -+ struct kdbus_msg *msg; -+ int ret; -+ -+ ret = kdbus_cmd_recv(conn->fd, &recv); -+ if (ret < 0) { -+ kdbus_printf("error receiving message: %d (%m)\n", -errno); -+ return ret; -+ } -+ -+ msg = (struct kdbus_msg *)(conn->buf + recv.msg.offset); -+ kdbus_msg_dump(conn, msg); -+ -+ if (msg->priority != expected_prio) { -+ kdbus_printf("expected message prio %lld, got %lld\n", -+ (unsigned long long) expected_prio, -+ (unsigned long long) msg->priority); -+ return -EINVAL; -+ } -+ -+ kdbus_msg_free(msg); -+ ret = kdbus_free(conn, recv.msg.offset); -+ if (ret < 0) -+ return ret; -+ -+ return 0; -+} -+ -+int kdbus_test_message_prio(struct kdbus_test_env *env) -+{ -+ struct kdbus_conn *a, *b; -+ uint64_t cookie = 0; -+ -+ a = kdbus_hello(env->buspath, 0, NULL, 0); -+ b = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(a && b); -+ -+ ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0, 25, a->id) == 0); -+ ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0, -600, a->id) == 0); -+ ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0, 10, a->id) == 0); -+ ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0, -35, a->id) == 0); -+ ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0, -100, a->id) == 0); -+ ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0, 20, a->id) == 0); -+ ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0, -15, a->id) == 0); -+ ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0, -800, a->id) == 0); -+ ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0, -150, a->id) == 0); -+ ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0, 10, a->id) == 0); -+ ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0, -800, a->id) == 0); -+ ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0, -10, a->id) == 0); -+ -+ ASSERT_RETURN(msg_recv_prio(a, -200, -800) == 0); -+ ASSERT_RETURN(msg_recv_prio(a, -100, -800) == 0); -+ ASSERT_RETURN(msg_recv_prio(a, -400, -600) == 0); -+ ASSERT_RETURN(msg_recv_prio(a, -400, -600) == -EAGAIN); -+ ASSERT_RETURN(msg_recv_prio(a, 10, -150) == 0); -+ ASSERT_RETURN(msg_recv_prio(a, 10, -100) == 0); -+ -+ kdbus_printf("--- get priority (all)\n"); -+ ASSERT_RETURN(kdbus_msg_recv(a, NULL, NULL) == 0); -+ -+ kdbus_conn_free(a); -+ kdbus_conn_free(b); -+ -+ return TEST_OK; -+} -+ -+static int kdbus_test_notify_kernel_quota(struct kdbus_test_env *env) -+{ -+ int ret; -+ unsigned int i; -+ struct kdbus_conn *conn; -+ struct kdbus_conn *reader; -+ struct kdbus_msg *msg = NULL; -+ struct kdbus_cmd_recv recv = { .size = sizeof(recv) }; -+ -+ reader = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(reader); -+ -+ conn = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(conn); -+ -+ /* Register for ID signals */ -+ ret = kdbus_add_match_id(reader, 0x1, KDBUS_ITEM_ID_ADD, -+ KDBUS_MATCH_ID_ANY); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_add_match_id(reader, 0x2, KDBUS_ITEM_ID_REMOVE, -+ KDBUS_MATCH_ID_ANY); -+ ASSERT_RETURN(ret == 0); -+ -+ /* Each iteration two notifications: add and remove ID */ -+ for (i = 0; i < KDBUS_CONN_MAX_MSGS / 2; i++) { -+ struct kdbus_conn *notifier; -+ -+ notifier = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(notifier); -+ -+ kdbus_conn_free(notifier); -+ } -+ -+ /* -+ * Now the reader queue is full with kernel notfications, -+ * but as a user we still have room to push our messages. -+ */ -+ ret = kdbus_msg_send(conn, NULL, 0xdeadbeef, 0, 0, 0, reader->id); -+ ASSERT_RETURN(ret == 0); -+ -+ /* More ID kernel notifications that will be lost */ -+ kdbus_conn_free(conn); -+ -+ conn = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(conn); -+ -+ kdbus_conn_free(conn); -+ -+ /* -+ * We lost only 3 packets since only signal msgs are -+ * accounted. The connection ID add/remove notification -+ */ -+ ret = kdbus_cmd_recv(reader->fd, &recv); -+ ASSERT_RETURN(ret == 0); -+ ASSERT_RETURN(recv.return_flags & KDBUS_RECV_RETURN_DROPPED_MSGS); -+ ASSERT_RETURN(recv.dropped_msgs == 3); -+ -+ msg = (struct kdbus_msg *)(reader->buf + recv.msg.offset); -+ kdbus_msg_free(msg); -+ -+ /* Read our queue */ -+ for (i = 0; i < KDBUS_CONN_MAX_MSGS - 1; i++) { -+ memset(&recv, 0, sizeof(recv)); -+ recv.size = sizeof(recv); -+ -+ ret = kdbus_cmd_recv(reader->fd, &recv); -+ ASSERT_RETURN(ret == 0); -+ ASSERT_RETURN(!(recv.return_flags & -+ KDBUS_RECV_RETURN_DROPPED_MSGS)); -+ -+ msg = (struct kdbus_msg *)(reader->buf + recv.msg.offset); -+ kdbus_msg_free(msg); -+ } -+ -+ ret = kdbus_msg_recv(reader, NULL, NULL); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_msg_recv(reader, NULL, NULL); -+ ASSERT_RETURN(ret == -EAGAIN); -+ -+ kdbus_conn_free(reader); -+ -+ return 0; -+} -+ -+/* Return the number of message successfully sent */ -+static int kdbus_fill_conn_queue(struct kdbus_conn *conn_src, -+ uint64_t dst_id, -+ unsigned int max_msgs) -+{ -+ unsigned int i; -+ uint64_t cookie = 0; -+ size_t size; -+ struct kdbus_cmd_send cmd = {}; -+ struct kdbus_msg *msg; -+ int ret; -+ -+ size = sizeof(struct kdbus_msg); -+ msg = malloc(size); -+ ASSERT_RETURN_VAL(msg, -ENOMEM); -+ -+ memset(msg, 0, size); -+ msg->size = size; -+ msg->src_id = conn_src->id; -+ msg->dst_id = dst_id; -+ msg->payload_type = KDBUS_PAYLOAD_DBUS; -+ -+ cmd.size = sizeof(cmd); -+ cmd.msg_address = (uintptr_t)msg; -+ -+ for (i = 0; i < max_msgs; i++) { -+ msg->cookie = cookie++; -+ ret = kdbus_cmd_send(conn_src->fd, &cmd); -+ if (ret < 0) -+ break; -+ } -+ -+ free(msg); -+ -+ return i; -+} -+ -+static int kdbus_test_activator_quota(struct kdbus_test_env *env) -+{ -+ int ret; -+ unsigned int i; -+ unsigned int activator_msgs_count = 0; -+ uint64_t cookie = time(NULL); -+ struct kdbus_conn *conn; -+ struct kdbus_conn *sender; -+ struct kdbus_conn *activator; -+ struct kdbus_msg *msg; -+ uint64_t flags = KDBUS_NAME_REPLACE_EXISTING; -+ struct kdbus_cmd_recv recv = { .size = sizeof(recv) }; -+ struct kdbus_policy_access access = { -+ .type = KDBUS_POLICY_ACCESS_USER, -+ .id = geteuid(), -+ .access = KDBUS_POLICY_OWN, -+ }; -+ -+ activator = kdbus_hello_activator(env->buspath, "foo.test.activator", -+ &access, 1); -+ ASSERT_RETURN(activator); -+ -+ conn = kdbus_hello(env->buspath, 0, NULL, 0); -+ sender = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(conn || sender); -+ -+ ret = kdbus_list(sender, KDBUS_LIST_NAMES | -+ KDBUS_LIST_UNIQUE | -+ KDBUS_LIST_ACTIVATORS | -+ KDBUS_LIST_QUEUED); -+ ASSERT_RETURN(ret == 0); -+ -+ for (i = 0; i < KDBUS_CONN_MAX_MSGS; i++) { -+ ret = kdbus_msg_send(sender, "foo.test.activator", -+ cookie++, 0, 0, 0, -+ KDBUS_DST_ID_NAME); -+ if (ret < 0) -+ break; -+ activator_msgs_count++; -+ } -+ -+ /* we must have at least sent one message */ -+ ASSERT_RETURN_VAL(i > 0, -errno); -+ ASSERT_RETURN(ret == -ENOBUFS); -+ -+ /* Good, activator queue is full now */ -+ -+ /* ENXIO on direct send (activators can never be addressed by ID) */ -+ ret = kdbus_msg_send(conn, NULL, cookie++, 0, 0, 0, activator->id); -+ ASSERT_RETURN(ret == -ENXIO); -+ -+ /* can't queue more */ -+ ret = kdbus_msg_send(conn, "foo.test.activator", cookie++, -+ 0, 0, 0, KDBUS_DST_ID_NAME); -+ ASSERT_RETURN(ret == -ENOBUFS); -+ -+ /* no match installed, so the broadcast will not inc dropped_msgs */ -+ ret = kdbus_msg_send(sender, NULL, cookie++, 0, 0, 0, -+ KDBUS_DST_ID_BROADCAST); -+ ASSERT_RETURN(ret == 0); -+ -+ /* Check activator queue */ -+ ret = kdbus_cmd_recv(activator->fd, &recv); -+ ASSERT_RETURN(ret == 0); -+ ASSERT_RETURN(recv.dropped_msgs == 0); -+ -+ activator_msgs_count--; -+ -+ msg = (struct kdbus_msg *)(activator->buf + recv.msg.offset); -+ kdbus_msg_free(msg); -+ -+ -+ /* Stage 1) of test check the pool memory quota */ -+ -+ /* Consume the connection pool memory */ -+ for (i = 0; i < KDBUS_CONN_MAX_MSGS; i++) { -+ ret = kdbus_msg_send(sender, NULL, -+ cookie++, 0, 0, 0, conn->id); -+ if (ret < 0) -+ break; -+ } -+ -+ /* consume one message, so later at least one can be moved */ -+ memset(&recv, 0, sizeof(recv)); -+ recv.size = sizeof(recv); -+ ret = kdbus_cmd_recv(conn->fd, &recv); -+ ASSERT_RETURN(ret == 0); -+ ASSERT_RETURN(recv.dropped_msgs == 0); -+ msg = (struct kdbus_msg *)(conn->buf + recv.msg.offset); -+ kdbus_msg_free(msg); -+ -+ /* Try to acquire the name now */ -+ ret = kdbus_name_acquire(conn, "foo.test.activator", &flags); -+ ASSERT_RETURN(ret == 0); -+ -+ /* try to read messages and see if we have lost some */ -+ memset(&recv, 0, sizeof(recv)); -+ recv.size = sizeof(recv); -+ ret = kdbus_cmd_recv(conn->fd, &recv); -+ ASSERT_RETURN(ret == 0); -+ ASSERT_RETURN(recv.dropped_msgs != 0); -+ -+ /* number of dropped msgs < received ones (at least one was moved) */ -+ ASSERT_RETURN(recv.dropped_msgs < activator_msgs_count); -+ -+ /* Deduct the number of dropped msgs from the activator msgs */ -+ activator_msgs_count -= recv.dropped_msgs; -+ -+ msg = (struct kdbus_msg *)(activator->buf + recv.msg.offset); -+ kdbus_msg_free(msg); -+ -+ /* -+ * Release the name and hand it back to activator, now -+ * we should have 'activator_msgs_count' msgs again in -+ * the activator queue -+ */ -+ ret = kdbus_name_release(conn, "foo.test.activator"); -+ ASSERT_RETURN(ret == 0); -+ -+ /* make sure that we got our previous activator msgs */ -+ ret = kdbus_msg_recv(activator, &msg, NULL); -+ ASSERT_RETURN(ret == 0); -+ ASSERT_RETURN(msg->src_id == sender->id); -+ -+ activator_msgs_count--; -+ -+ kdbus_msg_free(msg); -+ -+ -+ /* Stage 2) of test check max message quota */ -+ -+ /* Empty conn queue */ -+ for (i = 0; i < KDBUS_CONN_MAX_MSGS; i++) { -+ ret = kdbus_msg_recv(conn, NULL, NULL); -+ if (ret == -EAGAIN) -+ break; -+ } -+ -+ /* fill queue with max msgs quota */ -+ ret = kdbus_fill_conn_queue(sender, conn->id, KDBUS_CONN_MAX_MSGS); -+ ASSERT_RETURN(ret == KDBUS_CONN_MAX_MSGS); -+ -+ /* This one is lost but it is not accounted */ -+ ret = kdbus_msg_send(sender, NULL, -+ cookie++, 0, 0, 0, conn->id); -+ ASSERT_RETURN(ret == -ENOBUFS); -+ -+ /* Acquire the name again */ -+ ret = kdbus_name_acquire(conn, "foo.test.activator", &flags); -+ ASSERT_RETURN(ret == 0); -+ -+ memset(&recv, 0, sizeof(recv)); -+ recv.size = sizeof(recv); -+ -+ /* -+ * Try to read messages and make sure that we have lost all -+ * the activator messages due to quota checks. Our queue is -+ * already full. -+ */ -+ ret = kdbus_cmd_recv(conn->fd, &recv); -+ ASSERT_RETURN(ret == 0); -+ ASSERT_RETURN(recv.dropped_msgs == activator_msgs_count); -+ -+ msg = (struct kdbus_msg *)(activator->buf + recv.msg.offset); -+ kdbus_msg_free(msg); -+ -+ kdbus_conn_free(sender); -+ kdbus_conn_free(conn); -+ kdbus_conn_free(activator); -+ -+ return 0; -+} -+ -+static int kdbus_test_expected_reply_quota(struct kdbus_test_env *env) -+{ -+ int ret; -+ unsigned int i, n; -+ unsigned int count; -+ uint64_t cookie = 0x1234abcd5678eeff; -+ struct kdbus_conn *conn; -+ struct kdbus_conn *connections[9]; -+ -+ conn = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(conn); -+ -+ for (i = 0; i < 9; i++) { -+ connections[i] = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(connections[i]); -+ } -+ -+ count = 0; -+ /* Send 16 messages to 8 different connections */ -+ for (i = 0; i < 8; i++) { -+ for (n = 0; n < 16; n++) { -+ ret = kdbus_msg_send(conn, NULL, cookie++, -+ KDBUS_MSG_EXPECT_REPLY, -+ 100000000ULL, 0, -+ connections[i]->id); -+ if (ret < 0) -+ break; -+ -+ count++; -+ } -+ } -+ -+ /* -+ * We should have queued at least -+ * KDBUS_CONN_MAX_REQUESTS_PENDING method call -+ */ -+ ASSERT_RETURN(count == KDBUS_CONN_MAX_REQUESTS_PENDING); -+ -+ /* -+ * Now try to send a message to the last connection, -+ * if we have reached KDBUS_CONN_MAX_REQUESTS_PENDING -+ * no further requests are allowed -+ */ -+ ret = kdbus_msg_send(conn, NULL, cookie++, KDBUS_MSG_EXPECT_REPLY, -+ 1000000000ULL, 0, connections[8]->id); -+ ASSERT_RETURN(ret == -EMLINK); -+ -+ for (i = 0; i < 9; i++) -+ kdbus_conn_free(connections[i]); -+ -+ kdbus_conn_free(conn); -+ -+ return 0; -+} -+ -+int kdbus_test_pool_quota(struct kdbus_test_env *env) -+{ -+ struct kdbus_conn *a, *b, *c; -+ struct kdbus_cmd_send cmd = {}; -+ struct kdbus_item *item; -+ struct kdbus_msg *recv_msg; -+ struct kdbus_msg *msg; -+ uint64_t cookie = time(NULL); -+ uint64_t size; -+ unsigned int i; -+ char *payload; -+ int ret; -+ -+ /* just a guard */ -+ if (POOL_SIZE <= KDBUS_MSG_MAX_PAYLOAD_VEC_SIZE || -+ POOL_SIZE % KDBUS_MSG_MAX_PAYLOAD_VEC_SIZE != 0) -+ return 0; -+ -+ payload = calloc(KDBUS_MSG_MAX_PAYLOAD_VEC_SIZE, sizeof(char)); -+ ASSERT_RETURN_VAL(payload, -ENOMEM); -+ -+ a = kdbus_hello(env->buspath, 0, NULL, 0); -+ b = kdbus_hello(env->buspath, 0, NULL, 0); -+ c = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(a && b && c); -+ -+ size = sizeof(struct kdbus_msg); -+ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec)); -+ -+ msg = malloc(size); -+ ASSERT_RETURN_VAL(msg, -ENOMEM); -+ -+ memset(msg, 0, size); -+ msg->size = size; -+ msg->src_id = a->id; -+ msg->dst_id = c->id; -+ msg->payload_type = KDBUS_PAYLOAD_DBUS; -+ -+ item = msg->items; -+ item->type = KDBUS_ITEM_PAYLOAD_VEC; -+ item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_vec); -+ item->vec.address = (uintptr_t)payload; -+ item->vec.size = KDBUS_MSG_MAX_PAYLOAD_VEC_SIZE; -+ item = KDBUS_ITEM_NEXT(item); -+ -+ cmd.size = sizeof(cmd); -+ cmd.msg_address = (uintptr_t)msg; -+ -+ /* -+ * Send 2097248 bytes, a user is only allowed to get 33% of half of -+ * the free space of the pool, the already used space is -+ * accounted as free space -+ */ -+ size += KDBUS_MSG_MAX_PAYLOAD_VEC_SIZE; -+ for (i = size; i < (POOL_SIZE / 2 / 3); i += size) { -+ msg->cookie = cookie++; -+ -+ ret = kdbus_cmd_send(a->fd, &cmd); -+ ASSERT_RETURN_VAL(ret == 0, ret); -+ } -+ -+ /* Try to get more than 33% */ -+ msg->cookie = cookie++; -+ ret = kdbus_cmd_send(a->fd, &cmd); -+ ASSERT_RETURN(ret == -ENOBUFS); -+ -+ /* We still can pass small messages */ -+ ret = kdbus_msg_send(b, NULL, cookie++, 0, 0, 0, c->id); -+ ASSERT_RETURN(ret == 0); -+ -+ for (i = size; i < (POOL_SIZE / 2 / 3); i += size) { -+ ret = kdbus_msg_recv(c, &recv_msg, NULL); -+ ASSERT_RETURN(ret == 0); -+ ASSERT_RETURN(recv_msg->src_id == a->id); -+ -+ kdbus_msg_free(recv_msg); -+ } -+ -+ ret = kdbus_msg_recv(c, &recv_msg, NULL); -+ ASSERT_RETURN(ret == 0); -+ ASSERT_RETURN(recv_msg->src_id == b->id); -+ -+ kdbus_msg_free(recv_msg); -+ -+ ret = kdbus_msg_recv(c, NULL, NULL); -+ ASSERT_RETURN(ret == -EAGAIN); -+ -+ free(msg); -+ free(payload); -+ -+ kdbus_conn_free(c); -+ kdbus_conn_free(b); -+ kdbus_conn_free(a); -+ -+ return 0; -+} -+ -+int kdbus_test_message_quota(struct kdbus_test_env *env) -+{ -+ struct kdbus_conn *a, *b; -+ uint64_t cookie = 0; -+ int ret; -+ int i; -+ -+ ret = kdbus_test_activator_quota(env); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_test_notify_kernel_quota(env); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_test_pool_quota(env); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_test_expected_reply_quota(env); -+ ASSERT_RETURN(ret == 0); -+ -+ a = kdbus_hello(env->buspath, 0, NULL, 0); -+ b = kdbus_hello(env->buspath, 0, NULL, 0); -+ -+ ret = kdbus_fill_conn_queue(b, a->id, KDBUS_CONN_MAX_MSGS); -+ ASSERT_RETURN(ret == KDBUS_CONN_MAX_MSGS); -+ -+ ret = kdbus_msg_send(b, NULL, ++cookie, 0, 0, 0, a->id); -+ ASSERT_RETURN(ret == -ENOBUFS); -+ -+ for (i = 0; i < KDBUS_CONN_MAX_MSGS; ++i) { -+ ret = kdbus_msg_recv(a, NULL, NULL); -+ ASSERT_RETURN(ret == 0); -+ } -+ -+ ret = kdbus_msg_recv(a, NULL, NULL); -+ ASSERT_RETURN(ret == -EAGAIN); -+ -+ ret = kdbus_fill_conn_queue(b, a->id, KDBUS_CONN_MAX_MSGS + 1); -+ ASSERT_RETURN(ret == KDBUS_CONN_MAX_MSGS); -+ -+ ret = kdbus_msg_send(b, NULL, ++cookie, 0, 0, 0, a->id); -+ ASSERT_RETURN(ret == -ENOBUFS); -+ -+ kdbus_conn_free(a); -+ kdbus_conn_free(b); -+ -+ return TEST_OK; -+} -+ -+int kdbus_test_memory_access(struct kdbus_test_env *env) -+{ -+ struct kdbus_conn *a, *b; -+ struct kdbus_cmd_send cmd = {}; -+ struct kdbus_item *item; -+ struct kdbus_msg *msg; -+ uint64_t test_addr = 0; -+ char line[256]; -+ uint64_t size; -+ FILE *f; -+ int ret; -+ -+ /* -+ * Search in /proc/kallsyms for the address of a kernel symbol that -+ * should always be there, regardless of the config. Use that address -+ * in a PAYLOAD_VEC item and make sure it's inaccessible. -+ */ -+ -+ f = fopen("/proc/kallsyms", "r"); -+ if (!f) -+ return TEST_SKIP; -+ -+ while (fgets(line, sizeof(line), f)) { -+ char *s = line; -+ -+ if (!strsep(&s, " ")) -+ continue; -+ -+ if (!strsep(&s, " ")) -+ continue; -+ -+ if (!strncmp(s, "mutex_lock", 10)) { -+ test_addr = strtoull(line, NULL, 16); -+ break; -+ } -+ } -+ -+ fclose(f); -+ -+ if (!test_addr) -+ return TEST_SKIP; -+ -+ a = kdbus_hello(env->buspath, 0, NULL, 0); -+ b = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(a && b); -+ -+ size = sizeof(struct kdbus_msg); -+ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec)); -+ -+ msg = alloca(size); -+ ASSERT_RETURN_VAL(msg, -ENOMEM); -+ -+ memset(msg, 0, size); -+ msg->size = size; -+ msg->src_id = a->id; -+ msg->dst_id = b->id; -+ msg->payload_type = KDBUS_PAYLOAD_DBUS; -+ -+ item = msg->items; -+ item->type = KDBUS_ITEM_PAYLOAD_VEC; -+ item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_vec); -+ item->vec.address = test_addr; -+ item->vec.size = sizeof(void*); -+ item = KDBUS_ITEM_NEXT(item); -+ -+ cmd.size = sizeof(cmd); -+ cmd.msg_address = (uintptr_t)msg; -+ -+ ret = kdbus_cmd_send(a->fd, &cmd); -+ ASSERT_RETURN(ret == -EFAULT); -+ -+ kdbus_conn_free(b); -+ kdbus_conn_free(a); -+ -+ return 0; -+} -diff --git a/tools/testing/selftests/kdbus/test-metadata-ns.c b/tools/testing/selftests/kdbus/test-metadata-ns.c -new file mode 100644 -index 000000000000..2cb1d4d2a5be ---- /dev/null -+++ b/tools/testing/selftests/kdbus/test-metadata-ns.c -@@ -0,0 +1,506 @@ -+/* -+ * Test metadata in new namespaces. Even if our tests can run -+ * in a namespaced setup, this test is necessary so we can inspect -+ * metadata on the same kdbusfs but between multiple namespaces -+ */ -+ -+#include <stdio.h> -+#include <string.h> -+#include <sched.h> -+#include <time.h> -+#include <fcntl.h> -+#include <stdlib.h> -+#include <stddef.h> -+#include <unistd.h> -+#include <stdint.h> -+#include <errno.h> -+#include <assert.h> -+#include <signal.h> -+#include <sys/wait.h> -+#include <sys/prctl.h> -+#include <sys/eventfd.h> -+#include <sys/syscall.h> -+#include <sys/capability.h> -+#include <linux/sched.h> -+ -+#include "kdbus-test.h" -+#include "kdbus-util.h" -+#include "kdbus-enum.h" -+ -+static const struct kdbus_creds privileged_creds = {}; -+ -+static const struct kdbus_creds unmapped_creds = { -+ .uid = UNPRIV_UID, -+ .euid = UNPRIV_UID, -+ .suid = UNPRIV_UID, -+ .fsuid = UNPRIV_UID, -+ .gid = UNPRIV_GID, -+ .egid = UNPRIV_GID, -+ .sgid = UNPRIV_GID, -+ .fsgid = UNPRIV_GID, -+}; -+ -+static const struct kdbus_pids unmapped_pids = {}; -+ -+/* Get only the first item */ -+static struct kdbus_item *kdbus_get_item(struct kdbus_msg *msg, -+ uint64_t type) -+{ -+ struct kdbus_item *item; -+ -+ KDBUS_ITEM_FOREACH(item, msg, items) -+ if (item->type == type) -+ return item; -+ -+ return NULL; -+} -+ -+static int kdbus_match_kdbus_creds(struct kdbus_msg *msg, -+ const struct kdbus_creds *expected_creds) -+{ -+ struct kdbus_item *item; -+ -+ item = kdbus_get_item(msg, KDBUS_ITEM_CREDS); -+ ASSERT_RETURN(item); -+ -+ ASSERT_RETURN(memcmp(&item->creds, expected_creds, -+ sizeof(struct kdbus_creds)) == 0); -+ -+ return 0; -+} -+ -+static int kdbus_match_kdbus_pids(struct kdbus_msg *msg, -+ const struct kdbus_pids *expected_pids) -+{ -+ struct kdbus_item *item; -+ -+ item = kdbus_get_item(msg, KDBUS_ITEM_PIDS); -+ ASSERT_RETURN(item); -+ -+ ASSERT_RETURN(memcmp(&item->pids, expected_pids, -+ sizeof(struct kdbus_pids)) == 0); -+ -+ return 0; -+} -+ -+static int __kdbus_clone_userns_test(const char *bus, -+ struct kdbus_conn *conn, -+ uint64_t grandpa_pid, -+ int signal_fd) -+{ -+ int clone_ret; -+ int ret; -+ struct kdbus_msg *msg = NULL; -+ const struct kdbus_item *item; -+ uint64_t cookie = time(NULL) ^ 0xdeadbeef; -+ struct kdbus_conn *unpriv_conn = NULL; -+ struct kdbus_pids parent_pids = { -+ .pid = getppid(), -+ .tid = getppid(), -+ .ppid = grandpa_pid, -+ }; -+ -+ ret = drop_privileges(UNPRIV_UID, UNPRIV_GID); -+ ASSERT_EXIT(ret == 0); -+ -+ unpriv_conn = kdbus_hello(bus, 0, NULL, 0); -+ ASSERT_EXIT(unpriv_conn); -+ -+ ret = kdbus_add_match_empty(unpriv_conn); -+ ASSERT_EXIT(ret == 0); -+ -+ /* -+ * ping privileged connection from this new unprivileged -+ * one -+ */ -+ -+ ret = kdbus_msg_send(unpriv_conn, NULL, cookie, 0, 0, -+ 0, conn->id); -+ ASSERT_EXIT(ret == 0); -+ -+ /* -+ * Since we just dropped privileges, the dumpable flag -+ * was just cleared which makes the /proc/$clone_child/uid_map -+ * to be owned by root, hence any userns uid mapping will fail -+ * with -EPERM since the mapping will be done by uid 65534. -+ * -+ * To avoid this set the dumpable flag again which makes -+ * procfs update the /proc/$clone_child/ inodes owner to 65534. -+ * -+ * Using this we will be able write to /proc/$clone_child/uid_map -+ * as uid 65534 and map the uid 65534 to 0 inside the user namespace. -+ */ -+ ret = prctl(PR_SET_DUMPABLE, SUID_DUMP_USER); -+ ASSERT_EXIT(ret == 0); -+ -+ /* Make child privileged in its new userns and run tests */ -+ -+ ret = RUN_CLONE_CHILD(&clone_ret, -+ SIGCHLD | CLONE_NEWUSER | CLONE_NEWPID, -+ ({ 0; /* Clone setup, nothing */ }), -+ ({ -+ eventfd_t event_status = 0; -+ struct kdbus_conn *userns_conn; -+ -+ /* ping connection from the new user namespace */ -+ userns_conn = kdbus_hello(bus, 0, NULL, 0); -+ ASSERT_EXIT(userns_conn); -+ -+ ret = kdbus_add_match_empty(userns_conn); -+ ASSERT_EXIT(ret == 0); -+ -+ cookie++; -+ ret = kdbus_msg_send(userns_conn, NULL, cookie, -+ 0, 0, 0, conn->id); -+ ASSERT_EXIT(ret == 0); -+ -+ /* Parent did send */ -+ ret = eventfd_read(signal_fd, &event_status); -+ ASSERT_RETURN(ret >= 0 && event_status == 1); -+ -+ /* -+ * Receive from privileged connection -+ */ -+ kdbus_printf("Privileged → unprivileged/privileged " -+ "in its userns " -+ "(different userns and pidns):\n"); -+ ret = kdbus_msg_recv_poll(userns_conn, 300, &msg, NULL); -+ ASSERT_EXIT(ret == 0); -+ ASSERT_EXIT(msg->dst_id == userns_conn->id); -+ -+ /* Different namespaces no CAPS */ -+ item = kdbus_get_item(msg, KDBUS_ITEM_CAPS); -+ ASSERT_EXIT(item == NULL); -+ -+ /* uid/gid not mapped, so we have unpriv cached creds */ -+ ret = kdbus_match_kdbus_creds(msg, &unmapped_creds); -+ ASSERT_EXIT(ret == 0); -+ -+ /* -+ * Diffent pid namepsaces. This is the child pidns -+ * so it should not see its parent kdbus_pids -+ */ -+ ret = kdbus_match_kdbus_pids(msg, &unmapped_pids); -+ ASSERT_EXIT(ret == 0); -+ -+ kdbus_msg_free(msg); -+ -+ -+ /* -+ * Receive broadcast from privileged connection -+ */ -+ kdbus_printf("Privileged → unprivileged/privileged " -+ "in its userns " -+ "(different userns and pidns):\n"); -+ ret = kdbus_msg_recv_poll(userns_conn, 300, &msg, NULL); -+ ASSERT_EXIT(ret == 0); -+ ASSERT_EXIT(msg->dst_id == KDBUS_DST_ID_BROADCAST); -+ -+ /* Different namespaces no CAPS */ -+ item = kdbus_get_item(msg, KDBUS_ITEM_CAPS); -+ ASSERT_EXIT(item == NULL); -+ -+ /* uid/gid not mapped, so we have unpriv cached creds */ -+ ret = kdbus_match_kdbus_creds(msg, &unmapped_creds); -+ ASSERT_EXIT(ret == 0); -+ -+ /* -+ * Diffent pid namepsaces. This is the child pidns -+ * so it should not see its parent kdbus_pids -+ */ -+ ret = kdbus_match_kdbus_pids(msg, &unmapped_pids); -+ ASSERT_EXIT(ret == 0); -+ -+ kdbus_msg_free(msg); -+ -+ kdbus_conn_free(userns_conn); -+ }), -+ ({ -+ /* Parent setup map child uid/gid */ -+ ret = userns_map_uid_gid(pid, "0 65534 1", "0 65534 1"); -+ ASSERT_EXIT(ret == 0); -+ }), -+ ({ 0; })); -+ /* Unprivileged was not able to create user namespace */ -+ if (clone_ret == -EPERM) { -+ kdbus_printf("-- CLONE_NEWUSER TEST Failed for " -+ "uid: %u\n -- Make sure that your kernel " -+ "do not allow CLONE_NEWUSER for " -+ "unprivileged users\n", UNPRIV_UID); -+ ret = 0; -+ goto out; -+ } -+ -+ ASSERT_EXIT(ret == 0); -+ -+ -+ /* -+ * Receive from privileged connection -+ */ -+ kdbus_printf("\nPrivileged → unprivileged (same namespaces):\n"); -+ ret = kdbus_msg_recv_poll(unpriv_conn, 300, &msg, NULL); -+ -+ ASSERT_EXIT(ret == 0); -+ ASSERT_EXIT(msg->dst_id == unpriv_conn->id); -+ -+ /* will get the privileged creds */ -+ ret = kdbus_match_kdbus_creds(msg, &privileged_creds); -+ ASSERT_EXIT(ret == 0); -+ -+ /* Same pidns so will get the kdbus_pids */ -+ ret = kdbus_match_kdbus_pids(msg, &parent_pids); -+ ASSERT_RETURN(ret == 0); -+ -+ kdbus_msg_free(msg); -+ -+ -+ /* -+ * Receive broadcast from privileged connection -+ */ -+ kdbus_printf("\nPrivileged → unprivileged (same namespaces):\n"); -+ ret = kdbus_msg_recv_poll(unpriv_conn, 300, &msg, NULL); -+ -+ ASSERT_EXIT(ret == 0); -+ ASSERT_EXIT(msg->dst_id == KDBUS_DST_ID_BROADCAST); -+ -+ /* will get the privileged creds */ -+ ret = kdbus_match_kdbus_creds(msg, &privileged_creds); -+ ASSERT_EXIT(ret == 0); -+ -+ ret = kdbus_match_kdbus_pids(msg, &parent_pids); -+ ASSERT_RETURN(ret == 0); -+ -+ kdbus_msg_free(msg); -+ -+out: -+ kdbus_conn_free(unpriv_conn); -+ -+ return ret; -+} -+ -+static int kdbus_clone_userns_test(const char *bus, -+ struct kdbus_conn *conn) -+{ -+ int ret; -+ int status; -+ int efd = -1; -+ pid_t pid, ppid; -+ uint64_t unpriv_conn_id = 0; -+ uint64_t userns_conn_id = 0; -+ struct kdbus_msg *msg; -+ const struct kdbus_item *item; -+ struct kdbus_pids expected_pids; -+ struct kdbus_conn *monitor = NULL; -+ -+ kdbus_printf("STARTING TEST 'metadata-ns'.\n"); -+ -+ monitor = kdbus_hello(bus, KDBUS_HELLO_MONITOR, NULL, 0); -+ ASSERT_EXIT(monitor); -+ -+ /* -+ * parent will signal to child that is in its -+ * userns to read its queue -+ */ -+ efd = eventfd(0, EFD_CLOEXEC); -+ ASSERT_RETURN_VAL(efd >= 0, efd); -+ -+ ppid = getppid(); -+ -+ pid = fork(); -+ ASSERT_RETURN_VAL(pid >= 0, -errno); -+ -+ if (pid == 0) { -+ ret = prctl(PR_SET_PDEATHSIG, SIGKILL); -+ ASSERT_EXIT_VAL(ret == 0, -errno); -+ -+ ret = __kdbus_clone_userns_test(bus, conn, ppid, efd); -+ _exit(ret); -+ } -+ -+ -+ /* Phase 1) privileged receives from unprivileged */ -+ -+ /* -+ * Receive from the unprivileged child -+ */ -+ kdbus_printf("\nUnprivileged → privileged (same namespaces):\n"); -+ ret = kdbus_msg_recv_poll(conn, 300, &msg, NULL); -+ ASSERT_RETURN(ret == 0); -+ -+ unpriv_conn_id = msg->src_id; -+ -+ /* Unprivileged user */ -+ ret = kdbus_match_kdbus_creds(msg, &unmapped_creds); -+ ASSERT_RETURN(ret == 0); -+ -+ /* Set the expected creds_pids */ -+ expected_pids = (struct kdbus_pids) { -+ .pid = pid, -+ .tid = pid, -+ .ppid = getpid(), -+ }; -+ ret = kdbus_match_kdbus_pids(msg, &expected_pids); -+ ASSERT_RETURN(ret == 0); -+ -+ kdbus_msg_free(msg); -+ -+ -+ /* -+ * Receive from the unprivileged that is in his own -+ * userns and pidns -+ */ -+ -+ kdbus_printf("\nUnprivileged/privileged in its userns → privileged " -+ "(different userns and pidns)\n"); -+ ret = kdbus_msg_recv_poll(conn, 300, &msg, NULL); -+ if (ret == -ETIMEDOUT) -+ /* perhaps unprivileged userns is not allowed */ -+ goto wait; -+ -+ ASSERT_RETURN(ret == 0); -+ -+ userns_conn_id = msg->src_id; -+ -+ /* We do not share the userns, os no KDBUS_ITEM_CAPS */ -+ item = kdbus_get_item(msg, KDBUS_ITEM_CAPS); -+ ASSERT_RETURN(item == NULL); -+ -+ /* -+ * Compare received items, creds must be translated into -+ * the receiver user namespace, so the user is unprivileged -+ */ -+ ret = kdbus_match_kdbus_creds(msg, &unmapped_creds); -+ ASSERT_RETURN(ret == 0); -+ -+ /* -+ * We should have the kdbus_pids since we are the parent -+ * pidns -+ */ -+ item = kdbus_get_item(msg, KDBUS_ITEM_PIDS); -+ ASSERT_RETURN(item); -+ -+ ASSERT_RETURN(memcmp(&item->pids, &unmapped_pids, -+ sizeof(struct kdbus_pids)) != 0); -+ -+ /* -+ * Parent pid of the unprivileged/privileged in its userns -+ * is the unprivileged child pid that was forked here. -+ */ -+ ASSERT_RETURN((uint64_t)pid == item->pids.ppid); -+ -+ kdbus_msg_free(msg); -+ -+ -+ /* Phase 2) Privileged connection sends now 3 packets */ -+ -+ /* -+ * Sending to unprivileged connections a unicast -+ */ -+ ret = kdbus_msg_send(conn, NULL, 0xdeadbeef, 0, 0, -+ 0, unpriv_conn_id); -+ ASSERT_RETURN(ret == 0); -+ -+ /* signal to child that is in its userns */ -+ ret = eventfd_write(efd, 1); -+ ASSERT_EXIT(ret == 0); -+ -+ /* -+ * Sending to unprivileged/privilged in its userns -+ * connections a unicast -+ */ -+ ret = kdbus_msg_send(conn, NULL, 0xdeadbeef, 0, 0, -+ 0, userns_conn_id); -+ ASSERT_RETURN(ret == 0); -+ -+ /* -+ * Sending to unprivileged connections a broadcast -+ */ -+ ret = kdbus_msg_send(conn, NULL, 0xdeadbeef, 0, 0, -+ 0, KDBUS_DST_ID_BROADCAST); -+ ASSERT_RETURN(ret == 0); -+ -+ -+wait: -+ ret = waitpid(pid, &status, 0); -+ ASSERT_RETURN(ret >= 0); -+ -+ ASSERT_RETURN(WIFEXITED(status)) -+ ASSERT_RETURN(!WEXITSTATUS(status)); -+ -+ /* Dump monitor queue */ -+ kdbus_printf("\n\nMonitor queue:\n"); -+ for (;;) { -+ ret = kdbus_msg_recv_poll(monitor, 100, &msg, NULL); -+ if (ret < 0) -+ break; -+ -+ if (msg->payload_type == KDBUS_PAYLOAD_DBUS) { -+ /* -+ * Parent pidns should see all the -+ * pids -+ */ -+ item = kdbus_get_item(msg, KDBUS_ITEM_PIDS); -+ ASSERT_RETURN(item); -+ -+ ASSERT_RETURN(item->pids.pid != 0 && -+ item->pids.tid != 0 && -+ item->pids.ppid != 0); -+ } -+ -+ kdbus_msg_free(msg); -+ } -+ -+ kdbus_conn_free(monitor); -+ close(efd); -+ -+ return 0; -+} -+ -+int kdbus_test_metadata_ns(struct kdbus_test_env *env) -+{ -+ int ret; -+ struct kdbus_conn *holder, *conn; -+ struct kdbus_policy_access policy_access = { -+ /* Allow world so we can inspect metadata in namespace */ -+ .type = KDBUS_POLICY_ACCESS_WORLD, -+ .id = geteuid(), -+ .access = KDBUS_POLICY_TALK, -+ }; -+ -+ /* -+ * We require user-namespaces and all uids/gids -+ * should be mapped (we can just require the necessary ones) -+ */ -+ if (!config_user_ns_is_enabled() || -+ !all_uids_gids_are_mapped()) -+ return TEST_SKIP; -+ -+ ret = test_is_capable(CAP_SETUID, CAP_SETGID, CAP_SYS_ADMIN, -1); -+ ASSERT_RETURN(ret >= 0); -+ -+ /* no enough privileges, SKIP test */ -+ if (!ret) -+ return TEST_SKIP; -+ -+ holder = kdbus_hello_registrar(env->buspath, "com.example.metadata", -+ &policy_access, 1, -+ KDBUS_HELLO_POLICY_HOLDER); -+ ASSERT_RETURN(holder); -+ -+ conn = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(conn); -+ -+ ret = kdbus_add_match_empty(conn); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_name_acquire(conn, "com.example.metadata", NULL); -+ ASSERT_EXIT(ret >= 0); -+ -+ ret = kdbus_clone_userns_test(env->buspath, conn); -+ ASSERT_RETURN(ret == 0); -+ -+ kdbus_conn_free(holder); -+ kdbus_conn_free(conn); -+ -+ return TEST_OK; -+} -diff --git a/tools/testing/selftests/kdbus/test-monitor.c b/tools/testing/selftests/kdbus/test-monitor.c -new file mode 100644 -index 000000000000..e00d738a3986 ---- /dev/null -+++ b/tools/testing/selftests/kdbus/test-monitor.c -@@ -0,0 +1,176 @@ -+#include <stdio.h> -+#include <string.h> -+#include <time.h> -+#include <fcntl.h> -+#include <stdlib.h> -+#include <stddef.h> -+#include <unistd.h> -+#include <stdint.h> -+#include <stdbool.h> -+#include <errno.h> -+#include <assert.h> -+#include <signal.h> -+#include <sys/time.h> -+#include <sys/mman.h> -+#include <sys/capability.h> -+#include <sys/wait.h> -+ -+#include "kdbus-util.h" -+#include "kdbus-enum.h" -+ -+#include "kdbus-util.h" -+#include "kdbus-enum.h" -+#include "kdbus-test.h" -+ -+int kdbus_test_monitor(struct kdbus_test_env *env) -+{ -+ struct kdbus_conn *monitor, *conn; -+ unsigned int cookie = 0xdeadbeef; -+ struct kdbus_msg *msg; -+ uint64_t offset = 0; -+ int ret; -+ -+ conn = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(conn); -+ -+ /* add matches to make sure the monitor do not trigger an item add or -+ * remove on connect and disconnect, respectively. -+ */ -+ ret = kdbus_add_match_id(conn, 0x1, KDBUS_ITEM_ID_ADD, -+ KDBUS_MATCH_ID_ANY); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_add_match_id(conn, 0x2, KDBUS_ITEM_ID_REMOVE, -+ KDBUS_MATCH_ID_ANY); -+ ASSERT_RETURN(ret == 0); -+ -+ /* register a monitor */ -+ monitor = kdbus_hello(env->buspath, KDBUS_HELLO_MONITOR, NULL, 0); -+ ASSERT_RETURN(monitor); -+ -+ /* make sure we did not receive a monitor connect notification */ -+ ret = kdbus_msg_recv(conn, &msg, &offset); -+ ASSERT_RETURN(ret == -EAGAIN); -+ -+ /* check that a monitor cannot acquire a name */ -+ ret = kdbus_name_acquire(monitor, "foo.bar.baz", NULL); -+ ASSERT_RETURN(ret == -EOPNOTSUPP); -+ -+ ret = kdbus_msg_send(env->conn, NULL, cookie, 0, 0, 0, conn->id); -+ ASSERT_RETURN(ret == 0); -+ -+ /* the recipient should have gotten the message */ -+ ret = kdbus_msg_recv(conn, &msg, &offset); -+ ASSERT_RETURN(ret == 0); -+ ASSERT_RETURN(msg->cookie == cookie); -+ kdbus_msg_free(msg); -+ kdbus_free(conn, offset); -+ -+ /* and so should the monitor */ -+ ret = kdbus_msg_recv(monitor, &msg, &offset); -+ ASSERT_RETURN(ret == 0); -+ ASSERT_RETURN(msg->cookie == cookie); -+ -+ kdbus_msg_free(msg); -+ kdbus_free(monitor, offset); -+ -+ /* Installing matches for monitors must fais must fail */ -+ ret = kdbus_add_match_empty(monitor); -+ ASSERT_RETURN(ret == -EOPNOTSUPP); -+ -+ cookie++; -+ ret = kdbus_msg_send(env->conn, NULL, cookie, 0, 0, 0, -+ KDBUS_DST_ID_BROADCAST); -+ ASSERT_RETURN(ret == 0); -+ -+ /* The monitor should get the message. */ -+ ret = kdbus_msg_recv_poll(monitor, 100, &msg, &offset); -+ ASSERT_RETURN(ret == 0); -+ ASSERT_RETURN(msg->cookie == cookie); -+ -+ kdbus_msg_free(msg); -+ kdbus_free(monitor, offset); -+ -+ /* -+ * Since we are the only monitor, update the attach flags -+ * and tell we are not interessted in attach flags recv -+ */ -+ -+ ret = kdbus_conn_update_attach_flags(monitor, -+ _KDBUS_ATTACH_ALL, -+ 0); -+ ASSERT_RETURN(ret == 0); -+ -+ cookie++; -+ ret = kdbus_msg_send(env->conn, NULL, cookie, 0, 0, 0, -+ KDBUS_DST_ID_BROADCAST); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_msg_recv_poll(monitor, 100, &msg, &offset); -+ ASSERT_RETURN(ret == 0); -+ ASSERT_RETURN(msg->cookie == cookie); -+ -+ ret = kdbus_item_in_message(msg, KDBUS_ITEM_TIMESTAMP); -+ ASSERT_RETURN(ret == 0); -+ -+ kdbus_msg_free(msg); -+ kdbus_free(monitor, offset); -+ -+ /* -+ * Now we are interested in KDBUS_ITEM_TIMESTAMP and -+ * KDBUS_ITEM_CREDS -+ */ -+ ret = kdbus_conn_update_attach_flags(monitor, -+ _KDBUS_ATTACH_ALL, -+ KDBUS_ATTACH_TIMESTAMP | -+ KDBUS_ATTACH_CREDS); -+ ASSERT_RETURN(ret == 0); -+ -+ cookie++; -+ ret = kdbus_msg_send(env->conn, NULL, cookie, 0, 0, 0, -+ KDBUS_DST_ID_BROADCAST); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_msg_recv_poll(monitor, 100, &msg, &offset); -+ ASSERT_RETURN(ret == 0); -+ ASSERT_RETURN(msg->cookie == cookie); -+ -+ ret = kdbus_item_in_message(msg, KDBUS_ITEM_TIMESTAMP); -+ ASSERT_RETURN(ret == 1); -+ -+ ret = kdbus_item_in_message(msg, KDBUS_ITEM_CREDS); -+ ASSERT_RETURN(ret == 1); -+ -+ /* the KDBUS_ITEM_PID_COMM was not requested */ -+ ret = kdbus_item_in_message(msg, KDBUS_ITEM_PID_COMM); -+ ASSERT_RETURN(ret == 0); -+ -+ kdbus_msg_free(msg); -+ kdbus_free(monitor, offset); -+ -+ kdbus_conn_free(monitor); -+ /* make sure we did not receive a monitor disconnect notification */ -+ ret = kdbus_msg_recv(conn, &msg, &offset); -+ ASSERT_RETURN(ret == -EAGAIN); -+ -+ kdbus_conn_free(conn); -+ -+ /* Make sure that monitor as unprivileged is not allowed */ -+ ret = test_is_capable(CAP_SETUID, CAP_SETGID, -1); -+ ASSERT_RETURN(ret >= 0); -+ -+ if (ret && all_uids_gids_are_mapped()) { -+ ret = RUN_UNPRIVILEGED(UNPRIV_UID, UNPRIV_UID, ({ -+ monitor = kdbus_hello(env->buspath, -+ KDBUS_HELLO_MONITOR, -+ NULL, 0); -+ ASSERT_EXIT(!monitor && errno == EPERM); -+ -+ _exit(EXIT_SUCCESS); -+ }), -+ ({ 0; })); -+ ASSERT_RETURN(ret == 0); -+ } -+ -+ return TEST_OK; -+} -diff --git a/tools/testing/selftests/kdbus/test-names.c b/tools/testing/selftests/kdbus/test-names.c -new file mode 100644 -index 000000000000..66ebb47370eb ---- /dev/null -+++ b/tools/testing/selftests/kdbus/test-names.c -@@ -0,0 +1,194 @@ -+#include <stdio.h> -+#include <string.h> -+#include <time.h> -+#include <fcntl.h> -+#include <stdlib.h> -+#include <stddef.h> -+#include <unistd.h> -+#include <stdint.h> -+#include <errno.h> -+#include <assert.h> -+#include <limits.h> -+#include <getopt.h> -+#include <stdbool.h> -+ -+#include "kdbus-api.h" -+#include "kdbus-util.h" -+#include "kdbus-enum.h" -+#include "kdbus-test.h" -+ -+static int conn_is_name_owner(const struct kdbus_conn *conn, -+ const char *needle) -+{ -+ struct kdbus_cmd_list cmd_list = { .size = sizeof(cmd_list) }; -+ struct kdbus_info *name, *list; -+ bool found = false; -+ int ret; -+ -+ cmd_list.flags = KDBUS_LIST_NAMES; -+ -+ ret = kdbus_cmd_list(conn->fd, &cmd_list); -+ ASSERT_RETURN(ret == 0); -+ -+ list = (struct kdbus_info *)(conn->buf + cmd_list.offset); -+ KDBUS_FOREACH(name, list, cmd_list.list_size) { -+ struct kdbus_item *item; -+ const char *n = NULL; -+ -+ KDBUS_ITEM_FOREACH(item, name, items) -+ if (item->type == KDBUS_ITEM_OWNED_NAME) -+ n = item->name.name; -+ -+ if (name->id == conn->id && -+ n && strcmp(needle, n) == 0) { -+ found = true; -+ break; -+ } -+ } -+ -+ ret = kdbus_free(conn, cmd_list.offset); -+ ASSERT_RETURN(ret == 0); -+ -+ return found ? 0 : -1; -+} -+ -+int kdbus_test_name_basic(struct kdbus_test_env *env) -+{ -+ struct kdbus_conn *conn; -+ char *name, *dot_name, *invalid_name, *wildcard_name; -+ int ret; -+ -+ name = "foo.bla.blaz"; -+ dot_name = ".bla.blaz"; -+ invalid_name = "foo"; -+ wildcard_name = "foo.bla.bl.*"; -+ -+ /* create a 2nd connection */ -+ conn = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(conn != NULL); -+ -+ /* acquire name "foo.bar.xxx" name */ -+ ret = kdbus_name_acquire(conn, "foo.bar.xxx", NULL); -+ ASSERT_RETURN(ret == 0); -+ -+ /* Name is not valid, must fail */ -+ ret = kdbus_name_acquire(env->conn, dot_name, NULL); -+ ASSERT_RETURN(ret == -EINVAL); -+ -+ ret = kdbus_name_acquire(env->conn, invalid_name, NULL); -+ ASSERT_RETURN(ret == -EINVAL); -+ -+ ret = kdbus_name_acquire(env->conn, wildcard_name, NULL); -+ ASSERT_RETURN(ret == -EINVAL); -+ -+ /* check that we can acquire a name */ -+ ret = kdbus_name_acquire(env->conn, name, NULL); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = conn_is_name_owner(env->conn, name); -+ ASSERT_RETURN(ret == 0); -+ -+ /* ... and release it again */ -+ ret = kdbus_name_release(env->conn, name); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = conn_is_name_owner(env->conn, name); -+ ASSERT_RETURN(ret != 0); -+ -+ /* check that we can't release it again */ -+ ret = kdbus_name_release(env->conn, name); -+ ASSERT_RETURN(ret == -ESRCH); -+ -+ /* check that we can't release a name that we don't own */ -+ ret = kdbus_name_release(env->conn, "foo.bar.xxx"); -+ ASSERT_RETURN(ret == -EADDRINUSE); -+ -+ /* Name is not valid, must fail */ -+ ret = kdbus_name_release(env->conn, dot_name); -+ ASSERT_RETURN(ret == -ESRCH); -+ -+ ret = kdbus_name_release(env->conn, invalid_name); -+ ASSERT_RETURN(ret == -ESRCH); -+ -+ ret = kdbus_name_release(env->conn, wildcard_name); -+ ASSERT_RETURN(ret == -ESRCH); -+ -+ kdbus_conn_free(conn); -+ -+ return TEST_OK; -+} -+ -+int kdbus_test_name_conflict(struct kdbus_test_env *env) -+{ -+ struct kdbus_conn *conn; -+ char *name; -+ int ret; -+ -+ name = "foo.bla.blaz"; -+ -+ /* create a 2nd connection */ -+ conn = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(conn != NULL); -+ -+ /* allow the new connection to own the same name */ -+ /* acquire name from the 1st connection */ -+ ret = kdbus_name_acquire(env->conn, name, NULL); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = conn_is_name_owner(env->conn, name); -+ ASSERT_RETURN(ret == 0); -+ -+ /* check that we can't acquire it again from the 1st connection */ -+ ret = kdbus_name_acquire(env->conn, name, NULL); -+ ASSERT_RETURN(ret == -EALREADY); -+ -+ /* check that we also can't acquire it again from the 2nd connection */ -+ ret = kdbus_name_acquire(conn, name, NULL); -+ ASSERT_RETURN(ret == -EEXIST); -+ -+ kdbus_conn_free(conn); -+ -+ return TEST_OK; -+} -+ -+int kdbus_test_name_queue(struct kdbus_test_env *env) -+{ -+ struct kdbus_conn *conn; -+ const char *name; -+ uint64_t flags; -+ int ret; -+ -+ name = "foo.bla.blaz"; -+ -+ flags = KDBUS_NAME_ALLOW_REPLACEMENT; -+ -+ /* create a 2nd connection */ -+ conn = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(conn != NULL); -+ -+ /* allow the new connection to own the same name */ -+ /* acquire name from the 1st connection */ -+ ret = kdbus_name_acquire(env->conn, name, &flags); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = conn_is_name_owner(env->conn, name); -+ ASSERT_RETURN(ret == 0); -+ -+ /* queue the 2nd connection as waiting owner */ -+ flags = KDBUS_NAME_QUEUE; -+ ret = kdbus_name_acquire(conn, name, &flags); -+ ASSERT_RETURN(ret == 0); -+ ASSERT_RETURN(flags & KDBUS_NAME_IN_QUEUE); -+ -+ /* release name from 1st connection */ -+ ret = kdbus_name_release(env->conn, name); -+ ASSERT_RETURN(ret == 0); -+ -+ /* now the name should be owned by the 2nd connection */ -+ ret = conn_is_name_owner(conn, name); -+ ASSERT_RETURN(ret == 0); -+ -+ kdbus_conn_free(conn); -+ -+ return TEST_OK; -+} -diff --git a/tools/testing/selftests/kdbus/test-policy-ns.c b/tools/testing/selftests/kdbus/test-policy-ns.c -new file mode 100644 -index 000000000000..3437012f90af ---- /dev/null -+++ b/tools/testing/selftests/kdbus/test-policy-ns.c -@@ -0,0 +1,632 @@ -+/* -+ * Test metadata and policies in new namespaces. Even if our tests -+ * can run in a namespaced setup, this test is necessary so we can -+ * inspect policies on the same kdbusfs but between multiple -+ * namespaces. -+ * -+ * Copyright (C) 2014-2015 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 <stdio.h> -+#include <string.h> -+#include <fcntl.h> -+#include <pthread.h> -+#include <sched.h> -+#include <stdlib.h> -+#include <stddef.h> -+#include <stdint.h> -+#include <stdbool.h> -+#include <unistd.h> -+#include <errno.h> -+#include <signal.h> -+#include <sys/wait.h> -+#include <sys/prctl.h> -+#include <sys/eventfd.h> -+#include <sys/syscall.h> -+#include <sys/capability.h> -+#include <linux/sched.h> -+ -+#include "kdbus-test.h" -+#include "kdbus-util.h" -+#include "kdbus-enum.h" -+ -+#define MAX_CONN 64 -+#define POLICY_NAME "foo.test.policy-test" -+ -+#define KDBUS_CONN_MAX_MSGS_PER_USER 16 -+ -+/** -+ * Note: this test can be used to inspect policy_db->talk_access_hash -+ * -+ * The purpose of these tests: -+ * 1) Check KDBUS_POLICY_TALK -+ * 2) Check the cache state: kdbus_policy_db->talk_access_hash -+ * Should be extended -+ */ -+ -+/** -+ * Check a list of connections against conn_db[0] -+ * conn_db[0] will own the name "foo.test.policy-test" and the -+ * policy holder connection for this name will update the policy -+ * entries, so different use cases can be tested. -+ */ -+static struct kdbus_conn **conn_db; -+ -+static void *kdbus_recv_echo(void *ptr) -+{ -+ int ret; -+ struct kdbus_conn *conn = ptr; -+ -+ ret = kdbus_msg_recv_poll(conn, 200, NULL, NULL); -+ -+ return (void *)(long)ret; -+} -+ -+/* Trigger kdbus_policy_set() */ -+static int kdbus_set_policy_talk(struct kdbus_conn *conn, -+ const char *name, -+ uid_t id, unsigned int type) -+{ -+ int ret; -+ struct kdbus_policy_access access = { -+ .type = type, -+ .id = id, -+ .access = KDBUS_POLICY_TALK, -+ }; -+ -+ ret = kdbus_conn_update_policy(conn, name, &access, 1); -+ ASSERT_RETURN(ret == 0); -+ -+ return TEST_OK; -+} -+ -+/* return TEST_OK or TEST_ERR on failure */ -+static int kdbus_register_same_activator(char *bus, const char *name, -+ struct kdbus_conn **c) -+{ -+ int ret; -+ struct kdbus_conn *activator; -+ -+ activator = kdbus_hello_activator(bus, name, NULL, 0); -+ if (activator) { -+ *c = activator; -+ fprintf(stderr, "--- error was able to register name twice '%s'.\n", -+ name); -+ return TEST_ERR; -+ } -+ -+ ret = -errno; -+ /* -EEXIST means test succeeded */ -+ if (ret == -EEXIST) -+ return TEST_OK; -+ -+ return TEST_ERR; -+} -+ -+/* return TEST_OK or TEST_ERR on failure */ -+static int kdbus_register_policy_holder(char *bus, const char *name, -+ struct kdbus_conn **conn) -+{ -+ struct kdbus_conn *c; -+ struct kdbus_policy_access access[2]; -+ -+ access[0].type = KDBUS_POLICY_ACCESS_USER; -+ access[0].access = KDBUS_POLICY_OWN; -+ access[0].id = geteuid(); -+ -+ access[1].type = KDBUS_POLICY_ACCESS_WORLD; -+ access[1].access = KDBUS_POLICY_TALK; -+ access[1].id = geteuid(); -+ -+ c = kdbus_hello_registrar(bus, name, access, 2, -+ KDBUS_HELLO_POLICY_HOLDER); -+ ASSERT_RETURN(c); -+ -+ *conn = c; -+ -+ return TEST_OK; -+} -+ -+/** -+ * Create new threads for receiving from multiple senders, -+ * The 'conn_db' will be populated by newly created connections. -+ * Caller should free all allocated connections. -+ * -+ * return 0 on success, negative errno on failure. -+ */ -+static int kdbus_recv_in_threads(const char *bus, const char *name, -+ struct kdbus_conn **conn_db) -+{ -+ int ret; -+ bool pool_full = false; -+ unsigned int sent_packets = 0; -+ unsigned int lost_packets = 0; -+ unsigned int i, tid; -+ unsigned long dst_id; -+ unsigned long cookie = 1; -+ unsigned int thread_nr = MAX_CONN - 1; -+ pthread_t thread_id[MAX_CONN - 1] = {'\0'}; -+ -+ dst_id = name ? KDBUS_DST_ID_NAME : conn_db[0]->id; -+ -+ for (tid = 0, i = 1; tid < thread_nr; tid++, i++) { -+ ret = pthread_create(&thread_id[tid], NULL, -+ kdbus_recv_echo, (void *)conn_db[0]); -+ if (ret < 0) { -+ ret = -errno; -+ kdbus_printf("error pthread_create: %d (%m)\n", -+ ret); -+ break; -+ } -+ -+ /* just free before re-using */ -+ kdbus_conn_free(conn_db[i]); -+ conn_db[i] = NULL; -+ -+ /* We need to create connections here */ -+ conn_db[i] = kdbus_hello(bus, 0, NULL, 0); -+ if (!conn_db[i]) { -+ ret = -errno; -+ break; -+ } -+ -+ ret = kdbus_add_match_empty(conn_db[i]); -+ if (ret < 0) -+ break; -+ -+ ret = kdbus_msg_send(conn_db[i], name, cookie++, -+ 0, 0, 0, dst_id); -+ if (ret < 0) { -+ /* -+ * Receivers are not reading their messages, -+ * not scheduled ?! -+ * -+ * So set the pool full here, perhaps the -+ * connection pool or queue was full, later -+ * recheck receivers errors -+ */ -+ if (ret == -ENOBUFS || ret == -EXFULL) -+ pool_full = true; -+ break; -+ } -+ -+ sent_packets++; -+ } -+ -+ for (tid = 0; tid < thread_nr; tid++) { -+ int thread_ret = 0; -+ -+ if (thread_id[tid]) { -+ pthread_join(thread_id[tid], (void *)&thread_ret); -+ if (thread_ret < 0) { -+ /* Update only if send did not fail */ -+ if (ret == 0) -+ ret = thread_ret; -+ -+ lost_packets++; -+ } -+ } -+ } -+ -+ /* -+ * When sending if we did fail with -ENOBUFS or -EXFULL -+ * then we should have set lost_packet and we should at -+ * least have sent_packets set to KDBUS_CONN_MAX_MSGS_PER_USER -+ */ -+ if (pool_full) { -+ ASSERT_RETURN(lost_packets > 0); -+ -+ /* -+ * We should at least send KDBUS_CONN_MAX_MSGS_PER_USER -+ * -+ * For every send operation we create a thread to -+ * recv the packet, so we keep the queue clean -+ */ -+ ASSERT_RETURN(sent_packets >= KDBUS_CONN_MAX_MSGS_PER_USER); -+ -+ /* -+ * Set ret to zero since we only failed due to -+ * the receiving threads that have not been -+ * scheduled -+ */ -+ ret = 0; -+ } -+ -+ return ret; -+} -+ -+/* Return: TEST_OK or TEST_ERR on failure */ -+static int kdbus_normal_test(const char *bus, const char *name, -+ struct kdbus_conn **conn_db) -+{ -+ int ret; -+ -+ ret = kdbus_recv_in_threads(bus, name, conn_db); -+ ASSERT_RETURN(ret >= 0); -+ -+ return TEST_OK; -+} -+ -+static int kdbus_fork_test_by_id(const char *bus, -+ struct kdbus_conn **conn_db, -+ int parent_status, int child_status) -+{ -+ int ret; -+ pid_t pid; -+ uint64_t cookie = 0x9876ecba; -+ struct kdbus_msg *msg = NULL; -+ uint64_t offset = 0; -+ int status = 0; -+ -+ /* -+ * If the child_status is not EXIT_SUCCESS, then we expect -+ * that sending from the child will fail, thus receiving -+ * from parent must error with -ETIMEDOUT, and vice versa. -+ */ -+ bool parent_timedout = !!child_status; -+ bool child_timedout = !!parent_status; -+ -+ pid = fork(); -+ ASSERT_RETURN_VAL(pid >= 0, pid); -+ -+ if (pid == 0) { -+ struct kdbus_conn *conn_src; -+ -+ ret = prctl(PR_SET_PDEATHSIG, SIGKILL); -+ ASSERT_EXIT(ret == 0); -+ -+ ret = drop_privileges(65534, 65534); -+ ASSERT_EXIT(ret == 0); -+ -+ conn_src = kdbus_hello(bus, 0, NULL, 0); -+ ASSERT_EXIT(conn_src); -+ -+ ret = kdbus_add_match_empty(conn_src); -+ ASSERT_EXIT(ret == 0); -+ -+ /* -+ * child_status is always checked against send -+ * operations, in case it fails always return -+ * EXIT_FAILURE. -+ */ -+ ret = kdbus_msg_send(conn_src, NULL, cookie, -+ 0, 0, 0, conn_db[0]->id); -+ ASSERT_EXIT(ret == child_status); -+ -+ ret = kdbus_msg_recv_poll(conn_src, 100, NULL, NULL); -+ -+ kdbus_conn_free(conn_src); -+ -+ /* -+ * Child kdbus_msg_recv_poll() should timeout since -+ * the parent_status was set to a non EXIT_SUCCESS -+ * value. -+ */ -+ if (child_timedout) -+ _exit(ret == -ETIMEDOUT ? EXIT_SUCCESS : EXIT_FAILURE); -+ -+ _exit(ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE); -+ } -+ -+ ret = kdbus_msg_recv_poll(conn_db[0], 100, &msg, &offset); -+ /* -+ * If parent_timedout is set then this should fail with -+ * -ETIMEDOUT since the child_status was set to a non -+ * EXIT_SUCCESS value. Otherwise, assume -+ * that kdbus_msg_recv_poll() has succeeded. -+ */ -+ if (parent_timedout) { -+ ASSERT_RETURN_VAL(ret == -ETIMEDOUT, TEST_ERR); -+ -+ /* timedout no need to continue, we don't have the -+ * child connection ID, so just terminate. */ -+ goto out; -+ } else { -+ ASSERT_RETURN_VAL(ret == 0, ret); -+ } -+ -+ ret = kdbus_msg_send(conn_db[0], NULL, ++cookie, -+ 0, 0, 0, msg->src_id); -+ /* -+ * parent_status is checked against send operations, -+ * on failures always return TEST_ERR. -+ */ -+ ASSERT_RETURN_VAL(ret == parent_status, TEST_ERR); -+ -+ kdbus_msg_free(msg); -+ kdbus_free(conn_db[0], offset); -+ -+out: -+ ret = waitpid(pid, &status, 0); -+ ASSERT_RETURN_VAL(ret >= 0, ret); -+ -+ return (status == EXIT_SUCCESS) ? TEST_OK : TEST_ERR; -+} -+ -+/* -+ * Return: TEST_OK, TEST_ERR or TEST_SKIP -+ * we return TEST_OK only if the children return with the expected -+ * 'expected_status' that is specified as an argument. -+ */ -+static int kdbus_fork_test(const char *bus, const char *name, -+ struct kdbus_conn **conn_db, int expected_status) -+{ -+ pid_t pid; -+ int ret = 0; -+ int status = 0; -+ -+ pid = fork(); -+ ASSERT_RETURN_VAL(pid >= 0, pid); -+ -+ if (pid == 0) { -+ ret = prctl(PR_SET_PDEATHSIG, SIGKILL); -+ ASSERT_EXIT(ret == 0); -+ -+ ret = drop_privileges(65534, 65534); -+ ASSERT_EXIT(ret == 0); -+ -+ ret = kdbus_recv_in_threads(bus, name, conn_db); -+ _exit(ret == expected_status ? EXIT_SUCCESS : EXIT_FAILURE); -+ } -+ -+ ret = waitpid(pid, &status, 0); -+ ASSERT_RETURN(ret >= 0); -+ -+ return (status == EXIT_SUCCESS) ? TEST_OK : TEST_ERR; -+} -+ -+/* Return EXIT_SUCCESS, EXIT_FAILURE or negative errno */ -+static int __kdbus_clone_userns_test(const char *bus, -+ const char *name, -+ struct kdbus_conn **conn_db, -+ int expected_status) -+{ -+ int efd; -+ pid_t pid; -+ int ret = 0; -+ unsigned int uid = 65534; -+ int status; -+ -+ ret = drop_privileges(uid, uid); -+ ASSERT_RETURN_VAL(ret == 0, ret); -+ -+ /* -+ * Since we just dropped privileges, the dumpable flag was just -+ * cleared which makes the /proc/$clone_child/uid_map to be -+ * owned by root, hence any userns uid mapping will fail with -+ * -EPERM since the mapping will be done by uid 65534. -+ * -+ * To avoid this set the dumpable flag again which makes procfs -+ * update the /proc/$clone_child/ inodes owner to 65534. -+ * -+ * Using this we will be able write to /proc/$clone_child/uid_map -+ * as uid 65534 and map the uid 65534 to 0 inside the user -+ * namespace. -+ */ -+ ret = prctl(PR_SET_DUMPABLE, SUID_DUMP_USER); -+ ASSERT_RETURN_VAL(ret == 0, ret); -+ -+ /* sync parent/child */ -+ efd = eventfd(0, EFD_CLOEXEC); -+ ASSERT_RETURN_VAL(efd >= 0, efd); -+ -+ pid = syscall(__NR_clone, SIGCHLD|CLONE_NEWUSER, NULL); -+ if (pid < 0) { -+ ret = -errno; -+ kdbus_printf("error clone: %d (%m)\n", ret); -+ /* -+ * Normal user not allowed to create userns, -+ * so nothing to worry about ? -+ */ -+ if (ret == -EPERM) { -+ kdbus_printf("-- CLONE_NEWUSER TEST Failed for uid: %u\n" -+ "-- Make sure that your kernel do not allow " -+ "CLONE_NEWUSER for unprivileged users\n" -+ "-- Upstream Commit: " -+ "https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=5eaf563e\n", -+ uid); -+ ret = 0; -+ } -+ -+ return ret; -+ } -+ -+ if (pid == 0) { -+ struct kdbus_conn *conn_src; -+ eventfd_t event_status = 0; -+ -+ ret = prctl(PR_SET_PDEATHSIG, SIGKILL); -+ ASSERT_EXIT(ret == 0); -+ -+ ret = eventfd_read(efd, &event_status); -+ ASSERT_EXIT(ret >= 0 && event_status == 1); -+ -+ /* ping connection from the new user namespace */ -+ conn_src = kdbus_hello(bus, 0, NULL, 0); -+ ASSERT_EXIT(conn_src); -+ -+ ret = kdbus_add_match_empty(conn_src); -+ ASSERT_EXIT(ret == 0); -+ -+ ret = kdbus_msg_send(conn_src, name, 0xabcd1234, -+ 0, 0, 0, KDBUS_DST_ID_NAME); -+ kdbus_conn_free(conn_src); -+ -+ _exit(ret == expected_status ? EXIT_SUCCESS : EXIT_FAILURE); -+ } -+ -+ ret = userns_map_uid_gid(pid, "0 65534 1", "0 65534 1"); -+ ASSERT_RETURN_VAL(ret == 0, ret); -+ -+ /* Tell child we are ready */ -+ ret = eventfd_write(efd, 1); -+ ASSERT_RETURN_VAL(ret == 0, ret); -+ -+ ret = waitpid(pid, &status, 0); -+ ASSERT_RETURN_VAL(ret >= 0, ret); -+ -+ close(efd); -+ -+ return status == EXIT_SUCCESS ? TEST_OK : TEST_ERR; -+} -+ -+static int kdbus_clone_userns_test(const char *bus, -+ const char *name, -+ struct kdbus_conn **conn_db, -+ int expected_status) -+{ -+ pid_t pid; -+ int ret = 0; -+ int status; -+ -+ pid = fork(); -+ ASSERT_RETURN_VAL(pid >= 0, -errno); -+ -+ if (pid == 0) { -+ ret = prctl(PR_SET_PDEATHSIG, SIGKILL); -+ if (ret < 0) -+ _exit(EXIT_FAILURE); -+ -+ ret = __kdbus_clone_userns_test(bus, name, conn_db, -+ expected_status); -+ _exit(ret); -+ } -+ -+ /* -+ * Receive in the original (root privileged) user namespace, -+ * must fail with -ETIMEDOUT. -+ */ -+ ret = kdbus_msg_recv_poll(conn_db[0], 100, NULL, NULL); -+ ASSERT_RETURN_VAL(ret == -ETIMEDOUT, ret); -+ -+ ret = waitpid(pid, &status, 0); -+ ASSERT_RETURN_VAL(ret >= 0, ret); -+ -+ return (status == EXIT_SUCCESS) ? TEST_OK : TEST_ERR; -+} -+ -+int kdbus_test_policy_ns(struct kdbus_test_env *env) -+{ -+ int i; -+ int ret; -+ struct kdbus_conn *activator = NULL; -+ struct kdbus_conn *policy_holder = NULL; -+ char *bus = env->buspath; -+ -+ ret = test_is_capable(CAP_SETUID, CAP_SETGID, -1); -+ ASSERT_RETURN(ret >= 0); -+ -+ /* no enough privileges, SKIP test */ -+ if (!ret) -+ return TEST_SKIP; -+ -+ /* we require user-namespaces */ -+ if (access("/proc/self/uid_map", F_OK) != 0) -+ return TEST_SKIP; -+ -+ /* uids/gids must be mapped */ -+ if (!all_uids_gids_are_mapped()) -+ return TEST_SKIP; -+ -+ conn_db = calloc(MAX_CONN, sizeof(struct kdbus_conn *)); -+ ASSERT_RETURN(conn_db); -+ -+ memset(conn_db, 0, MAX_CONN * sizeof(struct kdbus_conn *)); -+ -+ conn_db[0] = kdbus_hello(bus, 0, NULL, 0); -+ ASSERT_RETURN(conn_db[0]); -+ -+ ret = kdbus_add_match_empty(conn_db[0]); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_fork_test_by_id(bus, conn_db, -EPERM, -EPERM); -+ ASSERT_EXIT(ret == 0); -+ -+ ret = kdbus_register_policy_holder(bus, POLICY_NAME, -+ &policy_holder); -+ ASSERT_RETURN(ret == 0); -+ -+ /* Try to register the same name with an activator */ -+ ret = kdbus_register_same_activator(bus, POLICY_NAME, -+ &activator); -+ ASSERT_RETURN(ret == 0); -+ -+ /* Acquire POLICY_NAME */ -+ ret = kdbus_name_acquire(conn_db[0], POLICY_NAME, NULL); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_normal_test(bus, POLICY_NAME, conn_db); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_list(conn_db[0], KDBUS_LIST_NAMES | -+ KDBUS_LIST_UNIQUE | -+ KDBUS_LIST_ACTIVATORS | -+ KDBUS_LIST_QUEUED); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_fork_test(bus, POLICY_NAME, conn_db, EXIT_SUCCESS); -+ ASSERT_RETURN(ret == 0); -+ -+ /* -+ * children connections are able to talk to conn_db[0] since -+ * current POLICY_NAME TALK type is KDBUS_POLICY_ACCESS_WORLD, -+ * so expect EXIT_SUCCESS when sending from child. However, -+ * since the child's connection does not own any well-known -+ * name, The parent connection conn_db[0] should fail with -+ * -EPERM but since it is a privileged bus user the TALK is -+ * allowed. -+ */ -+ ret = kdbus_fork_test_by_id(bus, conn_db, -+ EXIT_SUCCESS, EXIT_SUCCESS); -+ ASSERT_EXIT(ret == 0); -+ -+ /* -+ * Connections that can talk are perhaps being destroyed now. -+ * Restrict the policy and purge cache entries where the -+ * conn_db[0] is the destination. -+ * -+ * Now only connections with uid == 0 are allowed to talk. -+ */ -+ ret = kdbus_set_policy_talk(policy_holder, POLICY_NAME, -+ geteuid(), KDBUS_POLICY_ACCESS_USER); -+ ASSERT_RETURN(ret == 0); -+ -+ /* -+ * Testing connections (FORK+DROP) again: -+ * After setting the policy re-check connections -+ * we expect the children to fail with -EPERM -+ */ -+ ret = kdbus_fork_test(bus, POLICY_NAME, conn_db, -EPERM); -+ ASSERT_RETURN(ret == 0); -+ -+ /* -+ * Now expect that both parent and child to fail. -+ * -+ * Child should fail with -EPERM since we just restricted -+ * the POLICY_NAME TALK to uid 0 and its uid is 65534. -+ * -+ * Since the parent's connection will timeout when receiving -+ * from the child, we never continue. FWIW just put -EPERM. -+ */ -+ ret = kdbus_fork_test_by_id(bus, conn_db, -EPERM, -EPERM); -+ ASSERT_EXIT(ret == 0); -+ -+ /* Check if the name can be reached in a new userns */ -+ ret = kdbus_clone_userns_test(bus, POLICY_NAME, conn_db, -EPERM); -+ ASSERT_RETURN(ret == 0); -+ -+ for (i = 0; i < MAX_CONN; i++) -+ kdbus_conn_free(conn_db[i]); -+ -+ kdbus_conn_free(activator); -+ kdbus_conn_free(policy_holder); -+ -+ free(conn_db); -+ -+ return ret; -+} -diff --git a/tools/testing/selftests/kdbus/test-policy-priv.c b/tools/testing/selftests/kdbus/test-policy-priv.c -new file mode 100644 -index 000000000000..a318cccad0d5 ---- /dev/null -+++ b/tools/testing/selftests/kdbus/test-policy-priv.c -@@ -0,0 +1,1269 @@ -+#include <errno.h> -+#include <stdio.h> -+#include <string.h> -+#include <fcntl.h> -+#include <stdlib.h> -+#include <stdint.h> -+#include <stdbool.h> -+#include <unistd.h> -+#include <time.h> -+#include <sys/capability.h> -+#include <sys/eventfd.h> -+#include <sys/wait.h> -+ -+#include "kdbus-test.h" -+#include "kdbus-util.h" -+#include "kdbus-enum.h" -+ -+static int test_policy_priv_by_id(const char *bus, -+ struct kdbus_conn *conn_dst, -+ bool drop_second_user, -+ int parent_status, -+ int child_status) -+{ -+ int ret = 0; -+ uint64_t expected_cookie = time(NULL) ^ 0xdeadbeef; -+ -+ ASSERT_RETURN(conn_dst); -+ -+ ret = RUN_UNPRIVILEGED_CONN(unpriv, bus, ({ -+ ret = kdbus_msg_send(unpriv, NULL, -+ expected_cookie, 0, 0, 0, -+ conn_dst->id); -+ ASSERT_EXIT(ret == child_status); -+ })); -+ ASSERT_RETURN(ret >= 0); -+ -+ ret = kdbus_msg_recv_poll(conn_dst, 300, NULL, NULL); -+ ASSERT_RETURN(ret == parent_status); -+ -+ return 0; -+} -+ -+static int test_policy_priv_by_broadcast(const char *bus, -+ struct kdbus_conn *conn_dst, -+ int drop_second_user, -+ int parent_status, -+ int child_status) -+{ -+ int efd; -+ int ret = 0; -+ eventfd_t event_status = 0; -+ struct kdbus_msg *msg = NULL; -+ uid_t second_uid = UNPRIV_UID; -+ gid_t second_gid = UNPRIV_GID; -+ struct kdbus_conn *child_2 = conn_dst; -+ uint64_t expected_cookie = time(NULL) ^ 0xdeadbeef; -+ -+ /* Drop to another unprivileged user other than UNPRIV_UID */ -+ if (drop_second_user == DROP_OTHER_UNPRIV) { -+ second_uid = UNPRIV_UID - 1; -+ second_gid = UNPRIV_GID - 1; -+ } -+ -+ /* child will signal parent to send broadcast */ -+ efd = eventfd(0, EFD_CLOEXEC); -+ ASSERT_RETURN_VAL(efd >= 0, efd); -+ -+ ret = RUN_UNPRIVILEGED(UNPRIV_UID, UNPRIV_GID, ({ -+ struct kdbus_conn *child; -+ -+ child = kdbus_hello(bus, 0, NULL, 0); -+ ASSERT_EXIT(child); -+ -+ ret = kdbus_add_match_empty(child); -+ ASSERT_EXIT(ret == 0); -+ -+ /* signal parent */ -+ ret = eventfd_write(efd, 1); -+ ASSERT_EXIT(ret == 0); -+ -+ /* Use a little bit high time */ -+ ret = kdbus_msg_recv_poll(child, 500, &msg, NULL); -+ ASSERT_EXIT(ret == child_status); -+ -+ /* -+ * If we expect the child to get the broadcast -+ * message, then check the received cookie. -+ */ -+ if (ret == 0) { -+ ASSERT_EXIT(expected_cookie == msg->cookie); -+ } -+ -+ /* Use expected_cookie since 'msg' might be NULL */ -+ ret = kdbus_msg_send(child, NULL, expected_cookie + 1, -+ 0, 0, 0, KDBUS_DST_ID_BROADCAST); -+ ASSERT_EXIT(ret == 0); -+ -+ kdbus_msg_free(msg); -+ kdbus_conn_free(child); -+ }), -+ ({ -+ if (drop_second_user == DO_NOT_DROP) { -+ ASSERT_RETURN(child_2); -+ -+ ret = eventfd_read(efd, &event_status); -+ ASSERT_RETURN(ret >= 0 && event_status == 1); -+ -+ ret = kdbus_msg_send(child_2, NULL, -+ expected_cookie, 0, 0, 0, -+ KDBUS_DST_ID_BROADCAST); -+ ASSERT_RETURN(ret == 0); -+ -+ /* Use a little bit high time */ -+ ret = kdbus_msg_recv_poll(child_2, 1000, -+ &msg, NULL); -+ ASSERT_RETURN(ret == parent_status); -+ -+ /* -+ * Check returned cookie in case we expect -+ * success. -+ */ -+ if (ret == 0) { -+ ASSERT_RETURN(msg->cookie == -+ expected_cookie + 1); -+ } -+ -+ kdbus_msg_free(msg); -+ } else { -+ /* -+ * Two unprivileged users will try to -+ * communicate using broadcast. -+ */ -+ ret = RUN_UNPRIVILEGED(second_uid, second_gid, ({ -+ child_2 = kdbus_hello(bus, 0, NULL, 0); -+ ASSERT_EXIT(child_2); -+ -+ ret = kdbus_add_match_empty(child_2); -+ ASSERT_EXIT(ret == 0); -+ -+ ret = eventfd_read(efd, &event_status); -+ ASSERT_EXIT(ret >= 0 && event_status == 1); -+ -+ ret = kdbus_msg_send(child_2, NULL, -+ expected_cookie, 0, 0, 0, -+ KDBUS_DST_ID_BROADCAST); -+ ASSERT_EXIT(ret == 0); -+ -+ /* Use a little bit high time */ -+ ret = kdbus_msg_recv_poll(child_2, 1000, -+ &msg, NULL); -+ ASSERT_EXIT(ret == parent_status); -+ -+ /* -+ * Check returned cookie in case we expect -+ * success. -+ */ -+ if (ret == 0) { -+ ASSERT_EXIT(msg->cookie == -+ expected_cookie + 1); -+ } -+ -+ kdbus_msg_free(msg); -+ kdbus_conn_free(child_2); -+ }), -+ ({ 0; })); -+ ASSERT_RETURN(ret == 0); -+ } -+ })); -+ ASSERT_RETURN(ret == 0); -+ -+ close(efd); -+ -+ return ret; -+} -+ -+static void nosig(int sig) -+{ -+} -+ -+static int test_priv_before_policy_upload(struct kdbus_test_env *env) -+{ -+ int ret = 0; -+ struct kdbus_conn *conn; -+ -+ conn = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(conn); -+ -+ /* -+ * Make sure unprivileged bus user cannot acquire names -+ * before registring any policy holder. -+ */ -+ -+ ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ -+ ret = kdbus_name_acquire(unpriv, "com.example.a", NULL); -+ ASSERT_EXIT(ret < 0); -+ })); -+ ASSERT_RETURN(ret == 0); -+ -+ /* -+ * Make sure unprivileged bus users cannot talk by default -+ * to privileged ones, unless a policy holder that allows -+ * this was uploaded. -+ */ -+ -+ ret = test_policy_priv_by_id(env->buspath, conn, false, -+ -ETIMEDOUT, -EPERM); -+ ASSERT_RETURN(ret == 0); -+ -+ /* Activate matching for a privileged connection */ -+ ret = kdbus_add_match_empty(conn); -+ ASSERT_RETURN(ret == 0); -+ -+ /* -+ * First make sure that BROADCAST with msg flag -+ * KDBUS_MSG_EXPECT_REPLY will fail with -ENOTUNIQ -+ */ -+ ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ -+ ret = kdbus_msg_send(unpriv, NULL, 0xdeadbeef, -+ KDBUS_MSG_EXPECT_REPLY, -+ 5000000000ULL, 0, -+ KDBUS_DST_ID_BROADCAST); -+ ASSERT_EXIT(ret == -ENOTUNIQ); -+ })); -+ ASSERT_RETURN(ret == 0); -+ -+ /* -+ * Test broadcast with a privileged connection. -+ * -+ * The first unprivileged receiver should not get the -+ * broadcast message sent by the privileged connection, -+ * since there is no a TALK policy that allows the -+ * unprivileged to TALK to the privileged connection. It -+ * will fail with -ETIMEDOUT -+ * -+ * Then second case: -+ * The privileged connection should get the broadcast -+ * message from the unprivileged one. Since the receiver is -+ * a privileged bus user and it has default TALK access to -+ * all connections it will receive those. -+ */ -+ -+ ret = test_policy_priv_by_broadcast(env->buspath, conn, -+ DO_NOT_DROP, -+ 0, -ETIMEDOUT); -+ ASSERT_RETURN(ret == 0); -+ -+ -+ /* -+ * Test broadcast with two unprivileged connections running -+ * under the same user. -+ * -+ * Both connections should succeed. -+ */ -+ -+ ret = test_policy_priv_by_broadcast(env->buspath, NULL, -+ DROP_SAME_UNPRIV, 0, 0); -+ ASSERT_RETURN(ret == 0); -+ -+ /* -+ * Test broadcast with two unprivileged connections running -+ * under different users. -+ * -+ * Both connections will fail with -ETIMEDOUT. -+ */ -+ -+ ret = test_policy_priv_by_broadcast(env->buspath, NULL, -+ DROP_OTHER_UNPRIV, -+ -ETIMEDOUT, -ETIMEDOUT); -+ ASSERT_RETURN(ret == 0); -+ -+ kdbus_conn_free(conn); -+ -+ return ret; -+} -+ -+static int test_broadcast_after_policy_upload(struct kdbus_test_env *env) -+{ -+ int ret; -+ int efd; -+ eventfd_t event_status = 0; -+ struct kdbus_msg *msg = NULL; -+ struct kdbus_conn *owner_a, *owner_b; -+ struct kdbus_conn *holder_a, *holder_b; -+ struct kdbus_policy_access access = {}; -+ uint64_t expected_cookie = time(NULL) ^ 0xdeadbeef; -+ -+ owner_a = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(owner_a); -+ -+ ret = kdbus_name_acquire(owner_a, "com.example.broadcastA", NULL); -+ ASSERT_EXIT(ret >= 0); -+ -+ /* -+ * Make sure unprivileged bus users cannot talk by default -+ * to privileged ones, unless a policy holder that allows -+ * this was uploaded. -+ */ -+ -+ ++expected_cookie; -+ ret = test_policy_priv_by_id(env->buspath, owner_a, false, -+ -ETIMEDOUT, -EPERM); -+ ASSERT_RETURN(ret == 0); -+ -+ /* -+ * Make sure that privileged won't receive broadcasts unless -+ * it installs a match. It will fail with -ETIMEDOUT -+ * -+ * At same time check that the unprivileged connection will -+ * not receive the broadcast message from the privileged one -+ * since the privileged one owns a name with a restricted -+ * policy TALK (actually the TALK policy is still not -+ * registered so we fail by default), thus the unprivileged -+ * receiver is not able to TALK to that name. -+ */ -+ -+ ret = test_policy_priv_by_broadcast(env->buspath, owner_a, -+ DO_NOT_DROP, -+ -ETIMEDOUT, -ETIMEDOUT); -+ ASSERT_RETURN(ret == 0); -+ -+ /* Activate matching for a privileged connection */ -+ ret = kdbus_add_match_empty(owner_a); -+ ASSERT_RETURN(ret == 0); -+ -+ /* -+ * Redo the previous test. The privileged conn owner_a is -+ * able to TALK to any connection so it will receive the -+ * broadcast message now. -+ */ -+ -+ ret = test_policy_priv_by_broadcast(env->buspath, owner_a, -+ DO_NOT_DROP, -+ 0, -ETIMEDOUT); -+ ASSERT_RETURN(ret == 0); -+ -+ /* -+ * Test that broadcast between two unprivileged users running -+ * under the same user still succeed. -+ */ -+ -+ ret = test_policy_priv_by_broadcast(env->buspath, NULL, -+ DROP_SAME_UNPRIV, 0, 0); -+ ASSERT_RETURN(ret == 0); -+ -+ /* -+ * Test broadcast with two unprivileged connections running -+ * under different users. -+ * -+ * Both connections will fail with -ETIMEDOUT. -+ */ -+ -+ ret = test_policy_priv_by_broadcast(env->buspath, NULL, -+ DROP_OTHER_UNPRIV, -+ -ETIMEDOUT, -ETIMEDOUT); -+ ASSERT_RETURN(ret == 0); -+ -+ access = (struct kdbus_policy_access){ -+ .type = KDBUS_POLICY_ACCESS_USER, -+ .id = geteuid(), -+ .access = KDBUS_POLICY_OWN, -+ }; -+ -+ holder_a = kdbus_hello_registrar(env->buspath, -+ "com.example.broadcastA", -+ &access, 1, -+ KDBUS_HELLO_POLICY_HOLDER); -+ ASSERT_RETURN(holder_a); -+ -+ holder_b = kdbus_hello_registrar(env->buspath, -+ "com.example.broadcastB", -+ &access, 1, -+ KDBUS_HELLO_POLICY_HOLDER); -+ ASSERT_RETURN(holder_b); -+ -+ /* Free connections and their received messages and restart */ -+ kdbus_conn_free(owner_a); -+ -+ owner_a = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(owner_a); -+ -+ /* Activate matching for a privileged connection */ -+ ret = kdbus_add_match_empty(owner_a); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_name_acquire(owner_a, "com.example.broadcastA", NULL); -+ ASSERT_EXIT(ret >= 0); -+ -+ owner_b = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(owner_b); -+ -+ ret = kdbus_name_acquire(owner_b, "com.example.broadcastB", NULL); -+ ASSERT_EXIT(ret >= 0); -+ -+ /* Activate matching for a privileged connection */ -+ ret = kdbus_add_match_empty(owner_b); -+ ASSERT_RETURN(ret == 0); -+ -+ /* -+ * Test that even if "com.example.broadcastA" and -+ * "com.example.broadcastB" do have a TALK access by default -+ * they are able to signal each other using broadcast due to -+ * the fact they are privileged connections, they receive -+ * all broadcasts if the match allows it. -+ */ -+ -+ ++expected_cookie; -+ ret = kdbus_msg_send(owner_a, NULL, expected_cookie, 0, -+ 0, 0, KDBUS_DST_ID_BROADCAST); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_msg_recv_poll(owner_b, 100, &msg, NULL); -+ ASSERT_RETURN(ret == 0); -+ ASSERT_RETURN(msg->cookie == expected_cookie); -+ -+ /* Check src ID */ -+ ASSERT_RETURN(msg->src_id == owner_a->id); -+ -+ kdbus_msg_free(msg); -+ -+ /* Release name "com.example.broadcastB" */ -+ -+ ret = kdbus_name_release(owner_b, "com.example.broadcastB"); -+ ASSERT_EXIT(ret >= 0); -+ -+ /* KDBUS_POLICY_OWN for unprivileged connections */ -+ access = (struct kdbus_policy_access){ -+ .type = KDBUS_POLICY_ACCESS_WORLD, -+ .id = geteuid(), -+ .access = KDBUS_POLICY_OWN, -+ }; -+ -+ /* Update the policy so unprivileged will own the name */ -+ -+ ret = kdbus_conn_update_policy(holder_b, -+ "com.example.broadcastB", -+ &access, 1); -+ ASSERT_RETURN(ret == 0); -+ -+ /* -+ * Send broadcasts from an unprivileged connection that -+ * owns a name "com.example.broadcastB". -+ * -+ * We'll have four destinations here: -+ * -+ * 1) destination owner_a: privileged connection that owns -+ * "com.example.broadcastA". It will receive the broadcast -+ * since it is a privileged has default TALK access to all -+ * connections, and it is subscribed to the match. -+ * Will succeed. -+ * -+ * owner_b: privileged connection (running under a different -+ * uid) that do not own names, but with an empty broadcast -+ * match, so it will receive broadcasts since it has default -+ * TALK access to all connection. -+ * -+ * unpriv_a: unpriv connection that do not own any name. -+ * It will receive the broadcast since it is running under -+ * the same user of the one broadcasting and did install -+ * matches. It should get the message. -+ * -+ * unpriv_b: unpriv connection is not interested in broadcast -+ * messages, so it did not install broadcast matches. Should -+ * fail with -ETIMEDOUT -+ */ -+ -+ ++expected_cookie; -+ efd = eventfd(0, EFD_CLOEXEC); -+ ASSERT_RETURN_VAL(efd >= 0, efd); -+ -+ ret = RUN_UNPRIVILEGED(UNPRIV_UID, UNPRIV_UID, ({ -+ struct kdbus_conn *unpriv_owner; -+ struct kdbus_conn *unpriv_a, *unpriv_b; -+ -+ unpriv_owner = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_EXIT(unpriv_owner); -+ -+ unpriv_a = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_EXIT(unpriv_a); -+ -+ unpriv_b = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_EXIT(unpriv_b); -+ -+ ret = kdbus_name_acquire(unpriv_owner, -+ "com.example.broadcastB", -+ NULL); -+ ASSERT_EXIT(ret >= 0); -+ -+ ret = kdbus_add_match_empty(unpriv_a); -+ ASSERT_EXIT(ret == 0); -+ -+ /* Signal that we are doing broadcasts */ -+ ret = eventfd_write(efd, 1); -+ ASSERT_EXIT(ret == 0); -+ -+ /* -+ * Do broadcast from a connection that owns the -+ * names "com.example.broadcastB". -+ */ -+ ret = kdbus_msg_send(unpriv_owner, NULL, -+ expected_cookie, -+ 0, 0, 0, -+ KDBUS_DST_ID_BROADCAST); -+ ASSERT_EXIT(ret == 0); -+ -+ /* -+ * Unprivileged connection running under the same -+ * user. It should succeed. -+ */ -+ ret = kdbus_msg_recv_poll(unpriv_a, 300, &msg, NULL); -+ ASSERT_EXIT(ret == 0 && msg->cookie == expected_cookie); -+ -+ /* -+ * Did not install matches, not interested in -+ * broadcasts -+ */ -+ ret = kdbus_msg_recv_poll(unpriv_b, 300, NULL, NULL); -+ ASSERT_EXIT(ret == -ETIMEDOUT); -+ }), -+ ({ -+ ret = eventfd_read(efd, &event_status); -+ ASSERT_RETURN(ret >= 0 && event_status == 1); -+ -+ /* -+ * owner_a must fail with -ETIMEDOUT, since it owns -+ * name "com.example.broadcastA" and its TALK -+ * access is restriced. -+ */ -+ ret = kdbus_msg_recv_poll(owner_a, 300, &msg, NULL); -+ ASSERT_RETURN(ret == 0); -+ -+ /* confirm the received cookie */ -+ ASSERT_RETURN(msg->cookie == expected_cookie); -+ -+ kdbus_msg_free(msg); -+ -+ /* -+ * owner_b got the broadcast from an unprivileged -+ * connection. -+ */ -+ ret = kdbus_msg_recv_poll(owner_b, 300, &msg, NULL); -+ ASSERT_RETURN(ret == 0); -+ -+ /* confirm the received cookie */ -+ ASSERT_RETURN(msg->cookie == expected_cookie); -+ -+ kdbus_msg_free(msg); -+ -+ })); -+ ASSERT_RETURN(ret == 0); -+ -+ close(efd); -+ -+ /* -+ * Test broadcast with two unprivileged connections running -+ * under different users. -+ * -+ * Both connections will fail with -ETIMEDOUT. -+ */ -+ -+ ret = test_policy_priv_by_broadcast(env->buspath, NULL, -+ DROP_OTHER_UNPRIV, -+ -ETIMEDOUT, -ETIMEDOUT); -+ ASSERT_RETURN(ret == 0); -+ -+ /* Drop received broadcasts by privileged */ -+ ret = kdbus_msg_recv_poll(owner_a, 100, NULL, NULL); -+ ret = kdbus_msg_recv_poll(owner_a, 100, NULL, NULL); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_msg_recv(owner_a, NULL, NULL); -+ ASSERT_RETURN(ret == -EAGAIN); -+ -+ ret = kdbus_msg_recv_poll(owner_b, 100, NULL, NULL); -+ ret = kdbus_msg_recv_poll(owner_b, 100, NULL, NULL); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_msg_recv(owner_b, NULL, NULL); -+ ASSERT_RETURN(ret == -EAGAIN); -+ -+ /* -+ * Perform last tests, allow others to talk to name -+ * "com.example.broadcastA". So now receiving broadcasts -+ * from it should succeed since the TALK policy allow it. -+ */ -+ -+ /* KDBUS_POLICY_OWN for unprivileged connections */ -+ access = (struct kdbus_policy_access){ -+ .type = KDBUS_POLICY_ACCESS_WORLD, -+ .id = geteuid(), -+ .access = KDBUS_POLICY_TALK, -+ }; -+ -+ ret = kdbus_conn_update_policy(holder_a, -+ "com.example.broadcastA", -+ &access, 1); -+ ASSERT_RETURN(ret == 0); -+ -+ /* -+ * Unprivileged is able to TALK to "com.example.broadcastA" -+ * now so it will receive its broadcasts -+ */ -+ ret = test_policy_priv_by_broadcast(env->buspath, owner_a, -+ DO_NOT_DROP, 0, 0); -+ ASSERT_RETURN(ret == 0); -+ -+ ++expected_cookie; -+ ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ -+ ret = kdbus_name_acquire(unpriv, "com.example.broadcastB", -+ NULL); -+ ASSERT_EXIT(ret >= 0); -+ ret = kdbus_msg_send(unpriv, NULL, expected_cookie, -+ 0, 0, 0, KDBUS_DST_ID_BROADCAST); -+ ASSERT_EXIT(ret == 0); -+ })); -+ ASSERT_RETURN(ret == 0); -+ -+ /* owner_a is privileged it will get the broadcast now. */ -+ ret = kdbus_msg_recv_poll(owner_a, 300, &msg, NULL); -+ ASSERT_RETURN(ret == 0); -+ -+ /* confirm the received cookie */ -+ ASSERT_RETURN(msg->cookie == expected_cookie); -+ -+ kdbus_msg_free(msg); -+ -+ /* -+ * owner_a released name "com.example.broadcastA". It should -+ * receive broadcasts since it is still privileged and has -+ * the right match. -+ * -+ * Unprivileged connection will own a name and will try to -+ * signal to the privileged connection. -+ */ -+ -+ ret = kdbus_name_release(owner_a, "com.example.broadcastA"); -+ ASSERT_EXIT(ret >= 0); -+ -+ ++expected_cookie; -+ ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ -+ ret = kdbus_name_acquire(unpriv, "com.example.broadcastB", -+ NULL); -+ ASSERT_EXIT(ret >= 0); -+ ret = kdbus_msg_send(unpriv, NULL, expected_cookie, -+ 0, 0, 0, KDBUS_DST_ID_BROADCAST); -+ ASSERT_EXIT(ret == 0); -+ })); -+ ASSERT_RETURN(ret == 0); -+ -+ /* owner_a will get the broadcast now. */ -+ ret = kdbus_msg_recv_poll(owner_a, 300, &msg, NULL); -+ ASSERT_RETURN(ret == 0); -+ -+ /* confirm the received cookie */ -+ ASSERT_RETURN(msg->cookie == expected_cookie); -+ -+ kdbus_msg_free(msg); -+ -+ kdbus_conn_free(owner_a); -+ kdbus_conn_free(owner_b); -+ kdbus_conn_free(holder_a); -+ kdbus_conn_free(holder_b); -+ -+ return 0; -+} -+ -+static int test_policy_priv(struct kdbus_test_env *env) -+{ -+ struct kdbus_conn *conn_a, *conn_b, *conn, *owner; -+ struct kdbus_policy_access access, *acc; -+ sigset_t sset; -+ size_t num; -+ int ret; -+ -+ /* -+ * Make sure we have CAP_SETUID/SETGID so we can drop privileges -+ */ -+ -+ ret = test_is_capable(CAP_SETUID, CAP_SETGID, -1); -+ ASSERT_RETURN(ret >= 0); -+ -+ if (!ret) -+ return TEST_SKIP; -+ -+ /* make sure that uids and gids are mapped */ -+ if (!all_uids_gids_are_mapped()) -+ return TEST_SKIP; -+ -+ /* -+ * Setup: -+ * conn_a: policy holder for com.example.a -+ * conn_b: name holder of com.example.b -+ */ -+ -+ signal(SIGUSR1, nosig); -+ sigemptyset(&sset); -+ sigaddset(&sset, SIGUSR1); -+ sigprocmask(SIG_BLOCK, &sset, NULL); -+ -+ conn = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(conn); -+ -+ /* -+ * Before registering any policy holder, make sure that the -+ * bus is secure by default. This test is necessary, it catches -+ * several cases where old D-Bus was vulnerable. -+ */ -+ -+ ret = test_priv_before_policy_upload(env); -+ ASSERT_RETURN(ret == 0); -+ -+ /* -+ * Make sure unprivileged are not able to register policy -+ * holders -+ */ -+ -+ ret = RUN_UNPRIVILEGED(UNPRIV_UID, UNPRIV_GID, ({ -+ struct kdbus_conn *holder; -+ -+ holder = kdbus_hello_registrar(env->buspath, -+ "com.example.a", NULL, 0, -+ KDBUS_HELLO_POLICY_HOLDER); -+ ASSERT_EXIT(holder == NULL && errno == EPERM); -+ }), -+ ({ 0; })); -+ ASSERT_RETURN(ret == 0); -+ -+ -+ /* Register policy holder */ -+ -+ conn_a = kdbus_hello_registrar(env->buspath, "com.example.a", -+ NULL, 0, KDBUS_HELLO_POLICY_HOLDER); -+ ASSERT_RETURN(conn_a); -+ -+ conn_b = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(conn_b); -+ -+ ret = kdbus_name_acquire(conn_b, "com.example.b", NULL); -+ ASSERT_EXIT(ret >= 0); -+ -+ /* -+ * Make sure bus-owners can always acquire names. -+ */ -+ ret = kdbus_name_acquire(conn, "com.example.a", NULL); -+ ASSERT_EXIT(ret >= 0); -+ -+ kdbus_conn_free(conn); -+ -+ /* -+ * Make sure unprivileged users cannot acquire names with default -+ * policy assigned. -+ */ -+ -+ ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ -+ ret = kdbus_name_acquire(unpriv, "com.example.a", NULL); -+ ASSERT_EXIT(ret < 0); -+ })); -+ ASSERT_RETURN(ret >= 0); -+ -+ /* -+ * Make sure unprivileged users can acquire names if we make them -+ * world-accessible. -+ */ -+ -+ access = (struct kdbus_policy_access){ -+ .type = KDBUS_POLICY_ACCESS_WORLD, -+ .id = 0, -+ .access = KDBUS_POLICY_OWN, -+ }; -+ -+ /* -+ * Make sure unprivileged/normal connections are not able -+ * to update policies -+ */ -+ -+ ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ -+ ret = kdbus_conn_update_policy(unpriv, "com.example.a", -+ &access, 1); -+ ASSERT_EXIT(ret == -EOPNOTSUPP); -+ })); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_conn_update_policy(conn_a, "com.example.a", &access, 1); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ -+ ret = kdbus_name_acquire(unpriv, "com.example.a", NULL); -+ ASSERT_EXIT(ret >= 0); -+ })); -+ ASSERT_RETURN(ret >= 0); -+ -+ /* -+ * Make sure unprivileged users can acquire names if we make them -+ * gid-accessible. But only if the gid matches. -+ */ -+ -+ access = (struct kdbus_policy_access){ -+ .type = KDBUS_POLICY_ACCESS_GROUP, -+ .id = UNPRIV_GID, -+ .access = KDBUS_POLICY_OWN, -+ }; -+ -+ ret = kdbus_conn_update_policy(conn_a, "com.example.a", &access, 1); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ -+ ret = kdbus_name_acquire(unpriv, "com.example.a", NULL); -+ ASSERT_EXIT(ret >= 0); -+ })); -+ ASSERT_RETURN(ret >= 0); -+ -+ access = (struct kdbus_policy_access){ -+ .type = KDBUS_POLICY_ACCESS_GROUP, -+ .id = 1, -+ .access = KDBUS_POLICY_OWN, -+ }; -+ -+ ret = kdbus_conn_update_policy(conn_a, "com.example.a", &access, 1); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ -+ ret = kdbus_name_acquire(unpriv, "com.example.a", NULL); -+ ASSERT_EXIT(ret < 0); -+ })); -+ ASSERT_RETURN(ret >= 0); -+ -+ /* -+ * Make sure unprivileged users can acquire names if we make them -+ * uid-accessible. But only if the uid matches. -+ */ -+ -+ access = (struct kdbus_policy_access){ -+ .type = KDBUS_POLICY_ACCESS_USER, -+ .id = UNPRIV_UID, -+ .access = KDBUS_POLICY_OWN, -+ }; -+ -+ ret = kdbus_conn_update_policy(conn_a, "com.example.a", &access, 1); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ -+ ret = kdbus_name_acquire(unpriv, "com.example.a", NULL); -+ ASSERT_EXIT(ret >= 0); -+ })); -+ ASSERT_RETURN(ret >= 0); -+ -+ access = (struct kdbus_policy_access){ -+ .type = KDBUS_POLICY_ACCESS_USER, -+ .id = 1, -+ .access = KDBUS_POLICY_OWN, -+ }; -+ -+ ret = kdbus_conn_update_policy(conn_a, "com.example.a", &access, 1); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ -+ ret = kdbus_name_acquire(unpriv, "com.example.a", NULL); -+ ASSERT_EXIT(ret < 0); -+ })); -+ ASSERT_RETURN(ret >= 0); -+ -+ /* -+ * Make sure unprivileged users cannot acquire names if no owner-policy -+ * matches, even if SEE/TALK policies match. -+ */ -+ -+ num = 4; -+ acc = (struct kdbus_policy_access[]){ -+ { -+ .type = KDBUS_POLICY_ACCESS_GROUP, -+ .id = UNPRIV_GID, -+ .access = KDBUS_POLICY_SEE, -+ }, -+ { -+ .type = KDBUS_POLICY_ACCESS_USER, -+ .id = UNPRIV_UID, -+ .access = KDBUS_POLICY_TALK, -+ }, -+ { -+ .type = KDBUS_POLICY_ACCESS_WORLD, -+ .id = 0, -+ .access = KDBUS_POLICY_TALK, -+ }, -+ { -+ .type = KDBUS_POLICY_ACCESS_WORLD, -+ .id = 0, -+ .access = KDBUS_POLICY_SEE, -+ }, -+ }; -+ -+ ret = kdbus_conn_update_policy(conn_a, "com.example.a", acc, num); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ -+ ret = kdbus_name_acquire(unpriv, "com.example.a", NULL); -+ ASSERT_EXIT(ret < 0); -+ })); -+ ASSERT_RETURN(ret >= 0); -+ -+ /* -+ * Make sure unprivileged users can acquire names if the only matching -+ * policy is somewhere in the middle. -+ */ -+ -+ num = 5; -+ acc = (struct kdbus_policy_access[]){ -+ { -+ .type = KDBUS_POLICY_ACCESS_USER, -+ .id = 1, -+ .access = KDBUS_POLICY_OWN, -+ }, -+ { -+ .type = KDBUS_POLICY_ACCESS_USER, -+ .id = 2, -+ .access = KDBUS_POLICY_OWN, -+ }, -+ { -+ .type = KDBUS_POLICY_ACCESS_USER, -+ .id = UNPRIV_UID, -+ .access = KDBUS_POLICY_OWN, -+ }, -+ { -+ .type = KDBUS_POLICY_ACCESS_USER, -+ .id = 3, -+ .access = KDBUS_POLICY_OWN, -+ }, -+ { -+ .type = KDBUS_POLICY_ACCESS_USER, -+ .id = 4, -+ .access = KDBUS_POLICY_OWN, -+ }, -+ }; -+ -+ ret = kdbus_conn_update_policy(conn_a, "com.example.a", acc, num); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ -+ ret = kdbus_name_acquire(unpriv, "com.example.a", NULL); -+ ASSERT_EXIT(ret >= 0); -+ })); -+ ASSERT_RETURN(ret >= 0); -+ -+ /* -+ * Clear policies -+ */ -+ -+ ret = kdbus_conn_update_policy(conn_a, "com.example.a", NULL, 0); -+ ASSERT_RETURN(ret == 0); -+ -+ /* -+ * Make sure privileged bus users can _always_ talk to others. -+ */ -+ -+ conn = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(conn); -+ -+ ret = kdbus_msg_send(conn, "com.example.b", 0xdeadbeef, 0, 0, 0, 0); -+ ASSERT_EXIT(ret >= 0); -+ -+ ret = kdbus_msg_recv_poll(conn_b, 300, NULL, NULL); -+ ASSERT_EXIT(ret >= 0); -+ -+ kdbus_conn_free(conn); -+ -+ /* -+ * Make sure unprivileged bus users cannot talk by default. -+ */ -+ -+ ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ -+ ret = kdbus_msg_send(unpriv, "com.example.b", 0xdeadbeef, 0, 0, -+ 0, 0); -+ ASSERT_EXIT(ret == -EPERM); -+ })); -+ ASSERT_RETURN(ret >= 0); -+ -+ /* -+ * Make sure unprivileged bus users can talk to equals, even without -+ * policy. -+ */ -+ -+ access = (struct kdbus_policy_access){ -+ .type = KDBUS_POLICY_ACCESS_USER, -+ .id = UNPRIV_UID, -+ .access = KDBUS_POLICY_OWN, -+ }; -+ -+ ret = kdbus_conn_update_policy(conn_a, "com.example.c", &access, 1); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ -+ struct kdbus_conn *owner; -+ -+ owner = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(owner); -+ -+ ret = kdbus_name_acquire(owner, "com.example.c", NULL); -+ ASSERT_EXIT(ret >= 0); -+ -+ ret = kdbus_msg_send(unpriv, "com.example.c", 0xdeadbeef, 0, 0, -+ 0, 0); -+ ASSERT_EXIT(ret >= 0); -+ ret = kdbus_msg_recv_poll(owner, 100, NULL, NULL); -+ ASSERT_EXIT(ret >= 0); -+ -+ kdbus_conn_free(owner); -+ })); -+ ASSERT_RETURN(ret >= 0); -+ -+ /* -+ * Make sure unprivileged bus users can talk to privileged users if a -+ * suitable UID policy is set. -+ */ -+ -+ access = (struct kdbus_policy_access){ -+ .type = KDBUS_POLICY_ACCESS_USER, -+ .id = UNPRIV_UID, -+ .access = KDBUS_POLICY_TALK, -+ }; -+ -+ ret = kdbus_conn_update_policy(conn_a, "com.example.b", &access, 1); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ -+ ret = kdbus_msg_send(unpriv, "com.example.b", 0xdeadbeef, 0, 0, -+ 0, 0); -+ ASSERT_EXIT(ret >= 0); -+ })); -+ ASSERT_RETURN(ret >= 0); -+ -+ ret = kdbus_msg_recv_poll(conn_b, 100, NULL, NULL); -+ ASSERT_EXIT(ret >= 0); -+ -+ /* -+ * Make sure unprivileged bus users can talk to privileged users if a -+ * suitable GID policy is set. -+ */ -+ -+ access = (struct kdbus_policy_access){ -+ .type = KDBUS_POLICY_ACCESS_GROUP, -+ .id = UNPRIV_GID, -+ .access = KDBUS_POLICY_TALK, -+ }; -+ -+ ret = kdbus_conn_update_policy(conn_a, "com.example.b", &access, 1); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ -+ ret = kdbus_msg_send(unpriv, "com.example.b", 0xdeadbeef, 0, 0, -+ 0, 0); -+ ASSERT_EXIT(ret >= 0); -+ })); -+ ASSERT_RETURN(ret >= 0); -+ -+ ret = kdbus_msg_recv_poll(conn_b, 100, NULL, NULL); -+ ASSERT_EXIT(ret >= 0); -+ -+ /* -+ * Make sure unprivileged bus users can talk to privileged users if a -+ * suitable WORLD policy is set. -+ */ -+ -+ access = (struct kdbus_policy_access){ -+ .type = KDBUS_POLICY_ACCESS_WORLD, -+ .id = 0, -+ .access = KDBUS_POLICY_TALK, -+ }; -+ -+ ret = kdbus_conn_update_policy(conn_a, "com.example.b", &access, 1); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ -+ ret = kdbus_msg_send(unpriv, "com.example.b", 0xdeadbeef, 0, 0, -+ 0, 0); -+ ASSERT_EXIT(ret >= 0); -+ })); -+ ASSERT_RETURN(ret >= 0); -+ -+ ret = kdbus_msg_recv_poll(conn_b, 100, NULL, NULL); -+ ASSERT_EXIT(ret >= 0); -+ -+ /* -+ * Make sure unprivileged bus users cannot talk to privileged users if -+ * no suitable policy is set. -+ */ -+ -+ num = 5; -+ acc = (struct kdbus_policy_access[]){ -+ { -+ .type = KDBUS_POLICY_ACCESS_USER, -+ .id = 0, -+ .access = KDBUS_POLICY_OWN, -+ }, -+ { -+ .type = KDBUS_POLICY_ACCESS_USER, -+ .id = 1, -+ .access = KDBUS_POLICY_TALK, -+ }, -+ { -+ .type = KDBUS_POLICY_ACCESS_USER, -+ .id = UNPRIV_UID, -+ .access = KDBUS_POLICY_SEE, -+ }, -+ { -+ .type = KDBUS_POLICY_ACCESS_USER, -+ .id = 3, -+ .access = KDBUS_POLICY_TALK, -+ }, -+ { -+ .type = KDBUS_POLICY_ACCESS_USER, -+ .id = 4, -+ .access = KDBUS_POLICY_TALK, -+ }, -+ }; -+ -+ ret = kdbus_conn_update_policy(conn_a, "com.example.b", acc, num); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ -+ ret = kdbus_msg_send(unpriv, "com.example.b", 0xdeadbeef, 0, 0, -+ 0, 0); -+ ASSERT_EXIT(ret == -EPERM); -+ })); -+ ASSERT_RETURN(ret >= 0); -+ -+ /* -+ * Make sure unprivileged bus users can talk to privileged users if a -+ * suitable OWN privilege overwrites TALK. -+ */ -+ -+ access = (struct kdbus_policy_access){ -+ .type = KDBUS_POLICY_ACCESS_WORLD, -+ .id = 0, -+ .access = KDBUS_POLICY_OWN, -+ }; -+ -+ ret = kdbus_conn_update_policy(conn_a, "com.example.b", &access, 1); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ -+ ret = kdbus_msg_send(unpriv, "com.example.b", 0xdeadbeef, 0, 0, -+ 0, 0); -+ ASSERT_EXIT(ret >= 0); -+ })); -+ ASSERT_RETURN(ret >= 0); -+ -+ ret = kdbus_msg_recv_poll(conn_b, 100, NULL, NULL); -+ ASSERT_EXIT(ret >= 0); -+ -+ /* -+ * Make sure the TALK cache is reset correctly when policies are -+ * updated. -+ */ -+ -+ access = (struct kdbus_policy_access){ -+ .type = KDBUS_POLICY_ACCESS_WORLD, -+ .id = 0, -+ .access = KDBUS_POLICY_TALK, -+ }; -+ -+ ret = kdbus_conn_update_policy(conn_a, "com.example.b", &access, 1); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ -+ ret = kdbus_msg_send(unpriv, "com.example.b", 0xdeadbeef, 0, 0, -+ 0, 0); -+ ASSERT_EXIT(ret >= 0); -+ -+ ret = kdbus_msg_recv_poll(conn_b, 100, NULL, NULL); -+ ASSERT_EXIT(ret >= 0); -+ -+ ret = kdbus_conn_update_policy(conn_a, "com.example.b", -+ NULL, 0); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_msg_send(unpriv, "com.example.b", 0xdeadbeef, 0, 0, -+ 0, 0); -+ ASSERT_EXIT(ret == -EPERM); -+ })); -+ ASSERT_RETURN(ret >= 0); -+ -+ /* -+ * Make sure the TALK cache is reset correctly when policy holders -+ * disconnect. -+ */ -+ -+ access = (struct kdbus_policy_access){ -+ .type = KDBUS_POLICY_ACCESS_WORLD, -+ .id = 0, -+ .access = KDBUS_POLICY_OWN, -+ }; -+ -+ conn = kdbus_hello_registrar(env->buspath, "com.example.c", -+ NULL, 0, KDBUS_HELLO_POLICY_HOLDER); -+ ASSERT_RETURN(conn); -+ -+ ret = kdbus_conn_update_policy(conn, "com.example.c", &access, 1); -+ ASSERT_RETURN(ret == 0); -+ -+ owner = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(owner); -+ -+ ret = kdbus_name_acquire(owner, "com.example.c", NULL); -+ ASSERT_RETURN(ret >= 0); -+ -+ ret = RUN_UNPRIVILEGED(UNPRIV_UID, UNPRIV_GID, ({ -+ struct kdbus_conn *unpriv; -+ -+ /* wait for parent to be finished */ -+ sigemptyset(&sset); -+ ret = sigsuspend(&sset); -+ ASSERT_RETURN(ret == -1 && errno == EINTR); -+ -+ unpriv = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(unpriv); -+ -+ ret = kdbus_msg_send(unpriv, "com.example.c", 0xdeadbeef, 0, 0, -+ 0, 0); -+ ASSERT_EXIT(ret >= 0); -+ -+ ret = kdbus_msg_recv_poll(owner, 100, NULL, NULL); -+ ASSERT_EXIT(ret >= 0); -+ -+ /* free policy holder */ -+ kdbus_conn_free(conn); -+ -+ ret = kdbus_msg_send(unpriv, "com.example.c", 0xdeadbeef, 0, 0, -+ 0, 0); -+ ASSERT_EXIT(ret == -EPERM); -+ -+ kdbus_conn_free(unpriv); -+ }), ({ -+ /* make sure policy holder is only valid in child */ -+ kdbus_conn_free(conn); -+ kill(pid, SIGUSR1); -+ })); -+ ASSERT_RETURN(ret >= 0); -+ -+ -+ /* -+ * The following tests are necessary. -+ */ -+ -+ ret = test_broadcast_after_policy_upload(env); -+ ASSERT_RETURN(ret == 0); -+ -+ kdbus_conn_free(owner); -+ -+ /* -+ * cleanup resources -+ */ -+ -+ kdbus_conn_free(conn_b); -+ kdbus_conn_free(conn_a); -+ -+ return TEST_OK; -+} -+ -+int kdbus_test_policy_priv(struct kdbus_test_env *env) -+{ -+ pid_t pid; -+ int ret; -+ -+ /* make sure to exit() if a child returns from fork() */ -+ pid = getpid(); -+ ret = test_policy_priv(env); -+ if (pid != getpid()) -+ exit(1); -+ -+ return ret; -+} -diff --git a/tools/testing/selftests/kdbus/test-policy.c b/tools/testing/selftests/kdbus/test-policy.c -new file mode 100644 -index 000000000000..96d20d5e9172 ---- /dev/null -+++ b/tools/testing/selftests/kdbus/test-policy.c -@@ -0,0 +1,80 @@ -+#include <errno.h> -+#include <stdio.h> -+#include <string.h> -+#include <fcntl.h> -+#include <stdlib.h> -+#include <stdint.h> -+#include <stdbool.h> -+#include <unistd.h> -+ -+#include "kdbus-test.h" -+#include "kdbus-util.h" -+#include "kdbus-enum.h" -+ -+int kdbus_test_policy(struct kdbus_test_env *env) -+{ -+ struct kdbus_conn *conn_a, *conn_b; -+ struct kdbus_policy_access access; -+ int ret; -+ -+ /* Invalid name */ -+ conn_a = kdbus_hello_registrar(env->buspath, ".example.a", -+ NULL, 0, KDBUS_HELLO_POLICY_HOLDER); -+ ASSERT_RETURN(conn_a == NULL); -+ -+ conn_a = kdbus_hello_registrar(env->buspath, "example", -+ NULL, 0, KDBUS_HELLO_POLICY_HOLDER); -+ ASSERT_RETURN(conn_a == NULL); -+ -+ conn_a = kdbus_hello_registrar(env->buspath, "com.example.a", -+ NULL, 0, KDBUS_HELLO_POLICY_HOLDER); -+ ASSERT_RETURN(conn_a); -+ -+ conn_b = kdbus_hello_registrar(env->buspath, "com.example.b", -+ NULL, 0, KDBUS_HELLO_POLICY_HOLDER); -+ ASSERT_RETURN(conn_b); -+ -+ /* -+ * Verify there cannot be any duplicate entries, except for specific vs. -+ * wildcard entries. -+ */ -+ -+ access = (struct kdbus_policy_access){ -+ .type = KDBUS_POLICY_ACCESS_USER, -+ .id = geteuid(), -+ .access = KDBUS_POLICY_SEE, -+ }; -+ -+ ret = kdbus_conn_update_policy(conn_a, "com.example.a", &access, 1); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_conn_update_policy(conn_b, "com.example.a", &access, 1); -+ ASSERT_RETURN(ret == -EEXIST); -+ -+ ret = kdbus_conn_update_policy(conn_b, "com.example.a.*", &access, 1); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_conn_update_policy(conn_a, "com.example.a.*", &access, 1); -+ ASSERT_RETURN(ret == -EEXIST); -+ -+ ret = kdbus_conn_update_policy(conn_a, "com.example.*", &access, 1); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_conn_update_policy(conn_b, "com.example.a", &access, 1); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = kdbus_conn_update_policy(conn_b, "com.example.*", &access, 1); -+ ASSERT_RETURN(ret == -EEXIST); -+ -+ /* Invalid name */ -+ ret = kdbus_conn_update_policy(conn_b, ".example.*", &access, 1); -+ ASSERT_RETURN(ret == -EINVAL); -+ -+ ret = kdbus_conn_update_policy(conn_b, "example", &access, 1); -+ ASSERT_RETURN(ret == -EINVAL); -+ -+ kdbus_conn_free(conn_b); -+ kdbus_conn_free(conn_a); -+ -+ return TEST_OK; -+} -diff --git a/tools/testing/selftests/kdbus/test-sync.c b/tools/testing/selftests/kdbus/test-sync.c -new file mode 100644 -index 000000000000..e2be910d2ece ---- /dev/null -+++ b/tools/testing/selftests/kdbus/test-sync.c -@@ -0,0 +1,369 @@ -+#include <stdio.h> -+#include <string.h> -+#include <time.h> -+#include <fcntl.h> -+#include <stdlib.h> -+#include <stddef.h> -+#include <unistd.h> -+#include <stdint.h> -+#include <errno.h> -+#include <assert.h> -+#include <pthread.h> -+#include <stdbool.h> -+#include <signal.h> -+#include <sys/wait.h> -+#include <sys/eventfd.h> -+ -+#include "kdbus-api.h" -+#include "kdbus-test.h" -+#include "kdbus-util.h" -+#include "kdbus-enum.h" -+ -+static struct kdbus_conn *conn_a, *conn_b; -+static unsigned int cookie = 0xdeadbeef; -+ -+static void nop_handler(int sig) {} -+ -+static int interrupt_sync(struct kdbus_conn *conn_src, -+ struct kdbus_conn *conn_dst) -+{ -+ pid_t pid; -+ int ret, status; -+ struct kdbus_msg *msg = NULL; -+ struct sigaction sa = { -+ .sa_handler = nop_handler, -+ .sa_flags = SA_NOCLDSTOP|SA_RESTART, -+ }; -+ -+ cookie++; -+ pid = fork(); -+ ASSERT_RETURN_VAL(pid >= 0, pid); -+ -+ if (pid == 0) { -+ ret = sigaction(SIGINT, &sa, NULL); -+ ASSERT_EXIT(ret == 0); -+ -+ ret = kdbus_msg_send_sync(conn_dst, NULL, cookie, -+ KDBUS_MSG_EXPECT_REPLY, -+ 100000000ULL, 0, conn_src->id, -1); -+ ASSERT_EXIT(ret == -ETIMEDOUT); -+ -+ _exit(EXIT_SUCCESS); -+ } -+ -+ ret = kdbus_msg_recv_poll(conn_src, 100, &msg, NULL); -+ ASSERT_RETURN(ret == 0 && msg->cookie == cookie); -+ -+ kdbus_msg_free(msg); -+ -+ ret = kill(pid, SIGINT); -+ ASSERT_RETURN_VAL(ret == 0, ret); -+ -+ ret = waitpid(pid, &status, 0); -+ ASSERT_RETURN_VAL(ret >= 0, ret); -+ -+ if (WIFSIGNALED(status)) -+ return TEST_ERR; -+ -+ ret = kdbus_msg_recv_poll(conn_src, 100, NULL, NULL); -+ ASSERT_RETURN(ret == -ETIMEDOUT); -+ -+ return (status == EXIT_SUCCESS) ? TEST_OK : TEST_ERR; -+} -+ -+static int close_epipe_sync(const char *bus) -+{ -+ pid_t pid; -+ int ret, status; -+ struct kdbus_conn *conn_src; -+ struct kdbus_conn *conn_dst; -+ struct kdbus_msg *msg = NULL; -+ -+ conn_src = kdbus_hello(bus, 0, NULL, 0); -+ ASSERT_RETURN(conn_src); -+ -+ ret = kdbus_add_match_empty(conn_src); -+ ASSERT_RETURN(ret == 0); -+ -+ conn_dst = kdbus_hello(bus, 0, NULL, 0); -+ ASSERT_RETURN(conn_dst); -+ -+ cookie++; -+ pid = fork(); -+ ASSERT_RETURN_VAL(pid >= 0, pid); -+ -+ if (pid == 0) { -+ uint64_t dst_id; -+ -+ /* close our reference */ -+ dst_id = conn_dst->id; -+ kdbus_conn_free(conn_dst); -+ -+ ret = kdbus_msg_recv_poll(conn_src, 100, &msg, NULL); -+ ASSERT_EXIT(ret == 0 && msg->cookie == cookie); -+ ASSERT_EXIT(msg->src_id == dst_id); -+ -+ cookie++; -+ ret = kdbus_msg_send_sync(conn_src, NULL, cookie, -+ KDBUS_MSG_EXPECT_REPLY, -+ 100000000ULL, 0, dst_id, -1); -+ ASSERT_EXIT(ret == -EPIPE); -+ -+ _exit(EXIT_SUCCESS); -+ } -+ -+ ret = kdbus_msg_send(conn_dst, NULL, cookie, 0, 0, 0, -+ KDBUS_DST_ID_BROADCAST); -+ ASSERT_RETURN(ret == 0); -+ -+ cookie++; -+ ret = kdbus_msg_recv_poll(conn_dst, 100, &msg, NULL); -+ ASSERT_RETURN(ret == 0 && msg->cookie == cookie); -+ -+ kdbus_msg_free(msg); -+ -+ /* destroy connection */ -+ kdbus_conn_free(conn_dst); -+ kdbus_conn_free(conn_src); -+ -+ ret = waitpid(pid, &status, 0); -+ ASSERT_RETURN_VAL(ret >= 0, ret); -+ -+ if (!WIFEXITED(status)) -+ return TEST_ERR; -+ -+ return (status == EXIT_SUCCESS) ? TEST_OK : TEST_ERR; -+} -+ -+static int cancel_fd_sync(struct kdbus_conn *conn_src, -+ struct kdbus_conn *conn_dst) -+{ -+ pid_t pid; -+ int cancel_fd; -+ int ret, status; -+ uint64_t counter = 1; -+ struct kdbus_msg *msg = NULL; -+ -+ cancel_fd = eventfd(0, 0); -+ ASSERT_RETURN_VAL(cancel_fd >= 0, cancel_fd); -+ -+ cookie++; -+ pid = fork(); -+ ASSERT_RETURN_VAL(pid >= 0, pid); -+ -+ if (pid == 0) { -+ ret = kdbus_msg_send_sync(conn_dst, NULL, cookie, -+ KDBUS_MSG_EXPECT_REPLY, -+ 100000000ULL, 0, conn_src->id, -+ cancel_fd); -+ ASSERT_EXIT(ret == -ECANCELED); -+ -+ _exit(EXIT_SUCCESS); -+ } -+ -+ ret = kdbus_msg_recv_poll(conn_src, 100, &msg, NULL); -+ ASSERT_RETURN(ret == 0 && msg->cookie == cookie); -+ -+ kdbus_msg_free(msg); -+ -+ ret = write(cancel_fd, &counter, sizeof(counter)); -+ ASSERT_RETURN(ret == sizeof(counter)); -+ -+ ret = waitpid(pid, &status, 0); -+ ASSERT_RETURN_VAL(ret >= 0, ret); -+ -+ if (WIFSIGNALED(status)) -+ return TEST_ERR; -+ -+ return (status == EXIT_SUCCESS) ? TEST_OK : TEST_ERR; -+} -+ -+static int no_cancel_sync(struct kdbus_conn *conn_src, -+ struct kdbus_conn *conn_dst) -+{ -+ pid_t pid; -+ int cancel_fd; -+ int ret, status; -+ struct kdbus_msg *msg = NULL; -+ -+ /* pass eventfd, but never signal it so it shouldn't have any effect */ -+ -+ cancel_fd = eventfd(0, 0); -+ ASSERT_RETURN_VAL(cancel_fd >= 0, cancel_fd); -+ -+ cookie++; -+ pid = fork(); -+ ASSERT_RETURN_VAL(pid >= 0, pid); -+ -+ if (pid == 0) { -+ ret = kdbus_msg_send_sync(conn_dst, NULL, cookie, -+ KDBUS_MSG_EXPECT_REPLY, -+ 100000000ULL, 0, conn_src->id, -+ cancel_fd); -+ ASSERT_EXIT(ret == 0); -+ -+ _exit(EXIT_SUCCESS); -+ } -+ -+ ret = kdbus_msg_recv_poll(conn_src, 100, &msg, NULL); -+ ASSERT_RETURN_VAL(ret == 0 && msg->cookie == cookie, -1); -+ -+ kdbus_msg_free(msg); -+ -+ ret = kdbus_msg_send_reply(conn_src, cookie, conn_dst->id); -+ ASSERT_RETURN_VAL(ret >= 0, ret); -+ -+ ret = waitpid(pid, &status, 0); -+ ASSERT_RETURN_VAL(ret >= 0, ret); -+ -+ if (WIFSIGNALED(status)) -+ return -1; -+ -+ return (status == EXIT_SUCCESS) ? 0 : -1; -+} -+ -+static void *run_thread_reply(void *data) -+{ -+ int ret; -+ unsigned long status = TEST_OK; -+ -+ ret = kdbus_msg_recv_poll(conn_a, 3000, NULL, NULL); -+ if (ret < 0) -+ goto exit_thread; -+ -+ kdbus_printf("Thread received message, sending reply ...\n"); -+ -+ /* using an unknown cookie must fail */ -+ ret = kdbus_msg_send_reply(conn_a, ~cookie, conn_b->id); -+ if (ret != -EPERM) { -+ status = TEST_ERR; -+ goto exit_thread; -+ } -+ -+ ret = kdbus_msg_send_reply(conn_a, cookie, conn_b->id); -+ if (ret != 0) { -+ status = TEST_ERR; -+ goto exit_thread; -+ } -+ -+exit_thread: -+ pthread_exit(NULL); -+ return (void *) status; -+} -+ -+int kdbus_test_sync_reply(struct kdbus_test_env *env) -+{ -+ unsigned long status; -+ pthread_t thread; -+ int ret; -+ -+ conn_a = kdbus_hello(env->buspath, 0, NULL, 0); -+ conn_b = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(conn_a && conn_b); -+ -+ pthread_create(&thread, NULL, run_thread_reply, NULL); -+ -+ ret = kdbus_msg_send_sync(conn_b, NULL, cookie, -+ KDBUS_MSG_EXPECT_REPLY, -+ 5000000000ULL, 0, conn_a->id, -1); -+ -+ pthread_join(thread, (void *) &status); -+ ASSERT_RETURN(status == 0); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = interrupt_sync(conn_a, conn_b); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = close_epipe_sync(env->buspath); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = cancel_fd_sync(conn_a, conn_b); -+ ASSERT_RETURN(ret == 0); -+ -+ ret = no_cancel_sync(conn_a, conn_b); -+ ASSERT_RETURN(ret == 0); -+ -+ kdbus_printf("-- closing bus connections\n"); -+ -+ kdbus_conn_free(conn_a); -+ kdbus_conn_free(conn_b); -+ -+ return TEST_OK; -+} -+ -+#define BYEBYE_ME ((void*)0L) -+#define BYEBYE_THEM ((void*)1L) -+ -+static void *run_thread_byebye(void *data) -+{ -+ struct kdbus_cmd cmd_byebye = { .size = sizeof(cmd_byebye) }; -+ int ret; -+ -+ ret = kdbus_msg_recv_poll(conn_a, 3000, NULL, NULL); -+ if (ret == 0) { -+ kdbus_printf("Thread received message, invoking BYEBYE ...\n"); -+ kdbus_msg_recv(conn_a, NULL, NULL); -+ if (data == BYEBYE_ME) -+ kdbus_cmd_byebye(conn_b->fd, &cmd_byebye); -+ else if (data == BYEBYE_THEM) -+ kdbus_cmd_byebye(conn_a->fd, &cmd_byebye); -+ } -+ -+ pthread_exit(NULL); -+ return NULL; -+} -+ -+int kdbus_test_sync_byebye(struct kdbus_test_env *env) -+{ -+ pthread_t thread; -+ int ret; -+ -+ /* -+ * This sends a synchronous message to a thread, which waits until it -+ * received the message and then invokes BYEBYE on the *ORIGINAL* -+ * connection. That is, on the same connection that synchronously waits -+ * for an reply. -+ * This should properly wake the connection up and cause ECONNRESET as -+ * the connection is disconnected now. -+ * -+ * The second time, we do the same but invoke BYEBYE on the *TARGET* -+ * connection. This should also wake up the synchronous sender as the -+ * reply cannot be sent by a disconnected target. -+ */ -+ -+ conn_a = kdbus_hello(env->buspath, 0, NULL, 0); -+ conn_b = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(conn_a && conn_b); -+ -+ pthread_create(&thread, NULL, run_thread_byebye, BYEBYE_ME); -+ -+ ret = kdbus_msg_send_sync(conn_b, NULL, cookie, -+ KDBUS_MSG_EXPECT_REPLY, -+ 5000000000ULL, 0, conn_a->id, -1); -+ -+ ASSERT_RETURN(ret == -ECONNRESET); -+ -+ pthread_join(thread, NULL); -+ -+ kdbus_conn_free(conn_a); -+ kdbus_conn_free(conn_b); -+ -+ conn_a = kdbus_hello(env->buspath, 0, NULL, 0); -+ conn_b = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(conn_a && conn_b); -+ -+ pthread_create(&thread, NULL, run_thread_byebye, BYEBYE_THEM); -+ -+ ret = kdbus_msg_send_sync(conn_b, NULL, cookie, -+ KDBUS_MSG_EXPECT_REPLY, -+ 5000000000ULL, 0, conn_a->id, -1); -+ -+ ASSERT_RETURN(ret == -EPIPE); -+ -+ pthread_join(thread, NULL); -+ -+ kdbus_conn_free(conn_a); -+ kdbus_conn_free(conn_b); -+ -+ return TEST_OK; -+} -diff --git a/tools/testing/selftests/kdbus/test-timeout.c b/tools/testing/selftests/kdbus/test-timeout.c -new file mode 100644 -index 000000000000..cfd193066a64 ---- /dev/null -+++ b/tools/testing/selftests/kdbus/test-timeout.c -@@ -0,0 +1,99 @@ -+#include <stdio.h> -+#include <string.h> -+#include <time.h> -+#include <fcntl.h> -+#include <stdlib.h> -+#include <stddef.h> -+#include <unistd.h> -+#include <stdint.h> -+#include <errno.h> -+#include <assert.h> -+#include <poll.h> -+#include <stdbool.h> -+ -+#include "kdbus-api.h" -+#include "kdbus-test.h" -+#include "kdbus-util.h" -+#include "kdbus-enum.h" -+ -+int timeout_msg_recv(struct kdbus_conn *conn, uint64_t *expected) -+{ -+ struct kdbus_cmd_recv recv = { .size = sizeof(recv) }; -+ struct kdbus_msg *msg; -+ int ret; -+ -+ ret = kdbus_cmd_recv(conn->fd, &recv); -+ if (ret < 0) { -+ kdbus_printf("error receiving message: %d (%m)\n", ret); -+ return ret; -+ } -+ -+ msg = (struct kdbus_msg *)(conn->buf + recv.msg.offset); -+ -+ ASSERT_RETURN_VAL(msg->payload_type == KDBUS_PAYLOAD_KERNEL, -EINVAL); -+ ASSERT_RETURN_VAL(msg->src_id == KDBUS_SRC_ID_KERNEL, -EINVAL); -+ ASSERT_RETURN_VAL(msg->dst_id == conn->id, -EINVAL); -+ -+ *expected &= ~(1ULL << msg->cookie_reply); -+ kdbus_printf("Got message timeout for cookie %llu\n", -+ msg->cookie_reply); -+ -+ ret = kdbus_free(conn, recv.msg.offset); -+ if (ret < 0) -+ return ret; -+ -+ return 0; -+} -+ -+int kdbus_test_timeout(struct kdbus_test_env *env) -+{ -+ struct kdbus_conn *conn_a, *conn_b; -+ struct pollfd fd; -+ int ret, i, n_msgs = 4; -+ uint64_t expected = 0; -+ uint64_t cookie = 0xdeadbeef; -+ -+ conn_a = kdbus_hello(env->buspath, 0, NULL, 0); -+ conn_b = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(conn_a && conn_b); -+ -+ fd.fd = conn_b->fd; -+ -+ /* -+ * send messages that expect a reply (within 100 msec), -+ * but never answer it. -+ */ -+ for (i = 0; i < n_msgs; i++, cookie++) { -+ kdbus_printf("Sending message with cookie %llu ...\n", -+ (unsigned long long)cookie); -+ ASSERT_RETURN(kdbus_msg_send(conn_b, NULL, cookie, -+ KDBUS_MSG_EXPECT_REPLY, -+ (i + 1) * 100ULL * 1000000ULL, 0, -+ conn_a->id) == 0); -+ expected |= 1ULL << cookie; -+ } -+ -+ for (;;) { -+ fd.events = POLLIN | POLLPRI | POLLHUP; -+ fd.revents = 0; -+ -+ ret = poll(&fd, 1, (n_msgs + 1) * 100); -+ if (ret == 0) -+ kdbus_printf("--- timeout\n"); -+ if (ret <= 0) -+ break; -+ -+ if (fd.revents & POLLIN) -+ ASSERT_RETURN(!timeout_msg_recv(conn_b, &expected)); -+ -+ if (expected == 0) -+ break; -+ } -+ -+ ASSERT_RETURN(expected == 0); -+ -+ kdbus_conn_free(conn_a); -+ kdbus_conn_free(conn_b); -+ -+ return TEST_OK; -+} --- -2.4.3 - - -From e5f30afc29ce2da58a7795f86ae77b7a89b8084c Mon Sep 17 00:00:00 2001 -From: Daniel Mack <daniel@zonque.org> -Date: Mon, 9 Mar 2015 18:00:46 +0100 -Subject: [PATCH 015/132] Documentation: kdbus: fix location for generated - files - -The generated files should reside in Documentation/kdbus, not in the -top-level of the source tree. Also add a .gitignore file and ignore -everything that was built from the XML files. - -Signed-off-by: Daniel Mack <daniel@zonque.org> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - Documentation/kdbus/.gitignore | 2 ++ - Documentation/kdbus/Makefile | 4 ++-- - 2 files changed, 4 insertions(+), 2 deletions(-) - create mode 100644 Documentation/kdbus/.gitignore - -diff --git a/Documentation/kdbus/.gitignore b/Documentation/kdbus/.gitignore -new file mode 100644 -index 000000000000..b4a77ccba9b4 ---- /dev/null -+++ b/Documentation/kdbus/.gitignore -@@ -0,0 +1,2 @@ -+*.7 -+*.html -diff --git a/Documentation/kdbus/Makefile b/Documentation/kdbus/Makefile -index cd6b48ee41bf..f6d491251c25 100644 ---- a/Documentation/kdbus/Makefile -+++ b/Documentation/kdbus/Makefile -@@ -18,10 +18,10 @@ HTMLFILES := $(patsubst %.xml, %.html, $(XMLFILES)) - XMLTO_ARGS := -m $(obj)/stylesheet.xsl - - %.7: %.xml -- xmlto man $(XMLTO_ARGS) -o . $< -+ xmlto man $(XMLTO_ARGS) -o $(obj) $< - - %.html: %.xml -- xmlto html-nochunks $(XMLTO_ARGS) -o . $< -+ xmlto html-nochunks $(XMLTO_ARGS) -o $(obj) $< - - mandocs: $(MANFILES) - --- -2.4.3 - - -From 6ccaab40267b109c01f3ca82ebc8bdf7028ebf5f Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Thu, 12 Mar 2015 17:27:31 +0100 -Subject: [PATCH 016/132] kdbus: samples/kdbus: add -lrt - -On older systems -lrt is needed for clock_gettime(). Add it to -HOSTLOADLIBES of kdbus-workers so it builds fine on those systems. - -Reported-by: Sasha Levin <sasha.levin@oracle.com> -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - samples/kdbus/Makefile | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/samples/kdbus/Makefile b/samples/kdbus/Makefile -index d009025369f4..eee9b9aed632 100644 ---- a/samples/kdbus/Makefile -+++ b/samples/kdbus/Makefile -@@ -8,3 +8,4 @@ always := $(hostprogs-y) - HOSTCFLAGS_kdbus-workers.o += \ - -I$(objtree)/usr/include/ \ - -I$(objtree)/include/uapi/ -+HOSTLOADLIBES_kdbus-workers := -lrt --- -2.4.3 - - -From 9b12c3a3dc37178c3a41e3bbf3633aba53ccd10b Mon Sep 17 00:00:00 2001 -From: Nicolas Iooss <nicolas.iooss_linux@m4x.org> -Date: Sun, 15 Mar 2015 13:13:08 +0800 -Subject: [PATCH 017/132] kdbus: fix minor typo in the walk-through example - -s/receveiver/receiver/ - -Signed-off-by: Nicolas Iooss <nicolas.iooss_linux@m4x.org> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - samples/kdbus/kdbus-workers.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/samples/kdbus/kdbus-workers.c b/samples/kdbus/kdbus-workers.c -index d1d8f7a7697b..d331e0186899 100644 ---- a/samples/kdbus/kdbus-workers.c -+++ b/samples/kdbus/kdbus-workers.c -@@ -787,8 +787,8 @@ static int child_run(struct child *c) - * The 2nd item contains a vector to memory we want to send. It - * can be content of any type. In our case, we're sending a one-byte - * string only. The memory referenced by this item will be copied into -- * the pool of the receveiver connection, and does not need to be -- * valid after the command is employed. -+ * the pool of the receiver connection, and does not need to be valid -+ * after the command is employed. - */ - item = KDBUS_ITEM_NEXT(item); - item->type = KDBUS_ITEM_PAYLOAD_VEC; --- -2.4.3 - - -From 526edb23cd096375683455c73b56baba34ae3f06 Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Mon, 16 Mar 2015 10:17:10 +0100 -Subject: [PATCH 018/132] samples/kdbus: drop wrong include - -There is no reason to use ./include/uapi/ directly from samples. If your -system headers are not up-to-date, you _need_ to run "make -headers-install" (which will install them to ./usr/ in your kernel tree) -before building the examples. Otherwise, you will get warnings and build -failures. - -Once ./usr/ is updated with the correct headers, it contains everything we -need, so drop -Iinclude/uapi from the kdbus-workers CFLAGS. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - samples/kdbus/Makefile | 4 +--- - 1 file changed, 1 insertion(+), 3 deletions(-) - -diff --git a/samples/kdbus/Makefile b/samples/kdbus/Makefile -index eee9b9aed632..e714602b6260 100644 ---- a/samples/kdbus/Makefile -+++ b/samples/kdbus/Makefile -@@ -5,7 +5,5 @@ hostprogs-y += kdbus-workers - - always := $(hostprogs-y) - --HOSTCFLAGS_kdbus-workers.o += \ -- -I$(objtree)/usr/include/ \ -- -I$(objtree)/include/uapi/ -+HOSTCFLAGS_kdbus-workers.o += -I$(objtree)/usr/include - HOSTLOADLIBES_kdbus-workers := -lrt --- -2.4.3 - - -From ede527300a3ec34e284d31d5bd3fcdf7d6a0bc77 Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Mon, 16 Mar 2015 10:17:11 +0100 -Subject: [PATCH 019/132] Documentation/kdbus: fix out-of-tree builds - -Don't use $(obj) to access source files, but use $(srctree)/$(src)/ -instead. This fixes build issues if you use O= with a directory other than -the source directory. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - Documentation/kdbus/Makefile | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/Documentation/kdbus/Makefile b/Documentation/kdbus/Makefile -index f6d491251c25..d8e6bf37d53b 100644 ---- a/Documentation/kdbus/Makefile -+++ b/Documentation/kdbus/Makefile -@@ -15,7 +15,7 @@ XMLFILES := $(addprefix $(obj)/,$(DOCS)) - MANFILES := $(patsubst %.xml, %.7, $(XMLFILES)) - HTMLFILES := $(patsubst %.xml, %.html, $(XMLFILES)) - --XMLTO_ARGS := -m $(obj)/stylesheet.xsl -+XMLTO_ARGS := -m $(srctree)/$(src)/stylesheet.xsl - - %.7: %.xml - xmlto man $(XMLTO_ARGS) -o $(obj) $< --- -2.4.3 - - -From 58805f2c66a854b045cd905e157e57e46620ed8d Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Mon, 16 Mar 2015 10:17:12 +0100 -Subject: [PATCH 020/132] Documentation/kdbus: support quiet builds - -Add support for quiet builds, just like Documentation/DocBook/Makefile -supports. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - Documentation/kdbus/Makefile | 16 +++++++++++++--- - 1 file changed, 13 insertions(+), 3 deletions(-) - -diff --git a/Documentation/kdbus/Makefile b/Documentation/kdbus/Makefile -index d8e6bf37d53b..af87641db416 100644 ---- a/Documentation/kdbus/Makefile -+++ b/Documentation/kdbus/Makefile -@@ -15,13 +15,23 @@ XMLFILES := $(addprefix $(obj)/,$(DOCS)) - MANFILES := $(patsubst %.xml, %.7, $(XMLFILES)) - HTMLFILES := $(patsubst %.xml, %.html, $(XMLFILES)) - --XMLTO_ARGS := -m $(srctree)/$(src)/stylesheet.xsl -+XMLTO_ARGS := -m $(srctree)/$(src)/stylesheet.xsl --skip-validation - -+quiet_cmd_db2man = MAN $@ -+ cmd_db2man = xmlto man $(XMLTO_ARGS) -o $(obj) $< - %.7: %.xml -- xmlto man $(XMLTO_ARGS) -o $(obj) $< -+ @(which xmlto > /dev/null 2>&1) || \ -+ (echo "*** You need to install xmlto ***"; \ -+ exit 1) -+ $(call cmd,db2man) - -+quiet_cmd_db2html = HTML $@ -+ cmd_db2html = xmlto html-nochunks $(XMLTO_ARGS) -o $(obj) $< - %.html: %.xml -- xmlto html-nochunks $(XMLTO_ARGS) -o $(obj) $< -+ @(which xmlto > /dev/null 2>&1) || \ -+ (echo "*** You need to install xmlto ***"; \ -+ exit 1) -+ $(call cmd,db2html) - - mandocs: $(MANFILES) - --- -2.4.3 - - -From 2a46ff720698c3ceaea3f4ee05895b8c6931cf5e Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Mon, 16 Mar 2015 10:17:13 +0100 -Subject: [PATCH 021/132] selftests/kdbus: fix gitignore - -Drop unused elements from .gitignore (which are leftovers when -documentation was placed in the same directory). -Add "kdbus-test" to .gitignore, which is the test binary of all kdbus -selftests. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - tools/testing/selftests/kdbus/.gitignore | 4 +--- - 1 file changed, 1 insertion(+), 3 deletions(-) - -diff --git a/tools/testing/selftests/kdbus/.gitignore b/tools/testing/selftests/kdbus/.gitignore -index 7b421f76c888..d3ef42f6ada6 100644 ---- a/tools/testing/selftests/kdbus/.gitignore -+++ b/tools/testing/selftests/kdbus/.gitignore -@@ -1,3 +1 @@ --*.7 --manpage.* --*.proc -+kdbus-test --- -2.4.3 - - -From 3de5f3c6b98af25c1564c372d3e84d76658ed242 Mon Sep 17 00:00:00 2001 -From: Lukasz Skalski <l.skalski@samsung.com> -Date: Mon, 16 Mar 2015 10:35:08 +0100 -Subject: [PATCH 022/132] Documentation/kdbus: replace 'reply_cookie' with - 'cookie_reply' - -The member field is called 'cookie_reply', fix the documentation which -incorrectly used 'reply_cookie'. - -Signed-off-by: Lukasz Skalski <l.skalski@samsung.com> -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - Documentation/kdbus/kdbus.message.xml | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/Documentation/kdbus/kdbus.message.xml b/Documentation/kdbus/kdbus.message.xml -index c25000dcfbc7..5e7c7a3f537e 100644 ---- a/Documentation/kdbus/kdbus.message.xml -+++ b/Documentation/kdbus/kdbus.message.xml -@@ -393,7 +393,7 @@ struct kdbus_msg { - For a message to be accepted as reply, it must be a direct - message to the original sender (not a broadcast and not a - signal message), and its -- <varname>kdbus_msg.reply_cookie</varname> must match the -+ <varname>kdbus_msg.cookie_reply</varname> must match the - previous message's <varname>kdbus_msg.cookie</varname>. - </para><para> - Expected replies also temporarily open the policy of the --- -2.4.3 - - -From b9bc84f8b7a082ecdee741e69d0cfc6e720f4090 Mon Sep 17 00:00:00 2001 -From: Lucas De Marchi <lucas.demarchi@intel.com> -Date: Tue, 17 Mar 2015 09:21:42 -0300 -Subject: [PATCH 023/132] kdbus: fix header guard name - -UAPI headers have a _UAPI_ as prefix, which is removed during -headers_install. If it's put as a suffix it will not be removed and will -be the only header with UAPI in the header guard macro. - -Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com> -Reviewed-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - include/uapi/linux/kdbus.h | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/include/uapi/linux/kdbus.h b/include/uapi/linux/kdbus.h -index fc1d77dd7c93..2fe0a1c5056c 100644 ---- a/include/uapi/linux/kdbus.h -+++ b/include/uapi/linux/kdbus.h -@@ -5,8 +5,8 @@ - * your option) any later version. - */ - --#ifndef _KDBUS_UAPI_H_ --#define _KDBUS_UAPI_H_ -+#ifndef _UAPI_KDBUS_H_ -+#define _UAPI_KDBUS_H_ - - #include <linux/ioctl.h> - #include <linux/types.h> -@@ -976,4 +976,4 @@ enum kdbus_ioctl_type { - struct kdbus_cmd_match), - }; - --#endif /* _KDBUS_UAPI_H_ */ -+#endif /* _UAPI_KDBUS_H_ */ --- -2.4.3 - - -From ac30e5255c122d71775630f508b22e8c5822db6f Mon Sep 17 00:00:00 2001 -From: Daniel Mack <daniel@zonque.org> -Date: Tue, 17 Mar 2015 19:48:24 +0100 -Subject: [PATCH 024/132] kdbus: connection: fix handling of failed fget() - -The patch 5fc8dd5c84fc: "kdbus: add connection, queue handling and -message validation code" from Sep 11, 2014, leads to the following -static checker warning: - - ipc/kdbus/connection.c:2000 kdbus_cmd_send() - warn: 'cancel_fd' isn't an ERR_PTR - -Fix this by checking for NULL pointers returned from fget(). - -Reported-by: Dan Carpenter <dan.carpenter@oracle.com> -Signed-off-by: Daniel Mack <daniel@zonque.org> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - ipc/kdbus/connection.c | 5 ++--- - 1 file changed, 2 insertions(+), 3 deletions(-) - -diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c -index e554f1a71aa1..ab476fa9ccca 100644 ---- a/ipc/kdbus/connection.c -+++ b/ipc/kdbus/connection.c -@@ -1997,9 +1997,8 @@ int kdbus_cmd_send(struct kdbus_conn *conn, struct file *f, void __user *argp) - - if (argv[1].item) { - cancel_fd = fget(argv[1].item->fds[0]); -- if (IS_ERR(cancel_fd)) { -- ret = PTR_ERR(cancel_fd); -- cancel_fd = NULL; -+ if (!cancel_fd) { -+ ret = -EBADF; - goto exit; - } - --- -2.4.3 - - -From 1e951b699ad9237dca512dd1eb366290380cbd20 Mon Sep 17 00:00:00 2001 -From: Daniel Mack <daniel@zonque.org> -Date: Tue, 24 Mar 2015 19:51:55 +0100 -Subject: [PATCH 025/132] kdbus: Fix CONFIG_KDBUS help text - -Drop a left-over from the times when documentation lived in a -simple text file, which is no longer the case. Mention the -auto-generated man-pages and HTML files instead. - -Reported-by: Jiri Slaby <jslaby@suse.cz> -Signed-off-by: Daniel Mack <daniel@zonque.org> -Reviewed-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - init/Kconfig | 7 ++++--- - 1 file changed, 4 insertions(+), 3 deletions(-) - -diff --git a/init/Kconfig b/init/Kconfig -index a7b462e7d647..6bda631badc1 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -268,10 +268,11 @@ config KDBUS - D-Bus is a system for low-latency, low-overhead, easy to use - interprocess communication (IPC). - -- See Documentation/kdbus.txt -+ See the man-pages and HTML files in Documentation/kdbus/ -+ that are generated by 'make mandocs' and 'make htmldocs'. - -- To compile this driver as a module, choose M here: the -- module will be called kdbus. -+ If you have an ordinary machine, select M here. The module -+ will be called kdbus. - - config CROSS_MEMORY_ATTACH - bool "Enable process_vm_readv/writev syscalls" --- -2.4.3 - - -From 4e403bc9bdb439a9c5fab5b25844820293d2777a Mon Sep 17 00:00:00 2001 -From: Daniel Mack <daniel@zonque.org> -Date: Tue, 31 Mar 2015 15:11:34 +0200 -Subject: [PATCH 026/132] samples: kdbus: build kdbus-workers conditionally - -Give the kdbus sample its own config switch and only build it if it's -explicitly switched on. - -Signed-off-by: Daniel Mack <daniel@zonque.org> -Reviewed-by: David Herrmann <dh.herrmann@gmail.com> -Reported-by: Jiri Slaby <jslaby@suse.cz> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - samples/Kconfig | 7 +++++++ - samples/kdbus/Makefile | 2 +- - 2 files changed, 8 insertions(+), 1 deletion(-) - -diff --git a/samples/Kconfig b/samples/Kconfig -index 224ebb46bed5..a4c6b2f8fa85 100644 ---- a/samples/Kconfig -+++ b/samples/Kconfig -@@ -55,6 +55,13 @@ config SAMPLE_KDB - Build an example of how to dynamically add the hello - command to the kdb shell. - -+config SAMPLE_KDBUS -+ bool "Build kdbus API example" -+ depends on KDBUS -+ help -+ Build an example of how the kdbus API can be used from -+ userspace. -+ - config SAMPLE_RPMSG_CLIENT - tristate "Build rpmsg client sample -- loadable modules only" - depends on RPMSG && m -diff --git a/samples/kdbus/Makefile b/samples/kdbus/Makefile -index e714602b6260..137f84272099 100644 ---- a/samples/kdbus/Makefile -+++ b/samples/kdbus/Makefile -@@ -1,7 +1,7 @@ - # kbuild trick to avoid linker error. Can be omitted if a module is built. - obj- := dummy.o - --hostprogs-y += kdbus-workers -+hostprogs-$(CONFIG_SAMPLE_KDBUS) += kdbus-workers - - always := $(hostprogs-y) - --- -2.4.3 - - -From 98ecc663f3f9e7353eeb5da5cad7116e2f075c77 Mon Sep 17 00:00:00 2001 -From: Tyler Baker <tyler.baker@linaro.org> -Date: Wed, 1 Apr 2015 16:20:16 -0700 -Subject: [PATCH 027/132] selftest/kdbus: enable cross compilation - -Use the CC variable instead of hard coding gcc and include lib.mk. - -Signed-off-by: Tyler Baker <tyler.baker@linaro.org> -Acked-by: Shuah Khan <shuahkh@osg.samsung.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - tools/testing/selftests/kdbus/Makefile | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/tools/testing/selftests/kdbus/Makefile b/tools/testing/selftests/kdbus/Makefile -index f6cfab26f315..de8242f9b00e 100644 ---- a/tools/testing/selftests/kdbus/Makefile -+++ b/tools/testing/selftests/kdbus/Makefile -@@ -33,11 +33,13 @@ OBJS= \ - - all: kdbus-test - -+include ../lib.mk -+ - %.o: %.c -- gcc $(CFLAGS) -c $< -o $@ -+ $(CC) $(CFLAGS) -c $< -o $@ - - kdbus-test: $(OBJS) -- gcc $(CFLAGS) $^ $(LDLIBS) -o $@ -+ $(CC) $(CFLAGS) $^ $(LDLIBS) -o $@ - - run_tests: - ./kdbus-test --tap --- -2.4.3 - - -From 02e0a0d551ea598b3fe736ebe46cbcd367e87b9b Mon Sep 17 00:00:00 2001 -From: Sergei Zviagintsev <sergei@s15v.net> -Date: Thu, 9 Apr 2015 13:11:01 +0300 -Subject: [PATCH 028/132] kdbus: uapi: Fix kernel-doc for enum kdbus_send_flags - -Signed-off-by: Sergei Zviagintsev <sergei@s15v.net> -Acked-by: Daniel Mack <daniel@zonque.org> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - include/uapi/linux/kdbus.h | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/include/uapi/linux/kdbus.h b/include/uapi/linux/kdbus.h -index 2fe0a1c5056c..00a6e142c977 100644 ---- a/include/uapi/linux/kdbus.h -+++ b/include/uapi/linux/kdbus.h -@@ -544,7 +544,7 @@ struct kdbus_msg_info { - * reply to this message. The - * KDBUS_CMD_SEND ioctl() will block - * until the reply is received, and -- * offset_reply in struct kdbus_msg will -+ * reply in struct kdbus_cmd_send will - * yield the offset in the sender's pool - * where the reply can be found. - * This flag is only valid if --- -2.4.3 - - -From 2e5b0f5001bca06c81f32b7438da98f45380545f Mon Sep 17 00:00:00 2001 -From: Sergei Zviagintsev <sergei@s15v.net> -Date: Thu, 9 Apr 2015 13:08:07 +0300 -Subject: [PATCH 029/132] Documentation: kdbus: Fix list of - KDBUS_CMD_ENDPOINT_UPDATE errors - -Remove EEXIST. - -Signed-off-by: Sergei Zviagintsev <sergei@s15v.net> -Acked-by: Daniel Mack <daniel@zonque.org> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - Documentation/kdbus/kdbus.endpoint.xml | 7 ------- - 1 file changed, 7 deletions(-) - -diff --git a/Documentation/kdbus/kdbus.endpoint.xml b/Documentation/kdbus/kdbus.endpoint.xml -index 76e325d4e931..c36aa9781739 100644 ---- a/Documentation/kdbus/kdbus.endpoint.xml -+++ b/Documentation/kdbus/kdbus.endpoint.xml -@@ -369,13 +369,6 @@ struct kdbus_cmd { - <constant>KDBUS_ITEM_POLICY_ACCESS</constant> was provided. - </para></listitem> - </varlistentry> -- -- <varlistentry> -- <term><constant>EEXIST</constant></term> -- <listitem><para> -- An endpoint of that name already exists. -- </para></listitem> -- </varlistentry> - </variablelist> - </refsect2> - </refsect1> --- -2.4.3 - - -From 1effb1e0675e0654c442bc284df44c1bbf5eb75a Mon Sep 17 00:00:00 2001 -From: Sergei Zviagintsev <sergei@s15v.net> -Date: Thu, 9 Apr 2015 13:08:06 +0300 -Subject: [PATCH 030/132] Documentation: kdbus: Update list of ioctls which - cause writing to receiver's pool - -Add KDBUS_CMD_BUS_CREATOR_INFO. - -Signed-off-by: Sergei Zviagintsev <sergei@s15v.net> -Acked-by: Daniel Mack <daniel@zonque.org> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - Documentation/kdbus/kdbus.pool.xml | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/Documentation/kdbus/kdbus.pool.xml b/Documentation/kdbus/kdbus.pool.xml -index 05fd01902ad4..a9e16f196d39 100644 ---- a/Documentation/kdbus/kdbus.pool.xml -+++ b/Documentation/kdbus/kdbus.pool.xml -@@ -66,6 +66,12 @@ - ... to retrieve information on a connection - </para></listitem> - </varlistentry> -+ <varlistentry> -+ <term><constant>KDBUS_CMD_BUS_CREATOR_INFO</constant></term> -+ <listitem><para> -+ ... to retrieve information about a connection's bus creator -+ </para></listitem> -+ </varlistentry> - </variablelist> - - </para> --- -2.4.3 - - -From 480e1a131b561a043e1b7cfeb4b1e838b9c88b1d Mon Sep 17 00:00:00 2001 -From: Sergei Zviagintsev <sergei@s15v.net> -Date: Thu, 9 Apr 2015 13:08:05 +0300 -Subject: [PATCH 031/132] Documentation: kdbus: Fix description of - KDBUS_SEND_SYNC_REPLY flag - -Signed-off-by: Sergei Zviagintsev <sergei@s15v.net> -Acked-by: Daniel Mack <daniel@zonque.org> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - Documentation/kdbus/kdbus.message.xml | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/Documentation/kdbus/kdbus.message.xml b/Documentation/kdbus/kdbus.message.xml -index 5e7c7a3f537e..90f6596dcc20 100644 ---- a/Documentation/kdbus/kdbus.message.xml -+++ b/Documentation/kdbus/kdbus.message.xml -@@ -242,8 +242,8 @@ struct kdbus_cmd_send { - </citerefentry>. - - The offset of the reply message in the sender's pool is stored -- in in <varname>offset_reply</varname> when the ioctl has -- returned without error. Hence, there is no need for another -+ in <varname>reply</varname> when the ioctl has returned without -+ error. Hence, there is no need for another - <constant>KDBUS_CMD_RECV</constant> ioctl or anything else to - receive the reply. - </para> --- -2.4.3 - - -From 13ed3ae959a6f0d4bdc1509a2d7219444726d9e8 Mon Sep 17 00:00:00 2001 -From: Sergei Zviagintsev <sergei@s15v.net> -Date: Thu, 9 Apr 2015 13:08:04 +0300 -Subject: [PATCH 032/132] Documentation: kdbus: Fix typos - -Signed-off-by: Sergei Zviagintsev <sergei@s15v.net> -Acked-by: Daniel Mack <daniel@zonque.org> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - Documentation/kdbus/kdbus.bus.xml | 9 ++++----- - Documentation/kdbus/kdbus.connection.xml | 10 ++++------ - Documentation/kdbus/kdbus.endpoint.xml | 2 +- - Documentation/kdbus/kdbus.item.xml | 9 ++++----- - Documentation/kdbus/kdbus.match.xml | 14 ++++++++------ - Documentation/kdbus/kdbus.message.xml | 11 +++++------ - Documentation/kdbus/kdbus.xml | 6 +++--- - 7 files changed, 29 insertions(+), 32 deletions(-) - -diff --git a/Documentation/kdbus/kdbus.bus.xml b/Documentation/kdbus/kdbus.bus.xml -index 4d875e59ac02..4b9a0ac1b351 100644 ---- a/Documentation/kdbus/kdbus.bus.xml -+++ b/Documentation/kdbus/kdbus.bus.xml -@@ -28,8 +28,7 @@ - <citerefentry> - <refentrytitle>kdbus.message</refentrytitle> - <manvolnum>7</manvolnum> -- </citerefentry> -- ). -+ </citerefentry>). - Each bus is independent, and operations on the bus will not have any - effect on other buses. A bus is a management entity that controls the - addresses of its connections, their policies and message transactions -@@ -42,7 +41,7 @@ - <refentrytitle>kdbus.fs</refentrytitle> - <manvolnum>7</manvolnum> - </citerefentry> -- , a bus is presented as a directory. No operations can be performed on -+ a bus is presented as a directory. No operations can be performed on - the bus itself; instead you need to perform the operations on an endpoint - associated with the bus. Endpoints are accessible as files underneath the - bus directory. A default endpoint called <constant>bus</constant> is -@@ -165,8 +164,8 @@ struct kdbus_cmd { - <citerefentry> - <refentrytitle>kdbus.item</refentrytitle> - <manvolnum>7</manvolnum> -- </citerefentry> -- ) are expected for <constant>KDBUS_CMD_BUS_MAKE</constant>. -+ </citerefentry>) -+ are expected for <constant>KDBUS_CMD_BUS_MAKE</constant>. - </para> - <variablelist> - <varlistentry> -diff --git a/Documentation/kdbus/kdbus.connection.xml b/Documentation/kdbus/kdbus.connection.xml -index 09852125b2d4..cefb419f1093 100644 ---- a/Documentation/kdbus/kdbus.connection.xml -+++ b/Documentation/kdbus/kdbus.connection.xml -@@ -50,8 +50,7 @@ - <citerefentry> - <refentrytitle>kdbus.match</refentrytitle> - <manvolnum>7</manvolnum> -- </citerefentry> -- ). -+ </citerefentry>). - </para> - <para> - Messages synthesized and sent directly by the kernel will carry the -@@ -595,13 +594,13 @@ struct kdbus_cmd_info { - </varlistentry> - - <varlistentry> -- <term><varname>flags</varname></term> -+ <term><varname>attach_flags</varname></term> - <listitem><para> - Specifies which metadata items should be attached to the answer. See - <citerefentry> - <refentrytitle>kdbus.message</refentrytitle> - <manvolnum>7</manvolnum> -- </citerefentry> -+ </citerefentry>. - </para></listitem> - </varlistentry> - -@@ -986,8 +985,7 @@ struct kdbus_cmd { - <term><varname>items</varname></term> - <listitem> - <para> -- Items to describe the connection details to be updated. The -- following item types are supported. -+ The following item types are supported. - </para> - <variablelist> - <varlistentry> -diff --git a/Documentation/kdbus/kdbus.endpoint.xml b/Documentation/kdbus/kdbus.endpoint.xml -index c36aa9781739..6632485f3e84 100644 ---- a/Documentation/kdbus/kdbus.endpoint.xml -+++ b/Documentation/kdbus/kdbus.endpoint.xml -@@ -201,7 +201,7 @@ struct kdbus_cmd { - <para> - To update an existing endpoint, the - <constant>KDBUS_CMD_ENDPOINT_UPDATE</constant> command is used on the file -- descriptor that was used to create the update, using -+ descriptor that was used to create the endpoint, using - <constant>KDBUS_CMD_ENDPOINT_MAKE</constant>. The only relevant detail of - the endpoint that can be updated is the policy. When the command is - employed, the policy of the endpoint is <emphasis>replaced</emphasis> -diff --git a/Documentation/kdbus/kdbus.item.xml b/Documentation/kdbus/kdbus.item.xml -index bfe47362097f..09f8b903116f 100644 ---- a/Documentation/kdbus/kdbus.item.xml -+++ b/Documentation/kdbus/kdbus.item.xml -@@ -139,7 +139,7 @@ struct kdbus_item { - <term><constant>KDBUS_ITEM_NEGOTIATE</constant></term> - <listitem><para> - With this item is attached to any ioctl, programs can -- <emphasis>probe</emphasis> the kernel for known item items. -+ <emphasis>probe</emphasis> the kernel for known item types. - The item carries an array of <type>uint64_t</type> values in - <varname>item.data64</varname>, each set to an item type to - probe. The kernel will reset each member of this array that is -@@ -232,7 +232,6 @@ struct kdbus_memfd { - When received as item attached to a message, the array will - contain the numbers of the installed file descriptors, or - <constant>-1</constant> in case an error occurred. -- file descriptor. - In either case, the number of entries in the array is derived from - the item's total size. See - <citerefentry> -@@ -487,7 +486,7 @@ struct kdbus_pids { - a remote peer is a member of, stored as array of - <type>uint32_t</type> values in <varname>item.data32</varname>. - The array length can be determined by looking at the item's total -- size, subtracting the size of the header and and dividing the -+ size, subtracting the size of the header and dividing the - remainder by <constant>sizeof(uint32_t)</constant>. - </para></listitem> - </varlistentry> -@@ -748,7 +747,7 @@ struct kdbus_notify_name_change { - This item is sent as attachment to a - <emphasis>kernel notification</emphasis>. It informs the receiver - that an expected reply to a message was not received in time. -- The remote peer ID and the message cookie is stored in the message -+ The remote peer ID and the message cookie are stored in the message - header. See - <citerefentry> - <refentrytitle>kdbus.message</refentrytitle> -@@ -765,7 +764,7 @@ struct kdbus_notify_name_change { - <emphasis>kernel notification</emphasis>. It informs the receiver - that a remote connection a reply is expected from was disconnected - before that reply was sent. The remote peer ID and the message -- cookie is stored in the message header. See -+ cookie are stored in the message header. See - <citerefentry> - <refentrytitle>kdbus.message</refentrytitle> - <manvolnum>7</manvolnum> -diff --git a/Documentation/kdbus/kdbus.match.xml b/Documentation/kdbus/kdbus.match.xml -index ef77b64e5890..ae38e04ab4d6 100644 ---- a/Documentation/kdbus/kdbus.match.xml -+++ b/Documentation/kdbus/kdbus.match.xml -@@ -55,7 +55,7 @@ - possibly along with some other rules to further limit the match. - - The kernel will match the signal message's bloom filter against the -- connections bloom mask (simply by &-ing it), and will decide whether -+ connection's bloom mask (simply by &-ing it), and will decide whether - the message should be delivered to a connection. - </para> - <para> -@@ -138,9 +138,9 @@ - <title>Generations</title> - - <para> -- Uploaded matches may contain multiple masks, which have are as large as -- the bloom size defined by the bus. Each block of a mask is called a -- <emphasis>generation</emphasis>, starting at index 0. -+ Uploaded matches may contain multiple masks, which have to be as large -+ as the bloom filter size defined by the bus. Each block of a mask is -+ called a <emphasis>generation</emphasis>, starting at index 0. - - At match time, when a signal is about to be delivered, a bloom mask - generation is passed, which denotes which of the bloom masks the filter -@@ -171,7 +171,8 @@ - <title>Adding a match</title> - <para> - To add a match, the <constant>KDBUS_CMD_MATCH_ADD</constant> ioctl is -- used, which takes a struct of the struct described below. -+ used, which takes a <type>struct kdbus_cmd_match</type> as an argument -+ described below. - - Note that each of the items attached to this command will internally - create one match <emphasis>rule</emphasis>, and the collection of them, -@@ -266,7 +267,8 @@ struct kdbus_cmd_match { - 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 the section below for more information on bloom filters. -+ See the "Bloom filters" section above for more information on -+ bloom filters. - </para> - </listitem> - </varlistentry> -diff --git a/Documentation/kdbus/kdbus.message.xml b/Documentation/kdbus/kdbus.message.xml -index 90f6596dcc20..0115d9d50db3 100644 ---- a/Documentation/kdbus/kdbus.message.xml -+++ b/Documentation/kdbus/kdbus.message.xml -@@ -344,8 +344,7 @@ struct kdbus_cmd_send { - </variablelist> - - <para> -- The fields in this struct are described below. -- The message referenced the <varname>msg_address</varname> above has -+ The message referenced by the <varname>msg_address</varname> above has - the following layout. - </para> - -@@ -528,7 +527,7 @@ struct kdbus_msg { - <listitem> - <para> - Actual data records containing the payload. See section -- "Passing of Payload Data". -+ "Message payload". - </para> - </listitem> - </varlistentry> -@@ -707,7 +706,7 @@ struct kdbus_cmd_recv { - <listitem><para> - Whenever a message with <constant>KDBUS_MSG_SIGNAL</constant> is sent - but cannot be queued on a peer (e.g., as it contains FDs but the peer -- does not support FDs, or there is no space left in the peer's pool..) -+ does not support FDs, or there is no space left in the peer's pool) - the 'dropped_msgs' counter of the peer is incremented. On the next - RECV ioctl, the 'dropped_msgs' field is copied into the ioctl struct - and cleared on the peer. If it was non-zero, the -@@ -963,7 +962,7 @@ struct kdbus_msg_info { - <varlistentry> - <term><constant>E2BIG</constant></term> - <listitem><para> -- Too many items -+ Too many items. - </para></listitem> - </varlistentry> - -@@ -1172,7 +1171,7 @@ struct kdbus_msg_info { - <varlistentry> - <term><constant>EAGAIN</constant></term> - <listitem><para> -- No message found in the queue -+ No message found in the queue. - </para></listitem> - </varlistentry> - </variablelist> -diff --git a/Documentation/kdbus/kdbus.xml b/Documentation/kdbus/kdbus.xml -index 194abd2e76cc..d8e7400df2af 100644 ---- a/Documentation/kdbus/kdbus.xml -+++ b/Documentation/kdbus/kdbus.xml -@@ -379,7 +379,7 @@ - <listitem> - <para> - When a message is sent (<constant>KDBUS_CMD_SEND</constant>), -- information about the sending task and the sending connection are -+ information about the sending task and the sending connection is - collected. This metadata will be attached to the message when it - arrives in the receiver's pool. If the connection sending the - message installed faked credentials (see -@@ -514,7 +514,7 @@ - To let the kernel know which metadata information to attach as items - to the aforementioned commands, it uses a bitmask. In those, the - following <emphasis>attach flags</emphasis> are currently supported. -- Both the the <varname>attach_flags_recv</varname> and -+ Both the <varname>attach_flags_recv</varname> and - <varname>attach_flags_send</varname> fields of - <type>struct kdbus_cmd_hello</type>, as well as the payload of the - <constant>KDBUS_ITEM_ATTACH_FLAGS_SEND</constant> and -@@ -924,7 +924,7 @@ - - <para> - These ioctls, along with the structs they transport, are explained in -- detail in the other documents linked to in the 'see also' section below. -+ detail in the other documents linked to in the "See Also" section below. - </para> - </refsect1> - --- -2.4.3 - - -From 9fb9cd0f4434a23487b6ef3237e733afae90e336 Mon Sep 17 00:00:00 2001 -From: Arnd Bergmann <arnd@arndb.de> -Date: Fri, 10 Apr 2015 13:43:37 +0200 -Subject: [PATCH 033/132] kdbus: avoid the use of struct timespec - -I did a routine check for new users of 'timespec', which we are trying to remove -from the kernel in order to survive y2038. kdbus came up and looks particularly -trivial to clean up. - -This changes the three ktime_get_ts() variants used in kdbus to ktime_get_ns(), -which aside from removing timespec also simplifies the code and makes it -slightly more efficient by avoiding a two-way conversion. - -Signed-off-by: Arnd Bergmann <arnd@arndb.de> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - ipc/kdbus/metadata.c | 9 ++------- - ipc/kdbus/reply.c | 4 +--- - 2 files changed, 3 insertions(+), 10 deletions(-) - -diff --git a/ipc/kdbus/metadata.c b/ipc/kdbus/metadata.c -index 06e0a54a276a..3adc6c2c2e76 100644 ---- a/ipc/kdbus/metadata.c -+++ b/ipc/kdbus/metadata.c -@@ -678,13 +678,8 @@ struct kdbus_meta_conn *kdbus_meta_conn_unref(struct kdbus_meta_conn *mc) - static void kdbus_meta_conn_collect_timestamp(struct kdbus_meta_conn *mc, - struct kdbus_kmsg *kmsg) - { -- struct timespec ts; -- -- ktime_get_ts(&ts); -- mc->ts.monotonic_ns = timespec_to_ns(&ts); -- -- ktime_get_real_ts(&ts); -- mc->ts.realtime_ns = timespec_to_ns(&ts); -+ mc->ts.monotonic_ns = ktime_get_ns(); -+ mc->ts.realtime_ns = ktime_get_real_ns(); - - if (kmsg) - mc->ts.seqnum = kmsg->seq; -diff --git a/ipc/kdbus/reply.c b/ipc/kdbus/reply.c -index 6b3bd81bbb4d..008dca801627 100644 ---- a/ipc/kdbus/reply.c -+++ b/ipc/kdbus/reply.c -@@ -204,11 +204,9 @@ void kdbus_reply_list_scan_work(struct work_struct *work) - container_of(work, struct kdbus_conn, work.work); - struct kdbus_reply *reply, *reply_tmp; - u64 deadline = ~0ULL; -- struct timespec64 ts; - u64 now; - -- ktime_get_ts64(&ts); -- now = timespec64_to_ns(&ts); -+ now = ktime_get_ns(); - - mutex_lock(&conn->lock); - if (!kdbus_conn_active(conn)) { --- -2.4.3 - - -From 384ede7c5f52ff89d90bf3008360c5f7c0d6fcbf Mon Sep 17 00:00:00 2001 -From: Sergei Zviagintsev <sergei@s15v.net> -Date: Tue, 21 Apr 2015 02:12:18 +0300 -Subject: [PATCH 034/132] kdbus: pool: use __vfs_read() - -After commit 5d5d56897530 ("make new_sync_{read,write}() static") -->read() cannot be called directly. - -kdbus_pool_slice_copy() leads to oops, which can be reproduced by -launching tools/testing/selftests/kdbus/kdbus-test -t message-quota: - -[ 1167.146793] BUG: unable to handle kernel NULL pointer dereference at (null) -[ 1167.147554] IP: [< (null)>] (null) -[ 1167.148670] PGD 3a9dd067 PUD 3a841067 PMD 0 -[ 1167.149611] Oops: 0010 [#1] SMP -[ 1167.150088] Modules linked in: nfsv3 nfs kdbus lockd grace sunrpc -[ 1167.150771] CPU: 0 PID: 518 Comm: kdbus-test Not tainted 4.0.0-next-20150420-kdbus #62 -[ 1167.150771] Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 -[ 1167.150771] task: ffff88003daed120 ti: ffff88003a800000 task.ti: ffff88003a800000 -[ 1167.150771] RIP: 0010:[<0000000000000000>] [< (null)>] (null) -[ 1167.150771] RSP: 0018:ffff88003a803bc0 EFLAGS: 00010286 -[ 1167.150771] RAX: ffff8800377fb000 RBX: 00000000000201e8 RCX: ffff88003a803c00 -[ 1167.150771] RDX: 0000000000000b40 RSI: ffff8800377fb4c0 RDI: ffff88003d815700 -[ 1167.150771] RBP: ffff88003a803c48 R08: ffffffff8139e380 R09: ffff880039d80490 -[ 1167.150771] R10: ffff88003a803a90 R11: 00000000000004c0 R12: 00000000002a24c0 -[ 1167.150771] R13: 0000000000000b40 R14: ffff88003d815700 R15: ffffffff8139e460 -[ 1167.150771] FS: 00007f41dccd4740(0000) GS:ffff88003fc00000(0000) knlGS:0000000000000000 -[ 1167.150771] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 -[ 1167.150771] CR2: 0000000000000000 CR3: 000000003ccdf000 CR4: 00000000000007b0 -[ 1167.150771] Stack: -[ 1167.150771] ffffffffa0065497 ffff88003a803c10 00007ffffffff000 ffff88003aaa67c0 -[ 1167.150771] 00000000000004c0 ffff88003aaa6870 ffff88003ca83300 ffffffffa006537d -[ 1167.150771] 00000000000201e8 ffffea0000ddfec0 ffff88003a803c20 0000000000000018 -[ 1167.150771] Call Trace: -[ 1167.150771] [<ffffffffa0065497>] ? kdbus_pool_slice_copy+0x127/0x200 [kdbus] -[ 1167.150771] [<ffffffffa006537d>] ? kdbus_pool_slice_copy+0xd/0x200 [kdbus] -[ 1167.150771] [<ffffffffa006670a>] kdbus_queue_entry_move+0xaa/0x180 [kdbus] -[ 1167.150771] [<ffffffffa0059e64>] kdbus_conn_move_messages+0x1e4/0x2c0 [kdbus] -[ 1167.150771] [<ffffffffa006234e>] kdbus_name_acquire+0x31e/0x390 [kdbus] -[ 1167.150771] [<ffffffffa00625c5>] kdbus_cmd_name_acquire+0x125/0x130 [kdbus] -[ 1167.150771] [<ffffffffa005db5d>] kdbus_handle_ioctl+0x4ed/0x610 [kdbus] -[ 1167.150771] [<ffffffff811040e0>] do_vfs_ioctl+0x2e0/0x4e0 -[ 1167.150771] [<ffffffff81389750>] ? preempt_schedule_common+0x1f/0x3f -[ 1167.150771] [<ffffffff8110431c>] SyS_ioctl+0x3c/0x80 -[ 1167.150771] [<ffffffff8138c36e>] system_call_fastpath+0x12/0x71 -[ 1167.150771] Code: Bad RIP value. -[ 1167.150771] RIP [< (null)>] (null) -[ 1167.150771] RSP <ffff88003a803bc0> -[ 1167.150771] CR2: 0000000000000000 -[ 1167.168756] ---[ end trace a676bcfa75db5a96 ]--- - -Use __vfs_read() instead. - -Signed-off-by: Sergei Zviagintsev <sergei@s15v.net> -Reviewed-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - ipc/kdbus/pool.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ipc/kdbus/pool.c b/ipc/kdbus/pool.c -index 139bb77056b3..45dcdea505f4 100644 ---- a/ipc/kdbus/pool.c -+++ b/ipc/kdbus/pool.c -@@ -675,7 +675,7 @@ int kdbus_pool_slice_copy(const struct kdbus_pool_slice *slice_dst, - } - - kaddr = (char __force __user *)kmap(page) + page_off; -- n_read = f_src->f_op->read(f_src, kaddr, copy_len, &off_src); -+ n_read = __vfs_read(f_src, kaddr, copy_len, &off_src); - kunmap(page); - mark_page_accessed(page); - flush_dcache_page(page); --- -2.4.3 - - -From f3adf84302fb4fdb6698cf129b96546b47e27d33 Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Thu, 21 May 2015 20:03:29 +0200 -Subject: [PATCH 035/132] kdbus: skip mandatory items on negotiation - -The kdbus negotiation is used to figure out what items and flags an ioctl -supports. It is highly impractical to pass in mandatory items when all we -do is negotiation. Therefore, allow user-space to skip mandatory items if -KDBUS_FLAG_NEGOTIATE is passed. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Acked-by: Daniel Mack <daniel@zonque.org> ---- - ipc/kdbus/handle.c | 15 ++++++++++----- - 1 file changed, 10 insertions(+), 5 deletions(-) - -diff --git a/ipc/kdbus/handle.c b/ipc/kdbus/handle.c -index f72dbe513b4a..3f5d8085a297 100644 ---- a/ipc/kdbus/handle.c -+++ b/ipc/kdbus/handle.c -@@ -71,10 +71,6 @@ static int kdbus_args_verify(struct kdbus_args *args) - if (!KDBUS_ITEMS_END(item, args->items, args->items_size)) - return -EINVAL; - -- for (i = 0; i < args->argc; ++i) -- if (args->argv[i].mandatory && !args->argv[i].item) -- return -EINVAL; -- - return 0; - } - -@@ -149,7 +145,7 @@ static int kdbus_args_negotiate(struct kdbus_args *args) - int __kdbus_args_parse(struct kdbus_args *args, void __user *argp, - size_t type_size, size_t items_offset, void **out) - { -- int ret; -+ int ret, i; - - args->cmd = kdbus_memdup_user(argp, type_size, KDBUS_CMD_MAX_SIZE); - if (IS_ERR(args->cmd)) -@@ -173,6 +169,15 @@ int __kdbus_args_parse(struct kdbus_args *args, void __user *argp, - if (ret < 0) - goto error; - -+ /* mandatory items must be given (but not on negotiation) */ -+ if (!(args->cmd->flags & KDBUS_FLAG_NEGOTIATE)) { -+ for (i = 0; i < args->argc; ++i) -+ if (args->argv[i].mandatory && !args->argv[i].item) { -+ ret = -EINVAL; -+ goto error; -+ } -+ } -+ - *out = args->cmd; - return !!(args->cmd->flags & KDBUS_FLAG_NEGOTIATE); - --- -2.4.3 - - -From 3f7c4bc0522b92206a60b8acd3edcc9df6478fb7 Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Sat, 18 Apr 2015 12:00:33 +0200 -Subject: [PATCH 036/132] kdbus: turn kdbus_node_idr into an ida - -We no longer use the node-idr for lookups. We're only interested in unique -ID allocation. Hence, turn the kdbus_node_idr into an ida and drop the now -redundant locking. This is also what kernfs does for ino allocations. - -Reported-by: Al Viro <viro@zeniv.linux.org.uk> -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Acked-by: Daniel Mack <daniel@zonque.org> ---- - ipc/kdbus/main.c | 1 + - ipc/kdbus/node.c | 23 +++++------------------ - ipc/kdbus/node.h | 2 ++ - 3 files changed, 8 insertions(+), 18 deletions(-) - -diff --git a/ipc/kdbus/main.c b/ipc/kdbus/main.c -index 785f529d98b7..f8eac78cace6 100644 ---- a/ipc/kdbus/main.c -+++ b/ipc/kdbus/main.c -@@ -116,6 +116,7 @@ static void __exit kdbus_exit(void) - { - kdbus_fs_exit(); - kobject_put(kdbus_dir); -+ ida_destroy(&kdbus_node_ida); - } - - module_init(kdbus_init); -diff --git a/ipc/kdbus/node.c b/ipc/kdbus/node.c -index 520df00e676a..0d65c65d2bde 100644 ---- a/ipc/kdbus/node.c -+++ b/ipc/kdbus/node.c -@@ -178,7 +178,7 @@ - * accessed by other callers to properly initialize - * filesystem nodes. - * -- * * node->id: This is an unsigned 32bit integer allocated by an IDR. It is -+ * * node->id: This is an unsigned 32bit integer allocated by an IDA. It is - * always kept as small as possible during allocation and is - * globally unique across all nodes allocated by this module. 0 - * is reserved as "not assigned" and is the default. -@@ -233,8 +233,7 @@ - #define KDBUS_NODE_NEW (KDBUS_NODE_BIAS - 4) - - /* global unique ID mapping for kdbus nodes */ --static DEFINE_IDR(kdbus_node_idr); --static DECLARE_RWSEM(kdbus_node_idr_lock); -+DEFINE_IDA(kdbus_node_ida); - - /** - * kdbus_node_name_hash() - hash a name -@@ -337,15 +336,11 @@ int kdbus_node_link(struct kdbus_node *node, struct kdbus_node *parent, - node->hash = kdbus_node_name_hash(name); - } - -- down_write(&kdbus_node_idr_lock); -- ret = idr_alloc(&kdbus_node_idr, node, 1, 0, GFP_KERNEL); -- if (ret >= 0) -- node->id = ret; -- up_write(&kdbus_node_idr_lock); -- -+ ret = ida_simple_get(&kdbus_node_ida, 1, 0, GFP_KERNEL); - if (ret < 0) - return ret; - -+ node->id = ret; - ret = 0; - - if (parent) { -@@ -440,16 +435,8 @@ struct kdbus_node *kdbus_node_unref(struct kdbus_node *node) - - if (node->free_cb) - node->free_cb(node); -- -- down_write(&kdbus_node_idr_lock); - if (safe.id > 0) -- idr_remove(&kdbus_node_idr, safe.id); -- /* drop caches after last node to not leak memory on unload */ -- if (idr_is_empty(&kdbus_node_idr)) { -- idr_destroy(&kdbus_node_idr); -- idr_init(&kdbus_node_idr); -- } -- up_write(&kdbus_node_idr_lock); -+ ida_simple_remove(&kdbus_node_ida, safe.id); - - kfree(safe.name); - -diff --git a/ipc/kdbus/node.h b/ipc/kdbus/node.h -index be125ce4fd58..970e02b08e9f 100644 ---- a/ipc/kdbus/node.h -+++ b/ipc/kdbus/node.h -@@ -58,6 +58,8 @@ struct kdbus_node { - - #define kdbus_node_from_rb(_node) rb_entry((_node), struct kdbus_node, rb) - -+extern struct ida kdbus_node_ida; -+ - void kdbus_node_init(struct kdbus_node *node, unsigned int type); - - int kdbus_node_link(struct kdbus_node *node, struct kdbus_node *parent, --- -2.4.3 - - -From 438544057353e788f908b55819661678c79cc776 Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Sat, 18 Apr 2015 12:39:51 +0200 -Subject: [PATCH 037/132] kdbus: reduce scope of handle locking - -A kdbus handle is used to create objects in the kdbus hierarchy. During -open(), we do not have enough information to know how to setup the object. -Therefore, we provide setup ioctls, which allow user-space to pass in -parameters and options how the to-be-created object should behave. Once -setup is done, we allow user-space to use ioctls to operate on that newly -created object. - -It is important to notice: - 1) Only one setup ioctl can ever be called on a handle. You cannot call - multiple, different setup ioctls on the same handle. - 2) A setup ioctl can only be called once, if it succeeded. If it failed, - it must not modify the handle in any way. If it succeeded, no further - setup ioctl can be issued. - 3) After a setup ioctl is done, the handle is constant and must not be - modified in any way. - -So far, we used a write-lock around all setup ioctls, and a read-lock -around everything else. The handle setup-indicator (the type field) can -only be set under the write-lock. Whenever you access the handle under a -read-lock, you must verify it was set before, otherwise, you must bail out -as the handle was not initialized, yet. - -This has the downside that we need a read-lock on all operations on the -handle. For performance reasons, we should avoid that. This patch turns -the rwlock into a mutex and removes the read-side lock from all paths. It -relies on the 3 behaviors described above. - -With this patch, the mutex is only taken around setup ioctls. Furthermore, -the setup-indicator (the type field) is only ever set if the mutex is -held. The mutex guarantees that multiple setup ioctls cannot race, and -also, that only one setup ioctl will ever succeed. If a setup ioctl is -called after setup was already finished, we do not touch the handle at all -and immediately fail. - -Furthermore, all other operations (non-setup operations) can only be -called once setup is done. Therefore, we must synchronize them with any -racing setup, otherwise, they might access the handle which is currently -modified by setup. -We protect from this race by setting the setup-indicator (the type field) -_last_, and issue a write-barrier before setting it. Once it is set, we -never modify the handle ever again; it is constant from now on until -file-release. -Hence, on the read-side we simply read the type field and issue a -read-barrier afterwards. _Iff_ the type field was not set, yet, we must -not access the handle in any way, but bail out immediately. Setup was not -done, yet. But if the type field was set, the read-barrier pairs with the -write-barrier during setup. All member fields of the handle object are -guaranteed to be accessible by us, as the type-field is always the last -field that is written. - -With this in place, we reduce the locking-overhead of all non-setup ioctls -to a read-barrier, instead of a read-side lock. And in combination with -the follow-up that removes the active-refs from kdbus_handle_poll(), we're -now lock-free in ->poll and ->mmap callbacks. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Acked-by: Daniel Mack <daniel@zonque.org> ---- - ipc/kdbus/handle.c | 110 ++++++++++++++++++++++++++++++++++++++++------------- - 1 file changed, 83 insertions(+), 27 deletions(-) - -diff --git a/ipc/kdbus/handle.c b/ipc/kdbus/handle.c -index 3f5d8085a297..a3e01383a6f6 100644 ---- a/ipc/kdbus/handle.c -+++ b/ipc/kdbus/handle.c -@@ -18,6 +18,7 @@ - #include <linux/init.h> - #include <linux/kdev_t.h> - #include <linux/module.h> -+#include <linux/mutex.h> - #include <linux/poll.h> - #include <linux/rwsem.h> - #include <linux/sched.h> -@@ -229,7 +230,7 @@ enum kdbus_handle_type { - - /** - * struct kdbus_handle - handle to the kdbus system -- * @rwlock: handle lock -+ * @lock: handle lock - * @type: type of this handle (KDBUS_HANDLE_*) - * @bus_owner: bus this handle owns - * @ep_owner: endpoint this handle owns -@@ -237,7 +238,7 @@ enum kdbus_handle_type { - * @privileged: Flag to mark a handle as privileged - */ - struct kdbus_handle { -- struct rw_semaphore rwlock; -+ struct mutex lock; - - enum kdbus_handle_type type; - union { -@@ -265,7 +266,7 @@ static int kdbus_handle_open(struct inode *inode, struct file *file) - goto exit; - } - -- init_rwsem(&handle->rwlock); -+ mutex_init(&handle->lock); - handle->type = KDBUS_HANDLE_NONE; - - if (node->type == KDBUS_NODE_ENDPOINT) { -@@ -355,8 +356,8 @@ static long kdbus_handle_ioctl_control(struct file *file, unsigned int cmd, - break; - } - -- handle->type = KDBUS_HANDLE_BUS_OWNER; - handle->bus_owner = bus; -+ ret = KDBUS_HANDLE_BUS_OWNER; - break; - } - -@@ -396,8 +397,8 @@ static long kdbus_handle_ioctl_ep(struct file *file, unsigned int cmd, - break; - } - -- handle->type = KDBUS_HANDLE_EP_OWNER; - handle->ep_owner = ep; -+ ret = KDBUS_HANDLE_EP_OWNER; - break; - - case KDBUS_CMD_HELLO: -@@ -407,8 +408,8 @@ static long kdbus_handle_ioctl_ep(struct file *file, unsigned int cmd, - break; - } - -- handle->type = KDBUS_HANDLE_CONNECTED; - handle->conn = conn; -+ ret = KDBUS_HANDLE_CONNECTED; - break; - - default: -@@ -522,19 +523,41 @@ static long kdbus_handle_ioctl(struct file *file, unsigned int cmd, - case KDBUS_CMD_BUS_MAKE: - case KDBUS_CMD_ENDPOINT_MAKE: - case KDBUS_CMD_HELLO: -- /* bail out early if already typed */ -- if (handle->type != KDBUS_HANDLE_NONE) -- break; -- -- down_write(&handle->rwlock); -+ mutex_lock(&handle->lock); - if (handle->type == KDBUS_HANDLE_NONE) { - if (node->type == KDBUS_NODE_CONTROL) - ret = kdbus_handle_ioctl_control(file, cmd, - argp); - else if (node->type == KDBUS_NODE_ENDPOINT) - ret = kdbus_handle_ioctl_ep(file, cmd, argp); -+ -+ if (ret > 0) { -+ /* -+ * The data given via open() is not sufficient -+ * to setup a kdbus handle. Hence, we require -+ * the user to perform a setup ioctl. This setup -+ * can only be performed once and defines the -+ * type of the handle. The different setup -+ * ioctls are locked against each other so they -+ * cannot race. Once the handle type is set, -+ * the type-dependent ioctls are enabled. To -+ * improve performance, we don't lock those via -+ * handle->lock. Instead, we issue a -+ * write-barrier before performing the -+ * type-change, which pairs with smp_rmb() in -+ * all handlers that access the type field. This -+ * guarantees the handle is fully setup, if -+ * handle->type is set. If handle->type is -+ * unset, you must not make any assumptions -+ * without taking handle->lock. -+ * Note that handle->type is only set once. It -+ * will never change afterwards. -+ */ -+ smp_wmb(); -+ handle->type = ret; -+ } - } -- up_write(&handle->rwlock); -+ mutex_unlock(&handle->lock); - break; - - case KDBUS_CMD_ENDPOINT_UPDATE: -@@ -549,14 +572,30 @@ static long kdbus_handle_ioctl(struct file *file, unsigned int cmd, - case KDBUS_CMD_MATCH_REMOVE: - case KDBUS_CMD_SEND: - case KDBUS_CMD_RECV: -- case KDBUS_CMD_FREE: -- down_read(&handle->rwlock); -- if (handle->type == KDBUS_HANDLE_EP_OWNER) -+ case KDBUS_CMD_FREE: { -+ enum kdbus_handle_type type; -+ -+ /* -+ * This read-barrier pairs with smp_wmb() of the handle setup. -+ * it guarantees the handle is fully written, in case the -+ * type has been set. It allows us to access the handle without -+ * taking handle->lock, given the guarantee that the type is -+ * only ever set once, and stays constant afterwards. -+ * Furthermore, the handle object itself is not modified in any -+ * way after the type is set. That is, the type-field is the -+ * last field that is written on any handle. If it has not been -+ * set, we must not access the handle here. -+ */ -+ type = handle->type; -+ smp_rmb(); -+ -+ if (type == KDBUS_HANDLE_EP_OWNER) - ret = kdbus_handle_ioctl_ep_owner(file, cmd, argp); -- else if (handle->type == KDBUS_HANDLE_CONNECTED) -+ else if (type == KDBUS_HANDLE_CONNECTED) - ret = kdbus_handle_ioctl_connected(file, cmd, argp); -- up_read(&handle->rwlock); -+ - break; -+ } - default: - ret = -ENOTTY; - break; -@@ -569,16 +608,23 @@ static unsigned int kdbus_handle_poll(struct file *file, - struct poll_table_struct *wait) - { - struct kdbus_handle *handle = file->private_data; -+ enum kdbus_handle_type type; - unsigned int mask = POLLOUT | POLLWRNORM; - int ret; - -+ /* -+ * This pairs with smp_wmb() during handle setup. It guarantees that -+ * _iff_ the handle type is set, handle->conn is valid. Furthermore, -+ * _iff_ the type is set, the handle object is constant and never -+ * changed again. If it's not set, we must not access the handle but -+ * bail out. We also must assume no setup has taken place, yet. -+ */ -+ type = handle->type; -+ smp_rmb(); -+ - /* Only a connected endpoint can read/write data */ -- down_read(&handle->rwlock); -- if (handle->type != KDBUS_HANDLE_CONNECTED) { -- up_read(&handle->rwlock); -+ if (type != KDBUS_HANDLE_CONNECTED) - return POLLERR | POLLHUP; -- } -- up_read(&handle->rwlock); - - ret = kdbus_conn_acquire(handle->conn); - if (ret < 0) -@@ -598,13 +644,23 @@ static unsigned int kdbus_handle_poll(struct file *file, - static int kdbus_handle_mmap(struct file *file, struct vm_area_struct *vma) - { - struct kdbus_handle *handle = file->private_data; -+ enum kdbus_handle_type type; - int ret = -EBADFD; - -- if (down_read_trylock(&handle->rwlock)) { -- if (handle->type == KDBUS_HANDLE_CONNECTED) -- ret = kdbus_pool_mmap(handle->conn->pool, vma); -- up_read(&handle->rwlock); -- } -+ /* -+ * This pairs with smp_wmb() during handle setup. It guarantees that -+ * _iff_ the handle type is set, handle->conn is valid. Furthermore, -+ * _iff_ the type is set, the handle object is constant and never -+ * changed again. If it's not set, we must not access the handle but -+ * bail out. We also must assume no setup has taken place, yet. -+ */ -+ type = handle->type; -+ smp_rmb(); -+ -+ /* Only connected handles have a pool we can map */ -+ if (type == KDBUS_HANDLE_CONNECTED) -+ ret = kdbus_pool_mmap(handle->conn->pool, vma); -+ - return ret; - } - --- -2.4.3 - - -From 6422d0700f7fafd77c09d327c3df79f63de91b98 Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Sat, 18 Apr 2015 13:04:42 +0200 -Subject: [PATCH 038/132] kdbus: skip acquiring an active reference in poll() - -During poll(), we currently acquire an active reference to the connection -in question to verify it's still active. If it's not active, anymore, we -return POLLHUP. - -This works fine, but requires an atomic_inc() to acquire the active -reference. However, all we need is a guarantee that the connection is -active right now, and a guarantee we're called again once this changes. -This is as simple as adding the waitqueue first, then checking the -active-state afterwards. kdbus_conn_disconnect() guarantees to wake us up -_after_ deactivating the connection, thus providing the required barrier -implicitly (in case someone is actually polling / waiting on the -connection). - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Acked-by: Daniel Mack <daniel@zonque.org> ---- - ipc/kdbus/handle.c | 16 +++++++++------- - 1 file changed, 9 insertions(+), 7 deletions(-) - -diff --git a/ipc/kdbus/handle.c b/ipc/kdbus/handle.c -index a3e01383a6f6..6230c7ef4347 100644 ---- a/ipc/kdbus/handle.c -+++ b/ipc/kdbus/handle.c -@@ -610,7 +610,6 @@ static unsigned int kdbus_handle_poll(struct file *file, - struct kdbus_handle *handle = file->private_data; - enum kdbus_handle_type type; - unsigned int mask = POLLOUT | POLLWRNORM; -- int ret; - - /* - * This pairs with smp_wmb() during handle setup. It guarantees that -@@ -626,18 +625,21 @@ static unsigned int kdbus_handle_poll(struct file *file, - if (type != KDBUS_HANDLE_CONNECTED) - return POLLERR | POLLHUP; - -- ret = kdbus_conn_acquire(handle->conn); -- if (ret < 0) -- return POLLERR | POLLHUP; -- - poll_wait(file, &handle->conn->wait, wait); - -+ /* -+ * Verify the connection hasn't been deactivated _after_ adding the -+ * wait-queue. This guarantees, that if the connection is deactivated -+ * after we checked it, the waitqueue is signaled and we're called -+ * again. -+ */ -+ if (!kdbus_conn_active(handle->conn)) -+ return POLLERR | POLLHUP; -+ - if (!list_empty(&handle->conn->queue.msg_list) || - atomic_read(&handle->conn->lost_count) > 0) - mask |= POLLIN | POLLRDNORM; - -- kdbus_conn_release(handle->conn); -- - return mask; - } - --- -2.4.3 - - -From 60ffe50acb512c3e4d591efa3da90142aa46824a Mon Sep 17 00:00:00 2001 -From: Wei Yongjun <yongjun_wei@trendmicro.com.cn> -Date: Thu, 16 Apr 2015 21:07:18 +0800 -Subject: [PATCH 039/132] kdbus: remove unused linux/version.h include - -Remove <linux/version.h> include, it's not needed. - -Signed-off-by: Wei Yongjun <yongjun_wei@trendmicro.com.cn> -Acked-by: Daniel Mack <daniel@zonque.org> -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> ---- - ipc/kdbus/metadata.c | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/ipc/kdbus/metadata.c b/ipc/kdbus/metadata.c -index 3adc6c2c2e76..eeebfef11552 100644 ---- a/ipc/kdbus/metadata.c -+++ b/ipc/kdbus/metadata.c -@@ -29,7 +29,6 @@ - #include <linux/uidgid.h> - #include <linux/uio.h> - #include <linux/user_namespace.h> --#include <linux/version.h> - - #include "bus.h" - #include "connection.h" --- -2.4.3 - - -From 91d8de1b980c870542fadd0f7dbacb76b1387e71 Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Mon, 20 Apr 2015 10:53:35 +0200 -Subject: [PATCH 040/132] kdbus: optimize auxgroup collector - -current->creds can only be changed by 'current'. That is, as long as we -only access our own credentials, we can be sure it does not change. Hence, -there is no need to ref cred->group_info if all we do is copy its content. - -This avoids touching shared cachelines when collecting auxgroups. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Acked-by: Daniel Mack <daniel@zonque.org> ---- - ipc/kdbus/metadata.c | 10 ++++------ - 1 file changed, 4 insertions(+), 6 deletions(-) - -diff --git a/ipc/kdbus/metadata.c b/ipc/kdbus/metadata.c -index eeebfef11552..174436f0aa01 100644 ---- a/ipc/kdbus/metadata.c -+++ b/ipc/kdbus/metadata.c -@@ -245,25 +245,23 @@ static void kdbus_meta_proc_collect_pids(struct kdbus_meta_proc *mp) - - static int kdbus_meta_proc_collect_auxgroups(struct kdbus_meta_proc *mp) - { -- struct group_info *info; -+ const struct group_info *info; - size_t i; - -- info = get_current_groups(); -+ /* no need to lock/ref, current creds cannot change */ -+ info = current_cred()->group_info; - - if (info->ngroups > 0) { - mp->auxgrps = kmalloc_array(info->ngroups, sizeof(kgid_t), - GFP_KERNEL); -- if (!mp->auxgrps) { -- put_group_info(info); -+ if (!mp->auxgrps) - return -ENOMEM; -- } - - for (i = 0; i < info->ngroups; i++) - mp->auxgrps[i] = GROUP_AT(info, i); - } - - mp->n_auxgrps = info->ngroups; -- put_group_info(info); - mp->valid |= KDBUS_ATTACH_AUXGROUPS; - - return 0; --- -2.4.3 - - -From 9183e0fc8167933cd2870dadeac50d449b66733d Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Wed, 22 Apr 2015 19:31:50 +0200 -Subject: [PATCH 041/132] kdbus: drop obsolete WARN_ON - -entry->user is never set to an error-code. Drop the obsolete WARN_ON which -is a leftover from before the quota rework. - -Reported-by: Dan Carpenter <dan.carpenter@oracle.com> -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Acked-by: Daniel Mack <daniel@zonque.org> ---- - ipc/kdbus/queue.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ipc/kdbus/queue.c b/ipc/kdbus/queue.c -index a449464a3975..25bb3ad66b98 100644 ---- a/ipc/kdbus/queue.c -+++ b/ipc/kdbus/queue.c -@@ -637,7 +637,7 @@ int kdbus_queue_entry_move(struct kdbus_queue_entry *e, - lockdep_assert_held(&src->lock); - lockdep_assert_held(&dst->lock); - -- if (WARN_ON(IS_ERR(e->user)) || WARN_ON(list_empty(&e->entry))) -+ if (WARN_ON(list_empty(&e->entry))) - return -EINVAL; - if (src == dst) - return 0; --- -2.4.3 - - -From 6382dfde58617e682900ed45ce4d0fd888921a42 Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Mon, 20 Apr 2015 16:20:59 +0200 -Subject: [PATCH 042/132] kdbus: copy small ioctl payloads to stack - -Right now, we use memdup_user() on all ioctl payloads. However, most of -the time an ioctl payload is pretty small. 512 bytes on stack seem -reasonable (similar to what poll() does) to speed up small ioctl payloads. -Add a command-buffer to kdbus_args and use it instead of kmalloc() for -reasonably small payloads. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Acked-by: Daniel Mack <daniel@zonque.org> ---- - ipc/kdbus/handle.c | 30 ++++++++++++++++++++++++++---- - ipc/kdbus/handle.h | 5 +++++ - ipc/kdbus/util.c | 45 --------------------------------------------- - ipc/kdbus/util.h | 1 - - 4 files changed, 31 insertions(+), 50 deletions(-) - -diff --git a/ipc/kdbus/handle.c b/ipc/kdbus/handle.c -index 6230c7ef4347..07527990a051 100644 ---- a/ipc/kdbus/handle.c -+++ b/ipc/kdbus/handle.c -@@ -146,11 +146,32 @@ static int kdbus_args_negotiate(struct kdbus_args *args) - int __kdbus_args_parse(struct kdbus_args *args, void __user *argp, - size_t type_size, size_t items_offset, void **out) - { -+ u64 user_size; - int ret, i; - -- args->cmd = kdbus_memdup_user(argp, type_size, KDBUS_CMD_MAX_SIZE); -- if (IS_ERR(args->cmd)) -- return PTR_ERR(args->cmd); -+ ret = kdbus_copy_from_user(&user_size, argp, sizeof(user_size)); -+ if (ret < 0) -+ return ret; -+ -+ if (user_size < type_size) -+ return -EINVAL; -+ if (user_size > KDBUS_CMD_MAX_SIZE) -+ return -EMSGSIZE; -+ -+ if (user_size <= sizeof(args->cmd_buf)) { -+ if (copy_from_user(args->cmd_buf, argp, user_size)) -+ return -EFAULT; -+ args->cmd = (void*)args->cmd_buf; -+ } else { -+ args->cmd = memdup_user(argp, user_size); -+ if (IS_ERR(args->cmd)) -+ return PTR_ERR(args->cmd); -+ } -+ -+ if (args->cmd->size != user_size) { -+ ret = -EINVAL; -+ goto error; -+ } - - args->cmd->return_flags = 0; - args->user = argp; -@@ -207,7 +228,8 @@ int kdbus_args_clear(struct kdbus_args *args, int ret) - if (put_user(args->cmd->return_flags, - &args->user->return_flags)) - ret = -EFAULT; -- kfree(args->cmd); -+ if (args->cmd != (void*)args->cmd_buf) -+ kfree(args->cmd); - args->cmd = NULL; - } - -diff --git a/ipc/kdbus/handle.h b/ipc/kdbus/handle.h -index 93a372d554a2..13c59d975728 100644 ---- a/ipc/kdbus/handle.h -+++ b/ipc/kdbus/handle.h -@@ -45,6 +45,7 @@ struct kdbus_arg { - * @argv: array of items this command supports - * @user: set by parser to user-space location of current command - * @cmd: set by parser to kernel copy of command payload -+ * @cmd_buf: 512 bytes inline buf to avoid kmalloc() on small cmds - * @items: points to item array in @cmd - * @items_size: size of @items in bytes - * -@@ -52,6 +53,9 @@ struct kdbus_arg { - * The ioctl handler has to pre-fill the flags and allowed items before passing - * the object to kdbus_args_parse(). The parser will copy the command payload - * into kernel-space and verify the correctness of the data. -+ * -+ * We use a 512 bytes buffer for small command payloads, to be allocated on -+ * stack on syscall entrance. - */ - struct kdbus_args { - u64 allowed_flags; -@@ -60,6 +64,7 @@ struct kdbus_args { - - struct kdbus_cmd __user *user; - struct kdbus_cmd *cmd; -+ u8 cmd_buf[512]; - - struct kdbus_item *items; - size_t items_size; -diff --git a/ipc/kdbus/util.c b/ipc/kdbus/util.c -index eaa806a27997..72b188330896 100644 ---- a/ipc/kdbus/util.c -+++ b/ipc/kdbus/util.c -@@ -50,51 +50,6 @@ int kdbus_copy_from_user(void *dest, void __user *user_ptr, size_t size) - } - - /** -- * kdbus_memdup_user() - copy dynamically sized object from user-space -- * @user_ptr: user-provided source buffer -- * @sz_min: minimum object size -- * @sz_max: maximum object size -- * -- * This copies a dynamically sized object from user-space into kernel-space. We -- * require the object to have a 64bit size field at offset 0. We read it out -- * first, allocate a suitably sized buffer and then copy all data. -- * -- * The @sz_min and @sz_max parameters define possible min and max object sizes -- * so user-space cannot trigger un-bound kernel-space allocations. -- * -- * The same alignment-restrictions as described in kdbus_copy_from_user() apply. -- * -- * Return: pointer to dynamically allocated copy, or ERR_PTR() on failure. -- */ --void *kdbus_memdup_user(void __user *user_ptr, size_t sz_min, size_t sz_max) --{ -- void *ptr; -- u64 size; -- int ret; -- -- ret = kdbus_copy_from_user(&size, user_ptr, sizeof(size)); -- if (ret < 0) -- return ERR_PTR(ret); -- -- if (size < sz_min) -- return ERR_PTR(-EINVAL); -- -- if (size > sz_max) -- return ERR_PTR(-EMSGSIZE); -- -- ptr = memdup_user(user_ptr, size); -- if (IS_ERR(ptr)) -- return ptr; -- -- if (*(u64 *)ptr != size) { -- kfree(ptr); -- return ERR_PTR(-EINVAL); -- } -- -- return ptr; --} -- --/** - * kdbus_verify_uid_prefix() - verify UID prefix of a user-supplied name - * @name: user-supplied name to verify - * @user_ns: user-namespace to act in -diff --git a/ipc/kdbus/util.h b/ipc/kdbus/util.h -index 740b19880985..9fedf8ab41cd 100644 ---- a/ipc/kdbus/util.h -+++ b/ipc/kdbus/util.h -@@ -64,7 +64,6 @@ int kdbus_verify_uid_prefix(const char *name, struct user_namespace *user_ns, - int kdbus_sanitize_attach_flags(u64 flags, u64 *attach_flags); - - int kdbus_copy_from_user(void *dest, void __user *user_ptr, size_t size); --void *kdbus_memdup_user(void __user *user_ptr, size_t sz_min, size_t sz_max); - - struct kvec; - --- -2.4.3 - - -From 8fd53b89ea2e4044b8059f0535007fee48501b1b Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Fri, 22 May 2015 10:25:08 +0200 -Subject: [PATCH 043/132] kdbus: drop kdbus_meta_attach_mask modparam - -This parameter was introduced to mask out experimental metadata items. As -the discussion on metadata items has shifted, plans changed: Enable all -metadata items and drop the controversial items entirely. Lets not work -around differences of opinions, but figure them out. - -Also drop all the related kselftests infrastructure to make sure the tests -still run fine. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Acked-by: Daniel Mack <daniel@zonque.org> ---- - ipc/kdbus/main.c | 12 - - ipc/kdbus/metadata.c | 1 - - ipc/kdbus/metadata.h | 2 - - tools/testing/selftests/kdbus/Makefile | 1 - - tools/testing/selftests/kdbus/kdbus-test.c | 25 +- - tools/testing/selftests/kdbus/kdbus-test.h | 2 - - tools/testing/selftests/kdbus/test-attach-flags.c | 750 ---------------------- - tools/testing/selftests/kdbus/test-connection.c | 34 +- - 8 files changed, 13 insertions(+), 814 deletions(-) - delete mode 100644 tools/testing/selftests/kdbus/test-attach-flags.c - -diff --git a/ipc/kdbus/main.c b/ipc/kdbus/main.c -index f8eac78cace6..1ad4dc8dafa1 100644 ---- a/ipc/kdbus/main.c -+++ b/ipc/kdbus/main.c -@@ -15,7 +15,6 @@ - #include <linux/fs.h> - #include <linux/init.h> - #include <linux/module.h> --#include <linux/moduleparam.h> - - #include "util.h" - #include "fs.h" -@@ -79,17 +78,6 @@ - /* kdbus mount-point /sys/fs/kdbus */ - static struct kobject *kdbus_dir; - --/* global module option to apply a mask to exported metadata */ --unsigned long long kdbus_meta_attach_mask = KDBUS_ATTACH_TIMESTAMP | -- KDBUS_ATTACH_CREDS | -- KDBUS_ATTACH_PIDS | -- KDBUS_ATTACH_AUXGROUPS | -- KDBUS_ATTACH_NAMES | -- KDBUS_ATTACH_SECLABEL | -- KDBUS_ATTACH_CONN_DESCRIPTION; --MODULE_PARM_DESC(attach_flags_mask, "Attach-flags mask for exported metadata"); --module_param_named(attach_flags_mask, kdbus_meta_attach_mask, ullong, 0644); -- - static int __init kdbus_init(void) - { - int ret; -diff --git a/ipc/kdbus/metadata.c b/ipc/kdbus/metadata.c -index 174436f0aa01..b908b6314a00 100644 ---- a/ipc/kdbus/metadata.c -+++ b/ipc/kdbus/metadata.c -@@ -835,7 +835,6 @@ int kdbus_meta_export_prepare(struct kdbus_meta_proc *mp, - } - - *mask &= valid; -- *mask &= kdbus_meta_attach_mask; - - if (!*mask) - goto exit; -diff --git a/ipc/kdbus/metadata.h b/ipc/kdbus/metadata.h -index 42c942b34d2c..79b6ac31c8ad 100644 ---- a/ipc/kdbus/metadata.h -+++ b/ipc/kdbus/metadata.h -@@ -24,8 +24,6 @@ struct kdbus_pool_slice; - struct kdbus_meta_proc; - struct kdbus_meta_conn; - --extern unsigned long long kdbus_meta_attach_mask; -- - struct kdbus_meta_proc *kdbus_meta_proc_new(void); - struct kdbus_meta_proc *kdbus_meta_proc_ref(struct kdbus_meta_proc *mp); - struct kdbus_meta_proc *kdbus_meta_proc_unref(struct kdbus_meta_proc *mp); -diff --git a/tools/testing/selftests/kdbus/Makefile b/tools/testing/selftests/kdbus/Makefile -index de8242f9b00e..076f9f40566d 100644 ---- a/tools/testing/selftests/kdbus/Makefile -+++ b/tools/testing/selftests/kdbus/Makefile -@@ -11,7 +11,6 @@ OBJS= \ - kdbus-test.o \ - kdbus-test.o \ - test-activator.o \ -- test-attach-flags.o \ - test-benchmark.o \ - test-bus.o \ - test-chat.o \ -diff --git a/tools/testing/selftests/kdbus/kdbus-test.c b/tools/testing/selftests/kdbus/kdbus-test.c -index a43674ccdeb0..294e82a83ab6 100644 ---- a/tools/testing/selftests/kdbus/kdbus-test.c -+++ b/tools/testing/selftests/kdbus/kdbus-test.c -@@ -48,7 +48,6 @@ struct kdbus_test_args { - char *root; - char *test; - char *busname; -- char *mask_param_path; - }; - - static const struct kdbus_test tests[] = { -@@ -274,13 +273,6 @@ static const struct kdbus_test tests[] = { - .func = kdbus_test_benchmark_uds, - .flags = TEST_CREATE_BUS, - }, -- { -- /* Last test */ -- .name = "attach-flags", -- .desc = "attach flags mask", -- .func = kdbus_test_attach_flags, -- .flags = 0, -- }, - }; - - #define N_TESTS ((int) (sizeof(tests) / sizeof(tests[0]))) -@@ -323,7 +315,6 @@ static int test_prepare_env(const struct kdbus_test *t, - - env->root = args->root; - env->module = args->module; -- env->mask_param_path = args->mask_param_path; - - return 0; - } -@@ -754,8 +745,7 @@ int start_tests(struct kdbus_test_args *kdbus_args) - { - int ret; - bool namespaces; -- uint64_t kdbus_param_mask; -- static char fspath[4096], parampath[4096]; -+ static char fspath[4096]; - - namespaces = (kdbus_args->mntns || kdbus_args->pidns || - kdbus_args->userns); -@@ -791,19 +781,6 @@ int start_tests(struct kdbus_test_args *kdbus_args) - kdbus_args->root = fspath; - } - -- snprintf(parampath, sizeof(parampath), -- "/sys/module/%s/parameters/attach_flags_mask", -- kdbus_args->module); -- kdbus_args->mask_param_path = parampath; -- -- ret = kdbus_sysfs_get_parameter_mask(kdbus_args->mask_param_path, -- &kdbus_param_mask); -- if (ret < 0) -- return TEST_ERR; -- -- printf("# Starting tests with an attach_flags_mask=0x%llx\n", -- (unsigned long long)kdbus_param_mask); -- - /* Start tests */ - if (namespaces) - ret = run_tests_in_namespaces(kdbus_args); -diff --git a/tools/testing/selftests/kdbus/kdbus-test.h b/tools/testing/selftests/kdbus/kdbus-test.h -index 647331883763..a5c6ae81b81b 100644 ---- a/tools/testing/selftests/kdbus/kdbus-test.h -+++ b/tools/testing/selftests/kdbus/kdbus-test.h -@@ -5,7 +5,6 @@ struct kdbus_test_env { - char *buspath; - const char *root; - const char *module; -- const char *mask_param_path; - int control_fd; - struct kdbus_conn *conn; - }; -@@ -44,7 +43,6 @@ enum { - ASSERT_EXIT_VAL(cond, EXIT_FAILURE) - - int kdbus_test_activator(struct kdbus_test_env *env); --int kdbus_test_attach_flags(struct kdbus_test_env *env); - int kdbus_test_benchmark(struct kdbus_test_env *env); - int kdbus_test_benchmark_nomemfds(struct kdbus_test_env *env); - int kdbus_test_benchmark_uds(struct kdbus_test_env *env); -diff --git a/tools/testing/selftests/kdbus/test-attach-flags.c b/tools/testing/selftests/kdbus/test-attach-flags.c -deleted file mode 100644 -index deee7c332f25..000000000000 ---- a/tools/testing/selftests/kdbus/test-attach-flags.c -+++ /dev/null -@@ -1,750 +0,0 @@ --#include <stdio.h> --#include <string.h> --#include <stdlib.h> --#include <stdbool.h> --#include <stddef.h> --#include <fcntl.h> --#include <unistd.h> --#include <stdint.h> --#include <errno.h> --#include <assert.h> --#include <sys/capability.h> --#include <sys/mman.h> --#include <sys/stat.h> --#include <sys/types.h> --#include <linux/unistd.h> -- --#include "kdbus-api.h" --#include "kdbus-test.h" --#include "kdbus-util.h" --#include "kdbus-enum.h" -- --/* -- * Should be the sum of the currently supported and compiled-in -- * KDBUS_ITEMS_* that reflect KDBUS_ATTACH_* flags. -- */ --static unsigned int KDBUS_TEST_ITEMS_SUM = KDBUS_ATTACH_ITEMS_TYPE_SUM; -- --static struct kdbus_conn *__kdbus_hello(const char *path, uint64_t flags, -- uint64_t attach_flags_send, -- uint64_t attach_flags_recv) --{ -- struct kdbus_cmd_free cmd_free = {}; -- int ret, fd; -- struct kdbus_conn *conn; -- struct { -- struct kdbus_cmd_hello hello; -- -- struct { -- uint64_t size; -- uint64_t type; -- char str[16]; -- } conn_name; -- -- uint8_t extra_items[0]; -- } h; -- -- memset(&h, 0, sizeof(h)); -- -- kdbus_printf("-- opening bus connection %s\n", path); -- fd = open(path, O_RDWR|O_CLOEXEC); -- if (fd < 0) { -- kdbus_printf("--- error %d (%m)\n", fd); -- return NULL; -- } -- -- h.hello.flags = flags | KDBUS_HELLO_ACCEPT_FD; -- h.hello.attach_flags_send = attach_flags_send; -- h.hello.attach_flags_recv = attach_flags_recv; -- h.conn_name.type = KDBUS_ITEM_CONN_DESCRIPTION; -- strcpy(h.conn_name.str, "this-is-my-name"); -- h.conn_name.size = KDBUS_ITEM_HEADER_SIZE + strlen(h.conn_name.str) + 1; -- -- h.hello.size = sizeof(h); -- h.hello.pool_size = POOL_SIZE; -- -- ret = kdbus_cmd_hello(fd, (struct kdbus_cmd_hello *) &h.hello); -- if (ret < 0) { -- kdbus_printf("--- error when saying hello: %d (%m)\n", ret); -- return NULL; -- } -- -- kdbus_printf("-- New connection ID : %llu\n", -- (unsigned long long)h.hello.id); -- -- cmd_free.size = sizeof(cmd_free); -- cmd_free.offset = h.hello.offset; -- ret = kdbus_cmd_free(fd, &cmd_free); -- if (ret < 0) -- return NULL; -- -- conn = malloc(sizeof(*conn)); -- if (!conn) { -- kdbus_printf("unable to malloc()!?\n"); -- return NULL; -- } -- -- conn->buf = mmap(NULL, POOL_SIZE, PROT_READ, MAP_SHARED, fd, 0); -- if (conn->buf == MAP_FAILED) { -- ret = -errno; -- free(conn); -- close(fd); -- kdbus_printf("--- error mmap: %d (%m)\n", ret); -- return NULL; -- } -- -- conn->fd = fd; -- conn->id = h.hello.id; -- return conn; --} -- --static int kdbus_test_peers_creation(struct kdbus_test_env *env) --{ -- int ret; -- int control_fd; -- char *path; -- char *busname; -- char buspath[2048]; -- char control_path[2048]; -- uint64_t attach_flags_mask; -- struct kdbus_conn *conn; -- -- snprintf(control_path, sizeof(control_path), -- "%s/control", env->root); -- -- /* -- * Set kdbus system-wide mask to 0, this has nothing -- * to do with the following tests, bus and connection -- * creation nor connection update, but we do it so we are -- * sure that everything work as expected -- */ -- -- attach_flags_mask = 0; -- ret = kdbus_sysfs_set_parameter_mask(env->mask_param_path, -- attach_flags_mask); -- ASSERT_RETURN(ret == 0); -- -- -- /* -- * Create bus with a full set of ATTACH flags -- */ -- -- control_fd = open(control_path, O_RDWR); -- ASSERT_RETURN(control_fd >= 0); -- -- busname = unique_name("test-peers-creation-bus"); -- ASSERT_RETURN(busname); -- -- ret = kdbus_create_bus(control_fd, busname, _KDBUS_ATTACH_ALL, -- 0, &path); -- ASSERT_RETURN(ret == 0); -- -- snprintf(buspath, sizeof(buspath), "%s/%s/bus", env->root, path); -- -- /* -- * Create a connection with an empty send attach flags, or -- * with just KDBUS_ATTACH_CREDS, this should fail -- */ -- conn = __kdbus_hello(buspath, 0, 0, 0); -- ASSERT_RETURN(conn == NULL); -- ASSERT_RETURN(errno == ECONNREFUSED); -- -- conn = __kdbus_hello(buspath, 0, KDBUS_ATTACH_CREDS, -- _KDBUS_ATTACH_ALL); -- ASSERT_RETURN(conn == NULL); -- ASSERT_RETURN(errno == ECONNREFUSED); -- -- conn = __kdbus_hello(buspath, 0, _KDBUS_ATTACH_ALL, 0); -- ASSERT_RETURN(conn); -- -- /* Try to cut back some send attach flags */ -- ret = kdbus_conn_update_attach_flags(conn, -- KDBUS_ATTACH_CREDS| -- KDBUS_ATTACH_PIDS, -- _KDBUS_ATTACH_ALL); -- ASSERT_RETURN(ret == -EINVAL); -- -- ret = kdbus_conn_update_attach_flags(conn, -- _KDBUS_ATTACH_ALL, 0); -- ASSERT_RETURN(ret == 0); -- -- kdbus_conn_free(conn); -- free(path); -- free(busname); -- close(control_fd); -- -- -- /* Test a new bus with KDBUS_ATTACH_PIDS */ -- -- control_fd = open(control_path, O_RDWR); -- ASSERT_RETURN(control_fd >= 0); -- -- busname = unique_name("test-peer-flags-bus"); -- ASSERT_RETURN(busname); -- -- ret = kdbus_create_bus(control_fd, busname, KDBUS_ATTACH_PIDS, -- 0, &path); -- ASSERT_RETURN(ret == 0); -- -- snprintf(buspath, sizeof(buspath), "%s/%s/bus", env->root, path); -- -- /* -- * Create a connection with an empty send attach flags, or -- * all flags except KDBUS_ATTACH_PIDS -- */ -- conn = __kdbus_hello(buspath, 0, 0, 0); -- ASSERT_RETURN(conn == NULL); -- ASSERT_RETURN(errno == ECONNREFUSED); -- -- conn = __kdbus_hello(buspath, 0, -- _KDBUS_ATTACH_ALL & ~KDBUS_ATTACH_PIDS, -- _KDBUS_ATTACH_ALL); -- ASSERT_RETURN(conn == NULL); -- ASSERT_RETURN(errno == ECONNREFUSED); -- -- /* The following should succeed */ -- conn = __kdbus_hello(buspath, 0, KDBUS_ATTACH_PIDS, 0); -- ASSERT_RETURN(conn); -- kdbus_conn_free(conn); -- -- conn = __kdbus_hello(buspath, 0, _KDBUS_ATTACH_ALL, 0); -- ASSERT_RETURN(conn); -- -- ret = kdbus_conn_update_attach_flags(conn, -- _KDBUS_ATTACH_ALL & -- ~KDBUS_ATTACH_PIDS, -- _KDBUS_ATTACH_ALL); -- ASSERT_RETURN(ret == -EINVAL); -- -- ret = kdbus_conn_update_attach_flags(conn, 0, -- _KDBUS_ATTACH_ALL); -- ASSERT_RETURN(ret == -EINVAL); -- -- /* Now we want only KDBUS_ATTACH_PIDS */ -- ret = kdbus_conn_update_attach_flags(conn, -- KDBUS_ATTACH_PIDS, 0); -- ASSERT_RETURN(ret == 0); -- -- kdbus_conn_free(conn); -- free(path); -- free(busname); -- close(control_fd); -- -- -- /* -- * Create bus with 0 as ATTACH flags, the bus does not -- * require any attach flags -- */ -- -- control_fd = open(control_path, O_RDWR); -- ASSERT_RETURN(control_fd >= 0); -- -- busname = unique_name("test-peer-flags-bus"); -- ASSERT_RETURN(busname); -- -- ret = kdbus_create_bus(control_fd, busname, 0, 0, &path); -- ASSERT_RETURN(ret == 0); -- -- snprintf(buspath, sizeof(buspath), "%s/%s/bus", env->root, path); -- -- /* Bus is open it does not require any send attach flags */ -- conn = __kdbus_hello(buspath, 0, 0, 0); -- ASSERT_RETURN(conn); -- kdbus_conn_free(conn); -- -- conn = __kdbus_hello(buspath, 0, _KDBUS_ATTACH_ALL, 0); -- ASSERT_RETURN(conn); -- -- ret = kdbus_conn_update_attach_flags(conn, 0, 0); -- ASSERT_RETURN(ret == 0); -- -- ret = kdbus_conn_update_attach_flags(conn, KDBUS_ATTACH_CREDS, 0); -- ASSERT_RETURN(ret == 0); -- -- kdbus_conn_free(conn); -- free(path); -- free(busname); -- close(control_fd); -- -- return 0; --} -- --static int kdbus_test_peers_info(struct kdbus_test_env *env) --{ -- int ret; -- int control_fd; -- char *path; -- char *busname; -- unsigned int i = 0; -- uint64_t offset = 0; -- char buspath[2048]; -- char control_path[2048]; -- uint64_t attach_flags_mask; -- struct kdbus_item *item; -- struct kdbus_info *info; -- struct kdbus_conn *conn; -- struct kdbus_conn *reader; -- unsigned long long attach_count = 0; -- -- snprintf(control_path, sizeof(control_path), -- "%s/control", env->root); -- -- attach_flags_mask = 0; -- ret = kdbus_sysfs_set_parameter_mask(env->mask_param_path, -- attach_flags_mask); -- ASSERT_RETURN(ret == 0); -- -- control_fd = open(control_path, O_RDWR); -- ASSERT_RETURN(control_fd >= 0); -- -- busname = unique_name("test-peers-info-bus"); -- ASSERT_RETURN(busname); -- -- ret = kdbus_create_bus(control_fd, busname, _KDBUS_ATTACH_ALL, -- 0, &path); -- ASSERT_RETURN(ret == 0); -- -- snprintf(buspath, sizeof(buspath), "%s/%s/bus", env->root, path); -- -- /* Create connections with the appropriate flags */ -- conn = __kdbus_hello(buspath, 0, _KDBUS_ATTACH_ALL, 0); -- ASSERT_RETURN(conn); -- -- reader = __kdbus_hello(buspath, 0, _KDBUS_ATTACH_ALL, 0); -- ASSERT_RETURN(reader); -- -- ret = kdbus_conn_info(reader, conn->id, NULL, -- _KDBUS_ATTACH_ALL, &offset); -- ASSERT_RETURN(ret == 0); -- -- info = (struct kdbus_info *)(reader->buf + offset); -- ASSERT_RETURN(info->id == conn->id); -- -- /* all attach flags are masked, no metadata */ -- KDBUS_ITEM_FOREACH(item, info, items) -- i++; -- -- ASSERT_RETURN(i == 0); -- -- kdbus_free(reader, offset); -- -- /* Set the mask to _KDBUS_ATTACH_ANY */ -- attach_flags_mask = _KDBUS_ATTACH_ANY; -- ret = kdbus_sysfs_set_parameter_mask(env->mask_param_path, -- attach_flags_mask); -- ASSERT_RETURN(ret == 0); -- -- ret = kdbus_conn_info(reader, conn->id, NULL, -- _KDBUS_ATTACH_ALL, &offset); -- ASSERT_RETURN(ret == 0); -- -- info = (struct kdbus_info *)(reader->buf + offset); -- ASSERT_RETURN(info->id == conn->id); -- -- attach_count = 0; -- KDBUS_ITEM_FOREACH(item, info, items) -- attach_count += item->type; -- -- /* -- * All flags have been returned except for: -- * KDBUS_ITEM_TIMESTAMP and -- * KDBUS_ITEM_OWNED_NAME we do not own any name. -- */ -- ASSERT_RETURN(attach_count == (KDBUS_TEST_ITEMS_SUM - -- KDBUS_ITEM_OWNED_NAME - -- KDBUS_ITEM_TIMESTAMP)); -- -- kdbus_free(reader, offset); -- -- /* Request only OWNED names */ -- ret = kdbus_conn_info(reader, conn->id, NULL, -- KDBUS_ATTACH_NAMES, &offset); -- ASSERT_RETURN(ret == 0); -- -- info = (struct kdbus_info *)(reader->buf + offset); -- ASSERT_RETURN(info->id == conn->id); -- -- attach_count = 0; -- KDBUS_ITEM_FOREACH(item, info, items) -- attach_count += item->type; -- -- /* we should not get any metadata since we do not own names */ -- ASSERT_RETURN(attach_count == 0); -- -- kdbus_free(reader, offset); -- -- kdbus_conn_free(conn); -- kdbus_conn_free(reader); -- -- return 0; --} -- --/** -- * @kdbus_mask_param: kdbus module mask parameter (system-wide) -- * @requested_meta: The bus owner metadata that we want -- * @expected_items: The returned KDBUS_ITEMS_* sum. Used to -- * validate the returned metadata items -- */ --static int kdbus_cmp_bus_creator_metadata(struct kdbus_test_env *env, -- struct kdbus_conn *conn, -- uint64_t kdbus_mask_param, -- uint64_t requested_meta, -- unsigned long expected_items) --{ -- int ret; -- uint64_t offset = 0; -- struct kdbus_info *info; -- struct kdbus_item *item; -- unsigned long attach_count = 0; -- -- ret = kdbus_sysfs_set_parameter_mask(env->mask_param_path, -- kdbus_mask_param); -- ASSERT_RETURN(ret == 0); -- -- ret = kdbus_bus_creator_info(conn, requested_meta, &offset); -- ASSERT_RETURN(ret == 0); -- -- info = (struct kdbus_info *)(conn->buf + offset); -- -- KDBUS_ITEM_FOREACH(item, info, items) -- attach_count += item->type; -- -- ASSERT_RETURN(attach_count == expected_items); -- -- ret = kdbus_free(conn, offset); -- ASSERT_RETURN(ret == 0); -- -- return 0; --} -- --static int kdbus_test_bus_creator_info(struct kdbus_test_env *env) --{ -- int ret; -- int control_fd; -- char *path; -- char *busname; -- char buspath[2048]; -- char control_path[2048]; -- uint64_t attach_flags_mask; -- struct kdbus_conn *conn; -- unsigned long expected_items = 0; -- -- snprintf(control_path, sizeof(control_path), -- "%s/control", env->root); -- -- control_fd = open(control_path, O_RDWR); -- ASSERT_RETURN(control_fd >= 0); -- -- busname = unique_name("test-peers-info-bus"); -- ASSERT_RETURN(busname); -- -- /* -- * Now the bus allows us to see all its KDBUS_ATTACH_* -- * items -- */ -- ret = kdbus_create_bus(control_fd, busname, 0, -- _KDBUS_ATTACH_ALL, &path); -- ASSERT_RETURN(ret == 0); -- -- snprintf(buspath, sizeof(buspath), "%s/%s/bus", env->root, path); -- -- conn = __kdbus_hello(buspath, 0, 0, 0); -- ASSERT_RETURN(conn); -- -- /* -- * Start with a kdbus module mask set to _KDBUS_ATTACH_ANY -- */ -- attach_flags_mask = _KDBUS_ATTACH_ANY; -- -- /* -- * All flags will be returned except for: -- * KDBUS_ITEM_TIMESTAMP -- * KDBUS_ITEM_OWNED_NAME -- * KDBUS_ITEM_CONN_DESCRIPTION -- * -- * An extra flags is always returned KDBUS_ITEM_MAKE_NAME -- * which contains the bus name -- */ -- expected_items = KDBUS_TEST_ITEMS_SUM + KDBUS_ITEM_MAKE_NAME; -- expected_items -= KDBUS_ITEM_TIMESTAMP + -- KDBUS_ITEM_OWNED_NAME + -- KDBUS_ITEM_CONN_DESCRIPTION; -- ret = kdbus_cmp_bus_creator_metadata(env, conn, -- attach_flags_mask, -- _KDBUS_ATTACH_ALL, -- expected_items); -- ASSERT_RETURN(ret == 0); -- -- /* -- * We should have: -- * KDBUS_ITEM_PIDS + KDBUS_ITEM_CREDS + KDBUS_ITEM_MAKE_NAME -- */ -- expected_items = KDBUS_ITEM_PIDS + KDBUS_ITEM_CREDS + -- KDBUS_ITEM_MAKE_NAME; -- ret = kdbus_cmp_bus_creator_metadata(env, conn, -- attach_flags_mask, -- KDBUS_ATTACH_PIDS | -- KDBUS_ATTACH_CREDS, -- expected_items); -- ASSERT_RETURN(ret == 0); -- -- /* KDBUS_ITEM_MAKE_NAME is always returned */ -- expected_items = KDBUS_ITEM_MAKE_NAME; -- ret = kdbus_cmp_bus_creator_metadata(env, conn, -- attach_flags_mask, -- 0, expected_items); -- ASSERT_RETURN(ret == 0); -- -- /* -- * Restrict kdbus system-wide mask to KDBUS_ATTACH_PIDS -- */ -- -- attach_flags_mask = KDBUS_ATTACH_PIDS; -- -- /* -- * We should have: -- * KDBUS_ITEM_PIDS + KDBUS_ITEM_MAKE_NAME -- */ -- expected_items = KDBUS_ITEM_PIDS + KDBUS_ITEM_MAKE_NAME; -- ret = kdbus_cmp_bus_creator_metadata(env, conn, -- attach_flags_mask, -- _KDBUS_ATTACH_ALL, -- expected_items); -- ASSERT_RETURN(ret == 0); -- -- -- /* system-wide mask to 0 */ -- attach_flags_mask = 0; -- -- /* we should only see: KDBUS_ITEM_MAKE_NAME */ -- expected_items = KDBUS_ITEM_MAKE_NAME; -- ret = kdbus_cmp_bus_creator_metadata(env, conn, -- attach_flags_mask, -- _KDBUS_ATTACH_ALL, -- expected_items); -- ASSERT_RETURN(ret == 0); -- -- kdbus_conn_free(conn); -- free(path); -- free(busname); -- close(control_fd); -- -- -- /* -- * A new bus that hides all its owner metadata -- */ -- -- control_fd = open(control_path, O_RDWR); -- ASSERT_RETURN(control_fd >= 0); -- -- busname = unique_name("test-peers-info-bus"); -- ASSERT_RETURN(busname); -- -- ret = kdbus_create_bus(control_fd, busname, 0, 0, &path); -- ASSERT_RETURN(ret == 0); -- -- snprintf(buspath, sizeof(buspath), "%s/%s/bus", env->root, path); -- -- conn = __kdbus_hello(buspath, 0, 0, 0); -- ASSERT_RETURN(conn); -- -- /* -- * Start with a kdbus module mask set to _KDBUS_ATTACH_ANY -- */ -- attach_flags_mask = _KDBUS_ATTACH_ANY; -- -- /* -- * We only get the KDBUS_ITEM_MAKE_NAME -- */ -- expected_items = KDBUS_ITEM_MAKE_NAME; -- ret = kdbus_cmp_bus_creator_metadata(env, conn, -- attach_flags_mask, -- _KDBUS_ATTACH_ALL, -- expected_items); -- ASSERT_RETURN(ret == 0); -- -- /* -- * We still get only kdbus_ITEM_MAKE_NAME -- */ -- attach_flags_mask = 0; -- expected_items = KDBUS_ITEM_MAKE_NAME; -- ret = kdbus_cmp_bus_creator_metadata(env, conn, -- attach_flags_mask, -- _KDBUS_ATTACH_ALL, -- expected_items); -- ASSERT_RETURN(ret == 0); -- -- kdbus_conn_free(conn); -- free(path); -- free(busname); -- close(control_fd); -- -- -- /* -- * A new bus that shows only the PID and CREDS metadata -- * of the bus owner. -- */ -- control_fd = open(control_path, O_RDWR); -- ASSERT_RETURN(control_fd >= 0); -- -- busname = unique_name("test-peers-info-bus"); -- ASSERT_RETURN(busname); -- -- ret = kdbus_create_bus(control_fd, busname, 0, -- KDBUS_ATTACH_PIDS| -- KDBUS_ATTACH_CREDS, &path); -- ASSERT_RETURN(ret == 0); -- -- snprintf(buspath, sizeof(buspath), "%s/%s/bus", env->root, path); -- -- conn = __kdbus_hello(buspath, 0, 0, 0); -- ASSERT_RETURN(conn); -- -- /* -- * Start with a kdbus module mask set to _KDBUS_ATTACH_ANY -- */ -- attach_flags_mask = _KDBUS_ATTACH_ANY; -- -- /* -- * We should have: -- * KDBUS_ITEM_PIDS + KDBUS_ITEM_CREDS + KDBUS_ITEM_MAKE_NAME -- */ -- expected_items = KDBUS_ITEM_PIDS + KDBUS_ITEM_CREDS + -- KDBUS_ITEM_MAKE_NAME; -- ret = kdbus_cmp_bus_creator_metadata(env, conn, -- attach_flags_mask, -- _KDBUS_ATTACH_ALL, -- expected_items); -- ASSERT_RETURN(ret == 0); -- -- expected_items = KDBUS_ITEM_CREDS + KDBUS_ITEM_MAKE_NAME; -- ret = kdbus_cmp_bus_creator_metadata(env, conn, -- attach_flags_mask, -- KDBUS_ATTACH_CREDS, -- expected_items); -- ASSERT_RETURN(ret == 0); -- -- /* KDBUS_ITEM_MAKE_NAME is always returned */ -- expected_items = KDBUS_ITEM_MAKE_NAME; -- ret = kdbus_cmp_bus_creator_metadata(env, conn, -- attach_flags_mask, -- 0, expected_items); -- ASSERT_RETURN(ret == 0); -- -- /* -- * Restrict kdbus system-wide mask to KDBUS_ATTACH_PIDS -- */ -- -- attach_flags_mask = KDBUS_ATTACH_PIDS; -- /* -- * We should have: -- * KDBUS_ITEM_PIDS + KDBUS_ITEM_MAKE_NAME -- */ -- expected_items = KDBUS_ITEM_PIDS + KDBUS_ITEM_MAKE_NAME; -- ret = kdbus_cmp_bus_creator_metadata(env, conn, -- attach_flags_mask, -- _KDBUS_ATTACH_ALL, -- expected_items); -- ASSERT_RETURN(ret == 0); -- -- /* No KDBUS_ATTACH_CREDS */ -- expected_items = KDBUS_ITEM_MAKE_NAME; -- ret = kdbus_cmp_bus_creator_metadata(env, conn, -- attach_flags_mask, -- KDBUS_ATTACH_CREDS, -- expected_items); -- ASSERT_RETURN(ret == 0); -- -- /* system-wide mask to 0 */ -- attach_flags_mask = 0; -- -- /* we should only see: KDBUS_ITEM_MAKE_NAME */ -- expected_items = KDBUS_ITEM_MAKE_NAME; -- ret = kdbus_cmp_bus_creator_metadata(env, conn, -- attach_flags_mask, -- _KDBUS_ATTACH_ALL, -- expected_items); -- ASSERT_RETURN(ret == 0); -- -- -- kdbus_conn_free(conn); -- free(path); -- free(busname); -- close(control_fd); -- -- return 0; --} -- --int kdbus_test_attach_flags(struct kdbus_test_env *env) --{ -- int ret; -- uint64_t flags_mask; -- uint64_t old_kdbus_flags_mask; -- -- /* We need CAP_DAC_OVERRIDE to overwrite the kdbus mask */ -- ret = test_is_capable(CAP_DAC_OVERRIDE, -1); -- ASSERT_RETURN(ret >= 0); -- -- /* no enough privileges, SKIP test */ -- if (!ret) -- return TEST_SKIP; -- -- /* -- * We need to be able to write to -- * "/sys/module/kdbus/parameters/attach_flags_mask" -- * perhaps we are unprvileged/privileged in its userns -- */ -- ret = access(env->mask_param_path, W_OK); -- if (ret < 0) { -- kdbus_printf("--- access() '%s' failed: %d (%m)\n", -- env->mask_param_path, -errno); -- return TEST_SKIP; -- } -- -- ret = kdbus_sysfs_get_parameter_mask(env->mask_param_path, -- &old_kdbus_flags_mask); -- ASSERT_RETURN(ret == 0); -- -- /* setup the right KDBUS_TEST_ITEMS_SUM */ -- if (!config_auditsyscall_is_enabled()) -- KDBUS_TEST_ITEMS_SUM -= KDBUS_ITEM_AUDIT; -- -- if (!config_cgroups_is_enabled()) -- KDBUS_TEST_ITEMS_SUM -= KDBUS_ITEM_CGROUP; -- -- if (!config_security_is_enabled()) -- KDBUS_TEST_ITEMS_SUM -= KDBUS_ITEM_SECLABEL; -- -- /* -- * Test the connection creation attach flags -- */ -- ret = kdbus_test_peers_creation(env); -- /* Restore previous kdbus mask */ -- kdbus_sysfs_set_parameter_mask(env->mask_param_path, -- old_kdbus_flags_mask); -- ASSERT_RETURN(ret == 0); -- -- /* -- * Test the CONN_INFO attach flags -- */ -- ret = kdbus_test_peers_info(env); -- /* Restore previous kdbus mask */ -- kdbus_sysfs_set_parameter_mask(env->mask_param_path, -- old_kdbus_flags_mask); -- ASSERT_RETURN(ret == 0); -- -- /* -- * Test the Bus creator info and its attach flags -- */ -- ret = kdbus_test_bus_creator_info(env); -- /* Restore previous kdbus mask */ -- kdbus_sysfs_set_parameter_mask(env->mask_param_path, -- old_kdbus_flags_mask); -- ASSERT_RETURN(ret == 0); -- -- ret = kdbus_sysfs_get_parameter_mask(env->mask_param_path, -- &flags_mask); -- ASSERT_RETURN(ret == 0 && old_kdbus_flags_mask == flags_mask); -- -- return TEST_OK; --} -diff --git a/tools/testing/selftests/kdbus/test-connection.c b/tools/testing/selftests/kdbus/test-connection.c -index 5c2bf3511daa..e7c486621b04 100644 ---- a/tools/testing/selftests/kdbus/test-connection.c -+++ b/tools/testing/selftests/kdbus/test-connection.c -@@ -185,13 +185,10 @@ static int kdbus_fuzz_conn_info(struct kdbus_test_env *env, int capable) - int ret; - unsigned int cnt = 0; - uint64_t offset = 0; -- uint64_t kdbus_flags_mask; - struct kdbus_info *info; - struct kdbus_conn *conn; - struct kdbus_conn *privileged; - const struct kdbus_item *item; -- uint64_t valid_flags_set; -- uint64_t invalid_flags_set; - uint64_t valid_flags = KDBUS_ATTACH_NAMES | - KDBUS_ATTACH_CREDS | - KDBUS_ATTACH_PIDS | -@@ -227,13 +224,6 @@ static int kdbus_fuzz_conn_info(struct kdbus_test_env *env, int capable) - .ppid = getppid(), - }; - -- ret = kdbus_sysfs_get_parameter_mask(env->mask_param_path, -- &kdbus_flags_mask); -- ASSERT_RETURN(ret == 0); -- -- valid_flags_set = valid_flags & kdbus_flags_mask; -- invalid_flags_set = invalid_flags & kdbus_flags_mask; -- - ret = kdbus_conn_info(env->conn, env->conn->id, NULL, - valid_flags, &offset); - ASSERT_RETURN(ret == 0); -@@ -246,7 +236,7 @@ static int kdbus_fuzz_conn_info(struct kdbus_test_env *env, int capable) - ASSERT_RETURN(item == NULL); - - item = kdbus_get_item(info, KDBUS_ITEM_CONN_DESCRIPTION); -- if (valid_flags_set & KDBUS_ATTACH_CONN_DESCRIPTION) { -+ if (valid_flags & KDBUS_ATTACH_CONN_DESCRIPTION) { - ASSERT_RETURN(item); - } else { - ASSERT_RETURN(item == NULL); -@@ -271,7 +261,7 @@ static int kdbus_fuzz_conn_info(struct kdbus_test_env *env, int capable) - ASSERT_RETURN(item == NULL); - - cnt = kdbus_count_item(info, KDBUS_ITEM_CREDS); -- if (valid_flags_set & KDBUS_ATTACH_CREDS) { -+ if (valid_flags & KDBUS_ATTACH_CREDS) { - ASSERT_RETURN(cnt == 1); - - item = kdbus_get_item(info, KDBUS_ITEM_CREDS); -@@ -285,7 +275,7 @@ static int kdbus_fuzz_conn_info(struct kdbus_test_env *env, int capable) - } - - item = kdbus_get_item(info, KDBUS_ITEM_PIDS); -- if (valid_flags_set & KDBUS_ATTACH_PIDS) { -+ if (valid_flags & KDBUS_ATTACH_PIDS) { - ASSERT_RETURN(item); - - /* Compare item->pids with cached PIDs */ -@@ -312,7 +302,7 @@ static int kdbus_fuzz_conn_info(struct kdbus_test_env *env, int capable) - ASSERT_RETURN(info->id == conn->id); - - item = kdbus_get_item(info, KDBUS_ITEM_OWNED_NAME); -- if (valid_flags_set & KDBUS_ATTACH_NAMES) { -+ if (valid_flags & KDBUS_ATTACH_NAMES) { - ASSERT_RETURN(item && !strcmp(item->name.name, "com.example.a")); - } else { - ASSERT_RETURN(item == NULL); -@@ -340,14 +330,14 @@ static int kdbus_fuzz_conn_info(struct kdbus_test_env *env, int capable) - info = (struct kdbus_info *)(conn->buf + offset); - ASSERT_EXIT(info->id == conn->id); - -- if (valid_flags_set & KDBUS_ATTACH_NAMES) { -+ if (valid_flags & KDBUS_ATTACH_NAMES) { - item = kdbus_get_item(info, KDBUS_ITEM_OWNED_NAME); - ASSERT_EXIT(item && - strcmp(item->name.name, - "com.example.a") == 0); - } - -- if (valid_flags_set & KDBUS_ATTACH_CREDS) { -+ if (valid_flags & KDBUS_ATTACH_CREDS) { - item = kdbus_get_item(info, KDBUS_ITEM_CREDS); - ASSERT_EXIT(item); - -@@ -356,7 +346,7 @@ static int kdbus_fuzz_conn_info(struct kdbus_test_env *env, int capable) - sizeof(struct kdbus_creds)) == 0); - } - -- if (valid_flags_set & KDBUS_ATTACH_PIDS) { -+ if (valid_flags & KDBUS_ATTACH_PIDS) { - item = kdbus_get_item(info, KDBUS_ITEM_PIDS); - ASSERT_EXIT(item); - -@@ -385,7 +375,7 @@ static int kdbus_fuzz_conn_info(struct kdbus_test_env *env, int capable) - * it points to the cached creds. - */ - cnt = kdbus_count_item(info, KDBUS_ITEM_CREDS); -- if (invalid_flags_set & KDBUS_ATTACH_CREDS) { -+ if (invalid_flags & KDBUS_ATTACH_CREDS) { - ASSERT_EXIT(cnt == 1); - - item = kdbus_get_item(info, KDBUS_ITEM_CREDS); -@@ -398,7 +388,7 @@ static int kdbus_fuzz_conn_info(struct kdbus_test_env *env, int capable) - ASSERT_EXIT(cnt == 0); - } - -- if (invalid_flags_set & KDBUS_ATTACH_PIDS) { -+ if (invalid_flags & KDBUS_ATTACH_PIDS) { - cnt = kdbus_count_item(info, KDBUS_ITEM_PIDS); - ASSERT_EXIT(cnt == 1); - -@@ -411,14 +401,14 @@ static int kdbus_fuzz_conn_info(struct kdbus_test_env *env, int capable) - } - - cnt = kdbus_count_item(info, KDBUS_ITEM_CGROUP); -- if (invalid_flags_set & KDBUS_ATTACH_CGROUP) { -+ if (invalid_flags & KDBUS_ATTACH_CGROUP) { - ASSERT_EXIT(cnt == 1); - } else { - ASSERT_EXIT(cnt == 0); - } - - cnt = kdbus_count_item(info, KDBUS_ITEM_CAPS); -- if (invalid_flags_set & KDBUS_ATTACH_CAPS) { -+ if (invalid_flags & KDBUS_ATTACH_CAPS) { - ASSERT_EXIT(cnt == 1); - } else { - ASSERT_EXIT(cnt == 0); -@@ -442,7 +432,7 @@ continue_test: - ASSERT_RETURN(info->id == conn->id); - - cnt = kdbus_count_item(info, KDBUS_ITEM_OWNED_NAME); -- if (valid_flags_set & KDBUS_ATTACH_NAMES) { -+ if (valid_flags & KDBUS_ATTACH_NAMES) { - ASSERT_RETURN(cnt == 2); - } else { - ASSERT_RETURN(cnt == 0); --- -2.4.3 - - -From 9fe5eedbb73fb706cbbc6725e7d083e1fab06720 Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Tue, 26 May 2015 09:29:52 +0200 -Subject: [PATCH 044/132] kdbus: fix typo - -Fix "there" -> "their" typo. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Acked-by: Daniel Mack <daniel@zonque.org> ---- - ipc/kdbus/connection.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c -index ab476fa9ccca..fb2c6c67c4c1 100644 ---- a/ipc/kdbus/connection.c -+++ b/ipc/kdbus/connection.c -@@ -753,7 +753,7 @@ void kdbus_conn_quota_dec(struct kdbus_conn *c, struct kdbus_user *u, - * - * kdbus is reliable. That means, we try hard to never lose messages. However, - * memory is limited, so we cannot rely on transmissions to never fail. -- * Therefore, we use quota-limits to let callers know if there unicast message -+ * Therefore, we use quota-limits to let callers know if their unicast message - * cannot be transmitted to a peer. This works fine for unicasts, but for - * broadcasts we cannot make the caller handle the transmission failure. - * Instead, we must let the destination know that it couldn't receive a --- -2.4.3 - - -From d27c8057699d164648b7d8c1559fa6529998f89d Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Tue, 26 May 2015 09:30:14 +0200 -Subject: [PATCH 045/132] kdbus: forward ID notifications to everyone - -Even if you cannot SEE another peer (eg., if you're behind a private -endpoint), the other peer might be able to TALK to you. Therefore, you -might get messages from them. This works mostly fine, with one major -exception, that you cannot track the remote peer. You will not receive ID -notifications for it, thus, you don't get notified when they disconnect. -This is unforunate and breaks sandboxes kdbus peers. - -Fix this by forwarding ID notifications to everyone. Note that those -notifications don't carry _any_ useful information, besides the peer ID. -Therefore, even if you should not able to SEE a peer, you will now still -get ID notifications. This does not reveal any additional information on -the remote peer, besides its lifetime. Hence, it should be fine. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Acked-by: Daniel Mack <daniel@zonque.org> ---- - ipc/kdbus/connection.c | 8 +++----- - tools/testing/selftests/kdbus/test-endpoint.c | 13 ++++++++++++- - 2 files changed, 15 insertions(+), 6 deletions(-) - -diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c -index fb2c6c67c4c1..272b991f36f4 100644 ---- a/ipc/kdbus/connection.c -+++ b/ipc/kdbus/connection.c -@@ -1588,10 +1588,8 @@ bool kdbus_conn_policy_see_notification(struct kdbus_conn *conn, - * to a peer if, and only if, that peer can see the name this - * notification is for. - * -- * KDBUS_ITEM_ID_{ADD,REMOVE}: As new peers cannot have names, and all -- * names are dropped before a peer is removed, those notifications -- * cannot be seen on custom endpoints. Thus, we only pass them -- * through on default endpoints. -+ * KDBUS_ITEM_ID_{ADD,REMOVE}: Notifications for ID changes are -+ * broadcast to everyone, to allow tracking peers. - */ - - switch (kmsg->notify_type) { -@@ -1603,7 +1601,7 @@ bool kdbus_conn_policy_see_notification(struct kdbus_conn *conn, - - case KDBUS_ITEM_ID_ADD: - case KDBUS_ITEM_ID_REMOVE: -- return !conn->ep->user; -+ return true; - - default: - WARN(1, "Invalid type for notification broadcast: %llu\n", -diff --git a/tools/testing/selftests/kdbus/test-endpoint.c b/tools/testing/selftests/kdbus/test-endpoint.c -index dcc6ab91c4e6..34a7be49c482 100644 ---- a/tools/testing/selftests/kdbus/test-endpoint.c -+++ b/tools/testing/selftests/kdbus/test-endpoint.c -@@ -255,6 +255,13 @@ int kdbus_test_custom_endpoint(struct kdbus_test_env *env) - ep_conn = kdbus_hello(ep, 0, NULL, 0); - ASSERT_RETURN(ep_conn); - -+ /* Check that the reader got the IdAdd notification */ -+ ret = kdbus_msg_recv(reader, &msg, NULL); -+ ASSERT_RETURN(ret == 0); -+ ASSERT_RETURN(msg->items[0].type == KDBUS_ITEM_ID_ADD); -+ ASSERT_RETURN(msg->items[0].id_change.id == ep_conn->id); -+ kdbus_msg_free(msg); -+ - /* - * Add a name add match on the endpoint connection, acquire name from - * the unfiltered connection, and make sure the filtered connection -@@ -283,7 +290,7 @@ int kdbus_test_custom_endpoint(struct kdbus_test_env *env) - ret = kdbus_conn_info(ep_conn, 0x0fffffffffffffffULL, NULL, 0, NULL); - ASSERT_RETURN(ret == -ENXIO); - -- /* Check that the reader did not receive anything */ -+ /* Check that the reader did not receive the name notification */ - ret = kdbus_msg_recv(reader, NULL, NULL); - ASSERT_RETURN(ret == -EAGAIN); - -@@ -295,6 +302,10 @@ int kdbus_test_custom_endpoint(struct kdbus_test_env *env) - ret = kdbus_name_release(env->conn, name); - ASSERT_RETURN(ret == 0); - -+ /* Check that the reader did not receive the name notification */ -+ ret = kdbus_msg_recv(reader, NULL, NULL); -+ ASSERT_RETURN(ret == -EAGAIN); -+ - ret = update_endpoint(ep_fd, name); - ASSERT_RETURN(ret == 0); - --- -2.4.3 - - -From 60ed22097557fec418b846a38b17b9baa0fef86a Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Tue, 26 May 2015 09:59:02 +0200 -Subject: [PATCH 046/132] kdbus: provide helper to collect metadata - -Provide a new helper kdbus_kmsg_collect_metadata() which implements the -common task of collecting proc- and conn-metadata on a kmsg. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Acked-by: Daniel Mack <daniel@zonque.org> ---- - ipc/kdbus/bus.c | 24 +++--------------------- - ipc/kdbus/connection.c | 35 ++++------------------------------- - ipc/kdbus/message.c | 24 ++++++++++++++++++++++++ - ipc/kdbus/message.h | 2 ++ - 4 files changed, 33 insertions(+), 52 deletions(-) - -diff --git a/ipc/kdbus/bus.c b/ipc/kdbus/bus.c -index 9d0679eb59f6..9a0ecbc9df2f 100644 ---- a/ipc/kdbus/bus.c -+++ b/ipc/kdbus/bus.c -@@ -285,8 +285,6 @@ void kdbus_bus_broadcast(struct kdbus_bus *bus, - continue; - - if (conn_src) { -- u64 attach_flags; -- - /* - * Anyone can send broadcasts, as they have no - * destination. But a receiver needs TALK access to -@@ -295,19 +293,12 @@ void kdbus_bus_broadcast(struct kdbus_bus *bus, - if (!kdbus_conn_policy_talk(conn_dst, NULL, conn_src)) - continue; - -- attach_flags = kdbus_meta_calc_attach_flags(conn_src, -- conn_dst); -- - /* - * Keep sending messages even if we cannot acquire the - * requested metadata. It's up to the receiver to drop - * messages that lack expected metadata. - */ -- if (!conn_src->faked_meta) -- kdbus_meta_proc_collect(kmsg->proc_meta, -- attach_flags); -- kdbus_meta_conn_collect(kmsg->conn_meta, kmsg, conn_src, -- attach_flags); -+ kdbus_kmsg_collect_metadata(kmsg, conn_src, conn_dst); - } else { - /* - * Check if there is a policy db that prevents the -@@ -359,17 +350,8 @@ void kdbus_bus_eavesdrop(struct kdbus_bus *bus, - * availability, anyway. So it's still better to send messages - * that lack data, than to skip it entirely. - */ -- if (conn_src) { -- u64 attach_flags; -- -- attach_flags = kdbus_meta_calc_attach_flags(conn_src, -- conn_dst); -- if (!conn_src->faked_meta) -- kdbus_meta_proc_collect(kmsg->proc_meta, -- attach_flags); -- kdbus_meta_conn_collect(kmsg->conn_meta, kmsg, conn_src, -- attach_flags); -- } -+ if (conn_src) -+ kdbus_kmsg_collect_metadata(kmsg, conn_src, conn_dst); - - ret = kdbus_conn_entry_insert(conn_src, conn_dst, kmsg, NULL); - if (ret < 0) -diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c -index 272b991f36f4..cbfbf3847c24 100644 ---- a/ipc/kdbus/connection.c -+++ b/ipc/kdbus/connection.c -@@ -1098,7 +1098,6 @@ static int kdbus_conn_reply(struct kdbus_conn *src, struct kdbus_kmsg *kmsg) - struct kdbus_reply *reply, *wake = NULL; - struct kdbus_conn *dst = NULL; - struct kdbus_bus *bus = src->ep->bus; -- u64 attach; - int ret; - - if (WARN_ON(kmsg->msg.dst_id == KDBUS_DST_ID_BROADCAST) || -@@ -1131,15 +1130,7 @@ static int kdbus_conn_reply(struct kdbus_conn *src, struct kdbus_kmsg *kmsg) - - /* attach metadata */ - -- attach = kdbus_meta_calc_attach_flags(src, dst); -- -- if (!src->faked_meta) { -- ret = kdbus_meta_proc_collect(kmsg->proc_meta, attach); -- if (ret < 0) -- goto exit; -- } -- -- ret = kdbus_meta_conn_collect(kmsg->conn_meta, kmsg, src, attach); -+ ret = kdbus_kmsg_collect_metadata(kmsg, src, dst); - if (ret < 0) - goto exit; - -@@ -1167,7 +1158,6 @@ static struct kdbus_reply *kdbus_conn_call(struct kdbus_conn *src, - struct kdbus_reply *wait = NULL; - struct kdbus_conn *dst = NULL; - struct kdbus_bus *bus = src->ep->bus; -- u64 attach; - int ret; - - if (WARN_ON(kmsg->msg.dst_id == KDBUS_DST_ID_BROADCAST) || -@@ -1218,15 +1208,7 @@ static struct kdbus_reply *kdbus_conn_call(struct kdbus_conn *src, - - /* attach metadata */ - -- attach = kdbus_meta_calc_attach_flags(src, dst); -- -- if (!src->faked_meta) { -- ret = kdbus_meta_proc_collect(kmsg->proc_meta, attach); -- if (ret < 0) -- goto exit; -- } -- -- ret = kdbus_meta_conn_collect(kmsg->conn_meta, kmsg, src, attach); -+ ret = kdbus_kmsg_collect_metadata(kmsg, src, dst); - if (ret < 0) - goto exit; - -@@ -1257,7 +1239,6 @@ static int kdbus_conn_unicast(struct kdbus_conn *src, struct kdbus_kmsg *kmsg) - struct kdbus_conn *dst = NULL; - struct kdbus_bus *bus = src->ep->bus; - bool is_signal = (kmsg->msg.flags & KDBUS_MSG_SIGNAL); -- u64 attach; - int ret = 0; - - if (WARN_ON(kmsg->msg.dst_id == KDBUS_DST_ID_BROADCAST) || -@@ -1296,16 +1277,8 @@ static int kdbus_conn_unicast(struct kdbus_conn *src, struct kdbus_kmsg *kmsg) - - /* attach metadata */ - -- attach = kdbus_meta_calc_attach_flags(src, dst); -- -- if (!src->faked_meta) { -- ret = kdbus_meta_proc_collect(kmsg->proc_meta, attach); -- if (ret < 0 && !is_signal) -- goto exit; -- } -- -- ret = kdbus_meta_conn_collect(kmsg->conn_meta, kmsg, src, attach); -- if (ret < 0 && !is_signal) -+ ret = kdbus_kmsg_collect_metadata(kmsg, src, dst); -+ if (ret < 0) - goto exit; - - /* send message */ -diff --git a/ipc/kdbus/message.c b/ipc/kdbus/message.c -index 80960756a329..066e816dfdea 100644 ---- a/ipc/kdbus/message.c -+++ b/ipc/kdbus/message.c -@@ -614,3 +614,27 @@ exit_free: - kdbus_kmsg_free(m); - return ERR_PTR(ret); - } -+ -+/** -+ * kdbus_kmsg_collect_metadata() - collect metadata -+ * @kmsg: message to collect metadata on -+ * @src: source connection of message -+ * @dst: destination connection of message -+ * -+ * Return: 0 on success, negative error code on failure. -+ */ -+int kdbus_kmsg_collect_metadata(struct kdbus_kmsg *kmsg, struct kdbus_conn *src, -+ struct kdbus_conn *dst) -+{ -+ u64 attach; -+ int ret; -+ -+ attach = kdbus_meta_calc_attach_flags(src, dst); -+ if (!src->faked_meta) { -+ ret = kdbus_meta_proc_collect(kmsg->proc_meta, attach); -+ if (ret < 0) -+ return ret; -+ } -+ -+ return kdbus_meta_conn_collect(kmsg->conn_meta, kmsg, src, attach); -+} -diff --git a/ipc/kdbus/message.h b/ipc/kdbus/message.h -index af4775850235..cdaa65c4e6ae 100644 ---- a/ipc/kdbus/message.h -+++ b/ipc/kdbus/message.h -@@ -129,5 +129,7 @@ struct kdbus_kmsg *kdbus_kmsg_new(struct kdbus_bus *bus, size_t extra_size); - struct kdbus_kmsg *kdbus_kmsg_new_from_cmd(struct kdbus_conn *conn, - struct kdbus_cmd_send *cmd_send); - void kdbus_kmsg_free(struct kdbus_kmsg *kmsg); -+int kdbus_kmsg_collect_metadata(struct kdbus_kmsg *kmsg, struct kdbus_conn *src, -+ struct kdbus_conn *dst); - - #endif --- -2.4.3 - - -From 1cbe6696fa1eefd1adea66aa1fef378bc8b23cc4 Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Tue, 26 May 2015 10:01:37 +0200 -Subject: [PATCH 047/132] kdbus: make metadata on broadcasts reliable - -If we cannot collect metadata, this is a serious error. Don't try to -continue sending a message, but immediately bail out and tell the receiver -that we dropped it. Otherwise, the receiver cannot rely on metadata to be -present and might assume it's a faked connection. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Acked-by: Daniel Mack <daniel@zonque.org> ---- - ipc/kdbus/bus.c | 28 ++++++++++++++-------------- - 1 file changed, 14 insertions(+), 14 deletions(-) - -diff --git a/ipc/kdbus/bus.c b/ipc/kdbus/bus.c -index 9a0ecbc9df2f..d5475961b896 100644 ---- a/ipc/kdbus/bus.c -+++ b/ipc/kdbus/bus.c -@@ -293,12 +293,12 @@ void kdbus_bus_broadcast(struct kdbus_bus *bus, - if (!kdbus_conn_policy_talk(conn_dst, NULL, conn_src)) - continue; - -- /* -- * Keep sending messages even if we cannot acquire the -- * requested metadata. It's up to the receiver to drop -- * messages that lack expected metadata. -- */ -- kdbus_kmsg_collect_metadata(kmsg, conn_src, conn_dst); -+ ret = kdbus_kmsg_collect_metadata(kmsg, conn_src, -+ conn_dst); -+ if (ret < 0) { -+ kdbus_conn_lost_message(conn_dst); -+ continue; -+ } - } else { - /* - * Check if there is a policy db that prevents the -@@ -344,14 +344,14 @@ void kdbus_bus_eavesdrop(struct kdbus_bus *bus, - - down_read(&bus->conn_rwlock); - list_for_each_entry(conn_dst, &bus->monitors_list, monitor_entry) { -- /* -- * Collect metadata requested by the destination connection. -- * Ignore errors, as receivers need to check metadata -- * availability, anyway. So it's still better to send messages -- * that lack data, than to skip it entirely. -- */ -- if (conn_src) -- kdbus_kmsg_collect_metadata(kmsg, conn_src, conn_dst); -+ if (conn_src) { -+ ret = kdbus_kmsg_collect_metadata(kmsg, conn_src, -+ conn_dst); -+ if (ret < 0) { -+ kdbus_conn_lost_message(conn_dst); -+ continue; -+ } -+ } - - ret = kdbus_conn_entry_insert(conn_src, conn_dst, kmsg, NULL); - if (ret < 0) --- -2.4.3 - - -From c7d30619471faef78920b02d17ad44da56987faa Mon Sep 17 00:00:00 2001 -From: Daniel Mack <daniel@zonque.org> -Date: Fri, 3 Apr 2015 12:41:52 +0200 -Subject: [PATCH 048/132] samples/kdbus: stub out code for glibc < 2.7 - -Andrew Morton reports the following build error in samples/kdbus on Fedora -Core 6: - - samples/kdbus/kdbus-workers.c:73:26: error: sys/signalfd.h: No such file or directory - samples/kdbus/kdbus-workers.c: In function 'master_new': - samples/kdbus/kdbus-workers.c:231: warning: implicit declaration of function 'signalfd' - samples/kdbus/kdbus-workers.c:231: error: 'SFD_CLOEXEC' undeclared (first use in this function) - samples/kdbus/kdbus-workers.c:231: error: (Each undeclared identifier is reported only once - samples/kdbus/kdbus-workers.c:231: error: for each function it appears in.) - samples/kdbus/kdbus-workers.c: In function 'master_handle_signal': - samples/kdbus/kdbus-workers.c:406: error: storage size of 'val' isn't known - samples/kdbus/kdbus-workers.c:406: warning: unused variable 'val' - samples/kdbus/kdbus-workers.c: In function 'child_run': - samples/kdbus/kdbus-workers.c:773: error: 'CLOCK_MONOTONIC_COARSE' undeclared (first use in this function) - samples/kdbus/kdbus-workers.c: In function 'bus_open_connection': - samples/kdbus/kdbus-workers.c:1038: error: 'O_CLOEXEC' undeclared (first use in this function) - samples/kdbus/kdbus-workers.c: In function 'bus_make': - samples/kdbus/kdbus-workers.c:1275: error: 'O_CLOEXEC' undeclared (first use in this function) - -Fedora Core 6 was released in 2006, which predates the introduction of -signalfds in the kernel (v2.6.22, 2007). - -The example cannot be built without signalfds, and kbuild cannot depend on -specific features of the local libc when building userspace executables, so -we have to work around the issue by checking for specific glibc versions at -compile time and stub the entire thing if it can't be compiled. - -Reported-by: Andrew Morton <akpm@linux-foundation.org> -Signed-off-by: Daniel Mack <daniel@zonque.org> -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> ---- - samples/kdbus/kdbus-workers.c | 23 +++++++++++++++++++++-- - 1 file changed, 21 insertions(+), 2 deletions(-) - -diff --git a/samples/kdbus/kdbus-workers.c b/samples/kdbus/kdbus-workers.c -index d331e0186899..c3ba958639f3 100644 ---- a/samples/kdbus/kdbus-workers.c -+++ b/samples/kdbus/kdbus-workers.c -@@ -57,6 +57,12 @@ - * top-down, but requires some forward-declarations. Just ignore those. - */ - -+#include <stdio.h> -+#include <stdlib.h> -+ -+/* glibc < 2.7 does not ship sys/signalfd.h */ -+#if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 7 -+ - #include <ctype.h> - #include <errno.h> - #include <fcntl.h> -@@ -65,8 +71,6 @@ - #include <stdbool.h> - #include <stddef.h> - #include <stdint.h> --#include <stdio.h> --#include <stdlib.h> - #include <string.h> - #include <sys/mman.h> - #include <sys/poll.h> -@@ -1324,3 +1328,18 @@ static int bus_make(uid_t uid, const char *name) - - return fd; - } -+ -+#else -+ -+#warning "Skipping compilation due to unsupported libc version" -+ -+int main(int argc, char **argv) -+{ -+ fprintf(stderr, -+ "Compilation of %s was skipped due to unsupported libc.\n", -+ argv[0]); -+ -+ return EXIT_FAILURE; -+} -+ -+#endif /* libc sanity check */ --- -2.4.3 - - -From cf28849b4e905e91485b60174454d30f411b08be Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Thu, 23 Apr 2015 10:23:38 +0200 -Subject: [PATCH 049/132] kdbus: fix up documentation of ioctl handlers - -We support feature negotiation on ioctls. As this is not necessarily fully -generic, we indicate this by returning >0 from kdbus_args_parse(). -Therefore, all ioctl handlers that forward the return value of -kdbus_args_parse() might also return >0 on negotiation. Which is totally -fine and handled in kdbus_handle_ioctl(). However, the documentation of -the ioctl handlers doesn't reflect that behavior. Fix those up! - -Reported-by: Dan Carpenter <dan.carpenter@oracle.com> -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> ---- - ipc/kdbus/bus.c | 4 ++-- - ipc/kdbus/connection.c | 14 +++++++------- - ipc/kdbus/endpoint.c | 4 ++-- - ipc/kdbus/match.c | 4 ++-- - ipc/kdbus/names.c | 6 +++--- - 5 files changed, 16 insertions(+), 16 deletions(-) - -diff --git a/ipc/kdbus/bus.c b/ipc/kdbus/bus.c -index d5475961b896..bbdf0f2f391e 100644 ---- a/ipc/kdbus/bus.c -+++ b/ipc/kdbus/bus.c -@@ -365,7 +365,7 @@ void kdbus_bus_eavesdrop(struct kdbus_bus *bus, - * @domain: domain to operate on - * @argp: command payload - * -- * Return: Newly created bus on success, ERR_PTR on failure. -+ * Return: NULL or newly created bus on success, ERR_PTR on failure. - */ - struct kdbus_bus *kdbus_cmd_bus_make(struct kdbus_domain *domain, - void __user *argp) -@@ -459,7 +459,7 @@ exit: - * @conn: connection to operate on - * @argp: command payload - * -- * Return: 0 on success, negative error code on failure. -+ * Return: >=0 on success, negative error code on failure. - */ - int kdbus_cmd_bus_creator_info(struct kdbus_conn *conn, void __user *argp) - { -diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c -index cbfbf3847c24..8ee62fc0bd46 100644 ---- a/ipc/kdbus/connection.c -+++ b/ipc/kdbus/connection.c -@@ -1589,7 +1589,7 @@ bool kdbus_conn_policy_see_notification(struct kdbus_conn *conn, - * @privileged: Whether the caller is privileged - * @argp: Command payload - * -- * Return: Newly created connection on success, ERR_PTR on failure. -+ * Return: NULL or newly created connection on success, ERR_PTR on failure. - */ - struct kdbus_conn *kdbus_cmd_hello(struct kdbus_ep *ep, bool privileged, - void __user *argp) -@@ -1676,7 +1676,7 @@ exit: - * - * The caller must not hold any active reference to @conn or this will deadlock. - * -- * Return: 0 on success, negative error code on failure. -+ * Return: >=0 on success, negative error code on failure. - */ - int kdbus_cmd_byebye_unlocked(struct kdbus_conn *conn, void __user *argp) - { -@@ -1708,7 +1708,7 @@ int kdbus_cmd_byebye_unlocked(struct kdbus_conn *conn, void __user *argp) - * @conn: connection to operate on - * @argp: command payload - * -- * Return: 0 on success, negative error code on failure. -+ * Return: >=0 on success, negative error code on failure. - */ - int kdbus_cmd_conn_info(struct kdbus_conn *conn, void __user *argp) - { -@@ -1838,7 +1838,7 @@ exit: - * @conn: connection to operate on - * @argp: command payload - * -- * Return: 0 on success, negative error code on failure. -+ * Return: >=0 on success, negative error code on failure. - */ - int kdbus_cmd_update(struct kdbus_conn *conn, void __user *argp) - { -@@ -1935,7 +1935,7 @@ exit: - * @f: file this command was called on - * @argp: command payload - * -- * Return: 0 on success, negative error code on failure. -+ * Return: >=0 on success, negative error code on failure. - */ - int kdbus_cmd_send(struct kdbus_conn *conn, struct file *f, void __user *argp) - { -@@ -2031,7 +2031,7 @@ exit: - * @conn: connection to operate on - * @argp: command payload - * -- * Return: 0 on success, negative error code on failure. -+ * Return: >=0 on success, negative error code on failure. - */ - int kdbus_cmd_recv(struct kdbus_conn *conn, void __user *argp) - { -@@ -2154,7 +2154,7 @@ exit: - * @conn: connection to operate on - * @argp: command payload - * -- * Return: 0 on success, negative error code on failure. -+ * Return: >=0 on success, negative error code on failure. - */ - int kdbus_cmd_free(struct kdbus_conn *conn, void __user *argp) - { -diff --git a/ipc/kdbus/endpoint.c b/ipc/kdbus/endpoint.c -index 174d274b113e..9a95a5ea84d7 100644 ---- a/ipc/kdbus/endpoint.c -+++ b/ipc/kdbus/endpoint.c -@@ -188,7 +188,7 @@ struct kdbus_ep *kdbus_ep_unref(struct kdbus_ep *ep) - * @bus: bus to operate on - * @argp: command payload - * -- * Return: Newly created endpoint on success, ERR_PTR on failure. -+ * Return: NULL or newly created endpoint on success, ERR_PTR on failure. - */ - struct kdbus_ep *kdbus_cmd_ep_make(struct kdbus_bus *bus, void __user *argp) - { -@@ -247,7 +247,7 @@ exit: - * @ep: endpoint to operate on - * @argp: command payload - * -- * Return: Newly created endpoint on success, ERR_PTR on failure. -+ * Return: >=0 on success, negative error code on failure. - */ - int kdbus_cmd_ep_update(struct kdbus_ep *ep, void __user *argp) - { -diff --git a/ipc/kdbus/match.c b/ipc/kdbus/match.c -index 30cec1ca819f..cc083b4211de 100644 ---- a/ipc/kdbus/match.c -+++ b/ipc/kdbus/match.c -@@ -368,7 +368,7 @@ static int kdbus_match_db_remove_unlocked(struct kdbus_match_db *mdb, - * are used to match messages from userspace, while the others apply to - * kernel-generated notifications. - * -- * Return: 0 on success, negative error code on failure. -+ * Return: >=0 on success, negative error code on failure. - */ - int kdbus_cmd_match_add(struct kdbus_conn *conn, void __user *argp) - { -@@ -528,7 +528,7 @@ exit: - * @conn: connection to operate on - * @argp: command payload - * -- * Return: 0 on success, negative error code on failure. -+ * Return: >=0 on success, negative error code on failure. - */ - int kdbus_cmd_match_remove(struct kdbus_conn *conn, void __user *argp) - { -diff --git a/ipc/kdbus/names.c b/ipc/kdbus/names.c -index 657008e1bb37..5f5d84ea0e8e 100644 ---- a/ipc/kdbus/names.c -+++ b/ipc/kdbus/names.c -@@ -469,7 +469,7 @@ void kdbus_name_release_all(struct kdbus_name_registry *reg, - * @conn: connection to operate on - * @argp: command payload - * -- * Return: 0 on success, negative error code on failure. -+ * Return: >=0 on success, negative error code on failure. - */ - int kdbus_cmd_name_acquire(struct kdbus_conn *conn, void __user *argp) - { -@@ -528,7 +528,7 @@ exit: - * @conn: connection to operate on - * @argp: command payload - * -- * Return: 0 on success, negative error code on failure. -+ * Return: >=0 on success, negative error code on failure. - */ - int kdbus_cmd_name_release(struct kdbus_conn *conn, void __user *argp) - { -@@ -699,7 +699,7 @@ static int kdbus_list_all(struct kdbus_conn *conn, u64 flags, - * @conn: connection to operate on - * @argp: command payload - * -- * Return: 0 on success, negative error code on failure. -+ * Return: >=0 on success, negative error code on failure. - */ - int kdbus_cmd_list(struct kdbus_conn *conn, void __user *argp) - { --- -2.4.3 - - -From 07994686b022d6fe632d86c300db51ecf7587ce7 Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Wed, 22 Apr 2015 13:14:24 +0200 -Subject: [PATCH 050/132] kdbus: translate capabilities between namespaces - -Right now, we always drop capability-items if we cross user-namespaces. -However, the kernel _does_ support capability translation, as defined in -./security/commoncap.c cap_capable(). - -This patch adds capability translation support just like cap_capable() -does. This way, a message sent from a task into a child user-namespace of -its own, will retain the capability-item and thus keep the parent -privileged inside of the user-namespace of its children. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> ---- - ipc/kdbus/metadata.c | 126 ++++++++++++++++++++++++++++++++++----------------- - 1 file changed, 84 insertions(+), 42 deletions(-) - -diff --git a/ipc/kdbus/metadata.c b/ipc/kdbus/metadata.c -index b908b6314a00..7949c8d3ed64 100644 ---- a/ipc/kdbus/metadata.c -+++ b/ipc/kdbus/metadata.c -@@ -63,8 +63,7 @@ - * @root_path: Root-FS path - * @cmdline: Command-line - * @cgroup: Full cgroup path -- * @caps: Capabilities -- * @caps_namespace: User-namespace of @caps -+ * @cred: Credentials - * @seclabel: Seclabel - * @audit_loginuid: Audit login-UID - * @audit_sessionid: Audit session-ID -@@ -104,14 +103,7 @@ struct kdbus_meta_proc { - char *cgroup; - - /* KDBUS_ITEM_CAPS */ -- struct caps { -- /* binary compatible to kdbus_caps */ -- u32 last_cap; -- struct { -- u32 caps[_KERNEL_CAPABILITY_U32S]; -- } set[4]; -- } caps; -- struct user_namespace *caps_namespace; -+ const struct cred *cred; - - /* KDBUS_ITEM_SECLABEL */ - char *seclabel; -@@ -149,6 +141,14 @@ struct kdbus_meta_conn { - char *conn_description; - }; - -+/* fixed size equivalent of "kdbus_caps" */ -+struct kdbus_meta_caps { -+ u32 last_cap; -+ struct { -+ u32 caps[_KERNEL_CAPABILITY_U32S]; -+ } set[4]; -+}; -+ - /** - * kdbus_meta_proc_new() - Create process metadata object - * -@@ -175,7 +175,8 @@ static void kdbus_meta_proc_free(struct kref *kref) - - path_put(&mp->exe_path); - path_put(&mp->root_path); -- put_user_ns(mp->caps_namespace); -+ if (mp->cred) -+ put_cred(mp->cred); - put_pid(mp->ppid); - put_pid(mp->tgid); - put_pid(mp->pid); -@@ -354,25 +355,7 @@ static int kdbus_meta_proc_collect_cgroup(struct kdbus_meta_proc *mp) - - static void kdbus_meta_proc_collect_caps(struct kdbus_meta_proc *mp) - { -- const struct cred *c = current_cred(); -- int i; -- -- /* ABI: "last_cap" equals /proc/sys/kernel/cap_last_cap */ -- mp->caps.last_cap = CAP_LAST_CAP; -- mp->caps_namespace = get_user_ns(current_user_ns()); -- -- CAP_FOR_EACH_U32(i) { -- mp->caps.set[0].caps[i] = c->cap_inheritable.cap[i]; -- mp->caps.set[1].caps[i] = c->cap_permitted.cap[i]; -- mp->caps.set[2].caps[i] = c->cap_effective.cap[i]; -- mp->caps.set[3].caps[i] = c->cap_bset.cap[i]; -- } -- -- /* clear unused bits */ -- for (i = 0; i < 4; i++) -- mp->caps.set[i].caps[CAP_TO_INDEX(CAP_LAST_CAP)] &= -- CAP_LAST_U32_VALID_MASK; -- -+ mp->cred = get_current_cred(); - mp->valid |= KDBUS_ATTACH_CAPS; - } - -@@ -880,7 +863,7 @@ int kdbus_meta_export_prepare(struct kdbus_meta_proc *mp, - size += KDBUS_ITEM_SIZE(strlen(mp->cgroup) + 1); - - if (mp && (*mask & KDBUS_ATTACH_CAPS)) -- size += KDBUS_ITEM_SIZE(sizeof(mp->caps)); -+ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_meta_caps)); - - if (mp && (*mask & KDBUS_ATTACH_SECLABEL)) - size += KDBUS_ITEM_SIZE(strlen(mp->seclabel) + 1); -@@ -917,6 +900,69 @@ static int kdbus_meta_push_kvec(struct kvec *kvec, - return 2 + !!kdbus_kvec_pad(kvec++, size); - } - -+static void kdbus_meta_export_caps(struct kdbus_meta_caps *out, -+ struct kdbus_meta_proc *mp) -+{ -+ struct user_namespace *iter; -+ const struct cred *cred = mp->cred; -+ bool parent = false, owner = false; -+ int i; -+ -+ /* -+ * This translates the effective capabilities of 'cred' into the current -+ * user-namespace. If the current user-namespace is a child-namespace of -+ * the user-namespace of 'cred', the mask can be copied verbatim. If -+ * not, the mask is cleared. -+ * There's one exception: If 'cred' is the owner of any user-namespace -+ * in the path between the current user-namespace and the user-namespace -+ * of 'cred', then it has all effective capabilities set. This means, -+ * the user who created a user-namespace always has all effective -+ * capabilities in any child namespaces. Note that this is based on the -+ * uid of the namespace creator, not the task hierarchy. -+ */ -+ for (iter = current_user_ns(); iter; iter = iter->parent) { -+ if (iter == cred->user_ns) { -+ parent = true; -+ break; -+ } -+ -+ if (iter == &init_user_ns) -+ break; -+ -+ if ((iter->parent == cred->user_ns) && -+ uid_eq(iter->owner, cred->euid)) { -+ owner = true; -+ break; -+ } -+ } -+ -+ out->last_cap = CAP_LAST_CAP; -+ -+ CAP_FOR_EACH_U32(i) { -+ if (parent) { -+ out->set[0].caps[i] = cred->cap_inheritable.cap[i]; -+ out->set[1].caps[i] = cred->cap_permitted.cap[i]; -+ out->set[2].caps[i] = cred->cap_effective.cap[i]; -+ out->set[3].caps[i] = cred->cap_bset.cap[i]; -+ } else if (owner) { -+ out->set[0].caps[i] = 0U; -+ out->set[1].caps[i] = ~0U; -+ out->set[2].caps[i] = ~0U; -+ out->set[3].caps[i] = ~0U; -+ } else { -+ out->set[0].caps[i] = 0U; -+ out->set[1].caps[i] = 0U; -+ out->set[2].caps[i] = 0U; -+ out->set[3].caps[i] = 0U; -+ } -+ } -+ -+ /* clear unused bits */ -+ for (i = 0; i < 4; i++) -+ out->set[i].caps[CAP_TO_INDEX(CAP_LAST_CAP)] &= -+ CAP_LAST_U32_VALID_MASK; -+} -+ - /* This is equivalent to from_kuid_munged(), but maps INVALID_UID to itself */ - static uid_t kdbus_from_kuid_keep(kuid_t uid) - { -@@ -975,14 +1021,6 @@ int kdbus_meta_export(struct kdbus_meta_proc *mp, - - hdr = &item_hdr[0]; - -- /* -- * TODO: We currently have no sane way of translating a set of caps -- * between different user namespaces. Until that changes, we have -- * to drop such items. -- */ -- if (mp && mp->caps_namespace != user_ns) -- mask &= ~KDBUS_ATTACH_CAPS; -- - if (mask == 0) { - *real_size = 0; - return 0; -@@ -1088,10 +1126,14 @@ int kdbus_meta_export(struct kdbus_meta_proc *mp, - KDBUS_ITEM_CGROUP, mp->cgroup, - strlen(mp->cgroup) + 1, &size); - -- if (mp && (mask & KDBUS_ATTACH_CAPS)) -+ if (mp && (mask & KDBUS_ATTACH_CAPS)) { -+ struct kdbus_meta_caps caps = {}; -+ -+ kdbus_meta_export_caps(&caps, mp); - cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, -- KDBUS_ITEM_CAPS, &mp->caps, -- sizeof(mp->caps), &size); -+ KDBUS_ITEM_CAPS, &caps, -+ sizeof(caps), &size); -+ } - - if (mp && (mask & KDBUS_ATTACH_SECLABEL)) - cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, --- -2.4.3 - - -From f28a57a2c5f6a27f56f1522711ec31f7b7cde06e Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Wed, 3 Jun 2015 17:53:29 +0200 -Subject: [PATCH 051/132] kdbus/selftests: add build-dependencies on headers - -Make sure the selftests are re-built if one of the local headers changes. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> ---- - tools/testing/selftests/kdbus/Makefile | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/tools/testing/selftests/kdbus/Makefile b/tools/testing/selftests/kdbus/Makefile -index 076f9f40566d..7ad587b3c767 100644 ---- a/tools/testing/selftests/kdbus/Makefile -+++ b/tools/testing/selftests/kdbus/Makefile -@@ -34,7 +34,7 @@ all: kdbus-test - - include ../lib.mk - --%.o: %.c -+%.o: %.c kdbus-enum.h kdbus-test.h kdbus-util.h - $(CC) $(CFLAGS) -c $< -o $@ - - kdbus-test: $(OBJS) --- -2.4.3 - - -From c88c27dccd43972d12e31c3ff02a24d7e8026d7e Mon Sep 17 00:00:00 2001 -From: Daniel Mack <daniel@zonque.org> -Date: Sat, 18 Apr 2015 12:04:36 +0200 -Subject: [PATCH 052/132] kdbus: use rcu to access exe file in metadata - -Commit 90f31d0ea888 ("mm: rcu-protected get_mm_exe_file()") removed -mm->mmap_sem from mm->exe_file read side. Follow that change in the -kdbus metadata code. - -Signed-off-by: Daniel Mack <daniel@zonque.org> -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> ---- - ipc/kdbus/metadata.c | 10 ++++++---- - 1 file changed, 6 insertions(+), 4 deletions(-) - -diff --git a/ipc/kdbus/metadata.c b/ipc/kdbus/metadata.c -index 7949c8d3ed64..a85eac34a5c4 100644 ---- a/ipc/kdbus/metadata.c -+++ b/ipc/kdbus/metadata.c -@@ -283,19 +283,21 @@ static void kdbus_meta_proc_collect_pid_comm(struct kdbus_meta_proc *mp) - static void kdbus_meta_proc_collect_exe(struct kdbus_meta_proc *mp) - { - struct mm_struct *mm; -+ struct file *exe_file; - - mm = get_task_mm(current); - if (!mm) - return; - -- down_read(&mm->mmap_sem); -- if (mm->exe_file) { -- mp->exe_path = mm->exe_file->f_path; -+ rcu_read_lock(); -+ exe_file = rcu_dereference(mm->exe_file); -+ if (exe_file) { -+ mp->exe_path = exe_file->f_path; - path_get(&mp->exe_path); - get_fs_root(current->fs, &mp->root_path); - mp->valid |= KDBUS_ATTACH_EXE; - } -- up_read(&mm->mmap_sem); -+ rcu_read_unlock(); - - mmput(mm); - } --- -2.4.3 - - -From 9efa7187a1522f57d4022b943378703b09db6c1b Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Mon, 20 Apr 2015 11:13:54 +0200 -Subject: [PATCH 053/132] kdbus: no need to ref current->mm - -If we access current->mm temporarily, there is no need to ref it. It can -only be changed by us, so no-one can race with us. - -Avoid ref'ing and unref'ing it just to access some of its fields, similar -to what syscalls in mm/ do. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> ---- - ipc/kdbus/metadata.c | 21 +++------------------ - 1 file changed, 3 insertions(+), 18 deletions(-) - -diff --git a/ipc/kdbus/metadata.c b/ipc/kdbus/metadata.c -index a85eac34a5c4..c36b9cc67637 100644 ---- a/ipc/kdbus/metadata.c -+++ b/ipc/kdbus/metadata.c -@@ -282,15 +282,10 @@ static void kdbus_meta_proc_collect_pid_comm(struct kdbus_meta_proc *mp) - - static void kdbus_meta_proc_collect_exe(struct kdbus_meta_proc *mp) - { -- struct mm_struct *mm; - struct file *exe_file; - -- mm = get_task_mm(current); -- if (!mm) -- return; -- - rcu_read_lock(); -- exe_file = rcu_dereference(mm->exe_file); -+ exe_file = rcu_dereference(current->mm->exe_file); - if (exe_file) { - mp->exe_path = exe_file->f_path; - path_get(&mp->exe_path); -@@ -298,28 +293,18 @@ static void kdbus_meta_proc_collect_exe(struct kdbus_meta_proc *mp) - mp->valid |= KDBUS_ATTACH_EXE; - } - rcu_read_unlock(); -- -- mmput(mm); - } - - static int kdbus_meta_proc_collect_cmdline(struct kdbus_meta_proc *mp) - { -- struct mm_struct *mm; -+ struct mm_struct *mm = current->mm; - char *cmdline; - -- mm = get_task_mm(current); -- if (!mm) -- return 0; -- -- if (!mm->arg_end) { -- mmput(mm); -+ if (!mm->arg_end) - return 0; -- } - - cmdline = strndup_user((const char __user *)mm->arg_start, - mm->arg_end - mm->arg_start); -- mmput(mm); -- - if (IS_ERR(cmdline)) - return PTR_ERR(cmdline); - --- -2.4.3 - - -From 5d183f20dc41d67794b19115780cde10a2f616dd Mon Sep 17 00:00:00 2001 -From: Tyler Baker <tyler.baker@linaro.org> -Date: Tue, 21 Apr 2015 15:50:51 -0700 -Subject: [PATCH 054/132] selftests/kdbus: install kdbus-test - -Set TEST_PROGS so that kdbus-test is installed. - -Acked-by: Michael Ellerman <mpe@ellerman.id.au> -Signed-off-by: Tyler Baker <tyler.baker@linaro.org> -Cc: Shuah Khan <shuahkh@osg.samsung.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - tools/testing/selftests/kdbus/Makefile | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/tools/testing/selftests/kdbus/Makefile b/tools/testing/selftests/kdbus/Makefile -index 7ad587b3c767..8f36cb5667cc 100644 ---- a/tools/testing/selftests/kdbus/Makefile -+++ b/tools/testing/selftests/kdbus/Makefile -@@ -40,6 +40,8 @@ include ../lib.mk - kdbus-test: $(OBJS) - $(CC) $(CFLAGS) $^ $(LDLIBS) -o $@ - -+TEST_PROGS := kdbus-test -+ - run_tests: - ./kdbus-test --tap - --- -2.4.3 - - -From 9e8514b8ad380f98014ea01eebae04bbaf4018f2 Mon Sep 17 00:00:00 2001 -From: Sergei Zviagintsev <sergei@s15v.net> -Date: Tue, 2 Jun 2015 18:48:47 +0300 -Subject: [PATCH 055/132] kdbus: update kernel-doc for - kdbus_sync_reply_wakeup() - -kdbus_sync_reply_wakeup() doesn't remove reply object from connection -reply_list. Update function description. - -Signed-off-by: Sergei Zviagintsev <sergei@s15v.net> -Reviewed-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - ipc/kdbus/reply.c | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - -diff --git a/ipc/kdbus/reply.c b/ipc/kdbus/reply.c -index 008dca801627..89d355b44f63 100644 ---- a/ipc/kdbus/reply.c -+++ b/ipc/kdbus/reply.c -@@ -140,8 +140,7 @@ void kdbus_reply_unlink(struct kdbus_reply *r) - * @reply: The reply object - * @err: Error code to set on the remote side - * -- * Remove the synchronous reply object from its connection reply_list, and -- * wake up remote peer (method origin) with the appropriate synchronous reply -+ * Wake up remote peer (method origin) with the appropriate synchronous reply - * code. - */ - void kdbus_sync_reply_wakeup(struct kdbus_reply *reply, int err) --- -2.4.3 - - -From 6ea19b271bd51d2e36a82980a9af409b24c1812f Mon Sep 17 00:00:00 2001 -From: Sergei Zviagintsev <sergei@s15v.net> -Date: Tue, 2 Jun 2015 18:48:48 +0300 -Subject: [PATCH 056/132] kdbus: remove redundant code from - kdbus_conn_entry_make() - -We don't need to check `entry' for error, as in either case it is -returned as is. Return result of kdbus_queue_entry_new() directly. - -Signed-off-by: Sergei Zviagintsev <sergei@s15v.net> -Reviewed-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - ipc/kdbus/connection.c | 8 +------- - 1 file changed, 1 insertion(+), 7 deletions(-) - -diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c -index 8ee62fc0bd46..1bd7bb968f9f 100644 ---- a/ipc/kdbus/connection.c -+++ b/ipc/kdbus/connection.c -@@ -775,8 +775,6 @@ kdbus_conn_entry_make(struct kdbus_conn *conn_dst, - const struct kdbus_kmsg *kmsg, - struct kdbus_user *user) - { -- struct kdbus_queue_entry *entry; -- - /* The remote connection was disconnected */ - if (!kdbus_conn_active(conn_dst)) - return ERR_PTR(-ECONNRESET); -@@ -793,11 +791,7 @@ kdbus_conn_entry_make(struct kdbus_conn *conn_dst, - kmsg->res && kmsg->res->fds_count > 0) - return ERR_PTR(-ECOMM); - -- entry = kdbus_queue_entry_new(conn_dst, kmsg, user); -- if (IS_ERR(entry)) -- return entry; -- -- return entry; -+ return kdbus_queue_entry_new(conn_dst, kmsg, user); - } - - /* --- -2.4.3 - - -From 715284ed8cefde60ffcc2ce6d7c358d927fe1e86 Mon Sep 17 00:00:00 2001 -From: Sergei Zviagintsev <sergei@s15v.net> -Date: Tue, 2 Jun 2015 18:48:49 +0300 -Subject: [PATCH 057/132] kdbus: kdbus_item_validate(): remove duplicated code - -KDBUS_ITEM_PAYLOAD_VEC and KDBUS_ITEM_PAYLOAD_OFF cases use literally -the same code, so merge them. - -Signed-off-by: Sergei Zviagintsev <sergei@s15v.net> -Reviewed-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - ipc/kdbus/item.c | 6 ------ - 1 file changed, 6 deletions(-) - -diff --git a/ipc/kdbus/item.c b/ipc/kdbus/item.c -index 745ad5495096..1ee72c2ad7c3 100644 ---- a/ipc/kdbus/item.c -+++ b/ipc/kdbus/item.c -@@ -96,12 +96,6 @@ int kdbus_item_validate(const struct kdbus_item *item) - break; - - case KDBUS_ITEM_PAYLOAD_VEC: -- if (payload_size != sizeof(struct kdbus_vec)) -- return -EINVAL; -- if (item->vec.size == 0 || item->vec.size > SIZE_MAX) -- return -EINVAL; -- break; -- - case KDBUS_ITEM_PAYLOAD_OFF: - if (payload_size != sizeof(struct kdbus_vec)) - return -EINVAL; --- -2.4.3 - - -From 3451de5a838c23fe32d13b3e283c9470413d0cfa Mon Sep 17 00:00:00 2001 -From: Sergei Zviagintsev <sergei@s15v.net> -Date: Tue, 2 Jun 2015 18:48:50 +0300 -Subject: [PATCH 058/132] kdbus: kdbus_conn_connect(): use `bus' instead of - `conn->ep->bus' - -Local `bus' is already set to `conn->ep->bus'. Use it. - -Signed-off-by: Sergei Zviagintsev <sergei@s15v.net> -Reviewed-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - ipc/kdbus/connection.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c -index 1bd7bb968f9f..707be050b408 100644 ---- a/ipc/kdbus/connection.c -+++ b/ipc/kdbus/connection.c -@@ -432,7 +432,7 @@ static int kdbus_conn_connect(struct kdbus_conn *conn, const char *name) - * directly, and won't cause any notifications. - */ - if (!kdbus_conn_is_monitor(conn)) { -- ret = kdbus_notify_id_change(conn->ep->bus, KDBUS_ITEM_ID_ADD, -+ ret = kdbus_notify_id_change(bus, KDBUS_ITEM_ID_ADD, - conn->id, conn->flags); - if (ret < 0) - goto exit_disconnect; --- -2.4.3 - - -From cf15adc8b4810c8e8f84bca9300c553d968feef3 Mon Sep 17 00:00:00 2001 -From: Sergei Zviagintsev <sergei@s15v.net> -Date: Thu, 4 Jun 2015 13:39:30 +0300 -Subject: [PATCH 059/132] kdbus: use FIELD_SIZEOF in kdbus_member_set_user - macro - -sizeof(((_t *)0)->_m) -> FIELD_SIZEOF(_t, _m) - -Use conventional macro according to chapter 17 of -Documentation/CodingStyle. - -Signed-off-by: Sergei Zviagintsev <sergei@s15v.net> -Reviewed-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - ipc/kdbus/util.h | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ipc/kdbus/util.h b/ipc/kdbus/util.h -index 9fedf8ab41cd..529716669fe7 100644 ---- a/ipc/kdbus/util.h -+++ b/ipc/kdbus/util.h -@@ -40,7 +40,7 @@ - ({ \ - u64 __user *_sz = \ - (void __user *)((u8 __user *)(_b) + offsetof(_t, _m)); \ -- copy_to_user(_sz, _s, sizeof(((_t *)0)->_m)); \ -+ copy_to_user(_sz, _s, FIELD_SIZEOF(_t, _m)); \ - }) - - /** --- -2.4.3 - - -From 1c224742f07d78d600d4d987c4745d791dbed901 Mon Sep 17 00:00:00 2001 -From: Sergei Zviagintsev <sergei@s15v.net> -Date: Wed, 17 Jun 2015 19:33:24 +0300 -Subject: [PATCH 060/132] selftests/kdbus: handle cap_get_proc() error properly - -Fix typo in checking error value of cap_get_proc(): cap -> caps - -Signed-off-by: Sergei Zviagintsev <sergei@s15v.net> -Reviewed-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - tools/testing/selftests/kdbus/kdbus-util.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/tools/testing/selftests/kdbus/kdbus-util.c b/tools/testing/selftests/kdbus/kdbus-util.c -index 4b376ecfdbed..6909fb9b1ce5 100644 ---- a/tools/testing/selftests/kdbus/kdbus-util.c -+++ b/tools/testing/selftests/kdbus/kdbus-util.c -@@ -1547,7 +1547,7 @@ int test_is_capable(int cap, ...) - cap_t caps; - - caps = cap_get_proc(); -- if (!cap) { -+ if (!caps) { - ret = -errno; - kdbus_printf("error cap_get_proc(): %d (%m)\n", ret); - return ret; --- -2.4.3 - - -From 88bbfef2fa9e24a501166b6911852e3e6f4596e5 Mon Sep 17 00:00:00 2001 -From: Sergei Zviagintsev <sergei@s15v.net> -Date: Wed, 17 Jun 2015 19:33:25 +0300 -Subject: [PATCH 061/132] selftests/kdbus: drop useless assignment - -Assign returned file descriptor directly to `fd', without intermediate -`ret' variable. - -Signed-off-by: Sergei Zviagintsev <sergei@s15v.net> -Reviewed-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - tools/testing/selftests/kdbus/kdbus-util.c | 8 +++----- - 1 file changed, 3 insertions(+), 5 deletions(-) - -diff --git a/tools/testing/selftests/kdbus/kdbus-util.c b/tools/testing/selftests/kdbus/kdbus-util.c -index 6909fb9b1ce5..5b924531d938 100644 ---- a/tools/testing/selftests/kdbus/kdbus-util.c -+++ b/tools/testing/selftests/kdbus/kdbus-util.c -@@ -408,11 +408,9 @@ int sys_memfd_create(const char *name, __u64 size) - { - int ret, fd; - -- ret = syscall(__NR_memfd_create, name, MFD_ALLOW_SEALING); -- if (ret < 0) -- return ret; -- -- fd = ret; -+ fd = syscall(__NR_memfd_create, name, MFD_ALLOW_SEALING); -+ if (fd < 0) -+ return fd; - - ret = ftruncate(fd, size); - if (ret < 0) { --- -2.4.3 - - -From 9007a5075dfba1025086cc753bbcccf52cd9254a Mon Sep 17 00:00:00 2001 -From: Sergei Zviagintsev <sergei@s15v.net> -Date: Wed, 17 Jun 2015 19:33:26 +0300 -Subject: [PATCH 062/132] selftests/kdbus: remove useless initializations from - kdbus_clone_userns_test() - -Do not initialize efd, unpriv_conn_id, userns_conn_id and monitor. These -vars are assigned to values later in code while initial values are never -used. - -Signed-off-by: Sergei Zviagintsev <sergei@s15v.net> -Reviewed-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - tools/testing/selftests/kdbus/test-metadata-ns.c | 9 +++------ - 1 file changed, 3 insertions(+), 6 deletions(-) - -diff --git a/tools/testing/selftests/kdbus/test-metadata-ns.c b/tools/testing/selftests/kdbus/test-metadata-ns.c -index 2cb1d4d2a5be..ccdfae06922b 100644 ---- a/tools/testing/selftests/kdbus/test-metadata-ns.c -+++ b/tools/testing/selftests/kdbus/test-metadata-ns.c -@@ -281,16 +281,13 @@ out: - static int kdbus_clone_userns_test(const char *bus, - struct kdbus_conn *conn) - { -- int ret; -- int status; -- int efd = -1; -+ int ret, status, efd; - pid_t pid, ppid; -- uint64_t unpriv_conn_id = 0; -- uint64_t userns_conn_id = 0; -+ uint64_t unpriv_conn_id, userns_conn_id; - struct kdbus_msg *msg; - const struct kdbus_item *item; - struct kdbus_pids expected_pids; -- struct kdbus_conn *monitor = NULL; -+ struct kdbus_conn *monitor; - - kdbus_printf("STARTING TEST 'metadata-ns'.\n"); - --- -2.4.3 - - -From 9815916bcf318aac46c6fb69563e9c7fd8d6394e Mon Sep 17 00:00:00 2001 -From: Sergei Zviagintsev <sergei@s15v.net> -Date: Wed, 17 Jun 2015 19:33:27 +0300 -Subject: [PATCH 063/132] selftests/kdbus: drop duplicated code from - __kdbus_msg_send() - -Set value of `size' in one step instead of four. - -Signed-off-by: Sergei Zviagintsev <sergei@s15v.net> -Reviewed-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - tools/testing/selftests/kdbus/kdbus-util.c | 5 +---- - 1 file changed, 1 insertion(+), 4 deletions(-) - -diff --git a/tools/testing/selftests/kdbus/kdbus-util.c b/tools/testing/selftests/kdbus/kdbus-util.c -index 5b924531d938..d35ec89cb816 100644 ---- a/tools/testing/selftests/kdbus/kdbus-util.c -+++ b/tools/testing/selftests/kdbus/kdbus-util.c -@@ -462,10 +462,7 @@ static int __kdbus_msg_send(const struct kdbus_conn *conn, - int memfd = -1; - int ret; - -- size = sizeof(*msg); -- size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec)); -- size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec)); -- size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec)); -+ size = sizeof(*msg) + 3 * KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec)); - - if (dst_id == KDBUS_DST_ID_BROADCAST) - size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_bloom_filter)) + 64; --- -2.4.3 - - -From 376c89d522b012e662c41c7d7b7e2748bd4d266f Mon Sep 17 00:00:00 2001 -From: Sergei Zviagintsev <sergei@s15v.net> -Date: Wed, 17 Jun 2015 19:33:28 +0300 -Subject: [PATCH 064/132] selftests/kdbus: fix error paths in - __kdbus_msg_send() - -Handle errors properly, free allocated resources. - -Signed-off-by: Sergei Zviagintsev <sergei@s15v.net> -Reviewed-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - tools/testing/selftests/kdbus/kdbus-util.c | 31 ++++++++++++++++++------------ - 1 file changed, 19 insertions(+), 12 deletions(-) - -diff --git a/tools/testing/selftests/kdbus/kdbus-util.c b/tools/testing/selftests/kdbus/kdbus-util.c -index d35ec89cb816..9fac4b31536d 100644 ---- a/tools/testing/selftests/kdbus/kdbus-util.c -+++ b/tools/testing/selftests/kdbus/kdbus-util.c -@@ -452,8 +452,8 @@ static int __kdbus_msg_send(const struct kdbus_conn *conn, - uint64_t cmd_flags, - int cancel_fd) - { -- struct kdbus_cmd_send *cmd; -- struct kdbus_msg *msg; -+ struct kdbus_cmd_send *cmd = NULL; -+ struct kdbus_msg *msg = NULL; - const char ref1[1024 * 128 + 3] = "0123456789_0"; - const char ref2[] = "0123456789_1"; - struct kdbus_item *item; -@@ -476,14 +476,14 @@ static int __kdbus_msg_send(const struct kdbus_conn *conn, - if (write(memfd, "kdbus memfd 1234567", 19) != 19) { - ret = -errno; - kdbus_printf("writing to memfd failed: %m\n"); -- return ret; -+ goto out; - } - - ret = sys_memfd_seal_set(memfd); - if (ret < 0) { - ret = -errno; - kdbus_printf("memfd sealing failed: %m\n"); -- return ret; -+ goto out; - } - - size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_memfd)); -@@ -496,7 +496,7 @@ static int __kdbus_msg_send(const struct kdbus_conn *conn, - if (!msg) { - ret = -errno; - kdbus_printf("unable to malloc()!?\n"); -- return ret; -+ goto out; - } - - if (dst_id == KDBUS_DST_ID_BROADCAST) -@@ -514,7 +514,7 @@ static int __kdbus_msg_send(const struct kdbus_conn *conn, - if (timeout) { - ret = clock_gettime(CLOCK_MONOTONIC_COARSE, &now); - if (ret < 0) -- return ret; -+ goto out; - - msg->timeout_ns = now.tv_sec * 1000000000ULL + - now.tv_nsec + timeout; -@@ -565,6 +565,12 @@ static int __kdbus_msg_send(const struct kdbus_conn *conn, - size += KDBUS_ITEM_SIZE(sizeof(cancel_fd)); - - cmd = malloc(size); -+ if (!cmd) { -+ ret = -errno; -+ kdbus_printf("unable to malloc()!?\n"); -+ goto out; -+ } -+ - cmd->size = size; - cmd->flags = cmd_flags; - cmd->msg_address = (uintptr_t)msg; -@@ -579,12 +585,9 @@ static int __kdbus_msg_send(const struct kdbus_conn *conn, - } - - ret = kdbus_cmd_send(conn->fd, cmd); -- if (memfd >= 0) -- close(memfd); -- - if (ret < 0) { - kdbus_printf("error sending message: %d (%m)\n", ret); -- return ret; -+ goto out; - } - - if (cmd_flags & KDBUS_SEND_SYNC_REPLY) { -@@ -598,13 +601,17 @@ static int __kdbus_msg_send(const struct kdbus_conn *conn, - - ret = kdbus_free(conn, cmd->reply.offset); - if (ret < 0) -- return ret; -+ goto out; - } - -+out: - free(msg); - free(cmd); - -- return 0; -+ if (memfd >= 0) -+ close(memfd); -+ -+ return ret < 0 ? ret : 0; - } - - int kdbus_msg_send(const struct kdbus_conn *conn, const char *name, --- -2.4.3 - - -From 1784f9e4f4b0e246edd741e7c595a2a5ea60acb2 Mon Sep 17 00:00:00 2001 -From: Marc-Antoine Perennou <Marc-Antoine@Perennou.com> -Date: Fri, 5 Jun 2015 14:37:34 +0200 -Subject: [PATCH 065/132] kdbus: drop useless goto - -Signed-off-by: Marc-Antoine Perennou <Marc-Antoine@Perennou.com> -Reviewed-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - ipc/kdbus/names.c | 2 -- - 1 file changed, 2 deletions(-) - -diff --git a/ipc/kdbus/names.c b/ipc/kdbus/names.c -index 5f5d84ea0e8e..d77ee08afeda 100644 ---- a/ipc/kdbus/names.c -+++ b/ipc/kdbus/names.c -@@ -514,8 +514,6 @@ int kdbus_cmd_name_acquire(struct kdbus_conn *conn, void __user *argp) - - ret = kdbus_name_acquire(conn->ep->bus->name_registry, conn, item_name, - cmd->flags, &cmd->return_flags); -- if (ret < 0) -- goto exit_dec; - - exit_dec: - atomic_dec(&conn->name_count); --- -2.4.3 - - -From 98d1cdd709a452b229364faf705a6a3a5ba430b7 Mon Sep 17 00:00:00 2001 -From: Sergei Zviagintsev <sergei@s15v.net> -Date: Tue, 9 Jun 2015 23:59:59 +0300 -Subject: [PATCH 066/132] kdbus: fix operator precedence issues in item macros - -`_i' argument in KDBUS_ITEM_NEXT and KDBUS_ITEMS_END macros is not -enclosed into parentheses when the cast operator is applied, which -leads to improper type conversion if `_i' is supplied as a complex -expression, e.g. - - KDBUS_ITEM_NEXT(condition ? a : b) - -KDBUS_ITEMS_SIZE macro has similar issue, missing parentheses around -`_h' when using indirection operator. - -Use parentheses properly to guarantee right precedence. - -Signed-off-by: Sergei Zviagintsev <sergei@s15v.net> -Reviewed-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - ipc/kdbus/item.h | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/ipc/kdbus/item.h b/ipc/kdbus/item.h -index eeefd8beac3b..32909e2e7954 100644 ---- a/ipc/kdbus/item.h -+++ b/ipc/kdbus/item.h -@@ -21,8 +21,8 @@ - #include "util.h" - - /* generic access and iterators over a stream of items */ --#define KDBUS_ITEM_NEXT(_i) (typeof(_i))(((u8 *)_i) + KDBUS_ALIGN8((_i)->size)) --#define KDBUS_ITEMS_SIZE(_h, _is) ((_h)->size - offsetof(typeof(*_h), _is)) -+#define KDBUS_ITEM_NEXT(_i) (typeof(_i))((u8 *)(_i) + KDBUS_ALIGN8((_i)->size)) -+#define KDBUS_ITEMS_SIZE(_h, _is) ((_h)->size - offsetof(typeof(*(_h)), _is)) - #define KDBUS_ITEM_HEADER_SIZE offsetof(struct kdbus_item, data) - #define KDBUS_ITEM_SIZE(_s) KDBUS_ALIGN8(KDBUS_ITEM_HEADER_SIZE + (_s)) - #define KDBUS_ITEM_PAYLOAD_SIZE(_i) ((_i)->size - KDBUS_ITEM_HEADER_SIZE) -@@ -40,7 +40,7 @@ - (u8 *)(_i) >= (u8 *)(_is)) - - #define KDBUS_ITEMS_END(_i, _is, _s) \ -- ((u8 *)_i == ((u8 *)(_is) + KDBUS_ALIGN8(_s))) -+ ((u8 *)(_i) == ((u8 *)(_is) + KDBUS_ALIGN8(_s))) - - /** - * struct kdbus_item_header - Describes the fix part of an item --- -2.4.3 - - -From 4c87b4fb0469abef56390b9107785a92d5457331 Mon Sep 17 00:00:00 2001 -From: Sergei Zviagintsev <sergei@s15v.net> -Date: Wed, 10 Jun 2015 00:00:00 +0300 -Subject: [PATCH 067/132] kdbus: use parentheses uniformly in - KDBUS_ITEMS_FOREACH macro - -Enclose all arguments into parentheses to stay consistent across the -whole macro. - -Signed-off-by: Sergei Zviagintsev <sergei@s15v.net> -Reviewed-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - ipc/kdbus/item.h | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/ipc/kdbus/item.h b/ipc/kdbus/item.h -index 32909e2e7954..bca63b4e6e80 100644 ---- a/ipc/kdbus/item.h -+++ b/ipc/kdbus/item.h -@@ -28,10 +28,10 @@ - #define KDBUS_ITEM_PAYLOAD_SIZE(_i) ((_i)->size - KDBUS_ITEM_HEADER_SIZE) - - #define KDBUS_ITEMS_FOREACH(_i, _is, _s) \ -- for (_i = _is; \ -+ for ((_i) = (_is); \ - ((u8 *)(_i) < (u8 *)(_is) + (_s)) && \ - ((u8 *)(_i) >= (u8 *)(_is)); \ -- _i = KDBUS_ITEM_NEXT(_i)) -+ (_i) = KDBUS_ITEM_NEXT(_i)) - - #define KDBUS_ITEM_VALID(_i, _is, _s) \ - ((_i)->size >= KDBUS_ITEM_HEADER_SIZE && \ --- -2.4.3 - - -From 212de70178064a60afb6fa1ca0c1ed865ebab0ad Mon Sep 17 00:00:00 2001 -From: Sergei Zviagintsev <sergei@s15v.net> -Date: Wed, 10 Jun 2015 00:00:01 +0300 -Subject: [PATCH 068/132] Documentation/kdbus: fix operator precedence issue in - KDBUS_ITEM_NEXT macro - -`item' argument in KDBUS_ITEM_NEXT macro example is not enclosed into -parentheses when the cast operator is applied, which leads to improper -type conversion if `item' is supplied as a complex expression, e.g. - - KDBUS_ITEM_NEXT(condition ? a : b) - -Use parentheses properly to guarantee right precedence. - -Signed-off-by: Sergei Zviagintsev <sergei@s15v.net> -Reviewed-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - Documentation/kdbus/kdbus.item.xml | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/Documentation/kdbus/kdbus.item.xml b/Documentation/kdbus/kdbus.item.xml -index 09f8b903116f..b0eeeef995af 100644 ---- a/Documentation/kdbus/kdbus.item.xml -+++ b/Documentation/kdbus/kdbus.item.xml -@@ -69,7 +69,7 @@ - #define KDBUS_ALIGN8(val) (((val) + 7) & ~7) - - #define KDBUS_ITEM_NEXT(item) \ -- (typeof(item))(((uint8_t *)item) + KDBUS_ALIGN8((item)->size)) -+ (typeof(item))((uint8_t *)(item) + KDBUS_ALIGN8((item)->size)) - - #define KDBUS_ITEM_FOREACH(item, head, first) \ - for (item = (head)->first; \ --- -2.4.3 - - -From 4cb75ab413ae6f0d54d94084dd747d8521fa7776 Mon Sep 17 00:00:00 2001 -From: Sergei Zviagintsev <sergei@s15v.net> -Date: Wed, 10 Jun 2015 00:00:02 +0300 -Subject: [PATCH 069/132] Documentation/kdbus: use parentheses uniformly in - KDBUS_ITEM_FOREACH macro - -Enclose all arguments into parentheses to stay consistent across the -whole macro. - -Signed-off-by: Sergei Zviagintsev <sergei@s15v.net> -Reviewed-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - Documentation/kdbus/kdbus.item.xml | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/Documentation/kdbus/kdbus.item.xml b/Documentation/kdbus/kdbus.item.xml -index b0eeeef995af..ee09dfa443b8 100644 ---- a/Documentation/kdbus/kdbus.item.xml -+++ b/Documentation/kdbus/kdbus.item.xml -@@ -72,10 +72,10 @@ - (typeof(item))((uint8_t *)(item) + KDBUS_ALIGN8((item)->size)) - - #define KDBUS_ITEM_FOREACH(item, head, first) \ -- for (item = (head)->first; \ -+ for ((item) = (head)->first; \ - ((uint8_t *)(item) < (uint8_t *)(head) + (head)->size) && \ - ((uint8_t *)(item) >= (uint8_t *)(head)); \ -- item = KDBUS_ITEM_NEXT(item)) -+ (item) = KDBUS_ITEM_NEXT(item)) - ]]></programlisting> - </refsect2> - </refsect1> --- -2.4.3 - - -From 95402929419fde796fdd763ab9f288d22abac3f7 Mon Sep 17 00:00:00 2001 -From: Sergei Zviagintsev <sergei@s15v.net> -Date: Wed, 10 Jun 2015 00:00:03 +0300 -Subject: [PATCH 070/132] selftests/kdbus: fix trivial style issues - -Signed-off-by: Sergei Zviagintsev <sergei@s15v.net> -Reviewed-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - tools/testing/selftests/kdbus/kdbus-enum.h | 1 + - tools/testing/selftests/kdbus/kdbus-util.c | 2 +- - tools/testing/selftests/kdbus/kdbus-util.h | 21 +++++++++------------ - 3 files changed, 11 insertions(+), 13 deletions(-) - -diff --git a/tools/testing/selftests/kdbus/kdbus-enum.h b/tools/testing/selftests/kdbus/kdbus-enum.h -index a67cec3512a7..ed28cca26906 100644 ---- a/tools/testing/selftests/kdbus/kdbus-enum.h -+++ b/tools/testing/selftests/kdbus/kdbus-enum.h -@@ -6,6 +6,7 @@ - * 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); -diff --git a/tools/testing/selftests/kdbus/kdbus-util.c b/tools/testing/selftests/kdbus/kdbus-util.c -index 9fac4b31536d..29a0cb1aace2 100644 ---- a/tools/testing/selftests/kdbus/kdbus-util.c -+++ b/tools/testing/selftests/kdbus/kdbus-util.c -@@ -1355,7 +1355,7 @@ static int all_ids_are_mapped(const char *path) - return 0; - } - --int all_uids_gids_are_mapped() -+int all_uids_gids_are_mapped(void) - { - int ret; - -diff --git a/tools/testing/selftests/kdbus/kdbus-util.h b/tools/testing/selftests/kdbus/kdbus-util.h -index 50ff07140bdd..b53b03f0565c 100644 ---- a/tools/testing/selftests/kdbus/kdbus-util.h -+++ b/tools/testing/selftests/kdbus/kdbus-util.h -@@ -7,6 +7,7 @@ - * Free Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. - */ -+ - #pragma once - - #define BIT(X) (1 << (X)) -@@ -30,24 +31,22 @@ - #define KDBUS_ITEM_FOREACH(item, head, first) \ - for (item = (head)->first; \ - ((uint8_t *)(item) < (uint8_t *)(head) + (head)->size) && \ -- ((uint8_t *)(item) >= (uint8_t *)(head)); \ -+ ((uint8_t *)(item) >= (uint8_t *)(head)); \ - item = KDBUS_ITEM_NEXT(item)) - #define KDBUS_FOREACH(iter, first, _size) \ - for (iter = (first); \ - ((uint8_t *)(iter) < (uint8_t *)(first) + (_size)) && \ - ((uint8_t *)(iter) >= (uint8_t *)(first)); \ -- iter = (void*)(((uint8_t *)iter) + KDBUS_ALIGN8((iter)->size))) -- -+ iter = (void *)(((uint8_t *)iter) + KDBUS_ALIGN8((iter)->size))) - --#define _KDBUS_ATTACH_BITS_SET_NR (__builtin_popcountll(_KDBUS_ATTACH_ALL)) -+#define _KDBUS_ATTACH_BITS_SET_NR (__builtin_popcountll(_KDBUS_ATTACH_ALL)) - - /* Sum of KDBUS_ITEM_* that reflects _KDBUS_ATTACH_ALL */ --#define KDBUS_ATTACH_ITEMS_TYPE_SUM \ -- ((((_KDBUS_ATTACH_BITS_SET_NR - 1) * \ -- ((_KDBUS_ATTACH_BITS_SET_NR - 1) + 1)) / 2 ) + \ -+#define KDBUS_ATTACH_ITEMS_TYPE_SUM \ -+ ((((_KDBUS_ATTACH_BITS_SET_NR - 1) * \ -+ ((_KDBUS_ATTACH_BITS_SET_NR - 1) + 1)) / 2) + \ - (_KDBUS_ITEM_ATTACH_BASE * _KDBUS_ATTACH_BITS_SET_NR)) - -- - #define POOL_SIZE (16 * 1024LU * 1024LU) - - #define UNPRIV_UID 65534 -@@ -207,14 +206,12 @@ int kdbus_add_match_id(struct kdbus_conn *conn, uint64_t cookie, - uint64_t type, uint64_t id); - int kdbus_add_match_empty(struct kdbus_conn *conn); - --int all_uids_gids_are_mapped(); -+int all_uids_gids_are_mapped(void); - int drop_privileges(uid_t uid, gid_t gid); - uint64_t now(clockid_t clock); - char *unique_name(const char *prefix); - --int userns_map_uid_gid(pid_t pid, -- const char *map_uid, -- const char *map_gid); -+int userns_map_uid_gid(pid_t pid, const char *map_uid, const char *map_gid); - int test_is_capable(int cap, ...); - int config_user_ns_is_enabled(void); - int config_auditsyscall_is_enabled(void); --- -2.4.3 - - -From da5813db5d0cb6db3fc92e381fd4d85ea0639daa Mon Sep 17 00:00:00 2001 -From: Sergei Zviagintsev <sergei@s15v.net> -Date: Wed, 10 Jun 2015 00:00:04 +0300 -Subject: [PATCH 071/132] selftests/kdbus: fix precedence issues in macros - -`item' argument in KDBUS_ITEM_NEXT macro is not enclosed into -parentheses when the cast operator is applied, which leads to improper -type conversion if `item' is supplied as a complex expression, e.g. - - KDBUS_ITEM_NEXT(condition ? a : b) - -RUN_CLONE_CHILD macro has similar issue, missing parentheses around -`clone_ret' when using indirection operator. - -Use parentheses properly to guarantee right precedence. - -Signed-off-by: Sergei Zviagintsev <sergei@s15v.net> -Reviewed-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - tools/testing/selftests/kdbus/kdbus-util.h | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/tools/testing/selftests/kdbus/kdbus-util.h b/tools/testing/selftests/kdbus/kdbus-util.h -index b53b03f0565c..df5721ee8f54 100644 ---- a/tools/testing/selftests/kdbus/kdbus-util.h -+++ b/tools/testing/selftests/kdbus/kdbus-util.h -@@ -27,7 +27,7 @@ - #define KDBUS_ITEM_SIZE(s) KDBUS_ALIGN8((s) + KDBUS_ITEM_HEADER_SIZE) - - #define KDBUS_ITEM_NEXT(item) \ -- (typeof(item))(((uint8_t *)item) + KDBUS_ALIGN8((item)->size)) -+ (typeof(item))((uint8_t *)(item) + KDBUS_ALIGN8((item)->size)) - #define KDBUS_ITEM_FOREACH(item, head, first) \ - for (item = (head)->first; \ - ((uint8_t *)(item) < (uint8_t *)(head) + (head)->size) && \ -@@ -104,7 +104,7 @@ extern int kdbus_util_verbose; - _setup_; \ - efd = eventfd(0, EFD_CLOEXEC); \ - ASSERT_RETURN(efd >= 0); \ -- *clone_ret = 0; \ -+ *(clone_ret) = 0; \ - pid = syscall(__NR_clone, flags, NULL); \ - if (pid == 0) { \ - eventfd_t event_status = 0; \ -@@ -129,7 +129,7 @@ extern int kdbus_util_verbose; - ret = TEST_OK; \ - } else { \ - ret = -errno; \ -- *clone_ret = -errno; \ -+ *(clone_ret) = -errno; \ - } \ - close(efd); \ - ret; \ --- -2.4.3 - - -From 241cbf64fe9f77fe597820f0960b61f627874884 Mon Sep 17 00:00:00 2001 -From: Sergei Zviagintsev <sergei@s15v.net> -Date: Wed, 10 Jun 2015 00:00:05 +0300 -Subject: [PATCH 072/132] selftests/kdbus: use parentheses in iteration macros - uniformly - -Enclose all arguments into parentheses in KDBUS_ITEM_FOREACH and -KDBUS_FOREACH macros to stay consistent across the whole macro. - -Signed-off-by: Sergei Zviagintsev <sergei@s15v.net> -Reviewed-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - tools/testing/selftests/kdbus/kdbus-util.h | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/tools/testing/selftests/kdbus/kdbus-util.h b/tools/testing/selftests/kdbus/kdbus-util.h -index df5721ee8f54..d1a0f1b4d0eb 100644 ---- a/tools/testing/selftests/kdbus/kdbus-util.h -+++ b/tools/testing/selftests/kdbus/kdbus-util.h -@@ -29,15 +29,15 @@ - #define KDBUS_ITEM_NEXT(item) \ - (typeof(item))((uint8_t *)(item) + KDBUS_ALIGN8((item)->size)) - #define KDBUS_ITEM_FOREACH(item, head, first) \ -- for (item = (head)->first; \ -+ for ((item) = (head)->first; \ - ((uint8_t *)(item) < (uint8_t *)(head) + (head)->size) && \ - ((uint8_t *)(item) >= (uint8_t *)(head)); \ -- item = KDBUS_ITEM_NEXT(item)) -+ (item) = KDBUS_ITEM_NEXT(item)) - #define KDBUS_FOREACH(iter, first, _size) \ -- for (iter = (first); \ -+ for ((iter) = (first); \ - ((uint8_t *)(iter) < (uint8_t *)(first) + (_size)) && \ - ((uint8_t *)(iter) >= (uint8_t *)(first)); \ -- iter = (void *)(((uint8_t *)iter) + KDBUS_ALIGN8((iter)->size))) -+ (iter) = (void *)((uint8_t *)(iter) + KDBUS_ALIGN8((iter)->size))) - - #define _KDBUS_ATTACH_BITS_SET_NR (__builtin_popcountll(_KDBUS_ATTACH_ALL)) - --- -2.4.3 - - -From faba978ced06bf21cdc701034222085f79e2f632 Mon Sep 17 00:00:00 2001 -From: Sergei Zviagintsev <sergei@s15v.net> -Date: Wed, 10 Jun 2015 00:00:06 +0300 -Subject: [PATCH 073/132] samples/kdbus: add whitespace - -Signed-off-by: Sergei Zviagintsev <sergei@s15v.net> -Reviewed-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - samples/kdbus/kdbus-api.h | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/samples/kdbus/kdbus-api.h b/samples/kdbus/kdbus-api.h -index 5ed5907c5cb4..2de4d6a8c51e 100644 ---- a/samples/kdbus/kdbus-api.h -+++ b/samples/kdbus/kdbus-api.h -@@ -13,7 +13,7 @@ - for (iter = (first); \ - ((uint8_t *)(iter) < (uint8_t *)(first) + (_size)) && \ - ((uint8_t *)(iter) >= (uint8_t *)(first)); \ -- iter = (void*)(((uint8_t *)iter) + KDBUS_ALIGN8((iter)->size))) -+ iter = (void *)(((uint8_t *)iter) + KDBUS_ALIGN8((iter)->size))) - - static inline int kdbus_cmd_bus_make(int control_fd, struct kdbus_cmd *cmd) - { --- -2.4.3 - - -From e7841b776fc00419da991c5ccdc938193b939743 Mon Sep 17 00:00:00 2001 -From: Sergei Zviagintsev <sergei@s15v.net> -Date: Wed, 10 Jun 2015 00:00:07 +0300 -Subject: [PATCH 074/132] samples/kdbus: fix operator precedence issue in - KDBUS_ITEM_NEXT macro - -`item' argument in KDBUS_ITEM_NEXT macro is not enclosed into -parentheses when the cast operator is applied, which leads to improper -type conversion if `item' is supplied as a complex expression, e.g. - - KDBUS_ITEM_NEXT(condition ? a : b) - -Use parentheses properly to guarantee right precedence. - -Signed-off-by: Sergei Zviagintsev <sergei@s15v.net> -Reviewed-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - samples/kdbus/kdbus-api.h | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/samples/kdbus/kdbus-api.h b/samples/kdbus/kdbus-api.h -index 2de4d6a8c51e..fab873b89d97 100644 ---- a/samples/kdbus/kdbus-api.h -+++ b/samples/kdbus/kdbus-api.h -@@ -8,7 +8,7 @@ - #define KDBUS_ITEM_HEADER_SIZE offsetof(struct kdbus_item, data) - #define KDBUS_ITEM_SIZE(s) KDBUS_ALIGN8((s) + KDBUS_ITEM_HEADER_SIZE) - #define KDBUS_ITEM_NEXT(item) \ -- (typeof(item))(((uint8_t *)item) + KDBUS_ALIGN8((item)->size)) -+ (typeof(item))((uint8_t *)(item) + KDBUS_ALIGN8((item)->size)) - #define KDBUS_FOREACH(iter, first, _size) \ - for (iter = (first); \ - ((uint8_t *)(iter) < (uint8_t *)(first) + (_size)) && \ --- -2.4.3 - - -From 221166e11530c205e3e3e23fbf06519858af3615 Mon Sep 17 00:00:00 2001 -From: Sergei Zviagintsev <sergei@s15v.net> -Date: Wed, 10 Jun 2015 00:00:08 +0300 -Subject: [PATCH 075/132] samples/kdbus: use parentheses uniformly in - KDBUS_FOREACH macro - -Enclose all arguments into parentheses to stay consistent across the -whole macro. - -Signed-off-by: Sergei Zviagintsev <sergei@s15v.net> -Reviewed-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - samples/kdbus/kdbus-api.h | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/samples/kdbus/kdbus-api.h b/samples/kdbus/kdbus-api.h -index fab873b89d97..7f3abae18396 100644 ---- a/samples/kdbus/kdbus-api.h -+++ b/samples/kdbus/kdbus-api.h -@@ -10,10 +10,10 @@ - #define KDBUS_ITEM_NEXT(item) \ - (typeof(item))((uint8_t *)(item) + KDBUS_ALIGN8((item)->size)) - #define KDBUS_FOREACH(iter, first, _size) \ -- for (iter = (first); \ -+ for ((iter) = (first); \ - ((uint8_t *)(iter) < (uint8_t *)(first) + (_size)) && \ - ((uint8_t *)(iter) >= (uint8_t *)(first)); \ -- iter = (void *)(((uint8_t *)iter) + KDBUS_ALIGN8((iter)->size))) -+ (iter) = (void *)((uint8_t *)(iter) + KDBUS_ALIGN8((iter)->size))) - - static inline int kdbus_cmd_bus_make(int control_fd, struct kdbus_cmd *cmd) - { --- -2.4.3 - - -From 053ebc09cd130ff6a3dd08b28c6123c0f7410090 Mon Sep 17 00:00:00 2001 -From: Sergei Zviagintsev <sergei@s15v.net> -Date: Wed, 17 Jun 2015 20:14:56 +0300 -Subject: [PATCH 076/132] kdbus: kdbus_reply_find(): return on found entry - -Return found entry immediately instead of assigning it to additional -variable and breaking the loop. It's simpler to read, the same way is -used in kdbus_conn_has_name(), for example. - -Signed-off-by: Sergei Zviagintsev <sergei@s15v.net> -Reviewed-by: David Herrmann <dh.herrmann@gmail.com> -Reviewed-by: Djalal Harouni <tixxdz@opendz.org> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - ipc/kdbus/reply.c | 10 ++++------ - 1 file changed, 4 insertions(+), 6 deletions(-) - -diff --git a/ipc/kdbus/reply.c b/ipc/kdbus/reply.c -index 89d355b44f63..9d823ebee71f 100644 ---- a/ipc/kdbus/reply.c -+++ b/ipc/kdbus/reply.c -@@ -171,17 +171,15 @@ struct kdbus_reply *kdbus_reply_find(struct kdbus_conn *replying, - struct kdbus_conn *reply_dst, - u64 cookie) - { -- struct kdbus_reply *r, *reply = NULL; -+ struct kdbus_reply *r; - - list_for_each_entry(r, &reply_dst->reply_list, entry) { - if (r->cookie == cookie && -- (!replying || r->reply_src == replying)) { -- reply = r; -- break; -- } -+ (!replying || r->reply_src == replying)) -+ return r; - } - -- return reply; -+ return NULL; - } - - /** --- -2.4.3 - - -From 650e5e551cc45de5d54731d79fcbd429dfed53c4 Mon Sep 17 00:00:00 2001 -From: Sergei Zviagintsev <sergei@s15v.net> -Date: Wed, 17 Jun 2015 20:14:57 +0300 -Subject: [PATCH 077/132] kdbus: optimize error path in kdbus_reply_new() - -Move cleanup code to separate location as it never executes on normal -flow. This removes extra if-block and the need to initialize `ret'. - -Signed-off-by: Sergei Zviagintsev <sergei@s15v.net> -Reviewed-by: David Herrmann <dh.herrmann@gmail.com> -Reviewed-by: Djalal Harouni <tixxdz@opendz.org> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - ipc/kdbus/reply.c | 12 +++++------- - 1 file changed, 5 insertions(+), 7 deletions(-) - -diff --git a/ipc/kdbus/reply.c b/ipc/kdbus/reply.c -index 9d823ebee71f..e6791d86ec92 100644 ---- a/ipc/kdbus/reply.c -+++ b/ipc/kdbus/reply.c -@@ -37,7 +37,7 @@ struct kdbus_reply *kdbus_reply_new(struct kdbus_conn *reply_src, - bool sync) - { - struct kdbus_reply *r; -- int ret = 0; -+ int ret; - - if (atomic_inc_return(&reply_dst->request_count) > - KDBUS_CONN_MAX_REQUESTS_PENDING) { -@@ -64,13 +64,11 @@ struct kdbus_reply *kdbus_reply_new(struct kdbus_conn *reply_src, - r->waiting = true; - } - --exit_dec_request_count: -- if (ret < 0) { -- atomic_dec(&reply_dst->request_count); -- return ERR_PTR(ret); -- } -- - return r; -+ -+exit_dec_request_count: -+ atomic_dec(&reply_dst->request_count); -+ return ERR_PTR(ret); - } - - static void __kdbus_reply_free(struct kref *kref) --- -2.4.3 - - -From b69af624a0d1d43a7c52e1a907ee97bfa0fc79bb Mon Sep 17 00:00:00 2001 -From: Sergei Zviagintsev <sergei@s15v.net> -Date: Wed, 17 Jun 2015 20:14:58 +0300 -Subject: [PATCH 078/132] kdbus: optimize if statements in - kdbus_conn_disconnect() - -if (r->sync) branch and code after it both call kdbus_reply_unlink(). -Rewrite them as if-else to eliminate code duplication and make algorithm -more obvious. - -Convert outer if statement to use continue in order to reduce -indentation and make things easier to read. - -Signed-off-by: Sergei Zviagintsev <sergei@s15v.net> -Reviewed-by: David Herrmann <dh.herrmann@gmail.com> -Reviewed-by: Djalal Harouni <tixxdz@opendz.org> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - ipc/kdbus/connection.c | 15 +++++++-------- - 1 file changed, 7 insertions(+), 8 deletions(-) - -diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c -index 707be050b408..9993753d11de 100644 ---- a/ipc/kdbus/connection.c -+++ b/ipc/kdbus/connection.c -@@ -559,17 +559,16 @@ int kdbus_conn_disconnect(struct kdbus_conn *conn, bool ensure_queue_empty) - hash_for_each(bus->conn_hash, i, c, hentry) { - mutex_lock(&c->lock); - list_for_each_entry_safe(r, r_tmp, &c->reply_list, entry) { -- if (r->reply_src == conn) { -- if (r->sync) { -- kdbus_sync_reply_wakeup(r, -EPIPE); -- kdbus_reply_unlink(r); -- continue; -- } -+ if (r->reply_src != conn) -+ continue; - -+ if (r->sync) -+ kdbus_sync_reply_wakeup(r, -EPIPE); -+ else - /* send a 'connection dead' notification */ - kdbus_notify_reply_dead(bus, c->id, r->cookie); -- kdbus_reply_unlink(r); -- } -+ -+ kdbus_reply_unlink(r); - } - mutex_unlock(&c->lock); - } --- -2.4.3 - - -From 7d894da303164a38522eaac6e95ee558423b9272 Mon Sep 17 00:00:00 2001 -From: Markus Elfring <elfring@users.sourceforge.net> -Date: Wed, 24 Jun 2015 14:30:17 +0200 -Subject: [PATCH 079/132] kdbus: delete unnecessary check before - kdbus_domain_unref - -The kdbus_domain_unref() function tests whether its argument is NULL -and then returns immediately. Thus the test around the call is not needed. - -This issue was detected by using the Coccinelle software. - -Signed-off-by: Markus Elfring <elfring@users.sourceforge.net> -Reviewed-by: David Herrmann <dh.herrmann@gmail.com> -(shorten commit-message-head slightly) -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> ---- - ipc/kdbus/fs.c | 4 +--- - 1 file changed, 1 insertion(+), 3 deletions(-) - -diff --git a/ipc/kdbus/fs.c b/ipc/kdbus/fs.c -index d01f33baaa0d..205a3adaa2ab 100644 ---- a/ipc/kdbus/fs.c -+++ b/ipc/kdbus/fs.c -@@ -325,9 +325,7 @@ static void fs_super_kill(struct super_block *sb) - } - - kill_anon_super(sb); -- -- if (domain) -- kdbus_domain_unref(domain); -+ kdbus_domain_unref(domain); - } - - static int fs_super_set(struct super_block *sb, void *data) --- -2.4.3 - - -From b57a271a7a2c5bac0fdfa848481bca55dc1d1336 Mon Sep 17 00:00:00 2001 -From: Sergei Zviagintsev <sergei@s15v.net> -Date: Sun, 28 Jun 2015 16:17:30 +0300 -Subject: [PATCH 080/132] kdbus: fix typos in kdbus_conn_quota_inc() - -Signed-off-by: Sergei Zviagintsev <sergei@s15v.net> -Reviewed-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> ---- - ipc/kdbus/connection.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c -index 9993753d11de..df072487e23c 100644 ---- a/ipc/kdbus/connection.c -+++ b/ipc/kdbus/connection.c -@@ -646,7 +646,7 @@ int kdbus_conn_quota_inc(struct kdbus_conn *c, struct kdbus_user *u, - * allocation schemes. Furthermore, resource utilization should be - * maximized, so only minimal resources stay reserved. However, we need - * to adapt to a dynamic number of users, as we cannot know how many -- * users will talk to a connection. Therefore, the current allocations -+ * users will talk to a connection. Therefore, the current allocation - * works like this: - * We limit the number of bytes in a destination's pool per sending - * user. The space available for a user is 33% of the unused pool space -@@ -688,7 +688,7 @@ int kdbus_conn_quota_inc(struct kdbus_conn *c, struct kdbus_user *u, - - /* - * Pool owner slices are un-accounted slices; they can claim more -- * than 50% of the queue. However, the slice we're dealing with here -+ * than 50% of the queue. However, the slices we're dealing with here - * belong to the incoming queue, hence they are 'accounted' slices - * to which the 50%-limit applies. - */ --- -2.4.3 - - -From c1bddc44862c977384e66aea1d2be7ded9fb0f0e Mon Sep 17 00:00:00 2001 -From: Sergei Zviagintsev <sergei@s15v.net> -Date: Sun, 28 Jun 2015 16:17:31 +0300 -Subject: [PATCH 081/132] kdbus: use standard kernel types in struct - kdbus_quota - -uint{8,16,32}_t -> u{8,16,32} - -Signed-off-by: Sergei Zviagintsev <sergei@s15v.net> -Reviewed-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> ---- - ipc/kdbus/connection.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c -index df072487e23c..af044f93c14f 100644 ---- a/ipc/kdbus/connection.c -+++ b/ipc/kdbus/connection.c -@@ -606,9 +606,9 @@ bool kdbus_conn_has_name(struct kdbus_conn *conn, const char *name) - } - - struct kdbus_quota { -- uint32_t memory; -- uint16_t msgs; -- uint8_t fds; -+ u32 memory; -+ u16 msgs; -+ u8 fds; - }; - - /** --- -2.4.3 - - -From eb526cf227f121c8320275dde32d18495631a622 Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Tue, 9 Jun 2015 09:41:40 +0200 -Subject: [PATCH 082/132] kdbus/selftests: fix CAP translation tests - -We now support CAP translations. Make sure our tests reflect that. So far -they made sure we drop CAPS on namespace borders. This is wrong, though. -We really need to just make sure that no _or_ the correctly translated -caps are returned. Fix this. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> ---- - tools/testing/selftests/kdbus/test-metadata-ns.c | 9 +++------ - 1 file changed, 3 insertions(+), 6 deletions(-) - -diff --git a/tools/testing/selftests/kdbus/test-metadata-ns.c b/tools/testing/selftests/kdbus/test-metadata-ns.c -index ccdfae06922b..1f6edc09008a 100644 ---- a/tools/testing/selftests/kdbus/test-metadata-ns.c -+++ b/tools/testing/selftests/kdbus/test-metadata-ns.c -@@ -168,9 +168,8 @@ static int __kdbus_clone_userns_test(const char *bus, - ASSERT_EXIT(ret == 0); - ASSERT_EXIT(msg->dst_id == userns_conn->id); - -- /* Different namespaces no CAPS */ - item = kdbus_get_item(msg, KDBUS_ITEM_CAPS); -- ASSERT_EXIT(item == NULL); -+ ASSERT_EXIT(item); - - /* uid/gid not mapped, so we have unpriv cached creds */ - ret = kdbus_match_kdbus_creds(msg, &unmapped_creds); -@@ -196,9 +195,8 @@ static int __kdbus_clone_userns_test(const char *bus, - ASSERT_EXIT(ret == 0); - ASSERT_EXIT(msg->dst_id == KDBUS_DST_ID_BROADCAST); - -- /* Different namespaces no CAPS */ - item = kdbus_get_item(msg, KDBUS_ITEM_CAPS); -- ASSERT_EXIT(item == NULL); -+ ASSERT_EXIT(item); - - /* uid/gid not mapped, so we have unpriv cached creds */ - ret = kdbus_match_kdbus_creds(msg, &unmapped_creds); -@@ -358,9 +356,8 @@ static int kdbus_clone_userns_test(const char *bus, - - userns_conn_id = msg->src_id; - -- /* We do not share the userns, os no KDBUS_ITEM_CAPS */ - item = kdbus_get_item(msg, KDBUS_ITEM_CAPS); -- ASSERT_RETURN(item == NULL); -+ ASSERT_RETURN(item); - - /* - * Compare received items, creds must be translated into --- -2.4.3 - - -From 42c6f60d15f3a359e0d779f7af4a8ee51144e16d Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Mon, 15 Jun 2015 12:20:28 +0200 -Subject: [PATCH 083/132] kdbus: drop redundant KDBUS_MSG_MAX_ITEMS - -We already limit the size of the message object, there's no reason to add -an arbitrary additional limit on the number of items. We don't do this for -other item-arrays, so lets stop restricting the messages in this way. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> ---- - ipc/kdbus/limits.h | 3 --- - ipc/kdbus/message.c | 12 ++++-------- - 2 files changed, 4 insertions(+), 11 deletions(-) - -diff --git a/ipc/kdbus/limits.h b/ipc/kdbus/limits.h -index 6450f58cffcf..c54925a25971 100644 ---- a/ipc/kdbus/limits.h -+++ b/ipc/kdbus/limits.h -@@ -19,9 +19,6 @@ - /* maximum size of message header and items */ - #define KDBUS_MSG_MAX_SIZE SZ_8K - --/* maximum number of message items */ --#define KDBUS_MSG_MAX_ITEMS 128 -- - /* maximum number of memfd items per message */ - #define KDBUS_MSG_MAX_MEMFD_ITEMS 16 - -diff --git a/ipc/kdbus/message.c b/ipc/kdbus/message.c -index 066e816dfdea..e9da67229eb1 100644 ---- a/ipc/kdbus/message.c -+++ b/ipc/kdbus/message.c -@@ -214,7 +214,7 @@ static int kdbus_msg_scan_items(struct kdbus_kmsg *kmsg, - struct kdbus_msg_resources *res = kmsg->res; - const struct kdbus_msg *msg = &kmsg->msg; - const struct kdbus_item *item; -- size_t n, n_vecs, n_memfds; -+ size_t n_res, n_vecs, n_memfds; - bool has_bloom = false; - bool has_name = false; - bool has_fds = false; -@@ -243,9 +243,9 @@ static int kdbus_msg_scan_items(struct kdbus_kmsg *kmsg, - } - } - -- n = n_vecs + n_memfds; -- if (n > 0) { -- res->data = kcalloc(n, sizeof(*res->data), GFP_KERNEL); -+ n_res = n_vecs + n_memfds; -+ if (n_res > 0) { -+ res->data = kcalloc(n_res, sizeof(*res->data), GFP_KERNEL); - if (!res->data) - return -ENOMEM; - } -@@ -257,15 +257,11 @@ static int kdbus_msg_scan_items(struct kdbus_kmsg *kmsg, - } - - /* import data payloads */ -- n = 0; - vec_size = 0; - KDBUS_ITEMS_FOREACH(item, msg->items, KDBUS_ITEMS_SIZE(msg, items)) { - size_t payload_size = KDBUS_ITEM_PAYLOAD_SIZE(item); - struct iovec *iov = kmsg->iov + kmsg->iov_count; - -- if (++n > KDBUS_MSG_MAX_ITEMS) -- return -E2BIG; -- - switch (item->type) { - case KDBUS_ITEM_PAYLOAD_VEC: { - struct kdbus_msg_data *d = res->data + res->data_count; --- -2.4.3 - - -From 80c15dbf8b5eff74a41ceae7d83e9fcf8abf9df9 Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Fri, 19 Jun 2015 17:08:08 +0200 -Subject: [PATCH 084/132] kdbus: drop unused 'bloom_generation' field - -This field is never used, drop it. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> ---- - ipc/kdbus/message.h | 2 -- - 1 file changed, 2 deletions(-) - -diff --git a/ipc/kdbus/message.h b/ipc/kdbus/message.h -index cdaa65c4e6ae..3b733474f335 100644 ---- a/ipc/kdbus/message.h -+++ b/ipc/kdbus/message.h -@@ -88,7 +88,6 @@ kdbus_msg_resources_unref(struct kdbus_msg_resources *r); - * @notify_name: Short-cut for faster lookup - * @dst_name_id: Short-cut to msg for faster lookup - * @bloom_filter: Bloom filter to match message properties -- * @bloom_generation: Generation of bloom element set - * @notify_entry: List of kernel-generated notifications - * @iov: Array of iovec, describing the payload to copy - * @iov_count: Number of array members in @iov -@@ -107,7 +106,6 @@ struct kdbus_kmsg { - - u64 dst_name_id; - const struct kdbus_bloom_filter *bloom_filter; -- u64 bloom_generation; - struct list_head notify_entry; - - struct iovec *iov; --- -2.4.3 - - -From fb1fa875dc1df36250e92085b914d9d5c5e952d3 Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Fri, 5 Jun 2015 15:30:40 +0200 -Subject: [PATCH 085/132] kdbus: drop support for required attach-flags on - buses - -This drops the KDBUS_ITEM_ATTACH_FLAGS_RECV item from KDBUS_CMD_BUS_MAKE. -This item was used to provide an attach-flags mask which defines metadata -items that all connections must have in their send-mask. Hence, -effectively forcing the transmission of such items in case the receiver -wants them. - -This was never used by any code and is of questionable use. With our new -effort to make sure metadata items are only transmitted if the receiver -has actual access to the same data via /proc, this is no longer needed. -Drop support for this item now. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> ---- - Documentation/kdbus/kdbus.bus.xml | 15 --------------- - Documentation/kdbus/kdbus.connection.xml | 8 +------- - ipc/kdbus/bus.c | 10 ---------- - ipc/kdbus/bus.h | 2 -- - ipc/kdbus/connection.c | 10 ---------- - tools/testing/selftests/kdbus/kdbus-test.c | 1 - - tools/testing/selftests/kdbus/kdbus-util.c | 20 +++++++------------- - tools/testing/selftests/kdbus/kdbus-util.h | 3 +-- - tools/testing/selftests/kdbus/test-connection.c | 9 --------- - 9 files changed, 9 insertions(+), 69 deletions(-) - -diff --git a/Documentation/kdbus/kdbus.bus.xml b/Documentation/kdbus/kdbus.bus.xml -index 4b9a0ac1b351..83f1198bc6a1 100644 ---- a/Documentation/kdbus/kdbus.bus.xml -+++ b/Documentation/kdbus/kdbus.bus.xml -@@ -198,21 +198,6 @@ struct kdbus_cmd { - </varlistentry> - - <varlistentry> -- <term><constant>KDBUS_ITEM_ATTACH_FLAGS_RECV</constant></term> -- <listitem> -- <para> -- An optional item that contains a set of required attach flags -- that connections must allow. This item is used as a -- negotiation measure during connection creation. If connections -- do not satisfy the bus requirements, they are not allowed on -- the bus. If not set, the bus does not require any metadata to -- be attached; in this case connections are free to set their -- own attach flags. -- </para> -- </listitem> -- </varlistentry> -- -- <varlistentry> - <term><constant>KDBUS_ITEM_ATTACH_FLAGS_SEND</constant></term> - <listitem> - <para> -diff --git a/Documentation/kdbus/kdbus.connection.xml b/Documentation/kdbus/kdbus.connection.xml -index cefb419f1093..4bb5f30f379a 100644 ---- a/Documentation/kdbus/kdbus.connection.xml -+++ b/Documentation/kdbus/kdbus.connection.xml -@@ -355,13 +355,7 @@ struct kdbus_cmd_hello { - 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 be attached -- to the message. Note, however, that the bus may optionally require -- some of those bits to be set. If the match fails, the ioctl will fail -- with <varname>errno</varname> set to -- <constant>ECONNREFUSED</constant>. In either case, when returning the -- field will be set to the mask of metadata items that are enforced by -- the bus with the <constant>KDBUS_FLAGS_KERNEL</constant> bit set as -- well. -+ to the message. - </para></listitem> - </varlistentry> - -diff --git a/ipc/kdbus/bus.c b/ipc/kdbus/bus.c -index bbdf0f2f391e..7d2c336213ad 100644 ---- a/ipc/kdbus/bus.c -+++ b/ipc/kdbus/bus.c -@@ -66,23 +66,16 @@ static struct kdbus_bus *kdbus_bus_new(struct kdbus_domain *domain, - const char *name, - struct kdbus_bloom_parameter *bloom, - const u64 *pattach_owner, -- const u64 *pattach_recv, - u64 flags, kuid_t uid, kgid_t gid) - { - struct kdbus_bus *b; - u64 attach_owner; -- u64 attach_recv; - int ret; - - if (bloom->size < 8 || bloom->size > KDBUS_BUS_BLOOM_MAX_SIZE || - !KDBUS_IS_ALIGNED8(bloom->size) || bloom->n_hash < 1) - return ERR_PTR(-EINVAL); - -- ret = kdbus_sanitize_attach_flags(pattach_recv ? *pattach_recv : 0, -- &attach_recv); -- if (ret < 0) -- return ERR_PTR(ret); -- - ret = kdbus_sanitize_attach_flags(pattach_owner ? *pattach_owner : 0, - &attach_owner); - if (ret < 0) -@@ -111,7 +104,6 @@ static struct kdbus_bus *kdbus_bus_new(struct kdbus_domain *domain, - - b->id = atomic64_inc_return(&domain->last_id); - b->bus_flags = flags; -- b->attach_flags_req = attach_recv; - b->attach_flags_owner = attach_owner; - generate_random_uuid(b->id128); - b->bloom = *bloom; -@@ -380,7 +372,6 @@ struct kdbus_bus *kdbus_cmd_bus_make(struct kdbus_domain *domain, - { .type = KDBUS_ITEM_MAKE_NAME, .mandatory = true }, - { .type = KDBUS_ITEM_BLOOM_PARAMETER, .mandatory = true }, - { .type = KDBUS_ITEM_ATTACH_FLAGS_SEND }, -- { .type = KDBUS_ITEM_ATTACH_FLAGS_RECV }, - }; - struct kdbus_args args = { - .allowed_flags = KDBUS_FLAG_NEGOTIATE | -@@ -399,7 +390,6 @@ struct kdbus_bus *kdbus_cmd_bus_make(struct kdbus_domain *domain, - bus = kdbus_bus_new(domain, - argv[1].item->str, &argv[2].item->bloom_parameter, - argv[3].item ? argv[3].item->data64 : NULL, -- argv[4].item ? argv[4].item->data64 : NULL, - cmd->flags, current_euid(), current_egid()); - if (IS_ERR(bus)) { - ret = PTR_ERR(bus); -diff --git a/ipc/kdbus/bus.h b/ipc/kdbus/bus.h -index 5bea5ef768f1..e019ef34534c 100644 ---- a/ipc/kdbus/bus.h -+++ b/ipc/kdbus/bus.h -@@ -37,7 +37,6 @@ struct kdbus_user; - * @node: kdbus_node - * @id: ID of this bus in the domain - * @bus_flags: Simple pass-through flags from userspace to userspace -- * @attach_flags_req: KDBUS_ATTACH_* flags required by connecting peers - * @attach_flags_owner: KDBUS_ATTACH_* flags of bus creator that other - * connections can see or query - * @id128: Unique random 128 bit ID of this bus -@@ -60,7 +59,6 @@ struct kdbus_bus { - /* static */ - u64 id; - u64 bus_flags; -- u64 attach_flags_req; - u64 attach_flags_owner; - u8 id128[16]; - struct kdbus_bloom_parameter bloom; -diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c -index af044f93c14f..02e3ce735034 100644 ---- a/ipc/kdbus/connection.c -+++ b/ipc/kdbus/connection.c -@@ -112,10 +112,6 @@ static struct kdbus_conn *kdbus_conn_new(struct kdbus_ep *ep, bool privileged, - if (ret < 0) - return ERR_PTR(ret); - -- /* The attach flags must always satisfy the bus requirements. */ -- if (bus->attach_flags_req & ~attach_flags_send) -- return ERR_PTR(-ECONNREFUSED); -- - conn = kzalloc(sizeof(*conn), GFP_KERNEL); - if (!conn) - return ERR_PTR(-ENOMEM); -@@ -1835,7 +1831,6 @@ exit: - */ - int kdbus_cmd_update(struct kdbus_conn *conn, void __user *argp) - { -- struct kdbus_bus *bus = conn->ep->bus; - struct kdbus_item *item_policy; - u64 *item_attach_send = NULL; - u64 *item_attach_recv = NULL; -@@ -1876,11 +1871,6 @@ int kdbus_cmd_update(struct kdbus_conn *conn, void __user *argp) - &attach_send); - if (ret < 0) - goto exit; -- -- if (bus->attach_flags_req & ~attach_send) { -- ret = -EINVAL; -- goto exit; -- } - } - - if (item_attach_recv) { -diff --git a/tools/testing/selftests/kdbus/kdbus-test.c b/tools/testing/selftests/kdbus/kdbus-test.c -index 294e82a83ab6..db732e59650a 100644 ---- a/tools/testing/selftests/kdbus/kdbus-test.c -+++ b/tools/testing/selftests/kdbus/kdbus-test.c -@@ -299,7 +299,6 @@ static int test_prepare_env(const struct kdbus_test *t, - - ret = kdbus_create_bus(env->control_fd, - args->busname ?: n, -- _KDBUS_ATTACH_ALL, - _KDBUS_ATTACH_ALL, &s); - free(n); - ASSERT_RETURN(ret == 0); -diff --git a/tools/testing/selftests/kdbus/kdbus-util.c b/tools/testing/selftests/kdbus/kdbus-util.c -index 29a0cb1aace2..a5e54ca3a492 100644 ---- a/tools/testing/selftests/kdbus/kdbus-util.c -+++ b/tools/testing/selftests/kdbus/kdbus-util.c -@@ -114,8 +114,7 @@ int kdbus_sysfs_set_parameter_mask(const char *path, uint64_t mask) - } - - int kdbus_create_bus(int control_fd, const char *name, -- uint64_t req_meta, uint64_t owner_meta, -- char **path) -+ uint64_t owner_meta, char **path) - { - struct { - struct kdbus_cmd cmd; -@@ -127,12 +126,12 @@ int kdbus_create_bus(int control_fd, const char *name, - struct kdbus_bloom_parameter bloom; - } bp; - -- /* required and owner metadata items */ -+ /* owner metadata items */ - struct { - uint64_t size; - uint64_t type; - uint64_t flags; -- } attach[2]; -+ } attach; - - /* name item */ - struct { -@@ -152,13 +151,9 @@ int kdbus_create_bus(int control_fd, const char *name, - snprintf(bus_make.name.str, sizeof(bus_make.name.str), - "%u-%s", getuid(), name); - -- bus_make.attach[0].type = KDBUS_ITEM_ATTACH_FLAGS_RECV; -- bus_make.attach[0].size = sizeof(bus_make.attach[0]); -- bus_make.attach[0].flags = req_meta; -- -- bus_make.attach[1].type = KDBUS_ITEM_ATTACH_FLAGS_SEND; -- bus_make.attach[1].size = sizeof(bus_make.attach[0]); -- bus_make.attach[1].flags = owner_meta; -+ bus_make.attach.type = KDBUS_ITEM_ATTACH_FLAGS_SEND; -+ bus_make.attach.size = sizeof(bus_make.attach); -+ bus_make.attach.flags = owner_meta; - - bus_make.name.type = KDBUS_ITEM_MAKE_NAME; - bus_make.name.size = KDBUS_ITEM_HEADER_SIZE + -@@ -167,8 +162,7 @@ int kdbus_create_bus(int control_fd, const char *name, - bus_make.cmd.flags = KDBUS_MAKE_ACCESS_WORLD; - bus_make.cmd.size = sizeof(bus_make.cmd) + - bus_make.bp.size + -- bus_make.attach[0].size + -- bus_make.attach[1].size + -+ bus_make.attach.size + - bus_make.name.size; - - kdbus_printf("Creating bus with name >%s< on control fd %d ...\n", -diff --git a/tools/testing/selftests/kdbus/kdbus-util.h b/tools/testing/selftests/kdbus/kdbus-util.h -index d1a0f1b4d0eb..e1e18b92f425 100644 ---- a/tools/testing/selftests/kdbus/kdbus-util.h -+++ b/tools/testing/selftests/kdbus/kdbus-util.h -@@ -168,8 +168,7 @@ int kdbus_free(const struct kdbus_conn *conn, uint64_t offset); - int kdbus_msg_dump(const struct kdbus_conn *conn, - const struct kdbus_msg *msg); - int kdbus_create_bus(int control_fd, const char *name, -- uint64_t req_meta, uint64_t owner_meta, -- char **path); -+ uint64_t owner_meta, char **path); - int kdbus_msg_send(const struct kdbus_conn *conn, const char *name, - uint64_t cookie, uint64_t flags, uint64_t timeout, - int64_t priority, uint64_t dst_id); -diff --git a/tools/testing/selftests/kdbus/test-connection.c b/tools/testing/selftests/kdbus/test-connection.c -index e7c486621b04..4688ce8ec40b 100644 ---- a/tools/testing/selftests/kdbus/test-connection.c -+++ b/tools/testing/selftests/kdbus/test-connection.c -@@ -70,15 +70,6 @@ int kdbus_test_hello(struct kdbus_test_env *env) - - hello.pool_size = POOL_SIZE; - -- /* -- * The connection created by the core requires ALL meta flags -- * to be sent. An attempt to send less than that should result in -- * -ECONNREFUSED. -- */ -- hello.attach_flags_send = _KDBUS_ATTACH_ALL & ~KDBUS_ATTACH_TIMESTAMP; -- ret = kdbus_cmd_hello(fd, &hello); -- ASSERT_RETURN(ret == -ECONNREFUSED); -- - hello.attach_flags_send = _KDBUS_ATTACH_ALL; - hello.offset = (__u64)-1; - --- -2.4.3 - - -From c2bc012ac7da42acdeb079cc1ef4ea25b67d0b74 Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Tue, 9 Jun 2015 09:43:47 +0200 -Subject: [PATCH 086/132] kdbus: pin namespaces on HELLO - -Whenever we send messages to a target connection, all we know about the -target is the 'struct file' associated with the kdbus connection. Hence, -we cannot know which namespaces a receiving process will be in when it -calls KDBUS_CMD_RECV on the message. So far, we pinned all metadata we -wanna send and translate it on RECV-time, since we then know the exact -namespaces to translate into. - -This has several drawbacks: - - Depending on the process calling RECV, the behavior is different (as - multiple processes might be in different namespaces but share the same - fd). This is unwanted behavior, as described by Eric here: - http://www.spinics.net/lists/netdev/msg329322.html - - We need to pin metadata with a message instead of translating it right - away. - - We cannot prep a message at SEND time as we don't know the size of the - translated metadata. Hence, we need to do all that at RECV time. - -This patch changes the namespace behavior. Instead of using the namespaces -at RECV time, we now pin the namespaces at HELLO (i.e., open()). So -regardless who calls RECV on this file-descriptor, the same namespaces -will be used. -This gives us the advantage that we now always know the target namespaces -for a message. Hence, we can now properly prep a message at SEND time and -never have to carry any metadata pins around. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> ---- - ipc/kdbus/bus.c | 2 +- - ipc/kdbus/connection.c | 8 +++++++- - ipc/kdbus/connection.h | 6 ++++++ - ipc/kdbus/metadata.c | 54 ++++++++++++++++++++++++++------------------------ - ipc/kdbus/metadata.h | 1 + - ipc/kdbus/queue.c | 1 + - 6 files changed, 44 insertions(+), 28 deletions(-) - -diff --git a/ipc/kdbus/bus.c b/ipc/kdbus/bus.c -index 7d2c336213ad..8fffc2f594a8 100644 ---- a/ipc/kdbus/bus.c -+++ b/ipc/kdbus/bus.c -@@ -507,7 +507,7 @@ int kdbus_cmd_bus_creator_info(struct kdbus_conn *conn, void __user *argp) - goto exit; - } - -- ret = kdbus_meta_export(bus->creator_meta, NULL, attach_flags, -+ ret = kdbus_meta_export(bus->creator_meta, NULL, conn, attach_flags, - slice, hdr_size, &meta_size); - if (ret < 0) - goto exit; -diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c -index 02e3ce735034..ca241fcf19f7 100644 ---- a/ipc/kdbus/connection.c -+++ b/ipc/kdbus/connection.c -@@ -130,6 +130,9 @@ static struct kdbus_conn *kdbus_conn_new(struct kdbus_ep *ep, bool privileged, - atomic_set(&conn->lost_count, 0); - INIT_DELAYED_WORK(&conn->work, kdbus_reply_list_scan_work); - conn->cred = get_current_cred(); -+ conn->user_ns = get_user_ns(current_user_ns()); -+ conn->pid_ns = get_pid_ns(task_active_pid_ns(current)); -+ get_fs_root(current->fs, &conn->root_path); - init_waitqueue_head(&conn->wait); - kdbus_queue_init(&conn->queue); - conn->privileged = privileged; -@@ -271,6 +274,9 @@ static void __kdbus_conn_free(struct kref *kref) - kdbus_match_db_free(conn->match_db); - kdbus_pool_free(conn->pool); - kdbus_ep_unref(conn->ep); -+ path_put(&conn->root_path); -+ put_pid_ns(conn->pid_ns); -+ put_user_ns(conn->user_ns); - put_cred(conn->cred); - kfree(conn->description); - kfree(conn->quota); -@@ -1792,7 +1798,7 @@ int kdbus_cmd_conn_info(struct kdbus_conn *conn, void __user *argp) - goto exit; - } - -- ret = kdbus_meta_export(owner_conn->meta, conn_meta, attach_flags, -+ ret = kdbus_meta_export(owner_conn->meta, conn_meta, conn, attach_flags, - slice, sizeof(info), &meta_size); - if (ret < 0) - goto exit; -diff --git a/ipc/kdbus/connection.h b/ipc/kdbus/connection.h -index d1ffe909cb31..226f3ff60e31 100644 ---- a/ipc/kdbus/connection.h -+++ b/ipc/kdbus/connection.h -@@ -59,6 +59,9 @@ struct kdbus_kmsg; - * @pool: The user's buffer to receive messages - * @user: Owner of the connection - * @cred: The credentials of the connection at creation time -+ * @user_ns: User namespace at creation time -+ * @pid_ns: Pid namespace at creation time -+ * @root_path: Root path at creation time - * @name_count: Number of owned well-known names - * @request_count: Number of pending requests issued by this - * connection that are waiting for replies from -@@ -97,6 +100,9 @@ struct kdbus_conn { - struct kdbus_pool *pool; - struct kdbus_user *user; - const struct cred *cred; -+ struct user_namespace *user_ns; -+ struct pid_namespace *pid_ns; -+ struct path root_path; - atomic_t name_count; - atomic_t request_count; - atomic_t lost_count; -diff --git a/ipc/kdbus/metadata.c b/ipc/kdbus/metadata.c -index c36b9cc67637..79f0e8c7f4a3 100644 ---- a/ipc/kdbus/metadata.c -+++ b/ipc/kdbus/metadata.c -@@ -888,7 +888,8 @@ static int kdbus_meta_push_kvec(struct kvec *kvec, - } - - static void kdbus_meta_export_caps(struct kdbus_meta_caps *out, -- struct kdbus_meta_proc *mp) -+ struct kdbus_meta_proc *mp, -+ struct user_namespace *user_ns) - { - struct user_namespace *iter; - const struct cred *cred = mp->cred; -@@ -896,18 +897,18 @@ static void kdbus_meta_export_caps(struct kdbus_meta_caps *out, - int i; - - /* -- * This translates the effective capabilities of 'cred' into the current -- * user-namespace. If the current user-namespace is a child-namespace of -+ * This translates the effective capabilities of 'cred' into the given -+ * user-namespace. If the given user-namespace is a child-namespace of - * the user-namespace of 'cred', the mask can be copied verbatim. If - * not, the mask is cleared. - * There's one exception: If 'cred' is the owner of any user-namespace -- * in the path between the current user-namespace and the user-namespace -+ * in the path between the given user-namespace and the user-namespace - * of 'cred', then it has all effective capabilities set. This means, - * the user who created a user-namespace always has all effective - * capabilities in any child namespaces. Note that this is based on the - * uid of the namespace creator, not the task hierarchy. - */ -- for (iter = current_user_ns(); iter; iter = iter->parent) { -+ for (iter = user_ns; iter; iter = iter->parent) { - if (iter == cred->user_ns) { - parent = true; - break; -@@ -951,23 +952,22 @@ static void kdbus_meta_export_caps(struct kdbus_meta_caps *out, - } - - /* This is equivalent to from_kuid_munged(), but maps INVALID_UID to itself */ --static uid_t kdbus_from_kuid_keep(kuid_t uid) -+static uid_t kdbus_from_kuid_keep(struct user_namespace *ns, kuid_t uid) - { -- return uid_valid(uid) ? -- from_kuid_munged(current_user_ns(), uid) : ((uid_t)-1); -+ return uid_valid(uid) ? from_kuid_munged(ns, uid) : ((uid_t)-1); - } - - /* This is equivalent to from_kgid_munged(), but maps INVALID_GID to itself */ --static gid_t kdbus_from_kgid_keep(kgid_t gid) -+static gid_t kdbus_from_kgid_keep(struct user_namespace *ns, kgid_t gid) - { -- return gid_valid(gid) ? -- from_kgid_munged(current_user_ns(), gid) : ((gid_t)-1); -+ return gid_valid(gid) ? from_kgid_munged(ns, gid) : ((gid_t)-1); - } - - /** - * kdbus_meta_export() - export information from metadata into a slice - * @mp: Process metadata, or NULL - * @mc: Connection metadata, or NULL -+ * @conn: Target connection to translate metadata into - * @mask: Mask of KDBUS_ATTACH_* flags to export - * @slice: The slice to export to - * @offset: The offset inside @slice to write to -@@ -983,18 +983,19 @@ static gid_t kdbus_from_kgid_keep(kgid_t gid) - * kdbus_meta_export_prepare(); depending on the namespaces in question, it - * might use up less than that. - * -- * All information will be translated using the current namespaces. -+ * All information will be translated using the namespaces of @conn. - * - * Return: 0 on success, negative error number otherwise. - */ - int kdbus_meta_export(struct kdbus_meta_proc *mp, - struct kdbus_meta_conn *mc, -+ struct kdbus_conn *conn, - u64 mask, - struct kdbus_pool_slice *slice, - off_t offset, - size_t *real_size) - { -- struct user_namespace *user_ns = current_user_ns(); -+ struct user_namespace *user_ns = conn->user_ns; - struct kdbus_item_header item_hdr[13], *hdr; - char *exe_pathname = NULL; - struct kdbus_creds creds; -@@ -1016,23 +1017,23 @@ int kdbus_meta_export(struct kdbus_meta_proc *mp, - /* process metadata */ - - if (mp && (mask & KDBUS_ATTACH_CREDS)) { -- creds.uid = kdbus_from_kuid_keep(mp->uid); -- creds.euid = kdbus_from_kuid_keep(mp->euid); -- creds.suid = kdbus_from_kuid_keep(mp->suid); -- creds.fsuid = kdbus_from_kuid_keep(mp->fsuid); -- creds.gid = kdbus_from_kgid_keep(mp->gid); -- creds.egid = kdbus_from_kgid_keep(mp->egid); -- creds.sgid = kdbus_from_kgid_keep(mp->sgid); -- creds.fsgid = kdbus_from_kgid_keep(mp->fsgid); -+ creds.uid = kdbus_from_kuid_keep(user_ns, mp->uid); -+ creds.euid = kdbus_from_kuid_keep(user_ns, mp->euid); -+ creds.suid = kdbus_from_kuid_keep(user_ns, mp->suid); -+ creds.fsuid = kdbus_from_kuid_keep(user_ns, mp->fsuid); -+ creds.gid = kdbus_from_kgid_keep(user_ns, mp->gid); -+ creds.egid = kdbus_from_kgid_keep(user_ns, mp->egid); -+ creds.sgid = kdbus_from_kgid_keep(user_ns, mp->sgid); -+ creds.fsgid = kdbus_from_kgid_keep(user_ns, mp->fsgid); - - cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, KDBUS_ITEM_CREDS, - &creds, sizeof(creds), &size); - } - - if (mp && (mask & KDBUS_ATTACH_PIDS)) { -- pids.pid = pid_vnr(mp->tgid); -- pids.tid = pid_vnr(mp->pid); -- pids.ppid = pid_vnr(mp->ppid); -+ pids.pid = pid_nr_ns(mp->tgid, conn->pid_ns); -+ pids.tid = pid_nr_ns(mp->pid, conn->pid_ns); -+ pids.ppid = pid_nr_ns(mp->ppid, conn->pid_ns); - - cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, KDBUS_ITEM_PIDS, - &pids, sizeof(pids), &size); -@@ -1078,7 +1079,8 @@ int kdbus_meta_export(struct kdbus_meta_proc *mp, - */ - - get_fs_root(current->fs, &p); -- if (path_equal(&p, &mp->root_path)) { -+ if (path_equal(&p, &mp->root_path) && -+ path_equal(&p, &conn->root_path)) { - exe_page = (void *)__get_free_page(GFP_TEMPORARY); - if (!exe_page) { - path_put(&p); -@@ -1116,7 +1118,7 @@ int kdbus_meta_export(struct kdbus_meta_proc *mp, - if (mp && (mask & KDBUS_ATTACH_CAPS)) { - struct kdbus_meta_caps caps = {}; - -- kdbus_meta_export_caps(&caps, mp); -+ kdbus_meta_export_caps(&caps, mp, user_ns); - cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, - KDBUS_ITEM_CAPS, &caps, - sizeof(caps), &size); -diff --git a/ipc/kdbus/metadata.h b/ipc/kdbus/metadata.h -index 79b6ac31c8ad..2dbbb3d78d97 100644 ---- a/ipc/kdbus/metadata.h -+++ b/ipc/kdbus/metadata.h -@@ -46,6 +46,7 @@ int kdbus_meta_export_prepare(struct kdbus_meta_proc *mp, - u64 *mask, size_t *sz); - int kdbus_meta_export(struct kdbus_meta_proc *mp, - struct kdbus_meta_conn *mc, -+ struct kdbus_conn *conn, - u64 mask, - struct kdbus_pool_slice *slice, - off_t offset, size_t *real_size); -diff --git a/ipc/kdbus/queue.c b/ipc/kdbus/queue.c -index 25bb3ad66b98..6650b7804d87 100644 ---- a/ipc/kdbus/queue.c -+++ b/ipc/kdbus/queue.c -@@ -479,6 +479,7 @@ int kdbus_queue_entry_install(struct kdbus_queue_entry *entry, - - ret = kdbus_meta_export(entry->proc_meta, - entry->conn_meta, -+ conn_dst, - entry->attach_flags, - entry->slice, - entry->meta_offset, --- -2.4.3 - - -From 539d66c50c22a40a29c97c8f1e497769de75c078 Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Wed, 1 Jul 2015 17:15:14 +0200 -Subject: [PATCH 087/132] kdbus: fix NULL-deref in activator cleanup - -Right now, we always assume an activator has a valid name and -conn->activator_of is set. However, this assumption is not true if the -setup of the activator fails. In those cases, the ->flags field indicates -an activator, but the name might not have been claimed, yet. - -Fix the destructor of connections to not assume all activators have -claimed names. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> ---- - ipc/kdbus/names.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ipc/kdbus/names.c b/ipc/kdbus/names.c -index d77ee08afeda..057f8061c20f 100644 ---- a/ipc/kdbus/names.c -+++ b/ipc/kdbus/names.c -@@ -444,7 +444,7 @@ void kdbus_name_release_all(struct kdbus_name_registry *reg, - - down_write(®->rwlock); - -- if (kdbus_conn_is_activator(conn)) { -+ if (conn->activator_of) { - activator = conn->activator_of->activator; - conn->activator_of->activator = NULL; - } --- -2.4.3 - - -From 3c18b8a477e0eda28b3390cf9168dbdb3c7fdd56 Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Fri, 3 Jul 2015 11:10:22 +0200 -Subject: [PATCH 088/132] kdbus: allow building development modules - -If you run your system on kdbus.ko, but you want to run tests on your -development version of kdbus, you will have a hard-time debugging as you -need to boot your machine with it. You either have to boot with legacy -dbus-daemon or boot without dbus entirely (eg., /bin/sh). - -The kdbus module always used KBUILD_MODNAME as base for all exported -objects (like kdbusfs and file-system paths). Hence, we can easily build -kdbus2.ko and get an independent module of the first one. This patch makes -the kdbus Makefile read KDBUS_EXT= and appends it to the module name. - -Now you can get an independent kdbus2.ko, by simply running: - make KDBUS_EXT=2 M=ipc/kdbus - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> ---- - ipc/kdbus/Makefile | 15 +++++++++++++-- - 1 file changed, 13 insertions(+), 2 deletions(-) - -diff --git a/ipc/kdbus/Makefile b/ipc/kdbus/Makefile -index 7ee9271e1449..66663a124104 100644 ---- a/ipc/kdbus/Makefile -+++ b/ipc/kdbus/Makefile -@@ -1,4 +1,15 @@ --kdbus-y := \ -+# -+# By setting KDBUS_EXT=2, the kdbus module will be built as kdbus2.ko, and -+# KBUILD_MODNAME=kdbus2. This has the effect that all exported objects have -+# different names than usually (kdbus2fs, /sys/fs/kdbus2/) and you can run -+# your test-infrastructure against the kdbus2.ko, while running your system -+# on kdbus.ko. -+# -+# To just build the module, use: -+# make KDBUS_EXT=2 M=ipc/kdbus -+# -+ -+kdbus$(KDBUS_EXT)-y := \ - bus.o \ - connection.o \ - endpoint.o \ -@@ -19,4 +30,4 @@ kdbus-y := \ - queue.o \ - util.o - --obj-$(CONFIG_KDBUS) += kdbus.o -+obj-$(CONFIG_KDBUS) += kdbus$(KDBUS_EXT).o --- -2.4.3 - - -From f8253aa89c645d1d979aa4743ebabe005f54f7df Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Mon, 15 Jun 2015 20:49:21 +0200 -Subject: [PATCH 089/132] kdbus: split off faked metadata into separate object - -Right now we treat faked metadata the same as process metadata. This has -the downside, that we cannot use "struct cred" to pin normal process -credentials, as we don't want to fake such structure for faked -credentials. - -Splitt off handling of faked metadata into a separate kdbus_meta_fake -object. As a side effect, faked metadata is now handled explicitly instead -of hidden in the process metadata. - -In follow-up patches, the kdbus_meta_proc state-tracking can be reduced -significantly by pinning "struct cred" instead of copying each field -individually. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> ---- - ipc/kdbus/bus.c | 6 +- - ipc/kdbus/connection.c | 37 +++++---- - ipc/kdbus/connection.h | 9 +-- - ipc/kdbus/message.c | 2 +- - ipc/kdbus/metadata.c | 216 ++++++++++++++++++++++++++++++------------------- - ipc/kdbus/metadata.h | 43 +++++++++- - ipc/kdbus/queue.c | 2 + - 7 files changed, 206 insertions(+), 109 deletions(-) - -diff --git a/ipc/kdbus/bus.c b/ipc/kdbus/bus.c -index 8fffc2f594a8..dd1e600b8f01 100644 ---- a/ipc/kdbus/bus.c -+++ b/ipc/kdbus/bus.c -@@ -484,7 +484,7 @@ int kdbus_cmd_bus_creator_info(struct kdbus_conn *conn, void __user *argp) - - attach_flags &= bus->attach_flags_owner; - -- ret = kdbus_meta_export_prepare(bus->creator_meta, NULL, -+ ret = kdbus_meta_export_prepare(bus->creator_meta, NULL, NULL, - &attach_flags, &meta_size); - if (ret < 0) - goto exit; -@@ -507,8 +507,8 @@ int kdbus_cmd_bus_creator_info(struct kdbus_conn *conn, void __user *argp) - goto exit; - } - -- ret = kdbus_meta_export(bus->creator_meta, NULL, conn, attach_flags, -- slice, hdr_size, &meta_size); -+ ret = kdbus_meta_export(bus->creator_meta, NULL, NULL, conn, -+ attach_flags, slice, hdr_size, &meta_size); - if (ret < 0) - goto exit; - -diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c -index ca241fcf19f7..8976bb32ab69 100644 ---- a/ipc/kdbus/connection.c -+++ b/ipc/kdbus/connection.c -@@ -172,22 +172,28 @@ static struct kdbus_conn *kdbus_conn_new(struct kdbus_ep *ep, bool privileged, - BUILD_BUG_ON(sizeof(bus->id128) != sizeof(hello->id128)); - memcpy(hello->id128, bus->id128, sizeof(hello->id128)); - -- conn->meta = kdbus_meta_proc_new(); -- if (IS_ERR(conn->meta)) { -- ret = PTR_ERR(conn->meta); -- conn->meta = NULL; -- goto exit_unref; -- } -- - /* privileged processes can impersonate somebody else */ - if (creds || pids || seclabel) { -- ret = kdbus_meta_proc_fake(conn->meta, creds, pids, seclabel); -- if (ret < 0) -+ conn->meta_fake = kdbus_meta_fake_new(); -+ if (IS_ERR(conn->meta_fake)) { -+ ret = PTR_ERR(conn->meta_fake); -+ conn->meta_fake = NULL; - goto exit_unref; -+ } - -- conn->faked_meta = true; -+ ret = kdbus_meta_fake_collect(conn->meta_fake, -+ creds, pids, seclabel); -+ if (ret < 0) -+ goto exit_unref; - } else { -- ret = kdbus_meta_proc_collect(conn->meta, -+ conn->meta_proc = kdbus_meta_proc_new(); -+ if (IS_ERR(conn->meta_proc)) { -+ ret = PTR_ERR(conn->meta_proc); -+ conn->meta_proc = NULL; -+ goto exit_unref; -+ } -+ -+ ret = kdbus_meta_proc_collect(conn->meta_proc, - KDBUS_ATTACH_CREDS | - KDBUS_ATTACH_PIDS | - KDBUS_ATTACH_AUXGROUPS | -@@ -270,7 +276,8 @@ static void __kdbus_conn_free(struct kref *kref) - kdbus_user_unref(conn->user); - } - -- kdbus_meta_proc_unref(conn->meta); -+ kdbus_meta_fake_free(conn->meta_fake); -+ kdbus_meta_proc_unref(conn->meta_proc); - kdbus_match_db_free(conn->match_db); - kdbus_pool_free(conn->pool); - kdbus_ep_unref(conn->ep); -@@ -1785,7 +1792,8 @@ int kdbus_cmd_conn_info(struct kdbus_conn *conn, void __user *argp) - if (ret < 0) - goto exit; - -- ret = kdbus_meta_export_prepare(owner_conn->meta, conn_meta, -+ ret = kdbus_meta_export_prepare(owner_conn->meta_proc, -+ owner_conn->meta_fake, conn_meta, - &attach_flags, &meta_size); - if (ret < 0) - goto exit; -@@ -1798,7 +1806,8 @@ int kdbus_cmd_conn_info(struct kdbus_conn *conn, void __user *argp) - goto exit; - } - -- ret = kdbus_meta_export(owner_conn->meta, conn_meta, conn, attach_flags, -+ ret = kdbus_meta_export(owner_conn->meta_proc, owner_conn->meta_fake, -+ conn_meta, conn, attach_flags, - slice, sizeof(info), &meta_size); - if (ret < 0) - goto exit; -diff --git a/ipc/kdbus/connection.h b/ipc/kdbus/connection.h -index 226f3ff60e31..0eb3d2e70a5e 100644 ---- a/ipc/kdbus/connection.h -+++ b/ipc/kdbus/connection.h -@@ -54,8 +54,8 @@ struct kdbus_kmsg; - * @work: Delayed work to handle timeouts - * activator for - * @match_db: Subscription filter to broadcast messages -- * @meta: Active connection creator's metadata/credentials, -- * either from the handle or from HELLO -+ * @meta_proc: Process metadata of connection creator, or NULL -+ * @meta_fake: Faked metadata, or NULL - * @pool: The user's buffer to receive messages - * @user: Owner of the connection - * @cred: The credentials of the connection at creation time -@@ -75,7 +75,6 @@ struct kdbus_kmsg; - * @names_list: List of well-known names - * @names_queue_list: Well-known names this connection waits for - * @privileged: Whether this connection is privileged on the bus -- * @faked_meta: Whether the metadata was faked on HELLO - */ - struct kdbus_conn { - struct kref kref; -@@ -96,7 +95,8 @@ struct kdbus_conn { - struct list_head reply_list; - struct delayed_work work; - struct kdbus_match_db *match_db; -- struct kdbus_meta_proc *meta; -+ struct kdbus_meta_proc *meta_proc; -+ struct kdbus_meta_fake *meta_fake; - struct kdbus_pool *pool; - struct kdbus_user *user; - const struct cred *cred; -@@ -118,7 +118,6 @@ struct kdbus_conn { - struct list_head names_queue_list; - - bool privileged:1; -- bool faked_meta:1; - }; - - struct kdbus_conn *kdbus_conn_ref(struct kdbus_conn *conn); -diff --git a/ipc/kdbus/message.c b/ipc/kdbus/message.c -index e9da67229eb1..55e432397b93 100644 ---- a/ipc/kdbus/message.c -+++ b/ipc/kdbus/message.c -@@ -626,7 +626,7 @@ int kdbus_kmsg_collect_metadata(struct kdbus_kmsg *kmsg, struct kdbus_conn *src, - int ret; - - attach = kdbus_meta_calc_attach_flags(src, dst); -- if (!src->faked_meta) { -+ if (!src->meta_fake) { - ret = kdbus_meta_proc_collect(kmsg->proc_meta, attach); - if (ret < 0) - return ret; -diff --git a/ipc/kdbus/metadata.c b/ipc/kdbus/metadata.c -index 79f0e8c7f4a3..ac4135c507c4 100644 ---- a/ipc/kdbus/metadata.c -+++ b/ipc/kdbus/metadata.c -@@ -494,101 +494,116 @@ exit_unlock: - } - - /** -- * kdbus_meta_proc_fake() - Fill process metadata from faked credentials -- * @mp: Metadata -+ * kdbus_meta_fake_new() - Create fake metadata object -+ * -+ * Return: Pointer to new object on success, ERR_PTR on failure. -+ */ -+struct kdbus_meta_fake *kdbus_meta_fake_new(void) -+{ -+ struct kdbus_meta_fake *mf; -+ -+ mf = kzalloc(sizeof(*mf), GFP_KERNEL); -+ if (!mf) -+ return ERR_PTR(-ENOMEM); -+ -+ return mf; -+} -+ -+/** -+ * kdbus_meta_fake_free() - Free fake metadata object -+ * @mf: Fake metadata object -+ * -+ * Return: NULL -+ */ -+struct kdbus_meta_fake *kdbus_meta_fake_free(struct kdbus_meta_fake *mf) -+{ -+ if (mf) { -+ put_pid(mf->ppid); -+ put_pid(mf->tgid); -+ put_pid(mf->pid); -+ kfree(mf->seclabel); -+ kfree(mf); -+ } -+ -+ return NULL; -+} -+ -+/** -+ * kdbus_meta_fake_collect() - Fill fake metadata from faked credentials -+ * @mf: Fake metadata object - * @creds: Creds to set, may be %NULL - * @pids: PIDs to set, may be %NULL - * @seclabel: Seclabel to set, may be %NULL - * - * This function takes information stored in @creds, @pids and @seclabel and -- * resolves them to kernel-representations, if possible. A call to this function -- * is considered an alternative to calling kdbus_meta_add_current(), which -- * derives the same information from the 'current' task. -- * -- * This call uses the current task's namespaces to resolve the given -- * information. -+ * resolves them to kernel-representations, if possible. This call uses the -+ * current task's namespaces to resolve the given information. - * -- * Return: 0 on success, negative error number otherwise. -+ * Return: 0 on success, negative error code on failure. - */ --int kdbus_meta_proc_fake(struct kdbus_meta_proc *mp, -- const struct kdbus_creds *creds, -- const struct kdbus_pids *pids, -- const char *seclabel) -+int kdbus_meta_fake_collect(struct kdbus_meta_fake *mf, -+ const struct kdbus_creds *creds, -+ const struct kdbus_pids *pids, -+ const char *seclabel) - { -- int ret; -- -- if (!mp) -- return 0; -- -- mutex_lock(&mp->lock); -+ if (mf->valid) -+ return -EALREADY; - -- if (creds && !(mp->collected & KDBUS_ATTACH_CREDS)) { -+ if (creds) { - struct user_namespace *ns = current_user_ns(); - -- mp->uid = make_kuid(ns, creds->uid); -- mp->euid = make_kuid(ns, creds->euid); -- mp->suid = make_kuid(ns, creds->suid); -- mp->fsuid = make_kuid(ns, creds->fsuid); -- -- mp->gid = make_kgid(ns, creds->gid); -- mp->egid = make_kgid(ns, creds->egid); -- mp->sgid = make_kgid(ns, creds->sgid); -- mp->fsgid = make_kgid(ns, creds->fsgid); -- -- if ((creds->uid != (uid_t)-1 && !uid_valid(mp->uid)) || -- (creds->euid != (uid_t)-1 && !uid_valid(mp->euid)) || -- (creds->suid != (uid_t)-1 && !uid_valid(mp->suid)) || -- (creds->fsuid != (uid_t)-1 && !uid_valid(mp->fsuid)) || -- (creds->gid != (gid_t)-1 && !gid_valid(mp->gid)) || -- (creds->egid != (gid_t)-1 && !gid_valid(mp->egid)) || -- (creds->sgid != (gid_t)-1 && !gid_valid(mp->sgid)) || -- (creds->fsgid != (gid_t)-1 && !gid_valid(mp->fsgid))) { -- ret = -EINVAL; -- goto exit_unlock; -- } -- -- mp->valid |= KDBUS_ATTACH_CREDS; -- mp->collected |= KDBUS_ATTACH_CREDS; -+ mf->uid = make_kuid(ns, creds->uid); -+ mf->euid = make_kuid(ns, creds->euid); -+ mf->suid = make_kuid(ns, creds->suid); -+ mf->fsuid = make_kuid(ns, creds->fsuid); -+ -+ mf->gid = make_kgid(ns, creds->gid); -+ mf->egid = make_kgid(ns, creds->egid); -+ mf->sgid = make_kgid(ns, creds->sgid); -+ mf->fsgid = make_kgid(ns, creds->fsgid); -+ -+ if ((creds->uid != (uid_t)-1 && !uid_valid(mf->uid)) || -+ (creds->euid != (uid_t)-1 && !uid_valid(mf->euid)) || -+ (creds->suid != (uid_t)-1 && !uid_valid(mf->suid)) || -+ (creds->fsuid != (uid_t)-1 && !uid_valid(mf->fsuid)) || -+ (creds->gid != (gid_t)-1 && !gid_valid(mf->gid)) || -+ (creds->egid != (gid_t)-1 && !gid_valid(mf->egid)) || -+ (creds->sgid != (gid_t)-1 && !gid_valid(mf->sgid)) || -+ (creds->fsgid != (gid_t)-1 && !gid_valid(mf->fsgid))) -+ return -EINVAL; -+ -+ mf->valid |= KDBUS_ATTACH_CREDS; - } - -- if (pids && !(mp->collected & KDBUS_ATTACH_PIDS)) { -- mp->pid = get_pid(find_vpid(pids->tid)); -- mp->tgid = get_pid(find_vpid(pids->pid)); -- mp->ppid = get_pid(find_vpid(pids->ppid)); -- -- if ((pids->tid != 0 && !mp->pid) || -- (pids->pid != 0 && !mp->tgid) || -- (pids->ppid != 0 && !mp->ppid)) { -- put_pid(mp->pid); -- put_pid(mp->tgid); -- put_pid(mp->ppid); -- mp->pid = NULL; -- mp->tgid = NULL; -- mp->ppid = NULL; -- ret = -EINVAL; -- goto exit_unlock; -+ if (pids) { -+ mf->pid = get_pid(find_vpid(pids->tid)); -+ mf->tgid = get_pid(find_vpid(pids->pid)); -+ mf->ppid = get_pid(find_vpid(pids->ppid)); -+ -+ if ((pids->tid != 0 && !mf->pid) || -+ (pids->pid != 0 && !mf->tgid) || -+ (pids->ppid != 0 && !mf->ppid)) { -+ put_pid(mf->pid); -+ put_pid(mf->tgid); -+ put_pid(mf->ppid); -+ mf->pid = NULL; -+ mf->tgid = NULL; -+ mf->ppid = NULL; -+ return -EINVAL; - } - -- mp->valid |= KDBUS_ATTACH_PIDS; -- mp->collected |= KDBUS_ATTACH_PIDS; -+ mf->valid |= KDBUS_ATTACH_PIDS; - } - -- if (seclabel && !(mp->collected & KDBUS_ATTACH_SECLABEL)) { -- mp->seclabel = kstrdup(seclabel, GFP_KERNEL); -- if (!mp->seclabel) { -- ret = -ENOMEM; -- goto exit_unlock; -- } -+ if (seclabel) { -+ mf->seclabel = kstrdup(seclabel, GFP_KERNEL); -+ if (!mf->seclabel) -+ return -ENOMEM; - -- mp->valid |= KDBUS_ATTACH_SECLABEL; -- mp->collected |= KDBUS_ATTACH_SECLABEL; -+ mf->valid |= KDBUS_ATTACH_SECLABEL; - } - -- ret = 0; -- --exit_unlock: -- mutex_unlock(&mp->lock); -- return ret; -+ return 0; - } - - /** -@@ -768,6 +783,7 @@ exit_unlock: - /* - * kdbus_meta_export_prepare() - Prepare metadata for export - * @mp: Process metadata, or NULL -+ * @mf: Fake metadata, or NULL - * @mc: Connection metadata, or NULL - * @mask: Pointer to mask of KDBUS_ATTACH_* flags to export - * @sz: Pointer to return the size needed by the metadata -@@ -783,6 +799,7 @@ exit_unlock: - * Return: 0 on success, negative error number otherwise. - */ - int kdbus_meta_export_prepare(struct kdbus_meta_proc *mp, -+ struct kdbus_meta_fake *mf, - struct kdbus_meta_conn *mc, - u64 *mask, size_t *sz) - { -@@ -792,6 +809,12 @@ int kdbus_meta_export_prepare(struct kdbus_meta_proc *mp, - u64 valid = 0; - int ret = 0; - -+ if (WARN_ON(mf && mp)) -+ mp = NULL; -+ -+ if (mf) -+ valid |= mf->valid; -+ - if (mp) { - mutex_lock(&mp->lock); - valid |= mp->valid; -@@ -811,10 +834,10 @@ int kdbus_meta_export_prepare(struct kdbus_meta_proc *mp, - - /* process metadata */ - -- if (mp && (*mask & KDBUS_ATTACH_CREDS)) -+ if ((mp || mf) && (*mask & KDBUS_ATTACH_CREDS)) - size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_creds)); - -- if (mp && (*mask & KDBUS_ATTACH_PIDS)) -+ if ((mp || mf) && (*mask & KDBUS_ATTACH_PIDS)) - size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_pids)); - - if (mp && (*mask & KDBUS_ATTACH_AUXGROUPS)) -@@ -852,8 +875,9 @@ int kdbus_meta_export_prepare(struct kdbus_meta_proc *mp, - if (mp && (*mask & KDBUS_ATTACH_CAPS)) - size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_meta_caps)); - -- if (mp && (*mask & KDBUS_ATTACH_SECLABEL)) -- size += KDBUS_ITEM_SIZE(strlen(mp->seclabel) + 1); -+ if ((mp || mf) && (*mask & KDBUS_ATTACH_SECLABEL)) -+ size += KDBUS_ITEM_SIZE(strlen(mp ? mp->seclabel -+ : mf->seclabel) + 1); - - if (mp && (*mask & KDBUS_ATTACH_AUDIT)) - size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_audit)); -@@ -966,6 +990,7 @@ static gid_t kdbus_from_kgid_keep(struct user_namespace *ns, kgid_t gid) - /** - * kdbus_meta_export() - export information from metadata into a slice - * @mp: Process metadata, or NULL -+ * @mf: Fake metadata, or NULL - * @mc: Connection metadata, or NULL - * @conn: Target connection to translate metadata into - * @mask: Mask of KDBUS_ATTACH_* flags to export -@@ -988,6 +1013,7 @@ static gid_t kdbus_from_kgid_keep(struct user_namespace *ns, kgid_t gid) - * Return: 0 on success, negative error number otherwise. - */ - int kdbus_meta_export(struct kdbus_meta_proc *mp, -+ struct kdbus_meta_fake *mf, - struct kdbus_meta_conn *mc, - struct kdbus_conn *conn, - u64 mask, -@@ -1007,6 +1033,9 @@ int kdbus_meta_export(struct kdbus_meta_proc *mp, - u64 size = 0; - int ret = 0; - -+ if (WARN_ON(mf && mp)) -+ mp = NULL; -+ - hdr = &item_hdr[0]; - - if (mask == 0) { -@@ -1016,7 +1045,19 @@ int kdbus_meta_export(struct kdbus_meta_proc *mp, - - /* process metadata */ - -- if (mp && (mask & KDBUS_ATTACH_CREDS)) { -+ if (mf && (mask & KDBUS_ATTACH_CREDS)) { -+ creds.uid = kdbus_from_kuid_keep(user_ns, mf->uid); -+ creds.euid = kdbus_from_kuid_keep(user_ns, mf->euid); -+ creds.suid = kdbus_from_kuid_keep(user_ns, mf->suid); -+ creds.fsuid = kdbus_from_kuid_keep(user_ns, mf->fsuid); -+ creds.gid = kdbus_from_kgid_keep(user_ns, mf->gid); -+ creds.egid = kdbus_from_kgid_keep(user_ns, mf->egid); -+ creds.sgid = kdbus_from_kgid_keep(user_ns, mf->sgid); -+ creds.fsgid = kdbus_from_kgid_keep(user_ns, mf->fsgid); -+ -+ cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, KDBUS_ITEM_CREDS, -+ &creds, sizeof(creds), &size); -+ } else if (mp && (mask & KDBUS_ATTACH_CREDS)) { - creds.uid = kdbus_from_kuid_keep(user_ns, mp->uid); - creds.euid = kdbus_from_kuid_keep(user_ns, mp->euid); - creds.suid = kdbus_from_kuid_keep(user_ns, mp->suid); -@@ -1030,7 +1071,14 @@ int kdbus_meta_export(struct kdbus_meta_proc *mp, - &creds, sizeof(creds), &size); - } - -- if (mp && (mask & KDBUS_ATTACH_PIDS)) { -+ if (mf && (mask & KDBUS_ATTACH_PIDS)) { -+ pids.pid = pid_nr_ns(mf->tgid, conn->pid_ns); -+ pids.tid = pid_nr_ns(mf->pid, conn->pid_ns); -+ pids.ppid = pid_nr_ns(mf->ppid, conn->pid_ns); -+ -+ cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, KDBUS_ITEM_PIDS, -+ &pids, sizeof(pids), &size); -+ } else if (mp && (mask & KDBUS_ATTACH_PIDS)) { - pids.pid = pid_nr_ns(mp->tgid, conn->pid_ns); - pids.tid = pid_nr_ns(mp->pid, conn->pid_ns); - pids.ppid = pid_nr_ns(mp->ppid, conn->pid_ns); -@@ -1124,7 +1172,11 @@ int kdbus_meta_export(struct kdbus_meta_proc *mp, - sizeof(caps), &size); - } - -- if (mp && (mask & KDBUS_ATTACH_SECLABEL)) -+ if (mf && (mask & KDBUS_ATTACH_SECLABEL)) -+ cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, -+ KDBUS_ITEM_SECLABEL, mf->seclabel, -+ strlen(mf->seclabel) + 1, &size); -+ else if (mp && (mask & KDBUS_ATTACH_SECLABEL)) - cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, - KDBUS_ITEM_SECLABEL, mp->seclabel, - strlen(mp->seclabel) + 1, &size); -diff --git a/ipc/kdbus/metadata.h b/ipc/kdbus/metadata.h -index 2dbbb3d78d97..2fb04dad38d4 100644 ---- a/ipc/kdbus/metadata.h -+++ b/ipc/kdbus/metadata.h -@@ -24,14 +24,47 @@ struct kdbus_pool_slice; - struct kdbus_meta_proc; - struct kdbus_meta_conn; - -+/** -+ * struct kdbus_meta_fake - Fake metadata -+ * @valid: Bitmask of collected and valid items -+ * @uid: UID of process -+ * @euid: EUID of process -+ * @suid: SUID of process -+ * @fsuid: FSUID of process -+ * @gid: GID of process -+ * @egid: EGID of process -+ * @sgid: SGID of process -+ * @fsgid: FSGID of process -+ * @pid: PID of process -+ * @tgid: TGID of process -+ * @ppid: PPID of process -+ * @seclabel: Seclabel -+ */ -+struct kdbus_meta_fake { -+ u64 valid; -+ -+ /* KDBUS_ITEM_CREDS */ -+ kuid_t uid, euid, suid, fsuid; -+ kgid_t gid, egid, sgid, fsgid; -+ -+ /* KDBUS_ITEM_PIDS */ -+ struct pid *pid, *tgid, *ppid; -+ -+ /* KDBUS_ITEM_SECLABEL */ -+ char *seclabel; -+}; -+ - struct kdbus_meta_proc *kdbus_meta_proc_new(void); - struct kdbus_meta_proc *kdbus_meta_proc_ref(struct kdbus_meta_proc *mp); - struct kdbus_meta_proc *kdbus_meta_proc_unref(struct kdbus_meta_proc *mp); - int kdbus_meta_proc_collect(struct kdbus_meta_proc *mp, u64 what); --int kdbus_meta_proc_fake(struct kdbus_meta_proc *mp, -- const struct kdbus_creds *creds, -- const struct kdbus_pids *pids, -- const char *seclabel); -+ -+struct kdbus_meta_fake *kdbus_meta_fake_new(void); -+struct kdbus_meta_fake *kdbus_meta_fake_free(struct kdbus_meta_fake *mf); -+int kdbus_meta_fake_collect(struct kdbus_meta_fake *mf, -+ const struct kdbus_creds *creds, -+ const struct kdbus_pids *pids, -+ const char *seclabel); - - struct kdbus_meta_conn *kdbus_meta_conn_new(void); - struct kdbus_meta_conn *kdbus_meta_conn_ref(struct kdbus_meta_conn *mc); -@@ -42,9 +75,11 @@ int kdbus_meta_conn_collect(struct kdbus_meta_conn *mc, - u64 what); - - int kdbus_meta_export_prepare(struct kdbus_meta_proc *mp, -+ struct kdbus_meta_fake *mf, - struct kdbus_meta_conn *mc, - u64 *mask, size_t *sz); - int kdbus_meta_export(struct kdbus_meta_proc *mp, -+ struct kdbus_meta_fake *mf, - struct kdbus_meta_conn *mc, - struct kdbus_conn *conn, - u64 mask, -diff --git a/ipc/kdbus/queue.c b/ipc/kdbus/queue.c -index 6650b7804d87..1e7916155036 100644 ---- a/ipc/kdbus/queue.c -+++ b/ipc/kdbus/queue.c -@@ -251,6 +251,7 @@ struct kdbus_queue_entry *kdbus_queue_entry_new(struct kdbus_conn *conn_dst, - atomic64_read(&conn_dst->attach_flags_recv); - - ret = kdbus_meta_export_prepare(entry->proc_meta, -+ NULL, - entry->conn_meta, - &entry->attach_flags, - &meta_size); -@@ -478,6 +479,7 @@ int kdbus_queue_entry_install(struct kdbus_queue_entry *entry, - size_t meta_size; - - ret = kdbus_meta_export(entry->proc_meta, -+ NULL, - entry->conn_meta, - conn_dst, - entry->attach_flags, --- -2.4.3 - - -From 2bec5609205bc69f57c7bd27834b2637aa656f6d Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Mon, 15 Jun 2015 21:25:39 +0200 -Subject: [PATCH 090/132] kdbus: pin 'struct cred' in process metadata - -Instead of copying over all data from 'struct cred', pin it directly. This -reduces the memory footprint of kdbus_meta_proc considerably and speeds -up the fast-path. - -There's no change in behavior. We just change the level we pin data at. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> ---- - ipc/kdbus/metadata.c | 131 +++++++++++++-------------------------------------- - 1 file changed, 34 insertions(+), 97 deletions(-) - -diff --git a/ipc/kdbus/metadata.c b/ipc/kdbus/metadata.c -index ac4135c507c4..1bac0dda72e0 100644 ---- a/ipc/kdbus/metadata.c -+++ b/ipc/kdbus/metadata.c -@@ -44,26 +44,16 @@ - * @lock: Object lock - * @collected: Bitmask of collected items - * @valid: Bitmask of collected and valid items -- * @uid: UID of process -- * @euid: EUID of process -- * @suid: SUID of process -- * @fsuid: FSUID of process -- * @gid: GID of process -- * @egid: EGID of process -- * @sgid: SGID of process -- * @fsgid: FSGID of process -+ * @cred: Credentials - * @pid: PID of process - * @tgid: TGID of process - * @ppid: PPID of process -- * @auxgrps: Auxiliary groups -- * @n_auxgrps: Number of items in @auxgrps - * @tid_comm: TID comm line - * @pid_comm: PID comm line - * @exe_path: Executable path - * @root_path: Root-FS path - * @cmdline: Command-line - * @cgroup: Full cgroup path -- * @cred: Credentials - * @seclabel: Seclabel - * @audit_loginuid: Audit login-UID - * @audit_sessionid: Audit session-ID -@@ -75,18 +65,15 @@ struct kdbus_meta_proc { - u64 valid; - - /* KDBUS_ITEM_CREDS */ -- kuid_t uid, euid, suid, fsuid; -- kgid_t gid, egid, sgid, fsgid; -+ /* KDBUS_ITEM_AUXGROUPS */ -+ /* KDBUS_ITEM_CAPS */ -+ const struct cred *cred; - - /* KDBUS_ITEM_PIDS */ - struct pid *pid; - struct pid *tgid; - struct pid *ppid; - -- /* KDBUS_ITEM_AUXGROUPS */ -- kgid_t *auxgrps; -- size_t n_auxgrps; -- - /* KDBUS_ITEM_TID_COMM */ - char tid_comm[TASK_COMM_LEN]; - /* KDBUS_ITEM_PID_COMM */ -@@ -102,9 +89,6 @@ struct kdbus_meta_proc { - /* KDBUS_ITEM_CGROUP */ - char *cgroup; - -- /* KDBUS_ITEM_CAPS */ -- const struct cred *cred; -- - /* KDBUS_ITEM_SECLABEL */ - char *seclabel; - -@@ -182,7 +166,6 @@ static void kdbus_meta_proc_free(struct kref *kref) - put_pid(mp->pid); - - kfree(mp->seclabel); -- kfree(mp->auxgrps); - kfree(mp->cmdline); - kfree(mp->cgroup); - kfree(mp); -@@ -214,21 +197,6 @@ struct kdbus_meta_proc *kdbus_meta_proc_unref(struct kdbus_meta_proc *mp) - return NULL; - } - --static void kdbus_meta_proc_collect_creds(struct kdbus_meta_proc *mp) --{ -- mp->uid = current_uid(); -- mp->euid = current_euid(); -- mp->suid = current_suid(); -- mp->fsuid = current_fsuid(); -- -- mp->gid = current_gid(); -- mp->egid = current_egid(); -- mp->sgid = current_sgid(); -- mp->fsgid = current_fsgid(); -- -- mp->valid |= KDBUS_ATTACH_CREDS; --} -- - static void kdbus_meta_proc_collect_pids(struct kdbus_meta_proc *mp) - { - struct task_struct *parent; -@@ -244,30 +212,6 @@ static void kdbus_meta_proc_collect_pids(struct kdbus_meta_proc *mp) - mp->valid |= KDBUS_ATTACH_PIDS; - } - --static int kdbus_meta_proc_collect_auxgroups(struct kdbus_meta_proc *mp) --{ -- const struct group_info *info; -- size_t i; -- -- /* no need to lock/ref, current creds cannot change */ -- info = current_cred()->group_info; -- -- if (info->ngroups > 0) { -- mp->auxgrps = kmalloc_array(info->ngroups, sizeof(kgid_t), -- GFP_KERNEL); -- if (!mp->auxgrps) -- return -ENOMEM; -- -- for (i = 0; i < info->ngroups; i++) -- mp->auxgrps[i] = GROUP_AT(info, i); -- } -- -- mp->n_auxgrps = info->ngroups; -- mp->valid |= KDBUS_ATTACH_AUXGROUPS; -- -- return 0; --} -- - static void kdbus_meta_proc_collect_tid_comm(struct kdbus_meta_proc *mp) - { - get_task_comm(mp->tid_comm, current); -@@ -340,12 +284,6 @@ static int kdbus_meta_proc_collect_cgroup(struct kdbus_meta_proc *mp) - return 0; - } - --static void kdbus_meta_proc_collect_caps(struct kdbus_meta_proc *mp) --{ -- mp->cred = get_current_cred(); -- mp->valid |= KDBUS_ATTACH_CAPS; --} -- - static int kdbus_meta_proc_collect_seclabel(struct kdbus_meta_proc *mp) - { - #ifdef CONFIG_SECURITY -@@ -412,10 +350,17 @@ int kdbus_meta_proc_collect(struct kdbus_meta_proc *mp, u64 what) - - mutex_lock(&mp->lock); - -- if ((what & KDBUS_ATTACH_CREDS) && -- !(mp->collected & KDBUS_ATTACH_CREDS)) { -- kdbus_meta_proc_collect_creds(mp); -- mp->collected |= KDBUS_ATTACH_CREDS; -+ /* creds, auxgrps and caps share "struct cred" as context */ -+ { -+ const u64 m_cred = KDBUS_ATTACH_CREDS | -+ KDBUS_ATTACH_AUXGROUPS | -+ KDBUS_ATTACH_CAPS; -+ -+ if ((what & m_cred) && !(mp->collected & m_cred)) { -+ mp->cred = get_current_cred(); -+ mp->valid |= m_cred; -+ mp->collected |= m_cred; -+ } - } - - if ((what & KDBUS_ATTACH_PIDS) && -@@ -424,14 +369,6 @@ int kdbus_meta_proc_collect(struct kdbus_meta_proc *mp, u64 what) - mp->collected |= KDBUS_ATTACH_PIDS; - } - -- if ((what & KDBUS_ATTACH_AUXGROUPS) && -- !(mp->collected & KDBUS_ATTACH_AUXGROUPS)) { -- ret = kdbus_meta_proc_collect_auxgroups(mp); -- if (ret < 0) -- goto exit_unlock; -- mp->collected |= KDBUS_ATTACH_AUXGROUPS; -- } -- - if ((what & KDBUS_ATTACH_TID_COMM) && - !(mp->collected & KDBUS_ATTACH_TID_COMM)) { - kdbus_meta_proc_collect_tid_comm(mp); -@@ -466,12 +403,6 @@ int kdbus_meta_proc_collect(struct kdbus_meta_proc *mp, u64 what) - mp->collected |= KDBUS_ATTACH_CGROUP; - } - -- if ((what & KDBUS_ATTACH_CAPS) && -- !(mp->collected & KDBUS_ATTACH_CAPS)) { -- kdbus_meta_proc_collect_caps(mp); -- mp->collected |= KDBUS_ATTACH_CAPS; -- } -- - if ((what & KDBUS_ATTACH_SECLABEL) && - !(mp->collected & KDBUS_ATTACH_SECLABEL)) { - ret = kdbus_meta_proc_collect_seclabel(mp); -@@ -841,7 +772,8 @@ int kdbus_meta_export_prepare(struct kdbus_meta_proc *mp, - size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_pids)); - - if (mp && (*mask & KDBUS_ATTACH_AUXGROUPS)) -- size += KDBUS_ITEM_SIZE(mp->n_auxgrps * sizeof(u64)); -+ size += KDBUS_ITEM_SIZE(mp->cred->group_info->ngroups * -+ sizeof(u64)); - - if (mp && (*mask & KDBUS_ATTACH_TID_COMM)) - size += KDBUS_ITEM_SIZE(strlen(mp->tid_comm) + 1); -@@ -1058,14 +990,16 @@ int kdbus_meta_export(struct kdbus_meta_proc *mp, - cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, KDBUS_ITEM_CREDS, - &creds, sizeof(creds), &size); - } else if (mp && (mask & KDBUS_ATTACH_CREDS)) { -- creds.uid = kdbus_from_kuid_keep(user_ns, mp->uid); -- creds.euid = kdbus_from_kuid_keep(user_ns, mp->euid); -- creds.suid = kdbus_from_kuid_keep(user_ns, mp->suid); -- creds.fsuid = kdbus_from_kuid_keep(user_ns, mp->fsuid); -- creds.gid = kdbus_from_kgid_keep(user_ns, mp->gid); -- creds.egid = kdbus_from_kgid_keep(user_ns, mp->egid); -- creds.sgid = kdbus_from_kgid_keep(user_ns, mp->sgid); -- creds.fsgid = kdbus_from_kgid_keep(user_ns, mp->fsgid); -+ const struct cred *c = mp->cred; -+ -+ creds.uid = kdbus_from_kuid_keep(user_ns, c->uid); -+ creds.euid = kdbus_from_kuid_keep(user_ns, c->euid); -+ creds.suid = kdbus_from_kuid_keep(user_ns, c->suid); -+ creds.fsuid = kdbus_from_kuid_keep(user_ns, c->fsuid); -+ creds.gid = kdbus_from_kgid_keep(user_ns, c->gid); -+ creds.egid = kdbus_from_kgid_keep(user_ns, c->egid); -+ creds.sgid = kdbus_from_kgid_keep(user_ns, c->sgid); -+ creds.fsgid = kdbus_from_kgid_keep(user_ns, c->fsgid); - - cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, KDBUS_ITEM_CREDS, - &creds, sizeof(creds), &size); -@@ -1088,17 +1022,20 @@ int kdbus_meta_export(struct kdbus_meta_proc *mp, - } - - if (mp && (mask & KDBUS_ATTACH_AUXGROUPS)) { -- size_t payload_size = mp->n_auxgrps * sizeof(u64); -- int i; -+ const struct group_info *info = mp->cred->group_info; -+ size_t i, n, payload_size; - -+ n = info->ngroups; -+ payload_size = n * sizeof(u64); - auxgrps = kmalloc(payload_size, GFP_KERNEL); - if (!auxgrps) { - ret = -ENOMEM; - goto exit; - } - -- for (i = 0; i < mp->n_auxgrps; i++) -- auxgrps[i] = from_kgid_munged(user_ns, mp->auxgrps[i]); -+ for (i = 0; i < n; ++i) -+ auxgrps[i] = from_kgid_munged(user_ns, -+ GROUP_AT(info, i)); - - cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, - KDBUS_ITEM_AUXGROUPS, --- -2.4.3 - - -From 46a0b5df61b398fc58897aaeb3c1e57f210057a7 Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Fri, 19 Jun 2015 15:33:34 +0200 -Subject: [PATCH 091/132] kdbus: pass msg-seqnum directly into meta-conn - -Instead of passing the kmsg object into kdbus_meta_conn_collect(), pass -the message sequence number directly. It is the only field that is used -there, so avoid introducing a "kdbus_kmsg" dependency from metadata.h. - -This is also a preparation for an upcoming change to drop 'kdbus_kmsg'. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> ---- - ipc/kdbus/connection.c | 3 +-- - ipc/kdbus/message.c | 2 +- - ipc/kdbus/metadata.c | 18 +++++++++--------- - ipc/kdbus/metadata.h | 4 +--- - ipc/kdbus/notify.c | 2 +- - 5 files changed, 13 insertions(+), 16 deletions(-) - -diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c -index 8976bb32ab69..8fcff17ae2b6 100644 ---- a/ipc/kdbus/connection.c -+++ b/ipc/kdbus/connection.c -@@ -1787,8 +1787,7 @@ int kdbus_cmd_conn_info(struct kdbus_conn *conn, void __user *argp) - goto exit; - } - -- ret = kdbus_meta_conn_collect(conn_meta, NULL, owner_conn, -- attach_flags); -+ ret = kdbus_meta_conn_collect(conn_meta, owner_conn, 0, attach_flags); - if (ret < 0) - goto exit; - -diff --git a/ipc/kdbus/message.c b/ipc/kdbus/message.c -index 55e432397b93..974e8c4f6039 100644 ---- a/ipc/kdbus/message.c -+++ b/ipc/kdbus/message.c -@@ -632,5 +632,5 @@ int kdbus_kmsg_collect_metadata(struct kdbus_kmsg *kmsg, struct kdbus_conn *src, - return ret; - } - -- return kdbus_meta_conn_collect(kmsg->conn_meta, kmsg, src, attach); -+ return kdbus_meta_conn_collect(kmsg->conn_meta, src, kmsg->seq, attach); - } -diff --git a/ipc/kdbus/metadata.c b/ipc/kdbus/metadata.c -index 1bac0dda72e0..dcb603798aba 100644 ---- a/ipc/kdbus/metadata.c -+++ b/ipc/kdbus/metadata.c -@@ -589,13 +589,13 @@ struct kdbus_meta_conn *kdbus_meta_conn_unref(struct kdbus_meta_conn *mc) - } - - static void kdbus_meta_conn_collect_timestamp(struct kdbus_meta_conn *mc, -- struct kdbus_kmsg *kmsg) -+ u64 msg_seqnum) - { - mc->ts.monotonic_ns = ktime_get_ns(); - mc->ts.realtime_ns = ktime_get_real_ns(); - -- if (kmsg) -- mc->ts.seqnum = kmsg->seq; -+ if (msg_seqnum) -+ mc->ts.seqnum = msg_seqnum; - - mc->valid |= KDBUS_ATTACH_TIMESTAMP; - } -@@ -657,11 +657,12 @@ static int kdbus_meta_conn_collect_description(struct kdbus_meta_conn *mc, - /** - * kdbus_meta_conn_collect() - Collect connection metadata - * @mc: Message metadata object -- * @kmsg: Kmsg to collect data from - * @conn: Connection to collect data from -+ * @msg_seqnum: Sequence number of the message to send - * @what: Attach flags to collect - * -- * This collects connection metadata from @kmsg and @conn and saves it in @mc. -+ * This collects connection metadata from @msg_seqnum and @conn and saves it -+ * in @mc. - * - * If KDBUS_ATTACH_NAMES is set in @what and @conn is non-NULL, the caller must - * hold the name-registry read-lock of conn->ep->bus->registry. -@@ -669,9 +670,8 @@ static int kdbus_meta_conn_collect_description(struct kdbus_meta_conn *mc, - * Return: 0 on success, negative error code on failure. - */ - int kdbus_meta_conn_collect(struct kdbus_meta_conn *mc, -- struct kdbus_kmsg *kmsg, - struct kdbus_conn *conn, -- u64 what) -+ u64 msg_seqnum, u64 what) - { - int ret; - -@@ -682,9 +682,9 @@ int kdbus_meta_conn_collect(struct kdbus_meta_conn *mc, - - mutex_lock(&mc->lock); - -- if (kmsg && (what & KDBUS_ATTACH_TIMESTAMP) && -+ if (msg_seqnum && (what & KDBUS_ATTACH_TIMESTAMP) && - !(mc->collected & KDBUS_ATTACH_TIMESTAMP)) { -- kdbus_meta_conn_collect_timestamp(mc, kmsg); -+ kdbus_meta_conn_collect_timestamp(mc, msg_seqnum); - mc->collected |= KDBUS_ATTACH_TIMESTAMP; - } - -diff --git a/ipc/kdbus/metadata.h b/ipc/kdbus/metadata.h -index 2fb04dad38d4..c33315d0b82b 100644 ---- a/ipc/kdbus/metadata.h -+++ b/ipc/kdbus/metadata.h -@@ -18,7 +18,6 @@ - #include <linux/kernel.h> - - struct kdbus_conn; --struct kdbus_kmsg; - struct kdbus_pool_slice; - - struct kdbus_meta_proc; -@@ -70,9 +69,8 @@ struct kdbus_meta_conn *kdbus_meta_conn_new(void); - struct kdbus_meta_conn *kdbus_meta_conn_ref(struct kdbus_meta_conn *mc); - struct kdbus_meta_conn *kdbus_meta_conn_unref(struct kdbus_meta_conn *mc); - int kdbus_meta_conn_collect(struct kdbus_meta_conn *mc, -- struct kdbus_kmsg *kmsg, - struct kdbus_conn *conn, -- u64 what); -+ u64 msg_seqnum, u64 what); - - int kdbus_meta_export_prepare(struct kdbus_meta_proc *mp, - struct kdbus_meta_fake *mf, -diff --git a/ipc/kdbus/notify.c b/ipc/kdbus/notify.c -index e4a454222f09..216720fc26ff 100644 ---- a/ipc/kdbus/notify.c -+++ b/ipc/kdbus/notify.c -@@ -209,7 +209,7 @@ void kdbus_notify_flush(struct kdbus_bus *bus) - spin_unlock(&bus->notify_lock); - - list_for_each_entry_safe(kmsg, tmp, ¬ify_list, notify_entry) { -- kdbus_meta_conn_collect(kmsg->conn_meta, kmsg, NULL, -+ kdbus_meta_conn_collect(kmsg->conn_meta, NULL, kmsg->seq, - KDBUS_ATTACH_TIMESTAMP); - - if (kmsg->msg.dst_id != KDBUS_DST_ID_BROADCAST) { --- -2.4.3 - - -From 9b7d557456bf4528daaad686b545cd6285602d69 Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Fri, 19 Jun 2015 15:37:03 +0200 -Subject: [PATCH 092/132] kdbus: don't include padding in mc->owned_names_size - -Whenever we deal with kdbus-items, we have to distinguish the size of the -items (as written in item->size) and the offset of the next item (which -includes any padding). The KDBUS_ITEM_SIZE() macro always computes the -size *plus* padding, which is a bit misleading. In most cases it's what -you want, but in case of mc->owned_names_size it is not. - -Right now, mc->owned_names_size includes the padding after the last item, -even though that is not strictly part of the items. Furthermore, since we -merge all the OWNED_NAME items into an array, it is not possible to -compute the actual size (minus padding) in O(1). Therefore, change the -collector to *NOT* include the final padding. - -The reason we need this is to make sure msg->size does never include the -padding after the last item. Right now it does, which will be fixed in -follow-up patches. This patch just makes sure we actually know the real -size of the owned_names_items array. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> ---- - ipc/kdbus/metadata.c | 15 +++++++++------ - 1 file changed, 9 insertions(+), 6 deletions(-) - -diff --git a/ipc/kdbus/metadata.c b/ipc/kdbus/metadata.c -index dcb603798aba..beb7dbb73d08 100644 ---- a/ipc/kdbus/metadata.c -+++ b/ipc/kdbus/metadata.c -@@ -610,14 +610,16 @@ static int kdbus_meta_conn_collect_names(struct kdbus_meta_conn *mc, - lockdep_assert_held(&conn->ep->bus->name_registry->rwlock); - - size = 0; -+ /* open-code length calculation to avoid final padding */ - list_for_each_entry(e, &conn->names_list, conn_entry) -- size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_name) + -- strlen(e->name) + 1); -+ size = KDBUS_ALIGN8(size) + KDBUS_ITEM_HEADER_SIZE + -+ sizeof(struct kdbus_name) + strlen(e->name) + 1; - - if (!size) - return 0; - -- item = kmalloc(size, GFP_KERNEL); -+ /* make sure we include zeroed padding for convenience helpers */ -+ item = kmalloc(KDBUS_ALIGN8(size), GFP_KERNEL); - if (!item) - return -ENOMEM; - -@@ -634,7 +636,8 @@ static int kdbus_meta_conn_collect_names(struct kdbus_meta_conn *mc, - } - - /* sanity check: the buffer should be completely written now */ -- WARN_ON((u8 *)item != (u8 *)mc->owned_names_items + size); -+ WARN_ON((u8 *)item != -+ (u8 *)mc->owned_names_items + KDBUS_ALIGN8(size)); - - mc->valid |= KDBUS_ATTACH_NAMES; - return 0; -@@ -817,7 +820,7 @@ int kdbus_meta_export_prepare(struct kdbus_meta_proc *mp, - /* connection metadata */ - - if (mc && (*mask & KDBUS_ATTACH_NAMES)) -- size += mc->owned_names_size; -+ size += KDBUS_ALIGN8(mc->owned_names_size); - - if (mc && (*mask & KDBUS_ATTACH_CONN_DESCRIPTION)) - size += KDBUS_ITEM_SIZE(strlen(mc->conn_description) + 1); -@@ -1132,7 +1135,7 @@ int kdbus_meta_export(struct kdbus_meta_proc *mp, - - if (mc && (mask & KDBUS_ATTACH_NAMES)) - kdbus_kvec_set(&kvec[cnt++], mc->owned_names_items, -- mc->owned_names_size, &size); -+ KDBUS_ALIGN8(mc->owned_names_size), &size); - - if (mc && (mask & KDBUS_ATTACH_CONN_DESCRIPTION)) - cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, --- -2.4.3 - - -From 8c9a45e352f84382e773cec71e8ce5e936f01db5 Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Fri, 19 Jun 2015 16:16:30 +0200 -Subject: [PATCH 093/132] kdbus: re-introduce metadata buffers - -This re-introduces the old way of managing metadata. The new -kdbus_meta_emit() function takes metadata sources from the caller and -emits an item buffer of the requested metadata items. The buffer is -allocated dynamically and can be directly used to copy the metadata items -into the pool slice. - -Unlike kdbus_meta_export(), this new function avoids calling into -kdbus_pool_slice and as such the metadata items can be integrated into the -copy-operation of the surrounding objects. We trade one slice-copy for one -kmalloc(), which should speed up most use-cases we care about -significantly. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> ---- - ipc/kdbus/metadata.c | 368 ++++++++++++++++++++++++++++++++++++++++++++++++++- - ipc/kdbus/metadata.h | 7 + - 2 files changed, 374 insertions(+), 1 deletion(-) - -diff --git a/ipc/kdbus/metadata.c b/ipc/kdbus/metadata.c -index beb7dbb73d08..70ce5d15fc98 100644 ---- a/ipc/kdbus/metadata.c -+++ b/ipc/kdbus/metadata.c -@@ -847,7 +847,7 @@ static int kdbus_meta_push_kvec(struct kvec *kvec, - } - - static void kdbus_meta_export_caps(struct kdbus_meta_caps *out, -- struct kdbus_meta_proc *mp, -+ const struct kdbus_meta_proc *mp, - struct user_namespace *user_ns) - { - struct user_namespace *iter; -@@ -1161,6 +1161,372 @@ exit: - return ret; - } - -+struct kdbus_meta_staging { -+ const struct kdbus_meta_proc *mp; -+ const struct kdbus_meta_fake *mf; -+ const struct kdbus_meta_conn *mc; -+ const struct kdbus_conn *conn; -+ u64 mask; -+ -+ void *exe; -+ const char *exe_path; -+}; -+ -+static size_t kdbus_meta_measure(struct kdbus_meta_staging *staging) -+{ -+ const struct kdbus_meta_proc *mp = staging->mp; -+ const struct kdbus_meta_fake *mf = staging->mf; -+ const struct kdbus_meta_conn *mc = staging->mc; -+ const u64 mask = staging->mask; -+ size_t size = 0; -+ -+ /* process metadata */ -+ -+ if (mf && (mask & KDBUS_ATTACH_CREDS)) -+ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_creds)); -+ else if (mp && (mask & KDBUS_ATTACH_CREDS)) -+ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_creds)); -+ -+ if (mf && (mask & KDBUS_ATTACH_PIDS)) -+ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_pids)); -+ else if (mp && (mask & KDBUS_ATTACH_PIDS)) -+ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_pids)); -+ -+ if (mp && (mask & KDBUS_ATTACH_AUXGROUPS)) -+ size += KDBUS_ITEM_SIZE(mp->cred->group_info->ngroups * -+ sizeof(u64)); -+ -+ if (mp && (mask & KDBUS_ATTACH_TID_COMM)) -+ size += KDBUS_ITEM_SIZE(strlen(mp->tid_comm) + 1); -+ -+ if (mp && (mask & KDBUS_ATTACH_PID_COMM)) -+ size += KDBUS_ITEM_SIZE(strlen(mp->pid_comm) + 1); -+ -+ if (staging->exe_path && (mask & KDBUS_ATTACH_EXE)) -+ size += KDBUS_ITEM_SIZE(strlen(staging->exe_path) + 1); -+ -+ if (mp && (mask & KDBUS_ATTACH_CMDLINE)) -+ size += KDBUS_ITEM_SIZE(strlen(mp->cmdline) + 1); -+ -+ if (mp && (mask & KDBUS_ATTACH_CGROUP)) -+ size += KDBUS_ITEM_SIZE(strlen(mp->cgroup) + 1); -+ -+ if (mp && (mask & KDBUS_ATTACH_CAPS)) -+ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_meta_caps)); -+ -+ if (mf && (mask & KDBUS_ATTACH_SECLABEL)) -+ size += KDBUS_ITEM_SIZE(strlen(mf->seclabel) + 1); -+ else if (mp && (mask & KDBUS_ATTACH_SECLABEL)) -+ size += KDBUS_ITEM_SIZE(strlen(mp->seclabel) + 1); -+ -+ if (mp && (mask & KDBUS_ATTACH_AUDIT)) -+ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_audit)); -+ -+ /* connection metadata */ -+ -+ if (mc && (mask & KDBUS_ATTACH_NAMES)) -+ size += KDBUS_ALIGN8(mc->owned_names_size); -+ -+ if (mc && (mask & KDBUS_ATTACH_CONN_DESCRIPTION)) -+ size += KDBUS_ITEM_SIZE(strlen(mc->conn_description) + 1); -+ -+ if (mc && (mask & KDBUS_ATTACH_TIMESTAMP)) -+ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_timestamp)); -+ -+ return size; -+} -+ -+static struct kdbus_item *kdbus_write_head(struct kdbus_item **iter, -+ u64 type, u64 size) -+{ -+ struct kdbus_item *item = *iter; -+ size_t padding; -+ -+ item->type = type; -+ item->size = KDBUS_ITEM_HEADER_SIZE + size; -+ -+ /* clear padding */ -+ padding = KDBUS_ALIGN8(item->size) - item->size; -+ if (padding) -+ memset(item->data + size, 0, padding); -+ -+ *iter = KDBUS_ITEM_NEXT(item); -+ return item; -+} -+ -+static struct kdbus_item *kdbus_write_full(struct kdbus_item **iter, -+ u64 type, u64 size, const void *data) -+{ -+ struct kdbus_item *item; -+ -+ item = kdbus_write_head(iter, type, size); -+ memcpy(item->data, data, size); -+ return item; -+} -+ -+static size_t kdbus_meta_write(struct kdbus_meta_staging *staging, void *mem, -+ size_t size) -+{ -+ struct user_namespace *user_ns = staging->conn->user_ns; -+ struct pid_namespace *pid_ns = staging->conn->pid_ns; -+ struct kdbus_item *item = NULL, *items = mem; -+ u8 *end, *owned_names_end = NULL; -+ -+ /* process metadata */ -+ -+ if (staging->mf && (staging->mask & KDBUS_ATTACH_CREDS)) { -+ const struct kdbus_meta_fake *mf = staging->mf; -+ -+ item = kdbus_write_head(&items, KDBUS_ITEM_CREDS, -+ sizeof(struct kdbus_creds)); -+ item->creds = (struct kdbus_creds){ -+ .uid = kdbus_from_kuid_keep(user_ns, mf->uid), -+ .euid = kdbus_from_kuid_keep(user_ns, mf->euid), -+ .suid = kdbus_from_kuid_keep(user_ns, mf->suid), -+ .fsuid = kdbus_from_kuid_keep(user_ns, mf->fsuid), -+ .gid = kdbus_from_kgid_keep(user_ns, mf->gid), -+ .egid = kdbus_from_kgid_keep(user_ns, mf->egid), -+ .sgid = kdbus_from_kgid_keep(user_ns, mf->sgid), -+ .fsgid = kdbus_from_kgid_keep(user_ns, mf->fsgid), -+ }; -+ } else if (staging->mp && (staging->mask & KDBUS_ATTACH_CREDS)) { -+ const struct cred *c = staging->mp->cred; -+ -+ item = kdbus_write_head(&items, KDBUS_ITEM_CREDS, -+ sizeof(struct kdbus_creds)); -+ item->creds = (struct kdbus_creds){ -+ .uid = kdbus_from_kuid_keep(user_ns, c->uid), -+ .euid = kdbus_from_kuid_keep(user_ns, c->euid), -+ .suid = kdbus_from_kuid_keep(user_ns, c->suid), -+ .fsuid = kdbus_from_kuid_keep(user_ns, c->fsuid), -+ .gid = kdbus_from_kgid_keep(user_ns, c->gid), -+ .egid = kdbus_from_kgid_keep(user_ns, c->egid), -+ .sgid = kdbus_from_kgid_keep(user_ns, c->sgid), -+ .fsgid = kdbus_from_kgid_keep(user_ns, c->fsgid), -+ }; -+ } -+ -+ if (staging->mf && (staging->mask & KDBUS_ATTACH_PIDS)) { -+ item = kdbus_write_head(&items, KDBUS_ITEM_PIDS, -+ sizeof(struct kdbus_pids)); -+ item->pids = (struct kdbus_pids){ -+ .pid = pid_nr_ns(staging->mf->tgid, pid_ns), -+ .tid = pid_nr_ns(staging->mf->pid, pid_ns), -+ .ppid = pid_nr_ns(staging->mf->ppid, pid_ns), -+ }; -+ } else if (staging->mp && (staging->mask & KDBUS_ATTACH_PIDS)) { -+ item = kdbus_write_head(&items, KDBUS_ITEM_PIDS, -+ sizeof(struct kdbus_pids)); -+ item->pids = (struct kdbus_pids){ -+ .pid = pid_nr_ns(staging->mp->tgid, pid_ns), -+ .tid = pid_nr_ns(staging->mp->pid, pid_ns), -+ .ppid = pid_nr_ns(staging->mp->ppid, pid_ns), -+ }; -+ } -+ -+ if (staging->mp && (staging->mask & KDBUS_ATTACH_AUXGROUPS)) { -+ const struct group_info *info = staging->mp->cred->group_info; -+ size_t i; -+ -+ item = kdbus_write_head(&items, KDBUS_ITEM_AUXGROUPS, -+ info->ngroups * sizeof(u64)); -+ for (i = 0; i < info->ngroups; ++i) -+ item->data64[i] = from_kgid_munged(user_ns, -+ GROUP_AT(info, i)); -+ } -+ -+ if (staging->mp && (staging->mask & KDBUS_ATTACH_TID_COMM)) -+ item = kdbus_write_full(&items, KDBUS_ITEM_TID_COMM, -+ strlen(staging->mp->tid_comm) + 1, -+ staging->mp->tid_comm); -+ -+ if (staging->mp && (staging->mask & KDBUS_ATTACH_PID_COMM)) -+ item = kdbus_write_full(&items, KDBUS_ITEM_PID_COMM, -+ strlen(staging->mp->pid_comm) + 1, -+ staging->mp->pid_comm); -+ -+ if (staging->exe_path && (staging->mask & KDBUS_ATTACH_EXE)) -+ item = kdbus_write_full(&items, KDBUS_ITEM_EXE, -+ strlen(staging->exe_path) + 1, -+ staging->exe_path); -+ -+ if (staging->mp && (staging->mask & KDBUS_ATTACH_CMDLINE)) -+ item = kdbus_write_full(&items, KDBUS_ITEM_CMDLINE, -+ strlen(staging->mp->cmdline) + 1, -+ staging->mp->cmdline); -+ -+ if (staging->mp && (staging->mask & KDBUS_ATTACH_CGROUP)) -+ item = kdbus_write_full(&items, KDBUS_ITEM_CGROUP, -+ strlen(staging->mp->cgroup) + 1, -+ staging->mp->cgroup); -+ -+ if (staging->mp && (staging->mask & KDBUS_ATTACH_CAPS)) { -+ item = kdbus_write_head(&items, KDBUS_ITEM_CAPS, -+ sizeof(struct kdbus_meta_caps)); -+ kdbus_meta_export_caps((void*)&item->caps, staging->mp, -+ user_ns); -+ } -+ -+ if (staging->mf && (staging->mask & KDBUS_ATTACH_SECLABEL)) -+ item = kdbus_write_full(&items, KDBUS_ITEM_SECLABEL, -+ strlen(staging->mf->seclabel) + 1, -+ staging->mf->seclabel); -+ else if (staging->mp && (staging->mask & KDBUS_ATTACH_SECLABEL)) -+ item = kdbus_write_full(&items, KDBUS_ITEM_SECLABEL, -+ strlen(staging->mp->seclabel) + 1, -+ staging->mp->seclabel); -+ -+ if (staging->mp && (staging->mask & KDBUS_ATTACH_AUDIT)) { -+ item = kdbus_write_head(&items, KDBUS_ITEM_AUDIT, -+ sizeof(struct kdbus_audit)); -+ item->audit = (struct kdbus_audit){ -+ .loginuid = from_kuid(user_ns, -+ staging->mp->audit_loginuid), -+ .sessionid = staging->mp->audit_sessionid, -+ }; -+ } -+ -+ /* connection metadata */ -+ -+ if (staging->mc && (staging->mask & KDBUS_ATTACH_NAMES)) { -+ memcpy(items, staging->mc->owned_names_items, -+ KDBUS_ALIGN8(staging->mc->owned_names_size)); -+ owned_names_end = (u8 *)items + staging->mc->owned_names_size; -+ items = (void *)KDBUS_ALIGN8((unsigned long)owned_names_end); -+ } -+ -+ if (staging->mc && (staging->mask & KDBUS_ATTACH_CONN_DESCRIPTION)) -+ item = kdbus_write_full(&items, KDBUS_ITEM_CONN_DESCRIPTION, -+ strlen(staging->mc->conn_description) + 1, -+ staging->mc->conn_description); -+ -+ if (staging->mc && (staging->mask & KDBUS_ATTACH_TIMESTAMP)) -+ item = kdbus_write_full(&items, KDBUS_ITEM_TIMESTAMP, -+ sizeof(staging->mc->ts), -+ &staging->mc->ts); -+ -+ /* -+ * Return real size (minus trailing padding). In case of 'owned_names' -+ * we cannot deduce it from item->size, so treat it special. -+ */ -+ -+ if (items == (void *)KDBUS_ALIGN8((unsigned long)owned_names_end)) -+ end = owned_names_end; -+ else if (item) -+ end = (u8 *)item + item->size; -+ else -+ end = mem; -+ -+ WARN_ON((u8 *)items - (u8 *)mem != size); -+ WARN_ON((void *)KDBUS_ALIGN8((unsigned long)end) != (void *)items); -+ -+ return end - (u8 *)mem; -+} -+ -+int kdbus_meta_emit(struct kdbus_meta_proc *mp, -+ struct kdbus_meta_fake *mf, -+ struct kdbus_meta_conn *mc, -+ struct kdbus_conn *conn, -+ u64 mask, -+ struct kdbus_item **out_items, -+ size_t *out_size) -+{ -+ struct kdbus_meta_staging staging = {}; -+ struct kdbus_item *items = NULL; -+ size_t size = 0; -+ int ret; -+ -+ if (WARN_ON(mf && mp)) -+ mp = NULL; -+ -+ staging.mp = mp; -+ staging.mf = mf; -+ staging.mc = mc; -+ staging.conn = conn; -+ -+ /* get mask of valid items */ -+ if (mf) -+ staging.mask |= mf->valid; -+ if (mp) { -+ mutex_lock(&mp->lock); -+ staging.mask |= mp->valid; -+ mutex_unlock(&mp->lock); -+ } -+ if (mc) { -+ mutex_lock(&mc->lock); -+ staging.mask |= mc->valid; -+ mutex_unlock(&mc->lock); -+ } -+ -+ staging.mask &= mask; -+ -+ if (!staging.mask) { /* bail out if nothing to do */ -+ ret = 0; -+ goto exit; -+ } -+ -+ /* EXE is special as it needs a temporary page to assemble */ -+ if (mp && (staging.mask & KDBUS_ATTACH_EXE)) { -+ struct path p; -+ -+ /* -+ * XXX: We need access to __d_path() so we can write the path -+ * relative to conn->root_path. Once upstream, we need -+ * EXPORT_SYMBOL(__d_path) or an equivalent of d_path() that -+ * takes the root path directly. Until then, we drop this item -+ * if the root-paths differ. -+ */ -+ -+ get_fs_root(current->fs, &p); -+ if (path_equal(&p, &conn->root_path)) { -+ staging.exe = (void *)__get_free_page(GFP_TEMPORARY); -+ if (!staging.exe) { -+ path_put(&p); -+ ret = -ENOMEM; -+ goto exit; -+ } -+ -+ staging.exe_path = d_path(&mp->exe_path, staging.exe, -+ PAGE_SIZE); -+ if (IS_ERR(staging.exe_path)) { -+ path_put(&p); -+ ret = PTR_ERR(staging.exe_path); -+ goto exit; -+ } -+ } -+ path_put(&p); -+ } -+ -+ size = kdbus_meta_measure(&staging); -+ if (!size) { /* bail out if nothing to do */ -+ ret = 0; -+ goto exit; -+ } -+ -+ items = kmalloc(size, GFP_KERNEL); -+ if (!items) { -+ ret = -ENOMEM; -+ goto exit; -+ } -+ -+ size = kdbus_meta_write(&staging, items, size); -+ if (!size) { -+ kfree(items); -+ items = NULL; -+ } -+ -+ ret = 0; -+ -+exit: -+ if (staging.exe) -+ free_page((unsigned long)staging.exe); -+ if (ret >= 0) { -+ *out_items = items; -+ *out_size = size; -+ } -+ return ret; -+} -+ - /** - * kdbus_meta_calc_attach_flags() - calculate attach flags for a sender - * and a receiver -diff --git a/ipc/kdbus/metadata.h b/ipc/kdbus/metadata.h -index c33315d0b82b..a30b0ad26af2 100644 ---- a/ipc/kdbus/metadata.h -+++ b/ipc/kdbus/metadata.h -@@ -83,6 +83,13 @@ int kdbus_meta_export(struct kdbus_meta_proc *mp, - u64 mask, - struct kdbus_pool_slice *slice, - off_t offset, size_t *real_size); -+int kdbus_meta_emit(struct kdbus_meta_proc *mp, -+ struct kdbus_meta_fake *mf, -+ struct kdbus_meta_conn *mc, -+ struct kdbus_conn *conn, -+ u64 mask, -+ struct kdbus_item **out_items, -+ size_t *out_size); - u64 kdbus_meta_calc_attach_flags(const struct kdbus_conn *sender, - const struct kdbus_conn *receiver); - --- -2.4.3 - - -From fd856bf056f3737c73aefe34f55799b34919699b Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Fri, 19 Jun 2015 16:46:30 +0200 -Subject: [PATCH 094/132] kdbus: speed up KDBUS_CMD_*_INFO by using meta_emit() - -Avoid using kdbus_meta_export*() and switch to kdbus_meta_emit(). This -adds one kmalloc(), but on the other hand drops a call to -kdbus_pool_slice_copy_kvec(). As the latter is way more expensive, this -speeds up KDBUS_CMD_*_INFO ioctls by approx. 10%. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> ---- - ipc/kdbus/bus.c | 40 +++++++++++++++++++--------------------- - ipc/kdbus/connection.c | 42 +++++++++++++++++++++--------------------- - 2 files changed, 40 insertions(+), 42 deletions(-) - -diff --git a/ipc/kdbus/bus.c b/ipc/kdbus/bus.c -index dd1e600b8f01..82b7171f1fdb 100644 ---- a/ipc/kdbus/bus.c -+++ b/ipc/kdbus/bus.c -@@ -456,13 +456,12 @@ int kdbus_cmd_bus_creator_info(struct kdbus_conn *conn, void __user *argp) - struct kdbus_cmd_info *cmd; - struct kdbus_bus *bus = conn->ep->bus; - struct kdbus_pool_slice *slice = NULL; -+ struct kdbus_item *meta_items = NULL; - struct kdbus_item_header item_hdr; - struct kdbus_info info = {}; -- size_t meta_size, name_len; -- struct kvec kvec[5]; -- u64 hdr_size = 0; -- u64 attach_flags; -- size_t cnt = 0; -+ size_t meta_size, name_len, cnt = 0; -+ struct kvec kvec[6]; -+ u64 attach_flags, size = 0; - int ret; - - struct kdbus_arg argv[] = { -@@ -484,8 +483,8 @@ int kdbus_cmd_bus_creator_info(struct kdbus_conn *conn, void __user *argp) - - attach_flags &= bus->attach_flags_owner; - -- ret = kdbus_meta_export_prepare(bus->creator_meta, NULL, NULL, -- &attach_flags, &meta_size); -+ ret = kdbus_meta_emit(bus->creator_meta, NULL, NULL, conn, -+ attach_flags, &meta_items, &meta_size); - if (ret < 0) - goto exit; - -@@ -495,26 +494,25 @@ int kdbus_cmd_bus_creator_info(struct kdbus_conn *conn, void __user *argp) - item_hdr.type = KDBUS_ITEM_MAKE_NAME; - item_hdr.size = KDBUS_ITEM_HEADER_SIZE + name_len; - -- kdbus_kvec_set(&kvec[cnt++], &info, sizeof(info), &hdr_size); -- kdbus_kvec_set(&kvec[cnt++], &item_hdr, sizeof(item_hdr), &hdr_size); -- kdbus_kvec_set(&kvec[cnt++], bus->node.name, name_len, &hdr_size); -- cnt += !!kdbus_kvec_pad(&kvec[cnt], &hdr_size); -+ kdbus_kvec_set(&kvec[cnt++], &info, sizeof(info), &size); -+ kdbus_kvec_set(&kvec[cnt++], &item_hdr, sizeof(item_hdr), &size); -+ kdbus_kvec_set(&kvec[cnt++], bus->node.name, name_len, &size); -+ cnt += !!kdbus_kvec_pad(&kvec[cnt], &size); -+ if (meta_size > 0) { -+ kdbus_kvec_set(&kvec[cnt++], meta_items, meta_size, &size); -+ cnt += !!kdbus_kvec_pad(&kvec[cnt], &size); -+ } -+ -+ info.size = size; - -- slice = kdbus_pool_slice_alloc(conn->pool, hdr_size + meta_size, false); -+ slice = kdbus_pool_slice_alloc(conn->pool, size, false); - if (IS_ERR(slice)) { - ret = PTR_ERR(slice); - slice = NULL; - goto exit; - } - -- ret = kdbus_meta_export(bus->creator_meta, NULL, NULL, conn, -- attach_flags, slice, hdr_size, &meta_size); -- if (ret < 0) -- goto exit; -- -- info.size = hdr_size + meta_size; -- -- ret = kdbus_pool_slice_copy_kvec(slice, 0, kvec, cnt, hdr_size); -+ ret = kdbus_pool_slice_copy_kvec(slice, 0, kvec, cnt, size); - if (ret < 0) - goto exit; - -@@ -527,6 +525,6 @@ int kdbus_cmd_bus_creator_info(struct kdbus_conn *conn, void __user *argp) - - exit: - kdbus_pool_slice_release(slice); -- -+ kfree(meta_items); - return kdbus_args_clear(&args, ret); - } -diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c -index 8fcff17ae2b6..7b800b299caf 100644 ---- a/ipc/kdbus/connection.c -+++ b/ipc/kdbus/connection.c -@@ -1718,13 +1718,14 @@ int kdbus_cmd_conn_info(struct kdbus_conn *conn, void __user *argp) - struct kdbus_pool_slice *slice = NULL; - struct kdbus_name_entry *entry = NULL; - struct kdbus_conn *owner_conn = NULL; -+ struct kdbus_item *meta_items = NULL; - struct kdbus_info info = {}; - struct kdbus_cmd_info *cmd; - struct kdbus_bus *bus = conn->ep->bus; -- struct kvec kvec; -- size_t meta_size; -+ struct kvec kvec[3]; -+ size_t meta_size, cnt = 0; - const char *name; -- u64 attach_flags; -+ u64 attach_flags, size = 0; - int ret; - - struct kdbus_arg argv[] = { -@@ -1774,10 +1775,6 @@ int kdbus_cmd_conn_info(struct kdbus_conn *conn, void __user *argp) - goto exit; - } - -- info.id = owner_conn->id; -- info.flags = owner_conn->flags; -- kdbus_kvec_set(&kvec, &info, sizeof(info), &info.size); -- - attach_flags &= atomic64_read(&owner_conn->attach_flags_send); - - conn_meta = kdbus_meta_conn_new(); -@@ -1791,29 +1788,31 @@ int kdbus_cmd_conn_info(struct kdbus_conn *conn, void __user *argp) - if (ret < 0) - goto exit; - -- ret = kdbus_meta_export_prepare(owner_conn->meta_proc, -- owner_conn->meta_fake, conn_meta, -- &attach_flags, &meta_size); -+ ret = kdbus_meta_emit(owner_conn->meta_proc, owner_conn->meta_fake, -+ conn_meta, conn, attach_flags, -+ &meta_items, &meta_size); - if (ret < 0) - goto exit; - -- slice = kdbus_pool_slice_alloc(conn->pool, -- info.size + meta_size, false); -+ info.id = owner_conn->id; -+ info.flags = owner_conn->flags; -+ -+ kdbus_kvec_set(&kvec[cnt++], &info, sizeof(info), &size); -+ if (meta_size > 0) { -+ kdbus_kvec_set(&kvec[cnt++], meta_items, meta_size, &size); -+ cnt += !!kdbus_kvec_pad(&kvec[cnt], &size); -+ } -+ -+ info.size = size; -+ -+ slice = kdbus_pool_slice_alloc(conn->pool, size, false); - if (IS_ERR(slice)) { - ret = PTR_ERR(slice); - slice = NULL; - goto exit; - } - -- ret = kdbus_meta_export(owner_conn->meta_proc, owner_conn->meta_fake, -- conn_meta, conn, attach_flags, -- slice, sizeof(info), &meta_size); -- if (ret < 0) -- goto exit; -- -- info.size += meta_size; -- -- ret = kdbus_pool_slice_copy_kvec(slice, 0, &kvec, 1, sizeof(info)); -+ ret = kdbus_pool_slice_copy_kvec(slice, 0, kvec, cnt, size); - if (ret < 0) - goto exit; - -@@ -1831,6 +1830,7 @@ int kdbus_cmd_conn_info(struct kdbus_conn *conn, void __user *argp) - exit: - up_read(&bus->name_registry->rwlock); - kdbus_pool_slice_release(slice); -+ kfree(meta_items); - kdbus_meta_conn_unref(conn_meta); - kdbus_conn_unref(owner_conn); - return kdbus_args_clear(&args, ret); --- -2.4.3 - - -From b410b7c6a9e90977dd14d6da72f8e5fd39f04e0b Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Fri, 19 Jun 2015 21:34:08 +0200 -Subject: [PATCH 095/132] kdbus: simplify kdbus_match_rules() - -Split up the huge kdbus_match_rules() helper into 3 helper functions. This -reduces the code size almost by half, as we no longer have to maintain 4 -levels of indentation. - -No functional change. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> ---- - ipc/kdbus/match.c | 123 +++++++++++++++++++++--------------------------------- - 1 file changed, 48 insertions(+), 75 deletions(-) - -diff --git a/ipc/kdbus/match.c b/ipc/kdbus/match.c -index cc083b4211de..869a9fbce37d 100644 ---- a/ipc/kdbus/match.c -+++ b/ipc/kdbus/match.c -@@ -204,87 +204,60 @@ static bool kdbus_match_bloom(const struct kdbus_bloom_filter *filter, - return true; - } - --static bool kdbus_match_rules(const struct kdbus_match_entry *entry, -- struct kdbus_conn *conn_src, -- struct kdbus_kmsg *kmsg) -+static bool kdbus_match_rule_conn(const struct kdbus_match_rule *r, -+ struct kdbus_conn *c, -+ const struct kdbus_kmsg *kmsg) - { -- struct kdbus_match_rule *r; -- -- if (conn_src) -- lockdep_assert_held(&conn_src->ep->bus->name_registry->rwlock); -- -- /* -- * 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) { -- /* 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; -+ lockdep_assert_held(&c->ep->bus->name_registry->rwlock); - -- case KDBUS_ITEM_NAME: -- if (!kdbus_conn_has_name(conn_src, r->name)) -- return false; -- -- break; -- -- default: -- return false; -- } -- } else { -- /* 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; -+ switch (r->type) { -+ case KDBUS_ITEM_BLOOM_MASK: -+ return kdbus_match_bloom(kmsg->bloom_filter, &r->bloom_mask, c); -+ case KDBUS_ITEM_ID: -+ return r->src_id == c->id || r->src_id == KDBUS_MATCH_ID_ANY; -+ case KDBUS_ITEM_NAME: -+ return kdbus_conn_has_name(c, r->name); -+ default: -+ return false; -+ } -+} - -- break; -+static bool kdbus_match_rule_kernel(const struct kdbus_match_rule *r, -+ const struct kdbus_kmsg *kmsg) -+{ -+ if (kmsg->notify_type != r->type) -+ return false; - -- 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; -+ switch (r->type) { -+ case KDBUS_ITEM_ID_ADD: -+ return r->new_id == KDBUS_MATCH_ID_ANY || -+ r->new_id == kmsg->notify_new_id; -+ case KDBUS_ITEM_ID_REMOVE: -+ return r->old_id == KDBUS_MATCH_ID_ANY || -+ r->old_id == kmsg->notify_old_id; -+ case KDBUS_ITEM_NAME_ADD: -+ case KDBUS_ITEM_NAME_CHANGE: -+ case KDBUS_ITEM_NAME_REMOVE: -+ return (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 || !strcmp(r->name, kmsg->notify_name)); -+ default: -+ return false; -+ } -+} - -- break; -+static bool kdbus_match_rules(const struct kdbus_match_entry *entry, -+ struct kdbus_conn *c, -+ const struct kdbus_kmsg *kmsg) -+{ -+ struct kdbus_match_rule *r; - -- default: -- return false; -- } -- } -- } -+ list_for_each_entry(r, &entry->rules_list, rules_entry) -+ if ((c && !kdbus_match_rule_conn(r, c, kmsg)) || -+ (!c && !kdbus_match_rule_kernel(r, kmsg))) -+ return false; - - return true; - } --- -2.4.3 - - -From c4146fd608177530fb3f6c6ad6e395d3fb0eee4e Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Fri, 19 Jun 2015 21:39:25 +0200 -Subject: [PATCH 096/132] kdbus: pass notification details directly into policy - wrapper - -Avoid passing the kmsg into the policy wrapper, but pass the notification -details directly. This reduces the scope of 'struct kdbus_kmsg' and avoids -accessing its members directly. This will ease the introduction of the -kmsg rework later on. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> ---- - ipc/kdbus/bus.c | 3 ++- - ipc/kdbus/connection.c | 18 ++++++++---------- - ipc/kdbus/connection.h | 2 +- - 3 files changed, 11 insertions(+), 12 deletions(-) - -diff --git a/ipc/kdbus/bus.c b/ipc/kdbus/bus.c -index 82b7171f1fdb..3c33339cf332 100644 ---- a/ipc/kdbus/bus.c -+++ b/ipc/kdbus/bus.c -@@ -298,7 +298,8 @@ void kdbus_bus_broadcast(struct kdbus_bus *bus, - * notification - */ - if (!kdbus_conn_policy_see_notification(conn_dst, NULL, -- kmsg)) -+ kmsg->notify_type, -+ kmsg->notify_name)) - continue; - } - -diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c -index 7b800b299caf..73cad58d2acd 100644 ---- a/ipc/kdbus/connection.c -+++ b/ipc/kdbus/connection.c -@@ -1542,19 +1542,18 @@ static bool kdbus_conn_policy_see(struct kdbus_conn *conn, - * receive a given kernel notification - * @conn: Connection - * @conn_creds: Credentials of @conn to use for policy check -- * @kmsg: The message carrying the notification -+ * @type: Type of notification -+ * @name: Well-known name this notification is about, or NULL - * -- * This checks whether @conn is allowed to see the kernel notification @kmsg. -+ * This checks whether @conn is allowed to see the kernel notification of type -+ * @type for well-known name @name. - * - * Return: true if allowed, false if not. - */ - bool kdbus_conn_policy_see_notification(struct kdbus_conn *conn, - const struct cred *conn_creds, -- const struct kdbus_kmsg *kmsg) -+ u64 type, const char *name) - { -- if (WARN_ON(kmsg->msg.src_id != KDBUS_SRC_ID_KERNEL)) -- return false; -- - /* - * Depending on the notification type, broadcasted kernel notifications - * have to be filtered: -@@ -1567,12 +1566,11 @@ bool kdbus_conn_policy_see_notification(struct kdbus_conn *conn, - * broadcast to everyone, to allow tracking peers. - */ - -- switch (kmsg->notify_type) { -+ switch (type) { - case KDBUS_ITEM_NAME_ADD: - case KDBUS_ITEM_NAME_REMOVE: - case KDBUS_ITEM_NAME_CHANGE: -- return kdbus_conn_policy_see_name(conn, conn_creds, -- kmsg->notify_name); -+ return kdbus_conn_policy_see_name(conn, conn_creds, name); - - case KDBUS_ITEM_ID_ADD: - case KDBUS_ITEM_ID_REMOVE: -@@ -1580,7 +1578,7 @@ bool kdbus_conn_policy_see_notification(struct kdbus_conn *conn, - - default: - WARN(1, "Invalid type for notification broadcast: %llu\n", -- (unsigned long long)kmsg->notify_type); -+ (unsigned long long)type); - return false; - } - } -diff --git a/ipc/kdbus/connection.h b/ipc/kdbus/connection.h -index 0eb3d2e70a5e..aa4234a4e3e4 100644 ---- a/ipc/kdbus/connection.h -+++ b/ipc/kdbus/connection.h -@@ -152,7 +152,7 @@ bool kdbus_conn_policy_see_name_unlocked(struct kdbus_conn *conn, - const char *name); - bool kdbus_conn_policy_see_notification(struct kdbus_conn *conn, - const struct cred *curr_creds, -- const struct kdbus_kmsg *kmsg); -+ u64 type, const char *name); - - /* command dispatcher */ - struct kdbus_conn *kdbus_cmd_hello(struct kdbus_ep *ep, bool privileged, --- -2.4.3 - - -From bdac38baecf3b1af14b647f791a795a91ef7f6c6 Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Fri, 19 Jun 2015 21:46:39 +0200 -Subject: [PATCH 097/132] kdbus: pass source connection to queue handling - -Make sure we always pass the source-connection of a message along. Right -now we drop it for queue allocation, which prevents us from accessing any -source details in the queue helpers. We work around this, by passing -everything manually, but that just makes things more complex. - -Pass the source connection down to the queue helpers to allow further -cleanups in follow up patches. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> ---- - ipc/kdbus/connection.c | 15 +++++++-------- - ipc/kdbus/queue.c | 9 +++++---- - ipc/kdbus/queue.h | 6 +++--- - 3 files changed, 15 insertions(+), 15 deletions(-) - -diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c -index 73cad58d2acd..f1667df70b7f 100644 ---- a/ipc/kdbus/connection.c -+++ b/ipc/kdbus/connection.c -@@ -779,9 +779,9 @@ void kdbus_conn_lost_message(struct kdbus_conn *c) - - /* Callers should take the conn_dst lock */ - static struct kdbus_queue_entry * --kdbus_conn_entry_make(struct kdbus_conn *conn_dst, -- const struct kdbus_kmsg *kmsg, -- struct kdbus_user *user) -+kdbus_conn_entry_make(struct kdbus_conn *conn_src, -+ struct kdbus_conn *conn_dst, -+ const struct kdbus_kmsg *kmsg) - { - /* The remote connection was disconnected */ - if (!kdbus_conn_active(conn_dst)) -@@ -799,7 +799,7 @@ kdbus_conn_entry_make(struct kdbus_conn *conn_dst, - kmsg->res && kmsg->res->fds_count > 0) - return ERR_PTR(-ECOMM); - -- return kdbus_queue_entry_new(conn_dst, kmsg, user); -+ return kdbus_queue_entry_new(conn_src, conn_dst, kmsg); - } - - /* -@@ -822,8 +822,8 @@ static int kdbus_conn_entry_sync_attach(struct kdbus_conn *conn_dst, - * entry and attach it to the reply object - */ - if (reply_wake->waiting) { -- entry = kdbus_conn_entry_make(conn_dst, kmsg, -- reply_wake->reply_src->user); -+ entry = kdbus_conn_entry_make(reply_wake->reply_src, conn_dst, -+ kmsg); - if (IS_ERR(entry)) - ret = PTR_ERR(entry); - else -@@ -879,8 +879,7 @@ int kdbus_conn_entry_insert(struct kdbus_conn *conn_src, - - kdbus_conn_lock2(conn_src, conn_dst); - -- entry = kdbus_conn_entry_make(conn_dst, kmsg, -- conn_src ? conn_src->user : NULL); -+ entry = kdbus_conn_entry_make(conn_src, conn_dst, kmsg); - if (IS_ERR(entry)) { - ret = PTR_ERR(entry); - goto exit_unlock; -diff --git a/ipc/kdbus/queue.c b/ipc/kdbus/queue.c -index 1e7916155036..43824c93fb03 100644 ---- a/ipc/kdbus/queue.c -+++ b/ipc/kdbus/queue.c -@@ -171,9 +171,9 @@ static void kdbus_queue_entry_unlink(struct kdbus_queue_entry *entry) - - /** - * kdbus_queue_entry_new() - allocate a queue entry -+ * @conn_src: source connection - * @conn_dst: destination connection - * @kmsg: kmsg object the queue entry should track -- * @user: user to account message on (or NULL for kernel messages) - * - * Allocates a queue entry based on a given kmsg and allocate space for - * the message payload and the requested metadata in the connection's pool. -@@ -181,10 +181,11 @@ static void kdbus_queue_entry_unlink(struct kdbus_queue_entry *entry) - * - * Return: the allocated entry on success, or an ERR_PTR on failures. - */ --struct kdbus_queue_entry *kdbus_queue_entry_new(struct kdbus_conn *conn_dst, -- const struct kdbus_kmsg *kmsg, -- struct kdbus_user *user) -+struct kdbus_queue_entry *kdbus_queue_entry_new(struct kdbus_conn *conn_src, -+ struct kdbus_conn *conn_dst, -+ const struct kdbus_kmsg *kmsg) - { -+ struct kdbus_user *user = conn_src ? conn_src->user : NULL; - struct kdbus_msg_resources *res = kmsg->res; - const struct kdbus_msg *msg = &kmsg->msg; - struct kdbus_queue_entry *entry; -diff --git a/ipc/kdbus/queue.h b/ipc/kdbus/queue.h -index 7f2db96fe308..ac471d0c809d 100644 ---- a/ipc/kdbus/queue.h -+++ b/ipc/kdbus/queue.h -@@ -78,9 +78,9 @@ void kdbus_queue_init(struct kdbus_queue *queue); - struct kdbus_queue_entry *kdbus_queue_peek(struct kdbus_queue *queue, - s64 priority, bool use_priority); - --struct kdbus_queue_entry *kdbus_queue_entry_new(struct kdbus_conn *conn_dst, -- const struct kdbus_kmsg *kmsg, -- struct kdbus_user *user); -+struct kdbus_queue_entry *kdbus_queue_entry_new(struct kdbus_conn *conn_src, -+ struct kdbus_conn *conn_dst, -+ const struct kdbus_kmsg *kmsg); - void kdbus_queue_entry_free(struct kdbus_queue_entry *entry); - int kdbus_queue_entry_install(struct kdbus_queue_entry *entry, - u64 *return_flags, bool install_fds); --- -2.4.3 - - -From 5347bdd081c75f847c9739fc50e43f71440687bb Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Fri, 19 Jun 2015 21:56:25 +0200 -Subject: [PATCH 098/132] kdbus: remove redundant kmsg->dst_name_id - -Right now we store the dst_name_id in "struct kdbus_kmsg" just to make -sure it's available when we allocate the "struct kdbus_queue_entry". This -is really not needed and we can easily get rid of this field by passing -the kdbus_name_entry to the queue allocator. - -No change in behavior. - -This change allows us to make "kmsg" constant in kdbus_pin_dst() and avoid -touching it ever outside of kmsg-allocation. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> ---- - ipc/kdbus/bus.c | 6 ++++-- - ipc/kdbus/connection.c | 29 ++++++++++++++++------------- - ipc/kdbus/connection.h | 3 ++- - ipc/kdbus/message.h | 2 -- - ipc/kdbus/notify.c | 3 ++- - ipc/kdbus/queue.c | 1 - - 6 files changed, 24 insertions(+), 20 deletions(-) - -diff --git a/ipc/kdbus/bus.c b/ipc/kdbus/bus.c -index 3c33339cf332..16f69acfec8a 100644 ---- a/ipc/kdbus/bus.c -+++ b/ipc/kdbus/bus.c -@@ -303,7 +303,8 @@ void kdbus_bus_broadcast(struct kdbus_bus *bus, - continue; - } - -- ret = kdbus_conn_entry_insert(conn_src, conn_dst, kmsg, NULL); -+ ret = kdbus_conn_entry_insert(conn_src, conn_dst, kmsg, NULL, -+ NULL); - if (ret < 0) - kdbus_conn_lost_message(conn_dst); - } -@@ -346,7 +347,8 @@ void kdbus_bus_eavesdrop(struct kdbus_bus *bus, - } - } - -- ret = kdbus_conn_entry_insert(conn_src, conn_dst, kmsg, NULL); -+ ret = kdbus_conn_entry_insert(conn_src, conn_dst, kmsg, NULL, -+ NULL); - if (ret < 0) - kdbus_conn_lost_message(conn_dst); - } -diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c -index f1667df70b7f..2ce63ccca3b4 100644 ---- a/ipc/kdbus/connection.c -+++ b/ipc/kdbus/connection.c -@@ -866,13 +866,15 @@ static int kdbus_conn_entry_sync_attach(struct kdbus_conn *conn_dst, - * @conn_dst: The connection to queue into - * @kmsg: The kmsg to queue - * @reply: The reply tracker to attach to the queue entry -+ * @name: Destination name this msg is sent to, or NULL - * - * 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_reply *reply) -+ struct kdbus_reply *reply, -+ const struct kdbus_name_entry *name) - { - struct kdbus_queue_entry *entry; - int ret; -@@ -891,6 +893,14 @@ int kdbus_conn_entry_insert(struct kdbus_conn *conn_src, - schedule_delayed_work(&conn_src->work, 0); - } - -+ /* -+ * Record the sequence number of the registered name; it will -+ * be remembered by the queue, in case messages addressed to a -+ * name need to be moved from or to an activator. -+ */ -+ if (name) -+ entry->dst_name_id = name->name_id; -+ - kdbus_queue_entry_enqueue(entry, reply); - wake_up_interruptible(&conn_dst->wait); - -@@ -1023,14 +1033,14 @@ static int kdbus_conn_wait_reply(struct kdbus_conn *conn_src, - } - - static int kdbus_pin_dst(struct kdbus_bus *bus, -- struct kdbus_kmsg *kmsg, -+ const struct kdbus_kmsg *kmsg, - struct kdbus_name_entry **out_name, - struct kdbus_conn **out_dst) - { - struct kdbus_msg_resources *res = kmsg->res; -+ const struct kdbus_msg *msg = &kmsg->msg; - struct kdbus_name_entry *name = NULL; - struct kdbus_conn *dst = NULL; -- struct kdbus_msg *msg = &kmsg->msg; - int ret; - - if (WARN_ON(!res)) -@@ -1075,13 +1085,6 @@ static int kdbus_pin_dst(struct kdbus_bus *bus, - ret = -EADDRNOTAVAIL; - goto error; - } -- -- /* -- * 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 an activator. -- */ -- kmsg->dst_name_id = name->name_id; - } - - *out_name = name; -@@ -1142,7 +1145,7 @@ static int kdbus_conn_reply(struct kdbus_conn *src, struct kdbus_kmsg *kmsg) - if (wake) - ret = kdbus_conn_entry_sync_attach(dst, kmsg, wake); - else -- ret = kdbus_conn_entry_insert(src, dst, kmsg, NULL); -+ ret = kdbus_conn_entry_insert(src, dst, kmsg, NULL, name); - - exit: - up_read(&bus->name_registry->rwlock); -@@ -1217,7 +1220,7 @@ static struct kdbus_reply *kdbus_conn_call(struct kdbus_conn *src, - - kdbus_bus_eavesdrop(bus, src, kmsg); - -- ret = kdbus_conn_entry_insert(src, dst, kmsg, wait); -+ ret = kdbus_conn_entry_insert(src, dst, kmsg, wait, name); - if (ret < 0) - goto exit; - -@@ -1287,7 +1290,7 @@ static int kdbus_conn_unicast(struct kdbus_conn *src, struct kdbus_kmsg *kmsg) - if (!is_signal) - kdbus_bus_eavesdrop(bus, src, kmsg); - -- ret = kdbus_conn_entry_insert(src, dst, kmsg, wait); -+ ret = kdbus_conn_entry_insert(src, dst, kmsg, wait, name); - if (ret < 0 && !is_signal) - goto exit; - -diff --git a/ipc/kdbus/connection.h b/ipc/kdbus/connection.h -index aa4234a4e3e4..8cffba94a564 100644 ---- a/ipc/kdbus/connection.h -+++ b/ipc/kdbus/connection.h -@@ -135,7 +135,8 @@ void kdbus_conn_lost_message(struct kdbus_conn *c); - int kdbus_conn_entry_insert(struct kdbus_conn *conn_src, - struct kdbus_conn *conn_dst, - const struct kdbus_kmsg *kmsg, -- struct kdbus_reply *reply); -+ struct kdbus_reply *reply, -+ const struct kdbus_name_entry *name); - void kdbus_conn_move_messages(struct kdbus_conn *conn_dst, - struct kdbus_conn *conn_src, - u64 name_id); -diff --git a/ipc/kdbus/message.h b/ipc/kdbus/message.h -index 3b733474f335..88e2366e49b6 100644 ---- a/ipc/kdbus/message.h -+++ b/ipc/kdbus/message.h -@@ -86,7 +86,6 @@ kdbus_msg_resources_unref(struct kdbus_msg_resources *r); - * @notify_old_id: Short-cut for faster lookup - * @notify_new_id: Short-cut for faster lookup - * @notify_name: Short-cut for faster lookup -- * @dst_name_id: Short-cut to msg for faster lookup - * @bloom_filter: Bloom filter to match message properties - * @notify_entry: List of kernel-generated notifications - * @iov: Array of iovec, describing the payload to copy -@@ -104,7 +103,6 @@ struct kdbus_kmsg { - u64 notify_new_id; - const char *notify_name; - -- u64 dst_name_id; - const struct kdbus_bloom_filter *bloom_filter; - struct list_head notify_entry; - -diff --git a/ipc/kdbus/notify.c b/ipc/kdbus/notify.c -index 216720fc26ff..bcf7555e386a 100644 ---- a/ipc/kdbus/notify.c -+++ b/ipc/kdbus/notify.c -@@ -218,7 +218,8 @@ void kdbus_notify_flush(struct kdbus_bus *bus) - conn = kdbus_bus_find_conn_by_id(bus, kmsg->msg.dst_id); - if (conn) { - kdbus_bus_eavesdrop(bus, NULL, kmsg); -- kdbus_conn_entry_insert(NULL, conn, kmsg, NULL); -+ kdbus_conn_entry_insert(NULL, conn, kmsg, NULL, -+ NULL); - kdbus_conn_unref(conn); - } - } else { -diff --git a/ipc/kdbus/queue.c b/ipc/kdbus/queue.c -index 43824c93fb03..4749b23a4f14 100644 ---- a/ipc/kdbus/queue.c -+++ b/ipc/kdbus/queue.c -@@ -203,7 +203,6 @@ struct kdbus_queue_entry *kdbus_queue_entry_new(struct kdbus_conn *conn_src, - - INIT_LIST_HEAD(&entry->entry); - entry->priority = msg->priority; -- entry->dst_name_id = kmsg->dst_name_id; - entry->msg_res = kdbus_msg_resources_ref(res); - entry->proc_meta = kdbus_meta_proc_ref(kmsg->proc_meta); - entry->conn_meta = kdbus_meta_conn_ref(kmsg->conn_meta); --- -2.4.3 - - -From 462d196d27840d84e1ff686c481fbbd99509864e Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Fri, 19 Jun 2015 23:04:49 +0200 -Subject: [PATCH 099/132] kdbus: simplify collecting metadata on messages - -Instead of collecting metadata on the call-side for each message origin, -move it to the core: Handle it directly before allocating the message -slice. - -The number of times we call into the helper stays exactly the same, but -the code paths are reduced significantly. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> ---- - ipc/kdbus/bus.c | 16 ---------------- - ipc/kdbus/connection.c | 31 ++++++++++++------------------- - ipc/kdbus/message.c | 4 ++-- - ipc/kdbus/message.h | 4 ++-- - 4 files changed, 16 insertions(+), 39 deletions(-) - -diff --git a/ipc/kdbus/bus.c b/ipc/kdbus/bus.c -index 16f69acfec8a..bc3c3c0383cb 100644 ---- a/ipc/kdbus/bus.c -+++ b/ipc/kdbus/bus.c -@@ -284,13 +284,6 @@ void kdbus_bus_broadcast(struct kdbus_bus *bus, - */ - if (!kdbus_conn_policy_talk(conn_dst, NULL, conn_src)) - continue; -- -- ret = kdbus_kmsg_collect_metadata(kmsg, conn_src, -- conn_dst); -- if (ret < 0) { -- kdbus_conn_lost_message(conn_dst); -- continue; -- } - } else { - /* - * Check if there is a policy db that prevents the -@@ -338,15 +331,6 @@ void kdbus_bus_eavesdrop(struct kdbus_bus *bus, - - down_read(&bus->conn_rwlock); - list_for_each_entry(conn_dst, &bus->monitors_list, monitor_entry) { -- if (conn_src) { -- ret = kdbus_kmsg_collect_metadata(kmsg, conn_src, -- conn_dst); -- if (ret < 0) { -- kdbus_conn_lost_message(conn_dst); -- continue; -- } -- } -- - ret = kdbus_conn_entry_insert(conn_src, conn_dst, kmsg, NULL, - NULL); - if (ret < 0) -diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c -index 2ce63ccca3b4..25e49455b24b 100644 ---- a/ipc/kdbus/connection.c -+++ b/ipc/kdbus/connection.c -@@ -813,7 +813,12 @@ static int kdbus_conn_entry_sync_attach(struct kdbus_conn *conn_dst, - { - struct kdbus_queue_entry *entry; - int remote_ret; -- int ret = 0; -+ int ret; -+ -+ ret = kdbus_kmsg_collect_metadata(kmsg, reply_wake->reply_src, -+ conn_dst); -+ if (ret < 0) -+ return ret; - - mutex_lock(&reply_wake->reply_dst->lock); - -@@ -879,6 +884,12 @@ int kdbus_conn_entry_insert(struct kdbus_conn *conn_src, - struct kdbus_queue_entry *entry; - int ret; - -+ if (conn_src) { -+ ret = kdbus_kmsg_collect_metadata(kmsg, conn_src, conn_dst); -+ if (ret < 0) -+ return ret; -+ } -+ - kdbus_conn_lock2(conn_src, conn_dst); - - entry = kdbus_conn_entry_make(conn_src, conn_dst, kmsg); -@@ -1132,12 +1143,6 @@ static int kdbus_conn_reply(struct kdbus_conn *src, struct kdbus_kmsg *kmsg) - goto exit; - } - -- /* attach metadata */ -- -- ret = kdbus_kmsg_collect_metadata(kmsg, src, dst); -- if (ret < 0) -- goto exit; -- - /* send message */ - - kdbus_bus_eavesdrop(bus, src, kmsg); -@@ -1210,12 +1215,6 @@ static struct kdbus_reply *kdbus_conn_call(struct kdbus_conn *src, - goto exit; - } - -- /* attach metadata */ -- -- ret = kdbus_kmsg_collect_metadata(kmsg, src, dst); -- if (ret < 0) -- goto exit; -- - /* send message */ - - kdbus_bus_eavesdrop(bus, src, kmsg); -@@ -1279,12 +1278,6 @@ static int kdbus_conn_unicast(struct kdbus_conn *src, struct kdbus_kmsg *kmsg) - } - } - -- /* attach metadata */ -- -- ret = kdbus_kmsg_collect_metadata(kmsg, src, dst); -- if (ret < 0) -- goto exit; -- - /* send message */ - - if (!is_signal) -diff --git a/ipc/kdbus/message.c b/ipc/kdbus/message.c -index 974e8c4f6039..9346a04e10ef 100644 ---- a/ipc/kdbus/message.c -+++ b/ipc/kdbus/message.c -@@ -619,8 +619,8 @@ exit_free: - * - * Return: 0 on success, negative error code on failure. - */ --int kdbus_kmsg_collect_metadata(struct kdbus_kmsg *kmsg, struct kdbus_conn *src, -- struct kdbus_conn *dst) -+int kdbus_kmsg_collect_metadata(const struct kdbus_kmsg *kmsg, -+ struct kdbus_conn *src, struct kdbus_conn *dst) - { - u64 attach; - int ret; -diff --git a/ipc/kdbus/message.h b/ipc/kdbus/message.h -index 88e2366e49b6..9a11389d9f27 100644 ---- a/ipc/kdbus/message.h -+++ b/ipc/kdbus/message.h -@@ -125,7 +125,7 @@ struct kdbus_kmsg *kdbus_kmsg_new(struct kdbus_bus *bus, size_t extra_size); - struct kdbus_kmsg *kdbus_kmsg_new_from_cmd(struct kdbus_conn *conn, - struct kdbus_cmd_send *cmd_send); - void kdbus_kmsg_free(struct kdbus_kmsg *kmsg); --int kdbus_kmsg_collect_metadata(struct kdbus_kmsg *kmsg, struct kdbus_conn *src, -- struct kdbus_conn *dst); -+int kdbus_kmsg_collect_metadata(const struct kdbus_kmsg *kmsg, -+ struct kdbus_conn *src, struct kdbus_conn *dst); - - #endif --- -2.4.3 - - -From 6d75879b543c4eeb9544547e87174bba1be3a173 Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Fri, 19 Jun 2015 23:38:19 +0200 -Subject: [PATCH 100/132] kdbus: simplify notification shortcuts - -Right now, we have a bunch of shortcuts in "struct kdbus_kmsg" that cache -the values of the first kdbus-item, _iff_ the message is a kernel -notification. These are then used during match-db lookups and policy -lookups. - -These shortcuts make the actually more complex and in no way faster. Drop -them in favor of a simple "struct kdbus_item *notify" shortcut which -points to the notification item (to distinguish it from normal -user-supplied messages). This way, we save a bunch of code and can even -simplify the notification message setup (as it is now fully generic). - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> ---- - ipc/kdbus/bus.c | 3 +- - ipc/kdbus/connection.c | 15 +++++----- - ipc/kdbus/connection.h | 2 +- - ipc/kdbus/match.c | 14 +++++---- - ipc/kdbus/message.c | 54 ++++++++++++++++++---------------- - ipc/kdbus/message.h | 14 ++++----- - ipc/kdbus/notify.c | 78 ++++++++++++-------------------------------------- - 7 files changed, 69 insertions(+), 111 deletions(-) - -diff --git a/ipc/kdbus/bus.c b/ipc/kdbus/bus.c -index bc3c3c0383cb..4f51723f8780 100644 ---- a/ipc/kdbus/bus.c -+++ b/ipc/kdbus/bus.c -@@ -291,8 +291,7 @@ void kdbus_bus_broadcast(struct kdbus_bus *bus, - * notification - */ - if (!kdbus_conn_policy_see_notification(conn_dst, NULL, -- kmsg->notify_type, -- kmsg->notify_name)) -+ &kmsg->msg)) - continue; - } - -diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c -index 25e49455b24b..29b99c023bfe 100644 ---- a/ipc/kdbus/connection.c -+++ b/ipc/kdbus/connection.c -@@ -1537,17 +1537,15 @@ static bool kdbus_conn_policy_see(struct kdbus_conn *conn, - * receive a given kernel notification - * @conn: Connection - * @conn_creds: Credentials of @conn to use for policy check -- * @type: Type of notification -- * @name: Well-known name this notification is about, or NULL -+ * @msg: Notification message - * -- * This checks whether @conn is allowed to see the kernel notification of type -- * @type for well-known name @name. -+ * This checks whether @conn is allowed to see the kernel notification. - * - * Return: true if allowed, false if not. - */ - bool kdbus_conn_policy_see_notification(struct kdbus_conn *conn, - const struct cred *conn_creds, -- u64 type, const char *name) -+ const struct kdbus_msg *msg) - { - /* - * Depending on the notification type, broadcasted kernel notifications -@@ -1561,11 +1559,12 @@ bool kdbus_conn_policy_see_notification(struct kdbus_conn *conn, - * broadcast to everyone, to allow tracking peers. - */ - -- switch (type) { -+ switch (msg->items[0].type) { - case KDBUS_ITEM_NAME_ADD: - case KDBUS_ITEM_NAME_REMOVE: - case KDBUS_ITEM_NAME_CHANGE: -- return kdbus_conn_policy_see_name(conn, conn_creds, name); -+ return kdbus_conn_policy_see_name(conn, conn_creds, -+ msg->items[0].name_change.name); - - case KDBUS_ITEM_ID_ADD: - case KDBUS_ITEM_ID_REMOVE: -@@ -1573,7 +1572,7 @@ bool kdbus_conn_policy_see_notification(struct kdbus_conn *conn, - - default: - WARN(1, "Invalid type for notification broadcast: %llu\n", -- (unsigned long long)type); -+ (unsigned long long)msg->items[0].type); - return false; - } - } -diff --git a/ipc/kdbus/connection.h b/ipc/kdbus/connection.h -index 8cffba94a564..90c1bcc91fe6 100644 ---- a/ipc/kdbus/connection.h -+++ b/ipc/kdbus/connection.h -@@ -153,7 +153,7 @@ bool kdbus_conn_policy_see_name_unlocked(struct kdbus_conn *conn, - const char *name); - bool kdbus_conn_policy_see_notification(struct kdbus_conn *conn, - const struct cred *curr_creds, -- u64 type, const char *name); -+ const struct kdbus_msg *msg); - - /* command dispatcher */ - struct kdbus_conn *kdbus_cmd_hello(struct kdbus_ep *ep, bool privileged, -diff --git a/ipc/kdbus/match.c b/ipc/kdbus/match.c -index 869a9fbce37d..3f86e4c81468 100644 ---- a/ipc/kdbus/match.c -+++ b/ipc/kdbus/match.c -@@ -225,24 +225,26 @@ static bool kdbus_match_rule_conn(const struct kdbus_match_rule *r, - static bool kdbus_match_rule_kernel(const struct kdbus_match_rule *r, - const struct kdbus_kmsg *kmsg) - { -- if (kmsg->notify_type != r->type) -+ struct kdbus_item *n = kmsg->notify; -+ -+ if (WARN_ON(!n) || n->type != r->type) - return false; - - switch (r->type) { - case KDBUS_ITEM_ID_ADD: - return r->new_id == KDBUS_MATCH_ID_ANY || -- r->new_id == kmsg->notify_new_id; -+ r->new_id == n->id_change.id; - case KDBUS_ITEM_ID_REMOVE: - return r->old_id == KDBUS_MATCH_ID_ANY || -- r->old_id == kmsg->notify_old_id; -+ r->old_id == n->id_change.id; - case KDBUS_ITEM_NAME_ADD: - case KDBUS_ITEM_NAME_CHANGE: - case KDBUS_ITEM_NAME_REMOVE: - return (r->old_id == KDBUS_MATCH_ID_ANY || -- r->old_id == kmsg->notify_old_id) && -+ r->old_id == n->name_change.old_id.id) && - (r->new_id == KDBUS_MATCH_ID_ANY || -- r->new_id == kmsg->notify_new_id) && -- (!r->name || !strcmp(r->name, kmsg->notify_name)); -+ r->new_id == n->name_change.new_id.id) && -+ (!r->name || !strcmp(r->name, n->name_change.name)); - default: - return false; - } -diff --git a/ipc/kdbus/message.c b/ipc/kdbus/message.c -index 9346a04e10ef..7f23e5c857dd 100644 ---- a/ipc/kdbus/message.c -+++ b/ipc/kdbus/message.c -@@ -124,46 +124,50 @@ void kdbus_kmsg_free(struct kdbus_kmsg *kmsg) - kfree(kmsg); - } - --/** -- * kdbus_kmsg_new() - allocate message -- * @bus: Bus this message is allocated on -- * @extra_size: Additional size to reserve for data -- * -- * Return: new kdbus_kmsg on success, ERR_PTR on failure. -- */ --struct kdbus_kmsg *kdbus_kmsg_new(struct kdbus_bus *bus, size_t extra_size) -+struct kdbus_kmsg *kdbus_kmsg_new_kernel(struct kdbus_bus *bus, -+ u64 dst, u64 cookie_timeout, -+ size_t it_size, size_t it_type) - { -- struct kdbus_kmsg *m; -+ struct kdbus_kmsg *kmsg; - size_t size; - int ret; - -- size = sizeof(struct kdbus_kmsg) + KDBUS_ITEM_SIZE(extra_size); -- m = kzalloc(size, GFP_KERNEL); -- if (!m) -+ size = sizeof(struct kdbus_kmsg) + KDBUS_ITEM_SIZE(it_size); -+ kmsg = kzalloc(size, GFP_KERNEL); -+ if (!kmsg) - return ERR_PTR(-ENOMEM); - -- m->seq = atomic64_inc_return(&bus->domain->last_id); -- m->msg.size = size - KDBUS_KMSG_HEADER_SIZE; -- m->msg.items[0].size = KDBUS_ITEM_SIZE(extra_size); -+ kmsg->seq = atomic64_inc_return(&bus->domain->last_id); - -- m->proc_meta = kdbus_meta_proc_new(); -- if (IS_ERR(m->proc_meta)) { -- ret = PTR_ERR(m->proc_meta); -- m->proc_meta = NULL; -+ kmsg->proc_meta = kdbus_meta_proc_new(); -+ if (IS_ERR(kmsg->proc_meta)) { -+ ret = PTR_ERR(kmsg->proc_meta); -+ kmsg->proc_meta = NULL; - goto exit; - } - -- m->conn_meta = kdbus_meta_conn_new(); -- if (IS_ERR(m->conn_meta)) { -- ret = PTR_ERR(m->conn_meta); -- m->conn_meta = NULL; -+ kmsg->conn_meta = kdbus_meta_conn_new(); -+ if (IS_ERR(kmsg->conn_meta)) { -+ ret = PTR_ERR(kmsg->conn_meta); -+ kmsg->conn_meta = NULL; - goto exit; - } - -- return m; -+ kmsg->msg.size = size - KDBUS_KMSG_HEADER_SIZE; -+ kmsg->msg.flags = (dst == KDBUS_DST_ID_BROADCAST) ? -+ KDBUS_MSG_SIGNAL : 0; -+ kmsg->msg.dst_id = dst; -+ kmsg->msg.src_id = KDBUS_SRC_ID_KERNEL; -+ kmsg->msg.payload_type = KDBUS_PAYLOAD_KERNEL; -+ kmsg->msg.cookie_reply = cookie_timeout; -+ kmsg->notify = kmsg->msg.items; -+ kmsg->notify->size = KDBUS_ITEM_HEADER_SIZE + it_size; -+ kmsg->notify->type = it_type; -+ -+ return kmsg; - - exit: -- kdbus_kmsg_free(m); -+ kdbus_kmsg_free(kmsg); - return ERR_PTR(ret); - } - -diff --git a/ipc/kdbus/message.h b/ipc/kdbus/message.h -index 9a11389d9f27..5755ad4c9fd9 100644 ---- a/ipc/kdbus/message.h -+++ b/ipc/kdbus/message.h -@@ -82,10 +82,7 @@ kdbus_msg_resources_unref(struct kdbus_msg_resources *r); - /** - * struct kdbus_kmsg - internal message handling data - * @seq: Domain-global message sequence number -- * @notify_type: Short-cut for faster lookup -- * @notify_old_id: Short-cut for faster lookup -- * @notify_new_id: Short-cut for faster lookup -- * @notify_name: Short-cut for faster lookup -+ * @notify: Short-cut to notify-item for kernel notifications - * @bloom_filter: Bloom filter to match message properties - * @notify_entry: List of kernel-generated notifications - * @iov: Array of iovec, describing the payload to copy -@@ -98,10 +95,7 @@ kdbus_msg_resources_unref(struct kdbus_msg_resources *r); - */ - struct kdbus_kmsg { - u64 seq; -- u64 notify_type; -- u64 notify_old_id; -- u64 notify_new_id; -- const char *notify_name; -+ struct kdbus_item *notify; - - const struct kdbus_bloom_filter *bloom_filter; - struct list_head notify_entry; -@@ -121,7 +115,9 @@ struct kdbus_kmsg { - struct kdbus_bus; - struct kdbus_conn; - --struct kdbus_kmsg *kdbus_kmsg_new(struct kdbus_bus *bus, size_t extra_size); -+struct kdbus_kmsg *kdbus_kmsg_new_kernel(struct kdbus_bus *bus, -+ u64 dst, u64 cookie_timeout, -+ size_t it_size, size_t it_type); - struct kdbus_kmsg *kdbus_kmsg_new_from_cmd(struct kdbus_conn *conn, - struct kdbus_cmd_send *cmd_send); - void kdbus_kmsg_free(struct kdbus_kmsg *kmsg); -diff --git a/ipc/kdbus/notify.c b/ipc/kdbus/notify.c -index bcf7555e386a..a07d242d0470 100644 ---- a/ipc/kdbus/notify.c -+++ b/ipc/kdbus/notify.c -@@ -39,29 +39,13 @@ static inline void kdbus_notify_add_tail(struct kdbus_kmsg *kmsg, - static int kdbus_notify_reply(struct kdbus_bus *bus, u64 id, - u64 cookie, u64 msg_type) - { -- struct kdbus_kmsg *kmsg = NULL; -+ struct kdbus_kmsg *kmsg; - -- WARN_ON(id == 0); -- -- kmsg = kdbus_kmsg_new(bus, 0); -+ kmsg = kdbus_kmsg_new_kernel(bus, id, cookie, 0, msg_type); - if (IS_ERR(kmsg)) - return PTR_ERR(kmsg); - -- /* -- * a kernel-generated notification can only contain one -- * struct kdbus_item, so make a shortcut here for -- * faster lookup in the match db. -- */ -- kmsg->notify_type = msg_type; -- kmsg->msg.flags = KDBUS_MSG_SIGNAL; -- kmsg->msg.dst_id = id; -- kmsg->msg.src_id = KDBUS_SRC_ID_KERNEL; -- kmsg->msg.payload_type = KDBUS_PAYLOAD_KERNEL; -- kmsg->msg.cookie_reply = cookie; -- kmsg->msg.items[0].type = msg_type; -- - kdbus_notify_add_tail(kmsg, bus); -- - return 0; - } - -@@ -115,32 +99,24 @@ int kdbus_notify_name_change(struct kdbus_bus *bus, u64 type, - u64 old_flags, u64 new_flags, - const char *name) - { -- struct kdbus_kmsg *kmsg = NULL; - size_t name_len, extra_size; -+ struct kdbus_kmsg *kmsg; - - name_len = strlen(name) + 1; - extra_size = sizeof(struct kdbus_notify_name_change) + name_len; -- kmsg = kdbus_kmsg_new(bus, extra_size); -+ -+ kmsg = kdbus_kmsg_new_kernel(bus, KDBUS_DST_ID_BROADCAST, 0, -+ extra_size, type); - if (IS_ERR(kmsg)) - return PTR_ERR(kmsg); - -- kmsg->msg.flags = KDBUS_MSG_SIGNAL; -- kmsg->msg.dst_id = KDBUS_DST_ID_BROADCAST; -- kmsg->msg.src_id = KDBUS_SRC_ID_KERNEL; -- kmsg->msg.payload_type = KDBUS_PAYLOAD_KERNEL; -- kmsg->notify_type = type; -- kmsg->notify_old_id = old_id; -- kmsg->notify_new_id = new_id; -- kmsg->msg.items[0].type = type; -- kmsg->msg.items[0].name_change.old_id.id = old_id; -- kmsg->msg.items[0].name_change.old_id.flags = old_flags; -- kmsg->msg.items[0].name_change.new_id.id = new_id; -- kmsg->msg.items[0].name_change.new_id.flags = new_flags; -- memcpy(kmsg->msg.items[0].name_change.name, name, name_len); -- kmsg->notify_name = kmsg->msg.items[0].name_change.name; -+ kmsg->notify->name_change.old_id.id = old_id; -+ kmsg->notify->name_change.old_id.flags = old_flags; -+ kmsg->notify->name_change.new_id.id = new_id; -+ kmsg->notify->name_change.new_id.flags = new_flags; -+ memcpy(kmsg->notify->name_change.name, name, name_len); - - kdbus_notify_add_tail(kmsg, bus); -- - return 0; - } - -@@ -156,37 +132,19 @@ int kdbus_notify_name_change(struct kdbus_bus *bus, u64 type, - */ - int kdbus_notify_id_change(struct kdbus_bus *bus, u64 type, u64 id, u64 flags) - { -- struct kdbus_kmsg *kmsg = NULL; -+ struct kdbus_kmsg *kmsg; -+ size_t extra_size; - -- kmsg = kdbus_kmsg_new(bus, sizeof(struct kdbus_notify_id_change)); -+ extra_size = sizeof(struct kdbus_notify_id_change); -+ kmsg = kdbus_kmsg_new_kernel(bus, KDBUS_DST_ID_BROADCAST, 0, -+ extra_size, type); - if (IS_ERR(kmsg)) - return PTR_ERR(kmsg); - -- kmsg->msg.flags = KDBUS_MSG_SIGNAL; -- kmsg->msg.dst_id = KDBUS_DST_ID_BROADCAST; -- kmsg->msg.src_id = KDBUS_SRC_ID_KERNEL; -- kmsg->msg.payload_type = KDBUS_PAYLOAD_KERNEL; -- kmsg->notify_type = type; -- -- switch (type) { -- case KDBUS_ITEM_ID_ADD: -- kmsg->notify_new_id = id; -- break; -- -- case KDBUS_ITEM_ID_REMOVE: -- kmsg->notify_old_id = id; -- break; -- -- default: -- BUG(); -- } -- -- kmsg->msg.items[0].type = type; -- kmsg->msg.items[0].id_change.id = id; -- kmsg->msg.items[0].id_change.flags = flags; -+ kmsg->notify->id_change.id = id; -+ kmsg->notify->id_change.flags = flags; - - kdbus_notify_add_tail(kmsg, bus); -- - return 0; - } - --- -2.4.3 - - -From 2e3c15be5c1f48a9082b47a5cf825dc7c9592b12 Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Fri, 19 Jun 2015 23:56:19 +0200 -Subject: [PATCH 101/132] kdbus: rewrite message importer - -This is a complete rewrite of the message importer (currently known as -'kmsg'). I did some benchmarks on the old code, and our many calls into -kdbus_pool_slice_copy_iovec/kvec() are by far the biggest CPU consumers. -As it turns out, we can reduce the number of calls into that function to -*one* (and one additional call per FD-set transmitted). Compared to our -10x (?) calls we do right now, this reduces the time spent on a message -transaction significantly. - -The new message importer uses a new structure called "struct -kdbus_staging". This structure is solely used to import the "kdbus_msg" -object into the kernel, parse it, create some helper data and then use it -to allocate messages in each receivers pool. The staging object thus is -only used at SEND time and its sole purpose is to prepare for the real -message we allocate (as part of the queue_entry). Hence, the rename to -kdbus_staging, instead of kdbus_kmsg (which was really misleading). - -Furthermore, this patch replaces "struct kdbus_msg_resources". The old -resources contained far more data than was really necessary. There is no -reason to pin VECs until RECV time. This can all be dropped. All that -needs to be pinned is memfds and fds. - -This patch only introduces the new infrastructure. It is not hooked up, -yet. Follow-up patches will make sure it's actually used. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> ---- - ipc/kdbus/message.c | 990 ++++++++++++++++++++++++++++++++++++++++++++++++++++ - ipc/kdbus/message.h | 93 +++++ - 2 files changed, 1083 insertions(+) - -diff --git a/ipc/kdbus/message.c b/ipc/kdbus/message.c -index 7f23e5c857dd..f1ec69f3697f 100644 ---- a/ipc/kdbus/message.c -+++ b/ipc/kdbus/message.c -@@ -638,3 +638,993 @@ int kdbus_kmsg_collect_metadata(const struct kdbus_kmsg *kmsg, - - return kdbus_meta_conn_collect(kmsg->conn_meta, src, kmsg->seq, attach); - } -+ -+static struct kdbus_gaps *kdbus_gaps_new(size_t n_memfds, size_t n_fds) -+{ -+ size_t size_offsets, size_memfds, size_fds, size; -+ struct kdbus_gaps *gaps; -+ -+ size_offsets = n_memfds * sizeof(*gaps->memfd_offsets); -+ size_memfds = n_memfds * sizeof(*gaps->memfd_files); -+ size_fds = n_fds * sizeof(*gaps->fd_files); -+ size = sizeof(*gaps) + size_offsets + size_memfds + size_fds; -+ -+ gaps = kzalloc(size, GFP_KERNEL); -+ if (!gaps) -+ return ERR_PTR(-ENOMEM); -+ -+ kref_init(&gaps->kref); -+ gaps->n_memfds = 0; /* we reserve n_memfds, but don't enforce them */ -+ gaps->memfd_offsets = (void *)(gaps + 1); -+ gaps->memfd_files = (void *)((u8 *)gaps->memfd_offsets + size_offsets); -+ gaps->n_fds = 0; /* we reserve n_fds, but don't enforce them */ -+ gaps->fd_files = (void *)((u8 *)gaps->memfd_files + size_memfds); -+ -+ return gaps; -+} -+ -+static void kdbus_gaps_free(struct kref *kref) -+{ -+ struct kdbus_gaps *gaps = container_of(kref, struct kdbus_gaps, kref); -+ size_t i; -+ -+ for (i = 0; i < gaps->n_fds; ++i) -+ if (gaps->fd_files[i]) -+ fput(gaps->fd_files[i]); -+ for (i = 0; i < gaps->n_memfds; ++i) -+ if (gaps->memfd_files[i]) -+ fput(gaps->memfd_files[i]); -+ -+ kfree(gaps); -+} -+ -+/** -+ * kdbus_gaps_ref() - gain reference -+ * @gaps: gaps object -+ * -+ * Return: @gaps is returned -+ */ -+struct kdbus_gaps *kdbus_gaps_ref(struct kdbus_gaps *gaps) -+{ -+ if (gaps) -+ kref_get(&gaps->kref); -+ return gaps; -+} -+ -+/** -+ * kdbus_gaps_unref() - drop reference -+ * @gaps: gaps object -+ * -+ * Return: NULL -+ */ -+struct kdbus_gaps *kdbus_gaps_unref(struct kdbus_gaps *gaps) -+{ -+ if (gaps) -+ kref_put(&gaps->kref, kdbus_gaps_free); -+ return NULL; -+} -+ -+/** -+ * kdbus_gaps_install() - install file-descriptors -+ * @gaps: gaps object, or NULL -+ * @slice: pool slice that contains the message -+ * @out_incomplete output variable to note incomplete fds -+ * -+ * This function installs all file-descriptors of @gaps into the current -+ * process and copies the file-descriptor numbers into the target pool slice. -+ * -+ * If the file-descriptors were only partially installed, then @out_incomplete -+ * will be set to true. Otherwise, it's set to false. -+ * -+ * Return: 0 on success, negative error code on failure -+ */ -+int kdbus_gaps_install(struct kdbus_gaps *gaps, struct kdbus_pool_slice *slice, -+ bool *out_incomplete) -+{ -+ bool incomplete_fds = false; -+ struct kvec kvec; -+ size_t i, n_fds; -+ int ret, *fds; -+ -+ if (!gaps) { -+ /* nothing to do */ -+ *out_incomplete = incomplete_fds; -+ return 0; -+ } -+ -+ n_fds = gaps->n_fds + gaps->n_memfds; -+ if (n_fds < 1) { -+ /* nothing to do */ -+ *out_incomplete = incomplete_fds; -+ return 0; -+ } -+ -+ fds = kmalloc_array(n_fds, sizeof(*fds), GFP_TEMPORARY); -+ n_fds = 0; -+ if (!fds) -+ return -ENOMEM; -+ -+ /* 1) allocate fds and copy them over */ -+ -+ if (gaps->n_fds > 0) { -+ for (i = 0; i < gaps->n_fds; ++i) { -+ int fd; -+ -+ fd = get_unused_fd_flags(O_CLOEXEC); -+ if (fd < 0) -+ incomplete_fds = true; -+ -+ WARN_ON(!gaps->fd_files[i]); -+ -+ fds[n_fds++] = fd < 0 ? -1 : fd; -+ } -+ -+ /* -+ * The file-descriptor array can only be present once per -+ * message. Hence, prepare all fds and then copy them over with -+ * a single kvec. -+ */ -+ -+ WARN_ON(!gaps->fd_offset); -+ -+ kvec.iov_base = fds; -+ kvec.iov_len = gaps->n_fds * sizeof(*fds); -+ ret = kdbus_pool_slice_copy_kvec(slice, gaps->fd_offset, -+ &kvec, 1, kvec.iov_len); -+ if (ret < 0) -+ goto exit; -+ } -+ -+ for (i = 0; i < gaps->n_memfds; ++i) { -+ int memfd; -+ -+ memfd = get_unused_fd_flags(O_CLOEXEC); -+ if (memfd < 0) { -+ incomplete_fds = true; -+ /* memfds are initialized to -1, skip copying it */ -+ continue; -+ } -+ -+ fds[n_fds++] = memfd; -+ -+ /* -+ * memfds have to be copied individually as they each are put -+ * into a separate item. This should not be an issue, though, -+ * as usually there is no need to send more than one memfd per -+ * message. -+ */ -+ -+ WARN_ON(!gaps->memfd_offsets[i]); -+ WARN_ON(!gaps->memfd_files[i]); -+ -+ kvec.iov_base = &memfd; -+ kvec.iov_len = sizeof(memfd); -+ ret = kdbus_pool_slice_copy_kvec(slice, gaps->memfd_offsets[i], -+ &kvec, 1, kvec.iov_len); -+ if (ret < 0) -+ goto exit; -+ } -+ -+ /* 2) install fds now that everything was successful */ -+ -+ for (i = 0; i < gaps->n_fds; ++i) -+ if (fds[i] >= 0) -+ fd_install(fds[i], get_file(gaps->fd_files[i])); -+ for (i = 0; i < gaps->n_memfds; ++i) -+ if (fds[gaps->n_fds + i] >= 0) -+ fd_install(fds[gaps->n_fds + i], -+ get_file(gaps->memfd_files[i])); -+ -+ ret = 0; -+ -+exit: -+ if (ret < 0) -+ for (i = 0; i < n_fds; ++i) -+ put_unused_fd(fds[i]); -+ kfree(fds); -+ *out_incomplete = incomplete_fds; -+ return ret; -+} -+ -+static struct file *kdbus_get_fd(int fd) -+{ -+ struct file *f, *ret; -+ struct inode *inode; -+ struct socket *sock; -+ -+ if (fd < 0) -+ return ERR_PTR(-EBADF); -+ -+ f = fget_raw(fd); -+ if (!f) -+ return ERR_PTR(-EBADF); -+ -+ inode = file_inode(f); -+ sock = S_ISSOCK(inode->i_mode) ? SOCKET_I(inode) : NULL; -+ -+ if (f->f_mode & FMODE_PATH) -+ ret = f; /* O_PATH is always allowed */ -+ else if (f->f_op == &kdbus_handle_ops) -+ ret = ERR_PTR(-EOPNOTSUPP); /* disallow kdbus-fd over kdbus */ -+ else if (sock && sock->sk && sock->ops && sock->ops->family == PF_UNIX) -+ ret = ERR_PTR(-EOPNOTSUPP); /* disallow UDS over kdbus */ -+ else -+ ret = f; /* all other are allowed */ -+ -+ if (f != ret) -+ fput(f); -+ -+ return ret; -+} -+ -+static struct file *kdbus_get_memfd(const struct kdbus_memfd *memfd) -+{ -+ const int m = F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL; -+ struct file *f, *ret; -+ int s; -+ -+ if (memfd->fd < 0) -+ return ERR_PTR(-EBADF); -+ -+ f = fget(memfd->fd); -+ if (!f) -+ return ERR_PTR(-EBADF); -+ -+ s = shmem_get_seals(f); -+ if (s < 0) -+ ret = ERR_PTR(-EMEDIUMTYPE); -+ else if ((s & m) != m) -+ ret = ERR_PTR(-ETXTBSY); -+ else if (memfd->start + memfd->size > (u64)i_size_read(file_inode(f))) -+ ret = ERR_PTR(-EFAULT); -+ else -+ ret = f; -+ -+ if (f != ret) -+ fput(f); -+ -+ return ret; -+} -+ -+static int kdbus_msg_examine(struct kdbus_msg *msg, struct kdbus_bus *bus, -+ struct kdbus_cmd_send *cmd, size_t *out_n_memfds, -+ size_t *out_n_fds, size_t *out_n_parts) -+{ -+ struct kdbus_item *item, *fds = NULL, *bloom = NULL, *dstname = NULL; -+ u64 n_parts, n_memfds, n_fds, vec_size; -+ -+ /* -+ * Step 1: -+ * Validate the message and command parameters. -+ */ -+ -+ /* KDBUS_PAYLOAD_KERNEL is reserved to kernel messages */ -+ if (msg->payload_type == KDBUS_PAYLOAD_KERNEL) -+ return -EINVAL; -+ -+ if (msg->dst_id == KDBUS_DST_ID_BROADCAST) { -+ /* broadcasts must be marked as signals */ -+ if (!(msg->flags & KDBUS_MSG_SIGNAL)) -+ return -EBADMSG; -+ /* broadcasts cannot have timeouts */ -+ if (msg->timeout_ns > 0) -+ return -ENOTUNIQ; -+ } -+ -+ if (msg->flags & KDBUS_MSG_EXPECT_REPLY) { -+ /* if you expect a reply, you must specify a timeout */ -+ if (msg->timeout_ns == 0) -+ return -EINVAL; -+ /* signals cannot have replies */ -+ if (msg->flags & KDBUS_MSG_SIGNAL) -+ return -ENOTUNIQ; -+ } else { -+ /* must expect reply if sent as synchronous call */ -+ if (cmd->flags & KDBUS_SEND_SYNC_REPLY) -+ return -EINVAL; -+ /* cannot mark replies as signal */ -+ if (msg->cookie_reply && (msg->flags & KDBUS_MSG_SIGNAL)) -+ return -EINVAL; -+ } -+ -+ /* -+ * Step 2: -+ * Validate all passed items. While at it, select some statistics that -+ * are required to allocate state objects later on. -+ * -+ * Generic item validation has already been done via -+ * kdbus_item_validate(). Furthermore, the number of items is naturally -+ * limited by the maximum message size. Hence, only non-generic item -+ * checks are performed here (mainly integer overflow tests). -+ */ -+ -+ n_parts = 0; -+ n_memfds = 0; -+ n_fds = 0; -+ vec_size = 0; -+ -+ KDBUS_ITEMS_FOREACH(item, msg->items, KDBUS_ITEMS_SIZE(msg, items)) { -+ switch (item->type) { -+ case KDBUS_ITEM_PAYLOAD_VEC: { -+ void __force __user *ptr = KDBUS_PTR(item->vec.address); -+ u64 size = item->vec.size; -+ -+ if (vec_size + size < vec_size) -+ return -EMSGSIZE; -+ if (vec_size + size > KDBUS_MSG_MAX_PAYLOAD_VEC_SIZE) -+ return -EMSGSIZE; -+ if (ptr && unlikely(!access_ok(VERIFY_READ, ptr, size))) -+ return -EFAULT; -+ -+ if (ptr || size % 8) /* data or padding */ -+ ++n_parts; -+ break; -+ } -+ case KDBUS_ITEM_PAYLOAD_MEMFD: { -+ u64 start = item->memfd.start; -+ u64 size = item->memfd.size; -+ -+ if (start + size < start) -+ return -EMSGSIZE; -+ if (n_memfds >= KDBUS_MSG_MAX_MEMFD_ITEMS) -+ return -E2BIG; -+ -+ ++n_memfds; -+ if (size % 8) /* vec-padding required */ -+ ++n_parts; -+ break; -+ } -+ case KDBUS_ITEM_FDS: { -+ if (fds) -+ return -EEXIST; -+ -+ fds = item; -+ n_fds = KDBUS_ITEM_PAYLOAD_SIZE(item) / sizeof(int); -+ if (n_fds > KDBUS_CONN_MAX_FDS_PER_USER) -+ return -EMFILE; -+ -+ break; -+ } -+ case KDBUS_ITEM_BLOOM_FILTER: { -+ u64 bloom_size; -+ -+ if (bloom) -+ return -EEXIST; -+ -+ bloom = item; -+ bloom_size = KDBUS_ITEM_PAYLOAD_SIZE(item) - -+ offsetof(struct kdbus_bloom_filter, data); -+ if (!KDBUS_IS_ALIGNED8(bloom_size)) -+ return -EFAULT; -+ if (bloom_size != bus->bloom.size) -+ return -EDOM; -+ -+ break; -+ } -+ case KDBUS_ITEM_DST_NAME: { -+ if (dstname) -+ return -EEXIST; -+ -+ dstname = item; -+ if (!kdbus_name_is_valid(item->str, false)) -+ return -EINVAL; -+ if (msg->dst_id == KDBUS_DST_ID_BROADCAST) -+ return -EBADMSG; -+ -+ break; -+ } -+ default: -+ return -EINVAL; -+ } -+ } -+ -+ /* -+ * Step 3: -+ * Validate that required items were actually passed, and that no item -+ * contradicts the message flags. -+ */ -+ -+ /* bloom filters must be attached _iff_ it's a signal */ -+ if (!(msg->flags & KDBUS_MSG_SIGNAL) != !bloom) -+ return -EBADMSG; -+ /* destination name is required if no ID is given */ -+ if (msg->dst_id == KDBUS_DST_ID_NAME && !dstname) -+ return -EDESTADDRREQ; -+ /* cannot send file-descriptors attached to broadcasts */ -+ if (msg->dst_id == KDBUS_DST_ID_BROADCAST && fds) -+ return -ENOTUNIQ; -+ -+ *out_n_memfds = n_memfds; -+ *out_n_fds = n_fds; -+ *out_n_parts = n_parts; -+ -+ return 0; -+} -+ -+static bool kdbus_staging_merge_vecs(struct kdbus_staging *staging, -+ struct kdbus_item **prev_item, -+ struct iovec **prev_vec, -+ const struct kdbus_item *merge) -+{ -+ void __user *ptr = (void __user *)KDBUS_PTR(merge->vec.address); -+ u64 padding = merge->vec.size % 8; -+ struct kdbus_item *prev = *prev_item; -+ struct iovec *vec = *prev_vec; -+ -+ /* XXX: merging is disabled so far */ -+ if (0 && prev && prev->type == KDBUS_ITEM_PAYLOAD_OFF && -+ !merge->vec.address == !prev->vec.address) { -+ /* -+ * If we merge two VECs, we can always drop the second -+ * PAYLOAD_VEC item. Hence, include its size in the previous -+ * one. -+ */ -+ prev->vec.size += merge->vec.size; -+ -+ if (ptr) { -+ /* -+ * If we merge two data VECs, we need two iovecs to copy -+ * the data. But the items can be easily merged by -+ * summing their lengths. -+ */ -+ vec = &staging->parts[staging->n_parts++]; -+ vec->iov_len = merge->vec.size; -+ vec->iov_base = ptr; -+ staging->n_payload += vec->iov_len; -+ } else if (padding) { -+ /* -+ * If we merge two 0-vecs with the second 0-vec -+ * requiring padding, we need to insert an iovec to copy -+ * the 0-padding. We try merging it with the previous -+ * 0-padding iovec. This might end up with an -+ * iov_len==0, in which case we simply drop the iovec. -+ */ -+ if (vec) { -+ staging->n_payload -= vec->iov_len; -+ vec->iov_len = prev->vec.size % 8; -+ if (!vec->iov_len) { -+ --staging->n_parts; -+ vec = NULL; -+ } else { -+ staging->n_payload += vec->iov_len; -+ } -+ } else { -+ vec = &staging->parts[staging->n_parts++]; -+ vec->iov_len = padding; -+ vec->iov_base = (char __user *)zeros; -+ staging->n_payload += vec->iov_len; -+ } -+ } else { -+ /* -+ * If we merge two 0-vecs with the second 0-vec having -+ * no padding, we know the padding of the first stays -+ * the same. Hence, @vec needs no adjustment. -+ */ -+ } -+ -+ /* successfully merged with previous item */ -+ merge = prev; -+ } else { -+ /* -+ * If we cannot merge the payload item with the previous one, -+ * we simply insert a new iovec for the data/padding. -+ */ -+ if (ptr) { -+ vec = &staging->parts[staging->n_parts++]; -+ vec->iov_len = merge->vec.size; -+ vec->iov_base = ptr; -+ staging->n_payload += vec->iov_len; -+ } else if (padding) { -+ vec = &staging->parts[staging->n_parts++]; -+ vec->iov_len = padding; -+ vec->iov_base = (char __user *)zeros; -+ staging->n_payload += vec->iov_len; -+ } else { -+ vec = NULL; -+ } -+ } -+ -+ *prev_item = (struct kdbus_item *)merge; -+ *prev_vec = vec; -+ -+ return merge == prev; -+} -+ -+static int kdbus_staging_import(struct kdbus_staging *staging) -+{ -+ struct kdbus_item *it, *item, *last, *prev_payload; -+ struct kdbus_gaps *gaps = staging->gaps; -+ struct kdbus_msg *msg = staging->msg; -+ struct iovec *part, *prev_part; -+ bool drop_item; -+ -+ drop_item = false; -+ last = NULL; -+ prev_payload = NULL; -+ prev_part = NULL; -+ -+ /* -+ * We modify msg->items along the way; make sure to use @item as offset -+ * to the next item (instead of the iterator @it). -+ */ -+ for (it = item = msg->items; -+ it >= msg->items && -+ (u8 *)it < (u8 *)msg + msg->size && -+ (u8 *)it + it->size <= (u8 *)msg + msg->size; ) { -+ /* -+ * If we dropped items along the way, move current item to -+ * front. We must not access @it afterwards, but use @item -+ * instead! -+ */ -+ if (it != item) -+ memmove(item, it, it->size); -+ it = (void *)((u8 *)it + KDBUS_ALIGN8(item->size)); -+ -+ switch (item->type) { -+ case KDBUS_ITEM_PAYLOAD_VEC: { -+ size_t offset = staging->n_payload; -+ -+ if (kdbus_staging_merge_vecs(staging, &prev_payload, -+ &prev_part, item)) { -+ drop_item = true; -+ } else if (item->vec.address) { -+ /* real offset is patched later on */ -+ item->type = KDBUS_ITEM_PAYLOAD_OFF; -+ item->vec.offset = offset; -+ } else { -+ item->type = KDBUS_ITEM_PAYLOAD_OFF; -+ item->vec.offset = ~0ULL; -+ } -+ -+ break; -+ } -+ case KDBUS_ITEM_PAYLOAD_MEMFD: { -+ struct file *f; -+ -+ f = kdbus_get_memfd(&item->memfd); -+ if (IS_ERR(f)) -+ return PTR_ERR(f); -+ -+ gaps->memfd_files[gaps->n_memfds] = f; -+ gaps->memfd_offsets[gaps->n_memfds] = -+ (u8 *)&item->memfd.fd - (u8 *)msg; -+ ++gaps->n_memfds; -+ -+ /* memfds cannot be merged */ -+ prev_payload = item; -+ prev_part = NULL; -+ -+ /* insert padding to make following VECs aligned */ -+ if (item->memfd.size % 8) { -+ part = &staging->parts[staging->n_parts++]; -+ part->iov_len = item->memfd.size % 8; -+ part->iov_base = (char __user *)zeros; -+ staging->n_payload += part->iov_len; -+ } -+ -+ break; -+ } -+ case KDBUS_ITEM_FDS: { -+ size_t i, n_fds; -+ -+ n_fds = KDBUS_ITEM_PAYLOAD_SIZE(item) / sizeof(int); -+ for (i = 0; i < n_fds; ++i) { -+ struct file *f; -+ -+ f = kdbus_get_fd(item->fds[i]); -+ if (IS_ERR(f)) -+ return PTR_ERR(f); -+ -+ gaps->fd_files[gaps->n_fds++] = f; -+ } -+ -+ gaps->fd_offset = (u8 *)item->fds - (u8 *)msg; -+ -+ break; -+ } -+ case KDBUS_ITEM_BLOOM_FILTER: -+ staging->bloom_filter = &item->bloom_filter; -+ break; -+ case KDBUS_ITEM_DST_NAME: -+ staging->dst_name = item->str; -+ break; -+ } -+ -+ /* drop item if we merged it with a previous one */ -+ if (drop_item) { -+ drop_item = false; -+ } else { -+ last = item; -+ item = KDBUS_ITEM_NEXT(item); -+ } -+ } -+ -+ /* adjust message size regarding dropped items */ -+ msg->size = offsetof(struct kdbus_msg, items); -+ if (last) -+ msg->size += ((u8 *)last - (u8 *)msg->items) + last->size; -+ -+ return 0; -+} -+ -+static void kdbus_staging_reserve(struct kdbus_staging *staging) -+{ -+ struct iovec *part; -+ -+ part = &staging->parts[staging->n_parts++]; -+ part->iov_base = (void __user *)zeros; -+ part->iov_len = 0; -+} -+ -+static struct kdbus_staging *kdbus_staging_new(struct kdbus_bus *bus, -+ size_t n_parts, -+ size_t msg_extra_size) -+{ -+ const size_t reserved_parts = 5; /* see below for explanation */ -+ struct kdbus_staging *staging; -+ int ret; -+ -+ n_parts += reserved_parts; -+ -+ staging = kzalloc(sizeof(*staging) + n_parts * sizeof(*staging->parts) + -+ msg_extra_size, GFP_TEMPORARY); -+ if (!staging) -+ return ERR_PTR(-ENOMEM); -+ -+ staging->msg_seqnum = atomic64_inc_return(&bus->domain->last_id); -+ staging->n_parts = 0; /* we reserve n_parts, but don't enforce them */ -+ staging->parts = (void *)(staging + 1); -+ -+ if (msg_extra_size) /* if requested, allocate message, too */ -+ staging->msg = (void *)((u8 *)staging->parts + -+ n_parts * sizeof(*staging->parts)); -+ -+ staging->meta_proc = kdbus_meta_proc_new(); -+ if (IS_ERR(staging->meta_proc)) { -+ ret = PTR_ERR(staging->meta_proc); -+ staging->meta_proc = NULL; -+ goto error; -+ } -+ -+ staging->meta_conn = kdbus_meta_conn_new(); -+ if (IS_ERR(staging->meta_conn)) { -+ ret = PTR_ERR(staging->meta_conn); -+ staging->meta_conn = NULL; -+ goto error; -+ } -+ -+ /* -+ * Prepare iovecs to copy the message into the target pool. We use the -+ * following iovecs: -+ * * iovec to copy "kdbus_msg.size" -+ * * iovec to copy "struct kdbus_msg" (minus size) plus items -+ * * iovec for possible padding after the items -+ * * iovec for metadata items -+ * * iovec for possible padding after the items -+ * -+ * Make sure to update @reserved_parts if you add more parts here. -+ */ -+ -+ kdbus_staging_reserve(staging); /* msg.size */ -+ kdbus_staging_reserve(staging); /* msg (minus msg.size) plus items */ -+ kdbus_staging_reserve(staging); /* msg padding */ -+ kdbus_staging_reserve(staging); /* meta */ -+ kdbus_staging_reserve(staging); /* meta padding */ -+ -+ return staging; -+ -+error: -+ kdbus_staging_free(staging); -+ return ERR_PTR(ret); -+} -+ -+struct kdbus_staging *kdbus_staging_new_kernel(struct kdbus_bus *bus, -+ u64 dst, u64 cookie_timeout, -+ size_t it_size, size_t it_type) -+{ -+ struct kdbus_staging *staging; -+ size_t size; -+ -+ size = offsetof(struct kdbus_msg, items) + -+ KDBUS_ITEM_HEADER_SIZE + it_size; -+ -+ staging = kdbus_staging_new(bus, 0, KDBUS_ALIGN8(size)); -+ if (IS_ERR(staging)) -+ return ERR_CAST(staging); -+ -+ staging->msg->size = size; -+ staging->msg->flags = (dst == KDBUS_DST_ID_BROADCAST) ? -+ KDBUS_MSG_SIGNAL : 0; -+ staging->msg->dst_id = dst; -+ staging->msg->src_id = KDBUS_SRC_ID_KERNEL; -+ staging->msg->payload_type = KDBUS_PAYLOAD_KERNEL; -+ staging->msg->cookie_reply = cookie_timeout; -+ staging->notify = staging->msg->items; -+ staging->notify->size = KDBUS_ITEM_HEADER_SIZE + it_size; -+ staging->notify->type = it_type; -+ -+ return staging; -+} -+ -+struct kdbus_staging *kdbus_staging_new_user(struct kdbus_bus *bus, -+ struct kdbus_cmd_send *cmd, -+ struct kdbus_msg *msg) -+{ -+ const size_t reserved_parts = 1; /* see below for explanation */ -+ size_t n_memfds, n_fds, n_parts; -+ struct kdbus_staging *staging; -+ int ret; -+ -+ /* -+ * Examine user-supplied message and figure out how many resources we -+ * need to allocate in our staging area. This requires us to iterate -+ * the message twice, but saves us from re-allocating our resources -+ * all the time. -+ */ -+ -+ ret = kdbus_msg_examine(msg, bus, cmd, &n_memfds, &n_fds, &n_parts); -+ if (ret < 0) -+ return ERR_PTR(ret); -+ -+ n_parts += reserved_parts; -+ -+ /* -+ * Allocate staging area with the number of required resources. Make -+ * sure that we have enough iovecs for all required parts pre-allocated -+ * so this will hopefully be the only memory allocation for this -+ * message transaction. -+ */ -+ -+ staging = kdbus_staging_new(bus, n_parts, 0); -+ if (IS_ERR(staging)) -+ return ERR_CAST(staging); -+ -+ staging->msg = msg; -+ -+ /* -+ * If the message contains memfds or fd items, we need to remember some -+ * state so we can fill in the requested information at RECV time. -+ * File-descriptors cannot be passed at SEND time. Hence, allocate a -+ * gaps-object to remember that state. That gaps object is linked to -+ * from the staging area, but will also be linked to from the message -+ * queue of each peer. Hence, each receiver owns a reference to it, and -+ * it will later be used to fill the 'gaps' in message that couldn't be -+ * filled at SEND time. -+ * Note that the 'gaps' object is read-only once the staging-allocator -+ * returns. There might be connections receiving a queued message while -+ * the sender still broadcasts the message to other receivers. -+ */ -+ -+ if (n_memfds > 0 || n_fds > 0) { -+ staging->gaps = kdbus_gaps_new(n_memfds, n_fds); -+ if (IS_ERR(staging->gaps)) { -+ ret = PTR_ERR(staging->gaps); -+ staging->gaps = NULL; -+ kdbus_staging_free(staging); -+ return ERR_PTR(ret); -+ } -+ } -+ -+ /* -+ * kdbus_staging_new() already reserves parts for message setup. For -+ * user-supplied messages, we add the following iovecs: -+ * ... variable number of iovecs for payload ... -+ * * final iovec for possible padding of payload -+ * -+ * Make sure to update @reserved_parts if you add more parts here. -+ */ -+ -+ ret = kdbus_staging_import(staging); /* payload */ -+ kdbus_staging_reserve(staging); /* payload padding */ -+ -+ if (ret < 0) -+ goto error; -+ -+ return staging; -+ -+error: -+ kdbus_staging_free(staging); -+ return ERR_PTR(ret); -+} -+ -+struct kdbus_staging *kdbus_staging_free(struct kdbus_staging *staging) -+{ -+ if (!staging) -+ return NULL; -+ -+ kdbus_meta_conn_unref(staging->meta_conn); -+ kdbus_meta_proc_unref(staging->meta_proc); -+ kdbus_gaps_unref(staging->gaps); -+ kfree(staging); -+ -+ return NULL; -+} -+ -+static int kdbus_staging_collect_metadata(struct kdbus_staging *staging, -+ struct kdbus_conn *src, -+ struct kdbus_conn *dst, -+ u64 *out_attach) -+{ -+ u64 attach; -+ int ret; -+ -+ if (src) -+ attach = kdbus_meta_calc_attach_flags(src, dst); -+ else -+ attach = KDBUS_ATTACH_TIMESTAMP; /* metadata for kernel msgs */ -+ -+ if (src && !src->meta_fake) { -+ ret = kdbus_meta_proc_collect(staging->meta_proc, attach); -+ if (ret < 0) -+ return ret; -+ } -+ -+ ret = kdbus_meta_conn_collect(staging->meta_conn, src, -+ staging->msg_seqnum, attach); -+ if (ret < 0) -+ return ret; -+ -+ *out_attach = attach; -+ return 0; -+} -+ -+/** -+ * kdbus_staging_emit() - emit linearized message in target pool -+ * @staging: staging object to create message from -+ * @src: sender of the message (or NULL) -+ * @dst: target connection to allocate message for -+ * -+ * This allocates a pool-slice for @dst and copies the message provided by -+ * @staging into it. The new slice is then returned to the caller for further -+ * processing. It's not linked into any queue, yet. -+ * -+ * Return: Newly allocated slice or ERR_PTR on failure. -+ */ -+struct kdbus_pool_slice *kdbus_staging_emit(struct kdbus_staging *staging, -+ struct kdbus_conn *src, -+ struct kdbus_conn *dst) -+{ -+ struct kdbus_item *item, *meta_items = NULL; -+ struct kdbus_pool_slice *slice = NULL; -+ size_t off, size, msg_size, meta_size; -+ struct iovec *v; -+ u64 attach; -+ int ret; -+ -+ /* -+ * Step 1: -+ * Collect metadata from @src depending on the attach-flags allowed for -+ * @dst. Translate it into the namespaces pinned by @dst. -+ */ -+ -+ ret = kdbus_staging_collect_metadata(staging, src, dst, &attach); -+ if (ret < 0) -+ goto error; -+ -+ ret = kdbus_meta_emit(staging->meta_proc, NULL, staging->meta_conn, -+ dst, attach, &meta_items, &meta_size); -+ if (ret < 0) -+ goto error; -+ -+ /* -+ * Step 2: -+ * Setup iovecs for the message. See kdbus_staging_new() for allocation -+ * of those iovecs. All reserved iovecs have been initialized with -+ * iov_len=0 + iov_base=zeros. Furthermore, the iovecs to copy the -+ * actual message payload have already been initialized and need not be -+ * touched. -+ */ -+ -+ v = staging->parts; -+ msg_size = staging->msg->size; -+ -+ /* msg.size */ -+ v->iov_len = sizeof(msg_size); -+ v->iov_base = &msg_size; -+ ++v; -+ -+ /* msg (after msg.size) plus items */ -+ v->iov_len = staging->msg->size - sizeof(staging->msg->size); -+ v->iov_base = (void __user *)((u8 *)staging->msg + -+ sizeof(staging->msg->size)); -+ ++v; -+ -+ /* padding after msg */ -+ v->iov_len = KDBUS_ALIGN8(staging->msg->size) - staging->msg->size; -+ v->iov_base = (void __user *)zeros; -+ ++v; -+ -+ if (meta_size > 0) { -+ /* metadata items */ -+ v->iov_len = meta_size; -+ v->iov_base = meta_items; -+ ++v; -+ -+ /* padding after metadata */ -+ v->iov_len = KDBUS_ALIGN8(meta_size) - meta_size; -+ v->iov_base = (void __user *)zeros; -+ ++v; -+ -+ msg_size = KDBUS_ALIGN8(msg_size) + meta_size; -+ } -+ -+ /* ... payload iovecs are already filled in ... */ -+ -+ /* compute overall size and fill in padding after payload */ -+ size = KDBUS_ALIGN8(msg_size); -+ -+ if (staging->n_payload > 0) { -+ size += staging->n_payload; -+ -+ v = &staging->parts[staging->n_parts - 1]; -+ v->iov_len = KDBUS_ALIGN8(size) - size; -+ v->iov_base = (void __user *)zeros; -+ -+ size = KDBUS_ALIGN8(size); -+ } -+ -+ /* -+ * Step 3: -+ * The PAYLOAD_OFF items in the message contain a relative 'offset' -+ * field that tells the receiver where to find the actual payload. This -+ * offset is relative to the start of the message, and as such depends -+ * on the size of the metadata items we inserted. This size is variable -+ * and changes for each peer we send the message to. Hence, we remember -+ * the last relative offset that was used to calculate the 'offset' -+ * fields. For each message, we re-calculate it and patch all items, in -+ * case it changed. -+ */ -+ -+ off = KDBUS_ALIGN8(msg_size); -+ -+ if (off != staging->i_payload) { -+ KDBUS_ITEMS_FOREACH(item, staging->msg->items, -+ KDBUS_ITEMS_SIZE(staging->msg, items)) { -+ if (item->type != KDBUS_ITEM_PAYLOAD_OFF) -+ continue; -+ -+ item->vec.offset -= staging->i_payload; -+ item->vec.offset += off; -+ } -+ -+ staging->i_payload = off; -+ } -+ -+ /* -+ * Step 4: -+ * Allocate pool slice and copy over all data. Make sure to properly -+ * account on user quota. -+ */ -+ -+ ret = kdbus_conn_quota_inc(dst, src ? src->user : NULL, size, -+ staging->gaps ? staging->gaps->n_fds : 0); -+ if (ret < 0) -+ goto error; -+ -+ slice = kdbus_pool_slice_alloc(dst->pool, size, true); -+ if (IS_ERR(slice)) { -+ ret = PTR_ERR(slice); -+ slice = NULL; -+ goto error; -+ } -+ -+ WARN_ON(kdbus_pool_slice_size(slice) != size); -+ -+ ret = kdbus_pool_slice_copy_iovec(slice, 0, staging->parts, -+ staging->n_parts, size); -+ if (ret < 0) -+ goto error; -+ -+ /* all done, return slice to caller */ -+ goto exit; -+ -+error: -+ if (slice) -+ kdbus_conn_quota_dec(dst, src ? src->user : NULL, size, -+ staging->gaps ? staging->gaps->n_fds : 0); -+ kdbus_pool_slice_release(slice); -+ slice = ERR_PTR(ret); -+exit: -+ kfree(meta_items); -+ return slice; -+} -diff --git a/ipc/kdbus/message.h b/ipc/kdbus/message.h -index 5755ad4c9fd9..8fe49a961834 100644 ---- a/ipc/kdbus/message.h -+++ b/ipc/kdbus/message.h -@@ -124,4 +124,97 @@ void kdbus_kmsg_free(struct kdbus_kmsg *kmsg); - int kdbus_kmsg_collect_metadata(const struct kdbus_kmsg *kmsg, - struct kdbus_conn *src, struct kdbus_conn *dst); - -+/** -+ * struct kdbus_gaps - gaps in message to be filled later -+ * @kref: Reference counter -+ * @n_memfd_offs: Number of memfds -+ * @memfd_offs: Offsets of kdbus_memfd items in target slice -+ * @n_fds: Number of fds -+ * @fds: Array of sent fds -+ * @fds_offset: Offset of fd-array in target slice -+ * -+ * The 'gaps' object is used to track data that is needed to fill gaps in a -+ * message at RECV time. Usually, we try to compile the whole message at SEND -+ * time. This has the advantage, that we don't have to cache any information and -+ * can keep the memory consumption small. Furthermore, all copy operations can -+ * be combined into a single function call, which speeds up transactions -+ * considerably. -+ * However, things like file-descriptors can only be fully installed at RECV -+ * time. The gaps object tracks this data and pins it until a message is -+ * received. The gaps object is shared between all receivers of the same -+ * message. -+ */ -+struct kdbus_gaps { -+ struct kref kref; -+ -+ /* state tracking for KDBUS_ITEM_PAYLOAD_MEMFD entries */ -+ size_t n_memfds; -+ u64 *memfd_offsets; -+ struct file **memfd_files; -+ -+ /* state tracking for KDBUS_ITEM_FDS */ -+ size_t n_fds; -+ struct file **fd_files; -+ u64 fd_offset; -+}; -+ -+struct kdbus_gaps *kdbus_gaps_ref(struct kdbus_gaps *gaps); -+struct kdbus_gaps *kdbus_gaps_unref(struct kdbus_gaps *gaps); -+int kdbus_gaps_install(struct kdbus_gaps *gaps, struct kdbus_pool_slice *slice, -+ bool *out_incomplete); -+ -+/** -+ * struct kdbus_staging - staging area to import messages -+ * @msg: User-supplied message -+ * @gaps: Gaps-object created during import (or NULL if empty) -+ * @msg_seqnum: Message sequence number -+ * @notify_entry: Entry into list of kernel-generated notifications -+ * @i_payload: Current relative index of start of payload -+ * @n_payload: Total number of bytes needed for payload -+ * @n_parts: Number of parts -+ * @parts: Array of iovecs that make up the whole message -+ * @meta_proc: Process metadata of the sender (or NULL if empty) -+ * @meta_conn: Connection metadata of the sender (or NULL if empty) -+ * @bloom_filter: Pointer to the bloom-item in @msg, or NULL -+ * @dst_name: Pointer to the dst-name-item in @msg, or NULL -+ * @notify: Pointer to the notification item in @msg, or NULL -+ * -+ * The kdbus_staging object is a temporary staging area to import user-supplied -+ * messages into the kernel. It is only used during SEND and dropped once the -+ * message is queued. Any data that cannot be collected during SEND, is -+ * collected in a kdbus_gaps object and attached to the message queue. -+ */ -+struct kdbus_staging { -+ struct kdbus_msg *msg; -+ struct kdbus_gaps *gaps; -+ u64 msg_seqnum; -+ struct list_head notify_entry; -+ -+ /* crafted iovecs to copy the message */ -+ size_t i_payload; -+ size_t n_payload; -+ size_t n_parts; -+ struct iovec *parts; -+ -+ /* metadata state */ -+ struct kdbus_meta_proc *meta_proc; -+ struct kdbus_meta_conn *meta_conn; -+ -+ /* cached pointers into @msg */ -+ const struct kdbus_bloom_filter *bloom_filter; -+ const char *dst_name; -+ struct kdbus_item *notify; -+}; -+ -+struct kdbus_staging *kdbus_staging_new_kernel(struct kdbus_bus *bus, -+ u64 dst, u64 cookie_timeout, -+ size_t it_size, size_t it_type); -+struct kdbus_staging *kdbus_staging_new_user(struct kdbus_bus *bus, -+ struct kdbus_cmd_send *cmd, -+ struct kdbus_msg *msg); -+struct kdbus_staging *kdbus_staging_free(struct kdbus_staging *staging); -+struct kdbus_pool_slice *kdbus_staging_emit(struct kdbus_staging *staging, -+ struct kdbus_conn *src, -+ struct kdbus_conn *dst); -+ - #endif --- -2.4.3 - - -From 5eb3ea76d55f52ff6f5abdb88f925e2a695c2732 Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Sat, 20 Jun 2015 00:53:58 +0200 -Subject: [PATCH 102/132] kdbus: remove unused code - -kdbus_item_get() and kdbus_item_get_str() are not used anywhere. Drop -them. They probably got obsoleted during the introduction of kdbus_args. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> ---- - ipc/kdbus/item.c | 41 ----------------------------------------- - ipc/kdbus/item.h | 3 --- - 2 files changed, 44 deletions(-) - -diff --git a/ipc/kdbus/item.c b/ipc/kdbus/item.c -index 1ee72c2ad7c3..e763083cc16c 100644 ---- a/ipc/kdbus/item.c -+++ b/ipc/kdbus/item.c -@@ -260,47 +260,6 @@ int kdbus_items_validate(const struct kdbus_item *items, size_t items_size) - return 0; - } - --static struct kdbus_item *kdbus_items_get(const struct kdbus_item *items, -- size_t items_size, -- unsigned int item_type) --{ -- const struct kdbus_item *iter, *found = NULL; -- -- KDBUS_ITEMS_FOREACH(iter, items, items_size) { -- if (iter->type == item_type) { -- if (found) -- return ERR_PTR(-EEXIST); -- found = iter; -- } -- } -- -- return (struct kdbus_item *)found ? : ERR_PTR(-EBADMSG); --} -- --/** -- * kdbus_items_get_str() - get string from a list of items -- * @items: The items to walk -- * @items_size: The size of all items -- * @item_type: The item type to look for -- * -- * This function walks a list of items and searches for items of type -- * @item_type. If it finds exactly one such item, @str_ret will be set to -- * the .str member of the item. -- * -- * Return: the string, if the item was found exactly once, ERR_PTR(-EEXIST) -- * if the item was found more than once, and ERR_PTR(-EBADMSG) if there was -- * no item of the given type. -- */ --const char *kdbus_items_get_str(const struct kdbus_item *items, -- size_t items_size, -- unsigned int item_type) --{ -- const struct kdbus_item *item; -- -- item = kdbus_items_get(items, items_size, item_type); -- return IS_ERR(item) ? ERR_CAST(item) : item->str; --} -- - /** - * kdbus_item_set() - Set item content - * @item: The item to modify -diff --git a/ipc/kdbus/item.h b/ipc/kdbus/item.h -index bca63b4e6e80..3a7e6ccc253c 100644 ---- a/ipc/kdbus/item.h -+++ b/ipc/kdbus/item.h -@@ -55,9 +55,6 @@ struct kdbus_item_header { - int kdbus_item_validate_name(const struct kdbus_item *item); - int kdbus_item_validate(const struct kdbus_item *item); - int kdbus_items_validate(const struct kdbus_item *items, size_t items_size); --const char *kdbus_items_get_str(const struct kdbus_item *items, -- size_t items_size, -- unsigned int item_type); - struct kdbus_item *kdbus_item_set(struct kdbus_item *item, u64 type, - const void *data, size_t len); - --- -2.4.3 - - -From 992775c9c377ca14c6dcd2890283602a3fb36213 Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Sat, 20 Jun 2015 11:37:58 +0200 -Subject: [PATCH 103/132] kdbus: import messages via kdbus_args - -The kdbus_args helpers take care of copying command payloads into -kernel-space, verifying item validity and implementing negotiation. So -far, we use it for all user-space interaction but messages. This patch -adds support for kdbus-messages via kdbus_args so all user-space -interaction will now use kdbus_args. - -This has the benefit that we now support negotiation for messages, -stack-placement in case the messages are small enough, and unify the item -handling across all callers. - -This patch does *not* remove the old message importer. Instead, follow-up -patches will slowly perform the transition to the new one. It will be -removed once the transition is done. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> ---- - ipc/kdbus/connection.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++--- - ipc/kdbus/handle.c | 15 +++++++++---- - ipc/kdbus/handle.h | 17 ++++++++++++-- - 3 files changed, 84 insertions(+), 9 deletions(-) - -diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c -index 29b99c023bfe..20bb083aa2b4 100644 ---- a/ipc/kdbus/connection.c -+++ b/ipc/kdbus/connection.c -@@ -1929,10 +1929,13 @@ exit: - int kdbus_cmd_send(struct kdbus_conn *conn, struct file *f, void __user *argp) - { - struct kdbus_cmd_send *cmd; -+ struct kdbus_staging *staging = NULL; - struct kdbus_kmsg *kmsg = NULL; -+ struct kdbus_msg *msg = NULL; - struct file *cancel_fd = NULL; -- int ret; -+ int ret, ret2; - -+ /* command arguments */ - struct kdbus_arg argv[] = { - { .type = KDBUS_ITEM_NEGOTIATE }, - { .type = KDBUS_ITEM_CANCEL_FD }, -@@ -1944,12 +1947,48 @@ int kdbus_cmd_send(struct kdbus_conn *conn, struct file *f, void __user *argp) - .argc = ARRAY_SIZE(argv), - }; - -+ /* message arguments */ -+ struct kdbus_arg msg_argv[] = { -+ { .type = KDBUS_ITEM_NEGOTIATE }, -+ { .type = KDBUS_ITEM_PAYLOAD_VEC, .multiple = true }, -+ { .type = KDBUS_ITEM_PAYLOAD_MEMFD, .multiple = true }, -+ { .type = KDBUS_ITEM_FDS }, -+ { .type = KDBUS_ITEM_BLOOM_FILTER }, -+ { .type = KDBUS_ITEM_DST_NAME }, -+ }; -+ struct kdbus_args msg_args = { -+ .allowed_flags = KDBUS_FLAG_NEGOTIATE | -+ KDBUS_MSG_EXPECT_REPLY | -+ KDBUS_MSG_NO_AUTO_START | -+ KDBUS_MSG_SIGNAL, -+ .argv = msg_argv, -+ .argc = ARRAY_SIZE(msg_argv), -+ }; -+ - if (!kdbus_conn_is_ordinary(conn)) - return -EOPNOTSUPP; - -+ /* make sure to parse both, @cmd and @msg on negotiation */ -+ - ret = kdbus_args_parse(&args, argp, &cmd); -- if (ret != 0) -- return ret; -+ if (ret < 0) -+ goto exit; -+ else if (ret > 0 && !cmd->msg_address) /* negotiation without msg */ -+ goto exit; -+ -+ ret2 = kdbus_args_parse_msg(&msg_args, KDBUS_PTR(cmd->msg_address), -+ &msg); -+ if (ret2 < 0) { /* cannot parse message */ -+ ret = ret2; -+ goto exit; -+ } else if (ret2 > 0 && !ret) { /* msg-negot implies cmd-negot */ -+ ret = -EINVAL; -+ goto exit; -+ } else if (ret > 0) { /* negotiation */ -+ goto exit; -+ } -+ -+ /* here we parsed both, @cmd and @msg, and neither wants negotiation */ - - cmd->reply.return_flags = 0; - kdbus_pool_publish_empty(conn->pool, &cmd->reply.offset, -@@ -1968,6 +2007,20 @@ int kdbus_cmd_send(struct kdbus_conn *conn, struct file *f, void __user *argp) - } - } - -+ /* patch-in the source of this message */ -+ if (msg->src_id > 0 && msg->src_id != conn->id) { -+ ret = -EINVAL; -+ goto exit; -+ } -+ msg->src_id = conn->id; -+ -+ staging = kdbus_staging_new_user(conn->ep->bus, cmd, msg); -+ if (IS_ERR(staging)) { -+ ret = PTR_ERR(staging); -+ staging = NULL; -+ goto exit; -+ } -+ - kmsg = kdbus_kmsg_new_from_cmd(conn, cmd); - if (IS_ERR(kmsg)) { - ret = PTR_ERR(kmsg); -@@ -2012,6 +2065,8 @@ exit: - if (cancel_fd) - fput(cancel_fd); - kdbus_kmsg_free(kmsg); -+ kdbus_staging_free(staging); -+ ret = kdbus_args_clear(&msg_args, ret); - return kdbus_args_clear(&args, ret); - } - -diff --git a/ipc/kdbus/handle.c b/ipc/kdbus/handle.c -index 07527990a051..e0e06b0e1114 100644 ---- a/ipc/kdbus/handle.c -+++ b/ipc/kdbus/handle.c -@@ -126,6 +126,7 @@ static int kdbus_args_negotiate(struct kdbus_args *args) - /** - * __kdbus_args_parse() - parse payload of kdbus command - * @args: object to parse data into -+ * @is_cmd: whether this is a command or msg payload - * @argp: user-space location of command payload to parse - * @type_size: overall size of command payload to parse - * @items_offset: offset of items array in command payload -@@ -140,10 +141,14 @@ static int kdbus_args_negotiate(struct kdbus_args *args) - * If this function succeeded, you must call kdbus_args_clear() to release - * allocated resources before destroying @args. - * -+ * This can also be used to import kdbus_msg objects. In that case, @is_cmd must -+ * be set to 'false' and the 'return_flags' field will not be touched (as it -+ * doesn't exist on kdbus_msg). -+ * - * Return: On failure a negative error code is returned. Otherwise, 1 is - * returned if negotiation was requested, 0 if not. - */ --int __kdbus_args_parse(struct kdbus_args *args, void __user *argp, -+int __kdbus_args_parse(struct kdbus_args *args, bool is_cmd, void __user *argp, - size_t type_size, size_t items_offset, void **out) - { - u64 user_size; -@@ -173,10 +178,12 @@ int __kdbus_args_parse(struct kdbus_args *args, void __user *argp, - goto error; - } - -- args->cmd->return_flags = 0; -+ if (is_cmd) -+ args->cmd->return_flags = 0; - args->user = argp; - args->items = (void *)((u8 *)args->cmd + items_offset); - args->items_size = args->cmd->size - items_offset; -+ args->is_cmd = is_cmd; - - if (args->cmd->flags & ~args->allowed_flags) { - ret = -EINVAL; -@@ -225,8 +232,8 @@ int kdbus_args_clear(struct kdbus_args *args, int ret) - return ret; - - if (!IS_ERR_OR_NULL(args->cmd)) { -- if (put_user(args->cmd->return_flags, -- &args->user->return_flags)) -+ if (args->is_cmd && put_user(args->cmd->return_flags, -+ &args->user->return_flags)) - ret = -EFAULT; - if (args->cmd != (void*)args->cmd_buf) - kfree(args->cmd); -diff --git a/ipc/kdbus/handle.h b/ipc/kdbus/handle.h -index 13c59d975728..8a36c0595091 100644 ---- a/ipc/kdbus/handle.h -+++ b/ipc/kdbus/handle.h -@@ -48,6 +48,7 @@ struct kdbus_arg { - * @cmd_buf: 512 bytes inline buf to avoid kmalloc() on small cmds - * @items: points to item array in @cmd - * @items_size: size of @items in bytes -+ * @is_cmd: whether this is a command-payload or msg-payload - * - * This structure is used to parse ioctl command payloads on each invocation. - * The ioctl handler has to pre-fill the flags and allowed items before passing -@@ -68,9 +69,10 @@ struct kdbus_args { - - struct kdbus_item *items; - size_t items_size; -+ bool is_cmd : 1; - }; - --int __kdbus_args_parse(struct kdbus_args *args, void __user *argp, -+int __kdbus_args_parse(struct kdbus_args *args, bool is_cmd, void __user *argp, - size_t type_size, size_t items_offset, void **out); - int kdbus_args_clear(struct kdbus_args *args, int ret); - -@@ -82,7 +84,18 @@ int kdbus_args_clear(struct kdbus_args *args, int ret); - offsetof(struct kdbus_cmd, flags)); \ - BUILD_BUG_ON(offsetof(typeof(**(_v)), return_flags) != \ - offsetof(struct kdbus_cmd, return_flags)); \ -- __kdbus_args_parse((_args), (_argp), sizeof(**(_v)), \ -+ __kdbus_args_parse((_args), 1, (_argp), sizeof(**(_v)), \ -+ offsetof(typeof(**(_v)), items), \ -+ (void **)(_v)); \ -+ }) -+ -+#define kdbus_args_parse_msg(_args, _argp, _v) \ -+ ({ \ -+ BUILD_BUG_ON(offsetof(typeof(**(_v)), size) != \ -+ offsetof(struct kdbus_cmd, size)); \ -+ BUILD_BUG_ON(offsetof(typeof(**(_v)), flags) != \ -+ offsetof(struct kdbus_cmd, flags)); \ -+ __kdbus_args_parse((_args), 0, (_argp), sizeof(**(_v)), \ - offsetof(typeof(**(_v)), items), \ - (void **)(_v)); \ - }) --- -2.4.3 - - -From c7bd78731b3a709a6d7d83f4851e30dc1ebf5cca Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Wed, 24 Jun 2015 15:27:03 +0200 -Subject: [PATCH 104/132] kdbus: switch to kdbus_staging - -This switches the existing infrastructure to use "kdbus_staging" in favor -of "kdbus_kmsg" and "kdbus_msg_resources". As described during the -introduction of kdbus_staging, it reduces the number of calls into shmem -during each message, and also minimizes the resources we pin until -RECV-time. - -This patch improves the pure message transaction speed by ~30% for empty -payloads. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> ---- - ipc/kdbus/bus.c | 30 ++-- - ipc/kdbus/bus.h | 6 +- - ipc/kdbus/connection.c | 134 ++++++++---------- - ipc/kdbus/connection.h | 4 +- - ipc/kdbus/match.c | 26 ++-- - ipc/kdbus/match.h | 8 +- - ipc/kdbus/message.h | 6 + - ipc/kdbus/notify.c | 77 +++++------ - ipc/kdbus/queue.c | 362 +++---------------------------------------------- - ipc/kdbus/queue.h | 42 +++--- - 10 files changed, 176 insertions(+), 519 deletions(-) - -diff --git a/ipc/kdbus/bus.c b/ipc/kdbus/bus.c -index 4f51723f8780..e7e17a7f7edd 100644 ---- a/ipc/kdbus/bus.c -+++ b/ipc/kdbus/bus.c -@@ -232,9 +232,9 @@ struct kdbus_conn *kdbus_bus_find_conn_by_id(struct kdbus_bus *bus, u64 id) - * 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. -+ * @staging: Staging object containing the message to send - * -- * Send @kmsg to all connections that are currently active on the bus. -+ * Send message to all connections that are currently active on the bus. - * Connections must still have matches installed in order to let the message - * pass. - * -@@ -242,7 +242,7 @@ struct kdbus_conn *kdbus_bus_find_conn_by_id(struct kdbus_bus *bus, u64 id) - */ - void kdbus_bus_broadcast(struct kdbus_bus *bus, - struct kdbus_conn *conn_src, -- struct kdbus_kmsg *kmsg) -+ struct kdbus_staging *staging) - { - struct kdbus_conn *conn_dst; - unsigned int i; -@@ -259,11 +259,11 @@ void kdbus_bus_broadcast(struct kdbus_bus *bus, - * can re-construct order via sequence numbers), but we should at least - * try to avoid re-ordering for monitors. - */ -- kdbus_bus_eavesdrop(bus, conn_src, kmsg); -+ kdbus_bus_eavesdrop(bus, conn_src, staging); - - down_read(&bus->conn_rwlock); - hash_for_each(bus->conn_hash, i, conn_dst, hentry) { -- if (conn_dst->id == kmsg->msg.src_id) -+ if (conn_dst->id == staging->msg->src_id) - continue; - if (!kdbus_conn_is_ordinary(conn_dst)) - continue; -@@ -272,8 +272,8 @@ void kdbus_bus_broadcast(struct kdbus_bus *bus, - * Check if there is a match for the kmsg object in - * the destination connection match db - */ -- if (!kdbus_match_db_match_kmsg(conn_dst->match_db, conn_src, -- kmsg)) -+ if (!kdbus_match_db_match_msg(conn_dst->match_db, conn_src, -+ staging)) - continue; - - if (conn_src) { -@@ -291,12 +291,12 @@ void kdbus_bus_broadcast(struct kdbus_bus *bus, - * notification - */ - if (!kdbus_conn_policy_see_notification(conn_dst, NULL, -- &kmsg->msg)) -+ staging->msg)) - continue; - } - -- ret = kdbus_conn_entry_insert(conn_src, conn_dst, kmsg, NULL, -- NULL); -+ ret = kdbus_conn_entry_insert(conn_src, conn_dst, staging, -+ NULL, NULL); - if (ret < 0) - kdbus_conn_lost_message(conn_dst); - } -@@ -307,16 +307,16 @@ void kdbus_bus_broadcast(struct kdbus_bus *bus, - * kdbus_bus_eavesdrop() - send a message to all subscribed monitors - * @bus: The bus the monitors are connected to - * @conn_src: The source connection, may be %NULL for kernel notifications -- * @kmsg: The message to send. -+ * @staging: Staging object containing the message to send - * -- * Send @kmsg to all monitors that are currently active on the bus. Monitors -+ * Send message to all monitors that are currently active on the bus. Monitors - * must still have matches installed in order to let the message pass. - * - * The caller must hold the name-registry lock of @bus. - */ - void kdbus_bus_eavesdrop(struct kdbus_bus *bus, - struct kdbus_conn *conn_src, -- struct kdbus_kmsg *kmsg) -+ struct kdbus_staging *staging) - { - struct kdbus_conn *conn_dst; - int ret; -@@ -330,8 +330,8 @@ void kdbus_bus_eavesdrop(struct kdbus_bus *bus, - - down_read(&bus->conn_rwlock); - list_for_each_entry(conn_dst, &bus->monitors_list, monitor_entry) { -- ret = kdbus_conn_entry_insert(conn_src, conn_dst, kmsg, NULL, -- NULL); -+ ret = kdbus_conn_entry_insert(conn_src, conn_dst, staging, -+ NULL, NULL); - if (ret < 0) - kdbus_conn_lost_message(conn_dst); - } -diff --git a/ipc/kdbus/bus.h b/ipc/kdbus/bus.h -index e019ef34534c..238986eff92f 100644 ---- a/ipc/kdbus/bus.h -+++ b/ipc/kdbus/bus.h -@@ -29,7 +29,7 @@ - - struct kdbus_conn; - struct kdbus_domain; --struct kdbus_kmsg; -+struct kdbus_staging; - struct kdbus_user; - - /** -@@ -87,10 +87,10 @@ struct kdbus_bus *kdbus_bus_unref(struct kdbus_bus *bus); - struct kdbus_conn *kdbus_bus_find_conn_by_id(struct kdbus_bus *bus, u64 id); - void kdbus_bus_broadcast(struct kdbus_bus *bus, - struct kdbus_conn *conn_src, -- struct kdbus_kmsg *kmsg); -+ struct kdbus_staging *staging); - void kdbus_bus_eavesdrop(struct kdbus_bus *bus, - struct kdbus_conn *conn_src, -- struct kdbus_kmsg *kmsg); -+ struct kdbus_staging *staging); - - struct kdbus_bus *kdbus_cmd_bus_make(struct kdbus_domain *domain, - void __user *argp); -diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c -index 20bb083aa2b4..2b334b04dd9d 100644 ---- a/ipc/kdbus/connection.c -+++ b/ipc/kdbus/connection.c -@@ -781,7 +781,7 @@ void kdbus_conn_lost_message(struct kdbus_conn *c) - 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_staging *staging) - { - /* The remote connection was disconnected */ - if (!kdbus_conn_active(conn_dst)) -@@ -796,10 +796,10 @@ kdbus_conn_entry_make(struct kdbus_conn *conn_src, - */ - if (!kdbus_conn_is_monitor(conn_dst) && - !(conn_dst->flags & KDBUS_HELLO_ACCEPT_FD) && -- kmsg->res && kmsg->res->fds_count > 0) -+ staging->gaps && staging->gaps->n_fds > 0) - return ERR_PTR(-ECOMM); - -- return kdbus_queue_entry_new(conn_src, conn_dst, kmsg); -+ return kdbus_queue_entry_new(conn_src, conn_dst, staging); - } - - /* -@@ -808,17 +808,11 @@ kdbus_conn_entry_make(struct kdbus_conn *conn_src, - * The connection's queue will never get to see it. - */ - static int kdbus_conn_entry_sync_attach(struct kdbus_conn *conn_dst, -- const struct kdbus_kmsg *kmsg, -+ struct kdbus_staging *staging, - struct kdbus_reply *reply_wake) - { - struct kdbus_queue_entry *entry; -- int remote_ret; -- int ret; -- -- ret = kdbus_kmsg_collect_metadata(kmsg, reply_wake->reply_src, -- conn_dst); -- if (ret < 0) -- return ret; -+ int remote_ret, ret = 0; - - mutex_lock(&reply_wake->reply_dst->lock); - -@@ -828,7 +822,7 @@ static int kdbus_conn_entry_sync_attach(struct kdbus_conn *conn_dst, - */ - if (reply_wake->waiting) { - entry = kdbus_conn_entry_make(reply_wake->reply_src, conn_dst, -- kmsg); -+ staging); - if (IS_ERR(entry)) - ret = PTR_ERR(entry); - else -@@ -869,7 +863,7 @@ static int kdbus_conn_entry_sync_attach(struct kdbus_conn *conn_dst, - * 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 kmsg to queue -+ * @staging: Message to send - * @reply: The reply tracker to attach to the queue entry - * @name: Destination name this msg is sent to, or NULL - * -@@ -877,22 +871,16 @@ static int kdbus_conn_entry_sync_attach(struct kdbus_conn *conn_dst, - */ - int kdbus_conn_entry_insert(struct kdbus_conn *conn_src, - struct kdbus_conn *conn_dst, -- const struct kdbus_kmsg *kmsg, -+ struct kdbus_staging *staging, - struct kdbus_reply *reply, - const struct kdbus_name_entry *name) - { - struct kdbus_queue_entry *entry; - int ret; - -- if (conn_src) { -- ret = kdbus_kmsg_collect_metadata(kmsg, conn_src, conn_dst); -- if (ret < 0) -- return ret; -- } -- - kdbus_conn_lock2(conn_src, conn_dst); - -- entry = kdbus_conn_entry_make(conn_src, conn_dst, kmsg); -+ entry = kdbus_conn_entry_make(conn_src, conn_dst, staging); - if (IS_ERR(entry)) { - ret = PTR_ERR(entry); - goto exit_unlock; -@@ -1044,22 +1032,18 @@ static int kdbus_conn_wait_reply(struct kdbus_conn *conn_src, - } - - static int kdbus_pin_dst(struct kdbus_bus *bus, -- const struct kdbus_kmsg *kmsg, -+ struct kdbus_staging *staging, - struct kdbus_name_entry **out_name, - struct kdbus_conn **out_dst) - { -- struct kdbus_msg_resources *res = kmsg->res; -- const struct kdbus_msg *msg = &kmsg->msg; -+ const struct kdbus_msg *msg = staging->msg; - struct kdbus_name_entry *name = NULL; - struct kdbus_conn *dst = NULL; - int ret; - -- if (WARN_ON(!res)) -- return -EINVAL; -- - lockdep_assert_held(&bus->name_registry->rwlock); - -- if (!res->dst_name) { -+ if (!staging->dst_name) { - dst = kdbus_bus_find_conn_by_id(bus, msg->dst_id); - if (!dst) - return -ENXIO; -@@ -1070,7 +1054,7 @@ static int kdbus_pin_dst(struct kdbus_bus *bus, - } - } else { - name = kdbus_name_lookup_unlocked(bus->name_registry, -- res->dst_name); -+ staging->dst_name); - if (!name) - return -ESRCH; - -@@ -1107,17 +1091,19 @@ error: - return ret; - } - --static int kdbus_conn_reply(struct kdbus_conn *src, struct kdbus_kmsg *kmsg) -+static int kdbus_conn_reply(struct kdbus_conn *src, -+ struct kdbus_staging *staging) - { -+ const struct kdbus_msg *msg = staging->msg; - struct kdbus_name_entry *name = NULL; - struct kdbus_reply *reply, *wake = NULL; - struct kdbus_conn *dst = NULL; - struct kdbus_bus *bus = src->ep->bus; - int ret; - -- if (WARN_ON(kmsg->msg.dst_id == KDBUS_DST_ID_BROADCAST) || -- WARN_ON(kmsg->msg.flags & KDBUS_MSG_EXPECT_REPLY) || -- WARN_ON(kmsg->msg.flags & KDBUS_MSG_SIGNAL)) -+ if (WARN_ON(msg->dst_id == KDBUS_DST_ID_BROADCAST) || -+ WARN_ON(msg->flags & KDBUS_MSG_EXPECT_REPLY) || -+ WARN_ON(msg->flags & KDBUS_MSG_SIGNAL)) - return -EINVAL; - - /* name-registry must be locked for lookup *and* collecting data */ -@@ -1125,12 +1111,12 @@ static int kdbus_conn_reply(struct kdbus_conn *src, struct kdbus_kmsg *kmsg) - - /* find and pin destination */ - -- ret = kdbus_pin_dst(bus, kmsg, &name, &dst); -+ ret = kdbus_pin_dst(bus, staging, &name, &dst); - if (ret < 0) - goto exit; - - mutex_lock(&dst->lock); -- reply = kdbus_reply_find(src, dst, kmsg->msg.cookie_reply); -+ reply = kdbus_reply_find(src, dst, msg->cookie_reply); - if (reply) { - if (reply->sync) - wake = kdbus_reply_ref(reply); -@@ -1145,12 +1131,12 @@ static int kdbus_conn_reply(struct kdbus_conn *src, struct kdbus_kmsg *kmsg) - - /* send message */ - -- kdbus_bus_eavesdrop(bus, src, kmsg); -+ kdbus_bus_eavesdrop(bus, src, staging); - - if (wake) -- ret = kdbus_conn_entry_sync_attach(dst, kmsg, wake); -+ ret = kdbus_conn_entry_sync_attach(dst, staging, wake); - else -- ret = kdbus_conn_entry_insert(src, dst, kmsg, NULL, name); -+ ret = kdbus_conn_entry_insert(src, dst, staging, NULL, name); - - exit: - up_read(&bus->name_registry->rwlock); -@@ -1160,24 +1146,25 @@ exit: - } - - static struct kdbus_reply *kdbus_conn_call(struct kdbus_conn *src, -- struct kdbus_kmsg *kmsg, -+ struct kdbus_staging *staging, - ktime_t exp) - { -+ const struct kdbus_msg *msg = staging->msg; - struct kdbus_name_entry *name = NULL; - struct kdbus_reply *wait = NULL; - struct kdbus_conn *dst = NULL; - struct kdbus_bus *bus = src->ep->bus; - int ret; - -- if (WARN_ON(kmsg->msg.dst_id == KDBUS_DST_ID_BROADCAST) || -- WARN_ON(kmsg->msg.flags & KDBUS_MSG_SIGNAL) || -- WARN_ON(!(kmsg->msg.flags & KDBUS_MSG_EXPECT_REPLY))) -+ if (WARN_ON(msg->dst_id == KDBUS_DST_ID_BROADCAST) || -+ WARN_ON(msg->flags & KDBUS_MSG_SIGNAL) || -+ WARN_ON(!(msg->flags & KDBUS_MSG_EXPECT_REPLY))) - return ERR_PTR(-EINVAL); - - /* resume previous wait-context, if available */ - - mutex_lock(&src->lock); -- wait = kdbus_reply_find(NULL, src, kmsg->msg.cookie); -+ wait = kdbus_reply_find(NULL, src, msg->cookie); - if (wait) { - if (wait->interrupted) { - kdbus_reply_ref(wait); -@@ -1199,7 +1186,7 @@ static struct kdbus_reply *kdbus_conn_call(struct kdbus_conn *src, - - /* find and pin destination */ - -- ret = kdbus_pin_dst(bus, kmsg, &name, &dst); -+ ret = kdbus_pin_dst(bus, staging, &name, &dst); - if (ret < 0) - goto exit; - -@@ -1208,7 +1195,7 @@ static struct kdbus_reply *kdbus_conn_call(struct kdbus_conn *src, - goto exit; - } - -- wait = kdbus_reply_new(dst, src, &kmsg->msg, name, true); -+ wait = kdbus_reply_new(dst, src, msg, name, true); - if (IS_ERR(wait)) { - ret = PTR_ERR(wait); - wait = NULL; -@@ -1217,9 +1204,9 @@ static struct kdbus_reply *kdbus_conn_call(struct kdbus_conn *src, - - /* send message */ - -- kdbus_bus_eavesdrop(bus, src, kmsg); -+ kdbus_bus_eavesdrop(bus, src, staging); - -- ret = kdbus_conn_entry_insert(src, dst, kmsg, wait, name); -+ ret = kdbus_conn_entry_insert(src, dst, staging, wait, name); - if (ret < 0) - goto exit; - -@@ -1235,18 +1222,20 @@ exit: - return wait; - } - --static int kdbus_conn_unicast(struct kdbus_conn *src, struct kdbus_kmsg *kmsg) -+static int kdbus_conn_unicast(struct kdbus_conn *src, -+ struct kdbus_staging *staging) - { -+ const struct kdbus_msg *msg = staging->msg; - struct kdbus_name_entry *name = NULL; - struct kdbus_reply *wait = NULL; - struct kdbus_conn *dst = NULL; - struct kdbus_bus *bus = src->ep->bus; -- bool is_signal = (kmsg->msg.flags & KDBUS_MSG_SIGNAL); -+ bool is_signal = (msg->flags & KDBUS_MSG_SIGNAL); - int ret = 0; - -- if (WARN_ON(kmsg->msg.dst_id == KDBUS_DST_ID_BROADCAST) || -- WARN_ON(!(kmsg->msg.flags & KDBUS_MSG_EXPECT_REPLY) && -- kmsg->msg.cookie_reply != 0)) -+ if (WARN_ON(msg->dst_id == KDBUS_DST_ID_BROADCAST) || -+ WARN_ON(!(msg->flags & KDBUS_MSG_EXPECT_REPLY) && -+ msg->cookie_reply != 0)) - return -EINVAL; - - /* name-registry must be locked for lookup *and* collecting data */ -@@ -1254,23 +1243,23 @@ static int kdbus_conn_unicast(struct kdbus_conn *src, struct kdbus_kmsg *kmsg) - - /* find and pin destination */ - -- ret = kdbus_pin_dst(bus, kmsg, &name, &dst); -+ ret = kdbus_pin_dst(bus, staging, &name, &dst); - if (ret < 0) - goto exit; - - if (is_signal) { - /* like broadcasts we eavesdrop even if the msg is dropped */ -- kdbus_bus_eavesdrop(bus, src, kmsg); -+ kdbus_bus_eavesdrop(bus, src, staging); - - /* drop silently if peer is not interested or not privileged */ -- if (!kdbus_match_db_match_kmsg(dst->match_db, src, kmsg) || -+ if (!kdbus_match_db_match_msg(dst->match_db, src, staging) || - !kdbus_conn_policy_talk(dst, NULL, src)) - goto exit; - } else if (!kdbus_conn_policy_talk(src, current_cred(), dst)) { - ret = -EPERM; - goto exit; -- } else if (kmsg->msg.flags & KDBUS_MSG_EXPECT_REPLY) { -- wait = kdbus_reply_new(dst, src, &kmsg->msg, name, false); -+ } else if (msg->flags & KDBUS_MSG_EXPECT_REPLY) { -+ wait = kdbus_reply_new(dst, src, msg, name, false); - if (IS_ERR(wait)) { - ret = PTR_ERR(wait); - wait = NULL; -@@ -1281,9 +1270,9 @@ static int kdbus_conn_unicast(struct kdbus_conn *src, struct kdbus_kmsg *kmsg) - /* send message */ - - if (!is_signal) -- kdbus_bus_eavesdrop(bus, src, kmsg); -+ kdbus_bus_eavesdrop(bus, src, staging); - -- ret = kdbus_conn_entry_insert(src, dst, kmsg, wait, name); -+ ret = kdbus_conn_entry_insert(src, dst, staging, wait, name); - if (ret < 0 && !is_signal) - goto exit; - -@@ -1353,7 +1342,7 @@ void kdbus_conn_move_messages(struct kdbus_conn *conn_dst, - continue; - - if (!(conn_dst->flags & KDBUS_HELLO_ACCEPT_FD) && -- e->msg_res && e->msg_res->fds_count > 0) { -+ e->gaps && e->gaps->n_fds > 0) { - kdbus_conn_lost_message(conn_dst); - kdbus_queue_entry_free(e); - continue; -@@ -1930,7 +1919,6 @@ int kdbus_cmd_send(struct kdbus_conn *conn, struct file *f, void __user *argp) - { - struct kdbus_cmd_send *cmd; - struct kdbus_staging *staging = NULL; -- struct kdbus_kmsg *kmsg = NULL; - struct kdbus_msg *msg = NULL; - struct file *cancel_fd = NULL; - int ret, ret2; -@@ -2021,23 +2009,16 @@ int kdbus_cmd_send(struct kdbus_conn *conn, struct file *f, void __user *argp) - goto exit; - } - -- kmsg = kdbus_kmsg_new_from_cmd(conn, cmd); -- if (IS_ERR(kmsg)) { -- ret = PTR_ERR(kmsg); -- kmsg = NULL; -- goto exit; -- } -- -- if (kmsg->msg.dst_id == KDBUS_DST_ID_BROADCAST) { -+ if (msg->dst_id == KDBUS_DST_ID_BROADCAST) { - down_read(&conn->ep->bus->name_registry->rwlock); -- kdbus_bus_broadcast(conn->ep->bus, conn, kmsg); -+ kdbus_bus_broadcast(conn->ep->bus, conn, staging); - up_read(&conn->ep->bus->name_registry->rwlock); - } else if (cmd->flags & KDBUS_SEND_SYNC_REPLY) { - struct kdbus_reply *r; - ktime_t exp; - -- exp = ns_to_ktime(kmsg->msg.timeout_ns); -- r = kdbus_conn_call(conn, kmsg, exp); -+ exp = ns_to_ktime(msg->timeout_ns); -+ r = kdbus_conn_call(conn, staging, exp); - if (IS_ERR(r)) { - ret = PTR_ERR(r); - goto exit; -@@ -2047,13 +2028,13 @@ int kdbus_cmd_send(struct kdbus_conn *conn, struct file *f, void __user *argp) - kdbus_reply_unref(r); - if (ret < 0) - goto exit; -- } else if ((kmsg->msg.flags & KDBUS_MSG_EXPECT_REPLY) || -- kmsg->msg.cookie_reply == 0) { -- ret = kdbus_conn_unicast(conn, kmsg); -+ } else if ((msg->flags & KDBUS_MSG_EXPECT_REPLY) || -+ msg->cookie_reply == 0) { -+ ret = kdbus_conn_unicast(conn, staging); - if (ret < 0) - goto exit; - } else { -- ret = kdbus_conn_reply(conn, kmsg); -+ ret = kdbus_conn_reply(conn, staging); - if (ret < 0) - goto exit; - } -@@ -2064,7 +2045,6 @@ int kdbus_cmd_send(struct kdbus_conn *conn, struct file *f, void __user *argp) - exit: - if (cancel_fd) - fput(cancel_fd); -- kdbus_kmsg_free(kmsg); - kdbus_staging_free(staging); - ret = kdbus_args_clear(&msg_args, ret); - return kdbus_args_clear(&args, ret); -diff --git a/ipc/kdbus/connection.h b/ipc/kdbus/connection.h -index 90c1bcc91fe6..b1769b877504 100644 ---- a/ipc/kdbus/connection.h -+++ b/ipc/kdbus/connection.h -@@ -31,7 +31,7 @@ - KDBUS_HELLO_MONITOR) - - struct kdbus_quota; --struct kdbus_kmsg; -+struct kdbus_staging; - - /** - * struct kdbus_conn - connection to a bus -@@ -134,7 +134,7 @@ void kdbus_conn_quota_dec(struct kdbus_conn *c, struct kdbus_user *u, - void kdbus_conn_lost_message(struct kdbus_conn *c); - int kdbus_conn_entry_insert(struct kdbus_conn *conn_src, - struct kdbus_conn *conn_dst, -- const struct kdbus_kmsg *kmsg, -+ struct kdbus_staging *staging, - struct kdbus_reply *reply, - const struct kdbus_name_entry *name); - void kdbus_conn_move_messages(struct kdbus_conn *conn_dst, -diff --git a/ipc/kdbus/match.c b/ipc/kdbus/match.c -index 3f86e4c81468..3ae224ff9f3f 100644 ---- a/ipc/kdbus/match.c -+++ b/ipc/kdbus/match.c -@@ -206,13 +206,13 @@ static bool kdbus_match_bloom(const struct kdbus_bloom_filter *filter, - - static bool kdbus_match_rule_conn(const struct kdbus_match_rule *r, - struct kdbus_conn *c, -- const struct kdbus_kmsg *kmsg) -+ const struct kdbus_staging *s) - { - lockdep_assert_held(&c->ep->bus->name_registry->rwlock); - - switch (r->type) { - case KDBUS_ITEM_BLOOM_MASK: -- return kdbus_match_bloom(kmsg->bloom_filter, &r->bloom_mask, c); -+ return kdbus_match_bloom(s->bloom_filter, &r->bloom_mask, c); - case KDBUS_ITEM_ID: - return r->src_id == c->id || r->src_id == KDBUS_MATCH_ID_ANY; - case KDBUS_ITEM_NAME: -@@ -223,9 +223,9 @@ static bool kdbus_match_rule_conn(const struct kdbus_match_rule *r, - } - - static bool kdbus_match_rule_kernel(const struct kdbus_match_rule *r, -- const struct kdbus_kmsg *kmsg) -+ const struct kdbus_staging *s) - { -- struct kdbus_item *n = kmsg->notify; -+ struct kdbus_item *n = s->notify; - - if (WARN_ON(!n) || n->type != r->type) - return false; -@@ -252,23 +252,23 @@ static bool kdbus_match_rule_kernel(const struct kdbus_match_rule *r, - - static bool kdbus_match_rules(const struct kdbus_match_entry *entry, - struct kdbus_conn *c, -- const struct kdbus_kmsg *kmsg) -+ const struct kdbus_staging *s) - { - struct kdbus_match_rule *r; - - list_for_each_entry(r, &entry->rules_list, rules_entry) -- if ((c && !kdbus_match_rule_conn(r, c, kmsg)) || -- (!c && !kdbus_match_rule_kernel(r, kmsg))) -+ if ((c && !kdbus_match_rule_conn(r, c, s)) || -+ (!c && !kdbus_match_rule_kernel(r, s))) - return false; - - return true; - } - - /** -- * kdbus_match_db_match_kmsg() - match a kmsg object agains the database entries -+ * kdbus_match_db_match_msg() - match a msg 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 -+ * @staging: Staging object containing the message to match against - * - * 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 -@@ -279,16 +279,16 @@ static bool kdbus_match_rules(const struct kdbus_match_entry *entry, - * - * 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) -+bool kdbus_match_db_match_msg(struct kdbus_match_db *mdb, -+ struct kdbus_conn *conn_src, -+ const struct kdbus_staging *staging) - { - 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); -+ matched = kdbus_match_rules(entry, conn_src, staging); - if (matched) - break; - } -diff --git a/ipc/kdbus/match.h b/ipc/kdbus/match.h -index ea4292938deb..ceb492f8e51c 100644 ---- a/ipc/kdbus/match.h -+++ b/ipc/kdbus/match.h -@@ -16,8 +16,8 @@ - #define __KDBUS_MATCH_H - - struct kdbus_conn; --struct kdbus_kmsg; - struct kdbus_match_db; -+struct kdbus_staging; - - struct kdbus_match_db *kdbus_match_db_new(void); - void kdbus_match_db_free(struct kdbus_match_db *db); -@@ -25,9 +25,9 @@ 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); -+bool kdbus_match_db_match_msg(struct kdbus_match_db *db, -+ struct kdbus_conn *conn_src, -+ const struct kdbus_staging *staging); - - int kdbus_cmd_match_add(struct kdbus_conn *conn, void __user *argp); - int kdbus_cmd_match_remove(struct kdbus_conn *conn, void __user *argp); -diff --git a/ipc/kdbus/message.h b/ipc/kdbus/message.h -index 8fe49a961834..e0c4f2e324b3 100644 ---- a/ipc/kdbus/message.h -+++ b/ipc/kdbus/message.h -@@ -14,6 +14,9 @@ - #ifndef __KDBUS_MESSAGE_H - #define __KDBUS_MESSAGE_H - -+#include <linux/fs.h> -+#include <linux/kref.h> -+#include <uapi/linux/kdbus.h> - #include "util.h" - #include "metadata.h" - -@@ -114,6 +117,9 @@ struct kdbus_kmsg { - - struct kdbus_bus; - struct kdbus_conn; -+struct kdbus_meta_conn; -+struct kdbus_meta_proc; -+struct kdbus_pool_slice; - - struct kdbus_kmsg *kdbus_kmsg_new_kernel(struct kdbus_bus *bus, - u64 dst, u64 cookie_timeout, -diff --git a/ipc/kdbus/notify.c b/ipc/kdbus/notify.c -index a07d242d0470..375758c4896a 100644 ---- a/ipc/kdbus/notify.c -+++ b/ipc/kdbus/notify.c -@@ -28,24 +28,24 @@ - #include "message.h" - #include "notify.h" - --static inline void kdbus_notify_add_tail(struct kdbus_kmsg *kmsg, -+static inline void kdbus_notify_add_tail(struct kdbus_staging *staging, - struct kdbus_bus *bus) - { - spin_lock(&bus->notify_lock); -- list_add_tail(&kmsg->notify_entry, &bus->notify_list); -+ list_add_tail(&staging->notify_entry, &bus->notify_list); - spin_unlock(&bus->notify_lock); - } - - static int kdbus_notify_reply(struct kdbus_bus *bus, u64 id, - u64 cookie, u64 msg_type) - { -- struct kdbus_kmsg *kmsg; -+ struct kdbus_staging *s; - -- kmsg = kdbus_kmsg_new_kernel(bus, id, cookie, 0, msg_type); -- if (IS_ERR(kmsg)) -- return PTR_ERR(kmsg); -+ s = kdbus_staging_new_kernel(bus, id, cookie, 0, msg_type); -+ if (IS_ERR(s)) -+ return PTR_ERR(s); - -- kdbus_notify_add_tail(kmsg, bus); -+ kdbus_notify_add_tail(s, bus); - return 0; - } - -@@ -100,23 +100,23 @@ int kdbus_notify_name_change(struct kdbus_bus *bus, u64 type, - const char *name) - { - size_t name_len, extra_size; -- struct kdbus_kmsg *kmsg; -+ struct kdbus_staging *s; - - name_len = strlen(name) + 1; - extra_size = sizeof(struct kdbus_notify_name_change) + name_len; - -- kmsg = kdbus_kmsg_new_kernel(bus, KDBUS_DST_ID_BROADCAST, 0, -+ s = kdbus_staging_new_kernel(bus, KDBUS_DST_ID_BROADCAST, 0, - extra_size, type); -- if (IS_ERR(kmsg)) -- return PTR_ERR(kmsg); -+ if (IS_ERR(s)) -+ return PTR_ERR(s); - -- kmsg->notify->name_change.old_id.id = old_id; -- kmsg->notify->name_change.old_id.flags = old_flags; -- kmsg->notify->name_change.new_id.id = new_id; -- kmsg->notify->name_change.new_id.flags = new_flags; -- memcpy(kmsg->notify->name_change.name, name, name_len); -+ s->notify->name_change.old_id.id = old_id; -+ s->notify->name_change.old_id.flags = old_flags; -+ s->notify->name_change.new_id.id = new_id; -+ s->notify->name_change.new_id.flags = new_flags; -+ memcpy(s->notify->name_change.name, name, name_len); - -- kdbus_notify_add_tail(kmsg, bus); -+ kdbus_notify_add_tail(s, bus); - return 0; - } - -@@ -132,19 +132,19 @@ int kdbus_notify_name_change(struct kdbus_bus *bus, u64 type, - */ - int kdbus_notify_id_change(struct kdbus_bus *bus, u64 type, u64 id, u64 flags) - { -- struct kdbus_kmsg *kmsg; -+ struct kdbus_staging *s; - size_t extra_size; - - extra_size = sizeof(struct kdbus_notify_id_change); -- kmsg = kdbus_kmsg_new_kernel(bus, KDBUS_DST_ID_BROADCAST, 0, -+ s = kdbus_staging_new_kernel(bus, KDBUS_DST_ID_BROADCAST, 0, - extra_size, type); -- if (IS_ERR(kmsg)) -- return PTR_ERR(kmsg); -+ if (IS_ERR(s)) -+ return PTR_ERR(s); - -- kmsg->notify->id_change.id = id; -- kmsg->notify->id_change.flags = flags; -+ s->notify->id_change.id = id; -+ s->notify->id_change.flags = flags; - -- kdbus_notify_add_tail(kmsg, bus); -+ kdbus_notify_add_tail(s, bus); - return 0; - } - -@@ -157,7 +157,7 @@ int kdbus_notify_id_change(struct kdbus_bus *bus, u64 type, u64 id, u64 flags) - void kdbus_notify_flush(struct kdbus_bus *bus) - { - LIST_HEAD(notify_list); -- struct kdbus_kmsg *kmsg, *tmp; -+ struct kdbus_staging *s, *tmp; - - mutex_lock(&bus->notify_flush_lock); - down_read(&bus->name_registry->rwlock); -@@ -166,26 +166,23 @@ void kdbus_notify_flush(struct kdbus_bus *bus) - list_splice_init(&bus->notify_list, ¬ify_list); - spin_unlock(&bus->notify_lock); - -- list_for_each_entry_safe(kmsg, tmp, ¬ify_list, notify_entry) { -- kdbus_meta_conn_collect(kmsg->conn_meta, NULL, kmsg->seq, -- KDBUS_ATTACH_TIMESTAMP); -- -- if (kmsg->msg.dst_id != KDBUS_DST_ID_BROADCAST) { -+ list_for_each_entry_safe(s, tmp, ¬ify_list, notify_entry) { -+ if (s->msg->dst_id != KDBUS_DST_ID_BROADCAST) { - struct kdbus_conn *conn; - -- conn = kdbus_bus_find_conn_by_id(bus, kmsg->msg.dst_id); -+ conn = kdbus_bus_find_conn_by_id(bus, s->msg->dst_id); - if (conn) { -- kdbus_bus_eavesdrop(bus, NULL, kmsg); -- kdbus_conn_entry_insert(NULL, conn, kmsg, NULL, -+ kdbus_bus_eavesdrop(bus, NULL, s); -+ kdbus_conn_entry_insert(NULL, conn, s, NULL, - NULL); - kdbus_conn_unref(conn); - } - } else { -- kdbus_bus_broadcast(bus, NULL, kmsg); -+ kdbus_bus_broadcast(bus, NULL, s); - } - -- list_del(&kmsg->notify_entry); -- kdbus_kmsg_free(kmsg); -+ list_del(&s->notify_entry); -+ kdbus_staging_free(s); - } - - up_read(&bus->name_registry->rwlock); -@@ -198,10 +195,10 @@ void kdbus_notify_flush(struct kdbus_bus *bus) - */ - void kdbus_notify_free(struct kdbus_bus *bus) - { -- struct kdbus_kmsg *kmsg, *tmp; -+ struct kdbus_staging *s, *tmp; - -- list_for_each_entry_safe(kmsg, tmp, &bus->notify_list, notify_entry) { -- list_del(&kmsg->notify_entry); -- kdbus_kmsg_free(kmsg); -+ list_for_each_entry_safe(s, tmp, &bus->notify_list, notify_entry) { -+ list_del(&s->notify_entry); -+ kdbus_staging_free(s); - } - } -diff --git a/ipc/kdbus/queue.c b/ipc/kdbus/queue.c -index 4749b23a4f14..f9c44d7bae6d 100644 ---- a/ipc/kdbus/queue.c -+++ b/ipc/kdbus/queue.c -@@ -171,243 +171,43 @@ static void kdbus_queue_entry_unlink(struct kdbus_queue_entry *entry) - - /** - * kdbus_queue_entry_new() - allocate a queue entry -- * @conn_src: source connection -- * @conn_dst: destination connection -- * @kmsg: kmsg object the queue entry should track -+ * @src: source connection, or NULL -+ * @dst: destination connection -+ * @s: staging object carrying the message - * -- * Allocates a queue entry based on a given kmsg and allocate space for -+ * Allocates a queue entry based on a given msg and allocate space for - * the message payload and the requested metadata in the connection's pool. - * The entry is not actually added to the queue's lists at this point. - * - * Return: the allocated entry on success, or an ERR_PTR on failures. - */ --struct kdbus_queue_entry *kdbus_queue_entry_new(struct kdbus_conn *conn_src, -- struct kdbus_conn *conn_dst, -- const struct kdbus_kmsg *kmsg) -+struct kdbus_queue_entry *kdbus_queue_entry_new(struct kdbus_conn *src, -+ struct kdbus_conn *dst, -+ struct kdbus_staging *s) - { -- struct kdbus_user *user = conn_src ? conn_src->user : NULL; -- struct kdbus_msg_resources *res = kmsg->res; -- const struct kdbus_msg *msg = &kmsg->msg; - struct kdbus_queue_entry *entry; -- size_t memfd_cnt = 0; -- struct kvec kvec[2]; -- size_t meta_size; -- size_t msg_size; -- u64 payload_off; -- u64 size = 0; -- int ret = 0; -+ int ret; - - entry = kzalloc(sizeof(*entry), GFP_KERNEL); - if (!entry) - return ERR_PTR(-ENOMEM); - - INIT_LIST_HEAD(&entry->entry); -- entry->priority = msg->priority; -- entry->msg_res = kdbus_msg_resources_ref(res); -- entry->proc_meta = kdbus_meta_proc_ref(kmsg->proc_meta); -- entry->conn_meta = kdbus_meta_conn_ref(kmsg->conn_meta); -- entry->conn = kdbus_conn_ref(conn_dst); -- -- if (kmsg->msg.src_id == KDBUS_SRC_ID_KERNEL) -- msg_size = msg->size; -- else -- msg_size = offsetof(struct kdbus_msg, items); -- -- /* sum up the size of the needed slice */ -- size = msg_size; -- -- if (res) { -- size += res->vec_count * -- KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec)); -- -- if (res->memfd_count) { -- entry->memfd_offset = -- kcalloc(res->memfd_count, sizeof(size_t), -- GFP_KERNEL); -- if (!entry->memfd_offset) { -- ret = -ENOMEM; -- goto exit_free_entry; -- } -- -- size += res->memfd_count * -- KDBUS_ITEM_SIZE(sizeof(struct kdbus_memfd)); -- } -- -- if (res->fds_count) -- size += KDBUS_ITEM_SIZE(sizeof(int) * res->fds_count); -- -- if (res->dst_name) -- size += KDBUS_ITEM_SIZE(strlen(res->dst_name) + 1); -- } -- -- /* -- * Remember the offset of the metadata part, so we can override -- * this part later during kdbus_queue_entry_install(). -- */ -- entry->meta_offset = size; -- -- if (entry->proc_meta || entry->conn_meta) { -- entry->attach_flags = -- atomic64_read(&conn_dst->attach_flags_recv); -- -- ret = kdbus_meta_export_prepare(entry->proc_meta, -- NULL, -- entry->conn_meta, -- &entry->attach_flags, -- &meta_size); -- if (ret < 0) -- goto exit_free_entry; -- -- size += meta_size; -- } -+ entry->priority = s->msg->priority; -+ entry->conn = kdbus_conn_ref(dst); -+ entry->gaps = kdbus_gaps_ref(s->gaps); - -- payload_off = size; -- size += kmsg->pool_size; -- size = KDBUS_ALIGN8(size); -- -- ret = kdbus_conn_quota_inc(conn_dst, user, size, -- res ? res->fds_count : 0); -- if (ret < 0) -- goto exit_free_entry; -- -- entry->slice = kdbus_pool_slice_alloc(conn_dst->pool, size, true); -+ entry->slice = kdbus_staging_emit(s, src, dst); - if (IS_ERR(entry->slice)) { - ret = PTR_ERR(entry->slice); - entry->slice = NULL; -- kdbus_conn_quota_dec(conn_dst, user, size, -- res ? res->fds_count : 0); -- goto exit_free_entry; -- } -- -- /* we accounted for exactly 'size' bytes, make sure it didn't grow */ -- WARN_ON(kdbus_pool_slice_size(entry->slice) != size); -- entry->user = kdbus_user_ref(user); -- -- /* copy message header */ -- kvec[0].iov_base = (char *)msg; -- kvec[0].iov_len = msg_size; -- -- ret = kdbus_pool_slice_copy_kvec(entry->slice, 0, kvec, 1, msg_size); -- if (ret < 0) -- goto exit_free_entry; -- -- /* 'size' will now track the write position */ -- size = msg_size; -- -- /* create message payload items */ -- if (res) { -- size_t dst_name_len = 0; -- unsigned int i; -- size_t sz = 0; -- -- if (res->dst_name) { -- dst_name_len = strlen(res->dst_name) + 1; -- sz += KDBUS_ITEM_SIZE(dst_name_len); -- } -- -- for (i = 0; i < res->data_count; ++i) { -- struct kdbus_vec v; -- struct kdbus_memfd m; -- -- switch (res->data[i].type) { -- case KDBUS_MSG_DATA_VEC: -- sz += KDBUS_ITEM_SIZE(sizeof(v)); -- break; -- -- case KDBUS_MSG_DATA_MEMFD: -- sz += KDBUS_ITEM_SIZE(sizeof(m)); -- break; -- } -- } -- -- if (sz) { -- struct kdbus_item *items, *item; -- -- items = kmalloc(sz, GFP_KERNEL); -- if (!items) { -- ret = -ENOMEM; -- goto exit_free_entry; -- } -- -- item = items; -- -- if (res->dst_name) -- item = kdbus_item_set(item, KDBUS_ITEM_DST_NAME, -- res->dst_name, -- dst_name_len); -- -- for (i = 0; i < res->data_count; ++i) { -- struct kdbus_msg_data *d = res->data + i; -- struct kdbus_memfd m = {}; -- struct kdbus_vec v = {}; -- -- switch (d->type) { -- case KDBUS_MSG_DATA_VEC: -- v.size = d->size; -- v.offset = d->vec.off; -- if (v.offset != ~0ULL) -- v.offset += payload_off; -- -- item = kdbus_item_set(item, -- KDBUS_ITEM_PAYLOAD_OFF, -- &v, sizeof(v)); -- break; -- -- case KDBUS_MSG_DATA_MEMFD: -- /* -- * Remember the location of memfds, so -- * we can override the content from -- * kdbus_queue_entry_install(). -- */ -- entry->memfd_offset[memfd_cnt++] = -- msg_size + -- (char *)item - (char *)items + -- offsetof(struct kdbus_item, -- memfd); -- -- item = kdbus_item_set(item, -- KDBUS_ITEM_PAYLOAD_MEMFD, -- &m, sizeof(m)); -- break; -- } -- } -- -- kvec[0].iov_base = items; -- kvec[0].iov_len = sz; -- -- ret = kdbus_pool_slice_copy_kvec(entry->slice, size, -- kvec, 1, sz); -- kfree(items); -- -- if (ret < 0) -- goto exit_free_entry; -- -- size += sz; -- } -- -- /* -- * Remember the location of the FD part, so we can override the -- * content in kdbus_queue_entry_install(). -- */ -- if (res->fds_count) { -- entry->fds_offset = size; -- size += KDBUS_ITEM_SIZE(sizeof(int) * res->fds_count); -- } -- } -- -- /* finally, copy over the actual message payload */ -- if (kmsg->iov_count) { -- ret = kdbus_pool_slice_copy_iovec(entry->slice, payload_off, -- kmsg->iov, -- kmsg->iov_count, -- kmsg->pool_size); -- if (ret < 0) -- goto exit_free_entry; -+ goto error; - } - -+ entry->user = src ? kdbus_user_ref(src->user) : NULL; - return entry; - --exit_free_entry: -+error: - kdbus_queue_entry_free(entry); - return ERR_PTR(ret); - } -@@ -432,17 +232,13 @@ void kdbus_queue_entry_free(struct kdbus_queue_entry *entry) - if (entry->slice) { - kdbus_conn_quota_dec(entry->conn, entry->user, - kdbus_pool_slice_size(entry->slice), -- entry->msg_res ? -- entry->msg_res->fds_count : 0); -+ entry->gaps ? entry->gaps->n_fds : 0); - kdbus_pool_slice_release(entry->slice); -- kdbus_user_unref(entry->user); - } - -- kdbus_msg_resources_unref(entry->msg_res); -- kdbus_meta_conn_unref(entry->conn_meta); -- kdbus_meta_proc_unref(entry->proc_meta); -+ kdbus_user_unref(entry->user); -+ kdbus_gaps_unref(entry->gaps); - kdbus_conn_unref(entry->conn); -- kfree(entry->memfd_offset); - kfree(entry); - } - -@@ -453,136 +249,22 @@ void kdbus_queue_entry_free(struct kdbus_queue_entry *entry) - * @return_flags: Pointer to store the return flags for userspace - * @install_fds: Whether or not to install associated file descriptors - * -- * This function will create a slice to transport the message header, the -- * metadata items and other items for information stored in @entry, and -- * store it as entry->slice. -- * -- * If @install_fds is %true, file descriptors will as well be installed. -- * This function must always be called from the task context of the receiver. -- * - * Return: 0 on success. - */ - int kdbus_queue_entry_install(struct kdbus_queue_entry *entry, - u64 *return_flags, bool install_fds) - { -- u64 msg_size = entry->meta_offset; -- struct kdbus_conn *conn_dst = entry->conn; -- struct kdbus_msg_resources *res; - bool incomplete_fds = false; -- struct kvec kvec[2]; -- size_t memfds = 0; -- int i, ret; -- -- lockdep_assert_held(&conn_dst->lock); -- -- if (entry->proc_meta || entry->conn_meta) { -- size_t meta_size; -- -- ret = kdbus_meta_export(entry->proc_meta, -- NULL, -- entry->conn_meta, -- conn_dst, -- entry->attach_flags, -- entry->slice, -- entry->meta_offset, -- &meta_size); -- if (ret < 0) -- return ret; -- -- msg_size += meta_size; -- } -+ int ret; - -- /* Update message size at offset 0 */ -- kvec[0].iov_base = &msg_size; -- kvec[0].iov_len = sizeof(msg_size); -+ lockdep_assert_held(&entry->conn->lock); - -- ret = kdbus_pool_slice_copy_kvec(entry->slice, 0, kvec, 1, -- sizeof(msg_size)); -+ ret = kdbus_gaps_install(entry->gaps, entry->slice, &incomplete_fds); - if (ret < 0) - return ret; - -- res = entry->msg_res; -- -- if (!res) -- return 0; -- -- if (res->fds_count) { -- struct kdbus_item_header hdr; -- size_t off; -- int *fds; -- -- fds = kmalloc_array(res->fds_count, sizeof(int), GFP_KERNEL); -- if (!fds) -- return -ENOMEM; -- -- for (i = 0; i < res->fds_count; i++) { -- if (install_fds) { -- fds[i] = get_unused_fd_flags(O_CLOEXEC); -- if (fds[i] >= 0) -- fd_install(fds[i], -- get_file(res->fds[i])); -- else -- incomplete_fds = true; -- } else { -- fds[i] = -1; -- } -- } -- -- off = entry->fds_offset; -- -- hdr.type = KDBUS_ITEM_FDS; -- hdr.size = KDBUS_ITEM_HEADER_SIZE + -- sizeof(int) * res->fds_count; -- -- kvec[0].iov_base = &hdr; -- kvec[0].iov_len = sizeof(hdr); -- -- kvec[1].iov_base = fds; -- kvec[1].iov_len = sizeof(int) * res->fds_count; -- -- ret = kdbus_pool_slice_copy_kvec(entry->slice, off, -- kvec, 2, hdr.size); -- kfree(fds); -- -- if (ret < 0) -- return ret; -- } -- -- for (i = 0; i < res->data_count; ++i) { -- struct kdbus_msg_data *d = res->data + i; -- struct kdbus_memfd m; -- -- if (d->type != KDBUS_MSG_DATA_MEMFD) -- continue; -- -- m.start = d->memfd.start; -- m.size = d->size; -- m.fd = -1; -- -- if (install_fds) { -- m.fd = get_unused_fd_flags(O_CLOEXEC); -- if (m.fd < 0) { -- m.fd = -1; -- incomplete_fds = true; -- } else { -- fd_install(m.fd, -- get_file(d->memfd.file)); -- } -- } -- -- kvec[0].iov_base = &m; -- kvec[0].iov_len = sizeof(m); -- -- ret = kdbus_pool_slice_copy_kvec(entry->slice, -- entry->memfd_offset[memfds++], -- kvec, 1, sizeof(m)); -- if (ret < 0) -- return ret; -- } -- - if (incomplete_fds) - *return_flags |= KDBUS_RECV_RETURN_INCOMPLETE_FDS; -- - return 0; - } - -@@ -646,7 +328,7 @@ int kdbus_queue_entry_move(struct kdbus_queue_entry *e, - return 0; - - size = kdbus_pool_slice_size(e->slice); -- fds = e->msg_res ? e->msg_res->fds_count : 0; -+ fds = e->gaps ? e->gaps->n_fds : 0; - - ret = kdbus_conn_quota_inc(dst, e->user, size, fds); - if (ret < 0) -diff --git a/ipc/kdbus/queue.h b/ipc/kdbus/queue.h -index ac471d0c809d..bf686d182ce1 100644 ---- a/ipc/kdbus/queue.h -+++ b/ipc/kdbus/queue.h -@@ -15,6 +15,13 @@ - #ifndef __KDBUS_QUEUE_H - #define __KDBUS_QUEUE_H - -+#include <linux/list.h> -+#include <linux/rbtree.h> -+ -+struct kdbus_conn; -+struct kdbus_pool_slice; -+struct kdbus_reply; -+struct kdbus_staging; - struct kdbus_user; - - /** -@@ -35,52 +42,37 @@ struct kdbus_queue { - * @entry: Entry in the connection's list - * @prio_node: Entry in the priority queue tree - * @prio_entry: Queue tree node entry in the list of one priority -- * @slice: Slice in the receiver's pool for the message -- * @attach_flags: Attach flags used during slice allocation -- * @meta_offset: Offset of first metadata item in slice -- * @fds_offset: Offset of FD item in slice -- * @memfd_offset: Array of slice-offsets for all memfd items - * @priority: Message priority - * @dst_name_id: The sequence number of the name this message is - * addressed to, 0 for messages sent to an ID -- * @msg_res: Message resources -- * @proc_meta: Process metadata, captured at message arrival -- * @conn_meta: Connection metadata, captured at message arrival -- * @reply: The reply block if a reply to this message is expected -+ * @conn: Connection this entry is queued on -+ * @gaps: Gaps object to fill message gaps at RECV time - * @user: User used for accounting -+ * @slice: Slice in the receiver's pool for the message -+ * @reply: The reply block if a reply to this message is expected - */ - struct kdbus_queue_entry { - struct list_head entry; - struct rb_node prio_node; - struct list_head prio_entry; - -- struct kdbus_pool_slice *slice; -- -- u64 attach_flags; -- size_t meta_offset; -- size_t fds_offset; -- size_t *memfd_offset; -- - s64 priority; - u64 dst_name_id; - -- struct kdbus_msg_resources *msg_res; -- struct kdbus_meta_proc *proc_meta; -- struct kdbus_meta_conn *conn_meta; -- struct kdbus_reply *reply; - struct kdbus_conn *conn; -+ struct kdbus_gaps *gaps; - struct kdbus_user *user; -+ struct kdbus_pool_slice *slice; -+ struct kdbus_reply *reply; - }; - --struct kdbus_kmsg; -- - void kdbus_queue_init(struct kdbus_queue *queue); - struct kdbus_queue_entry *kdbus_queue_peek(struct kdbus_queue *queue, - s64 priority, bool use_priority); - --struct kdbus_queue_entry *kdbus_queue_entry_new(struct kdbus_conn *conn_src, -- struct kdbus_conn *conn_dst, -- const struct kdbus_kmsg *kmsg); -+struct kdbus_queue_entry *kdbus_queue_entry_new(struct kdbus_conn *src, -+ struct kdbus_conn *dst, -+ struct kdbus_staging *s); - void kdbus_queue_entry_free(struct kdbus_queue_entry *entry); - int kdbus_queue_entry_install(struct kdbus_queue_entry *entry, - u64 *return_flags, bool install_fds); --- -2.4.3 - - -From 149fd9e2deb3fc394cf37f6f848ccb1ea34358d2 Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Wed, 24 Jun 2015 15:29:53 +0200 -Subject: [PATCH 105/132] kdbus: drop unused metadata code - -Now that we switched to the new kdbus_staging infrastructure, the old -RECV-time metadata helpers are no longer needed. Drop them. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> ---- - ipc/kdbus/metadata.c | 371 --------------------------------------------------- - ipc/kdbus/metadata.h | 11 -- - 2 files changed, 382 deletions(-) - -diff --git a/ipc/kdbus/metadata.c b/ipc/kdbus/metadata.c -index 70ce5d15fc98..43e5f4564925 100644 ---- a/ipc/kdbus/metadata.c -+++ b/ipc/kdbus/metadata.c -@@ -714,138 +714,6 @@ exit_unlock: - return ret; - } - --/* -- * kdbus_meta_export_prepare() - Prepare metadata for export -- * @mp: Process metadata, or NULL -- * @mf: Fake metadata, or NULL -- * @mc: Connection metadata, or NULL -- * @mask: Pointer to mask of KDBUS_ATTACH_* flags to export -- * @sz: Pointer to return the size needed by the metadata -- * -- * Does a conservative calculation of how much space metadata information -- * will take up during export. It is 'conservative' because for string -- * translations in namespaces, it will use the kernel namespaces, which is -- * the longest possible version. -- * -- * The actual size consumed by kdbus_meta_export() may hence vary from the -- * one reported here, but it is guaranteed never to be greater. -- * -- * Return: 0 on success, negative error number otherwise. -- */ --int kdbus_meta_export_prepare(struct kdbus_meta_proc *mp, -- struct kdbus_meta_fake *mf, -- struct kdbus_meta_conn *mc, -- u64 *mask, size_t *sz) --{ -- char *exe_pathname = NULL; -- void *exe_page = NULL; -- size_t size = 0; -- u64 valid = 0; -- int ret = 0; -- -- if (WARN_ON(mf && mp)) -- mp = NULL; -- -- if (mf) -- valid |= mf->valid; -- -- if (mp) { -- mutex_lock(&mp->lock); -- valid |= mp->valid; -- mutex_unlock(&mp->lock); -- } -- -- if (mc) { -- mutex_lock(&mc->lock); -- valid |= mc->valid; -- mutex_unlock(&mc->lock); -- } -- -- *mask &= valid; -- -- if (!*mask) -- goto exit; -- -- /* process metadata */ -- -- if ((mp || mf) && (*mask & KDBUS_ATTACH_CREDS)) -- size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_creds)); -- -- if ((mp || mf) && (*mask & KDBUS_ATTACH_PIDS)) -- size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_pids)); -- -- if (mp && (*mask & KDBUS_ATTACH_AUXGROUPS)) -- size += KDBUS_ITEM_SIZE(mp->cred->group_info->ngroups * -- sizeof(u64)); -- -- if (mp && (*mask & KDBUS_ATTACH_TID_COMM)) -- size += KDBUS_ITEM_SIZE(strlen(mp->tid_comm) + 1); -- -- if (mp && (*mask & KDBUS_ATTACH_PID_COMM)) -- size += KDBUS_ITEM_SIZE(strlen(mp->pid_comm) + 1); -- -- if (mp && (*mask & KDBUS_ATTACH_EXE)) { -- exe_page = (void *)__get_free_page(GFP_TEMPORARY); -- if (!exe_page) { -- ret = -ENOMEM; -- goto exit; -- } -- -- exe_pathname = d_path(&mp->exe_path, exe_page, PAGE_SIZE); -- if (IS_ERR(exe_pathname)) { -- ret = PTR_ERR(exe_pathname); -- goto exit; -- } -- -- size += KDBUS_ITEM_SIZE(strlen(exe_pathname) + 1); -- free_page((unsigned long)exe_page); -- } -- -- if (mp && (*mask & KDBUS_ATTACH_CMDLINE)) -- size += KDBUS_ITEM_SIZE(strlen(mp->cmdline) + 1); -- -- if (mp && (*mask & KDBUS_ATTACH_CGROUP)) -- size += KDBUS_ITEM_SIZE(strlen(mp->cgroup) + 1); -- -- if (mp && (*mask & KDBUS_ATTACH_CAPS)) -- size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_meta_caps)); -- -- if ((mp || mf) && (*mask & KDBUS_ATTACH_SECLABEL)) -- size += KDBUS_ITEM_SIZE(strlen(mp ? mp->seclabel -- : mf->seclabel) + 1); -- -- if (mp && (*mask & KDBUS_ATTACH_AUDIT)) -- size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_audit)); -- -- /* connection metadata */ -- -- if (mc && (*mask & KDBUS_ATTACH_NAMES)) -- size += KDBUS_ALIGN8(mc->owned_names_size); -- -- if (mc && (*mask & KDBUS_ATTACH_CONN_DESCRIPTION)) -- size += KDBUS_ITEM_SIZE(strlen(mc->conn_description) + 1); -- -- if (mc && (*mask & KDBUS_ATTACH_TIMESTAMP)) -- size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_timestamp)); -- --exit: -- *sz = size; -- -- return ret; --} -- --static int kdbus_meta_push_kvec(struct kvec *kvec, -- struct kdbus_item_header *hdr, -- u64 type, void *payload, -- size_t payload_size, u64 *size) --{ -- hdr->type = type; -- hdr->size = KDBUS_ITEM_HEADER_SIZE + payload_size; -- kdbus_kvec_set(kvec++, hdr, sizeof(*hdr), size); -- kdbus_kvec_set(kvec++, payload, payload_size, size); -- return 2 + !!kdbus_kvec_pad(kvec++, size); --} -- - static void kdbus_meta_export_caps(struct kdbus_meta_caps *out, - const struct kdbus_meta_proc *mp, - struct user_namespace *user_ns) -@@ -922,245 +790,6 @@ static gid_t kdbus_from_kgid_keep(struct user_namespace *ns, kgid_t gid) - return gid_valid(gid) ? from_kgid_munged(ns, gid) : ((gid_t)-1); - } - --/** -- * kdbus_meta_export() - export information from metadata into a slice -- * @mp: Process metadata, or NULL -- * @mf: Fake metadata, or NULL -- * @mc: Connection metadata, or NULL -- * @conn: Target connection to translate metadata into -- * @mask: Mask of KDBUS_ATTACH_* flags to export -- * @slice: The slice to export to -- * @offset: The offset inside @slice to write to -- * @real_size: The real size the metadata consumed -- * -- * This function exports information from metadata into @slice at offset -- * @offset inside that slice. Only information that is requested in @mask -- * and that has been collected before is exported. -- * -- * In order to make sure not to write out of bounds, @mask must be the same -- * value that was previously returned from kdbus_meta_export_prepare(). The -- * function will, however, not necessarily write as many bytes as returned by -- * kdbus_meta_export_prepare(); depending on the namespaces in question, it -- * might use up less than that. -- * -- * All information will be translated using the namespaces of @conn. -- * -- * Return: 0 on success, negative error number otherwise. -- */ --int kdbus_meta_export(struct kdbus_meta_proc *mp, -- struct kdbus_meta_fake *mf, -- struct kdbus_meta_conn *mc, -- struct kdbus_conn *conn, -- u64 mask, -- struct kdbus_pool_slice *slice, -- off_t offset, -- size_t *real_size) --{ -- struct user_namespace *user_ns = conn->user_ns; -- struct kdbus_item_header item_hdr[13], *hdr; -- char *exe_pathname = NULL; -- struct kdbus_creds creds; -- struct kdbus_pids pids; -- void *exe_page = NULL; -- struct kvec kvec[40]; -- u64 *auxgrps = NULL; -- size_t cnt = 0; -- u64 size = 0; -- int ret = 0; -- -- if (WARN_ON(mf && mp)) -- mp = NULL; -- -- hdr = &item_hdr[0]; -- -- if (mask == 0) { -- *real_size = 0; -- return 0; -- } -- -- /* process metadata */ -- -- if (mf && (mask & KDBUS_ATTACH_CREDS)) { -- creds.uid = kdbus_from_kuid_keep(user_ns, mf->uid); -- creds.euid = kdbus_from_kuid_keep(user_ns, mf->euid); -- creds.suid = kdbus_from_kuid_keep(user_ns, mf->suid); -- creds.fsuid = kdbus_from_kuid_keep(user_ns, mf->fsuid); -- creds.gid = kdbus_from_kgid_keep(user_ns, mf->gid); -- creds.egid = kdbus_from_kgid_keep(user_ns, mf->egid); -- creds.sgid = kdbus_from_kgid_keep(user_ns, mf->sgid); -- creds.fsgid = kdbus_from_kgid_keep(user_ns, mf->fsgid); -- -- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, KDBUS_ITEM_CREDS, -- &creds, sizeof(creds), &size); -- } else if (mp && (mask & KDBUS_ATTACH_CREDS)) { -- const struct cred *c = mp->cred; -- -- creds.uid = kdbus_from_kuid_keep(user_ns, c->uid); -- creds.euid = kdbus_from_kuid_keep(user_ns, c->euid); -- creds.suid = kdbus_from_kuid_keep(user_ns, c->suid); -- creds.fsuid = kdbus_from_kuid_keep(user_ns, c->fsuid); -- creds.gid = kdbus_from_kgid_keep(user_ns, c->gid); -- creds.egid = kdbus_from_kgid_keep(user_ns, c->egid); -- creds.sgid = kdbus_from_kgid_keep(user_ns, c->sgid); -- creds.fsgid = kdbus_from_kgid_keep(user_ns, c->fsgid); -- -- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, KDBUS_ITEM_CREDS, -- &creds, sizeof(creds), &size); -- } -- -- if (mf && (mask & KDBUS_ATTACH_PIDS)) { -- pids.pid = pid_nr_ns(mf->tgid, conn->pid_ns); -- pids.tid = pid_nr_ns(mf->pid, conn->pid_ns); -- pids.ppid = pid_nr_ns(mf->ppid, conn->pid_ns); -- -- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, KDBUS_ITEM_PIDS, -- &pids, sizeof(pids), &size); -- } else if (mp && (mask & KDBUS_ATTACH_PIDS)) { -- pids.pid = pid_nr_ns(mp->tgid, conn->pid_ns); -- pids.tid = pid_nr_ns(mp->pid, conn->pid_ns); -- pids.ppid = pid_nr_ns(mp->ppid, conn->pid_ns); -- -- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, KDBUS_ITEM_PIDS, -- &pids, sizeof(pids), &size); -- } -- -- if (mp && (mask & KDBUS_ATTACH_AUXGROUPS)) { -- const struct group_info *info = mp->cred->group_info; -- size_t i, n, payload_size; -- -- n = info->ngroups; -- payload_size = n * sizeof(u64); -- auxgrps = kmalloc(payload_size, GFP_KERNEL); -- if (!auxgrps) { -- ret = -ENOMEM; -- goto exit; -- } -- -- for (i = 0; i < n; ++i) -- auxgrps[i] = from_kgid_munged(user_ns, -- GROUP_AT(info, i)); -- -- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, -- KDBUS_ITEM_AUXGROUPS, -- auxgrps, payload_size, &size); -- } -- -- if (mp && (mask & KDBUS_ATTACH_TID_COMM)) -- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, -- KDBUS_ITEM_TID_COMM, mp->tid_comm, -- strlen(mp->tid_comm) + 1, &size); -- -- if (mp && (mask & KDBUS_ATTACH_PID_COMM)) -- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, -- KDBUS_ITEM_PID_COMM, mp->pid_comm, -- strlen(mp->pid_comm) + 1, &size); -- -- if (mp && (mask & KDBUS_ATTACH_EXE)) { -- struct path p; -- -- /* -- * TODO: We need access to __d_path() so we can write the path -- * relative to conn->root_path. Once upstream, we need -- * EXPORT_SYMBOL(__d_path) or an equivalent of d_path() that -- * takes the root path directly. Until then, we drop this item -- * if the root-paths differ. -- */ -- -- get_fs_root(current->fs, &p); -- if (path_equal(&p, &mp->root_path) && -- path_equal(&p, &conn->root_path)) { -- exe_page = (void *)__get_free_page(GFP_TEMPORARY); -- if (!exe_page) { -- path_put(&p); -- ret = -ENOMEM; -- goto exit; -- } -- -- exe_pathname = d_path(&mp->exe_path, exe_page, -- PAGE_SIZE); -- if (IS_ERR(exe_pathname)) { -- path_put(&p); -- ret = PTR_ERR(exe_pathname); -- goto exit; -- } -- -- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, -- KDBUS_ITEM_EXE, -- exe_pathname, -- strlen(exe_pathname) + 1, -- &size); -- } -- path_put(&p); -- } -- -- if (mp && (mask & KDBUS_ATTACH_CMDLINE)) -- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, -- KDBUS_ITEM_CMDLINE, mp->cmdline, -- strlen(mp->cmdline) + 1, &size); -- -- if (mp && (mask & KDBUS_ATTACH_CGROUP)) -- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, -- KDBUS_ITEM_CGROUP, mp->cgroup, -- strlen(mp->cgroup) + 1, &size); -- -- if (mp && (mask & KDBUS_ATTACH_CAPS)) { -- struct kdbus_meta_caps caps = {}; -- -- kdbus_meta_export_caps(&caps, mp, user_ns); -- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, -- KDBUS_ITEM_CAPS, &caps, -- sizeof(caps), &size); -- } -- -- if (mf && (mask & KDBUS_ATTACH_SECLABEL)) -- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, -- KDBUS_ITEM_SECLABEL, mf->seclabel, -- strlen(mf->seclabel) + 1, &size); -- else if (mp && (mask & KDBUS_ATTACH_SECLABEL)) -- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, -- KDBUS_ITEM_SECLABEL, mp->seclabel, -- strlen(mp->seclabel) + 1, &size); -- -- if (mp && (mask & KDBUS_ATTACH_AUDIT)) { -- struct kdbus_audit a = { -- .loginuid = from_kuid(user_ns, mp->audit_loginuid), -- .sessionid = mp->audit_sessionid, -- }; -- -- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, KDBUS_ITEM_AUDIT, -- &a, sizeof(a), &size); -- } -- -- /* connection metadata */ -- -- if (mc && (mask & KDBUS_ATTACH_NAMES)) -- kdbus_kvec_set(&kvec[cnt++], mc->owned_names_items, -- KDBUS_ALIGN8(mc->owned_names_size), &size); -- -- if (mc && (mask & KDBUS_ATTACH_CONN_DESCRIPTION)) -- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, -- KDBUS_ITEM_CONN_DESCRIPTION, -- mc->conn_description, -- strlen(mc->conn_description) + 1, -- &size); -- -- if (mc && (mask & KDBUS_ATTACH_TIMESTAMP)) -- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, -- KDBUS_ITEM_TIMESTAMP, &mc->ts, -- sizeof(mc->ts), &size); -- -- ret = kdbus_pool_slice_copy_kvec(slice, offset, kvec, cnt, size); -- *real_size = size; -- --exit: -- kfree(auxgrps); -- -- if (exe_page) -- free_page((unsigned long)exe_page); -- -- return ret; --} -- - struct kdbus_meta_staging { - const struct kdbus_meta_proc *mp; - const struct kdbus_meta_fake *mf; -diff --git a/ipc/kdbus/metadata.h b/ipc/kdbus/metadata.h -index a30b0ad26af2..8fb2a9f7f82e 100644 ---- a/ipc/kdbus/metadata.h -+++ b/ipc/kdbus/metadata.h -@@ -72,17 +72,6 @@ int kdbus_meta_conn_collect(struct kdbus_meta_conn *mc, - struct kdbus_conn *conn, - u64 msg_seqnum, u64 what); - --int kdbus_meta_export_prepare(struct kdbus_meta_proc *mp, -- struct kdbus_meta_fake *mf, -- struct kdbus_meta_conn *mc, -- u64 *mask, size_t *sz); --int kdbus_meta_export(struct kdbus_meta_proc *mp, -- struct kdbus_meta_fake *mf, -- struct kdbus_meta_conn *mc, -- struct kdbus_conn *conn, -- u64 mask, -- struct kdbus_pool_slice *slice, -- off_t offset, size_t *real_size); - int kdbus_meta_emit(struct kdbus_meta_proc *mp, - struct kdbus_meta_fake *mf, - struct kdbus_meta_conn *mc, --- -2.4.3 - - -From 5c9d1e5ee20da087dee20f20d5fa312249a163e4 Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Wed, 24 Jun 2015 15:31:10 +0200 -Subject: [PATCH 106/132] kdbus: drop unused message handling - -Now that we switched to kdbus_staging, the old message importer and -handling is no longer needed. Drop it. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> ---- - ipc/kdbus/message.c | 600 ---------------------------------------------------- - ipc/kdbus/message.h | 106 ---------- - 2 files changed, 706 deletions(-) - -diff --git a/ipc/kdbus/message.c b/ipc/kdbus/message.c -index f1ec69f3697f..72fb5908c927 100644 ---- a/ipc/kdbus/message.c -+++ b/ipc/kdbus/message.c -@@ -37,608 +37,8 @@ - #include "names.h" - #include "policy.h" - --#define KDBUS_KMSG_HEADER_SIZE offsetof(struct kdbus_kmsg, msg) -- --static struct kdbus_msg_resources *kdbus_msg_resources_new(void) --{ -- struct kdbus_msg_resources *r; -- -- r = kzalloc(sizeof(*r), GFP_KERNEL); -- if (!r) -- return ERR_PTR(-ENOMEM); -- -- kref_init(&r->kref); -- -- return r; --} -- --static void __kdbus_msg_resources_free(struct kref *kref) --{ -- struct kdbus_msg_resources *r = -- container_of(kref, struct kdbus_msg_resources, kref); -- size_t i; -- -- for (i = 0; i < r->data_count; ++i) { -- switch (r->data[i].type) { -- case KDBUS_MSG_DATA_VEC: -- /* nothing to do */ -- break; -- case KDBUS_MSG_DATA_MEMFD: -- if (r->data[i].memfd.file) -- fput(r->data[i].memfd.file); -- break; -- } -- } -- -- for (i = 0; i < r->fds_count; i++) -- if (r->fds[i]) -- fput(r->fds[i]); -- -- kfree(r->dst_name); -- kfree(r->data); -- kfree(r->fds); -- kfree(r); --} -- --/** -- * kdbus_msg_resources_ref() - Acquire reference to msg resources -- * @r: resources to acquire ref to -- * -- * Return: The acquired resource -- */ --struct kdbus_msg_resources * --kdbus_msg_resources_ref(struct kdbus_msg_resources *r) --{ -- if (r) -- kref_get(&r->kref); -- return r; --} -- --/** -- * kdbus_msg_resources_unref() - Drop reference to msg resources -- * @r: resources to drop reference of -- * -- * Return: NULL -- */ --struct kdbus_msg_resources * --kdbus_msg_resources_unref(struct kdbus_msg_resources *r) --{ -- if (r) -- kref_put(&r->kref, __kdbus_msg_resources_free); -- return NULL; --} -- --/** -- * kdbus_kmsg_free() - free allocated message -- * @kmsg: Message -- */ --void kdbus_kmsg_free(struct kdbus_kmsg *kmsg) --{ -- if (!kmsg) -- return; -- -- kdbus_msg_resources_unref(kmsg->res); -- kdbus_meta_conn_unref(kmsg->conn_meta); -- kdbus_meta_proc_unref(kmsg->proc_meta); -- kfree(kmsg->iov); -- kfree(kmsg); --} -- --struct kdbus_kmsg *kdbus_kmsg_new_kernel(struct kdbus_bus *bus, -- u64 dst, u64 cookie_timeout, -- size_t it_size, size_t it_type) --{ -- struct kdbus_kmsg *kmsg; -- size_t size; -- int ret; -- -- size = sizeof(struct kdbus_kmsg) + KDBUS_ITEM_SIZE(it_size); -- kmsg = kzalloc(size, GFP_KERNEL); -- if (!kmsg) -- return ERR_PTR(-ENOMEM); -- -- kmsg->seq = atomic64_inc_return(&bus->domain->last_id); -- -- kmsg->proc_meta = kdbus_meta_proc_new(); -- if (IS_ERR(kmsg->proc_meta)) { -- ret = PTR_ERR(kmsg->proc_meta); -- kmsg->proc_meta = NULL; -- goto exit; -- } -- -- kmsg->conn_meta = kdbus_meta_conn_new(); -- if (IS_ERR(kmsg->conn_meta)) { -- ret = PTR_ERR(kmsg->conn_meta); -- kmsg->conn_meta = NULL; -- goto exit; -- } -- -- kmsg->msg.size = size - KDBUS_KMSG_HEADER_SIZE; -- kmsg->msg.flags = (dst == KDBUS_DST_ID_BROADCAST) ? -- KDBUS_MSG_SIGNAL : 0; -- kmsg->msg.dst_id = dst; -- kmsg->msg.src_id = KDBUS_SRC_ID_KERNEL; -- kmsg->msg.payload_type = KDBUS_PAYLOAD_KERNEL; -- kmsg->msg.cookie_reply = cookie_timeout; -- kmsg->notify = kmsg->msg.items; -- kmsg->notify->size = KDBUS_ITEM_HEADER_SIZE + it_size; -- kmsg->notify->type = it_type; -- -- return kmsg; -- --exit: -- kdbus_kmsg_free(kmsg); -- return ERR_PTR(ret); --} -- --static int kdbus_handle_check_file(struct file *file) --{ -- struct inode *inode = file_inode(file); -- struct socket *sock; -- -- /* -- * Don't allow file descriptors in the transport that themselves allow -- * file descriptor queueing. This will eventually be allowed once both -- * unix domain sockets and kdbus share a generic garbage collector. -- */ -- -- if (file->f_op == &kdbus_handle_ops) -- return -EOPNOTSUPP; -- -- if (!S_ISSOCK(inode->i_mode)) -- return 0; -- -- if (file->f_mode & FMODE_PATH) -- return 0; -- -- sock = SOCKET_I(inode); -- if (sock->sk && sock->ops && sock->ops->family == PF_UNIX) -- return -EOPNOTSUPP; -- -- return 0; --} -- - static const char * const zeros = "\0\0\0\0\0\0\0"; - --/* -- * kdbus_msg_scan_items() - validate incoming data and prepare parsing -- * @kmsg: Message -- * @bus: Bus the message is sent over -- * -- * Return: 0 on success, negative errno on failure. -- * -- * Files references in MEMFD or FDS items are pinned. -- * -- * On errors, the caller should drop any taken reference with -- * kdbus_kmsg_free() -- */ --static int kdbus_msg_scan_items(struct kdbus_kmsg *kmsg, -- struct kdbus_bus *bus) --{ -- struct kdbus_msg_resources *res = kmsg->res; -- const struct kdbus_msg *msg = &kmsg->msg; -- const struct kdbus_item *item; -- size_t n_res, n_vecs, n_memfds; -- bool has_bloom = false; -- bool has_name = false; -- bool has_fds = false; -- bool is_broadcast; -- bool is_signal; -- u64 vec_size; -- -- is_broadcast = (msg->dst_id == KDBUS_DST_ID_BROADCAST); -- is_signal = !!(msg->flags & KDBUS_MSG_SIGNAL); -- -- /* count data payloads */ -- n_vecs = 0; -- n_memfds = 0; -- KDBUS_ITEMS_FOREACH(item, msg->items, KDBUS_ITEMS_SIZE(msg, items)) { -- switch (item->type) { -- case KDBUS_ITEM_PAYLOAD_VEC: -- ++n_vecs; -- break; -- case KDBUS_ITEM_PAYLOAD_MEMFD: -- ++n_memfds; -- if (item->memfd.size % 8) -- ++n_vecs; -- break; -- default: -- break; -- } -- } -- -- n_res = n_vecs + n_memfds; -- if (n_res > 0) { -- res->data = kcalloc(n_res, sizeof(*res->data), GFP_KERNEL); -- if (!res->data) -- return -ENOMEM; -- } -- -- if (n_vecs > 0) { -- kmsg->iov = kcalloc(n_vecs, sizeof(*kmsg->iov), GFP_KERNEL); -- if (!kmsg->iov) -- return -ENOMEM; -- } -- -- /* import data payloads */ -- vec_size = 0; -- KDBUS_ITEMS_FOREACH(item, msg->items, KDBUS_ITEMS_SIZE(msg, items)) { -- size_t payload_size = KDBUS_ITEM_PAYLOAD_SIZE(item); -- struct iovec *iov = kmsg->iov + kmsg->iov_count; -- -- switch (item->type) { -- case KDBUS_ITEM_PAYLOAD_VEC: { -- struct kdbus_msg_data *d = res->data + res->data_count; -- void __force __user *ptr = KDBUS_PTR(item->vec.address); -- size_t size = item->vec.size; -- -- if (vec_size + size < vec_size) -- return -EMSGSIZE; -- if (vec_size + size > KDBUS_MSG_MAX_PAYLOAD_VEC_SIZE) -- return -EMSGSIZE; -- -- d->type = KDBUS_MSG_DATA_VEC; -- d->size = size; -- -- if (ptr) { -- if (unlikely(!access_ok(VERIFY_READ, ptr, -- size))) -- return -EFAULT; -- -- d->vec.off = kmsg->pool_size; -- iov->iov_base = ptr; -- iov->iov_len = size; -- } else { -- d->vec.off = ~0ULL; -- iov->iov_base = (char __user *)zeros; -- iov->iov_len = size % 8; -- } -- -- if (kmsg->pool_size + iov->iov_len < kmsg->pool_size) -- return -EMSGSIZE; -- -- kmsg->pool_size += iov->iov_len; -- ++kmsg->iov_count; -- ++res->vec_count; -- ++res->data_count; -- vec_size += size; -- -- break; -- } -- -- case KDBUS_ITEM_PAYLOAD_MEMFD: { -- struct kdbus_msg_data *d = res->data + res->data_count; -- u64 start = item->memfd.start; -- u64 size = item->memfd.size; -- size_t pad = size % 8; -- int seals, mask; -- struct file *f; -- -- if (kmsg->pool_size + size % 8 < kmsg->pool_size) -- return -EMSGSIZE; -- if (start + size < start) -- return -EMSGSIZE; -- -- if (item->memfd.fd < 0) -- return -EBADF; -- -- if (res->memfd_count >= KDBUS_MSG_MAX_MEMFD_ITEMS) -- return -E2BIG; -- -- f = fget(item->memfd.fd); -- if (!f) -- return -EBADF; -- -- if (pad) { -- iov->iov_base = (char __user *)zeros; -- iov->iov_len = pad; -- -- kmsg->pool_size += pad; -- ++kmsg->iov_count; -- } -- -- ++res->data_count; -- ++res->memfd_count; -- -- d->type = KDBUS_MSG_DATA_MEMFD; -- d->size = size; -- d->memfd.start = start; -- d->memfd.file = f; -- -- /* -- * We only accept a sealed memfd file whose content -- * cannot be altered by the sender or anybody else -- * while it is shared or in-flight. Other files need -- * to be passed with KDBUS_MSG_FDS. -- */ -- seals = shmem_get_seals(f); -- if (seals < 0) -- return -EMEDIUMTYPE; -- -- mask = F_SEAL_SHRINK | F_SEAL_GROW | -- F_SEAL_WRITE | F_SEAL_SEAL; -- if ((seals & mask) != mask) -- return -ETXTBSY; -- -- if (start + size > (u64)i_size_read(file_inode(f))) -- return -EBADF; -- -- break; -- } -- -- case KDBUS_ITEM_FDS: { -- unsigned int i; -- unsigned int fds_count = payload_size / sizeof(int); -- -- /* do not allow multiple fd arrays */ -- if (has_fds) -- return -EEXIST; -- has_fds = true; -- -- /* Do not allow to broadcast file descriptors */ -- if (is_broadcast) -- return -ENOTUNIQ; -- -- if (fds_count > KDBUS_CONN_MAX_FDS_PER_USER) -- return -EMFILE; -- -- res->fds = kcalloc(fds_count, sizeof(struct file *), -- GFP_KERNEL); -- if (!res->fds) -- return -ENOMEM; -- -- for (i = 0; i < fds_count; i++) { -- int fd = item->fds[i]; -- int ret; -- -- /* -- * Verify the fd and increment the usage count. -- * Use fget_raw() to allow passing O_PATH fds. -- */ -- if (fd < 0) -- return -EBADF; -- -- res->fds[i] = fget_raw(fd); -- if (!res->fds[i]) -- return -EBADF; -- -- res->fds_count++; -- -- ret = kdbus_handle_check_file(res->fds[i]); -- if (ret < 0) -- return ret; -- } -- -- break; -- } -- -- case KDBUS_ITEM_BLOOM_FILTER: { -- u64 bloom_size; -- -- /* do not allow multiple bloom filters */ -- if (has_bloom) -- return -EEXIST; -- has_bloom = true; -- -- bloom_size = payload_size - -- offsetof(struct kdbus_bloom_filter, data); -- -- /* -- * Allow only bloom filter sizes of a multiple of 64bit. -- */ -- if (!KDBUS_IS_ALIGNED8(bloom_size)) -- return -EFAULT; -- -- /* do not allow mismatching bloom filter sizes */ -- if (bloom_size != bus->bloom.size) -- return -EDOM; -- -- kmsg->bloom_filter = &item->bloom_filter; -- break; -- } -- -- case KDBUS_ITEM_DST_NAME: -- /* do not allow multiple names */ -- if (has_name) -- return -EEXIST; -- has_name = true; -- -- if (!kdbus_name_is_valid(item->str, false)) -- return -EINVAL; -- -- res->dst_name = kstrdup(item->str, GFP_KERNEL); -- if (!res->dst_name) -- return -ENOMEM; -- break; -- -- default: -- return -EINVAL; -- } -- } -- -- /* name is needed if no ID is given */ -- if (msg->dst_id == KDBUS_DST_ID_NAME && !has_name) -- return -EDESTADDRREQ; -- -- if (is_broadcast) { -- /* Broadcasts can't take names */ -- if (has_name) -- return -EBADMSG; -- -- /* All broadcasts have to be signals */ -- if (!is_signal) -- return -EBADMSG; -- -- /* Timeouts are not allowed for broadcasts */ -- if (msg->timeout_ns > 0) -- return -ENOTUNIQ; -- } -- -- /* -- * Signal messages require a bloom filter, and bloom filters are -- * only valid with signals. -- */ -- if (is_signal ^ has_bloom) -- return -EBADMSG; -- -- return 0; --} -- --/** -- * kdbus_kmsg_new_from_cmd() - create kernel message from send payload -- * @conn: Connection -- * @cmd_send: Payload of KDBUS_CMD_SEND -- * -- * Return: a new kdbus_kmsg on success, ERR_PTR on failure. -- */ --struct kdbus_kmsg *kdbus_kmsg_new_from_cmd(struct kdbus_conn *conn, -- struct kdbus_cmd_send *cmd_send) --{ -- struct kdbus_kmsg *m; -- u64 size; -- int ret; -- -- ret = kdbus_copy_from_user(&size, KDBUS_PTR(cmd_send->msg_address), -- sizeof(size)); -- if (ret < 0) -- return ERR_PTR(ret); -- -- if (size < sizeof(struct kdbus_msg) || size > KDBUS_MSG_MAX_SIZE) -- return ERR_PTR(-EINVAL); -- -- m = kmalloc(size + KDBUS_KMSG_HEADER_SIZE, GFP_KERNEL); -- if (!m) -- return ERR_PTR(-ENOMEM); -- -- memset(m, 0, KDBUS_KMSG_HEADER_SIZE); -- m->seq = atomic64_inc_return(&conn->ep->bus->domain->last_id); -- -- m->proc_meta = kdbus_meta_proc_new(); -- if (IS_ERR(m->proc_meta)) { -- ret = PTR_ERR(m->proc_meta); -- m->proc_meta = NULL; -- goto exit_free; -- } -- -- m->conn_meta = kdbus_meta_conn_new(); -- if (IS_ERR(m->conn_meta)) { -- ret = PTR_ERR(m->conn_meta); -- m->conn_meta = NULL; -- goto exit_free; -- } -- -- if (copy_from_user(&m->msg, KDBUS_PTR(cmd_send->msg_address), size)) { -- ret = -EFAULT; -- goto exit_free; -- } -- -- if (m->msg.size != size) { -- ret = -EINVAL; -- goto exit_free; -- } -- -- if (m->msg.flags & ~(KDBUS_MSG_EXPECT_REPLY | -- KDBUS_MSG_NO_AUTO_START | -- KDBUS_MSG_SIGNAL)) { -- ret = -EINVAL; -- goto exit_free; -- } -- -- ret = kdbus_items_validate(m->msg.items, -- KDBUS_ITEMS_SIZE(&m->msg, items)); -- if (ret < 0) -- goto exit_free; -- -- m->res = kdbus_msg_resources_new(); -- if (IS_ERR(m->res)) { -- ret = PTR_ERR(m->res); -- m->res = NULL; -- goto exit_free; -- } -- -- /* do not accept kernel-generated messages */ -- if (m->msg.payload_type == KDBUS_PAYLOAD_KERNEL) { -- ret = -EINVAL; -- goto exit_free; -- } -- -- if (m->msg.flags & KDBUS_MSG_EXPECT_REPLY) { -- /* requests for replies need timeout and cookie */ -- if (m->msg.timeout_ns == 0 || m->msg.cookie == 0) { -- ret = -EINVAL; -- goto exit_free; -- } -- -- /* replies may not be expected for broadcasts */ -- if (m->msg.dst_id == KDBUS_DST_ID_BROADCAST) { -- ret = -ENOTUNIQ; -- goto exit_free; -- } -- -- /* replies may not be expected for signals */ -- if (m->msg.flags & KDBUS_MSG_SIGNAL) { -- ret = -EINVAL; -- goto exit_free; -- } -- } else { -- /* -- * KDBUS_SEND_SYNC_REPLY is only valid together with -- * KDBUS_MSG_EXPECT_REPLY -- */ -- if (cmd_send->flags & KDBUS_SEND_SYNC_REPLY) { -- ret = -EINVAL; -- goto exit_free; -- } -- -- /* replies cannot be signals */ -- if (m->msg.cookie_reply && (m->msg.flags & KDBUS_MSG_SIGNAL)) { -- ret = -EINVAL; -- goto exit_free; -- } -- } -- -- ret = kdbus_msg_scan_items(m, conn->ep->bus); -- if (ret < 0) -- goto exit_free; -- -- /* patch-in the source of this message */ -- if (m->msg.src_id > 0 && m->msg.src_id != conn->id) { -- ret = -EINVAL; -- goto exit_free; -- } -- m->msg.src_id = conn->id; -- -- return m; -- --exit_free: -- kdbus_kmsg_free(m); -- return ERR_PTR(ret); --} -- --/** -- * kdbus_kmsg_collect_metadata() - collect metadata -- * @kmsg: message to collect metadata on -- * @src: source connection of message -- * @dst: destination connection of message -- * -- * Return: 0 on success, negative error code on failure. -- */ --int kdbus_kmsg_collect_metadata(const struct kdbus_kmsg *kmsg, -- struct kdbus_conn *src, struct kdbus_conn *dst) --{ -- u64 attach; -- int ret; -- -- attach = kdbus_meta_calc_attach_flags(src, dst); -- if (!src->meta_fake) { -- ret = kdbus_meta_proc_collect(kmsg->proc_meta, attach); -- if (ret < 0) -- return ret; -- } -- -- return kdbus_meta_conn_collect(kmsg->conn_meta, src, kmsg->seq, attach); --} -- - static struct kdbus_gaps *kdbus_gaps_new(size_t n_memfds, size_t n_fds) - { - size_t size_offsets, size_memfds, size_fds, size; -diff --git a/ipc/kdbus/message.h b/ipc/kdbus/message.h -index e0c4f2e324b3..298f9c99dfcf 100644 ---- a/ipc/kdbus/message.h -+++ b/ipc/kdbus/message.h -@@ -17,103 +17,6 @@ - #include <linux/fs.h> - #include <linux/kref.h> - #include <uapi/linux/kdbus.h> --#include "util.h" --#include "metadata.h" -- --/** -- * enum kdbus_msg_data_type - Type of kdbus_msg_data payloads -- * @KDBUS_MSG_DATA_VEC: Data vector provided by user-space -- * @KDBUS_MSG_DATA_MEMFD: Memfd payload -- */ --enum kdbus_msg_data_type { -- KDBUS_MSG_DATA_VEC, -- KDBUS_MSG_DATA_MEMFD, --}; -- --/** -- * struct kdbus_msg_data - Data payload as stored by messages -- * @type: Type of payload (KDBUS_MSG_DATA_*) -- * @size: Size of the described payload -- * @off: The offset, relative to the vec slice -- * @start: Offset inside the memfd -- * @file: Backing file referenced by the memfd -- */ --struct kdbus_msg_data { -- unsigned int type; -- u64 size; -- -- union { -- struct { -- u64 off; -- } vec; -- struct { -- u64 start; -- struct file *file; -- } memfd; -- }; --}; -- --/** -- * struct kdbus_kmsg_resources - resources of a message -- * @kref: Reference counter -- * @dst_name: Short-cut to msg for faster lookup -- * @fds: Array of file descriptors to pass -- * @fds_count: Number of file descriptors to pass -- * @data: Array of data payloads -- * @vec_count: Number of VEC entries -- * @memfd_count: Number of MEMFD entries in @data -- * @data_count: Sum of @vec_count + @memfd_count -- */ --struct kdbus_msg_resources { -- struct kref kref; -- const char *dst_name; -- -- struct file **fds; -- unsigned int fds_count; -- -- struct kdbus_msg_data *data; -- size_t vec_count; -- size_t memfd_count; -- size_t data_count; --}; -- --struct kdbus_msg_resources * --kdbus_msg_resources_ref(struct kdbus_msg_resources *r); --struct kdbus_msg_resources * --kdbus_msg_resources_unref(struct kdbus_msg_resources *r); -- --/** -- * struct kdbus_kmsg - internal message handling data -- * @seq: Domain-global message sequence number -- * @notify: Short-cut to notify-item for kernel notifications -- * @bloom_filter: Bloom filter to match message properties -- * @notify_entry: List of kernel-generated notifications -- * @iov: Array of iovec, describing the payload to copy -- * @iov_count: Number of array members in @iov -- * @pool_size: Overall size of inlined data referenced by @iov -- * @proc_meta: Appended SCM-like metadata of the sending process -- * @conn_meta: Appended SCM-like metadata of the sending connection -- * @res: Message resources -- * @msg: Message from or to userspace -- */ --struct kdbus_kmsg { -- u64 seq; -- struct kdbus_item *notify; -- -- const struct kdbus_bloom_filter *bloom_filter; -- struct list_head notify_entry; -- -- struct iovec *iov; -- size_t iov_count; -- u64 pool_size; -- -- struct kdbus_meta_proc *proc_meta; -- struct kdbus_meta_conn *conn_meta; -- struct kdbus_msg_resources *res; -- -- /* variable size, must be the last member */ -- struct kdbus_msg msg; --}; - - struct kdbus_bus; - struct kdbus_conn; -@@ -121,15 +24,6 @@ struct kdbus_meta_conn; - struct kdbus_meta_proc; - struct kdbus_pool_slice; - --struct kdbus_kmsg *kdbus_kmsg_new_kernel(struct kdbus_bus *bus, -- u64 dst, u64 cookie_timeout, -- size_t it_size, size_t it_type); --struct kdbus_kmsg *kdbus_kmsg_new_from_cmd(struct kdbus_conn *conn, -- struct kdbus_cmd_send *cmd_send); --void kdbus_kmsg_free(struct kdbus_kmsg *kmsg); --int kdbus_kmsg_collect_metadata(const struct kdbus_kmsg *kmsg, -- struct kdbus_conn *src, struct kdbus_conn *dst); -- - /** - * struct kdbus_gaps - gaps in message to be filled later - * @kref: Reference counter --- -2.4.3 - - -From 5b2ae5600065167040dd6d61466cce345568c68e Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Mon, 6 Jul 2015 11:29:05 +0200 -Subject: [PATCH 107/132] kdbus: allow senders to receive own broadcasts - -The dbus1 spec does not place a restriction on who can receive broadcasts. -As long as the sender has a MATCH-rule on itself, it can as well receive -its own broadcasts. - -As it turns out, user-space currently relies on this feature. So make sure -to allow this just like dbus1. If we find some client that does not work -with this, we will have to turn it into a HELLO-flag. Until then, just try -to adjust the default behavior. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> ---- - ipc/kdbus/bus.c | 2 -- - tools/testing/selftests/kdbus/test-message.c | 9 +++++--- - tools/testing/selftests/kdbus/test-policy-priv.c | 26 +++++++++++++++++++----- - 3 files changed, 27 insertions(+), 10 deletions(-) - -diff --git a/ipc/kdbus/bus.c b/ipc/kdbus/bus.c -index e7e17a7f7edd..a67f825bdeaf 100644 ---- a/ipc/kdbus/bus.c -+++ b/ipc/kdbus/bus.c -@@ -263,8 +263,6 @@ void kdbus_bus_broadcast(struct kdbus_bus *bus, - - down_read(&bus->conn_rwlock); - hash_for_each(bus->conn_hash, i, conn_dst, hentry) { -- if (conn_dst->id == staging->msg->src_id) -- continue; - if (!kdbus_conn_is_ordinary(conn_dst)) - continue; - -diff --git a/tools/testing/selftests/kdbus/test-message.c b/tools/testing/selftests/kdbus/test-message.c -index f1615dafb7f1..ddc1e0af877b 100644 ---- a/tools/testing/selftests/kdbus/test-message.c -+++ b/tools/testing/selftests/kdbus/test-message.c -@@ -54,9 +54,12 @@ int kdbus_test_message_basic(struct kdbus_test_env *env) - KDBUS_DST_ID_BROADCAST); - ASSERT_RETURN(ret == 0); - -- /* Make sure that we do not get our own broadcasts */ -- ret = kdbus_msg_recv(sender, NULL, NULL); -- ASSERT_RETURN(ret == -EAGAIN); -+ /* Make sure that we do get our own broadcasts */ -+ ret = kdbus_msg_recv(sender, &msg, &offset); -+ ASSERT_RETURN(ret == 0); -+ ASSERT_RETURN(msg->cookie == cookie); -+ -+ kdbus_msg_free(msg); - - /* ... and receive on the 2nd */ - ret = kdbus_msg_recv_poll(conn, 100, &msg, &offset); -diff --git a/tools/testing/selftests/kdbus/test-policy-priv.c b/tools/testing/selftests/kdbus/test-policy-priv.c -index a318cccad0d5..0208638a7245 100644 ---- a/tools/testing/selftests/kdbus/test-policy-priv.c -+++ b/tools/testing/selftests/kdbus/test-policy-priv.c -@@ -110,6 +110,12 @@ static int test_policy_priv_by_broadcast(const char *bus, - KDBUS_DST_ID_BROADCAST); - ASSERT_RETURN(ret == 0); - -+ /* drop own broadcast */ -+ ret = kdbus_msg_recv(child_2, &msg, NULL); -+ ASSERT_RETURN(ret == 0); -+ ASSERT_RETURN(msg->src_id == child_2->id); -+ kdbus_msg_free(msg); -+ - /* Use a little bit high time */ - ret = kdbus_msg_recv_poll(child_2, 1000, - &msg, NULL); -@@ -145,6 +151,12 @@ static int test_policy_priv_by_broadcast(const char *bus, - KDBUS_DST_ID_BROADCAST); - ASSERT_EXIT(ret == 0); - -+ /* drop own broadcast */ -+ ret = kdbus_msg_recv(child_2, &msg, NULL); -+ ASSERT_RETURN(ret == 0); -+ ASSERT_RETURN(msg->src_id == child_2->id); -+ kdbus_msg_free(msg); -+ - /* Use a little bit high time */ - ret = kdbus_msg_recv_poll(child_2, 1000, - &msg, NULL); -@@ -313,11 +325,6 @@ static int test_broadcast_after_policy_upload(struct kdbus_test_env *env) - * receiver is not able to TALK to that name. - */ - -- ret = test_policy_priv_by_broadcast(env->buspath, owner_a, -- DO_NOT_DROP, -- -ETIMEDOUT, -ETIMEDOUT); -- ASSERT_RETURN(ret == 0); -- - /* Activate matching for a privileged connection */ - ret = kdbus_add_match_empty(owner_a); - ASSERT_RETURN(ret == 0); -@@ -408,6 +415,15 @@ static int test_broadcast_after_policy_upload(struct kdbus_test_env *env) - 0, 0, KDBUS_DST_ID_BROADCAST); - ASSERT_RETURN(ret == 0); - -+ ret = kdbus_msg_recv_poll(owner_a, 100, &msg, NULL); -+ ASSERT_RETURN(ret == 0); -+ ASSERT_RETURN(msg->cookie == expected_cookie); -+ -+ /* Check src ID */ -+ ASSERT_RETURN(msg->src_id == owner_a->id); -+ -+ kdbus_msg_free(msg); -+ - ret = kdbus_msg_recv_poll(owner_b, 100, &msg, NULL); - ASSERT_RETURN(ret == 0); - ASSERT_RETURN(msg->cookie == expected_cookie); --- -2.4.3 - - -From ebca68e897b944559d77d7165bf3d1b173257e72 Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Sat, 4 Jul 2015 19:41:28 +0200 -Subject: [PATCH 108/132] kdbus: pass metadata which a receiver could read via - /proc - -Current kdbus behavior is to only pass metadata to a receiver if the -sender actively agreed on sending the metadata (via send-attach-flags). -We now extend this logic in 2 ways: - - - Implicit metadata is always sent, if requested by the receiver. This - includes basic process credentials, pids and connection metadata. The - latter is kdbus-specific information and always public (as it can be - retrieved via other means), and basic process credentials and pids are - required for compatibility to UDS. - - - Any extended process credentials were only passed if told by the - sender. We now extend this logic to pass them also if the receiver - could have read that information via /proc. We verify that the sending - process has a pid in the pid-namespace of the receiver (i.e., it shows - up in /proc mounted in the receiver namespace) and verify the hide_pid - restrictions. - -With this change, we make kdbus in-line with /proc access checks. We -basically say that we assume anyone with access to kdbusfs also has access -to /proc of its *own* pid-namespace (which should be given in any system -setup). We then automatically pass all information *as if* the receiver -would read them immediately on message-retrieval via /proc. But kdbus now -fixes the race-gap between message transmittal and /proc access. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> ---- - ipc/kdbus/connection.c | 2 + - ipc/kdbus/connection.h | 2 + - ipc/kdbus/message.c | 2 +- - ipc/kdbus/metadata.c | 189 ++++++++++++++++++++++++++++++++++++++++++++++--- - ipc/kdbus/metadata.h | 5 +- - 5 files changed, 187 insertions(+), 13 deletions(-) - -diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c -index 2b334b04dd9d..461b8d66b2b9 100644 ---- a/ipc/kdbus/connection.c -+++ b/ipc/kdbus/connection.c -@@ -132,6 +132,7 @@ static struct kdbus_conn *kdbus_conn_new(struct kdbus_ep *ep, bool privileged, - conn->cred = get_current_cred(); - conn->user_ns = get_user_ns(current_user_ns()); - conn->pid_ns = get_pid_ns(task_active_pid_ns(current)); -+ conn->pid = get_pid(task_pid(current)); - get_fs_root(current->fs, &conn->root_path); - init_waitqueue_head(&conn->wait); - kdbus_queue_init(&conn->queue); -@@ -282,6 +283,7 @@ static void __kdbus_conn_free(struct kref *kref) - kdbus_pool_free(conn->pool); - kdbus_ep_unref(conn->ep); - path_put(&conn->root_path); -+ put_pid(conn->pid); - put_pid_ns(conn->pid_ns); - put_user_ns(conn->user_ns); - put_cred(conn->cred); -diff --git a/ipc/kdbus/connection.h b/ipc/kdbus/connection.h -index b1769b877504..9a1b13d69085 100644 ---- a/ipc/kdbus/connection.h -+++ b/ipc/kdbus/connection.h -@@ -61,6 +61,7 @@ struct kdbus_staging; - * @cred: The credentials of the connection at creation time - * @user_ns: User namespace at creation time - * @pid_ns: Pid namespace at creation time -+ * @pid: Pid at creation time - * @root_path: Root path at creation time - * @name_count: Number of owned well-known names - * @request_count: Number of pending requests issued by this -@@ -102,6 +103,7 @@ struct kdbus_conn { - const struct cred *cred; - struct user_namespace *user_ns; - struct pid_namespace *pid_ns; -+ struct pid *pid; - struct path root_path; - atomic_t name_count; - atomic_t request_count; -diff --git a/ipc/kdbus/message.c b/ipc/kdbus/message.c -index 72fb5908c927..64763ead693c 100644 ---- a/ipc/kdbus/message.c -+++ b/ipc/kdbus/message.c -@@ -849,7 +849,7 @@ static int kdbus_staging_collect_metadata(struct kdbus_staging *staging, - int ret; - - if (src) -- attach = kdbus_meta_calc_attach_flags(src, dst); -+ attach = kdbus_meta_msg_mask(src, dst); - else - attach = KDBUS_ATTACH_TIMESTAMP; /* metadata for kernel msgs */ - -diff --git a/ipc/kdbus/metadata.c b/ipc/kdbus/metadata.c -index 43e5f4564925..5150932cb257 100644 ---- a/ipc/kdbus/metadata.c -+++ b/ipc/kdbus/metadata.c -@@ -1156,18 +1156,187 @@ exit: - return ret; - } - -+enum { -+ KDBUS_META_PROC_NONE, -+ KDBUS_META_PROC_NORMAL, -+}; -+ -+/** -+ * kdbus_proc_permission() - check /proc permissions on target pid -+ * @pid_ns: namespace we operate in -+ * @cred: credentials of requestor -+ * @target: target process -+ * -+ * This checks whether a process with credentials @cred can access information -+ * of @target in the namespace @pid_ns. This tries to follow /proc permissions, -+ * but is slightly more restrictive. -+ * -+ * Return: The /proc access level (KDBUS_META_PROC_*) is returned. -+ */ -+static unsigned int kdbus_proc_permission(const struct pid_namespace *pid_ns, -+ const struct cred *cred, -+ struct pid *target) -+{ -+ if (pid_ns->hide_pid < 1) -+ return KDBUS_META_PROC_NORMAL; -+ -+ /* XXX: we need groups_search() exported for aux-groups */ -+ if (gid_eq(cred->egid, pid_ns->pid_gid)) -+ return KDBUS_META_PROC_NORMAL; -+ -+ /* -+ * XXX: If ptrace_may_access(PTRACE_MODE_READ) is granted, you can -+ * overwrite hide_pid. However, ptrace_may_access() only supports -+ * checking 'current', hence, we cannot use this here. But we -+ * simply decide to not support this override, so no need to worry. -+ */ -+ -+ return KDBUS_META_PROC_NONE; -+} -+ -+/** -+ * kdbus_meta_proc_mask() - calculate which metadata would be visible to -+ * a connection via /proc -+ * @prv_pid: pid of metadata provider -+ * @req_pid: pid of metadata requestor -+ * @req_cred: credentials of metadata reqeuestor -+ * @wanted: metadata that is requested -+ * -+ * This checks which metadata items of @prv_pid can be read via /proc by the -+ * requestor @req_pid. -+ * -+ * Return: Set of metadata flags the requestor can see (limited by @wanted). -+ */ -+static u64 kdbus_meta_proc_mask(struct pid *prv_pid, -+ struct pid *req_pid, -+ const struct cred *req_cred, -+ u64 wanted) -+{ -+ struct pid_namespace *prv_ns, *req_ns; -+ unsigned int proc; -+ -+ prv_ns = ns_of_pid(prv_pid); -+ req_ns = ns_of_pid(req_pid); -+ -+ /* -+ * If the sender is not visible in the receiver namespace, then the -+ * receiver cannot access the sender via its own procfs. Hence, we do -+ * not attach any additional metadata. -+ */ -+ if (!pid_nr_ns(prv_pid, req_ns)) -+ return 0; -+ -+ /* -+ * If the pid-namespace of the receiver has hide_pid set, it cannot see -+ * any process but its own. We shortcut this /proc permission check if -+ * provider and requestor are the same. If not, we perform rather -+ * expensive /proc permission checks. -+ */ -+ if (prv_pid == req_pid) -+ proc = KDBUS_META_PROC_NORMAL; -+ else -+ proc = kdbus_proc_permission(req_ns, req_cred, prv_pid); -+ -+ /* you need /proc access to read standard process attributes */ -+ if (proc < KDBUS_META_PROC_NORMAL) -+ wanted &= ~(KDBUS_ATTACH_TID_COMM | -+ KDBUS_ATTACH_PID_COMM | -+ KDBUS_ATTACH_SECLABEL | -+ KDBUS_ATTACH_CMDLINE | -+ KDBUS_ATTACH_CGROUP | -+ KDBUS_ATTACH_AUDIT | -+ KDBUS_ATTACH_CAPS | -+ KDBUS_ATTACH_EXE); -+ -+ /* clear all non-/proc flags */ -+ return wanted & (KDBUS_ATTACH_TID_COMM | -+ KDBUS_ATTACH_PID_COMM | -+ KDBUS_ATTACH_SECLABEL | -+ KDBUS_ATTACH_CMDLINE | -+ KDBUS_ATTACH_CGROUP | -+ KDBUS_ATTACH_AUDIT | -+ KDBUS_ATTACH_CAPS | -+ KDBUS_ATTACH_EXE); -+} -+ - /** -- * kdbus_meta_calc_attach_flags() - calculate attach flags for a sender -- * and a receiver -- * @sender: Sending connection -- * @receiver: Receiving connection -+ * kdbus_meta_get_mask() - calculate attach flags mask for metadata request -+ * @prv_pid: pid of metadata provider -+ * @prv_mask: mask of metadata the provide grants unchecked -+ * @req_pid: pid of metadata requestor -+ * @req_cred: credentials of metadata requestor -+ * @req_mask: mask of metadata that is requested - * -- * Return: the attach flags both the sender and the receiver have opted-in -- * for. -+ * This calculates the metadata items that the requestor @req_pid can access -+ * from the metadata provider @prv_pid. This permission check consists of -+ * several different parts: -+ * - Providers can grant metadata items unchecked. Regardless of their type, -+ * they're always granted to the requestor. This mask is passed as @prv_mask. -+ * - Basic items (credentials and connection metadata) are granted implicitly -+ * to everyone. They're publicly available to any bus-user that can see the -+ * provider. -+ * - Process credentials that are not granted implicitly follow the same -+ * permission checks as /proc. This means, we always assume a requestor -+ * process has access to their *own* /proc mount, if they have access to -+ * kdbusfs. -+ * -+ * Return: Mask of metadata that is granted. -+ */ -+static u64 kdbus_meta_get_mask(struct pid *prv_pid, u64 prv_mask, -+ struct pid *req_pid, -+ const struct cred *req_cred, u64 req_mask) -+{ -+ u64 missing, impl_mask, proc_mask = 0; -+ -+ /* -+ * Connection metadata and basic unix process credentials are -+ * transmitted implicitly, and cannot be suppressed. Both are required -+ * to perform user-space policies on the receiver-side. Furthermore, -+ * connection metadata is public state, anyway, and unix credentials -+ * are needed for UDS-compatibility. We extend them slightly by -+ * auxiliary groups and additional uids/gids/pids. -+ */ -+ impl_mask = /* connection metadata */ -+ KDBUS_ATTACH_CONN_DESCRIPTION | -+ KDBUS_ATTACH_TIMESTAMP | -+ KDBUS_ATTACH_NAMES | -+ /* credentials and pids */ -+ KDBUS_ATTACH_AUXGROUPS | -+ KDBUS_ATTACH_CREDS | -+ KDBUS_ATTACH_PIDS; -+ -+ /* -+ * Calculate the set of metadata that is not granted implicitly nor by -+ * the sender, but still requested by the receiver. If any are left, -+ * perform rather expensive /proc access checks for them. -+ */ -+ missing = req_mask & ~((prv_mask | impl_mask) & req_mask); -+ if (missing) -+ proc_mask = kdbus_meta_proc_mask(prv_pid, req_pid, req_cred, -+ missing); -+ -+ return (prv_mask | impl_mask | proc_mask) & req_mask; -+} -+ -+/** -+ */ -+u64 kdbus_meta_info_mask(const struct kdbus_conn *conn, u64 mask) -+{ -+ return kdbus_meta_get_mask(conn->pid, -+ atomic64_read(&conn->attach_flags_send), -+ task_pid(current), -+ current_cred(), -+ mask); -+} -+ -+/** - */ --u64 kdbus_meta_calc_attach_flags(const struct kdbus_conn *sender, -- const struct kdbus_conn *receiver) -+u64 kdbus_meta_msg_mask(const struct kdbus_conn *snd, -+ const struct kdbus_conn *rcv) - { -- return atomic64_read(&sender->attach_flags_send) & -- atomic64_read(&receiver->attach_flags_recv); -+ return kdbus_meta_get_mask(task_pid(current), -+ atomic64_read(&snd->attach_flags_send), -+ rcv->pid, -+ rcv->cred, -+ atomic64_read(&rcv->attach_flags_recv)); - } -diff --git a/ipc/kdbus/metadata.h b/ipc/kdbus/metadata.h -index 8fb2a9f7f82e..dba7cc7fdbcb 100644 ---- a/ipc/kdbus/metadata.h -+++ b/ipc/kdbus/metadata.h -@@ -79,7 +79,8 @@ int kdbus_meta_emit(struct kdbus_meta_proc *mp, - u64 mask, - struct kdbus_item **out_items, - size_t *out_size); --u64 kdbus_meta_calc_attach_flags(const struct kdbus_conn *sender, -- const struct kdbus_conn *receiver); -+u64 kdbus_meta_info_mask(const struct kdbus_conn *conn, u64 mask); -+u64 kdbus_meta_msg_mask(const struct kdbus_conn *snd, -+ const struct kdbus_conn *rcv); - - #endif --- -2.4.3 - - -From 087d17ac489a3c8f7c35bb5faf4c1bc858fc0978 Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Mon, 6 Jul 2015 16:52:44 +0200 -Subject: [PATCH 109/132] kdbus: drop redundant ns pointers - -We already pin 'cred' and 'pid', so they provide the same information as -we store in 'user_ns' and 'pid_ns'. Drop the redundant information to -reduce memory consumption of kdbus_conn. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> ---- - ipc/kdbus/connection.c | 4 ---- - ipc/kdbus/connection.h | 4 ---- - ipc/kdbus/metadata.c | 4 ++-- - 3 files changed, 2 insertions(+), 10 deletions(-) - -diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c -index 461b8d66b2b9..d94b417e0f32 100644 ---- a/ipc/kdbus/connection.c -+++ b/ipc/kdbus/connection.c -@@ -130,8 +130,6 @@ static struct kdbus_conn *kdbus_conn_new(struct kdbus_ep *ep, bool privileged, - atomic_set(&conn->lost_count, 0); - INIT_DELAYED_WORK(&conn->work, kdbus_reply_list_scan_work); - conn->cred = get_current_cred(); -- conn->user_ns = get_user_ns(current_user_ns()); -- conn->pid_ns = get_pid_ns(task_active_pid_ns(current)); - conn->pid = get_pid(task_pid(current)); - get_fs_root(current->fs, &conn->root_path); - init_waitqueue_head(&conn->wait); -@@ -284,8 +282,6 @@ static void __kdbus_conn_free(struct kref *kref) - kdbus_ep_unref(conn->ep); - path_put(&conn->root_path); - put_pid(conn->pid); -- put_pid_ns(conn->pid_ns); -- put_user_ns(conn->user_ns); - put_cred(conn->cred); - kfree(conn->description); - kfree(conn->quota); -diff --git a/ipc/kdbus/connection.h b/ipc/kdbus/connection.h -index 9a1b13d69085..5ee864eb0e41 100644 ---- a/ipc/kdbus/connection.h -+++ b/ipc/kdbus/connection.h -@@ -59,8 +59,6 @@ struct kdbus_staging; - * @pool: The user's buffer to receive messages - * @user: Owner of the connection - * @cred: The credentials of the connection at creation time -- * @user_ns: User namespace at creation time -- * @pid_ns: Pid namespace at creation time - * @pid: Pid at creation time - * @root_path: Root path at creation time - * @name_count: Number of owned well-known names -@@ -101,8 +99,6 @@ struct kdbus_conn { - struct kdbus_pool *pool; - struct kdbus_user *user; - const struct cred *cred; -- struct user_namespace *user_ns; -- struct pid_namespace *pid_ns; - struct pid *pid; - struct path root_path; - atomic_t name_count; -diff --git a/ipc/kdbus/metadata.c b/ipc/kdbus/metadata.c -index 5150932cb257..d4973a90a81e 100644 ---- a/ipc/kdbus/metadata.c -+++ b/ipc/kdbus/metadata.c -@@ -896,8 +896,8 @@ static struct kdbus_item *kdbus_write_full(struct kdbus_item **iter, - static size_t kdbus_meta_write(struct kdbus_meta_staging *staging, void *mem, - size_t size) - { -- struct user_namespace *user_ns = staging->conn->user_ns; -- struct pid_namespace *pid_ns = staging->conn->pid_ns; -+ struct user_namespace *user_ns = staging->conn->cred->user_ns; -+ struct pid_namespace *pid_ns = ns_of_pid(staging->conn->pid); - struct kdbus_item *item = NULL, *items = mem; - u8 *end, *owned_names_end = NULL; - --- -2.4.3 - - -From c61382ef278eb8569c87e4be3077f3f9f1f2fc49 Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Mon, 6 Jul 2015 16:54:36 +0200 -Subject: [PATCH 110/132] kdbus: allow match rules on msg->dst_id - -This patch extends kdbus MATCH rules to allow matching on the destination -of a message. We add a KDBUS_ITEM_DST_ID type which takes a u64 and -matches on msg->dst_id. - -This is required for dbus1 compatibility, as dbus1 does not apply MATCH -rules to unicast signals. Therefore, this field allows to match on -unicasts directed to the owning connection. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> ---- - include/uapi/linux/kdbus.h | 1 + - ipc/kdbus/item.c | 1 + - ipc/kdbus/match.c | 18 +++++++++++++++--- - 3 files changed, 17 insertions(+), 3 deletions(-) - -diff --git a/include/uapi/linux/kdbus.h b/include/uapi/linux/kdbus.h -index 00a6e142c977..ecffc6b13c3e 100644 ---- a/include/uapi/linux/kdbus.h -+++ b/include/uapi/linux/kdbus.h -@@ -374,6 +374,7 @@ enum kdbus_item_type { - KDBUS_ITEM_ATTACH_FLAGS_RECV, - KDBUS_ITEM_ID, - KDBUS_ITEM_NAME, -+ KDBUS_ITEM_DST_ID, - - /* keep these item types in sync with KDBUS_ATTACH_* flags */ - _KDBUS_ITEM_ATTACH_BASE = 0x1000, -diff --git a/ipc/kdbus/item.c b/ipc/kdbus/item.c -index e763083cc16c..ce78dba03426 100644 ---- a/ipc/kdbus/item.c -+++ b/ipc/kdbus/item.c -@@ -147,6 +147,7 @@ int kdbus_item_validate(const struct kdbus_item *item) - case KDBUS_ITEM_ATTACH_FLAGS_SEND: - case KDBUS_ITEM_ATTACH_FLAGS_RECV: - case KDBUS_ITEM_ID: -+ case KDBUS_ITEM_DST_ID: - if (payload_size != sizeof(u64)) - return -EINVAL; - break; -diff --git a/ipc/kdbus/match.c b/ipc/kdbus/match.c -index 3ae224ff9f3f..d1b300769014 100644 ---- a/ipc/kdbus/match.c -+++ b/ipc/kdbus/match.c -@@ -78,6 +78,7 @@ struct kdbus_bloom_mask { - * KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE}, - * KDBUS_ITEM_ID_REMOVE - * @src_id: ID to match against, used with KDBUS_ITEM_ID -+ * @dst_id: Message destination ID, used with KDBUS_ITEM_DST_ID - * @rules_entry: Entry in the entry's rules list - */ - struct kdbus_match_rule { -@@ -90,6 +91,7 @@ struct kdbus_match_rule { - u64 new_id; - }; - u64 src_id; -+ u64 dst_id; - }; - struct list_head rules_entry; - }; -@@ -112,6 +114,7 @@ static void kdbus_match_rule_free(struct kdbus_match_rule *rule) - break; - - case KDBUS_ITEM_ID: -+ case KDBUS_ITEM_DST_ID: - case KDBUS_ITEM_ID_ADD: - case KDBUS_ITEM_ID_REMOVE: - break; -@@ -215,6 +218,9 @@ static bool kdbus_match_rule_conn(const struct kdbus_match_rule *r, - return kdbus_match_bloom(s->bloom_filter, &r->bloom_mask, c); - case KDBUS_ITEM_ID: - return r->src_id == c->id || r->src_id == KDBUS_MATCH_ID_ANY; -+ case KDBUS_ITEM_DST_ID: -+ return r->dst_id == s->msg->dst_id || -+ r->dst_id == KDBUS_MATCH_ID_ANY; - case KDBUS_ITEM_NAME: - return kdbus_conn_has_name(c, r->name); - default: -@@ -328,6 +334,7 @@ static int kdbus_match_db_remove_unlocked(struct kdbus_match_db *mdb, - * KDBUS_ITEM_BLOOM_MASK: A bloom mask - * KDBUS_ITEM_NAME: A connection's source name - * KDBUS_ITEM_ID: A connection ID -+ * KDBUS_ITEM_DST_ID: A connection ID - * KDBUS_ITEM_NAME_ADD: - * KDBUS_ITEM_NAME_REMOVE: - * KDBUS_ITEM_NAME_CHANGE: Well-known name changes, carry -@@ -339,9 +346,9 @@ static int kdbus_match_db_remove_unlocked(struct kdbus_match_db *mdb, - * For kdbus_notify_{id,name}_change structs, only the ID and name fields - * are looked 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. -+ * Also note that KDBUS_ITEM_BLOOM_MASK, KDBUS_ITEM_NAME, KDBUS_ITEM_ID, -+ * and KDBUS_ITEM_DST_ID are used to match messages from userspace, while the -+ * others apply to kernel-generated notifications. - * - * Return: >=0 on success, negative error code on failure. - */ -@@ -358,6 +365,7 @@ int kdbus_cmd_match_add(struct kdbus_conn *conn, void __user *argp) - { .type = KDBUS_ITEM_BLOOM_MASK, .multiple = true }, - { .type = KDBUS_ITEM_NAME, .multiple = true }, - { .type = KDBUS_ITEM_ID, .multiple = true }, -+ { .type = KDBUS_ITEM_DST_ID, .multiple = true }, - { .type = KDBUS_ITEM_NAME_ADD, .multiple = true }, - { .type = KDBUS_ITEM_NAME_REMOVE, .multiple = true }, - { .type = KDBUS_ITEM_NAME_CHANGE, .multiple = true }, -@@ -440,6 +448,10 @@ int kdbus_cmd_match_add(struct kdbus_conn *conn, void __user *argp) - rule->src_id = item->id; - break; - -+ case KDBUS_ITEM_DST_ID: -+ rule->dst_id = item->id; -+ break; -+ - case KDBUS_ITEM_NAME_ADD: - case KDBUS_ITEM_NAME_REMOVE: - case KDBUS_ITEM_NAME_CHANGE: --- -2.4.3 - - -From cf23304185c5787d875971cc730e29637d3f4d7e Mon Sep 17 00:00:00 2001 -From: Masanari Iida <standby24x7@gmail.com> -Date: Fri, 10 Jul 2015 21:55:33 +0900 -Subject: [PATCH 111/132] kdbus: Fix typo in ipc/kdbus - -This patch fix spelling typos found in ipc/kdbus - -Signed-off-by: Masanari Iida <standby24x7@gmail.com> -Reviewed-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - ipc/kdbus/endpoint.c | 2 +- - ipc/kdbus/endpoint.h | 4 ++-- - ipc/kdbus/fs.c | 2 +- - ipc/kdbus/match.c | 2 +- - ipc/kdbus/node.c | 4 ++-- - ipc/kdbus/policy.c | 2 +- - ipc/kdbus/pool.c | 2 +- - 7 files changed, 9 insertions(+), 9 deletions(-) - -diff --git a/ipc/kdbus/endpoint.c b/ipc/kdbus/endpoint.c -index 9a95a5ea84d7..977964dbb44a 100644 ---- a/ipc/kdbus/endpoint.c -+++ b/ipc/kdbus/endpoint.c -@@ -78,7 +78,7 @@ static void kdbus_ep_release(struct kdbus_node *node, bool was_active) - * @gid: The gid of the node - * @is_custom: Whether this is a custom endpoint - * -- * This function will create a new enpoint with the given -+ * This function will create a new endpoint with the given - * name and properties for a given bus. - * - * Return: a new kdbus_ep on success, ERR_PTR on failure. -diff --git a/ipc/kdbus/endpoint.h b/ipc/kdbus/endpoint.h -index d31954bfba2c..bc1b94a70f93 100644 ---- a/ipc/kdbus/endpoint.h -+++ b/ipc/kdbus/endpoint.h -@@ -25,7 +25,7 @@ struct kdbus_bus; - struct kdbus_user; - - /** -- * struct kdbus_ep - enpoint to access a bus -+ * struct kdbus_ep - endpoint to access a bus - * @node: The kdbus node - * @lock: Endpoint data lock - * @bus: Bus behind this endpoint -@@ -33,7 +33,7 @@ struct kdbus_user; - * @policy_db: Uploaded policy - * @conn_list: Connections of this endpoint - * -- * An enpoint offers access to a bus; the default endpoint node name is "bus". -+ * An endpoint offers access to a bus; the default endpoint node name is "bus". - * Additional custom endpoints to the same bus can be created and they can - * carry their own policies/filters. - */ -diff --git a/ipc/kdbus/fs.c b/ipc/kdbus/fs.c -index 205a3adaa2ab..09c480924b9e 100644 ---- a/ipc/kdbus/fs.c -+++ b/ipc/kdbus/fs.c -@@ -74,7 +74,7 @@ static int fs_dir_fop_iterate(struct file *file, struct dir_context *ctx) - * closest node to that position and cannot use our node pointer. This - * means iterating the rb-tree to find the closest match and start over - * from there. -- * Note that hash values are not neccessarily unique. Therefore, llseek -+ * Note that hash values are not necessarily unique. Therefore, llseek - * is not guaranteed to seek to the same node that you got when you - * retrieved the position. Seeking to 0, 1, 2 and >=INT_MAX is safe, - * though. We could use the inode-number as position, but this would -diff --git a/ipc/kdbus/match.c b/ipc/kdbus/match.c -index d1b300769014..4ee6a1f2e1bc 100644 ---- a/ipc/kdbus/match.c -+++ b/ipc/kdbus/match.c -@@ -66,7 +66,7 @@ struct kdbus_bloom_mask { - - /** - * struct kdbus_match_rule - a rule appended to a match entry -- * @type: An item type to match agains -+ * @type: An item type to match against - * @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, -diff --git a/ipc/kdbus/node.c b/ipc/kdbus/node.c -index 0d65c65d2bde..89f58bc85433 100644 ---- a/ipc/kdbus/node.c -+++ b/ipc/kdbus/node.c -@@ -120,7 +120,7 @@ - * new active references can be acquired. - * Once all active references are dropped, the node is considered 'drained'. Now - * kdbus_node_deactivate() is called on each child of the node before we -- * continue deactvating our node. That is, once all children are entirely -+ * continue deactivating our node. That is, once all children are entirely - * deactivated, we call ->release_cb() of our node. ->release_cb() can release - * any resources on that node which are bound to the "active" state of a node. - * When done, we unlink the node from its parent rb-tree, mark it as -@@ -637,7 +637,7 @@ void kdbus_node_deactivate(struct kdbus_node *node) - kdbus_fs_flush(pos); - - /* -- * If the node was activated and somone subtracted BIAS -+ * If the node was activated and someone subtracted BIAS - * from it to deactivate it, we, and only us, are - * responsible to release the extra ref-count that was - * taken once in kdbus_node_activate(). -diff --git a/ipc/kdbus/policy.c b/ipc/kdbus/policy.c -index dd7fffaafa84..f2618e15e78d 100644 ---- a/ipc/kdbus/policy.c -+++ b/ipc/kdbus/policy.c -@@ -344,7 +344,7 @@ err: - * In order to allow atomic replacement of rules, the function first removes - * all entries that have been created for the given owner previously. - * -- * Callers to this function must make sur that the owner is a custom -+ * Callers to this function must make sure that the owner is a custom - * endpoint, or if the endpoint is a default endpoint, then it must be - * either a policy holder or an activator. - * -diff --git a/ipc/kdbus/pool.c b/ipc/kdbus/pool.c -index 45dcdea505f4..63ccd55713c7 100644 ---- a/ipc/kdbus/pool.c -+++ b/ipc/kdbus/pool.c -@@ -44,7 +44,7 @@ - * The receiver's buffer, managed as a pool of allocated and free - * slices containing the queued messages. - * -- * Messages sent with KDBUS_CMD_SEND are copied direcly by the -+ * Messages sent with KDBUS_CMD_SEND are copied directly by the - * sending process into the receiver's pool. - * - * Messages received with KDBUS_CMD_RECV just return the offset --- -2.4.3 - - -From eee8b5b3ceaeca1b1b998552cd6c9f9dea8938e5 Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Tue, 14 Jul 2015 20:12:28 +0200 -Subject: [PATCH 112/132] kdbus: properly reset metadata iovecs on multicasts - -If a message is sent to multiple destinations, each destination might -request a different set of metadata. Hence, we cannot rely on each one -requesting at least a single bit. - -Fix the message exporter to properly reset the metadata iovec on each -emit-iteration. Otherwise, we might end up scanning random heap memory if -a following destination does not request metadata. - -Reported-by: Jan Alexander Steffens <jan.steffens@gmail.com> -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - ipc/kdbus/message.c | 10 ++++++++++ - 1 file changed, 10 insertions(+) - -diff --git a/ipc/kdbus/message.c b/ipc/kdbus/message.c -index 64763ead693c..3520f45875df 100644 ---- a/ipc/kdbus/message.c -+++ b/ipc/kdbus/message.c -@@ -946,6 +946,16 @@ struct kdbus_pool_slice *kdbus_staging_emit(struct kdbus_staging *staging, - ++v; - - msg_size = KDBUS_ALIGN8(msg_size) + meta_size; -+ } else { -+ /* metadata items */ -+ v->iov_len = 0; -+ v->iov_base = (void __user *)zeros; -+ ++v; -+ -+ /* padding after metadata */ -+ v->iov_len = 0; -+ v->iov_base = (void __user *)zeros; -+ ++v; - } - - /* ... payload iovecs are already filled in ... */ --- -2.4.3 - - -From 748cf9547ea30f5a4dfee5e97d1d2ff4b307c392 Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Thu, 16 Jul 2015 17:37:29 +0200 -Subject: [PATCH 113/132] kdbus: fix unused %docs make-targets - -The top-level Makefile re-routes all %docs targets to the Documentation -makefiles. The DocBook makefile supports a lot more targets than the kdbus -makefile, and it seems unreasonable to expect that both will always be in -sync. - -Therefore, add a fallback no-op target %docs: which is used for all -unspecified %docs targets. - -We will, from time to time, add further %docs targets that make sense -(like installdocs). But there is definitely no time pressure on those. -However, we really should add this fallback now, as otherwise "make" will -print errors due to unknown targets. - -Reported-by: Ulf Magnusson <ulfalizer.lkml@gmail.com> -Tested-by: Jim Davis <jim.epost@gmail.com> -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - Documentation/kdbus/Makefile | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/Documentation/kdbus/Makefile b/Documentation/kdbus/Makefile -index af87641db416..8caffe565750 100644 ---- a/Documentation/kdbus/Makefile -+++ b/Documentation/kdbus/Makefile -@@ -38,3 +38,7 @@ mandocs: $(MANFILES) - htmldocs: $(HTMLFILES) - - clean-files := $(MANFILES) $(HTMLFILES) -+ -+# we don't support other %docs targets right now -+%docs: -+ @true --- -2.4.3 - - -From 52e895942ba065db563de042a4fff21fb38b26e6 Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Fri, 24 Jul 2015 12:57:20 +0200 -Subject: [PATCH 114/132] kdbus: fix sparse address-space annotation - -Make sure to properly annotate casts in 'struct iovec' if we cross -address-spaces, to make sure sparse does not warn about them. - -All those conversions are fine, as we are allowed to pass those kvecs -through the iovec importer. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - ipc/kdbus/message.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/ipc/kdbus/message.c b/ipc/kdbus/message.c -index 3520f45875df..27a5021fe70f 100644 ---- a/ipc/kdbus/message.c -+++ b/ipc/kdbus/message.c -@@ -920,7 +920,7 @@ struct kdbus_pool_slice *kdbus_staging_emit(struct kdbus_staging *staging, - - /* msg.size */ - v->iov_len = sizeof(msg_size); -- v->iov_base = &msg_size; -+ v->iov_base = (void __user *)&msg_size; - ++v; - - /* msg (after msg.size) plus items */ -@@ -937,7 +937,7 @@ struct kdbus_pool_slice *kdbus_staging_emit(struct kdbus_staging *staging, - if (meta_size > 0) { - /* metadata items */ - v->iov_len = meta_size; -- v->iov_base = meta_items; -+ v->iov_base = (void __user *)meta_items; - ++v; - - /* padding after metadata */ --- -2.4.3 - - -From 63c8e2f6f33766723d35a13be094a4e475e6d46d Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Fri, 24 Jul 2015 12:32:09 +0200 -Subject: [PATCH 115/132] kdbus: fix wrong message size on 32bit - -When broadcasting messages, each receiver might get a different message -due to different metadata requirements. Therefore, the value of msg->size -might be different for each receiver. To account for that, we use a -temporary variable to store the real size and use it as source for the -iovec-copy transaction instead of &msg->size. - -But we incorrectly used "size_t" for this variable. Hence, on 32bit, we -end up missing 4 bytes of the message header as "size_t" might only be -32bit wide. - -Fix this and properly use "u64" for the message size that is copied to -user-space. - -Reported-by: Alban Browaeys <prahal@yahoo.com> -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - ipc/kdbus/message.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/ipc/kdbus/message.c b/ipc/kdbus/message.c -index 27a5021fe70f..432dba4dcfdc 100644 ---- a/ipc/kdbus/message.c -+++ b/ipc/kdbus/message.c -@@ -886,9 +886,9 @@ struct kdbus_pool_slice *kdbus_staging_emit(struct kdbus_staging *staging, - { - struct kdbus_item *item, *meta_items = NULL; - struct kdbus_pool_slice *slice = NULL; -- size_t off, size, msg_size, meta_size; -+ size_t off, size, meta_size; - struct iovec *v; -- u64 attach; -+ u64 attach, msg_size; - int ret; - - /* --- -2.4.3 - - -From 12000cd279ab5502006441c406ceba5bde44be71 Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Thu, 6 Aug 2015 10:21:20 +0200 -Subject: [PATCH 116/132] kdbus: return EBADSLT on replies without slot - -If you send a reply without an active reply slot, we used to return EPERM. -However, this makes it impossible to distinguish this case from a real -permission-denied error (eg., LSM). Hence, make sure we return a unique -error-code if the reply-slot is missing. - -With this patch, you get EBADSLT ("Invalid slot") if you call -KDBUS_CMD_SEND with a reply-cookie that has no valid slot. - -Reviewed-by: Daniel Mack <daniel@zonque.org> -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - ipc/kdbus/connection.c | 2 +- - tools/testing/selftests/kdbus/test-message.c | 2 +- - tools/testing/selftests/kdbus/test-sync.c | 2 +- - 3 files changed, 3 insertions(+), 3 deletions(-) - -diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c -index d94b417e0f32..2787bd7d00c1 100644 ---- a/ipc/kdbus/connection.c -+++ b/ipc/kdbus/connection.c -@@ -1123,7 +1123,7 @@ static int kdbus_conn_reply(struct kdbus_conn *src, - mutex_unlock(&dst->lock); - - if (!reply) { -- ret = -EPERM; -+ ret = -EBADSLT; - goto exit; - } - -diff --git a/tools/testing/selftests/kdbus/test-message.c b/tools/testing/selftests/kdbus/test-message.c -index ddc1e0af877b..563dc859077a 100644 ---- a/tools/testing/selftests/kdbus/test-message.c -+++ b/tools/testing/selftests/kdbus/test-message.c -@@ -75,7 +75,7 @@ int kdbus_test_message_basic(struct kdbus_test_env *env) - - /* Faked replies with a valid reply cookie are rejected */ - ret = kdbus_msg_send_reply(conn, time(NULL) ^ cookie, sender->id); -- ASSERT_RETURN(ret == -EPERM); -+ ASSERT_RETURN(ret == -EBADSLT); - - ret = kdbus_free(conn, offset); - ASSERT_RETURN(ret == 0); -diff --git a/tools/testing/selftests/kdbus/test-sync.c b/tools/testing/selftests/kdbus/test-sync.c -index e2be910d2ece..0655a545fbf1 100644 ---- a/tools/testing/selftests/kdbus/test-sync.c -+++ b/tools/testing/selftests/kdbus/test-sync.c -@@ -235,7 +235,7 @@ static void *run_thread_reply(void *data) - - /* using an unknown cookie must fail */ - ret = kdbus_msg_send_reply(conn_a, ~cookie, conn_b->id); -- if (ret != -EPERM) { -+ if (ret != -EBADSLT) { - status = TEST_ERR; - goto exit_thread; - } --- -2.4.3 - - -From 2fee35fd480b2387e1f148fdc2125cc93708501b Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Thu, 6 Aug 2015 10:21:21 +0200 -Subject: [PATCH 117/132] kdbus: reduce stack buffer to 256 bytes - -This reduces the stack-buffer for small ioctl payloads to 256 bytes. As -seen during real workloads, this is more than enough. And we really -should reduce stack pressure. Hence, lets limit the stack buffers to 256 -bytes. - -Reported-by: Dan Carpenter <dan.carpenter@oracle.com> -Reviewed-by: Daniel Mack <daniel@zonque.org> -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - ipc/kdbus/handle.h | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/ipc/kdbus/handle.h b/ipc/kdbus/handle.h -index 8a36c0595091..5dde2c10bed4 100644 ---- a/ipc/kdbus/handle.h -+++ b/ipc/kdbus/handle.h -@@ -45,7 +45,7 @@ struct kdbus_arg { - * @argv: array of items this command supports - * @user: set by parser to user-space location of current command - * @cmd: set by parser to kernel copy of command payload -- * @cmd_buf: 512 bytes inline buf to avoid kmalloc() on small cmds -+ * @cmd_buf: inline buf to avoid kmalloc() on small cmds - * @items: points to item array in @cmd - * @items_size: size of @items in bytes - * @is_cmd: whether this is a command-payload or msg-payload -@@ -55,7 +55,7 @@ struct kdbus_arg { - * the object to kdbus_args_parse(). The parser will copy the command payload - * into kernel-space and verify the correctness of the data. - * -- * We use a 512 bytes buffer for small command payloads, to be allocated on -+ * We use a 256 bytes buffer for small command payloads, to be allocated on - * stack on syscall entrance. - */ - struct kdbus_args { -@@ -65,7 +65,7 @@ struct kdbus_args { - - struct kdbus_cmd __user *user; - struct kdbus_cmd *cmd; -- u8 cmd_buf[512]; -+ u8 cmd_buf[256]; - - struct kdbus_item *items; - size_t items_size; --- -2.4.3 - - -From cff26ca42ae55286f5b8366302812d16bbc4a90a Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Thu, 6 Aug 2015 10:21:22 +0200 -Subject: [PATCH 118/132] kdbus: use separate counter for message IDs - -For each kdbus domain, we maintain an ID-counter to guarantee unique IDs -across all objects. We also used to use it for message IDs. However, this -requires touching a shared cacheline on each message transaction, even -though we never guaranteed global ordering across buses, anyway. - -Introduce a separate counter which is used solely for message IDs. -Semantics stay the same, but it no longer relates to IDs across buses. - -Reviewed-by: Daniel Mack <daniel@zonque.org> -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - ipc/kdbus/bus.h | 2 ++ - ipc/kdbus/message.c | 2 +- - 2 files changed, 3 insertions(+), 1 deletion(-) - -diff --git a/ipc/kdbus/bus.h b/ipc/kdbus/bus.h -index 238986eff92f..8c2acaed6258 100644 ---- a/ipc/kdbus/bus.h -+++ b/ipc/kdbus/bus.h -@@ -44,6 +44,7 @@ struct kdbus_user; - * @domain: Domain of this bus - * @creator: Creator of the bus - * @creator_meta: Meta information about the bus creator -+ * @last_message_id: Last used message id - * @policy_db: Policy database for this bus - * @name_registry: Name registry of this bus - * @conn_rwlock: Read/Write lock for all lists of child connections -@@ -67,6 +68,7 @@ struct kdbus_bus { - struct kdbus_meta_proc *creator_meta; - - /* protected by own locks */ -+ atomic64_t last_message_id; - struct kdbus_policy_db policy_db; - struct kdbus_name_registry *name_registry; - -diff --git a/ipc/kdbus/message.c b/ipc/kdbus/message.c -index 432dba4dcfdc..ae565cd343f8 100644 ---- a/ipc/kdbus/message.c -+++ b/ipc/kdbus/message.c -@@ -671,7 +671,7 @@ static struct kdbus_staging *kdbus_staging_new(struct kdbus_bus *bus, - if (!staging) - return ERR_PTR(-ENOMEM); - -- staging->msg_seqnum = atomic64_inc_return(&bus->domain->last_id); -+ staging->msg_seqnum = atomic64_inc_return(&bus->last_message_id); - staging->n_parts = 0; /* we reserve n_parts, but don't enforce them */ - staging->parts = (void *)(staging + 1); - --- -2.4.3 - - -From 41c64712fef883818dadd5796f7522f675931d16 Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Thu, 6 Aug 2015 10:21:23 +0200 -Subject: [PATCH 119/132] kdbus: move privilege checking in kdbus_conn_new() - -Instead of relying on handle.c to perform privilege evaluation and -passing information along, move this into kdbus_conn_new(). This has the -benefit that we can now split 'owner' level and 'privileged' levels -apart. This will be required for following extensions that need to -distinguish both cases. - -Also, pass on 'struct file*' from handle into kdbus_conn_new(). Most -kernel helpers cannot accept 'struct cred*' but instead only operate on -files (and access file->f_cred then). - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - ipc/kdbus/connection.c | 41 ++++++++++++++++++++++++++++++++--------- - ipc/kdbus/connection.h | 6 ++++-- - ipc/kdbus/handle.c | 2 +- - 3 files changed, 37 insertions(+), 12 deletions(-) - -diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c -index 2787bd7d00c1..243cbc77624e 100644 ---- a/ipc/kdbus/connection.c -+++ b/ipc/kdbus/connection.c -@@ -52,7 +52,8 @@ - #define KDBUS_CONN_ACTIVE_BIAS (INT_MIN + 2) - #define KDBUS_CONN_ACTIVE_NEW (INT_MIN + 1) - --static struct kdbus_conn *kdbus_conn_new(struct kdbus_ep *ep, bool privileged, -+static struct kdbus_conn *kdbus_conn_new(struct kdbus_ep *ep, -+ struct file *file, - struct kdbus_cmd_hello *hello, - const char *name, - const struct kdbus_creds *creds, -@@ -72,6 +73,8 @@ static struct kdbus_conn *kdbus_conn_new(struct kdbus_ep *ep, bool privileged, - bool is_policy_holder; - bool is_activator; - bool is_monitor; -+ bool privileged; -+ bool owner; - struct kvec kvec; - int ret; - -@@ -81,6 +84,25 @@ static struct kdbus_conn *kdbus_conn_new(struct kdbus_ep *ep, bool privileged, - struct kdbus_bloom_parameter bloom; - } bloom_item; - -+ /* -+ * A connection is considered privileged, if, and only if, it didn't -+ * connect through a custom endpoint *and* it has CAP_IPC_OWNER on the -+ * namespace of the current domain. -+ * Additionally, a connection is considered equivalent to the bus owner -+ * if it didn't connect through a custom endpoint *and* it either is -+ * privileged or the same user as the bus owner. -+ * -+ * Bus owners and alike can bypass bus policies. Privileged connections -+ * can additionally change accounting, modify kernel resources and -+ * perform restricted operations, as long as they're privileged on the -+ * same level as the resources they touch. -+ */ -+ privileged = !ep->user && -+ file_ns_capable(file, ep->bus->domain->user_namespace, -+ CAP_IPC_OWNER); -+ owner = !ep->user && -+ (privileged || uid_eq(file->f_cred->euid, ep->bus->node.uid)); -+ - is_monitor = hello->flags & KDBUS_HELLO_MONITOR; - is_activator = hello->flags & KDBUS_HELLO_ACTIVATOR; - is_policy_holder = hello->flags & KDBUS_HELLO_POLICY_HOLDER; -@@ -97,9 +119,9 @@ static struct kdbus_conn *kdbus_conn_new(struct kdbus_ep *ep, bool privileged, - return ERR_PTR(-EINVAL); - if (is_monitor && ep->user) - return ERR_PTR(-EOPNOTSUPP); -- if (!privileged && (is_activator || is_policy_holder || is_monitor)) -+ if (!owner && (is_activator || is_policy_holder || is_monitor)) - return ERR_PTR(-EPERM); -- if ((creds || pids || seclabel) && !privileged) -+ if (!owner && (creds || pids || seclabel)) - return ERR_PTR(-EPERM); - - ret = kdbus_sanitize_attach_flags(hello->attach_flags_send, -@@ -129,12 +151,13 @@ static struct kdbus_conn *kdbus_conn_new(struct kdbus_ep *ep, bool privileged, - atomic_set(&conn->request_count, 0); - atomic_set(&conn->lost_count, 0); - INIT_DELAYED_WORK(&conn->work, kdbus_reply_list_scan_work); -- conn->cred = get_current_cred(); -+ conn->cred = get_cred(file->f_cred); - conn->pid = get_pid(task_pid(current)); - get_fs_root(current->fs, &conn->root_path); - init_waitqueue_head(&conn->wait); - kdbus_queue_init(&conn->queue); - conn->privileged = privileged; -+ conn->owner = owner; - conn->ep = kdbus_ep_ref(ep); - conn->id = atomic64_inc_return(&bus->domain->last_id); - conn->flags = hello->flags; -@@ -1418,7 +1441,7 @@ bool kdbus_conn_policy_own_name(struct kdbus_conn *conn, - return false; - } - -- if (conn->privileged) -+ if (conn->owner) - return true; - - res = kdbus_policy_query(&conn->ep->bus->policy_db, conn_creds, -@@ -1448,7 +1471,7 @@ bool kdbus_conn_policy_talk(struct kdbus_conn *conn, - to, KDBUS_POLICY_TALK)) - return false; - -- if (conn->privileged) -+ if (conn->owner) - return true; - if (uid_eq(conn_creds->euid, to->cred->uid)) - return true; -@@ -1567,12 +1590,12 @@ bool kdbus_conn_policy_see_notification(struct kdbus_conn *conn, - /** - * kdbus_cmd_hello() - handle KDBUS_CMD_HELLO - * @ep: Endpoint to operate on -- * @privileged: Whether the caller is privileged -+ * @file: File this connection is opened on - * @argp: Command payload - * - * Return: NULL or newly created connection on success, ERR_PTR on failure. - */ --struct kdbus_conn *kdbus_cmd_hello(struct kdbus_ep *ep, bool privileged, -+struct kdbus_conn *kdbus_cmd_hello(struct kdbus_ep *ep, struct file *file, - void __user *argp) - { - struct kdbus_cmd_hello *cmd; -@@ -1607,7 +1630,7 @@ struct kdbus_conn *kdbus_cmd_hello(struct kdbus_ep *ep, bool privileged, - - item_name = argv[1].item ? argv[1].item->str : NULL; - -- c = kdbus_conn_new(ep, privileged, cmd, item_name, -+ c = kdbus_conn_new(ep, file, cmd, item_name, - argv[2].item ? &argv[2].item->creds : NULL, - argv[3].item ? &argv[3].item->pids : NULL, - argv[4].item ? argv[4].item->str : NULL, -diff --git a/ipc/kdbus/connection.h b/ipc/kdbus/connection.h -index 5ee864eb0e41..8e0180ace3f6 100644 ---- a/ipc/kdbus/connection.h -+++ b/ipc/kdbus/connection.h -@@ -73,7 +73,8 @@ struct kdbus_staging; - * @activator_of: Well-known name entry this connection acts as an - * @names_list: List of well-known names - * @names_queue_list: Well-known names this connection waits for -- * @privileged: Whether this connection is privileged on the bus -+ * @privileged: Whether this connection is privileged on the domain -+ * @owner: Owned by the same user as the bus owner - */ - struct kdbus_conn { - struct kref kref; -@@ -116,6 +117,7 @@ struct kdbus_conn { - struct list_head names_queue_list; - - bool privileged:1; -+ bool owner:1; - }; - - struct kdbus_conn *kdbus_conn_ref(struct kdbus_conn *conn); -@@ -154,7 +156,7 @@ bool kdbus_conn_policy_see_notification(struct kdbus_conn *conn, - const struct kdbus_msg *msg); - - /* command dispatcher */ --struct kdbus_conn *kdbus_cmd_hello(struct kdbus_ep *ep, bool privileged, -+struct kdbus_conn *kdbus_cmd_hello(struct kdbus_ep *ep, struct file *file, - void __user *argp); - int kdbus_cmd_byebye_unlocked(struct kdbus_conn *conn, void __user *argp); - int kdbus_cmd_conn_info(struct kdbus_conn *conn, void __user *argp); -diff --git a/ipc/kdbus/handle.c b/ipc/kdbus/handle.c -index e0e06b0e1114..a93c385c6280 100644 ---- a/ipc/kdbus/handle.c -+++ b/ipc/kdbus/handle.c -@@ -431,7 +431,7 @@ static long kdbus_handle_ioctl_ep(struct file *file, unsigned int cmd, - break; - - case KDBUS_CMD_HELLO: -- conn = kdbus_cmd_hello(file_ep, handle->privileged, buf); -+ conn = kdbus_cmd_hello(file_ep, file, buf); - if (IS_ERR_OR_NULL(conn)) { - ret = PTR_ERR_OR_ZERO(conn); - break; --- -2.4.3 - - -From 1cd893dae99f8169c0f0620f343e3ee2379d0d28 Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Thu, 6 Aug 2015 10:21:24 +0200 -Subject: [PATCH 120/132] kdbus: perform accounting on proxied uids - -If a connection proxies a uid, we should make sure to perform accounting -on that passed uid. Otherwise, limits will be shared across all proxied -users (or we'd require the proxy to run setuid() and thus require -CAP_SETUID). -However, this is only allowed if the proxy is privileged on the bus. That -is, it must have CAP_IPC_ADMIN on the domain and the passed uid must be -mapped in that domain. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - ipc/kdbus/connection.c | 12 +++++++++++- - 1 file changed, 11 insertions(+), 1 deletion(-) - -diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c -index 243cbc77624e..c81888ed1138 100644 ---- a/ipc/kdbus/connection.c -+++ b/ipc/kdbus/connection.c -@@ -237,11 +237,21 @@ static struct kdbus_conn *kdbus_conn_new(struct kdbus_ep *ep, - * Note that limits are always accounted against the real UID, not - * the effective UID (cred->user always points to the accounting of - * cred->uid, not cred->euid). -+ * In case the caller is privileged, we allow changing the accounting -+ * to the faked user. - */ - if (ep->user) { - conn->user = kdbus_user_ref(ep->user); - } else { -- conn->user = kdbus_user_lookup(ep->bus->domain, current_uid()); -+ kuid_t uid; -+ -+ if (conn->meta_fake && uid_valid(conn->meta_fake->uid) && -+ conn->privileged) -+ uid = conn->meta_fake->uid; -+ else -+ uid = conn->cred->uid; -+ -+ conn->user = kdbus_user_lookup(ep->bus->domain, uid); - if (IS_ERR(conn->user)) { - ret = PTR_ERR(conn->user); - conn->user = NULL; --- -2.4.3 - - -From 9dad3c87e273ac8e895ec86252bd79792d49da77 Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Thu, 6 Aug 2015 10:21:25 +0200 -Subject: [PATCH 121/132] kdbus: inline privilege checks - -Instead of caching privilege information in 'kdbus_handle' (and thus -increasing the size of each handle by 8 byte), perform privilege checks -on the cached creds in file->f_cred inline. None of the functions that -need those checks is a fast path (in fact, it's just EP_MAKE that needs -it right now), so there's no need to cache the data. - -If more functions need this check later on, we should turn it into a -small static helper. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - ipc/kdbus/handle.c | 34 +++++++++++----------------------- - 1 file changed, 11 insertions(+), 23 deletions(-) - -diff --git a/ipc/kdbus/handle.c b/ipc/kdbus/handle.c -index a93c385c6280..4d41ecf9cc7d 100644 ---- a/ipc/kdbus/handle.c -+++ b/ipc/kdbus/handle.c -@@ -264,7 +264,6 @@ enum kdbus_handle_type { - * @bus_owner: bus this handle owns - * @ep_owner: endpoint this handle owns - * @conn: connection this handle owns -- * @privileged: Flag to mark a handle as privileged - */ - struct kdbus_handle { - struct mutex lock; -@@ -275,8 +274,6 @@ struct kdbus_handle { - struct kdbus_ep *ep_owner; - struct kdbus_conn *conn; - }; -- -- bool privileged:1; - }; - - static int kdbus_handle_open(struct inode *inode, struct file *file) -@@ -298,23 +295,6 @@ static int kdbus_handle_open(struct inode *inode, struct file *file) - mutex_init(&handle->lock); - handle->type = KDBUS_HANDLE_NONE; - -- if (node->type == KDBUS_NODE_ENDPOINT) { -- struct kdbus_ep *ep = kdbus_ep_from_node(node); -- struct kdbus_bus *bus = ep->bus; -- -- /* -- * A connection is privileged if it is opened on an endpoint -- * without custom policy and either: -- * * the user has CAP_IPC_OWNER in the domain user namespace -- * or -- * * the callers euid matches the uid of the bus creator -- */ -- if (!ep->user && -- (ns_capable(bus->domain->user_namespace, CAP_IPC_OWNER) || -- uid_eq(file->f_cred->euid, bus->node.uid))) -- handle->privileged = true; -- } -- - file->private_data = handle; - ret = 0; - -@@ -406,6 +386,7 @@ static long kdbus_handle_ioctl_ep(struct file *file, unsigned int cmd, - struct kdbus_handle *handle = file->private_data; - struct kdbus_node *node = file_inode(file)->i_private; - struct kdbus_ep *ep, *file_ep = kdbus_ep_from_node(node); -+ struct kdbus_bus *bus = file_ep->bus; - struct kdbus_conn *conn; - int ret = 0; - -@@ -413,14 +394,20 @@ static long kdbus_handle_ioctl_ep(struct file *file, unsigned int cmd, - return -ESHUTDOWN; - - switch (cmd) { -- case KDBUS_CMD_ENDPOINT_MAKE: -+ case KDBUS_CMD_ENDPOINT_MAKE: { -+ bool priv; -+ -+ priv = uid_eq(file->f_cred->euid, bus->node.uid) || -+ file_ns_capable(file, bus->domain->user_namespace, -+ CAP_IPC_OWNER); -+ - /* creating custom endpoints is a privileged operation */ -- if (!handle->privileged) { -+ if (file_ep->user || !priv) { - ret = -EPERM; - break; - } - -- ep = kdbus_cmd_ep_make(file_ep->bus, buf); -+ ep = kdbus_cmd_ep_make(bus, buf); - if (IS_ERR_OR_NULL(ep)) { - ret = PTR_ERR_OR_ZERO(ep); - break; -@@ -429,6 +416,7 @@ static long kdbus_handle_ioctl_ep(struct file *file, unsigned int cmd, - handle->ep_owner = ep; - ret = KDBUS_HANDLE_EP_OWNER; - break; -+ } - - case KDBUS_CMD_HELLO: - conn = kdbus_cmd_hello(file_ep, file, buf); --- -2.4.3 - - -From c4bf3679fb862abfc7064c975a5782cdb2a01c9e Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Thu, 6 Aug 2015 10:21:26 +0200 -Subject: [PATCH 122/132] kdbus: consolidate common code - -Move the file-credential checkers into kdbus_ep_*() helper functions to -avoid hard-coding the same behavior in multiple places. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - ipc/kdbus/connection.c | 20 ++------------------ - ipc/kdbus/endpoint.c | 28 ++++++++++++++++++++++++++++ - ipc/kdbus/endpoint.h | 3 +++ - ipc/kdbus/handle.c | 8 +------- - 4 files changed, 34 insertions(+), 25 deletions(-) - -diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c -index c81888ed1138..aa3296ea4f93 100644 ---- a/ipc/kdbus/connection.c -+++ b/ipc/kdbus/connection.c -@@ -84,24 +84,8 @@ static struct kdbus_conn *kdbus_conn_new(struct kdbus_ep *ep, - struct kdbus_bloom_parameter bloom; - } bloom_item; - -- /* -- * A connection is considered privileged, if, and only if, it didn't -- * connect through a custom endpoint *and* it has CAP_IPC_OWNER on the -- * namespace of the current domain. -- * Additionally, a connection is considered equivalent to the bus owner -- * if it didn't connect through a custom endpoint *and* it either is -- * privileged or the same user as the bus owner. -- * -- * Bus owners and alike can bypass bus policies. Privileged connections -- * can additionally change accounting, modify kernel resources and -- * perform restricted operations, as long as they're privileged on the -- * same level as the resources they touch. -- */ -- privileged = !ep->user && -- file_ns_capable(file, ep->bus->domain->user_namespace, -- CAP_IPC_OWNER); -- owner = !ep->user && -- (privileged || uid_eq(file->f_cred->euid, ep->bus->node.uid)); -+ privileged = kdbus_ep_is_privileged(ep, file); -+ owner = kdbus_ep_is_owner(ep, file); - - is_monitor = hello->flags & KDBUS_HELLO_MONITOR; - is_activator = hello->flags & KDBUS_HELLO_ACTIVATOR; -diff --git a/ipc/kdbus/endpoint.c b/ipc/kdbus/endpoint.c -index 977964dbb44a..44e7a20de9c2 100644 ---- a/ipc/kdbus/endpoint.c -+++ b/ipc/kdbus/endpoint.c -@@ -184,6 +184,34 @@ struct kdbus_ep *kdbus_ep_unref(struct kdbus_ep *ep) - } - - /** -+ * kdbus_ep_is_privileged() - check whether a file is privileged -+ * @ep: endpoint to operate on -+ * @file: file to test -+ * -+ * Return: True if @file is privileged in the domain of @ep. -+ */ -+bool kdbus_ep_is_privileged(struct kdbus_ep *ep, struct file *file) -+{ -+ return !ep->user && -+ file_ns_capable(file, ep->bus->domain->user_namespace, -+ CAP_IPC_OWNER); -+} -+ -+/** -+ * kdbus_ep_is_owner() - check whether a file should be treated as bus owner -+ * @ep: endpoint to operate on -+ * @file: file to test -+ * -+ * Return: True if @file should be treated as bus owner on @ep -+ */ -+bool kdbus_ep_is_owner(struct kdbus_ep *ep, struct file *file) -+{ -+ return !ep->user && -+ (uid_eq(file->f_cred->euid, ep->bus->node.uid) || -+ kdbus_ep_is_privileged(ep, file)); -+} -+ -+/** - * kdbus_cmd_ep_make() - handle KDBUS_CMD_ENDPOINT_MAKE - * @bus: bus to operate on - * @argp: command payload -diff --git a/ipc/kdbus/endpoint.h b/ipc/kdbus/endpoint.h -index bc1b94a70f93..e0da59f01a7a 100644 ---- a/ipc/kdbus/endpoint.h -+++ b/ipc/kdbus/endpoint.h -@@ -61,6 +61,9 @@ struct kdbus_ep *kdbus_ep_new(struct kdbus_bus *bus, const char *name, - struct kdbus_ep *kdbus_ep_ref(struct kdbus_ep *ep); - struct kdbus_ep *kdbus_ep_unref(struct kdbus_ep *ep); - -+bool kdbus_ep_is_privileged(struct kdbus_ep *ep, struct file *file); -+bool kdbus_ep_is_owner(struct kdbus_ep *ep, struct file *file); -+ - struct kdbus_ep *kdbus_cmd_ep_make(struct kdbus_bus *bus, void __user *argp); - int kdbus_cmd_ep_update(struct kdbus_ep *ep, void __user *argp); - -diff --git a/ipc/kdbus/handle.c b/ipc/kdbus/handle.c -index 4d41ecf9cc7d..fc60932d69c7 100644 ---- a/ipc/kdbus/handle.c -+++ b/ipc/kdbus/handle.c -@@ -395,14 +395,8 @@ static long kdbus_handle_ioctl_ep(struct file *file, unsigned int cmd, - - switch (cmd) { - case KDBUS_CMD_ENDPOINT_MAKE: { -- bool priv; -- -- priv = uid_eq(file->f_cred->euid, bus->node.uid) || -- file_ns_capable(file, bus->domain->user_namespace, -- CAP_IPC_OWNER); -- - /* creating custom endpoints is a privileged operation */ -- if (file_ep->user || !priv) { -+ if (!kdbus_ep_is_owner(file_ep, file)) { - ret = -EPERM; - break; - } --- -2.4.3 - - -From 146f50d92e16b684da73ecbb290d980babe98366 Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Thu, 6 Aug 2015 10:21:27 +0200 -Subject: [PATCH 123/132] kdbus/samples: skip if __NR_memfd_create is not - defined - -We require __NR_memfd_create for the kdbus samples. Make sure we skip -compilation if the target architecture and kernel do not support memfds. - -Reported-by: Paul Gortmaker <paul.gortmaker@windriver.com> -Reviewed-by: Daniel Mack <daniel@zonque.org> -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - samples/kdbus/kdbus-workers.c | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - -diff --git a/samples/kdbus/kdbus-workers.c b/samples/kdbus/kdbus-workers.c -index c3ba958639f3..5a6dfdce3bfd 100644 ---- a/samples/kdbus/kdbus-workers.c -+++ b/samples/kdbus/kdbus-workers.c -@@ -59,9 +59,11 @@ - - #include <stdio.h> - #include <stdlib.h> -+#include <sys/syscall.h> - - /* glibc < 2.7 does not ship sys/signalfd.h */ --#if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 7 -+/* we require kernels with __NR_memfd_create */ -+#if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 7 && defined(__NR_memfd_create) - - #include <ctype.h> - #include <errno.h> -@@ -75,7 +77,6 @@ - #include <sys/mman.h> - #include <sys/poll.h> - #include <sys/signalfd.h> --#include <sys/syscall.h> - #include <sys/time.h> - #include <sys/wait.h> - #include <time.h> --- -2.4.3 - - -From 917ee9c6252234fdb8e08670d3c31b6cef18e902 Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Thu, 6 Aug 2015 10:21:28 +0200 -Subject: [PATCH 124/132] kdbus/tests: properly parse KDBUS_CMD_LIST objects - -There is no reason to assume the information returned by KDBUS_CMD_LIST -contains only a single KDBUS_ITEM_OWNED_NAME. Parse each of them properly -and don't bail out early. - -Reviewed-by: Daniel Mack <daniel@zonque.org> -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - tools/testing/selftests/kdbus/kdbus-util.c | 9 +++++---- - tools/testing/selftests/kdbus/test-names.c | 17 +++++++++++------ - 2 files changed, 16 insertions(+), 10 deletions(-) - -diff --git a/tools/testing/selftests/kdbus/kdbus-util.c b/tools/testing/selftests/kdbus/kdbus-util.c -index a5e54ca3a492..82fa89b1a881 100644 ---- a/tools/testing/selftests/kdbus/kdbus-util.c -+++ b/tools/testing/selftests/kdbus/kdbus-util.c -@@ -1155,11 +1155,12 @@ int kdbus_list(struct kdbus_conn *conn, uint64_t flags) - if (item->type == KDBUS_ITEM_OWNED_NAME) { - n = item->name.name; - flags = item->name.flags; -- } - -- kdbus_printf("%8llu flags=0x%08llx conn=0x%08llx '%s'\n", -- name->id, (unsigned long long) flags, -- name->flags, n); -+ kdbus_printf("%8llu flags=0x%08llx conn=0x%08llx '%s'\n", -+ name->id, -+ (unsigned long long) flags, -+ name->flags, n); -+ } - } - kdbus_printf("\n"); - -diff --git a/tools/testing/selftests/kdbus/test-names.c b/tools/testing/selftests/kdbus/test-names.c -index 66ebb47370eb..fd4ac5adc6d2 100644 ---- a/tools/testing/selftests/kdbus/test-names.c -+++ b/tools/testing/selftests/kdbus/test-names.c -@@ -35,15 +35,20 @@ static int conn_is_name_owner(const struct kdbus_conn *conn, - struct kdbus_item *item; - const char *n = NULL; - -- KDBUS_ITEM_FOREACH(item, name, items) -- if (item->type == KDBUS_ITEM_OWNED_NAME) -+ KDBUS_ITEM_FOREACH(item, name, items) { -+ if (item->type == KDBUS_ITEM_OWNED_NAME) { - n = item->name.name; - -- if (name->id == conn->id && -- n && strcmp(needle, n) == 0) { -- found = true; -- break; -+ if (name->id == conn->id && -+ n && strcmp(needle, n) == 0) { -+ found = true; -+ break; -+ } -+ } - } -+ -+ if (found) -+ break; - } - - ret = kdbus_free(conn, cmd_list.offset); --- -2.4.3 - - -From 0e807c0b41b9e5a434f803a3ea0ba12ed316cbb7 Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Fri, 7 Aug 2015 16:36:33 +0200 -Subject: [PATCH 125/132] kdbus: restructure name-registry to follow dbus-spec - -The DBus Specification [1] is pretty clear about how name-acquisition, -queueing and releasing must work. Most of it's peculiarities nobody -relies on, but we better comply to them to at least allow proper -backwards compatibility via bus-proxy. - -In particular, this means we don't implement the following details: - * NameAcquire must update the stored flags of a name-owner if it is - already queued or owns the name. - * Only KDBUS_NAME_QUEUE and KDBUS_NAME_ALLOW_REPLACEMENT are stored - flags of name owners. Everything else is only used during command - execution and/or as reply flags. - * NameAcquire on an already queued owner must not change the position in - the queue. - * KDBUS_NAME_REPLACE_EXISTING for already queued ownes *jumps* the queue - if the primary owner has ALLOW_REPLACEMENT set. - * If a primary owner is replaced by someone else, they must retain their - stored name-flags. - * If a primary owner is replaced by someone else, they must be placed at - second position in the queue, if queuing is requested. - -In dbus-daemon the name-owner queue is a single queue. That is, the -primary owner of a name is not special, instead, it simply is the first -queued owner. This explains most of the peculiarities of the NameAcquire -behavior and makes it much easier to implement them. - -Hence, this patch rewrites the name-registry to follow the lead: - * *ANY* name owner is now represented by a "struct kdbus_name_owner" - objects, regardless whether they're queued, activators or primary. - * All name-ownerships are linked in a *single* list on each connection. - This gets rid of redundant conn->queued_names_list and - conn->activator_of. - * Limits and control functions always apply to 'struct kdbus_name_owner' - now, instead of 'struct kdbus_name_entry'. This solves some issues - where name-ownership was properly limited, but name-queueing was not. - * Activators are now correctly updated regarding KDBUS_NAME_IN_QUEUE - depending whether they own the name or not. - * owner->flags is now kept clean. Only real requested flags are stored, - any operation-flags are cleared. - * Special handling of activators is kept to a minimum. This really - allows us to treat them more like real queued owners that allow - replacement, than something special. - -With this in place, we follow the dbus-spec regarding behavior of -name-acquisition perfectly. Hence, the bus-proxy can properly implement -backwards-compatibility to dbus1. - -[1] http://dbus.freedesktop.org/doc/dbus-specification.html - -Reviewed-by: Daniel Mack <daniel@zonque.org> -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - ipc/kdbus/connection.c | 53 ++-- - ipc/kdbus/connection.h | 9 +- - ipc/kdbus/metadata.c | 21 +- - ipc/kdbus/names.c | 749 +++++++++++++++++++++++++++---------------------- - ipc/kdbus/names.h | 55 +++- - 5 files changed, 496 insertions(+), 391 deletions(-) - -diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c -index aa3296ea4f93..ef63d6533273 100644 ---- a/ipc/kdbus/connection.c -+++ b/ipc/kdbus/connection.c -@@ -129,9 +129,7 @@ static struct kdbus_conn *kdbus_conn_new(struct kdbus_ep *ep, - #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->request_count, 0); - atomic_set(&conn->lost_count, 0); - INIT_DELAYED_WORK(&conn->work, kdbus_reply_list_scan_work); -@@ -284,7 +282,6 @@ static void __kdbus_conn_free(struct kref *kref) - WARN_ON(delayed_work_pending(&conn->work)); - WARN_ON(!list_empty(&conn->queue.msg_list)); - WARN_ON(!list_empty(&conn->names_list)); -- WARN_ON(!list_empty(&conn->names_queue_list)); - WARN_ON(!list_empty(&conn->reply_list)); - - if (conn->user) { -@@ -618,12 +615,13 @@ int kdbus_conn_disconnect(struct kdbus_conn *conn, bool ensure_queue_empty) - */ - bool kdbus_conn_has_name(struct kdbus_conn *conn, const char *name) - { -- struct kdbus_name_entry *e; -+ struct kdbus_name_owner *owner; - - lockdep_assert_held(&conn->ep->bus->name_registry->rwlock); - -- list_for_each_entry(e, &conn->names_list, conn_entry) -- if (strcmp(e->name, name) == 0) -+ list_for_each_entry(owner, &conn->names_list, conn_entry) -+ if (!(owner->flags & KDBUS_NAME_IN_QUEUE) && -+ !strcmp(name, owner->name->name)) - return true; - - return false; -@@ -1052,6 +1050,7 @@ static int kdbus_pin_dst(struct kdbus_bus *bus, - struct kdbus_conn **out_dst) - { - const struct kdbus_msg *msg = staging->msg; -+ struct kdbus_name_owner *owner = NULL; - struct kdbus_name_entry *name = NULL; - struct kdbus_conn *dst = NULL; - int ret; -@@ -1070,7 +1069,9 @@ static int kdbus_pin_dst(struct kdbus_bus *bus, - } else { - name = kdbus_name_lookup_unlocked(bus->name_registry, - staging->dst_name); -- if (!name) -+ if (name) -+ owner = kdbus_name_get_owner(name); -+ if (!owner) - return -ESRCH; - - /* -@@ -1082,19 +1083,14 @@ static int kdbus_pin_dst(struct kdbus_bus *bus, - * owns the given name. - */ - if (msg->dst_id != KDBUS_DST_ID_NAME && -- msg->dst_id != name->conn->id) -+ msg->dst_id != owner->conn->id) - return -EREMCHG; - -- if (!name->conn && name->activator) -- dst = kdbus_conn_ref(name->activator); -- else -- dst = kdbus_conn_ref(name->conn); -- - if ((msg->flags & KDBUS_MSG_NO_AUTO_START) && -- kdbus_conn_is_activator(dst)) { -- ret = -EADDRNOTAVAIL; -- goto error; -- } -+ kdbus_conn_is_activator(owner->conn)) -+ return -EADDRNOTAVAIL; -+ -+ dst = kdbus_conn_ref(owner->conn); - } - - *out_name = name; -@@ -1383,7 +1379,7 @@ static bool kdbus_conn_policy_query_all(struct kdbus_conn *conn, - struct kdbus_conn *whom, - unsigned int access) - { -- struct kdbus_name_entry *ne; -+ struct kdbus_name_owner *owner; - bool pass = false; - int res; - -@@ -1392,10 +1388,14 @@ static bool kdbus_conn_policy_query_all(struct kdbus_conn *conn, - down_read(&db->entries_rwlock); - mutex_lock(&whom->lock); - -- list_for_each_entry(ne, &whom->names_list, conn_entry) { -- res = kdbus_policy_query_unlocked(db, conn_creds ? : conn->cred, -- ne->name, -- kdbus_strhash(ne->name)); -+ list_for_each_entry(owner, &whom->names_list, conn_entry) { -+ if (owner->flags & KDBUS_NAME_IN_QUEUE) -+ continue; -+ -+ res = kdbus_policy_query_unlocked(db, -+ conn_creds ? : conn->cred, -+ owner->name->name, -+ kdbus_strhash(owner->name->name)); - if (res >= (int)access) { - pass = true; - break; -@@ -1713,6 +1713,7 @@ int kdbus_cmd_conn_info(struct kdbus_conn *conn, void __user *argp) - struct kdbus_meta_conn *conn_meta = NULL; - struct kdbus_pool_slice *slice = NULL; - struct kdbus_name_entry *entry = NULL; -+ struct kdbus_name_owner *owner = NULL; - struct kdbus_conn *owner_conn = NULL; - struct kdbus_item *meta_items = NULL; - struct kdbus_info info = {}; -@@ -1749,15 +1750,17 @@ int kdbus_cmd_conn_info(struct kdbus_conn *conn, void __user *argp) - - if (name) { - entry = kdbus_name_lookup_unlocked(bus->name_registry, name); -- if (!entry || !entry->conn || -+ if (entry) -+ owner = kdbus_name_get_owner(entry); -+ if (!owner || - !kdbus_conn_policy_see_name(conn, current_cred(), name) || -- (cmd->id != 0 && entry->conn->id != cmd->id)) { -+ (cmd->id != 0 && owner->conn->id != cmd->id)) { - /* pretend a name doesn't exist if you cannot see it */ - ret = -ESRCH; - goto exit; - } - -- owner_conn = kdbus_conn_ref(entry->conn); -+ owner_conn = kdbus_conn_ref(owner->conn); - } else if (cmd->id > 0) { - owner_conn = kdbus_bus_find_conn_by_id(bus, cmd->id); - if (!owner_conn || !kdbus_conn_policy_see(conn, current_cred(), -diff --git a/ipc/kdbus/connection.h b/ipc/kdbus/connection.h -index 8e0180ace3f6..1ad082014faa 100644 ---- a/ipc/kdbus/connection.h -+++ b/ipc/kdbus/connection.h -@@ -30,6 +30,7 @@ - KDBUS_HELLO_POLICY_HOLDER | \ - KDBUS_HELLO_MONITOR) - -+struct kdbus_name_entry; - struct kdbus_quota; - struct kdbus_staging; - -@@ -61,7 +62,6 @@ struct kdbus_staging; - * @cred: The credentials of the connection at creation time - * @pid: Pid at creation time - * @root_path: Root path at creation time -- * @name_count: Number of owned well-known names - * @request_count: Number of pending requests issued by this - * connection that are waiting for replies from - * other peers -@@ -70,9 +70,8 @@ struct kdbus_staging; - * @queue: The message queue associated with this connection - * @quota: Array of per-user quota indexed by user->id - * @n_quota: Number of elements in quota array -- * @activator_of: Well-known name entry this connection acts as an - * @names_list: List of well-known names -- * @names_queue_list: Well-known names this connection waits for -+ * @name_count: Number of owned well-known names - * @privileged: Whether this connection is privileged on the domain - * @owner: Owned by the same user as the bus owner - */ -@@ -102,7 +101,6 @@ struct kdbus_conn { - const struct cred *cred; - struct pid *pid; - struct path root_path; -- atomic_t name_count; - atomic_t request_count; - atomic_t lost_count; - wait_queue_head_t wait; -@@ -112,9 +110,8 @@ struct kdbus_conn { - unsigned int n_quota; - - /* protected by registry->rwlock */ -- struct kdbus_name_entry *activator_of; - struct list_head names_list; -- struct list_head names_queue_list; -+ unsigned int name_count; - - bool privileged:1; - bool owner:1; -diff --git a/ipc/kdbus/metadata.c b/ipc/kdbus/metadata.c -index d4973a90a81e..71ca475a80d5 100644 ---- a/ipc/kdbus/metadata.c -+++ b/ipc/kdbus/metadata.c -@@ -603,7 +603,7 @@ static void kdbus_meta_conn_collect_timestamp(struct kdbus_meta_conn *mc, - static int kdbus_meta_conn_collect_names(struct kdbus_meta_conn *mc, - struct kdbus_conn *conn) - { -- const struct kdbus_name_entry *e; -+ const struct kdbus_name_owner *owner; - struct kdbus_item *item; - size_t slen, size; - -@@ -611,9 +611,11 @@ static int kdbus_meta_conn_collect_names(struct kdbus_meta_conn *mc, - - size = 0; - /* open-code length calculation to avoid final padding */ -- list_for_each_entry(e, &conn->names_list, conn_entry) -- size = KDBUS_ALIGN8(size) + KDBUS_ITEM_HEADER_SIZE + -- sizeof(struct kdbus_name) + strlen(e->name) + 1; -+ list_for_each_entry(owner, &conn->names_list, conn_entry) -+ if (!(owner->flags & KDBUS_NAME_IN_QUEUE)) -+ size = KDBUS_ALIGN8(size) + KDBUS_ITEM_HEADER_SIZE + -+ sizeof(struct kdbus_name) + -+ strlen(owner->name->name) + 1; - - if (!size) - return 0; -@@ -626,12 +628,15 @@ static int kdbus_meta_conn_collect_names(struct kdbus_meta_conn *mc, - mc->owned_names_items = item; - mc->owned_names_size = size; - -- list_for_each_entry(e, &conn->names_list, conn_entry) { -- slen = strlen(e->name) + 1; -+ list_for_each_entry(owner, &conn->names_list, conn_entry) { -+ if (owner->flags & KDBUS_NAME_IN_QUEUE) -+ continue; -+ -+ slen = strlen(owner->name->name) + 1; - kdbus_item_set(item, KDBUS_ITEM_OWNED_NAME, NULL, - sizeof(struct kdbus_name) + slen); -- item->name.flags = e->flags; -- memcpy(item->name.name, e->name, slen); -+ item->name.flags = owner->flags; -+ memcpy(item->name.name, owner->name->name, slen); - item = KDBUS_ITEM_NEXT(item); - } - -diff --git a/ipc/kdbus/names.c b/ipc/kdbus/names.c -index 057f8061c20f..7a6e61c35ebf 100644 ---- a/ipc/kdbus/names.c -+++ b/ipc/kdbus/names.c -@@ -34,167 +34,128 @@ - #include "notify.h" - #include "policy.h" - --struct kdbus_name_pending { -- u64 flags; -- struct kdbus_conn *conn; -- struct kdbus_name_entry *name; -- struct list_head conn_entry; -- struct list_head name_entry; --}; -+#define KDBUS_NAME_SAVED_MASK (KDBUS_NAME_ALLOW_REPLACEMENT | \ -+ KDBUS_NAME_QUEUE) - --static int kdbus_name_pending_new(struct kdbus_name_entry *e, -- struct kdbus_conn *conn, u64 flags) -+static bool kdbus_name_owner_is_used(struct kdbus_name_owner *owner) - { -- struct kdbus_name_pending *p; -- -- kdbus_conn_assert_active(conn); -- -- p = kmalloc(sizeof(*p), GFP_KERNEL); -- if (!p) -- return -ENOMEM; -- -- p->flags = flags; -- p->conn = conn; -- p->name = e; -- list_add_tail(&p->conn_entry, &conn->names_queue_list); -- list_add_tail(&p->name_entry, &e->queue); -- -- return 0; -+ return !list_empty(&owner->name_entry) || -+ owner == owner->name->activator; - } - --static void kdbus_name_pending_free(struct kdbus_name_pending *p) -+static struct kdbus_name_owner * -+kdbus_name_owner_new(struct kdbus_conn *conn, struct kdbus_name_entry *name, -+ u64 flags) - { -- if (!p) -- return; -+ struct kdbus_name_owner *owner; - -- list_del(&p->name_entry); -- list_del(&p->conn_entry); -- kfree(p); --} -- --static struct kdbus_name_entry * --kdbus_name_entry_new(struct kdbus_name_registry *r, u32 hash, const char *name) --{ -- struct kdbus_name_entry *e; -- size_t namelen; -+ kdbus_conn_assert_active(conn); - -- namelen = strlen(name); -+ if (conn->name_count >= KDBUS_CONN_MAX_NAMES) -+ return ERR_PTR(-E2BIG); - -- e = kmalloc(sizeof(*e) + namelen + 1, GFP_KERNEL); -- if (!e) -+ owner = kmalloc(sizeof(*owner), GFP_KERNEL); -+ if (!owner) - return ERR_PTR(-ENOMEM); - -- e->name_id = ++r->name_seq_last; -- e->flags = 0; -- e->conn = NULL; -- e->activator = NULL; -- INIT_LIST_HEAD(&e->queue); -- INIT_LIST_HEAD(&e->conn_entry); -- hash_add(r->entries_hash, &e->hentry, hash); -- memcpy(e->name, name, namelen + 1); -+ owner->flags = flags & KDBUS_NAME_SAVED_MASK; -+ owner->conn = conn; -+ owner->name = name; -+ list_add_tail(&owner->conn_entry, &conn->names_list); -+ INIT_LIST_HEAD(&owner->name_entry); - -- return e; -+ ++conn->name_count; -+ return owner; - } - --static void kdbus_name_entry_free(struct kdbus_name_entry *e) -+static void kdbus_name_owner_free(struct kdbus_name_owner *owner) - { -- if (!e) -+ if (!owner) - return; - -- WARN_ON(!list_empty(&e->conn_entry)); -- WARN_ON(!list_empty(&e->queue)); -- WARN_ON(e->activator); -- WARN_ON(e->conn); -- -- hash_del(&e->hentry); -- kfree(e); -+ WARN_ON(kdbus_name_owner_is_used(owner)); -+ --owner->conn->name_count; -+ list_del(&owner->conn_entry); -+ kfree(owner); - } - --static void kdbus_name_entry_set_owner(struct kdbus_name_entry *e, -- struct kdbus_conn *conn, u64 flags) -+static struct kdbus_name_owner * -+kdbus_name_owner_find(struct kdbus_name_entry *name, struct kdbus_conn *conn) - { -- WARN_ON(e->conn); -+ struct kdbus_name_owner *owner; - -- e->conn = kdbus_conn_ref(conn); -- e->flags = flags; -- atomic_inc(&conn->name_count); -- list_add_tail(&e->conn_entry, &e->conn->names_list); -+ /* -+ * Use conn->names_list over name->queue to make sure boundaries of -+ * this linear search are controlled by the connection itself. -+ * Furthermore, this will find normal owners as well as activators -+ * without any additional code. -+ */ -+ list_for_each_entry(owner, &conn->names_list, conn_entry) -+ if (owner->name == name) -+ return owner; -+ -+ return NULL; - } - --static void kdbus_name_entry_remove_owner(struct kdbus_name_entry *e) -+static bool kdbus_name_entry_is_used(struct kdbus_name_entry *name) - { -- WARN_ON(!e->conn); -- -- list_del_init(&e->conn_entry); -- atomic_dec(&e->conn->name_count); -- e->flags = 0; -- e->conn = kdbus_conn_unref(e->conn); -+ return !list_empty(&name->queue) || name->activator; - } - --static void kdbus_name_entry_replace_owner(struct kdbus_name_entry *e, -- struct kdbus_conn *conn, u64 flags) -+static struct kdbus_name_owner * -+kdbus_name_entry_first(struct kdbus_name_entry *name) - { -- if (WARN_ON(!e->conn) || WARN_ON(conn == e->conn)) -- return; -- -- kdbus_notify_name_change(conn->ep->bus, KDBUS_ITEM_NAME_CHANGE, -- e->conn->id, conn->id, -- e->flags, flags, e->name); -- kdbus_name_entry_remove_owner(e); -- kdbus_name_entry_set_owner(e, conn, flags); -+ return list_first_entry_or_null(&name->queue, struct kdbus_name_owner, -+ name_entry); - } - --/** -- * 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) -+static struct kdbus_name_entry * -+kdbus_name_entry_new(struct kdbus_name_registry *r, u32 hash, -+ const char *name_str) - { -- bool dot, found_dot = false; -- const char *q; -+ struct kdbus_name_entry *name; -+ size_t namelen; - -- for (dot = true, q = p; *q; q++) { -- if (*q == '.') { -- if (dot) -- return false; -+ lockdep_assert_held(&r->rwlock); - -- found_dot = true; -- dot = true; -- } else { -- bool good; -+ namelen = strlen(name_str); - -- good = isalpha(*q) || (!dot && isdigit(*q)) || -- *q == '_' || *q == '-' || -- (allow_wildcard && dot && -- *q == '*' && *(q + 1) == '\0'); -+ name = kmalloc(sizeof(*name) + namelen + 1, GFP_KERNEL); -+ if (!name) -+ return ERR_PTR(-ENOMEM); - -- if (!good) -- return false; -+ name->name_id = ++r->name_seq_last; -+ name->activator = NULL; -+ INIT_LIST_HEAD(&name->queue); -+ hash_add(r->entries_hash, &name->hentry, hash); -+ memcpy(name->name, name_str, namelen + 1); - -- dot = false; -- } -- } -+ return name; -+} - -- if (q - p > KDBUS_NAME_MAX_LEN) -- return false; -+static void kdbus_name_entry_free(struct kdbus_name_entry *name) -+{ -+ if (!name) -+ return; - -- if (dot) -- return false; -+ WARN_ON(kdbus_name_entry_is_used(name)); -+ hash_del(&name->hentry); -+ kfree(name); -+} - -- if (!found_dot) -- return false; -+static struct kdbus_name_entry * -+kdbus_name_entry_find(struct kdbus_name_registry *r, u32 hash, -+ const char *name_str) -+{ -+ struct kdbus_name_entry *name; - -- return true; -+ lockdep_assert_held(&r->rwlock); -+ -+ hash_for_each_possible(r->entries_hash, name, hentry, hash) -+ if (!strcmp(name->name, name_str)) -+ return name; -+ -+ return NULL; - } - - /** -@@ -218,32 +179,19 @@ struct kdbus_name_registry *kdbus_name_registry_new(void) - } - - /** -- * kdbus_name_registry_free() - drop a name reg's reference -- * @reg: The name registry, may be %NULL -+ * kdbus_name_registry_free() - free name registry -+ * @r: name registry to free, or NULL - * -- * Cleanup the name registry's internal structures. -+ * Free a name registry and cleanup all internal objects. This is a no-op if -+ * you pass NULL as registry. - */ --void kdbus_name_registry_free(struct kdbus_name_registry *reg) -+void kdbus_name_registry_free(struct kdbus_name_registry *r) - { -- if (!reg) -+ if (!r) - return; - -- WARN_ON(!hash_empty(reg->entries_hash)); -- kfree(reg); --} -- --static struct kdbus_name_entry * --kdbus_name_find(struct kdbus_name_registry *reg, u32 hash, const char *name) --{ -- struct kdbus_name_entry *e; -- -- lockdep_assert_held(®->rwlock); -- -- hash_for_each_possible(reg->entries_hash, e, hentry, hash) -- if (strcmp(e->name, name) == 0) -- return e; -- -- return NULL; -+ WARN_ON(!hash_empty(r->entries_hash)); -+ kfree(r); - } - - /** -@@ -260,169 +208,271 @@ kdbus_name_find(struct kdbus_name_registry *reg, u32 hash, const char *name) - struct kdbus_name_entry * - kdbus_name_lookup_unlocked(struct kdbus_name_registry *reg, const char *name) - { -- return kdbus_name_find(reg, kdbus_strhash(name), name); -+ return kdbus_name_entry_find(reg, kdbus_strhash(name), name); - } - --/** -- * 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_*) -- * @return_flags: Pointer to return flags for the acquired name -- * (KDBUS_NAME_*), may be %NULL -- * -- * 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, u64 *return_flags) -+static int kdbus_name_become_activator(struct kdbus_name_owner *owner) - { -- struct kdbus_name_entry *e; -- u64 rflags = 0; -- int ret = 0; -- u32 hash; -- -- kdbus_conn_assert_active(conn); -+ if (kdbus_name_owner_is_used(owner)) -+ return -EALREADY; -+ if (owner->name->activator) -+ return -EEXIST; -+ -+ owner->name->activator = owner; -+ owner->flags |= KDBUS_NAME_ACTIVATOR; -+ -+ if (kdbus_name_entry_first(owner->name)) -+ owner->flags |= KDBUS_NAME_IN_QUEUE; -+ else -+ kdbus_notify_name_change(owner->conn->ep->bus, -+ KDBUS_ITEM_NAME_ADD, -+ 0, owner->conn->id, -+ 0, owner->flags, -+ owner->name->name); - -- down_write(®->rwlock); -- -- if (!kdbus_conn_policy_own_name(conn, current_cred(), name)) { -- ret = -EPERM; -- goto exit_unlock; -- } -- -- hash = kdbus_strhash(name); -- e = kdbus_name_find(reg, hash, name); -- if (!e) { -- /* claim new name */ -+ return 0; -+} - -- if (conn->activator_of) { -- ret = -EINVAL; -- goto exit_unlock; -- } -+static int kdbus_name_update(struct kdbus_name_owner *owner, u64 flags) -+{ -+ struct kdbus_name_owner *primary, *activator; -+ struct kdbus_name_entry *name; -+ struct kdbus_bus *bus; -+ int ret = 0; - -- e = kdbus_name_entry_new(reg, hash, name); -- if (IS_ERR(e)) { -- ret = PTR_ERR(e); -- goto exit_unlock; -+ name = owner->name; -+ bus = owner->conn->ep->bus; -+ primary = kdbus_name_entry_first(name); -+ activator = name->activator; -+ -+ /* cannot be activator and acquire a name */ -+ if (owner == activator) -+ return -EUCLEAN; -+ -+ /* update saved flags */ -+ owner->flags = flags & KDBUS_NAME_SAVED_MASK; -+ -+ if (!primary) { -+ /* -+ * No primary owner (but maybe an activator). Take over the -+ * name. -+ */ -+ -+ list_add(&owner->name_entry, &name->queue); -+ -+ /* move messages to new owner on activation */ -+ if (activator) { -+ kdbus_conn_move_messages(owner->conn, activator->conn, -+ name->name_id); -+ kdbus_notify_name_change(bus, KDBUS_ITEM_NAME_CHANGE, -+ activator->conn->id, owner->conn->id, -+ activator->flags, owner->flags, -+ name->name); -+ activator->flags |= KDBUS_NAME_IN_QUEUE; -+ } else { -+ kdbus_notify_name_change(bus, KDBUS_ITEM_NAME_ADD, -+ 0, owner->conn->id, -+ 0, owner->flags, -+ name->name); - } - -- if (kdbus_conn_is_activator(conn)) { -- e->activator = kdbus_conn_ref(conn); -- conn->activator_of = e; -- } -+ } else if (owner == primary) { -+ /* -+ * Already the primary owner of the name, flags were already -+ * updated. Nothing to do. -+ * For compatibility, we have to return -EALREADY. -+ */ - -- kdbus_name_entry_set_owner(e, conn, flags); -- kdbus_notify_name_change(e->conn->ep->bus, KDBUS_ITEM_NAME_ADD, -- 0, e->conn->id, 0, e->flags, e->name); -- } else if (e->conn == conn || e == conn->activator_of) { -- /* connection already owns that name */ - ret = -EALREADY; -- } else if (kdbus_conn_is_activator(conn)) { -- /* activator claims existing name */ - -- if (conn->activator_of) { -- ret = -EINVAL; /* multiple names not allowed */ -- } else if (e->activator) { -- ret = -EEXIST; /* only one activator per name */ -+ } else if ((primary->flags & KDBUS_NAME_ALLOW_REPLACEMENT) && -+ (flags & KDBUS_NAME_REPLACE_EXISTING)) { -+ /* -+ * We're not the primary owner but can replace it. Move us -+ * ahead of the primary owner and acquire the name (possibly -+ * skipping queued owners ahead of us). -+ */ -+ -+ list_del_init(&owner->name_entry); -+ list_add(&owner->name_entry, &name->queue); -+ -+ kdbus_notify_name_change(bus, KDBUS_ITEM_NAME_CHANGE, -+ primary->conn->id, owner->conn->id, -+ primary->flags, owner->flags, -+ name->name); -+ -+ /* requeue old primary, or drop if queueing not wanted */ -+ if (primary->flags & KDBUS_NAME_QUEUE) { -+ primary->flags |= KDBUS_NAME_IN_QUEUE; - } else { -- e->activator = kdbus_conn_ref(conn); -- conn->activator_of = e; -- } -- } else if (e->flags & KDBUS_NAME_ACTIVATOR) { -- /* claim name of an activator */ -- -- kdbus_conn_move_messages(conn, e->activator, 0); -- kdbus_name_entry_replace_owner(e, conn, flags); -- } else if ((flags & KDBUS_NAME_REPLACE_EXISTING) && -- (e->flags & KDBUS_NAME_ALLOW_REPLACEMENT)) { -- /* claim name of a previous owner */ -- -- if (e->flags & KDBUS_NAME_QUEUE) { -- /* move owner back to queue if they asked for it */ -- ret = kdbus_name_pending_new(e, e->conn, e->flags); -- if (ret < 0) -- goto exit_unlock; -+ list_del_init(&primary->name_entry); -+ kdbus_name_owner_free(primary); - } - -- kdbus_name_entry_replace_owner(e, conn, flags); - } else if (flags & KDBUS_NAME_QUEUE) { -- /* add to waiting-queue of the name */ -- -- ret = kdbus_name_pending_new(e, conn, flags); -- if (ret >= 0) -- /* tell the caller that we queued it */ -- rflags |= KDBUS_NAME_IN_QUEUE; -+ /* -+ * Name is already occupied and we cannot take it over, but -+ * queuing is allowed. Put us silently on the queue, if not -+ * already there. -+ */ -+ -+ owner->flags |= KDBUS_NAME_IN_QUEUE; -+ if (!kdbus_name_owner_is_used(owner)) -+ list_add_tail(&owner->name_entry, &name->queue); -+ } else if (kdbus_name_owner_is_used(owner)) { -+ /* -+ * Already queued on name, but re-queueing was not requested. -+ * Make sure to unlink it from the name, the caller is -+ * responsible for releasing it. -+ */ -+ -+ list_del_init(&owner->name_entry); -+ ret = -EEXIST; - } else { -- /* the name is busy, return a failure */ -+ /* -+ * Name is already claimed and queueing is not requested. -+ * Return error to the caller. -+ */ -+ - ret = -EEXIST; - } - -- if (ret == 0 && return_flags) -- *return_flags = rflags; -+ return ret; -+} - --exit_unlock: -+int kdbus_name_acquire(struct kdbus_name_registry *reg, -+ struct kdbus_conn *conn, const char *name_str, -+ u64 flags, u64 *return_flags) -+{ -+ struct kdbus_name_entry *name = NULL; -+ struct kdbus_name_owner *owner = NULL; -+ u32 hash; -+ int ret; -+ -+ kdbus_conn_assert_active(conn); -+ -+ down_write(®->rwlock); -+ -+ /* -+ * Verify the connection has access to the name. Do this before testing -+ * for double-acquisitions and other errors to make sure we do not leak -+ * information about this name through possible custom endpoints. -+ */ -+ if (!kdbus_conn_policy_own_name(conn, current_cred(), name_str)) { -+ ret = -EPERM; -+ goto exit; -+ } -+ -+ /* -+ * Lookup the name entry. If it already exists, search for an owner -+ * entry as we might already own that name. If either does not exist, -+ * we will allocate a fresh one. -+ */ -+ hash = kdbus_strhash(name_str); -+ name = kdbus_name_entry_find(reg, hash, name_str); -+ if (name) { -+ owner = kdbus_name_owner_find(name, conn); -+ } else { -+ name = kdbus_name_entry_new(reg, hash, name_str); -+ if (IS_ERR(name)) { -+ ret = PTR_ERR(name); -+ name = NULL; -+ goto exit; -+ } -+ } -+ -+ /* create name owner object if not already queued */ -+ if (!owner) { -+ owner = kdbus_name_owner_new(conn, name, flags); -+ if (IS_ERR(owner)) { -+ ret = PTR_ERR(owner); -+ owner = NULL; -+ goto exit; -+ } -+ } -+ -+ if (flags & KDBUS_NAME_ACTIVATOR) -+ ret = kdbus_name_become_activator(owner); -+ else -+ ret = kdbus_name_update(owner, flags); -+ if (ret < 0) -+ goto exit; -+ -+ if (return_flags) -+ *return_flags = owner->flags; -+ -+exit: -+ if (owner && !kdbus_name_owner_is_used(owner)) -+ kdbus_name_owner_free(owner); -+ if (name && !kdbus_name_entry_is_used(name)) -+ kdbus_name_entry_free(name); - up_write(®->rwlock); - kdbus_notify_flush(conn->ep->bus); - return ret; - } - --static void kdbus_name_release_unlocked(struct kdbus_name_registry *reg, -- struct kdbus_name_entry *e) -+static void kdbus_name_release_unlocked(struct kdbus_name_owner *owner) - { -- struct kdbus_name_pending *p; -- -- lockdep_assert_held(®->rwlock); -- -- p = list_first_entry_or_null(&e->queue, struct kdbus_name_pending, -- name_entry); -- -- if (p) { -- /* give it to first active waiter in the queue */ -- kdbus_name_entry_replace_owner(e, p->conn, p->flags); -- kdbus_name_pending_free(p); -- } else if (e->activator && e->activator != e->conn) { -- /* hand it back to an active activator connection */ -- kdbus_conn_move_messages(e->activator, e->conn, e->name_id); -- kdbus_name_entry_replace_owner(e, e->activator, -- KDBUS_NAME_ACTIVATOR); -- } else { -- /* release the name */ -- kdbus_notify_name_change(e->conn->ep->bus, -- KDBUS_ITEM_NAME_REMOVE, -- e->conn->id, 0, e->flags, 0, e->name); -- kdbus_name_entry_remove_owner(e); -- kdbus_name_entry_free(e); -+ struct kdbus_name_owner *primary, *next; -+ struct kdbus_name_entry *name; -+ -+ name = owner->name; -+ primary = kdbus_name_entry_first(name); -+ -+ list_del_init(&owner->name_entry); -+ if (owner == name->activator) -+ name->activator = NULL; -+ -+ if (!primary || owner == primary) { -+ next = kdbus_name_entry_first(name); -+ if (!next) -+ next = name->activator; -+ -+ if (next) { -+ /* hand to next in queue */ -+ next->flags &= ~KDBUS_NAME_IN_QUEUE; -+ if (next == name->activator) -+ kdbus_conn_move_messages(next->conn, -+ owner->conn, -+ name->name_id); -+ -+ kdbus_notify_name_change(owner->conn->ep->bus, -+ KDBUS_ITEM_NAME_CHANGE, -+ owner->conn->id, next->conn->id, -+ owner->flags, next->flags, -+ name->name); -+ } else { -+ kdbus_notify_name_change(owner->conn->ep->bus, -+ KDBUS_ITEM_NAME_REMOVE, -+ owner->conn->id, 0, -+ owner->flags, 0, -+ name->name); -+ } - } -+ -+ kdbus_name_owner_free(owner); -+ if (!kdbus_name_entry_is_used(name)) -+ kdbus_name_entry_free(name); - } - - static int kdbus_name_release(struct kdbus_name_registry *reg, - struct kdbus_conn *conn, -- const char *name) -+ const char *name_str) - { -- struct kdbus_name_pending *p; -- struct kdbus_name_entry *e; -+ struct kdbus_name_owner *owner; -+ struct kdbus_name_entry *name; - int ret = 0; - - down_write(®->rwlock); -- e = kdbus_name_find(reg, kdbus_strhash(name), name); -- if (!e) { -- ret = -ESRCH; -- } else if (e->conn == conn) { -- kdbus_name_release_unlocked(reg, e); -+ name = kdbus_name_entry_find(reg, kdbus_strhash(name_str), name_str); -+ if (name) { -+ owner = kdbus_name_owner_find(name, conn); -+ if (owner) -+ kdbus_name_release_unlocked(owner); -+ else -+ ret = -EADDRINUSE; - } else { -- ret = -EADDRINUSE; -- list_for_each_entry(p, &e->queue, name_entry) { -- if (p->conn == conn) { -- kdbus_name_pending_free(p); -- ret = 0; -- break; -- } -- } -+ ret = -ESRCH; - } - up_write(®->rwlock); - -@@ -438,33 +488,74 @@ static int kdbus_name_release(struct kdbus_name_registry *reg, - void kdbus_name_release_all(struct kdbus_name_registry *reg, - struct kdbus_conn *conn) - { -- struct kdbus_name_pending *p; -- struct kdbus_conn *activator = NULL; -- struct kdbus_name_entry *e; -+ struct kdbus_name_owner *owner; - - down_write(®->rwlock); - -- if (conn->activator_of) { -- activator = conn->activator_of->activator; -- conn->activator_of->activator = NULL; -- } -- -- while ((p = list_first_entry_or_null(&conn->names_queue_list, -- struct kdbus_name_pending, -- conn_entry))) -- kdbus_name_pending_free(p); -- while ((e = list_first_entry_or_null(&conn->names_list, -- struct kdbus_name_entry, -- conn_entry))) -- kdbus_name_release_unlocked(reg, e); -+ while ((owner = list_first_entry_or_null(&conn->names_list, -+ struct kdbus_name_owner, -+ conn_entry))) -+ kdbus_name_release_unlocked(owner); - - up_write(®->rwlock); - -- kdbus_conn_unref(activator); - kdbus_notify_flush(conn->ep->bus); - } - - /** -+ * 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_cmd_name_acquire() - handle KDBUS_CMD_NAME_ACQUIRE - * @conn: connection to operate on - * @argp: command payload -@@ -503,20 +594,9 @@ int kdbus_cmd_name_acquire(struct kdbus_conn *conn, void __user *argp) - goto exit; - } - -- /* -- * 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 exit_dec; -- } -- - ret = kdbus_name_acquire(conn->ep->bus->name_registry, conn, item_name, - cmd->flags, &cmd->return_flags); - --exit_dec: -- atomic_dec(&conn->name_count); - exit: - return kdbus_args_clear(&args, ret); - } -@@ -559,7 +639,7 @@ static int kdbus_list_write(struct kdbus_conn *conn, - struct kdbus_conn *c, - struct kdbus_pool_slice *slice, - size_t *pos, -- struct kdbus_name_entry *e, -+ struct kdbus_name_owner *o, - bool write) - { - struct kvec kvec[4]; -@@ -580,22 +660,22 @@ static int kdbus_list_write(struct kdbus_conn *conn, - u64 flags; - } h = {}; - -- if (e && !kdbus_conn_policy_see_name_unlocked(conn, current_cred(), -- e->name)) -+ if (o && !kdbus_conn_policy_see_name_unlocked(conn, current_cred(), -+ o->name->name)) - return 0; - - kdbus_kvec_set(&kvec[cnt++], &info, sizeof(info), &info.size); - - /* append name */ -- if (e) { -- size_t slen = strlen(e->name) + 1; -+ if (o) { -+ size_t slen = strlen(o->name->name) + 1; - - h.size = offsetof(struct kdbus_item, name.name) + slen; - h.type = KDBUS_ITEM_OWNED_NAME; -- h.flags = e->flags; -+ h.flags = o->flags; - - kdbus_kvec_set(&kvec[cnt++], &h, sizeof(h), &info.size); -- kdbus_kvec_set(&kvec[cnt++], e->name, slen, &info.size); -+ kdbus_kvec_set(&kvec[cnt++], o->name->name, slen, &info.size); - cnt += !!kdbus_kvec_pad(&kvec[cnt], &info.size); - } - -@@ -625,63 +705,52 @@ static int kdbus_list_all(struct kdbus_conn *conn, u64 flags, - if (kdbus_conn_is_monitor(c)) - continue; - -- /* skip activators */ -- if (!(flags & KDBUS_LIST_ACTIVATORS) && -- kdbus_conn_is_activator(c)) -- continue; -- - /* all names the connection owns */ -- if (flags & (KDBUS_LIST_NAMES | KDBUS_LIST_ACTIVATORS)) { -- struct kdbus_name_entry *e; -+ if (flags & (KDBUS_LIST_NAMES | -+ KDBUS_LIST_ACTIVATORS | -+ KDBUS_LIST_QUEUED)) { -+ struct kdbus_name_owner *o; - -- list_for_each_entry(e, &c->names_list, conn_entry) { -- struct kdbus_conn *a = e->activator; -+ list_for_each_entry(o, &c->names_list, conn_entry) { -+ if (o->flags & KDBUS_NAME_ACTIVATOR) { -+ if (!(flags & KDBUS_LIST_ACTIVATORS)) -+ continue; - -- if ((flags & KDBUS_LIST_ACTIVATORS) && -- a && a != c) { -- ret = kdbus_list_write(conn, a, slice, -- &p, e, write); -+ ret = kdbus_list_write(conn, c, slice, -+ &p, o, write); - if (ret < 0) { - mutex_unlock(&c->lock); - return ret; - } - - added = true; -- } -+ } else if (o->flags & KDBUS_NAME_IN_QUEUE) { -+ if (!(flags & KDBUS_LIST_QUEUED)) -+ continue; - -- if (flags & KDBUS_LIST_NAMES || -- kdbus_conn_is_activator(c)) { - ret = kdbus_list_write(conn, c, slice, -- &p, e, write); -+ &p, o, write); - if (ret < 0) { - mutex_unlock(&c->lock); - return ret; - } - - added = true; -- } -- } -- } -+ } else if (flags & KDBUS_LIST_NAMES) { -+ ret = kdbus_list_write(conn, c, slice, -+ &p, o, write); -+ if (ret < 0) { -+ mutex_unlock(&c->lock); -+ return ret; -+ } - -- /* queue of names the connection is currently waiting for */ -- if (flags & KDBUS_LIST_QUEUED) { -- struct kdbus_name_pending *q; -- -- list_for_each_entry(q, &c->names_queue_list, -- conn_entry) { -- ret = kdbus_list_write(conn, c, slice, &p, -- q->name, write); -- if (ret < 0) { -- mutex_unlock(&c->lock); -- return ret; -+ added = true; - } -- -- added = true; - } - } - - /* nothing added so far, just add the unique ID */ -- if (!added && flags & KDBUS_LIST_UNIQUE) { -+ if (!added && (flags & KDBUS_LIST_UNIQUE)) { - ret = kdbus_list_write(conn, c, slice, &p, NULL, write); - if (ret < 0) - return ret; -diff --git a/ipc/kdbus/names.h b/ipc/kdbus/names.h -index 3dd2589293e0..edac59ddd8ee 100644 ---- a/ipc/kdbus/names.h -+++ b/ipc/kdbus/names.h -@@ -18,6 +18,10 @@ - #include <linux/hashtable.h> - #include <linux/rwsem.h> - -+struct kdbus_name_entry; -+struct kdbus_name_owner; -+struct kdbus_name_registry; -+ - /** - * struct kdbus_name_registry - names registered for a bus - * @entries_hash: Map of entries -@@ -32,27 +36,37 @@ struct kdbus_name_registry { - - /** - * struct kdbus_name_entry - well-know name entry -- * @name_id: Sequence number of name entry to be able to uniquely -+ * @name_id: sequence number of name entry to be able to uniquely - * identify a name over its registration lifetime -- * @flags: KDBUS_NAME_* flags -- * @conn: Connection owning the name -- * @activator: Connection of the activator queuing incoming messages -- * @queue: List of queued connections -- * @conn_entry: Entry in connection -- * @hentry: Entry in registry map -- * @name: The well-known name -+ * @activator: activator of this name, or NULL -+ * @queue: list of queued owners -+ * @hentry: entry in registry map -+ * @name: well-known name - */ - struct kdbus_name_entry { - u64 name_id; -- u64 flags; -- struct kdbus_conn *conn; -- struct kdbus_conn *activator; -+ struct kdbus_name_owner *activator; - struct list_head queue; -- struct list_head conn_entry; - struct hlist_node hentry; - char name[]; - }; - -+/** -+ * struct kdbus_name_owner - owner of a well-known name -+ * @flags: KDBUS_NAME_* flags of this owner -+ * @conn: connection owning the name -+ * @name: name that is owned -+ * @conn_entry: link into @conn -+ * @name_entry: link into @name -+ */ -+struct kdbus_name_owner { -+ u64 flags; -+ struct kdbus_conn *conn; -+ struct kdbus_name_entry *name; -+ struct list_head conn_entry; -+ struct list_head name_entry; -+}; -+ - bool kdbus_name_is_valid(const char *p, bool allow_wildcard); - - struct kdbus_name_registry *kdbus_name_registry_new(void); -@@ -71,4 +85,21 @@ int kdbus_cmd_name_acquire(struct kdbus_conn *conn, void __user *argp); - int kdbus_cmd_name_release(struct kdbus_conn *conn, void __user *argp); - int kdbus_cmd_list(struct kdbus_conn *conn, void __user *argp); - -+/** -+ * kdbus_name_get_owner() - get current owner of a name -+ * @name: name to get current owner of -+ * -+ * This returns a pointer to the current owner of a name (or its activator if -+ * there is no owner). The caller must make sure @name is valid and does not -+ * vanish. -+ * -+ * Return: Pointer to current owner or NULL if there is none. -+ */ -+static inline struct kdbus_name_owner * -+kdbus_name_get_owner(struct kdbus_name_entry *name) -+{ -+ return list_first_entry_or_null(&name->queue, struct kdbus_name_owner, -+ name_entry) ? : name->activator; -+} -+ - #endif --- -2.4.3 - - -From 0486b859f05aa75d59e2c1a4f62053c1a1151d35 Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Fri, 7 Aug 2015 16:36:34 +0200 -Subject: [PATCH 126/132] kdbus: inform caller about exact updates on - NAME_ACQUIRE - -This adds two new return flags for KDBUS_CMD_NAME_ACQUIRE: - - * The KDBUS_NAME_PRIMARY flag is set for a name if, and only if, the - connection is currently the primary owner of a name. It is thus the - negation of KDBUS_NAME_IN_QUEUE, but is required to distinguish the - case from the situation where the connection is neither queued nor the - primary owner of a name. - Additionally, this flag is included in name listings and events. - - * The KDBUS_NAME_ACQUIRED flag is exclusively used as return flag for - KDBUS_CMD_NAME_ACQUIRE to let the caller know whether _this_ exact - call actually queued the connection on the name. If the flag is not - set, the connection was either already queued and only the flags were - updated, or the connection is not queued at all. - -This information was previously available to the caller via error-codes -from KDBUS_CMD_NAME_ACQUIRE. However, in some situations we actually -modify kernel state but return an error. This is considered bad style and -we really need to avoid this. Hence, these two new flags allow us to -avoid returning errors, but still inform the caller about the exact -conditions of the execution. - -Reviewed-by: Daniel Mack <daniel@zonque.org> -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - include/uapi/linux/kdbus.h | 4 ++++ - ipc/kdbus/names.c | 38 ++++++++++++++++++++++++++++---------- - 2 files changed, 32 insertions(+), 10 deletions(-) - -diff --git a/include/uapi/linux/kdbus.h b/include/uapi/linux/kdbus.h -index ecffc6b13c3e..4fc44cb1d4a8 100644 ---- a/include/uapi/linux/kdbus.h -+++ b/include/uapi/linux/kdbus.h -@@ -854,6 +854,8 @@ enum kdbus_make_flags { - * @KDBUS_NAME_QUEUE: Name should be queued if busy - * @KDBUS_NAME_IN_QUEUE: Name is queued - * @KDBUS_NAME_ACTIVATOR: Name is owned by a activator connection -+ * @KDBUS_NAME_PRIMARY: Primary owner of the name -+ * @KDBUS_NAME_ACQUIRED: Name was acquired/queued _now_ - */ - enum kdbus_name_flags { - KDBUS_NAME_REPLACE_EXISTING = 1ULL << 0, -@@ -861,6 +863,8 @@ enum kdbus_name_flags { - KDBUS_NAME_QUEUE = 1ULL << 2, - KDBUS_NAME_IN_QUEUE = 1ULL << 3, - KDBUS_NAME_ACTIVATOR = 1ULL << 4, -+ KDBUS_NAME_PRIMARY = 1ULL << 5, -+ KDBUS_NAME_ACQUIRED = 1ULL << 6, - }; - - /** -diff --git a/ipc/kdbus/names.c b/ipc/kdbus/names.c -index 7a6e61c35ebf..a47ee5452158 100644 ---- a/ipc/kdbus/names.c -+++ b/ipc/kdbus/names.c -@@ -211,7 +211,8 @@ kdbus_name_lookup_unlocked(struct kdbus_name_registry *reg, const char *name) - return kdbus_name_entry_find(reg, kdbus_strhash(name), name); - } - --static int kdbus_name_become_activator(struct kdbus_name_owner *owner) -+static int kdbus_name_become_activator(struct kdbus_name_owner *owner, -+ u64 *return_flags) - { - if (kdbus_name_owner_is_used(owner)) - return -EALREADY; -@@ -221,23 +222,30 @@ static int kdbus_name_become_activator(struct kdbus_name_owner *owner) - owner->name->activator = owner; - owner->flags |= KDBUS_NAME_ACTIVATOR; - -- if (kdbus_name_entry_first(owner->name)) -+ if (kdbus_name_entry_first(owner->name)) { - owner->flags |= KDBUS_NAME_IN_QUEUE; -- else -+ } else { -+ owner->flags |= KDBUS_NAME_PRIMARY; - kdbus_notify_name_change(owner->conn->ep->bus, - KDBUS_ITEM_NAME_ADD, - 0, owner->conn->id, - 0, owner->flags, - owner->name->name); -+ } -+ -+ if (return_flags) -+ *return_flags = owner->flags | KDBUS_NAME_ACQUIRED; - - return 0; - } - --static int kdbus_name_update(struct kdbus_name_owner *owner, u64 flags) -+static int kdbus_name_update(struct kdbus_name_owner *owner, u64 flags, -+ u64 *return_flags) - { - struct kdbus_name_owner *primary, *activator; - struct kdbus_name_entry *name; - struct kdbus_bus *bus; -+ u64 nflags = 0; - int ret = 0; - - name = owner->name; -@@ -259,6 +267,8 @@ static int kdbus_name_update(struct kdbus_name_owner *owner, u64 flags) - */ - - list_add(&owner->name_entry, &name->queue); -+ owner->flags |= KDBUS_NAME_PRIMARY; -+ nflags |= KDBUS_NAME_ACQUIRED; - - /* move messages to new owner on activation */ - if (activator) { -@@ -268,6 +278,7 @@ static int kdbus_name_update(struct kdbus_name_owner *owner, u64 flags) - activator->conn->id, owner->conn->id, - activator->flags, owner->flags, - name->name); -+ activator->flags &= ~KDBUS_NAME_PRIMARY; - activator->flags |= KDBUS_NAME_IN_QUEUE; - } else { - kdbus_notify_name_change(bus, KDBUS_ITEM_NAME_ADD, -@@ -283,6 +294,7 @@ static int kdbus_name_update(struct kdbus_name_owner *owner, u64 flags) - * For compatibility, we have to return -EALREADY. - */ - -+ owner->flags |= KDBUS_NAME_PRIMARY; - ret = -EALREADY; - - } else if ((primary->flags & KDBUS_NAME_ALLOW_REPLACEMENT) && -@@ -295,6 +307,8 @@ static int kdbus_name_update(struct kdbus_name_owner *owner, u64 flags) - - list_del_init(&owner->name_entry); - list_add(&owner->name_entry, &name->queue); -+ owner->flags |= KDBUS_NAME_PRIMARY; -+ nflags |= KDBUS_NAME_ACQUIRED; - - kdbus_notify_name_change(bus, KDBUS_ITEM_NAME_CHANGE, - primary->conn->id, owner->conn->id, -@@ -303,6 +317,7 @@ static int kdbus_name_update(struct kdbus_name_owner *owner, u64 flags) - - /* requeue old primary, or drop if queueing not wanted */ - if (primary->flags & KDBUS_NAME_QUEUE) { -+ primary->flags &= ~KDBUS_NAME_PRIMARY; - primary->flags |= KDBUS_NAME_IN_QUEUE; - } else { - list_del_init(&primary->name_entry); -@@ -317,8 +332,10 @@ static int kdbus_name_update(struct kdbus_name_owner *owner, u64 flags) - */ - - owner->flags |= KDBUS_NAME_IN_QUEUE; -- if (!kdbus_name_owner_is_used(owner)) -+ if (!kdbus_name_owner_is_used(owner)) { - list_add_tail(&owner->name_entry, &name->queue); -+ nflags |= KDBUS_NAME_ACQUIRED; -+ } - } else if (kdbus_name_owner_is_used(owner)) { - /* - * Already queued on name, but re-queueing was not requested. -@@ -337,6 +354,9 @@ static int kdbus_name_update(struct kdbus_name_owner *owner, u64 flags) - ret = -EEXIST; - } - -+ if (return_flags) -+ *return_flags = owner->flags | nflags; -+ - return ret; - } - -@@ -392,15 +412,12 @@ int kdbus_name_acquire(struct kdbus_name_registry *reg, - } - - if (flags & KDBUS_NAME_ACTIVATOR) -- ret = kdbus_name_become_activator(owner); -+ ret = kdbus_name_become_activator(owner, return_flags); - else -- ret = kdbus_name_update(owner, flags); -+ ret = kdbus_name_update(owner, flags, return_flags); - if (ret < 0) - goto exit; - -- if (return_flags) -- *return_flags = owner->flags; -- - exit: - if (owner && !kdbus_name_owner_is_used(owner)) - kdbus_name_owner_free(owner); -@@ -431,6 +448,7 @@ static void kdbus_name_release_unlocked(struct kdbus_name_owner *owner) - if (next) { - /* hand to next in queue */ - next->flags &= ~KDBUS_NAME_IN_QUEUE; -+ next->flags |= KDBUS_NAME_PRIMARY; - if (next == name->activator) - kdbus_conn_move_messages(next->conn, - owner->conn, --- -2.4.3 - - -From 39b055e664cd7dd31a6de860f87f4728b4138590 Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Fri, 7 Aug 2015 16:36:35 +0200 -Subject: [PATCH 127/132] kdbus: never return <0 from ioctls if we changed - state - -If an ioctl() returns <0, user-space should be safe to assume it had no -effect on the state of any object. This might not be always possible, but -in kdbus we adhered to this rule. But there's one exception, namely -KDBUS_CMD_NAME_ACQUIRE. This call used to fail with -EALREADY if we owned -a name and tried to acquire it again. However, regardless whether the -name was already owned, the name-flags are updated according to the newly -provided flags. Hence, we change the state of name-ownership, but might -still return an error. - -This patch changes behavior and now returns 0 in those cases. User-space -still gets the same information (via return_flags), but will no longer be -told that the call failed. The tests reflect that and simply check for -KDBUS_NAME_ACQUIRED in 'return_flags'. - -Reviewed-by: Daniel Mack <daniel@zonque.org> -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - ipc/kdbus/names.c | 3 --- - tools/testing/selftests/kdbus/test-chat.c | 6 ++++-- - tools/testing/selftests/kdbus/test-names.c | 4 ---- - 3 files changed, 4 insertions(+), 9 deletions(-) - -diff --git a/ipc/kdbus/names.c b/ipc/kdbus/names.c -index a47ee5452158..bf44ca3f12b6 100644 ---- a/ipc/kdbus/names.c -+++ b/ipc/kdbus/names.c -@@ -291,11 +291,9 @@ static int kdbus_name_update(struct kdbus_name_owner *owner, u64 flags, - /* - * Already the primary owner of the name, flags were already - * updated. Nothing to do. -- * For compatibility, we have to return -EALREADY. - */ - - owner->flags |= KDBUS_NAME_PRIMARY; -- ret = -EALREADY; - - } else if ((primary->flags & KDBUS_NAME_ALLOW_REPLACEMENT) && - (flags & KDBUS_NAME_REPLACE_EXISTING)) { -@@ -344,7 +342,6 @@ static int kdbus_name_update(struct kdbus_name_owner *owner, u64 flags, - */ - - list_del_init(&owner->name_entry); -- ret = -EEXIST; - } else { - /* - * Name is already claimed and queueing is not requested. -diff --git a/tools/testing/selftests/kdbus/test-chat.c b/tools/testing/selftests/kdbus/test-chat.c -index 71a92d8b7c85..41e5b53fe0cc 100644 ---- a/tools/testing/selftests/kdbus/test-chat.c -+++ b/tools/testing/selftests/kdbus/test-chat.c -@@ -41,8 +41,10 @@ int kdbus_test_chat(struct kdbus_test_env *env) - ret = kdbus_name_acquire(conn_a, "foo.bar.double", NULL); - ASSERT_RETURN(ret == 0); - -- ret = kdbus_name_acquire(conn_a, "foo.bar.double", NULL); -- ASSERT_RETURN(ret == -EALREADY); -+ flags = 0; -+ ret = kdbus_name_acquire(conn_a, "foo.bar.double", &flags); -+ ASSERT_RETURN(ret == 0); -+ ASSERT_RETURN(!(flags & KDBUS_NAME_ACQUIRED)); - - ret = kdbus_name_release(conn_a, "foo.bar.double"); - ASSERT_RETURN(ret == 0); -diff --git a/tools/testing/selftests/kdbus/test-names.c b/tools/testing/selftests/kdbus/test-names.c -index fd4ac5adc6d2..9217465f3ff1 100644 ---- a/tools/testing/selftests/kdbus/test-names.c -+++ b/tools/testing/selftests/kdbus/test-names.c -@@ -143,10 +143,6 @@ int kdbus_test_name_conflict(struct kdbus_test_env *env) - ret = conn_is_name_owner(env->conn, name); - ASSERT_RETURN(ret == 0); - -- /* check that we can't acquire it again from the 1st connection */ -- ret = kdbus_name_acquire(env->conn, name, NULL); -- ASSERT_RETURN(ret == -EALREADY); -- - /* check that we also can't acquire it again from the 2nd connection */ - ret = kdbus_name_acquire(conn, name, NULL); - ASSERT_RETURN(ret == -EEXIST); --- -2.4.3 - - -From a36324913ff21d7a0989c52b7208e8d738e17d64 Mon Sep 17 00:00:00 2001 -From: Daniel Mack <daniel@zonque.org> -Date: Fri, 7 Aug 2015 16:36:36 +0200 -Subject: [PATCH 128/132] kdbus: selftests: add more name registry tests - -Add some more code for testing the name registry state. This can now be used -to track the state of queued names and per-name queing settings. - -Also add new tests to check the newly added KDBUS_NAME_PRIMARY and -KDBUS_NAME_ACQUIRED flags and name takeovers. - -Signed-off-by: Daniel Mack <daniel@zonque.org> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - tools/testing/selftests/kdbus/kdbus-test.c | 6 ++ - tools/testing/selftests/kdbus/kdbus-test.h | 1 + - tools/testing/selftests/kdbus/test-names.c | 133 +++++++++++++++++++++++------ - 3 files changed, 112 insertions(+), 28 deletions(-) - -diff --git a/tools/testing/selftests/kdbus/kdbus-test.c b/tools/testing/selftests/kdbus/kdbus-test.c -index db732e59650a..db57381570fa 100644 ---- a/tools/testing/selftests/kdbus/kdbus-test.c -+++ b/tools/testing/selftests/kdbus/kdbus-test.c -@@ -118,6 +118,12 @@ static const struct kdbus_test tests[] = { - .flags = TEST_CREATE_BUS | TEST_CREATE_CONN, - }, - { -+ .name = "name-takeover", -+ .desc = "takeover of names", -+ .func = kdbus_test_name_takeover, -+ .flags = TEST_CREATE_BUS | TEST_CREATE_CONN, -+ }, -+ { - .name = "message-basic", - .desc = "basic message handling", - .func = kdbus_test_message_basic, -diff --git a/tools/testing/selftests/kdbus/kdbus-test.h b/tools/testing/selftests/kdbus/kdbus-test.h -index a5c6ae81b81b..ee937f9a84dc 100644 ---- a/tools/testing/selftests/kdbus/kdbus-test.h -+++ b/tools/testing/selftests/kdbus/kdbus-test.h -@@ -72,6 +72,7 @@ int kdbus_test_monitor(struct kdbus_test_env *env); - int kdbus_test_name_basic(struct kdbus_test_env *env); - int kdbus_test_name_conflict(struct kdbus_test_env *env); - int kdbus_test_name_queue(struct kdbus_test_env *env); -+int kdbus_test_name_takeover(struct kdbus_test_env *env); - int kdbus_test_policy(struct kdbus_test_env *env); - int kdbus_test_policy_ns(struct kdbus_test_env *env); - int kdbus_test_policy_priv(struct kdbus_test_env *env); -diff --git a/tools/testing/selftests/kdbus/test-names.c b/tools/testing/selftests/kdbus/test-names.c -index 9217465f3ff1..e400dc86a2f5 100644 ---- a/tools/testing/selftests/kdbus/test-names.c -+++ b/tools/testing/selftests/kdbus/test-names.c -@@ -17,44 +17,68 @@ - #include "kdbus-enum.h" - #include "kdbus-test.h" - --static int conn_is_name_owner(const struct kdbus_conn *conn, -- const char *needle) -+struct test_name { -+ const char *name; -+ __u64 owner_id; -+ __u64 flags; -+}; -+ -+static bool conn_test_names(const struct kdbus_conn *conn, -+ const struct test_name *tests, -+ unsigned int n_tests) - { -- struct kdbus_cmd_list cmd_list = { .size = sizeof(cmd_list) }; -+ struct kdbus_cmd_list cmd_list = {}; - struct kdbus_info *name, *list; -- bool found = false; -+ unsigned int i; - int ret; - -- cmd_list.flags = KDBUS_LIST_NAMES; -+ cmd_list.size = sizeof(cmd_list); -+ cmd_list.flags = KDBUS_LIST_NAMES | -+ KDBUS_LIST_ACTIVATORS | -+ KDBUS_LIST_QUEUED; - - ret = kdbus_cmd_list(conn->fd, &cmd_list); - ASSERT_RETURN(ret == 0); - - list = (struct kdbus_info *)(conn->buf + cmd_list.offset); -- KDBUS_FOREACH(name, list, cmd_list.list_size) { -- struct kdbus_item *item; -- const char *n = NULL; - -- KDBUS_ITEM_FOREACH(item, name, items) { -- if (item->type == KDBUS_ITEM_OWNED_NAME) { -- n = item->name.name; -+ for (i = 0; i < n_tests; i++) { -+ const struct test_name *t = tests + i; -+ bool found = false; -+ -+ KDBUS_FOREACH(name, list, cmd_list.list_size) { -+ struct kdbus_item *item; - -- if (name->id == conn->id && -- n && strcmp(needle, n) == 0) { -+ KDBUS_ITEM_FOREACH(item, name, items) { -+ if (item->type != KDBUS_ITEM_OWNED_NAME || -+ strcmp(item->name.name, t->name) != 0) -+ continue; -+ -+ if (t->owner_id == name->id && -+ t->flags == item->name.flags) { - found = true; - break; - } - } - } - -- if (found) -- break; -+ if (!found) -+ return false; - } - -- ret = kdbus_free(conn, cmd_list.offset); -- ASSERT_RETURN(ret == 0); -+ return true; -+} -+ -+static bool conn_is_name_primary_owner(const struct kdbus_conn *conn, -+ const char *needle) -+{ -+ struct test_name t = { -+ .name = needle, -+ .owner_id = conn->id, -+ .flags = KDBUS_NAME_PRIMARY, -+ }; - -- return found ? 0 : -1; -+ return conn_test_names(conn, &t, 1); - } - - int kdbus_test_name_basic(struct kdbus_test_env *env) -@@ -90,15 +114,15 @@ int kdbus_test_name_basic(struct kdbus_test_env *env) - ret = kdbus_name_acquire(env->conn, name, NULL); - ASSERT_RETURN(ret == 0); - -- ret = conn_is_name_owner(env->conn, name); -- ASSERT_RETURN(ret == 0); -+ ret = conn_is_name_primary_owner(env->conn, name); -+ ASSERT_RETURN(ret == true); - - /* ... and release it again */ - ret = kdbus_name_release(env->conn, name); - ASSERT_RETURN(ret == 0); - -- ret = conn_is_name_owner(env->conn, name); -- ASSERT_RETURN(ret != 0); -+ ret = conn_is_name_primary_owner(env->conn, name); -+ ASSERT_RETURN(ret == false); - - /* check that we can't release it again */ - ret = kdbus_name_release(env->conn, name); -@@ -140,8 +164,8 @@ int kdbus_test_name_conflict(struct kdbus_test_env *env) - ret = kdbus_name_acquire(env->conn, name, NULL); - ASSERT_RETURN(ret == 0); - -- ret = conn_is_name_owner(env->conn, name); -- ASSERT_RETURN(ret == 0); -+ ret = conn_is_name_primary_owner(env->conn, name); -+ ASSERT_RETURN(ret == true); - - /* check that we also can't acquire it again from the 2nd connection */ - ret = kdbus_name_acquire(conn, name, NULL); -@@ -155,13 +179,14 @@ int kdbus_test_name_conflict(struct kdbus_test_env *env) - int kdbus_test_name_queue(struct kdbus_test_env *env) - { - struct kdbus_conn *conn; -+ struct test_name t[2]; - const char *name; - uint64_t flags; - int ret; - - name = "foo.bla.blaz"; - -- flags = KDBUS_NAME_ALLOW_REPLACEMENT; -+ flags = 0; - - /* create a 2nd connection */ - conn = kdbus_hello(env->buspath, 0, NULL, 0); -@@ -172,8 +197,8 @@ int kdbus_test_name_queue(struct kdbus_test_env *env) - ret = kdbus_name_acquire(env->conn, name, &flags); - ASSERT_RETURN(ret == 0); - -- ret = conn_is_name_owner(env->conn, name); -- ASSERT_RETURN(ret == 0); -+ ret = conn_is_name_primary_owner(env->conn, name); -+ ASSERT_RETURN(ret == true); - - /* queue the 2nd connection as waiting owner */ - flags = KDBUS_NAME_QUEUE; -@@ -181,14 +206,66 @@ int kdbus_test_name_queue(struct kdbus_test_env *env) - ASSERT_RETURN(ret == 0); - ASSERT_RETURN(flags & KDBUS_NAME_IN_QUEUE); - -+ t[0].name = name; -+ t[0].owner_id = env->conn->id; -+ t[0].flags = KDBUS_NAME_PRIMARY; -+ t[1].name = name; -+ t[1].owner_id = conn->id; -+ t[1].flags = KDBUS_NAME_QUEUE | KDBUS_NAME_IN_QUEUE; -+ ret = conn_test_names(conn, t, 2); -+ ASSERT_RETURN(ret == true); -+ - /* release name from 1st connection */ - ret = kdbus_name_release(env->conn, name); - ASSERT_RETURN(ret == 0); - - /* now the name should be owned by the 2nd connection */ -- ret = conn_is_name_owner(conn, name); -+ t[0].name = name; -+ t[0].owner_id = conn->id; -+ t[0].flags = KDBUS_NAME_PRIMARY | KDBUS_NAME_QUEUE; -+ ret = conn_test_names(conn, t, 1); -+ ASSERT_RETURN(ret == true); -+ -+ kdbus_conn_free(conn); -+ -+ return TEST_OK; -+} -+ -+int kdbus_test_name_takeover(struct kdbus_test_env *env) -+{ -+ struct kdbus_conn *conn; -+ struct test_name t; -+ const char *name; -+ uint64_t flags; -+ int ret; -+ -+ name = "foo.bla.blaz"; -+ -+ flags = KDBUS_NAME_ALLOW_REPLACEMENT; -+ -+ /* create a 2nd connection */ -+ conn = kdbus_hello(env->buspath, 0, NULL, 0); -+ ASSERT_RETURN(conn != NULL); -+ -+ /* acquire name for 1st connection */ -+ ret = kdbus_name_acquire(env->conn, name, &flags); - ASSERT_RETURN(ret == 0); - -+ t.name = name; -+ t.owner_id = env->conn->id; -+ t.flags = KDBUS_NAME_ALLOW_REPLACEMENT | KDBUS_NAME_PRIMARY; -+ ret = conn_test_names(conn, &t, 1); -+ ASSERT_RETURN(ret == true); -+ -+ /* now steal name with 2nd connection */ -+ flags = KDBUS_NAME_REPLACE_EXISTING; -+ ret = kdbus_name_acquire(conn, name, &flags); -+ ASSERT_RETURN(ret == 0); -+ ASSERT_RETURN(flags & KDBUS_NAME_ACQUIRED); -+ -+ ret = conn_is_name_primary_owner(conn, name); -+ ASSERT_RETURN(ret == true); -+ - kdbus_conn_free(conn); - - return TEST_OK; --- -2.4.3 - - -From b3d2af97cdc01431d81b3a8ab28b9e9258988974 Mon Sep 17 00:00:00 2001 -From: Paul Osmialowski <p.osmialowsk@samsung.com> -Date: Tue, 8 Sep 2015 14:48:34 +0200 -Subject: [PATCH 129/132] kdbus: Eliminate warning caused by lack of - uapi/linux/kdbus.h inclusion - -metadata.h references struct kdbus_pids which is defined in -uapi/linux/kdbus.h - -Normally, kdbus/metadata.h is included after many other headers -that eventually include uapi/linux/kdbus.h at some point (e.g. kdbus/bus.h -includes uapi/linux/kdbus.h), this prevents the warning. - -When included alone, it causes warning. Also when kdbus/connection.h -is included alone, the same warning is shown since kdbus/connection.h -includes kdbus/metadata.h. - -This patch adds missing inclusion. - -Signed-off-by: Paul Osmialowski <p.osmialowsk@samsung.com> -Reviewed-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - ipc/kdbus/metadata.h | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/ipc/kdbus/metadata.h b/ipc/kdbus/metadata.h -index dba7cc7fdbcb..3f9ba3869849 100644 ---- a/ipc/kdbus/metadata.h -+++ b/ipc/kdbus/metadata.h -@@ -16,6 +16,7 @@ - #define __KDBUS_METADATA_H - - #include <linux/kernel.h> -+#include <uapi/linux/kdbus.h> - - struct kdbus_conn; - struct kdbus_pool_slice; --- -2.4.3 - - -From fbf8878a42017ea10cbccc2e4c690e3f22ce0c04 Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Fri, 4 Sep 2015 11:02:35 +0200 -Subject: [PATCH 130/132] kdbus: raise hard-coded limit of matches - -The current MATCH limit is far too low. We allow more bus-connections per -user than peers to install matches. Raise the limit to a reasonable -default of 4096. The current limit is exactly enough to run Gnome, but -can be easily exceeded by starting some additional service providers. -With the raised limit, we should be fine for the near future. - -Some day, we might decide to make those limits dynamically configurable. -However, that needs some more benchmarking, until we can figure out -perfect defaults. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - ipc/kdbus/limits.h | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ipc/kdbus/limits.h b/ipc/kdbus/limits.h -index c54925a25971..bd47119cdf1b 100644 ---- a/ipc/kdbus/limits.h -+++ b/ipc/kdbus/limits.h -@@ -41,7 +41,7 @@ - #define KDBUS_SYSNAME_MAX_LEN 63 - - /* maximum number of matches per connection */ --#define KDBUS_MATCH_MAX 256 -+#define KDBUS_MATCH_MAX 4096 - - /* maximum number of queued messages from the same individual user */ - #define KDBUS_CONN_MAX_MSGS 256 --- -2.4.3 - - -From d1ddb0cbb326298342d18f5bc83301f7bcd88681 Mon Sep 17 00:00:00 2001 -From: David Herrmann <dh.herrmann@gmail.com> -Date: Mon, 24 Aug 2015 13:07:34 +0200 -Subject: [PATCH 131/132] kdbus/selftests: properly reset flags on re-use - -If a test runs NAME_ACQUIRE multiple times, we really need to reset the -'flags' argument for each call. It's an in/out argument, so it might have -been changed by the kdbus_name_acquire() helper. We must not rely on the -flags to be unchanged, so reset them properly. - -Signed-off-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - tools/testing/selftests/kdbus/test-activator.c | 5 ++++- - tools/testing/selftests/kdbus/test-message.c | 4 +++- - 2 files changed, 7 insertions(+), 2 deletions(-) - -diff --git a/tools/testing/selftests/kdbus/test-activator.c b/tools/testing/selftests/kdbus/test-activator.c -index 3d1b76370ce8..c576a30add11 100644 ---- a/tools/testing/selftests/kdbus/test-activator.c -+++ b/tools/testing/selftests/kdbus/test-activator.c -@@ -47,7 +47,7 @@ static int kdbus_priv_activator(struct kdbus_test_env *env) - int ret; - struct kdbus_msg *msg = NULL; - uint64_t cookie = 0xdeadbeef; -- uint64_t flags = KDBUS_NAME_REPLACE_EXISTING; -+ uint64_t flags; - struct kdbus_conn *activator; - struct kdbus_conn *service; - struct kdbus_conn *client; -@@ -119,12 +119,14 @@ static int kdbus_priv_activator(struct kdbus_test_env *env) - /* Policies are still checked, access denied */ - - ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ -+ flags = KDBUS_NAME_REPLACE_EXISTING; - ret = kdbus_name_acquire(unpriv, "foo.priv.activator", - &flags); - ASSERT_RETURN(ret == -EPERM); - })); - ASSERT_RETURN(ret >= 0); - -+ flags = KDBUS_NAME_REPLACE_EXISTING; - ret = kdbus_name_acquire(service, "foo.priv.activator", - &flags); - ASSERT_RETURN(ret == 0); -@@ -216,6 +218,7 @@ static int kdbus_priv_activator(struct kdbus_test_env *env) - ASSERT_RETURN(ret == 0); - - ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ -+ flags = KDBUS_NAME_REPLACE_EXISTING; - ret = kdbus_name_acquire(unpriv, "foo.priv.activator", - &flags); - ASSERT_RETURN(ret == -EPERM); -diff --git a/tools/testing/selftests/kdbus/test-message.c b/tools/testing/selftests/kdbus/test-message.c -index 563dc859077a..33d349bb29a0 100644 ---- a/tools/testing/selftests/kdbus/test-message.c -+++ b/tools/testing/selftests/kdbus/test-message.c -@@ -293,7 +293,7 @@ static int kdbus_test_activator_quota(struct kdbus_test_env *env) - struct kdbus_conn *sender; - struct kdbus_conn *activator; - struct kdbus_msg *msg; -- uint64_t flags = KDBUS_NAME_REPLACE_EXISTING; -+ uint64_t flags; - struct kdbus_cmd_recv recv = { .size = sizeof(recv) }; - struct kdbus_policy_access access = { - .type = KDBUS_POLICY_ACCESS_USER, -@@ -375,6 +375,7 @@ static int kdbus_test_activator_quota(struct kdbus_test_env *env) - kdbus_msg_free(msg); - - /* Try to acquire the name now */ -+ flags = KDBUS_NAME_REPLACE_EXISTING; - ret = kdbus_name_acquire(conn, "foo.test.activator", &flags); - ASSERT_RETURN(ret == 0); - -@@ -431,6 +432,7 @@ static int kdbus_test_activator_quota(struct kdbus_test_env *env) - ASSERT_RETURN(ret == -ENOBUFS); - - /* Acquire the name again */ -+ flags = KDBUS_NAME_REPLACE_EXISTING; - ret = kdbus_name_acquire(conn, "foo.test.activator", &flags); - ASSERT_RETURN(ret == 0); - --- -2.4.3 - - -From fc87a0ace7e3a40e9e5988943a5187b04104fb7e Mon Sep 17 00:00:00 2001 -From: Lubomir Rintel <lkundrak@v3.sk> -Date: Fri, 14 Aug 2015 15:21:43 +0200 -Subject: [PATCH 132/132] kdbus: create /sys/fs/kdbus with - sysfs_create_mount_point() - -Since 0cbee99269 user-namespace pull, if a kdbusfs is mounted on a -location that's not created with sysfs_create_mount_point the user -namespaces are not allowed to mount their sysfs instances. - -Signed-off-by: Lubomir Rintel <lkundrak@v3.sk> -Reviewed-by: David Herrmann <dh.herrmann@gmail.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - ipc/kdbus/main.c | 13 +++++-------- - 1 file changed, 5 insertions(+), 8 deletions(-) - -diff --git a/ipc/kdbus/main.c b/ipc/kdbus/main.c -index 1ad4dc8dafa1..c2117ea53bb5 100644 ---- a/ipc/kdbus/main.c -+++ b/ipc/kdbus/main.c -@@ -75,16 +75,13 @@ - * '» struct kdbus_ep *ep (owned) - */ - --/* kdbus mount-point /sys/fs/kdbus */ --static struct kobject *kdbus_dir; -- - static int __init kdbus_init(void) - { - int ret; - -- kdbus_dir = kobject_create_and_add(KBUILD_MODNAME, fs_kobj); -- if (!kdbus_dir) -- return -ENOMEM; -+ ret = sysfs_create_mount_point(fs_kobj, KBUILD_MODNAME); -+ if (ret) -+ return ret; - - ret = kdbus_fs_init(); - if (ret < 0) { -@@ -96,14 +93,14 @@ static int __init kdbus_init(void) - return 0; - - exit_dir: -- kobject_put(kdbus_dir); -+ sysfs_remove_mount_point(fs_kobj, KBUILD_MODNAME); - return ret; - } - - static void __exit kdbus_exit(void) - { - kdbus_fs_exit(); -- kobject_put(kdbus_dir); -+ sysfs_remove_mount_point(fs_kobj, KBUILD_MODNAME); - ida_destroy(&kdbus_node_ida); - } - --- -2.4.3 - |