diff options
289 files changed, 1776 insertions, 34425 deletions
diff --git a/Documentation/Makefile b/Documentation/Makefile index e2127a76b..bc0548201 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -1,4 +1,4 @@ subdir-y := accounting auxdisplay blackfin connector \ - filesystems filesystems ia64 kdbus laptops mic misc-devices \ + filesystems filesystems ia64 laptops mic misc-devices \ networking pcmcia prctl ptp spi timers vDSO video4linux \ watchdog diff --git a/Documentation/filesystems/aufs/README b/Documentation/filesystems/aufs/README index e827ebfa8..ed1bafe08 100644 --- a/Documentation/filesystems/aufs/README +++ b/Documentation/filesystems/aufs/README @@ -371,6 +371,7 @@ Nikolay Pertsev made a donation (2014/5). James B made a donation (2014/7 and 2015/7). Stefano Di Biase made a donation (2014/8). Daniel Epellei made a donation (2015/1). +OmegaPhil made a donation (2016/1). Thank you very much. Donations are always, including future donations, very important and diff --git a/Documentation/filesystems/aufs/design/01intro.txt b/Documentation/filesystems/aufs/design/01intro.txt index 02a8c7b66..5d0121439 100644 --- a/Documentation/filesystems/aufs/design/01intro.txt +++ b/Documentation/filesystems/aufs/design/01intro.txt @@ -1,5 +1,5 @@ -# Copyright (C) 2005-2015 Junjiro R. Okajima +# Copyright (C) 2005-2016 Junjiro R. Okajima Introduction ---------------------------------------- diff --git a/Documentation/filesystems/aufs/design/02struct.txt b/Documentation/filesystems/aufs/design/02struct.txt index 1a5e5d03b..783328a75 100644 --- a/Documentation/filesystems/aufs/design/02struct.txt +++ b/Documentation/filesystems/aufs/design/02struct.txt @@ -1,5 +1,5 @@ -# Copyright (C) 2005-2015 Junjiro R. Okajima +# Copyright (C) 2005-2016 Junjiro R. Okajima Basic Aufs Internal Structure diff --git a/Documentation/filesystems/aufs/design/03atomic_open.txt b/Documentation/filesystems/aufs/design/03atomic_open.txt index d2c983412..741ad6d66 100644 --- a/Documentation/filesystems/aufs/design/03atomic_open.txt +++ b/Documentation/filesystems/aufs/design/03atomic_open.txt @@ -1,5 +1,5 @@ -# Copyright (C) 2015 Junjiro R. Okajima +# Copyright (C) 2015-2016 Junjiro R. Okajima Support for a branch who has its ->atomic_open() ---------------------------------------------------------------------- diff --git a/Documentation/filesystems/aufs/design/03lookup.txt b/Documentation/filesystems/aufs/design/03lookup.txt index 7adf4cc97..5b6b000b5 100644 --- a/Documentation/filesystems/aufs/design/03lookup.txt +++ b/Documentation/filesystems/aufs/design/03lookup.txt @@ -1,5 +1,5 @@ -# Copyright (C) 2005-2015 Junjiro R. Okajima +# Copyright (C) 2005-2016 Junjiro R. Okajima Lookup in a Branch ---------------------------------------------------------------------- diff --git a/Documentation/filesystems/aufs/design/04branch.txt b/Documentation/filesystems/aufs/design/04branch.txt index 1d11dbebb..e68f4d3df 100644 --- a/Documentation/filesystems/aufs/design/04branch.txt +++ b/Documentation/filesystems/aufs/design/04branch.txt @@ -1,5 +1,5 @@ -# Copyright (C) 2005-2015 Junjiro R. Okajima +# Copyright (C) 2005-2016 Junjiro R. Okajima Branch Manipulation diff --git a/Documentation/filesystems/aufs/design/05wbr_policy.txt b/Documentation/filesystems/aufs/design/05wbr_policy.txt index 0419a9025..1726d5d06 100644 --- a/Documentation/filesystems/aufs/design/05wbr_policy.txt +++ b/Documentation/filesystems/aufs/design/05wbr_policy.txt @@ -1,5 +1,5 @@ -# Copyright (C) 2005-2015 Junjiro R. Okajima +# Copyright (C) 2005-2016 Junjiro R. Okajima Policies to Select One among Multiple Writable Branches ---------------------------------------------------------------------- diff --git a/Documentation/filesystems/aufs/design/06fhsm.txt b/Documentation/filesystems/aufs/design/06fhsm.txt index 0eb7a8217..84b46dc5b 100644 --- a/Documentation/filesystems/aufs/design/06fhsm.txt +++ b/Documentation/filesystems/aufs/design/06fhsm.txt @@ -1,5 +1,5 @@ -# Copyright (C) 2011-2015 Junjiro R. Okajima +# Copyright (C) 2011-2016 Junjiro R. Okajima File-based Hierarchical Storage Management (FHSM) ---------------------------------------------------------------------- diff --git a/Documentation/filesystems/aufs/design/06mmap.txt b/Documentation/filesystems/aufs/design/06mmap.txt index f22d2a10c..991c0b1fa 100644 --- a/Documentation/filesystems/aufs/design/06mmap.txt +++ b/Documentation/filesystems/aufs/design/06mmap.txt @@ -1,5 +1,5 @@ -# Copyright (C) 2005-2015 Junjiro R. Okajima +# Copyright (C) 2005-2016 Junjiro R. Okajima mmap(2) -- File Memory Mapping ---------------------------------------------------------------------- diff --git a/Documentation/filesystems/aufs/design/06xattr.txt b/Documentation/filesystems/aufs/design/06xattr.txt index ec1e68c54..7bfa94f7b 100644 --- a/Documentation/filesystems/aufs/design/06xattr.txt +++ b/Documentation/filesystems/aufs/design/06xattr.txt @@ -1,5 +1,5 @@ -# Copyright (C) 2014-2015 Junjiro R. Okajima +# Copyright (C) 2014-2016 Junjiro R. Okajima Listing XATTR/EA and getting the value ---------------------------------------------------------------------- diff --git a/Documentation/filesystems/aufs/design/07export.txt b/Documentation/filesystems/aufs/design/07export.txt index 221d70c77..c23930b49 100644 --- a/Documentation/filesystems/aufs/design/07export.txt +++ b/Documentation/filesystems/aufs/design/07export.txt @@ -1,5 +1,5 @@ -# Copyright (C) 2005-2015 Junjiro R. Okajima +# Copyright (C) 2005-2016 Junjiro R. Okajima Export Aufs via NFS ---------------------------------------------------------------------- diff --git a/Documentation/filesystems/aufs/design/08shwh.txt b/Documentation/filesystems/aufs/design/08shwh.txt index 181dc021b..ad58ebe15 100644 --- a/Documentation/filesystems/aufs/design/08shwh.txt +++ b/Documentation/filesystems/aufs/design/08shwh.txt @@ -1,5 +1,5 @@ -# Copyright (C) 2005-2015 Junjiro R. Okajima +# Copyright (C) 2005-2016 Junjiro R. Okajima Show Whiteout Mode (shwh) ---------------------------------------------------------------------- diff --git a/Documentation/filesystems/aufs/design/10dynop.txt b/Documentation/filesystems/aufs/design/10dynop.txt index 9d502b50a..49afc5899 100644 --- a/Documentation/filesystems/aufs/design/10dynop.txt +++ b/Documentation/filesystems/aufs/design/10dynop.txt @@ -1,5 +1,5 @@ -# Copyright (C) 2010-2015 Junjiro R. Okajima +# Copyright (C) 2010-2016 Junjiro R. Okajima Dynamically customizable FS operations ---------------------------------------------------------------------- diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt index 4838bad42..91261a32a 100644 --- a/Documentation/ioctl/ioctl-number.txt +++ b/Documentation/ioctl/ioctl-number.txt @@ -298,7 +298,6 @@ 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/Documentation/kdbus/.gitignore b/Documentation/kdbus/.gitignore deleted file mode 100644 index b4a77ccba..000000000 --- a/Documentation/kdbus/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*.7 -*.html diff --git a/Documentation/kdbus/Makefile b/Documentation/kdbus/Makefile deleted file mode 100644 index 8caffe565..000000000 --- a/Documentation/kdbus/Makefile +++ /dev/null @@ -1,44 +0,0 @@ -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 $(srctree)/$(src)/stylesheet.xsl --skip-validation - -quiet_cmd_db2man = MAN $@ - cmd_db2man = xmlto man $(XMLTO_ARGS) -o $(obj) $< -%.7: %.xml - @(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 - @(which xmlto > /dev/null 2>&1) || \ - (echo "*** You need to install xmlto ***"; \ - exit 1) - $(call cmd,db2html) - -mandocs: $(MANFILES) - -htmldocs: $(HTMLFILES) - -clean-files := $(MANFILES) $(HTMLFILES) - -# we don't support other %docs targets right now -%docs: - @true diff --git a/Documentation/kdbus/kdbus.bus.xml b/Documentation/kdbus/kdbus.bus.xml deleted file mode 100644 index 83f1198bc..000000000 --- a/Documentation/kdbus/kdbus.bus.xml +++ /dev/null @@ -1,344 +0,0 @@ -<?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_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 deleted file mode 100644 index 4bb5f30f3..000000000 --- a/Documentation/kdbus/kdbus.connection.xml +++ /dev/null @@ -1,1244 +0,0 @@ -<?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. - </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>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>. - </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> - 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 deleted file mode 100644 index 6632485f3..000000000 --- a/Documentation/kdbus/kdbus.endpoint.xml +++ /dev/null @@ -1,429 +0,0 @@ -<?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 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> - 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> - </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 deleted file mode 100644 index 8c2a90e10..000000000 --- a/Documentation/kdbus/kdbus.fs.xml +++ /dev/null @@ -1,124 +0,0 @@ -<?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 deleted file mode 100644 index ee09dfa44..000000000 --- a/Documentation/kdbus/kdbus.item.xml +++ /dev/null @@ -1,839 +0,0 @@ -<?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 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 - 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. - 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 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 are 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 are 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 deleted file mode 100644 index ae38e04ab..000000000 --- a/Documentation/kdbus/kdbus.match.xml +++ /dev/null @@ -1,555 +0,0 @@ -<?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 - connection's 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 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 - 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 <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, - 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 "Bloom filters" section above 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 deleted file mode 100644 index 0115d9d50..000000000 --- a/Documentation/kdbus/kdbus.message.xml +++ /dev/null @@ -1,1276 +0,0 @@ -<?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 <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> - </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 message referenced by 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.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 - 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 - "Message payload". - </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 deleted file mode 100644 index 3f5f6a6c5..000000000 --- a/Documentation/kdbus/kdbus.name.xml +++ /dev/null @@ -1,711 +0,0 @@ -<?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 deleted file mode 100644 index 673241638..000000000 --- a/Documentation/kdbus/kdbus.policy.xml +++ /dev/null @@ -1,406 +0,0 @@ -<?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 deleted file mode 100644 index a9e16f196..000000000 --- a/Documentation/kdbus/kdbus.pool.xml +++ /dev/null @@ -1,326 +0,0 @@ -<?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> - <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> - <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 deleted file mode 100644 index d8e7400df..000000000 --- a/Documentation/kdbus/kdbus.xml +++ /dev/null @@ -1,1012 +0,0 @@ -<?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 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 - <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 <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 deleted file mode 100644 index 52565eac7..000000000 --- a/Documentation/kdbus/stylesheet.xsl +++ /dev/null @@ -1,16 +0,0 @@ -<?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/MAINTAINERS b/MAINTAINERS index 84af0bd68..e1a9511fc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6003,19 +6003,6 @@ 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> @@ -1,6 +1,6 @@ VERSION = 4 PATCHLEVEL = 4 -SUBLEVEL = 1 +SUBLEVEL = 2 EXTRAVERSION = -gnu NAME = Blurry Fish Butt @@ -1346,7 +1346,6 @@ $(help-board-dirs): help-%: %docs: scripts_basic FORCE $(Q)$(MAKE) $(build)=scripts build_docproc build_check-lc_ctype $(Q)$(MAKE) $(build)=Documentation/DocBook $@ - $(Q)$(MAKE) $(build)=Documentation/kdbus $@ else # KBUILD_EXTMOD diff --git a/arch/parisc/include/asm/hugetlb.h b/arch/parisc/include/asm/hugetlb.h index 7d56a9ccb..a65d88871 100644 --- a/arch/parisc/include/asm/hugetlb.h +++ b/arch/parisc/include/asm/hugetlb.h @@ -54,24 +54,12 @@ static inline pte_t huge_pte_wrprotect(pte_t pte) return pte_wrprotect(pte); } -static inline void huge_ptep_set_wrprotect(struct mm_struct *mm, - unsigned long addr, pte_t *ptep) -{ - pte_t old_pte = *ptep; - set_huge_pte_at(mm, addr, ptep, pte_wrprotect(old_pte)); -} +void huge_ptep_set_wrprotect(struct mm_struct *mm, + unsigned long addr, pte_t *ptep); -static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma, +int huge_ptep_set_access_flags(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep, - pte_t pte, int dirty) -{ - int changed = !pte_same(*ptep, pte); - if (changed) { - set_huge_pte_at(vma->vm_mm, addr, ptep, pte); - flush_tlb_page(vma, addr); - } - return changed; -} + pte_t pte, int dirty); static inline pte_t huge_ptep_get(pte_t *ptep) { diff --git a/arch/parisc/include/uapi/asm/siginfo.h b/arch/parisc/include/uapi/asm/siginfo.h index d7034728f..1c75565d9 100644 --- a/arch/parisc/include/uapi/asm/siginfo.h +++ b/arch/parisc/include/uapi/asm/siginfo.h @@ -1,6 +1,10 @@ #ifndef _PARISC_SIGINFO_H #define _PARISC_SIGINFO_H +#if defined(__LP64__) +#define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int)) +#endif + #include <asm-generic/siginfo.h> #undef NSIGTRAP diff --git a/arch/parisc/mm/hugetlbpage.c b/arch/parisc/mm/hugetlbpage.c index f6fdc77a7..54ba39262 100644 --- a/arch/parisc/mm/hugetlbpage.c +++ b/arch/parisc/mm/hugetlbpage.c @@ -105,15 +105,13 @@ static inline void purge_tlb_entries_huge(struct mm_struct *mm, unsigned long ad addr |= _HUGE_PAGE_SIZE_ENCODING_DEFAULT; for (i = 0; i < (1 << (HPAGE_SHIFT-REAL_HPAGE_SHIFT)); i++) { - mtsp(mm->context, 1); - pdtlb(addr); - if (unlikely(split_tlb)) - pitlb(addr); + purge_tlb_entries(mm, addr); addr += (1UL << REAL_HPAGE_SHIFT); } } -void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, +/* __set_huge_pte_at() must be called holding the pa_tlb_lock. */ +static void __set_huge_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t entry) { unsigned long addr_start; @@ -123,14 +121,9 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, addr_start = addr; for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) { - /* Directly write pte entry. We could call set_pte_at(mm, addr, ptep, entry) - * instead, but then we get double locking on pa_tlb_lock. */ - *ptep = entry; + set_pte(ptep, entry); ptep++; - /* Drop the PAGE_SIZE/non-huge tlb entry */ - purge_tlb_entries(mm, addr); - addr += PAGE_SIZE; pte_val(entry) += PAGE_SIZE; } @@ -138,18 +131,61 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, purge_tlb_entries_huge(mm, addr_start); } +void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, + pte_t *ptep, pte_t entry) +{ + unsigned long flags; + + purge_tlb_start(flags); + __set_huge_pte_at(mm, addr, ptep, entry); + purge_tlb_end(flags); +} + pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { + unsigned long flags; pte_t entry; + purge_tlb_start(flags); entry = *ptep; - set_huge_pte_at(mm, addr, ptep, __pte(0)); + __set_huge_pte_at(mm, addr, ptep, __pte(0)); + purge_tlb_end(flags); return entry; } + +void huge_ptep_set_wrprotect(struct mm_struct *mm, + unsigned long addr, pte_t *ptep) +{ + unsigned long flags; + pte_t old_pte; + + purge_tlb_start(flags); + old_pte = *ptep; + __set_huge_pte_at(mm, addr, ptep, pte_wrprotect(old_pte)); + purge_tlb_end(flags); +} + +int huge_ptep_set_access_flags(struct vm_area_struct *vma, + unsigned long addr, pte_t *ptep, + pte_t pte, int dirty) +{ + unsigned long flags; + int changed; + + purge_tlb_start(flags); + changed = !pte_same(*ptep, pte); + if (changed) { + __set_huge_pte_at(vma->vm_mm, addr, ptep, pte); + } + purge_tlb_end(flags); + return changed; +} + + int pmd_huge(pmd_t pmd) { return 0; diff --git a/arch/x86/crypto/chacha20-ssse3-x86_64.S b/arch/x86/crypto/chacha20-ssse3-x86_64.S index 712b13047..3a33124e9 100644 --- a/arch/x86/crypto/chacha20-ssse3-x86_64.S +++ b/arch/x86/crypto/chacha20-ssse3-x86_64.S @@ -157,7 +157,9 @@ ENTRY(chacha20_4block_xor_ssse3) # done with the slightly better performing SSSE3 byte shuffling, # 7/12-bit word rotation uses traditional shift+OR. - sub $0x40,%rsp + mov %rsp,%r11 + sub $0x80,%rsp + and $~63,%rsp # x0..15[0-3] = s0..3[0..3] movq 0x00(%rdi),%xmm1 @@ -620,6 +622,6 @@ ENTRY(chacha20_4block_xor_ssse3) pxor %xmm1,%xmm15 movdqu %xmm15,0xf0(%rsi) - add $0x40,%rsp + mov %r11,%rsp ret ENDPROC(chacha20_4block_xor_ssse3) diff --git a/block/blk-merge.c b/block/blk-merge.c index e01405a3e..b966db8f3 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -68,6 +68,18 @@ static struct bio *blk_bio_write_same_split(struct request_queue *q, return bio_split(bio, q->limits.max_write_same_sectors, GFP_NOIO, bs); } +static inline unsigned get_max_io_size(struct request_queue *q, + struct bio *bio) +{ + unsigned sectors = blk_max_size_offset(q, bio->bi_iter.bi_sector); + unsigned mask = queue_logical_block_size(q) - 1; + + /* aligned to logical block size */ + sectors &= ~(mask >> 9); + + return sectors; +} + static struct bio *blk_bio_segment_split(struct request_queue *q, struct bio *bio, struct bio_set *bs, @@ -79,11 +91,9 @@ static struct bio *blk_bio_segment_split(struct request_queue *q, unsigned front_seg_size = bio->bi_seg_front_size; bool do_split = true; struct bio *new = NULL; + const unsigned max_sectors = get_max_io_size(q, bio); bio_for_each_segment(bv, bio, iter) { - if (sectors + (bv.bv_len >> 9) > queue_max_sectors(q)) - goto split; - /* * If the queue doesn't support SG gaps and adding this * offset would create a gap, disallow it. @@ -91,6 +101,21 @@ static struct bio *blk_bio_segment_split(struct request_queue *q, if (bvprvp && bvec_gap_to_prev(q, bvprvp, bv.bv_offset)) goto split; + if (sectors + (bv.bv_len >> 9) > max_sectors) { + /* + * Consider this a new segment if we're splitting in + * the middle of this vector. + */ + if (nsegs < queue_max_segments(q) && + sectors < max_sectors) { + nsegs++; + sectors = max_sectors; + } + if (sectors) + goto split; + /* Make this single bvec as the 1st segment */ + } + if (bvprvp && blk_queue_cluster(q)) { if (seg_size + bv.bv_len > queue_max_segment_size(q)) goto new_segment; diff --git a/crypto/af_alg.c b/crypto/af_alg.c index a8e7aa3e2..f5e18c2a4 100644 --- a/crypto/af_alg.c +++ b/crypto/af_alg.c @@ -76,6 +76,8 @@ int af_alg_register_type(const struct af_alg_type *type) goto unlock; type->ops->owner = THIS_MODULE; + if (type->ops_nokey) + type->ops_nokey->owner = THIS_MODULE; node->type = type; list_add(&node->list, &alg_types); err = 0; @@ -125,6 +127,26 @@ int af_alg_release(struct socket *sock) } EXPORT_SYMBOL_GPL(af_alg_release); +void af_alg_release_parent(struct sock *sk) +{ + struct alg_sock *ask = alg_sk(sk); + unsigned int nokey = ask->nokey_refcnt; + bool last = nokey && !ask->refcnt; + + sk = ask->parent; + ask = alg_sk(sk); + + lock_sock(sk); + ask->nokey_refcnt -= nokey; + if (!last) + last = !--ask->refcnt; + release_sock(sk); + + if (last) + sock_put(sk); +} +EXPORT_SYMBOL_GPL(af_alg_release_parent); + static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) { const u32 forbidden = CRYPTO_ALG_INTERNAL; @@ -133,6 +155,7 @@ static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) struct sockaddr_alg *sa = (void *)uaddr; const struct af_alg_type *type; void *private; + int err; if (sock->state == SS_CONNECTED) return -EINVAL; @@ -160,16 +183,22 @@ static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) return PTR_ERR(private); } + err = -EBUSY; lock_sock(sk); + if (ask->refcnt | ask->nokey_refcnt) + goto unlock; swap(ask->type, type); swap(ask->private, private); + err = 0; + +unlock: release_sock(sk); alg_do_release(type, private); - return 0; + return err; } static int alg_setkey(struct sock *sk, char __user *ukey, @@ -202,11 +231,15 @@ static int alg_setsockopt(struct socket *sock, int level, int optname, struct sock *sk = sock->sk; struct alg_sock *ask = alg_sk(sk); const struct af_alg_type *type; - int err = -ENOPROTOOPT; + int err = -EBUSY; lock_sock(sk); + if (ask->refcnt) + goto unlock; + type = ask->type; + err = -ENOPROTOOPT; if (level != SOL_ALG || !type) goto unlock; @@ -238,6 +271,7 @@ int af_alg_accept(struct sock *sk, struct socket *newsock) struct alg_sock *ask = alg_sk(sk); const struct af_alg_type *type; struct sock *sk2; + unsigned int nokey; int err; lock_sock(sk); @@ -257,20 +291,29 @@ int af_alg_accept(struct sock *sk, struct socket *newsock) security_sk_clone(sk, sk2); err = type->accept(ask->private, sk2); - if (err) { - sk_free(sk2); + + nokey = err == -ENOKEY; + if (nokey && type->accept_nokey) + err = type->accept_nokey(ask->private, sk2); + + if (err) goto unlock; - } sk2->sk_family = PF_ALG; - sock_hold(sk); + if (nokey || !ask->refcnt++) + sock_hold(sk); + ask->nokey_refcnt += nokey; alg_sk(sk2)->parent = sk; alg_sk(sk2)->type = type; + alg_sk(sk2)->nokey_refcnt = nokey; newsock->ops = type->ops; newsock->state = SS_CONNECTED; + if (nokey) + newsock->ops = type->ops_nokey; + err = 0; unlock: diff --git a/crypto/ahash.c b/crypto/ahash.c index 9c1dc8d61..d19b52324 100644 --- a/crypto/ahash.c +++ b/crypto/ahash.c @@ -451,6 +451,7 @@ static int crypto_ahash_init_tfm(struct crypto_tfm *tfm) struct ahash_alg *alg = crypto_ahash_alg(hash); hash->setkey = ahash_nosetkey; + hash->has_setkey = false; hash->export = ahash_no_export; hash->import = ahash_no_import; @@ -463,8 +464,10 @@ static int crypto_ahash_init_tfm(struct crypto_tfm *tfm) hash->finup = alg->finup ?: ahash_def_finup; hash->digest = alg->digest; - if (alg->setkey) + if (alg->setkey) { hash->setkey = alg->setkey; + hash->has_setkey = true; + } if (alg->export) hash->export = alg->export; if (alg->import) diff --git a/crypto/algif_hash.c b/crypto/algif_hash.c index b4c24fe3d..68a5ceaa0 100644 --- a/crypto/algif_hash.c +++ b/crypto/algif_hash.c @@ -34,6 +34,11 @@ struct hash_ctx { struct ahash_request req; }; +struct algif_hash_tfm { + struct crypto_ahash *hash; + bool has_key; +}; + static int hash_sendmsg(struct socket *sock, struct msghdr *msg, size_t ignored) { @@ -49,7 +54,8 @@ static int hash_sendmsg(struct socket *sock, struct msghdr *msg, lock_sock(sk); if (!ctx->more) { - err = crypto_ahash_init(&ctx->req); + err = af_alg_wait_for_completion(crypto_ahash_init(&ctx->req), + &ctx->completion); if (err) goto unlock; } @@ -120,6 +126,7 @@ static ssize_t hash_sendpage(struct socket *sock, struct page *page, } else { if (!ctx->more) { err = crypto_ahash_init(&ctx->req); + err = af_alg_wait_for_completion(err, &ctx->completion); if (err) goto unlock; } @@ -235,19 +242,151 @@ static struct proto_ops algif_hash_ops = { .accept = hash_accept, }; +static int hash_check_key(struct socket *sock) +{ + int err = 0; + struct sock *psk; + struct alg_sock *pask; + struct algif_hash_tfm *tfm; + struct sock *sk = sock->sk; + struct alg_sock *ask = alg_sk(sk); + + lock_sock(sk); + if (ask->refcnt) + goto unlock_child; + + psk = ask->parent; + pask = alg_sk(ask->parent); + tfm = pask->private; + + err = -ENOKEY; + lock_sock_nested(psk, SINGLE_DEPTH_NESTING); + if (!tfm->has_key) + goto unlock; + + if (!pask->refcnt++) + sock_hold(psk); + + ask->refcnt = 1; + sock_put(psk); + + err = 0; + +unlock: + release_sock(psk); +unlock_child: + release_sock(sk); + + return err; +} + +static int hash_sendmsg_nokey(struct socket *sock, struct msghdr *msg, + size_t size) +{ + int err; + + err = hash_check_key(sock); + if (err) + return err; + + return hash_sendmsg(sock, msg, size); +} + +static ssize_t hash_sendpage_nokey(struct socket *sock, struct page *page, + int offset, size_t size, int flags) +{ + int err; + + err = hash_check_key(sock); + if (err) + return err; + + return hash_sendpage(sock, page, offset, size, flags); +} + +static int hash_recvmsg_nokey(struct socket *sock, struct msghdr *msg, + size_t ignored, int flags) +{ + int err; + + err = hash_check_key(sock); + if (err) + return err; + + return hash_recvmsg(sock, msg, ignored, flags); +} + +static int hash_accept_nokey(struct socket *sock, struct socket *newsock, + int flags) +{ + int err; + + err = hash_check_key(sock); + if (err) + return err; + + return hash_accept(sock, newsock, flags); +} + +static struct proto_ops algif_hash_ops_nokey = { + .family = PF_ALG, + + .connect = sock_no_connect, + .socketpair = sock_no_socketpair, + .getname = sock_no_getname, + .ioctl = sock_no_ioctl, + .listen = sock_no_listen, + .shutdown = sock_no_shutdown, + .getsockopt = sock_no_getsockopt, + .mmap = sock_no_mmap, + .bind = sock_no_bind, + .setsockopt = sock_no_setsockopt, + .poll = sock_no_poll, + + .release = af_alg_release, + .sendmsg = hash_sendmsg_nokey, + .sendpage = hash_sendpage_nokey, + .recvmsg = hash_recvmsg_nokey, + .accept = hash_accept_nokey, +}; + static void *hash_bind(const char *name, u32 type, u32 mask) { - return crypto_alloc_ahash(name, type, mask); + struct algif_hash_tfm *tfm; + struct crypto_ahash *hash; + + tfm = kzalloc(sizeof(*tfm), GFP_KERNEL); + if (!tfm) + return ERR_PTR(-ENOMEM); + + hash = crypto_alloc_ahash(name, type, mask); + if (IS_ERR(hash)) { + kfree(tfm); + return ERR_CAST(hash); + } + + tfm->hash = hash; + + return tfm; } static void hash_release(void *private) { - crypto_free_ahash(private); + struct algif_hash_tfm *tfm = private; + + crypto_free_ahash(tfm->hash); + kfree(tfm); } static int hash_setkey(void *private, const u8 *key, unsigned int keylen) { - return crypto_ahash_setkey(private, key, keylen); + struct algif_hash_tfm *tfm = private; + int err; + + err = crypto_ahash_setkey(tfm->hash, key, keylen); + tfm->has_key = !err; + + return err; } static void hash_sock_destruct(struct sock *sk) @@ -261,12 +400,14 @@ static void hash_sock_destruct(struct sock *sk) af_alg_release_parent(sk); } -static int hash_accept_parent(void *private, struct sock *sk) +static int hash_accept_parent_nokey(void *private, struct sock *sk) { struct hash_ctx *ctx; struct alg_sock *ask = alg_sk(sk); - unsigned len = sizeof(*ctx) + crypto_ahash_reqsize(private); - unsigned ds = crypto_ahash_digestsize(private); + struct algif_hash_tfm *tfm = private; + struct crypto_ahash *hash = tfm->hash; + unsigned len = sizeof(*ctx) + crypto_ahash_reqsize(hash); + unsigned ds = crypto_ahash_digestsize(hash); ctx = sock_kmalloc(sk, len, GFP_KERNEL); if (!ctx) @@ -286,7 +427,7 @@ static int hash_accept_parent(void *private, struct sock *sk) ask->private = ctx; - ahash_request_set_tfm(&ctx->req, private); + ahash_request_set_tfm(&ctx->req, hash); ahash_request_set_callback(&ctx->req, CRYPTO_TFM_REQ_MAY_BACKLOG, af_alg_complete, &ctx->completion); @@ -295,12 +436,24 @@ static int hash_accept_parent(void *private, struct sock *sk) return 0; } +static int hash_accept_parent(void *private, struct sock *sk) +{ + struct algif_hash_tfm *tfm = private; + + if (!tfm->has_key && crypto_ahash_has_setkey(tfm->hash)) + return -ENOKEY; + + return hash_accept_parent_nokey(private, sk); +} + static const struct af_alg_type algif_type_hash = { .bind = hash_bind, .release = hash_release, .setkey = hash_setkey, .accept = hash_accept_parent, + .accept_nokey = hash_accept_parent_nokey, .ops = &algif_hash_ops, + .ops_nokey = &algif_hash_ops_nokey, .name = "hash", .owner = THIS_MODULE }; diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c index 634b4d1ab..f5e9f9310 100644 --- a/crypto/algif_skcipher.c +++ b/crypto/algif_skcipher.c @@ -31,6 +31,11 @@ struct skcipher_sg_list { struct scatterlist sg[0]; }; +struct skcipher_tfm { + struct crypto_skcipher *skcipher; + bool has_key; +}; + struct skcipher_ctx { struct list_head tsgl; struct af_alg_sgl rsgl; @@ -60,18 +65,10 @@ struct skcipher_async_req { struct skcipher_async_rsgl first_sgl; struct list_head list; struct scatterlist *tsg; - char iv[]; + atomic_t *inflight; + struct skcipher_request req; }; -#define GET_SREQ(areq, ctx) (struct skcipher_async_req *)((char *)areq + \ - crypto_skcipher_reqsize(crypto_skcipher_reqtfm(&ctx->req))) - -#define GET_REQ_SIZE(ctx) \ - crypto_skcipher_reqsize(crypto_skcipher_reqtfm(&ctx->req)) - -#define GET_IV_SIZE(ctx) \ - crypto_skcipher_ivsize(crypto_skcipher_reqtfm(&ctx->req)) - #define MAX_SGL_ENTS ((4096 - sizeof(struct skcipher_sg_list)) / \ sizeof(struct scatterlist) - 1) @@ -97,15 +94,12 @@ static void skcipher_free_async_sgls(struct skcipher_async_req *sreq) static void skcipher_async_cb(struct crypto_async_request *req, int err) { - struct sock *sk = req->data; - struct alg_sock *ask = alg_sk(sk); - struct skcipher_ctx *ctx = ask->private; - struct skcipher_async_req *sreq = GET_SREQ(req, ctx); + struct skcipher_async_req *sreq = req->data; struct kiocb *iocb = sreq->iocb; - atomic_dec(&ctx->inflight); + atomic_dec(sreq->inflight); skcipher_free_async_sgls(sreq); - kfree(req); + kzfree(sreq); iocb->ki_complete(iocb, err, err); } @@ -301,8 +295,11 @@ static int skcipher_sendmsg(struct socket *sock, struct msghdr *msg, { struct sock *sk = sock->sk; struct alg_sock *ask = alg_sk(sk); + struct sock *psk = ask->parent; + struct alg_sock *pask = alg_sk(psk); struct skcipher_ctx *ctx = ask->private; - struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(&ctx->req); + struct skcipher_tfm *skc = pask->private; + struct crypto_skcipher *tfm = skc->skcipher; unsigned ivsize = crypto_skcipher_ivsize(tfm); struct skcipher_sg_list *sgl; struct af_alg_control con = {}; @@ -387,7 +384,8 @@ static int skcipher_sendmsg(struct socket *sock, struct msghdr *msg, sgl = list_entry(ctx->tsgl.prev, struct skcipher_sg_list, list); sg = sgl->sg; - sg_unmark_end(sg + sgl->cur); + if (sgl->cur) + sg_unmark_end(sg + sgl->cur - 1); do { i = sgl->cur; plen = min_t(int, len, PAGE_SIZE); @@ -503,37 +501,43 @@ static int skcipher_recvmsg_async(struct socket *sock, struct msghdr *msg, { struct sock *sk = sock->sk; struct alg_sock *ask = alg_sk(sk); + struct sock *psk = ask->parent; + struct alg_sock *pask = alg_sk(psk); struct skcipher_ctx *ctx = ask->private; + struct skcipher_tfm *skc = pask->private; + struct crypto_skcipher *tfm = skc->skcipher; struct skcipher_sg_list *sgl; struct scatterlist *sg; struct skcipher_async_req *sreq; struct skcipher_request *req; struct skcipher_async_rsgl *last_rsgl = NULL; - unsigned int txbufs = 0, len = 0, tx_nents = skcipher_all_sg_nents(ctx); - unsigned int reqlen = sizeof(struct skcipher_async_req) + - GET_REQ_SIZE(ctx) + GET_IV_SIZE(ctx); + unsigned int txbufs = 0, len = 0, tx_nents; + unsigned int reqsize = crypto_skcipher_reqsize(tfm); + unsigned int ivsize = crypto_skcipher_ivsize(tfm); int err = -ENOMEM; bool mark = false; + char *iv; - lock_sock(sk); - req = kmalloc(reqlen, GFP_KERNEL); - if (unlikely(!req)) - goto unlock; + sreq = kzalloc(sizeof(*sreq) + reqsize + ivsize, GFP_KERNEL); + if (unlikely(!sreq)) + goto out; - sreq = GET_SREQ(req, ctx); + req = &sreq->req; + iv = (char *)(req + 1) + reqsize; sreq->iocb = msg->msg_iocb; - memset(&sreq->first_sgl, '\0', sizeof(struct skcipher_async_rsgl)); INIT_LIST_HEAD(&sreq->list); + sreq->inflight = &ctx->inflight; + + lock_sock(sk); + tx_nents = skcipher_all_sg_nents(ctx); sreq->tsg = kcalloc(tx_nents, sizeof(*sg), GFP_KERNEL); - if (unlikely(!sreq->tsg)) { - kfree(req); + if (unlikely(!sreq->tsg)) goto unlock; - } sg_init_table(sreq->tsg, tx_nents); - memcpy(sreq->iv, ctx->iv, GET_IV_SIZE(ctx)); - skcipher_request_set_tfm(req, crypto_skcipher_reqtfm(&ctx->req)); - skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, - skcipher_async_cb, sk); + memcpy(iv, ctx->iv, ivsize); + skcipher_request_set_tfm(req, tfm); + skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, + skcipher_async_cb, sreq); while (iov_iter_count(&msg->msg_iter)) { struct skcipher_async_rsgl *rsgl; @@ -609,20 +613,22 @@ static int skcipher_recvmsg_async(struct socket *sock, struct msghdr *msg, sg_mark_end(sreq->tsg + txbufs - 1); skcipher_request_set_crypt(req, sreq->tsg, sreq->first_sgl.sgl.sg, - len, sreq->iv); + len, iv); err = ctx->enc ? crypto_skcipher_encrypt(req) : crypto_skcipher_decrypt(req); if (err == -EINPROGRESS) { atomic_inc(&ctx->inflight); err = -EIOCBQUEUED; + sreq = NULL; goto unlock; } free: skcipher_free_async_sgls(sreq); - kfree(req); unlock: skcipher_wmem_wakeup(sk); release_sock(sk); + kzfree(sreq); +out: return err; } @@ -631,9 +637,12 @@ static int skcipher_recvmsg_sync(struct socket *sock, struct msghdr *msg, { struct sock *sk = sock->sk; struct alg_sock *ask = alg_sk(sk); + struct sock *psk = ask->parent; + struct alg_sock *pask = alg_sk(psk); struct skcipher_ctx *ctx = ask->private; - unsigned bs = crypto_skcipher_blocksize(crypto_skcipher_reqtfm( - &ctx->req)); + struct skcipher_tfm *skc = pask->private; + struct crypto_skcipher *tfm = skc->skcipher; + unsigned bs = crypto_skcipher_blocksize(tfm); struct skcipher_sg_list *sgl; struct scatterlist *sg; int err = -EAGAIN; @@ -642,13 +651,6 @@ static int skcipher_recvmsg_sync(struct socket *sock, struct msghdr *msg, lock_sock(sk); while (msg_data_left(msg)) { - sgl = list_first_entry(&ctx->tsgl, - struct skcipher_sg_list, list); - sg = sgl->sg; - - while (!sg->length) - sg++; - if (!ctx->used) { err = skcipher_wait_for_data(sk, flags); if (err) @@ -669,6 +671,13 @@ static int skcipher_recvmsg_sync(struct socket *sock, struct msghdr *msg, if (!used) goto free; + sgl = list_first_entry(&ctx->tsgl, + struct skcipher_sg_list, list); + sg = sgl->sg; + + while (!sg->length) + sg++; + skcipher_request_set_crypt(&ctx->req, sg, ctx->rsgl.sg, used, ctx->iv); @@ -748,19 +757,139 @@ static struct proto_ops algif_skcipher_ops = { .poll = skcipher_poll, }; +static int skcipher_check_key(struct socket *sock) +{ + int err = 0; + struct sock *psk; + struct alg_sock *pask; + struct skcipher_tfm *tfm; + struct sock *sk = sock->sk; + struct alg_sock *ask = alg_sk(sk); + + lock_sock(sk); + if (ask->refcnt) + goto unlock_child; + + psk = ask->parent; + pask = alg_sk(ask->parent); + tfm = pask->private; + + err = -ENOKEY; + lock_sock_nested(psk, SINGLE_DEPTH_NESTING); + if (!tfm->has_key) + goto unlock; + + if (!pask->refcnt++) + sock_hold(psk); + + ask->refcnt = 1; + sock_put(psk); + + err = 0; + +unlock: + release_sock(psk); +unlock_child: + release_sock(sk); + + return err; +} + +static int skcipher_sendmsg_nokey(struct socket *sock, struct msghdr *msg, + size_t size) +{ + int err; + + err = skcipher_check_key(sock); + if (err) + return err; + + return skcipher_sendmsg(sock, msg, size); +} + +static ssize_t skcipher_sendpage_nokey(struct socket *sock, struct page *page, + int offset, size_t size, int flags) +{ + int err; + + err = skcipher_check_key(sock); + if (err) + return err; + + return skcipher_sendpage(sock, page, offset, size, flags); +} + +static int skcipher_recvmsg_nokey(struct socket *sock, struct msghdr *msg, + size_t ignored, int flags) +{ + int err; + + err = skcipher_check_key(sock); + if (err) + return err; + + return skcipher_recvmsg(sock, msg, ignored, flags); +} + +static struct proto_ops algif_skcipher_ops_nokey = { + .family = PF_ALG, + + .connect = sock_no_connect, + .socketpair = sock_no_socketpair, + .getname = sock_no_getname, + .ioctl = sock_no_ioctl, + .listen = sock_no_listen, + .shutdown = sock_no_shutdown, + .getsockopt = sock_no_getsockopt, + .mmap = sock_no_mmap, + .bind = sock_no_bind, + .accept = sock_no_accept, + .setsockopt = sock_no_setsockopt, + + .release = af_alg_release, + .sendmsg = skcipher_sendmsg_nokey, + .sendpage = skcipher_sendpage_nokey, + .recvmsg = skcipher_recvmsg_nokey, + .poll = skcipher_poll, +}; + static void *skcipher_bind(const char *name, u32 type, u32 mask) { - return crypto_alloc_skcipher(name, type, mask); + struct skcipher_tfm *tfm; + struct crypto_skcipher *skcipher; + + tfm = kzalloc(sizeof(*tfm), GFP_KERNEL); + if (!tfm) + return ERR_PTR(-ENOMEM); + + skcipher = crypto_alloc_skcipher(name, type, mask); + if (IS_ERR(skcipher)) { + kfree(tfm); + return ERR_CAST(skcipher); + } + + tfm->skcipher = skcipher; + + return tfm; } static void skcipher_release(void *private) { - crypto_free_skcipher(private); + struct skcipher_tfm *tfm = private; + + crypto_free_skcipher(tfm->skcipher); + kfree(tfm); } static int skcipher_setkey(void *private, const u8 *key, unsigned int keylen) { - return crypto_skcipher_setkey(private, key, keylen); + struct skcipher_tfm *tfm = private; + int err; + + err = crypto_skcipher_setkey(tfm->skcipher, key, keylen); + tfm->has_key = !err; + + return err; } static void skcipher_wait(struct sock *sk) @@ -788,24 +917,26 @@ static void skcipher_sock_destruct(struct sock *sk) af_alg_release_parent(sk); } -static int skcipher_accept_parent(void *private, struct sock *sk) +static int skcipher_accept_parent_nokey(void *private, struct sock *sk) { struct skcipher_ctx *ctx; struct alg_sock *ask = alg_sk(sk); - unsigned int len = sizeof(*ctx) + crypto_skcipher_reqsize(private); + struct skcipher_tfm *tfm = private; + struct crypto_skcipher *skcipher = tfm->skcipher; + unsigned int len = sizeof(*ctx) + crypto_skcipher_reqsize(skcipher); ctx = sock_kmalloc(sk, len, GFP_KERNEL); if (!ctx) return -ENOMEM; - ctx->iv = sock_kmalloc(sk, crypto_skcipher_ivsize(private), + ctx->iv = sock_kmalloc(sk, crypto_skcipher_ivsize(skcipher), GFP_KERNEL); if (!ctx->iv) { sock_kfree_s(sk, ctx, len); return -ENOMEM; } - memset(ctx->iv, 0, crypto_skcipher_ivsize(private)); + memset(ctx->iv, 0, crypto_skcipher_ivsize(skcipher)); INIT_LIST_HEAD(&ctx->tsgl); ctx->len = len; @@ -818,8 +949,9 @@ static int skcipher_accept_parent(void *private, struct sock *sk) ask->private = ctx; - skcipher_request_set_tfm(&ctx->req, private); - skcipher_request_set_callback(&ctx->req, CRYPTO_TFM_REQ_MAY_BACKLOG, + skcipher_request_set_tfm(&ctx->req, skcipher); + skcipher_request_set_callback(&ctx->req, CRYPTO_TFM_REQ_MAY_SLEEP | + CRYPTO_TFM_REQ_MAY_BACKLOG, af_alg_complete, &ctx->completion); sk->sk_destruct = skcipher_sock_destruct; @@ -827,12 +959,24 @@ static int skcipher_accept_parent(void *private, struct sock *sk) return 0; } +static int skcipher_accept_parent(void *private, struct sock *sk) +{ + struct skcipher_tfm *tfm = private; + + if (!tfm->has_key && crypto_skcipher_has_setkey(tfm->skcipher)) + return -ENOKEY; + + return skcipher_accept_parent_nokey(private, sk); +} + static const struct af_alg_type algif_type_skcipher = { .bind = skcipher_bind, .release = skcipher_release, .setkey = skcipher_setkey, .accept = skcipher_accept_parent, + .accept_nokey = skcipher_accept_parent_nokey, .ops = &algif_skcipher_ops, + .ops_nokey = &algif_skcipher_ops_nokey, .name = "skcipher", .owner = THIS_MODULE }; diff --git a/crypto/crc32c_generic.c b/crypto/crc32c_generic.c index 06f1b60f0..4c0a0e271 100644 --- a/crypto/crc32c_generic.c +++ b/crypto/crc32c_generic.c @@ -172,4 +172,3 @@ MODULE_DESCRIPTION("CRC32c (Castagnoli) calculations wrapper for lib/crc32c"); MODULE_LICENSE("GPL"); MODULE_ALIAS_CRYPTO("crc32c"); MODULE_ALIAS_CRYPTO("crc32c-generic"); -MODULE_SOFTDEP("pre: crc32c"); diff --git a/crypto/crypto_user.c b/crypto/crypto_user.c index 237f3795c..43fe85f20 100644 --- a/crypto/crypto_user.c +++ b/crypto/crypto_user.c @@ -499,6 +499,7 @@ static int crypto_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) if (link->dump == NULL) return -EINVAL; + down_read(&crypto_alg_sem); list_for_each_entry(alg, &crypto_alg_list, cra_list) dump_alloc += CRYPTO_REPORT_MAXSIZE; @@ -508,8 +509,11 @@ static int crypto_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) .done = link->done, .min_dump_alloc = dump_alloc, }; - return netlink_dump_start(crypto_nlsk, skb, nlh, &c); + err = netlink_dump_start(crypto_nlsk, skb, nlh, &c); } + up_read(&crypto_alg_sem); + + return err; } err = nlmsg_parse(nlh, crypto_msg_min[type], attrs, CRYPTOCFGA_MAX, diff --git a/crypto/shash.c b/crypto/shash.c index ecb1e3d39..359754591 100644 --- a/crypto/shash.c +++ b/crypto/shash.c @@ -354,9 +354,10 @@ int crypto_init_shash_ops_async(struct crypto_tfm *tfm) crt->final = shash_async_final; crt->finup = shash_async_finup; crt->digest = shash_async_digest; + crt->setkey = shash_async_setkey; + + crt->has_setkey = alg->setkey != shash_no_setkey; - if (alg->setkey) - crt->setkey = shash_async_setkey; if (alg->export) crt->export = shash_async_export; if (alg->import) diff --git a/crypto/skcipher.c b/crypto/skcipher.c index 7591928be..d199c0b17 100644 --- a/crypto/skcipher.c +++ b/crypto/skcipher.c @@ -118,6 +118,7 @@ static int crypto_init_skcipher_ops_blkcipher(struct crypto_tfm *tfm) skcipher->decrypt = skcipher_decrypt_blkcipher; skcipher->ivsize = crypto_blkcipher_ivsize(blkcipher); + skcipher->has_setkey = calg->cra_blkcipher.max_keysize; return 0; } @@ -210,6 +211,7 @@ static int crypto_init_skcipher_ops_ablkcipher(struct crypto_tfm *tfm) skcipher->ivsize = crypto_ablkcipher_ivsize(ablkcipher); skcipher->reqsize = crypto_ablkcipher_reqsize(ablkcipher) + sizeof(struct ablkcipher_request); + skcipher->has_setkey = calg->cra_ablkcipher.max_keysize; return 0; } diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index f1917908e..f8c0afb80 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -264,6 +264,26 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0x3b2b), board_ahci }, /* PCH RAID */ { PCI_VDEVICE(INTEL, 0x3b2c), board_ahci }, /* PCH RAID */ { PCI_VDEVICE(INTEL, 0x3b2f), board_ahci }, /* PCH AHCI */ + { PCI_VDEVICE(INTEL, 0x19b0), board_ahci }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19b1), board_ahci }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19b2), board_ahci }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19b3), board_ahci }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19b4), board_ahci }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19b5), board_ahci }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19b6), board_ahci }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19b7), board_ahci }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19bE), board_ahci }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19bF), board_ahci }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19c0), board_ahci }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19c1), board_ahci }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19c2), board_ahci }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19c3), board_ahci }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19c4), board_ahci }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19c5), board_ahci }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19c6), board_ahci }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19c7), board_ahci }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19cE), board_ahci }, /* DNV AHCI */ + { PCI_VDEVICE(INTEL, 0x19cF), board_ahci }, /* DNV AHCI */ { PCI_VDEVICE(INTEL, 0x1c02), board_ahci }, /* CPT AHCI */ { PCI_VDEVICE(INTEL, 0x1c03), board_ahci }, /* CPT AHCI */ { PCI_VDEVICE(INTEL, 0x1c04), board_ahci }, /* CPT RAID */ diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 89254bb3e..27a06e0cd 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -495,8 +495,8 @@ void ahci_save_initial_config(struct device *dev, struct ahci_host_priv *hpriv) } } - /* fabricate port_map from cap.nr_ports */ - if (!port_map) { + /* fabricate port_map from cap.nr_ports for < AHCI 1.3 */ + if (!port_map && vers < 0x10300) { port_map = (1 << ahci_nr_ports(cap)) - 1; dev_warn(dev, "forcing PORTS_IMPL to 0x%x\n", port_map); diff --git a/drivers/block/zram/zcomp.c b/drivers/block/zram/zcomp.c index 5cb13ca3a..c53617752 100644 --- a/drivers/block/zram/zcomp.c +++ b/drivers/block/zram/zcomp.c @@ -76,7 +76,7 @@ static void zcomp_strm_free(struct zcomp *comp, struct zcomp_strm *zstrm) */ static struct zcomp_strm *zcomp_strm_alloc(struct zcomp *comp) { - struct zcomp_strm *zstrm = kmalloc(sizeof(*zstrm), GFP_KERNEL); + struct zcomp_strm *zstrm = kmalloc(sizeof(*zstrm), GFP_NOIO); if (!zstrm) return NULL; @@ -85,7 +85,7 @@ static struct zcomp_strm *zcomp_strm_alloc(struct zcomp *comp) * allocate 2 pages. 1 for compressed data, plus 1 extra for the * case when compressed size is larger than the original one */ - zstrm->buffer = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 1); + zstrm->buffer = (void *)__get_free_pages(GFP_NOIO | __GFP_ZERO, 1); if (!zstrm->private || !zstrm->buffer) { zcomp_strm_free(comp, zstrm); zstrm = NULL; diff --git a/drivers/block/zram/zcomp_lz4.c b/drivers/block/zram/zcomp_lz4.c index f2afb7e98..dd6083124 100644 --- a/drivers/block/zram/zcomp_lz4.c +++ b/drivers/block/zram/zcomp_lz4.c @@ -10,17 +10,36 @@ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/lz4.h> +#include <linux/vmalloc.h> +#include <linux/mm.h> #include "zcomp_lz4.h" static void *zcomp_lz4_create(void) { - return kzalloc(LZ4_MEM_COMPRESS, GFP_KERNEL); + void *ret; + + /* + * This function can be called in swapout/fs write path + * so we can't use GFP_FS|IO. And it assumes we already + * have at least one stream in zram initialization so we + * don't do best effort to allocate more stream in here. + * A default stream will work well without further multiple + * streams. That's why we use NORETRY | NOWARN. + */ + ret = kzalloc(LZ4_MEM_COMPRESS, GFP_NOIO | __GFP_NORETRY | + __GFP_NOWARN); + if (!ret) + ret = __vmalloc(LZ4_MEM_COMPRESS, + GFP_NOIO | __GFP_NORETRY | __GFP_NOWARN | + __GFP_ZERO | __GFP_HIGHMEM, + PAGE_KERNEL); + return ret; } static void zcomp_lz4_destroy(void *private) { - kfree(private); + kvfree(private); } static int zcomp_lz4_compress(const unsigned char *src, unsigned char *dst, diff --git a/drivers/block/zram/zcomp_lzo.c b/drivers/block/zram/zcomp_lzo.c index da1bc47d5..edc549920 100644 --- a/drivers/block/zram/zcomp_lzo.c +++ b/drivers/block/zram/zcomp_lzo.c @@ -10,17 +10,36 @@ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/lzo.h> +#include <linux/vmalloc.h> +#include <linux/mm.h> #include "zcomp_lzo.h" static void *lzo_create(void) { - return kzalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL); + void *ret; + + /* + * This function can be called in swapout/fs write path + * so we can't use GFP_FS|IO. And it assumes we already + * have at least one stream in zram initialization so we + * don't do best effort to allocate more stream in here. + * A default stream will work well without further multiple + * streams. That's why we use NORETRY | NOWARN. + */ + ret = kzalloc(LZO1X_MEM_COMPRESS, GFP_NOIO | __GFP_NORETRY | + __GFP_NOWARN); + if (!ret) + ret = __vmalloc(LZO1X_MEM_COMPRESS, + GFP_NOIO | __GFP_NORETRY | __GFP_NOWARN | + __GFP_ZERO | __GFP_HIGHMEM, + PAGE_KERNEL); + return ret; } static void lzo_destroy(void *private) { - kfree(private); + kvfree(private); } static int lzo_compress(const unsigned char *src, unsigned char *dst, diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index 47915d736..370c2f760 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -1325,7 +1325,6 @@ static int zram_remove(struct zram *zram) pr_info("Removed device: %s\n", zram->disk->disk_name); - idr_remove(&zram_index_idr, zram->disk->first_minor); blk_cleanup_queue(zram->disk->queue); del_gendisk(zram->disk); put_disk(zram->disk); @@ -1367,10 +1366,12 @@ static ssize_t hot_remove_store(struct class *class, mutex_lock(&zram_index_mutex); zram = idr_find(&zram_index_idr, dev_id); - if (zram) + if (zram) { ret = zram_remove(zram); - else + idr_remove(&zram_index_idr, dev_id); + } else { ret = -ENODEV; + } mutex_unlock(&zram_index_mutex); return ret ? ret : count; diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c index 660d8c065..3178f84d2 100644 --- a/drivers/crypto/atmel-sha.c +++ b/drivers/crypto/atmel-sha.c @@ -783,7 +783,7 @@ static void atmel_sha_finish_req(struct ahash_request *req, int err) dd->flags &= ~(SHA_FLAGS_BUSY | SHA_FLAGS_FINAL | SHA_FLAGS_CPU | SHA_FLAGS_DMA_READY | SHA_FLAGS_OUTPUT_READY); - clk_disable_unprepare(dd->iclk); + clk_disable(dd->iclk); if (req->base.complete) req->base.complete(&req->base, err); @@ -796,7 +796,7 @@ static int atmel_sha_hw_init(struct atmel_sha_dev *dd) { int err; - err = clk_prepare_enable(dd->iclk); + err = clk_enable(dd->iclk); if (err) return err; @@ -823,7 +823,7 @@ static void atmel_sha_hw_version_init(struct atmel_sha_dev *dd) dev_info(dd->dev, "version: 0x%x\n", dd->hw_version); - clk_disable_unprepare(dd->iclk); + clk_disable(dd->iclk); } static int atmel_sha_handle_queue(struct atmel_sha_dev *dd, @@ -1411,6 +1411,10 @@ static int atmel_sha_probe(struct platform_device *pdev) goto res_err; } + err = clk_prepare(sha_dd->iclk); + if (err) + goto res_err; + atmel_sha_hw_version_init(sha_dd); atmel_sha_get_cap(sha_dd); @@ -1422,12 +1426,12 @@ static int atmel_sha_probe(struct platform_device *pdev) if (IS_ERR(pdata)) { dev_err(&pdev->dev, "platform data not available\n"); err = PTR_ERR(pdata); - goto res_err; + goto iclk_unprepare; } } if (!pdata->dma_slave) { err = -ENXIO; - goto res_err; + goto iclk_unprepare; } err = atmel_sha_dma_init(sha_dd, pdata); if (err) @@ -1458,6 +1462,8 @@ err_algs: if (sha_dd->caps.has_dma) atmel_sha_dma_cleanup(sha_dd); err_sha_dma: +iclk_unprepare: + clk_unprepare(sha_dd->iclk); res_err: tasklet_kill(&sha_dd->done_task); sha_dd_err: @@ -1484,12 +1490,7 @@ static int atmel_sha_remove(struct platform_device *pdev) if (sha_dd->caps.has_dma) atmel_sha_dma_cleanup(sha_dd); - iounmap(sha_dd->io_base); - - clk_put(sha_dd->iclk); - - if (sha_dd->irq >= 0) - free_irq(sha_dd->irq, sha_dd); + clk_unprepare(sha_dd->iclk); return 0; } diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c index 8abb4bc54..69d4a1326 100644 --- a/drivers/crypto/caam/ctrl.c +++ b/drivers/crypto/caam/ctrl.c @@ -534,8 +534,8 @@ static int caam_probe(struct platform_device *pdev) * long pointers in master configuration register */ clrsetbits_32(&ctrl->mcr, MCFGR_AWCACHE_MASK, MCFGR_AWCACHE_CACH | - MCFGR_WDENABLE | (sizeof(dma_addr_t) == sizeof(u64) ? - MCFGR_LONG_PTR : 0)); + MCFGR_AWCACHE_BUFF | MCFGR_WDENABLE | + (sizeof(dma_addr_t) == sizeof(u64) ? MCFGR_LONG_PTR : 0)); /* * Read the Compile Time paramters and SCFGR to determine diff --git a/drivers/crypto/marvell/cesa.c b/drivers/crypto/marvell/cesa.c index 0643e3366..c0656e7f3 100644 --- a/drivers/crypto/marvell/cesa.c +++ b/drivers/crypto/marvell/cesa.c @@ -306,7 +306,7 @@ static int mv_cesa_dev_dma_init(struct mv_cesa_dev *cesa) return -ENOMEM; dma->padding_pool = dmam_pool_create("cesa_padding", dev, 72, 1, 0); - if (!dma->cache_pool) + if (!dma->padding_pool) return -ENOMEM; cesa->dma = dma; diff --git a/drivers/crypto/sunxi-ss/sun4i-ss-core.c b/drivers/crypto/sunxi-ss/sun4i-ss-core.c index eab6fe227..107cd2a41 100644 --- a/drivers/crypto/sunxi-ss/sun4i-ss-core.c +++ b/drivers/crypto/sunxi-ss/sun4i-ss-core.c @@ -39,6 +39,7 @@ static struct sun4i_ss_alg_template ss_algs[] = { .import = sun4i_hash_import_md5, .halg = { .digestsize = MD5_DIGEST_SIZE, + .statesize = sizeof(struct md5_state), .base = { .cra_name = "md5", .cra_driver_name = "md5-sun4i-ss", @@ -66,6 +67,7 @@ static struct sun4i_ss_alg_template ss_algs[] = { .import = sun4i_hash_import_sha1, .halg = { .digestsize = SHA1_DIGEST_SIZE, + .statesize = sizeof(struct sha1_state), .base = { .cra_name = "sha1", .cra_driver_name = "sha1-sun4i-ss", diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 3d664d013..2b8ff18d3 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -357,8 +357,19 @@ static void mt_feature_mapping(struct hid_device *hdev, break; } - td->inputmode = field->report->id; - td->inputmode_index = usage->usage_index; + if (td->inputmode < 0) { + td->inputmode = field->report->id; + td->inputmode_index = usage->usage_index; + } else { + /* + * Some elan panels wrongly declare 2 input mode + * features, and silently ignore when we set the + * value in the second field. Skip the second feature + * and hope for the best. + */ + dev_info(&hdev->dev, + "Ignoring the extra HID_DG_INPUTMODE\n"); + } break; case HID_DG_CONTACTMAX: diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 36712e9f5..5dd426fee 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -477,8 +477,6 @@ static void hid_ctrl(struct urb *urb) struct usbhid_device *usbhid = hid->driver_data; int unplug = 0, status = urb->status; - spin_lock(&usbhid->lock); - switch (status) { case 0: /* success */ if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_IN) @@ -498,6 +496,8 @@ static void hid_ctrl(struct urb *urb) hid_warn(urb->dev, "ctrl urb status %d received\n", status); } + spin_lock(&usbhid->lock); + if (unplug) { usbhid->ctrltail = usbhid->ctrlhead; } else { diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c index 7df977776..dad768caa 100644 --- a/drivers/iommu/io-pgtable-arm.c +++ b/drivers/iommu/io-pgtable-arm.c @@ -405,17 +405,18 @@ static void __arm_lpae_free_pgtable(struct arm_lpae_io_pgtable *data, int lvl, arm_lpae_iopte *start, *end; unsigned long table_size; - /* Only leaf entries at the last level */ - if (lvl == ARM_LPAE_MAX_LEVELS - 1) - return; - if (lvl == ARM_LPAE_START_LVL(data)) table_size = data->pgd_size; else table_size = 1UL << data->pg_shift; start = ptep; - end = (void *)ptep + table_size; + + /* Only leaf entries at the last level */ + if (lvl == ARM_LPAE_MAX_LEVELS - 1) + end = ptep; + else + end = (void *)ptep + table_size; while (ptep != end) { arm_lpae_iopte pte = *ptep++; diff --git a/drivers/md/md.c b/drivers/md/md.c index 61aacab42..b1e1f6b95 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -2017,28 +2017,32 @@ int md_integrity_register(struct mddev *mddev) } EXPORT_SYMBOL(md_integrity_register); -/* Disable data integrity if non-capable/non-matching disk is being added */ -void md_integrity_add_rdev(struct md_rdev *rdev, struct mddev *mddev) +/* + * Attempt to add an rdev, but only if it is consistent with the current + * integrity profile + */ +int md_integrity_add_rdev(struct md_rdev *rdev, struct mddev *mddev) { struct blk_integrity *bi_rdev; struct blk_integrity *bi_mddev; + char name[BDEVNAME_SIZE]; if (!mddev->gendisk) - return; + return 0; bi_rdev = bdev_get_integrity(rdev->bdev); bi_mddev = blk_get_integrity(mddev->gendisk); if (!bi_mddev) /* nothing to do */ - return; - if (rdev->raid_disk < 0) /* skip spares */ - return; - if (bi_rdev && blk_integrity_compare(mddev->gendisk, - rdev->bdev->bd_disk) >= 0) - return; - WARN_ON_ONCE(!mddev->suspended); - printk(KERN_NOTICE "disabling data integrity on %s\n", mdname(mddev)); - blk_integrity_unregister(mddev->gendisk); + return 0; + + if (blk_integrity_compare(mddev->gendisk, rdev->bdev->bd_disk) != 0) { + printk(KERN_NOTICE "%s: incompatible integrity profile for %s\n", + mdname(mddev), bdevname(rdev->bdev, name)); + return -ENXIO; + } + + return 0; } EXPORT_SYMBOL(md_integrity_add_rdev); diff --git a/drivers/md/md.h b/drivers/md/md.h index ca0b643fe..dfa57b415 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -657,7 +657,7 @@ extern void md_wait_for_blocked_rdev(struct md_rdev *rdev, struct mddev *mddev); extern void md_set_array_sectors(struct mddev *mddev, sector_t array_sectors); extern int md_check_no_bitmap(struct mddev *mddev); extern int md_integrity_register(struct mddev *mddev); -extern void md_integrity_add_rdev(struct md_rdev *rdev, struct mddev *mddev); +extern int md_integrity_add_rdev(struct md_rdev *rdev, struct mddev *mddev); extern int strict_strtoul_scaled(const char *cp, unsigned long *res, int scale); extern void mddev_init(struct mddev *mddev); diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index 7331a80d8..0a72ab6e6 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -257,6 +257,9 @@ static int multipath_add_disk(struct mddev *mddev, struct md_rdev *rdev) disk_stack_limits(mddev->gendisk, rdev->bdev, rdev->data_offset << 9); + err = md_integrity_add_rdev(rdev, mddev); + if (err) + break; spin_lock_irq(&conf->device_lock); mddev->degraded--; rdev->raid_disk = path; @@ -264,9 +267,6 @@ static int multipath_add_disk(struct mddev *mddev, struct md_rdev *rdev) spin_unlock_irq(&conf->device_lock); rcu_assign_pointer(p->rdev, rdev); err = 0; - mddev_suspend(mddev); - md_integrity_add_rdev(rdev, mddev); - mddev_resume(mddev); break; } diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index e2169ff6e..c4b913409 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1589,6 +1589,9 @@ static int raid1_add_disk(struct mddev *mddev, struct md_rdev *rdev) if (mddev->recovery_disabled == conf->recovery_disabled) return -EBUSY; + if (md_integrity_add_rdev(rdev, mddev)) + return -ENXIO; + if (rdev->raid_disk >= 0) first = last = rdev->raid_disk; @@ -1632,9 +1635,6 @@ static int raid1_add_disk(struct mddev *mddev, struct md_rdev *rdev) break; } } - mddev_suspend(mddev); - md_integrity_add_rdev(rdev, mddev); - mddev_resume(mddev); if (mddev->queue && blk_queue_discard(bdev_get_queue(rdev->bdev))) queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, mddev->queue); print_conf(conf); diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 84e597e1c..ce959b4ae 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1698,6 +1698,9 @@ static int raid10_add_disk(struct mddev *mddev, struct md_rdev *rdev) if (rdev->saved_raid_disk < 0 && !_enough(conf, 1, -1)) return -EINVAL; + if (md_integrity_add_rdev(rdev, mddev)) + return -ENXIO; + if (rdev->raid_disk >= 0) first = last = rdev->raid_disk; @@ -1739,9 +1742,6 @@ static int raid10_add_disk(struct mddev *mddev, struct md_rdev *rdev) rcu_assign_pointer(p->rdev, rdev); break; } - mddev_suspend(mddev); - md_integrity_add_rdev(rdev, mddev); - mddev_resume(mddev); if (mddev->queue && blk_queue_discard(bdev_get_queue(rdev->bdev))) queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, mddev->queue); diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c index 728d2cc8a..175a76114 100644 --- a/drivers/media/i2c/ir-kbd-i2c.c +++ b/drivers/media/i2c/ir-kbd-i2c.c @@ -478,7 +478,6 @@ static const struct i2c_device_id ir_kbd_id[] = { { "ir_rx_z8f0811_hdpvr", 0 }, { } }; -MODULE_DEVICE_TABLE(i2c, ir_kbd_id); static struct i2c_driver ir_kbd_driver = { .driver = { diff --git a/drivers/media/pci/saa7134/saa7134-alsa.c b/drivers/media/pci/saa7134/saa7134-alsa.c index 1d2c310ce..94f816244 100644 --- a/drivers/media/pci/saa7134/saa7134-alsa.c +++ b/drivers/media/pci/saa7134/saa7134-alsa.c @@ -1211,6 +1211,8 @@ static int alsa_device_init(struct saa7134_dev *dev) static int alsa_device_exit(struct saa7134_dev *dev) { + if (!snd_saa7134_cards[dev->nr]) + return 1; snd_card_free(snd_saa7134_cards[dev->nr]); snd_saa7134_cards[dev->nr] = NULL; @@ -1260,7 +1262,8 @@ static void saa7134_alsa_exit(void) int idx; for (idx = 0; idx < SNDRV_CARDS; idx++) { - snd_card_free(snd_saa7134_cards[idx]); + if (snd_saa7134_cards[idx]) + snd_card_free(snd_saa7134_cards[idx]); } saa7134_dmasound_init = NULL; diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index ece544efc..3ff583f16 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -3995,6 +3995,9 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, return ret; } + if (!mtd->name && mtd->dev.parent) + mtd->name = dev_name(mtd->dev.parent); + /* Set the default functions */ nand_set_defaults(chip, chip->options & NAND_BUSWIDTH_16); diff --git a/drivers/net/wireless/realtek/rtlwifi/regd.c b/drivers/net/wireless/realtek/rtlwifi/regd.c index a62bf0a65..5be34118e 100644 --- a/drivers/net/wireless/realtek/rtlwifi/regd.c +++ b/drivers/net/wireless/realtek/rtlwifi/regd.c @@ -351,7 +351,6 @@ static const struct ieee80211_regdomain *_rtl_regdomain_select( case COUNTRY_CODE_SPAIN: case COUNTRY_CODE_FRANCE: case COUNTRY_CODE_ISRAEL: - case COUNTRY_CODE_WORLD_WIDE_13: return &rtl_regdom_12_13; case COUNTRY_CODE_MKK: case COUNTRY_CODE_MKK1: @@ -360,6 +359,7 @@ static const struct ieee80211_regdomain *_rtl_regdomain_select( return &rtl_regdom_14_60_64; case COUNTRY_CODE_GLOBAL_DOMAIN: return &rtl_regdom_14; + case COUNTRY_CODE_WORLD_WIDE_13: case COUNTRY_CODE_WORLD_WIDE_13_5G_ALL: return &rtl_regdom_12_13_5g_all; default: diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c index 2f9cf34a7..d83100479 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c @@ -95,8 +95,6 @@ int rtl8821ae_init_sw_vars(struct ieee80211_hw *hw) struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); rtl8821ae_bt_reg_init(hw); - rtlpci->msi_support = rtlpriv->cfg->mod_params->msi_support; - rtlpci->int_clear = rtlpriv->cfg->mod_params->int_clear; rtlpriv->btcoexist.btc_ops = rtl_btc_get_ops_pointer(); rtlpriv->dm.dm_initialgain_enable = 1; @@ -168,12 +166,15 @@ int rtl8821ae_init_sw_vars(struct ieee80211_hw *hw) rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps; rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps; rtlpci->msi_support = rtlpriv->cfg->mod_params->msi_support; - rtlpci->msi_support = rtlpriv->cfg->mod_params->int_clear; + rtlpci->int_clear = rtlpriv->cfg->mod_params->int_clear; + rtlpriv->cfg->mod_params->sw_crypto = + rtlpriv->cfg->mod_params->sw_crypto; + rtlpriv->cfg->mod_params->disable_watchdog = + rtlpriv->cfg->mod_params->disable_watchdog; if (rtlpriv->cfg->mod_params->disable_watchdog) pr_info("watchdog disabled\n"); rtlpriv->psc.reg_fwctrl_lps = 3; rtlpriv->psc.reg_max_lps_awakeintvl = 5; - rtlpci->msi_support = rtlpriv->cfg->mod_params->msi_support; /* for ASPM, you can close aspm through * set const_support_pciaspm = 0 diff --git a/drivers/net/wireless/ti/wlcore/io.h b/drivers/net/wireless/ti/wlcore/io.h index 0305729d0..10cf37476 100644 --- a/drivers/net/wireless/ti/wlcore/io.h +++ b/drivers/net/wireless/ti/wlcore/io.h @@ -207,19 +207,23 @@ static inline int __must_check wlcore_write_reg(struct wl1271 *wl, int reg, static inline void wl1271_power_off(struct wl1271 *wl) { - int ret; + int ret = 0; if (!test_bit(WL1271_FLAG_GPIO_POWER, &wl->flags)) return; - ret = wl->if_ops->power(wl->dev, false); + if (wl->if_ops->power) + ret = wl->if_ops->power(wl->dev, false); if (!ret) clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); } static inline int wl1271_power_on(struct wl1271 *wl) { - int ret = wl->if_ops->power(wl->dev, true); + int ret = 0; + + if (wl->if_ops->power) + ret = wl->if_ops->power(wl->dev, true); if (ret == 0) set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); diff --git a/drivers/net/wireless/ti/wlcore/spi.c b/drivers/net/wireless/ti/wlcore/spi.c index 236b41090..44f059f7f 100644 --- a/drivers/net/wireless/ti/wlcore/spi.c +++ b/drivers/net/wireless/ti/wlcore/spi.c @@ -73,7 +73,10 @@ */ #define SPI_AGGR_BUFFER_SIZE (4 * PAGE_SIZE) -#define WSPI_MAX_NUM_OF_CHUNKS (SPI_AGGR_BUFFER_SIZE / WSPI_MAX_CHUNK_SIZE) +/* Maximum number of SPI write chunks */ +#define WSPI_MAX_NUM_OF_CHUNKS \ + ((SPI_AGGR_BUFFER_SIZE / WSPI_MAX_CHUNK_SIZE) + 1) + struct wl12xx_spi_glue { struct device *dev; @@ -268,9 +271,10 @@ static int __must_check wl12xx_spi_raw_write(struct device *child, int addr, void *buf, size_t len, bool fixed) { struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent); - struct spi_transfer t[2 * (WSPI_MAX_NUM_OF_CHUNKS + 1)]; + /* SPI write buffers - 2 for each chunk */ + struct spi_transfer t[2 * WSPI_MAX_NUM_OF_CHUNKS]; struct spi_message m; - u32 commands[WSPI_MAX_NUM_OF_CHUNKS]; + u32 commands[WSPI_MAX_NUM_OF_CHUNKS]; /* 1 command per chunk */ u32 *cmd; u32 chunk_len; int i; diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index d3346d239..89b3befc7 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -140,6 +140,8 @@ static int pci_bus_alloc_from_region(struct pci_bus *bus, struct resource *res, type_mask |= IORESOURCE_TYPE_BITS; pci_bus_for_each_resource(bus, r, i) { + resource_size_t min_used = min; + if (!r) continue; @@ -163,12 +165,12 @@ static int pci_bus_alloc_from_region(struct pci_bus *bus, struct resource *res, * overrides "min". */ if (avail.start) - min = avail.start; + min_used = avail.start; max = avail.end; /* Ok, try it out.. */ - ret = allocate_resource(r, res, size, min, max, + ret = allocate_resource(r, res, size, min_used, max, align, alignf, alignf_data); if (ret == 0) return 0; diff --git a/drivers/pci/host/pci-dra7xx.c b/drivers/pci/host/pci-dra7xx.c index 8c3688046..923607bda 100644 --- a/drivers/pci/host/pci-dra7xx.c +++ b/drivers/pci/host/pci-dra7xx.c @@ -302,7 +302,8 @@ static int __init dra7xx_add_pcie_port(struct dra7xx_pcie *dra7xx, } ret = devm_request_irq(&pdev->dev, pp->irq, - dra7xx_pcie_msi_irq_handler, IRQF_SHARED, + dra7xx_pcie_msi_irq_handler, + IRQF_SHARED | IRQF_NO_THREAD, "dra7-pcie-msi", pp); if (ret) { dev_err(&pdev->dev, "failed to request irq\n"); diff --git a/drivers/pci/host/pci-exynos.c b/drivers/pci/host/pci-exynos.c index 01095e116..d997d22d4 100644 --- a/drivers/pci/host/pci-exynos.c +++ b/drivers/pci/host/pci-exynos.c @@ -522,7 +522,8 @@ static int __init exynos_add_pcie_port(struct pcie_port *pp, ret = devm_request_irq(&pdev->dev, pp->msi_irq, exynos_pcie_msi_irq_handler, - IRQF_SHARED, "exynos-pcie", pp); + IRQF_SHARED | IRQF_NO_THREAD, + "exynos-pcie", pp); if (ret) { dev_err(&pdev->dev, "failed to request msi irq\n"); return ret; diff --git a/drivers/pci/host/pci-imx6.c b/drivers/pci/host/pci-imx6.c index 22e822412..9ce7cd148 100644 --- a/drivers/pci/host/pci-imx6.c +++ b/drivers/pci/host/pci-imx6.c @@ -537,7 +537,8 @@ static int __init imx6_add_pcie_port(struct pcie_port *pp, ret = devm_request_irq(&pdev->dev, pp->msi_irq, imx6_pcie_msi_handler, - IRQF_SHARED, "mx6-pcie-msi", pp); + IRQF_SHARED | IRQF_NO_THREAD, + "mx6-pcie-msi", pp); if (ret) { dev_err(&pdev->dev, "failed to request MSI irq\n"); return ret; diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c index 3018ae52e..30323114c 100644 --- a/drivers/pci/host/pci-tegra.c +++ b/drivers/pci/host/pci-tegra.c @@ -1288,7 +1288,7 @@ static int tegra_pcie_enable_msi(struct tegra_pcie *pcie) msi->irq = err; - err = request_irq(msi->irq, tegra_pcie_msi_irq, 0, + err = request_irq(msi->irq, tegra_pcie_msi_irq, IRQF_NO_THREAD, tegra_msi_irq_chip.name, pcie); if (err < 0) { dev_err(&pdev->dev, "failed to request IRQ: %d\n", err); diff --git a/drivers/pci/host/pcie-rcar.c b/drivers/pci/host/pcie-rcar.c index f4fa6c537..414c33686 100644 --- a/drivers/pci/host/pcie-rcar.c +++ b/drivers/pci/host/pcie-rcar.c @@ -720,14 +720,16 @@ static int rcar_pcie_enable_msi(struct rcar_pcie *pcie) /* Two irqs are for MSI, but they are also used for non-MSI irqs */ err = devm_request_irq(&pdev->dev, msi->irq1, rcar_pcie_msi_irq, - IRQF_SHARED, rcar_msi_irq_chip.name, pcie); + IRQF_SHARED | IRQF_NO_THREAD, + rcar_msi_irq_chip.name, pcie); if (err < 0) { dev_err(&pdev->dev, "failed to request IRQ: %d\n", err); goto err; } err = devm_request_irq(&pdev->dev, msi->irq2, rcar_pcie_msi_irq, - IRQF_SHARED, rcar_msi_irq_chip.name, pcie); + IRQF_SHARED | IRQF_NO_THREAD, + rcar_msi_irq_chip.name, pcie); if (err < 0) { dev_err(&pdev->dev, "failed to request IRQ: %d\n", err); goto err; diff --git a/drivers/pci/host/pcie-spear13xx.c b/drivers/pci/host/pcie-spear13xx.c index b95b7563c..a6cd8233e 100644 --- a/drivers/pci/host/pcie-spear13xx.c +++ b/drivers/pci/host/pcie-spear13xx.c @@ -279,7 +279,8 @@ static int spear13xx_add_pcie_port(struct pcie_port *pp, return -ENODEV; } ret = devm_request_irq(dev, pp->irq, spear13xx_pcie_irq_handler, - IRQF_SHARED, "spear1340-pcie", pp); + IRQF_SHARED | IRQF_NO_THREAD, + "spear1340-pcie", pp); if (ret) { dev_err(dev, "failed to request irq %d\n", pp->irq); return ret; diff --git a/drivers/pci/host/pcie-xilinx.c b/drivers/pci/host/pcie-xilinx.c index 3c7a0d580..4cfa46360 100644 --- a/drivers/pci/host/pcie-xilinx.c +++ b/drivers/pci/host/pcie-xilinx.c @@ -781,7 +781,8 @@ static int xilinx_pcie_parse_dt(struct xilinx_pcie_port *port) port->irq = irq_of_parse_and_map(node, 0); err = devm_request_irq(dev, port->irq, xilinx_pcie_intr_handler, - IRQF_SHARED, "xilinx-pcie", port); + IRQF_SHARED | IRQF_NO_THREAD, + "xilinx-pcie", port); if (err) { dev_err(dev, "unable to request irq %d\n", port->irq); return err; diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index e49c2bce5..cf000b331 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -258,16 +258,13 @@ static void n_tty_check_throttle(struct tty_struct *tty) static void n_tty_check_unthrottle(struct tty_struct *tty) { - if (tty->driver->type == TTY_DRIVER_TYPE_PTY && - tty->link->ldisc->ops->write_wakeup == n_tty_write_wakeup) { + if (tty->driver->type == TTY_DRIVER_TYPE_PTY) { if (chars_in_buffer(tty) > TTY_THRESHOLD_UNTHROTTLE) return; if (!tty->count) return; n_tty_kick_worker(tty); - n_tty_write_wakeup(tty->link); - if (waitqueue_active(&tty->link->write_wait)) - wake_up_interruptible_poll(&tty->link->write_wait, POLLOUT); + tty_wakeup(tty->link); return; } diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index bcc8e1e8b..7cef54334 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -1462,13 +1462,13 @@ static int tty_reopen(struct tty_struct *tty) { struct tty_driver *driver = tty->driver; - if (!tty->count) - return -EIO; - if (driver->type == TTY_DRIVER_TYPE_PTY && driver->subtype == PTY_TYPE_MASTER) return -EIO; + if (!tty->count) + return -EAGAIN; + if (test_bit(TTY_EXCLUSIVE, &tty->flags) && !capable(CAP_SYS_ADMIN)) return -EBUSY; @@ -2069,7 +2069,12 @@ retry_open: if (tty) { mutex_unlock(&tty_mutex); - tty_lock(tty); + retval = tty_lock_interruptible(tty); + if (retval) { + if (retval == -EINTR) + retval = -ERESTARTSYS; + goto err_unref; + } /* safe to drop the kref from tty_driver_lookup_tty() */ tty_kref_put(tty); retval = tty_reopen(tty); @@ -2087,7 +2092,11 @@ retry_open: if (IS_ERR(tty)) { retval = PTR_ERR(tty); - goto err_file; + if (retval != -EAGAIN || signal_pending(current)) + goto err_file; + tty_free_file(filp); + schedule(); + goto retry_open; } tty_add_file(tty, filp); @@ -2156,6 +2165,7 @@ retry_open: return 0; err_unlock: mutex_unlock(&tty_mutex); +err_unref: /* after locks to avoid deadlock */ if (!IS_ERR_OR_NULL(driver)) tty_driver_kref_put(driver); @@ -2653,6 +2663,28 @@ static int tiocsetd(struct tty_struct *tty, int __user *p) } /** + * tiocgetd - get line discipline + * @tty: tty device + * @p: pointer to user data + * + * Retrieves the line discipline id directly from the ldisc. + * + * Locking: waits for ldisc reference (in case the line discipline + * is changing or the tty is being hungup) + */ + +static int tiocgetd(struct tty_struct *tty, int __user *p) +{ + struct tty_ldisc *ld; + int ret; + + ld = tty_ldisc_ref_wait(tty); + ret = put_user(ld->ops->num, p); + tty_ldisc_deref(ld); + return ret; +} + +/** * send_break - performed time break * @tty: device to break on * @duration: timeout in mS @@ -2878,7 +2910,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case TIOCGSID: return tiocgsid(tty, real_tty, p); case TIOCGETD: - return put_user(tty->ldisc->ops->num, (int __user *)p); + return tiocgetd(tty, p); case TIOCSETD: return tiocsetd(tty, p); case TIOCVHANGUP: diff --git a/drivers/tty/tty_mutex.c b/drivers/tty/tty_mutex.c index 0efcf713b..d09293bc0 100644 --- a/drivers/tty/tty_mutex.c +++ b/drivers/tty/tty_mutex.c @@ -22,6 +22,14 @@ void __lockfunc tty_lock(struct tty_struct *tty) } EXPORT_SYMBOL(tty_lock); +int tty_lock_interruptible(struct tty_struct *tty) +{ + if (WARN(tty->magic != TTY_MAGIC, "L Bad %p\n", tty)) + return -EIO; + tty_kref_get(tty); + return mutex_lock_interruptible(&tty->legacy_mutex); +} + void __lockfunc tty_unlock(struct tty_struct *tty) { if (tty->magic != TTY_MAGIC) { diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 26ca4f910..e4c70dce3 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -428,7 +428,8 @@ static void acm_read_bulk_callback(struct urb *urb) set_bit(rb->index, &acm->read_urbs_free); dev_dbg(&acm->data->dev, "%s - non-zero urb status: %d\n", __func__, status); - return; + if ((status != -ENOENT) || (urb->actual_length == 0)) + return; } usb_mark_last_busy(acm->dev); @@ -1404,6 +1405,8 @@ made_compressed_probe: usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress), NULL, acm->writesize, acm_write_bulk, snd); snd->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + if (quirks & SEND_ZERO_PACKET) + snd->urb->transfer_flags |= URB_ZERO_PACKET; snd->instance = acm; } @@ -1861,6 +1864,10 @@ static const struct usb_device_id acm_ids[] = { { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, USB_CDC_ACM_PROTO_AT_CDMA) }, + { USB_DEVICE(0x1519, 0x0452), /* Intel 7260 modem */ + .driver_info = SEND_ZERO_PACKET, + }, + { } }; diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h index dd9af38e7..ccfaba9ab 100644 --- a/drivers/usb/class/cdc-acm.h +++ b/drivers/usb/class/cdc-acm.h @@ -134,3 +134,4 @@ struct acm { #define IGNORE_DEVICE BIT(5) #define QUIRK_CONTROL_LINE_STATE BIT(6) #define CLEAR_HALT_CONDITIONS BIT(7) +#define SEND_ZERO_PACKET BIT(8) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 868343678..1560f3f3e 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -5386,7 +5386,6 @@ static int usb_reset_and_verify_device(struct usb_device *udev) } bos = udev->bos; - udev->bos = NULL; for (i = 0; i < SET_CONFIG_TRIES; ++i) { @@ -5479,8 +5478,11 @@ done: usb_set_usb2_hardware_lpm(udev, 1); usb_unlocked_enable_lpm(udev); usb_enable_ltm(udev); - usb_release_bos_descriptor(udev); - udev->bos = bos; + /* release the new BOS descriptor allocated by hub_port_init() */ + if (udev->bos != bos) { + usb_release_bos_descriptor(udev); + udev->bos = bos; + } return 0; re_enumerate: diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index c62109091..c2d65206e 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -28,7 +28,9 @@ #include "xhci.h" #include "xhci-trace.h" -#define PORT2_SSIC_CONFIG_REG2 0x883c +#define SSIC_PORT_NUM 2 +#define SSIC_PORT_CFG2 0x880c +#define SSIC_PORT_CFG2_OFFSET 0x30 #define PROG_DONE (1 << 30) #define SSIC_PORT_UNUSED (1 << 31) @@ -45,6 +47,7 @@ #define PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI 0x22b5 #define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_XHCI 0xa12f #define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI 0x9d2f +#define PCI_DEVICE_ID_INTEL_BROXTON_M_XHCI 0x0aa8 static const char hcd_name[] = "xhci_hcd"; @@ -152,7 +155,8 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) if (pdev->vendor == PCI_VENDOR_ID_INTEL && (pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI || pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_XHCI || - pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI)) { + pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI || + pdev->device == PCI_DEVICE_ID_INTEL_BROXTON_M_XHCI)) { xhci->quirks |= XHCI_PME_STUCK_QUIRK; } if (pdev->vendor == PCI_VENDOR_ID_ETRON && @@ -322,28 +326,36 @@ static void xhci_pme_quirk(struct usb_hcd *hcd, bool suspend) struct pci_dev *pdev = to_pci_dev(hcd->self.controller); u32 val; void __iomem *reg; + int i; if (pdev->vendor == PCI_VENDOR_ID_INTEL && pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI) { - reg = (void __iomem *) xhci->cap_regs + PORT2_SSIC_CONFIG_REG2; - - /* Notify SSIC that SSIC profile programming is not done */ - val = readl(reg) & ~PROG_DONE; - writel(val, reg); - - /* Mark SSIC port as unused(suspend) or used(resume) */ - val = readl(reg); - if (suspend) - val |= SSIC_PORT_UNUSED; - else - val &= ~SSIC_PORT_UNUSED; - writel(val, reg); - - /* Notify SSIC that SSIC profile programming is done */ - val = readl(reg) | PROG_DONE; - writel(val, reg); - readl(reg); + for (i = 0; i < SSIC_PORT_NUM; i++) { + reg = (void __iomem *) xhci->cap_regs + + SSIC_PORT_CFG2 + + i * SSIC_PORT_CFG2_OFFSET; + + /* + * Notify SSIC that SSIC profile programming + * is not done. + */ + val = readl(reg) & ~PROG_DONE; + writel(val, reg); + + /* Mark SSIC port as unused(suspend) or used(resume) */ + val = readl(reg); + if (suspend) + val |= SSIC_PORT_UNUSED; + else + val &= ~SSIC_PORT_UNUSED; + writel(val, reg); + + /* Notify SSIC that SSIC profile programming is done */ + val = readl(reg) | PROG_DONE; + writel(val, reg); + readl(reg); + } } reg = (void __iomem *) xhci->cap_regs + 0x80a4; diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index 0d19a6d61..970a30e15 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -1599,6 +1599,8 @@ static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg) &motg->id.nb); if (ret < 0) { dev_err(&pdev->dev, "register ID notifier failed\n"); + extcon_unregister_notifier(motg->vbus.extcon, + EXTCON_USB, &motg->vbus.nb); return ret; } @@ -1660,15 +1662,6 @@ static int msm_otg_probe(struct platform_device *pdev) if (!motg) return -ENOMEM; - pdata = dev_get_platdata(&pdev->dev); - if (!pdata) { - if (!np) - return -ENXIO; - ret = msm_otg_read_dt(pdev, motg); - if (ret) - return ret; - } - motg->phy.otg = devm_kzalloc(&pdev->dev, sizeof(struct usb_otg), GFP_KERNEL); if (!motg->phy.otg) @@ -1710,6 +1703,15 @@ static int msm_otg_probe(struct platform_device *pdev) if (!motg->regs) return -ENOMEM; + pdata = dev_get_platdata(&pdev->dev); + if (!pdata) { + if (!np) + return -ENXIO; + ret = msm_otg_read_dt(pdev, motg); + if (ret) + return ret; + } + /* * NOTE: The PHYs can be multiplexed between the chipidea controller * and the dwc3 controller, using a single bit. It is important that @@ -1717,8 +1719,10 @@ static int msm_otg_probe(struct platform_device *pdev) */ if (motg->phy_number) { phy_select = devm_ioremap_nocache(&pdev->dev, USB2_PHY_SEL, 4); - if (!phy_select) - return -ENOMEM; + if (!phy_select) { + ret = -ENOMEM; + goto unregister_extcon; + } /* Enable second PHY with the OTG port */ writel(0x1, phy_select); } @@ -1728,7 +1732,8 @@ static int msm_otg_probe(struct platform_device *pdev) motg->irq = platform_get_irq(pdev, 0); if (motg->irq < 0) { dev_err(&pdev->dev, "platform_get_irq failed\n"); - return motg->irq; + ret = motg->irq; + goto unregister_extcon; } regs[0].supply = "vddcx"; @@ -1737,7 +1742,7 @@ static int msm_otg_probe(struct platform_device *pdev) ret = devm_regulator_bulk_get(motg->phy.dev, ARRAY_SIZE(regs), regs); if (ret) - return ret; + goto unregister_extcon; motg->vddcx = regs[0].consumer; motg->v3p3 = regs[1].consumer; @@ -1834,6 +1839,12 @@ disable_clks: clk_disable_unprepare(motg->clk); if (!IS_ERR(motg->core_clk)) clk_disable_unprepare(motg->core_clk); +unregister_extcon: + extcon_unregister_notifier(motg->id.extcon, + EXTCON_USB_HOST, &motg->id.nb); + extcon_unregister_notifier(motg->vbus.extcon, + EXTCON_USB, &motg->vbus.nb); + return ret; } diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 59b2126b2..1dd991908 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -98,6 +98,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x10C4, 0x81AC) }, /* MSD Dash Hawk */ { USB_DEVICE(0x10C4, 0x81AD) }, /* INSYS USB Modem */ { USB_DEVICE(0x10C4, 0x81C8) }, /* Lipowsky Industrie Elektronik GmbH, Baby-JTAG */ + { USB_DEVICE(0x10C4, 0x81D7) }, /* IAI Corp. RCB-CV-USB USB to RS485 Adaptor */ { USB_DEVICE(0x10C4, 0x81E2) }, /* Lipowsky Industrie Elektronik GmbH, Baby-LIN */ { USB_DEVICE(0x10C4, 0x81E7) }, /* Aerocomm Radio */ { USB_DEVICE(0x10C4, 0x81E8) }, /* Zephyr Bioharness */ diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index a5a0376bb..8c660ae40 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -824,6 +824,7 @@ static const struct usb_device_id id_table_combined[] = { { USB_DEVICE(FTDI_VID, FTDI_TURTELIZER_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) }, + { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_SCU18) }, { USB_DEVICE(FTDI_VID, FTDI_REU_TINY_PID) }, /* Papouch devices based on FTDI chip */ diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 67c6d4469..a84df2513 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -615,6 +615,7 @@ */ #define RATOC_VENDOR_ID 0x0584 #define RATOC_PRODUCT_ID_USB60F 0xb020 +#define RATOC_PRODUCT_ID_SCU18 0xb03a /* * Infineon Technologies diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index f2280606b..db86e512e 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -268,6 +268,8 @@ static void option_instat_callback(struct urb *urb); #define TELIT_PRODUCT_CC864_SINGLE 0x1006 #define TELIT_PRODUCT_DE910_DUAL 0x1010 #define TELIT_PRODUCT_UE910_V2 0x1012 +#define TELIT_PRODUCT_LE922_USBCFG0 0x1042 +#define TELIT_PRODUCT_LE922_USBCFG3 0x1043 #define TELIT_PRODUCT_LE920 0x1200 #define TELIT_PRODUCT_LE910 0x1201 @@ -615,6 +617,16 @@ static const struct option_blacklist_info telit_le920_blacklist = { .reserved = BIT(1) | BIT(5), }; +static const struct option_blacklist_info telit_le922_blacklist_usbcfg0 = { + .sendsetup = BIT(2), + .reserved = BIT(0) | BIT(1) | BIT(3), +}; + +static const struct option_blacklist_info telit_le922_blacklist_usbcfg3 = { + .sendsetup = BIT(0), + .reserved = BIT(1) | BIT(2) | BIT(3), +}; + static const struct usb_device_id option_ids[] = { { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) }, { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) }, @@ -1160,6 +1172,10 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_SINGLE) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_DE910_DUAL) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UE910_V2) }, + { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG0), + .driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg0 }, + { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG3), + .driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg3 }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910), .driver_info = (kernel_ulong_t)&telit_le910_blacklist }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920), @@ -1679,7 +1695,7 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EU3_P) }, { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8), .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, - { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX) }, + { USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX, 0xff) }, { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PLXX), .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDM) }, diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 60afb39eb..337a0be89 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -544,6 +544,11 @@ static int treo_attach(struct usb_serial *serial) (serial->num_interrupt_in == 0)) return 0; + if (serial->num_bulk_in < 2 || serial->num_interrupt_in < 2) { + dev_err(&serial->interface->dev, "missing endpoints\n"); + return -ENODEV; + } + /* * It appears that Treos and Kyoceras want to use the * 1st bulk in endpoint to communicate with the 2nd bulk out endpoint, @@ -597,8 +602,10 @@ static int clie_5_attach(struct usb_serial *serial) */ /* some sanity check */ - if (serial->num_ports < 2) - return -1; + if (serial->num_bulk_out < 2) { + dev_err(&serial->interface->dev, "missing bulk out endpoints\n"); + return -ENODEV; + } /* port 0 now uses the modified endpoint Address */ port = serial->port[0]; diff --git a/fs/aufs/aufs.h b/fs/aufs/aufs.h index 75290bdbb..49f43b433 100644 --- a/fs/aufs/aufs.h +++ b/fs/aufs/aufs.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/branch.c b/fs/aufs/branch.c index f49142260..1ab5e1f2d 100644 --- a/fs/aufs/branch.c +++ b/fs/aufs/branch.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/branch.h b/fs/aufs/branch.h index 7b9e7c9cd..4c52ae166 100644 --- a/fs/aufs/branch.h +++ b/fs/aufs/branch.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/cpup.c b/fs/aufs/cpup.c index cd322746c..a34648874 100644 --- a/fs/aufs/cpup.c +++ b/fs/aufs/cpup.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* @@ -8,6 +8,7 @@ #include <linux/fs_stack.h> #include <linux/mm.h> +#include <linux/task_work.h> #include "aufs.h" void au_cpup_attr_flags(struct inode *dst, unsigned int iflags) @@ -380,6 +381,7 @@ static int au_cp_regular(struct au_cp_generic *cpg) } }; struct super_block *sb; + struct task_struct *tsk = current; /* bsrc branch can be ro/rw. */ sb = cpg->dentry->d_sb; @@ -397,7 +399,21 @@ static int au_cp_regular(struct au_cp_generic *cpg) IMustLock(d_inode(file[SRC].dentry)); err = au_copy_file(file[DST].file, file[SRC].file, cpg->len); - fput(file[DST].file); + /* i wonder if we had O_NO_DELAY_FPUT flag */ + if (tsk->flags & PF_KTHREAD) + __fput_sync(file[DST].file); + else { + WARN(1, "%pD\nPlease report this warning to aufs-users ML", + file[DST].file); + fput(file[DST].file); + /* + * too bad. + * we have to call both since we don't know which place the file + * was added to. + */ + task_work_run(); + flush_delayed_fput(); + } au_sbr_put(sb, file[DST].bindex); out_src: diff --git a/fs/aufs/cpup.h b/fs/aufs/cpup.h index 3355f0880..ccba2c427 100644 --- a/fs/aufs/cpup.h +++ b/fs/aufs/cpup.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/dbgaufs.c b/fs/aufs/dbgaufs.c index c7c612c28..0aefb5ed8 100644 --- a/fs/aufs/dbgaufs.c +++ b/fs/aufs/dbgaufs.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/dbgaufs.h b/fs/aufs/dbgaufs.h index efa9a4db9..81f272e42 100644 --- a/fs/aufs/dbgaufs.h +++ b/fs/aufs/dbgaufs.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/dcsub.c b/fs/aufs/dcsub.c index f9d9d526c..e72accebb 100644 --- a/fs/aufs/dcsub.c +++ b/fs/aufs/dcsub.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/dcsub.h b/fs/aufs/dcsub.h index 2aa87acc3..5d2cf661d 100644 --- a/fs/aufs/dcsub.h +++ b/fs/aufs/dcsub.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/debug.c b/fs/aufs/debug.c index 42053aa7f..4529831a9 100644 --- a/fs/aufs/debug.c +++ b/fs/aufs/debug.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/debug.h b/fs/aufs/debug.h index 0a2e7e7b0..0567f31d0 100644 --- a/fs/aufs/debug.h +++ b/fs/aufs/debug.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/dentry.c b/fs/aufs/dentry.c index aad25be88..e47a7e6c4 100644 --- a/fs/aufs/dentry.c +++ b/fs/aufs/dentry.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/dentry.h b/fs/aufs/dentry.h index 522522179..c794adf59 100644 --- a/fs/aufs/dentry.h +++ b/fs/aufs/dentry.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/dinfo.c b/fs/aufs/dinfo.c index 25b971bc6..ad6d045c4 100644 --- a/fs/aufs/dinfo.c +++ b/fs/aufs/dinfo.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/dir.c b/fs/aufs/dir.c index ccdcebeb3..8a619062a 100644 --- a/fs/aufs/dir.c +++ b/fs/aufs/dir.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/dir.h b/fs/aufs/dir.h index 803a0f1a5..b0a79d722 100644 --- a/fs/aufs/dir.h +++ b/fs/aufs/dir.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/dynop.c b/fs/aufs/dynop.c index 1f1283814..53a8b55d8 100644 --- a/fs/aufs/dynop.c +++ b/fs/aufs/dynop.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2015 Junjiro R. Okajima + * Copyright (C) 2010-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/dynop.h b/fs/aufs/dynop.h index 6d739c124..8680bfc53 100644 --- a/fs/aufs/dynop.h +++ b/fs/aufs/dynop.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2015 Junjiro R. Okajima + * Copyright (C) 2010-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/export.c b/fs/aufs/export.c index 3026f39a7..4ce7732b7 100644 --- a/fs/aufs/export.c +++ b/fs/aufs/export.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/f_op.c b/fs/aufs/f_op.c index 91c2ce78a..c1be75cb0 100644 --- a/fs/aufs/f_op.c +++ b/fs/aufs/f_op.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/fhsm.c b/fs/aufs/fhsm.c index 47106cbe9..db079d6ee 100644 --- a/fs/aufs/fhsm.c +++ b/fs/aufs/fhsm.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2015 Junjiro R. Okajima + * Copyright (C) 2011-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/file.c b/fs/aufs/file.c index 72316b122..6b8a66b4a 100644 --- a/fs/aufs/file.c +++ b/fs/aufs/file.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/file.h b/fs/aufs/file.h index 488473e31..27d802487 100644 --- a/fs/aufs/file.h +++ b/fs/aufs/file.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/finfo.c b/fs/aufs/finfo.c index e709205b5..b5eb55dfb 100644 --- a/fs/aufs/finfo.c +++ b/fs/aufs/finfo.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/fstype.h b/fs/aufs/fstype.h index 6196c606b..e429a8b17 100644 --- a/fs/aufs/fstype.h +++ b/fs/aufs/fstype.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* @@ -240,6 +240,7 @@ static inline int au_test_hfsplus(struct super_block *sb __maybe_unused) static inline int au_test_fs_unsuppoted(struct super_block *sb) { return + au_test_fuse(sb) || /* for a security reason, temporarily */ #ifndef CONFIG_AUFS_BR_RAMFS au_test_ramfs(sb) || #endif diff --git a/fs/aufs/hfsnotify.c b/fs/aufs/hfsnotify.c index 5c370196f..c0a1a63a9 100644 --- a/fs/aufs/hfsnotify.c +++ b/fs/aufs/hfsnotify.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/hfsplus.c b/fs/aufs/hfsplus.c index 34c1f1abf..145c6ac2f 100644 --- a/fs/aufs/hfsplus.c +++ b/fs/aufs/hfsplus.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2015 Junjiro R. Okajima + * Copyright (C) 2010-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/hnotify.c b/fs/aufs/hnotify.c index 3943dc4b4..3e0a4f67d 100644 --- a/fs/aufs/hnotify.c +++ b/fs/aufs/hnotify.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/i_op.c b/fs/aufs/i_op.c index daad67aa1..1c634bab9 100644 --- a/fs/aufs/i_op.c +++ b/fs/aufs/i_op.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/i_op_add.c b/fs/aufs/i_op_add.c index 0c3530e55..3fc355859 100644 --- a/fs/aufs/i_op_add.c +++ b/fs/aufs/i_op_add.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/i_op_del.c b/fs/aufs/i_op_del.c index 3cd4c7b19..68741aadb 100644 --- a/fs/aufs/i_op_del.c +++ b/fs/aufs/i_op_del.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/i_op_ren.c b/fs/aufs/i_op_ren.c index fd815fdbc..c880144b5 100644 --- a/fs/aufs/i_op_ren.c +++ b/fs/aufs/i_op_ren.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/iinfo.c b/fs/aufs/iinfo.c index c604f6987..67ef672a0 100644 --- a/fs/aufs/iinfo.c +++ b/fs/aufs/iinfo.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/inode.c b/fs/aufs/inode.c index cedc53420..5a87727ba 100644 --- a/fs/aufs/inode.c +++ b/fs/aufs/inode.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/inode.h b/fs/aufs/inode.h index c3e26940f..534b9e814 100644 --- a/fs/aufs/inode.h +++ b/fs/aufs/inode.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/ioctl.c b/fs/aufs/ioctl.c index 87e3ddc88..6528fb911 100644 --- a/fs/aufs/ioctl.c +++ b/fs/aufs/ioctl.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/loop.c b/fs/aufs/loop.c index f324758e9..5711e7a2f 100644 --- a/fs/aufs/loop.c +++ b/fs/aufs/loop.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/loop.h b/fs/aufs/loop.h index 6d9864dff..48bf070e8 100644 --- a/fs/aufs/loop.h +++ b/fs/aufs/loop.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/module.c b/fs/aufs/module.c index 3268e62e4..ec12f2e66 100644 --- a/fs/aufs/module.c +++ b/fs/aufs/module.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/module.h b/fs/aufs/module.h index adee827fa..b129ad4b6 100644 --- a/fs/aufs/module.h +++ b/fs/aufs/module.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/mvdown.c b/fs/aufs/mvdown.c index 53e0f6af9..1f2224f6d 100644 --- a/fs/aufs/mvdown.c +++ b/fs/aufs/mvdown.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2015 Junjiro R. Okajima + * Copyright (C) 2011-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/opts.c b/fs/aufs/opts.c index f79d15e32..5c39817f3 100644 --- a/fs/aufs/opts.c +++ b/fs/aufs/opts.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/opts.h b/fs/aufs/opts.h index 3899e9240..0d6c2e1c7 100644 --- a/fs/aufs/opts.h +++ b/fs/aufs/opts.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/plink.c b/fs/aufs/plink.c index af2246c09..6fdab1e0e 100644 --- a/fs/aufs/plink.c +++ b/fs/aufs/plink.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/poll.c b/fs/aufs/poll.c index c324fc727..dd2baf5dc 100644 --- a/fs/aufs/poll.c +++ b/fs/aufs/poll.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/posix_acl.c b/fs/aufs/posix_acl.c index d9ce95724..1c19e629b 100644 --- a/fs/aufs/posix_acl.c +++ b/fs/aufs/posix_acl.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2015 Junjiro R. Okajima + * Copyright (C) 2014-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/procfs.c b/fs/aufs/procfs.c index ead2a0052..2c8893edf 100644 --- a/fs/aufs/procfs.c +++ b/fs/aufs/procfs.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2015 Junjiro R. Okajima + * Copyright (C) 2010-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/rdu.c b/fs/aufs/rdu.c index f11d9bbbd..a9e9e9893 100644 --- a/fs/aufs/rdu.c +++ b/fs/aufs/rdu.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/rwsem.h b/fs/aufs/rwsem.h index 171ee0c18..ef50c2ccb 100644 --- a/fs/aufs/rwsem.h +++ b/fs/aufs/rwsem.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/sbinfo.c b/fs/aufs/sbinfo.c index 8f2ec5573..e3c58f643 100644 --- a/fs/aufs/sbinfo.c +++ b/fs/aufs/sbinfo.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/spl.h b/fs/aufs/spl.h index a66d39e9e..f9b528826 100644 --- a/fs/aufs/spl.h +++ b/fs/aufs/spl.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/super.c b/fs/aufs/super.c index 98cfd64dd..b41d78913 100644 --- a/fs/aufs/super.c +++ b/fs/aufs/super.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/super.h b/fs/aufs/super.h index d15172962..2761df917 100644 --- a/fs/aufs/super.h +++ b/fs/aufs/super.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/sysaufs.c b/fs/aufs/sysaufs.c index 29ac6faa6..8ec10fb31 100644 --- a/fs/aufs/sysaufs.c +++ b/fs/aufs/sysaufs.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/sysaufs.h b/fs/aufs/sysaufs.h index feb78fd86..1f799835e 100644 --- a/fs/aufs/sysaufs.h +++ b/fs/aufs/sysaufs.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/sysfs.c b/fs/aufs/sysfs.c index ec8df8f6c..ed42f53d0 100644 --- a/fs/aufs/sysfs.c +++ b/fs/aufs/sysfs.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/sysrq.c b/fs/aufs/sysrq.c index 3a0182b90..7921ed716 100644 --- a/fs/aufs/sysrq.c +++ b/fs/aufs/sysrq.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/vdir.c b/fs/aufs/vdir.c index db81f49dd..f64cc2b7a 100644 --- a/fs/aufs/vdir.c +++ b/fs/aufs/vdir.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/vfsub.c b/fs/aufs/vfsub.c index da0df5a38..f072c59c0 100644 --- a/fs/aufs/vfsub.c +++ b/fs/aufs/vfsub.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/vfsub.h b/fs/aufs/vfsub.h index 4218da12e..a7d8a1cf9 100644 --- a/fs/aufs/vfsub.h +++ b/fs/aufs/vfsub.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/wbr_policy.c b/fs/aufs/wbr_policy.c index 53a01fb06..c822b428d 100644 --- a/fs/aufs/wbr_policy.c +++ b/fs/aufs/wbr_policy.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/whout.c b/fs/aufs/whout.c index 05ba0857b..04eb9af2b 100644 --- a/fs/aufs/whout.c +++ b/fs/aufs/whout.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/whout.h b/fs/aufs/whout.h index b39acea2c..4077dd19e 100644 --- a/fs/aufs/whout.h +++ b/fs/aufs/whout.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/wkq.c b/fs/aufs/wkq.c index 08870ec06..0f1500e93 100644 --- a/fs/aufs/wkq.c +++ b/fs/aufs/wkq.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/wkq.h b/fs/aufs/wkq.h index 8f01343d8..f6c9b9902 100644 --- a/fs/aufs/wkq.h +++ b/fs/aufs/wkq.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/xattr.c b/fs/aufs/xattr.c index c1695b329..f592e05ea 100644 --- a/fs/aufs/xattr.c +++ b/fs/aufs/xattr.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2015 Junjiro R. Okajima + * Copyright (C) 2014-2016 Junjiro R. Okajima */ /* diff --git a/fs/aufs/xino.c b/fs/aufs/xino.c index 61df836cd..994258e3f 100644 --- a/fs/aufs/xino.c +++ b/fs/aufs/xino.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ /* diff --git a/fs/ext4/crypto_key.c b/fs/ext4/crypto_key.c index c5882b36e..9a16d1e75 100644 --- a/fs/ext4/crypto_key.c +++ b/fs/ext4/crypto_key.c @@ -213,9 +213,11 @@ retry: res = -ENOKEY; goto out; } + down_read(&keyring_key->sem); ukp = user_key_payload(keyring_key); if (ukp->datalen != sizeof(struct ext4_encryption_key)) { res = -EINVAL; + up_read(&keyring_key->sem); goto out; } master_key = (struct ext4_encryption_key *)ukp->data; @@ -226,10 +228,12 @@ retry: "ext4: key size incorrect: %d\n", master_key->size); res = -ENOKEY; + up_read(&keyring_key->sem); goto out; } res = ext4_derive_key_aes(ctx.nonce, master_key->raw, raw_key); + up_read(&keyring_key->sem); if (res) goto out; got_key: diff --git a/fs/file_table.c b/fs/file_table.c index df66450fb..38e046adc 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -259,6 +259,7 @@ void flush_delayed_fput(void) { delayed_fput(NULL); } +EXPORT_SYMBOL(flush_delayed_fput); static DECLARE_DELAYED_WORK(delayed_fput_work, delayed_fput); @@ -301,6 +302,7 @@ void __fput_sync(struct file *file) } EXPORT_SYMBOL(fput); +EXPORT_SYMBOL(__fput_sync); void put_filp(struct file *file) { diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 89818036f..343b0f1f1 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -8054,7 +8054,6 @@ static void nfs4_layoutreturn_release(void *calldata) pnfs_set_layout_stateid(lo, &lrp->res.stateid, true); pnfs_mark_matching_lsegs_invalid(lo, &freeme, &lrp->args.range); pnfs_clear_layoutreturn_waitbit(lo); - lo->plh_block_lgets--; spin_unlock(&lo->plh_inode->i_lock); pnfs_free_lseg_list(&freeme); pnfs_put_layout_hdr(lrp->args.layout); diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c index 84f2f8079..4e2162b35 100644 --- a/fs/ocfs2/dlm/dlmmaster.c +++ b/fs/ocfs2/dlm/dlmmaster.c @@ -2519,6 +2519,11 @@ static int dlm_migrate_lockres(struct dlm_ctxt *dlm, spin_lock(&dlm->master_lock); ret = dlm_add_migration_mle(dlm, res, mle, &oldmle, name, namelen, target, dlm->node_num); + /* get an extra reference on the mle. + * otherwise the assert_master from the new + * master will destroy this. + */ + dlm_get_mle_inuse(mle); spin_unlock(&dlm->master_lock); spin_unlock(&dlm->spinlock); @@ -2554,6 +2559,7 @@ fail: if (mle_added) { dlm_mle_detach_hb_events(dlm, mle); dlm_put_mle(mle); + dlm_put_mle_inuse(mle); } else if (mle) { kmem_cache_free(dlm_mle_cache, mle); mle = NULL; @@ -2571,17 +2577,6 @@ fail: * ensure that all assert_master work is flushed. */ flush_workqueue(dlm->dlm_worker); - /* get an extra reference on the mle. - * otherwise the assert_master from the new - * master will destroy this. - * also, make sure that all callers of dlm_get_mle - * take both dlm->spinlock and dlm->master_lock */ - spin_lock(&dlm->spinlock); - spin_lock(&dlm->master_lock); - dlm_get_mle_inuse(mle); - spin_unlock(&dlm->master_lock); - spin_unlock(&dlm->spinlock); - /* notify new node and send all lock state */ /* call send_one_lockres with migration flag. * this serves as notice to the target node that a @@ -3312,6 +3307,15 @@ top: mle->new_master != dead_node) continue; + if (mle->new_master == dead_node && mle->inuse) { + mlog(ML_NOTICE, "%s: target %u died during " + "migration from %u, the MLE is " + "still keep used, ignore it!\n", + dlm->name, dead_node, + mle->master); + continue; + } + /* If we have reached this point, this mle needs to be * removed from the list and freed. */ dlm_clean_migration_mle(dlm, mle); diff --git a/fs/ocfs2/dlm/dlmrecovery.c b/fs/ocfs2/dlm/dlmrecovery.c index 9e4f862d2..42f0cae93 100644 --- a/fs/ocfs2/dlm/dlmrecovery.c +++ b/fs/ocfs2/dlm/dlmrecovery.c @@ -2360,6 +2360,8 @@ static void dlm_do_local_recovery_cleanup(struct dlm_ctxt *dlm, u8 dead_node) break; } } + dlm_lockres_clear_refmap_bit(dlm, res, + dead_node); spin_unlock(&res->spinlock); continue; } diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c index 20276e340..b002acf50 100644 --- a/fs/ocfs2/dlmglue.c +++ b/fs/ocfs2/dlmglue.c @@ -1390,6 +1390,7 @@ static int __ocfs2_cluster_lock(struct ocfs2_super *osb, unsigned int gen; int noqueue_attempted = 0; int dlm_locked = 0; + int kick_dc = 0; if (!(lockres->l_flags & OCFS2_LOCK_INITIALIZED)) { mlog_errno(-EINVAL); @@ -1524,7 +1525,12 @@ update_holders: unlock: lockres_clear_flags(lockres, OCFS2_LOCK_UPCONVERT_FINISHING); + /* ocfs2_unblock_lock reques on seeing OCFS2_LOCK_UPCONVERT_FINISHING */ + kick_dc = (lockres->l_flags & OCFS2_LOCK_BLOCKED); + spin_unlock_irqrestore(&lockres->l_lock, flags); + if (kick_dc) + ocfs2_wake_downconvert_thread(osb); out: /* * This is helping work around a lock inversion between the page lock diff --git a/include/crypto/hash.h b/include/crypto/hash.h index 3d69c93d5..6361892ea 100644 --- a/include/crypto/hash.h +++ b/include/crypto/hash.h @@ -204,6 +204,7 @@ struct crypto_ahash { unsigned int keylen); unsigned int reqsize; + bool has_setkey; struct crypto_tfm base; }; @@ -375,6 +376,11 @@ static inline void *ahash_request_ctx(struct ahash_request *req) int crypto_ahash_setkey(struct crypto_ahash *tfm, const u8 *key, unsigned int keylen); +static inline bool crypto_ahash_has_setkey(struct crypto_ahash *tfm) +{ + return tfm->has_setkey; +} + /** * crypto_ahash_finup() - update and finalize message digest * @req: reference to the ahash_request handle that holds all information diff --git a/include/crypto/if_alg.h b/include/crypto/if_alg.h index 018afb264..a2bfd7843 100644 --- a/include/crypto/if_alg.h +++ b/include/crypto/if_alg.h @@ -30,6 +30,9 @@ struct alg_sock { struct sock *parent; + unsigned int refcnt; + unsigned int nokey_refcnt; + const struct af_alg_type *type; void *private; }; @@ -50,9 +53,11 @@ struct af_alg_type { void (*release)(void *private); int (*setkey)(void *private, const u8 *key, unsigned int keylen); int (*accept)(void *private, struct sock *sk); + int (*accept_nokey)(void *private, struct sock *sk); int (*setauthsize)(void *private, unsigned int authsize); struct proto_ops *ops; + struct proto_ops *ops_nokey; struct module *owner; char name[14]; }; @@ -67,6 +72,7 @@ int af_alg_register_type(const struct af_alg_type *type); int af_alg_unregister_type(const struct af_alg_type *type); int af_alg_release(struct socket *sock); +void af_alg_release_parent(struct sock *sk); int af_alg_accept(struct sock *sk, struct socket *newsock); int af_alg_make_sg(struct af_alg_sgl *sgl, struct iov_iter *iter, int len); @@ -83,11 +89,6 @@ static inline struct alg_sock *alg_sk(struct sock *sk) return (struct alg_sock *)sk; } -static inline void af_alg_release_parent(struct sock *sk) -{ - sock_put(alg_sk(sk)->parent); -} - static inline void af_alg_init_completion(struct af_alg_completion *completion) { init_completion(&completion->completion); diff --git a/include/crypto/skcipher.h b/include/crypto/skcipher.h index d8dd41fb0..fd8742a40 100644 --- a/include/crypto/skcipher.h +++ b/include/crypto/skcipher.h @@ -61,6 +61,8 @@ struct crypto_skcipher { unsigned int ivsize; unsigned int reqsize; + bool has_setkey; + struct crypto_tfm base; }; @@ -305,6 +307,11 @@ static inline int crypto_skcipher_setkey(struct crypto_skcipher *tfm, return tfm->setkey(tfm, key, keylen); } +static inline bool crypto_skcipher_has_setkey(struct crypto_skcipher *tfm) +{ + return tfm->has_setkey; +} + /** * crypto_skcipher_reqtfm() - obtain cipher handle from request * @req: skcipher_request out of which the cipher handle is to be obtained diff --git a/include/linux/console.h b/include/linux/console.h index ec3a76bfa..3a61cf71b 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -150,6 +150,7 @@ extern int console_trylock(void); extern void console_unlock(void); extern void console_conditional_schedule(void); extern void console_unblank(void); +extern void console_flush_on_panic(void); extern struct tty_driver *console_device(int *); extern void console_stop(struct console *); extern void console_start(struct console *); diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h index 76dd4f0da..2ead22dd7 100644 --- a/include/linux/hrtimer.h +++ b/include/linux/hrtimer.h @@ -87,7 +87,8 @@ enum hrtimer_restart { * @function: timer expiry callback function * @base: pointer to the timer base (per cpu and per clock) * @state: state information (See bit values above) - * @start_pid: timer statistics field to store the pid of the task which + * @is_rel: Set if the timer was armed relative + * @start_pid: timer statistics field to store the pid of the task which * started the timer * @start_site: timer statistics field to store the site where the timer * was started @@ -101,7 +102,8 @@ struct hrtimer { ktime_t _softexpires; enum hrtimer_restart (*function)(struct hrtimer *); struct hrtimer_clock_base *base; - unsigned long state; + u8 state; + u8 is_rel; #ifdef CONFIG_TIMER_STATS int start_pid; void *start_site; @@ -321,6 +323,27 @@ static inline void clock_was_set_delayed(void) { } #endif +static inline ktime_t +__hrtimer_expires_remaining_adjusted(const struct hrtimer *timer, ktime_t now) +{ + ktime_t rem = ktime_sub(timer->node.expires, now); + + /* + * Adjust relative timers for the extra we added in + * hrtimer_start_range_ns() to prevent short timeouts. + */ + if (IS_ENABLED(CONFIG_TIME_LOW_RES) && timer->is_rel) + rem.tv64 -= hrtimer_resolution; + return rem; +} + +static inline ktime_t +hrtimer_expires_remaining_adjusted(const struct hrtimer *timer) +{ + return __hrtimer_expires_remaining_adjusted(timer, + timer->base->get_time()); +} + extern void clock_was_set(void); #ifdef CONFIG_TIMERFD extern void timerfd_clock_was_set(void); @@ -390,7 +413,12 @@ static inline void hrtimer_restart(struct hrtimer *timer) } /* Query timers: */ -extern ktime_t hrtimer_get_remaining(const struct hrtimer *timer); +extern ktime_t __hrtimer_get_remaining(const struct hrtimer *timer, bool adjust); + +static inline ktime_t hrtimer_get_remaining(const struct hrtimer *timer) +{ + return __hrtimer_get_remaining(timer, false); +} extern u64 hrtimer_get_next_event(void); diff --git a/include/linux/tty.h b/include/linux/tty.h index 5e31f1b99..6b6e811f4 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -654,6 +654,7 @@ extern long vt_compat_ioctl(struct tty_struct *tty, /* tty_mutex.c */ /* functions for preparation of BKL removal */ extern void __lockfunc tty_lock(struct tty_struct *tty); +extern int tty_lock_interruptible(struct tty_struct *tty); extern void __lockfunc tty_unlock(struct tty_struct *tty); extern void __lockfunc tty_lock_slave(struct tty_struct *tty); extern void __lockfunc tty_unlock_slave(struct tty_struct *tty); diff --git a/include/sound/rawmidi.h b/include/sound/rawmidi.h index f6cbef78d..3b91ad5d5 100644 --- a/include/sound/rawmidi.h +++ b/include/sound/rawmidi.h @@ -167,6 +167,10 @@ int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count); int snd_rawmidi_transmit(struct snd_rawmidi_substream *substream, unsigned char *buffer, int count); +int __snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, + unsigned char *buffer, int count); +int __snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, + int count); /* main midi functions */ diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild index b3132cb19..d736c11b6 100644 --- a/include/uapi/linux/Kbuild +++ b/include/uapi/linux/Kbuild @@ -219,7 +219,6 @@ 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/aufs_type.h b/include/uapi/linux/aufs_type.h index 54fad75e8..5fd2da85e 100644 --- a/include/uapi/linux/aufs_type.h +++ b/include/uapi/linux/aufs_type.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Junjiro R. Okajima + * Copyright (C) 2005-2016 Junjiro R. Okajima */ #ifndef __AUFS_TYPE_H__ diff --git a/include/uapi/linux/kdbus.h b/include/uapi/linux/kdbus.h deleted file mode 100644 index 4fc44cb1d..000000000 --- a/include/uapi/linux/kdbus.h +++ /dev/null @@ -1,984 +0,0 @@ -/* - * 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 _UAPI_KDBUS_H_ -#define _UAPI_KDBUS_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, - KDBUS_ITEM_DST_ID, - - /* 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 - * 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 - * @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 - * @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, - KDBUS_NAME_ALLOW_REPLACEMENT = 1ULL << 1, - 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, -}; - -/** - * 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 /* _UAPI_KDBUS_H_ */ diff --git a/include/uapi/linux/magic.h b/include/uapi/linux/magic.h index 59e1c45b5..accb036bb 100644 --- a/include/uapi/linux/magic.h +++ b/include/uapi/linux/magic.h @@ -77,6 +77,4 @@ #define NSFS_MAGIC 0x6e736673 #define BPF_FS_MAGIC 0xcafe4a11 -#define KDBUS_SUPER_MAGIC 0x44427573 - #endif /* __LINUX_MAGIC_H__ */ diff --git a/init/Kconfig b/init/Kconfig index f7e8c274a..79f5ac6aa 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -281,19 +281,6 @@ 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 the man-pages and HTML files in Documentation/kdbus/ - that are generated by 'make mandocs' and 'make htmldocs'. - - 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" depends on MMU diff --git a/ipc/Makefile b/ipc/Makefile index 68ec4167d..61eeb1624 100644 --- a/ipc/Makefile +++ b/ipc/Makefile @@ -9,4 +9,3 @@ 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 deleted file mode 100644 index 66663a124..000000000 --- a/ipc/kdbus/Makefile +++ /dev/null @@ -1,33 +0,0 @@ -# -# 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 \ - 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$(KDBUS_EXT).o diff --git a/ipc/kdbus/bus.c b/ipc/kdbus/bus.c deleted file mode 100644 index e636d3478..000000000 --- a/ipc/kdbus/bus.c +++ /dev/null @@ -1,514 +0,0 @@ -/* - * 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, - u64 flags, kuid_t uid, kgid_t gid) -{ - struct kdbus_bus *b; - u64 attach_owner; - 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_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_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_drain(&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 - * @staging: Staging object containing the message to send - * - * 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. - * - * 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_staging *staging) -{ - 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, staging); - - down_read(&bus->conn_rwlock); - hash_for_each(bus->conn_hash, i, conn_dst, hentry) { - 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_msg(conn_dst->match_db, conn_src, - staging)) - continue; - - if (conn_src) { - /* - * 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; - } 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, - staging->msg)) - continue; - } - - ret = kdbus_conn_entry_insert(conn_src, conn_dst, staging, - NULL, 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 - * @staging: Staging object containing the message to send - * - * 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_staging *staging) -{ - 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) { - ret = kdbus_conn_entry_insert(conn_src, conn_dst, staging, - NULL, 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: 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) -{ - 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 }, - }; - 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, - 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_drain(&ep->node); - kdbus_ep_unref(ep); - } - if (bus) { - kdbus_node_drain(&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 *meta_items = NULL; - struct kdbus_item_header item_hdr; - struct kdbus_info info = {}; - size_t meta_size, name_len, cnt = 0; - struct kvec kvec[6]; - u64 attach_flags, size = 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_emit(bus->creator_meta, NULL, NULL, conn, - attach_flags, &meta_items, &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), &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, size, false); - if (IS_ERR(slice)) { - ret = PTR_ERR(slice); - slice = NULL; - goto exit; - } - - ret = kdbus_pool_slice_copy_kvec(slice, 0, kvec, cnt, 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); - kfree(meta_items); - return kdbus_args_clear(&args, ret); -} diff --git a/ipc/kdbus/bus.h b/ipc/kdbus/bus.h deleted file mode 100644 index 8c2acaed6..000000000 --- a/ipc/kdbus/bus.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * 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_staging; -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_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 - * @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 - * @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_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 */ - atomic64_t last_message_id; - 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_staging *staging); -void kdbus_bus_eavesdrop(struct kdbus_bus *bus, - struct kdbus_conn *conn_src, - struct kdbus_staging *staging); - -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/connection.c b/ipc/kdbus/connection.c deleted file mode 100644 index ef63d6533..000000000 --- a/ipc/kdbus/connection.c +++ /dev/null @@ -1,2227 +0,0 @@ -/* - * 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, - struct file *file, - 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; - bool privileged; - bool owner; - struct kvec kvec; - int ret; - - struct { - u64 size; - u64 type; - struct kdbus_bloom_parameter bloom; - } bloom_item; - - 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; - 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 (!owner && (is_activator || is_policy_holder || is_monitor)) - return ERR_PTR(-EPERM); - if (!owner && (creds || pids || seclabel)) - 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); - - 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->reply_list); - 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_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; - 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)); - - /* privileged processes can impersonate somebody else */ - if (creds || pids || seclabel) { - 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; - } - - ret = kdbus_meta_fake_collect(conn->meta_fake, - creds, pids, seclabel); - if (ret < 0) - goto exit_unref; - } else { - 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 | - 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). - * 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 { - 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; - 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->reply_list)); - - if (conn->user) { - atomic_dec(&conn->user->connections); - kdbus_user_unref(conn->user); - } - - 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); - path_put(&conn->root_path); - put_pid(conn->pid); - 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(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) - 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); - } - 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_owner *owner; - - lockdep_assert_held(&conn->ep->bus->name_registry->rwlock); - - 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; -} - -struct kdbus_quota { - u32 memory; - u16 msgs; - u8 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 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 - * (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 slices 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 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 - * 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_src, - struct kdbus_conn *conn_dst, - struct kdbus_staging *staging) -{ - /* 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) && - staging->gaps && staging->gaps->n_fds > 0) - return ERR_PTR(-ECOMM); - - return kdbus_queue_entry_new(conn_src, conn_dst, staging); -} - -/* - * 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, - struct kdbus_staging *staging, - struct kdbus_reply *reply_wake) -{ - struct kdbus_queue_entry *entry; - int remote_ret, 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(reply_wake->reply_src, conn_dst, - staging); - 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 - * @staging: Message to send - * @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, - struct kdbus_staging *staging, - struct kdbus_reply *reply, - const struct kdbus_name_entry *name) -{ - struct kdbus_queue_entry *entry; - int ret; - - kdbus_conn_lock2(conn_src, conn_dst); - - entry = kdbus_conn_entry_make(conn_src, conn_dst, staging); - 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); - } - - /* - * 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); - - 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_staging *staging, - struct kdbus_name_entry **out_name, - 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; - - lockdep_assert_held(&bus->name_registry->rwlock); - - if (!staging->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, - staging->dst_name); - if (name) - owner = kdbus_name_get_owner(name); - if (!owner) - 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 != owner->conn->id) - return -EREMCHG; - - if ((msg->flags & KDBUS_MSG_NO_AUTO_START) && - kdbus_conn_is_activator(owner->conn)) - return -EADDRNOTAVAIL; - - dst = kdbus_conn_ref(owner->conn); - } - - *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_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(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 */ - down_read(&bus->name_registry->rwlock); - - /* find and pin destination */ - - ret = kdbus_pin_dst(bus, staging, &name, &dst); - if (ret < 0) - goto exit; - - mutex_lock(&dst->lock); - reply = kdbus_reply_find(src, dst, msg->cookie_reply); - if (reply) { - if (reply->sync) - wake = kdbus_reply_ref(reply); - kdbus_reply_unlink(reply); - } - mutex_unlock(&dst->lock); - - if (!reply) { - ret = -EBADSLT; - goto exit; - } - - /* send message */ - - kdbus_bus_eavesdrop(bus, src, staging); - - if (wake) - ret = kdbus_conn_entry_sync_attach(dst, staging, wake); - else - ret = kdbus_conn_entry_insert(src, dst, staging, NULL, name); - -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_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(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, 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, staging, &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, msg, name, true); - if (IS_ERR(wait)) { - ret = PTR_ERR(wait); - wait = NULL; - goto exit; - } - - /* send message */ - - kdbus_bus_eavesdrop(bus, src, staging); - - ret = kdbus_conn_entry_insert(src, dst, staging, wait, name); - 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_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 = (msg->flags & KDBUS_MSG_SIGNAL); - int ret = 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 */ - down_read(&bus->name_registry->rwlock); - - /* find and pin destination */ - - 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, staging); - - /* drop silently if peer is not interested or not privileged */ - 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 (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; - goto exit; - } - } - - /* send message */ - - if (!is_signal) - kdbus_bus_eavesdrop(bus, src, staging); - - ret = kdbus_conn_entry_insert(src, dst, staging, wait, name); - 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->gaps && e->gaps->n_fds > 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_owner *owner; - 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(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; - } - } - - 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->owner) - 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->owner) - 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 - * @msg: Notification message - * - * 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, - const struct kdbus_msg *msg) -{ - /* - * 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}: Notifications for ID changes are - * broadcast to everyone, to allow tracking peers. - */ - - 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, - msg->items[0].name_change.name); - - case KDBUS_ITEM_ID_ADD: - case KDBUS_ITEM_ID_REMOVE: - return true; - - default: - WARN(1, "Invalid type for notification broadcast: %llu\n", - (unsigned long long)msg->items[0].type); - return false; - } -} - -/** - * kdbus_cmd_hello() - handle KDBUS_CMD_HELLO - * @ep: Endpoint to operate on - * @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, struct file *file, - 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, 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, - 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_name_owner *owner = 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[3]; - size_t meta_size, cnt = 0; - const char *name; - u64 attach_flags, size = 0; - 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) - owner = kdbus_name_get_owner(entry); - if (!owner || - !kdbus_conn_policy_see_name(conn, current_cred(), name) || - (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(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(), - owner_conn)) { - /* pretend an id doesn't exist if you cannot see it */ - ret = -ENXIO; - goto exit; - } - } else { - ret = -EINVAL; - goto exit; - } - - 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, owner_conn, 0, attach_flags); - if (ret < 0) - goto exit; - - 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; - - 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_pool_slice_copy_kvec(slice, 0, kvec, cnt, 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; - goto exit; - } - - ret = 0; - -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); -} - -/** - * 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_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 (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_staging *staging = NULL; - struct kdbus_msg *msg = NULL; - struct file *cancel_fd = NULL; - int ret, ret2; - - /* command arguments */ - 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), - }; - - /* 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) - 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, - &cmd->reply.msg_size); - - if (argv[1].item) { - cancel_fd = fget(argv[1].item->fds[0]); - if (!cancel_fd) { - ret = -EBADF; - goto exit; - } - - if (!cancel_fd->f_op->poll) { - ret = -EINVAL; - goto exit; - } - } - - /* 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; - } - - if (msg->dst_id == KDBUS_DST_ID_BROADCAST) { - down_read(&conn->ep->bus->name_registry->rwlock); - 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(msg->timeout_ns); - r = kdbus_conn_call(conn, staging, 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 ((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, staging); - 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_staging_free(staging); - ret = kdbus_args_clear(&msg_args, ret); - 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 deleted file mode 100644 index 1ad082014..000000000 --- a/ipc/kdbus/connection.h +++ /dev/null @@ -1,260 +0,0 @@ -/* - * 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_name_entry; -struct kdbus_quota; -struct kdbus_staging; - -/** - * 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_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 - * @pid: Pid at creation time - * @root_path: Root path at creation time - * @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 - * @names_list: List of well-known names - * @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 - */ -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_proc; - struct kdbus_meta_fake *meta_fake; - struct kdbus_pool *pool; - struct kdbus_user *user; - const struct cred *cred; - struct pid *pid; - struct path root_path; - 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 list_head names_list; - unsigned int name_count; - - bool privileged:1; - bool owner: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, - struct kdbus_staging *staging, - 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); - -/* 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_msg *msg); - -/* command dispatcher */ -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); -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/domain.c b/ipc/kdbus/domain.c deleted file mode 100644 index 5d52d009d..000000000 --- a/ipc/kdbus/domain.c +++ /dev/null @@ -1,296 +0,0 @@ -/* - * 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_drain(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_drain(&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 deleted file mode 100644 index 447a2bd4d..000000000 --- a/ipc/kdbus/domain.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * 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 deleted file mode 100644 index 5694ff6dc..000000000 --- a/ipc/kdbus/endpoint.c +++ /dev/null @@ -1,303 +0,0 @@ -/* - * 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 endpoint 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_drain(&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_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 - * - * 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) -{ - 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_drain(&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: >=0 on success, negative error code 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 deleted file mode 100644 index e0da59f01..000000000 --- a/ipc/kdbus/endpoint.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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 - endpoint 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 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. - */ -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); - -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); - -#endif diff --git a/ipc/kdbus/fs.c b/ipc/kdbus/fs.c deleted file mode 100644 index 6330c61e5..000000000 --- a/ipc/kdbus/fs.c +++ /dev/null @@ -1,508 +0,0 @@ -/* - * 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 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 - * 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_drain(&domain->node); - domain->dentry = NULL; - } - - kill_anon_super(sb); - 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_drain(&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 deleted file mode 100644 index 62f7d6abf..000000000 --- a/ipc/kdbus/fs.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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/handle.c b/ipc/kdbus/handle.c deleted file mode 100644 index 2f82c2a32..000000000 --- a/ipc/kdbus/handle.c +++ /dev/null @@ -1,691 +0,0 @@ -/* - * 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/mutex.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; - - 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 - * @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 - * @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. - * - * 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, bool is_cmd, void __user *argp, - size_t type_size, size_t items_offset, void **out) -{ - u64 user_size; - int ret, i; - - 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; - } - - 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; - goto error; - } - - ret = kdbus_args_verify(args); - if (ret < 0) - goto error; - - ret = kdbus_args_negotiate(args); - 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); - -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 (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); - 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 - * @lock: 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 - */ -struct kdbus_handle { - struct mutex lock; - - enum kdbus_handle_type type; - union { - struct kdbus_bus *bus_owner; - struct kdbus_ep *ep_owner; - struct kdbus_conn *conn; - }; -}; - -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; - } - - mutex_init(&handle->lock); - handle->type = KDBUS_HANDLE_NONE; - - 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_drain(&handle->bus_owner->node); - kdbus_bus_unref(handle->bus_owner); - } - break; - case KDBUS_HANDLE_EP_OWNER: - if (handle->ep_owner) { - kdbus_node_drain(&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->bus_owner = bus; - ret = KDBUS_HANDLE_BUS_OWNER; - 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_bus *bus = file_ep->bus; - 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 (!kdbus_ep_is_owner(file_ep, file)) { - ret = -EPERM; - break; - } - - ep = kdbus_cmd_ep_make(bus, buf); - if (IS_ERR_OR_NULL(ep)) { - ret = PTR_ERR_OR_ZERO(ep); - break; - } - - handle->ep_owner = ep; - ret = KDBUS_HANDLE_EP_OWNER; - break; - } - - case KDBUS_CMD_HELLO: - conn = kdbus_cmd_hello(file_ep, file, buf); - if (IS_ERR_OR_NULL(conn)) { - ret = PTR_ERR_OR_ZERO(conn); - break; - } - - handle->conn = conn; - ret = KDBUS_HANDLE_CONNECTED; - 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: - 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; - } - } - mutex_unlock(&handle->lock); - 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: { - 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 (type == KDBUS_HANDLE_CONNECTED) - ret = kdbus_handle_ioctl_connected(file, cmd, argp); - - 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; - enum kdbus_handle_type type; - unsigned int mask = POLLOUT | POLLWRNORM; - - /* - * 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 */ - if (type != KDBUS_HANDLE_CONNECTED) - 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; - - return mask; -} - -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; - - /* - * 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; -} - -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 deleted file mode 100644 index 5dde2c10b..000000000 --- a/ipc/kdbus/handle.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * 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 - * @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 - * - * 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. - * - * We use a 256 bytes buffer for small command payloads, to be allocated on - * stack on syscall entrance. - */ -struct kdbus_args { - u64 allowed_flags; - size_t argc; - struct kdbus_arg *argv; - - struct kdbus_cmd __user *user; - struct kdbus_cmd *cmd; - u8 cmd_buf[256]; - - struct kdbus_item *items; - size_t items_size; - bool is_cmd : 1; -}; - -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); - -#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), 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)); \ - }) - -#endif diff --git a/ipc/kdbus/item.c b/ipc/kdbus/item.c deleted file mode 100644 index ce78dba03..000000000 --- a/ipc/kdbus/item.c +++ /dev/null @@ -1,293 +0,0 @@ -/* - * 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: - 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: - case KDBUS_ITEM_DST_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; -} - -/** - * 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 deleted file mode 100644 index 3a7e6ccc2..000000000 --- a/ipc/kdbus/item.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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); -struct kdbus_item *kdbus_item_set(struct kdbus_item *item, u64 type, - const void *data, size_t len); - -#endif diff --git a/ipc/kdbus/limits.h b/ipc/kdbus/limits.h deleted file mode 100644 index bd47119cd..000000000 --- a/ipc/kdbus/limits.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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 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 4096 - -/* 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 deleted file mode 100644 index c2117ea53..000000000 --- a/ipc/kdbus/main.c +++ /dev/null @@ -1,111 +0,0 @@ -/* - * 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 "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) - */ - -static int __init kdbus_init(void) -{ - int ret; - - ret = sysfs_create_mount_point(fs_kobj, KBUILD_MODNAME); - if (ret) - return ret; - - 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: - sysfs_remove_mount_point(fs_kobj, KBUILD_MODNAME); - return ret; -} - -static void __exit kdbus_exit(void) -{ - kdbus_fs_exit(); - sysfs_remove_mount_point(fs_kobj, KBUILD_MODNAME); - ida_destroy(&kdbus_node_ida); -} - -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/match.c b/ipc/kdbus/match.c deleted file mode 100644 index 4ee6a1f2e..000000000 --- a/ipc/kdbus/match.c +++ /dev/null @@ -1,546 +0,0 @@ -/* - * 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 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, - * 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 - * @dst_id: Message destination ID, used with KDBUS_ITEM_DST_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; - u64 dst_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_DST_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_rule_conn(const struct kdbus_match_rule *r, - struct kdbus_conn *c, - 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(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: - return false; - } -} - -static bool kdbus_match_rule_kernel(const struct kdbus_match_rule *r, - const struct kdbus_staging *s) -{ - struct kdbus_item *n = s->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 == n->id_change.id; - case KDBUS_ITEM_ID_REMOVE: - return r->old_id == KDBUS_MATCH_ID_ANY || - 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 == n->name_change.old_id.id) && - (r->new_id == KDBUS_MATCH_ID_ANY || - r->new_id == n->name_change.new_id.id) && - (!r->name || !strcmp(r->name, n->name_change.name)); - default: - return false; - } -} - -static bool kdbus_match_rules(const struct kdbus_match_entry *entry, - struct kdbus_conn *c, - 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, s)) || - (!c && !kdbus_match_rule_kernel(r, s))) - return false; - - return true; -} - -/** - * 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 - * @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 - * 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_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, staging); - 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_DST_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, 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. - */ -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_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 }, - { .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_DST_ID: - rule->dst_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 deleted file mode 100644 index ceb492f8e..000000000 --- a/ipc/kdbus/match.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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_match_db; -struct kdbus_staging; - -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_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); - -#endif diff --git a/ipc/kdbus/message.c b/ipc/kdbus/message.c deleted file mode 100644 index ae565cd34..000000000 --- a/ipc/kdbus/message.c +++ /dev/null @@ -1,1040 +0,0 @@ -/* - * 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" - -static const char * const zeros = "\0\0\0\0\0\0\0"; - -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->last_message_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_msg_mask(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, meta_size; - struct iovec *v; - u64 attach, msg_size; - 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 = (void __user *)&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 = (void __user *)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; - } 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 ... */ - - /* 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 deleted file mode 100644 index 298f9c99d..000000000 --- a/ipc/kdbus/message.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - * 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 <linux/fs.h> -#include <linux/kref.h> -#include <uapi/linux/kdbus.h> - -struct kdbus_bus; -struct kdbus_conn; -struct kdbus_meta_conn; -struct kdbus_meta_proc; -struct kdbus_pool_slice; - -/** - * 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 diff --git a/ipc/kdbus/metadata.c b/ipc/kdbus/metadata.c deleted file mode 100644 index 71ca475a8..000000000 --- a/ipc/kdbus/metadata.c +++ /dev/null @@ -1,1347 +0,0 @@ -/* - * 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 "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 - * @cred: Credentials - * @pid: PID of process - * @tgid: TGID of process - * @ppid: PPID of process - * @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 - * @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 */ - /* KDBUS_ITEM_AUXGROUPS */ - /* KDBUS_ITEM_CAPS */ - const struct cred *cred; - - /* KDBUS_ITEM_PIDS */ - struct pid *pid; - struct pid *tgid; - struct pid *ppid; - - /* 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_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; -}; - -/* 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 - * - * 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); - if (mp->cred) - put_cred(mp->cred); - put_pid(mp->ppid); - put_pid(mp->tgid); - put_pid(mp->pid); - - kfree(mp->seclabel); - 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_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 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 file *exe_file; - - rcu_read_lock(); - exe_file = rcu_dereference(current->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; - } - rcu_read_unlock(); -} - -static int kdbus_meta_proc_collect_cmdline(struct kdbus_meta_proc *mp) -{ - struct mm_struct *mm = current->mm; - char *cmdline; - - if (!mm->arg_end) - return 0; - - cmdline = strndup_user((const char __user *)mm->arg_start, - mm->arg_end - mm->arg_start); - 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 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); - - /* 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) && - !(mp->collected & KDBUS_ATTACH_PIDS)) { - kdbus_meta_proc_collect_pids(mp); - mp->collected |= KDBUS_ATTACH_PIDS; - } - - 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_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_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. This call uses the - * current task's namespaces to resolve the given information. - * - * Return: 0 on success, negative error code on failure. - */ -int kdbus_meta_fake_collect(struct kdbus_meta_fake *mf, - const struct kdbus_creds *creds, - const struct kdbus_pids *pids, - const char *seclabel) -{ - if (mf->valid) - return -EALREADY; - - if (creds) { - struct user_namespace *ns = current_user_ns(); - - 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) { - 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; - } - - mf->valid |= KDBUS_ATTACH_PIDS; - } - - if (seclabel) { - mf->seclabel = kstrdup(seclabel, GFP_KERNEL); - if (!mf->seclabel) - return -ENOMEM; - - mf->valid |= KDBUS_ATTACH_SECLABEL; - } - - return 0; -} - -/** - * 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, - u64 msg_seqnum) -{ - mc->ts.monotonic_ns = ktime_get_ns(); - mc->ts.realtime_ns = ktime_get_real_ns(); - - if (msg_seqnum) - mc->ts.seqnum = msg_seqnum; - - 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_owner *owner; - struct kdbus_item *item; - size_t slen, size; - - lockdep_assert_held(&conn->ep->bus->name_registry->rwlock); - - size = 0; - /* open-code length calculation to avoid final padding */ - 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; - - /* make sure we include zeroed padding for convenience helpers */ - item = kmalloc(KDBUS_ALIGN8(size), GFP_KERNEL); - if (!item) - return -ENOMEM; - - mc->owned_names_items = item; - mc->owned_names_size = size; - - 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 = owner->flags; - memcpy(item->name.name, owner->name->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 + KDBUS_ALIGN8(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 - * @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 @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. - * - * Return: 0 on success, negative error code on failure. - */ -int kdbus_meta_conn_collect(struct kdbus_meta_conn *mc, - struct kdbus_conn *conn, - u64 msg_seqnum, u64 what) -{ - int ret; - - if (!mc || !(what & (KDBUS_ATTACH_TIMESTAMP | - KDBUS_ATTACH_NAMES | - KDBUS_ATTACH_CONN_DESCRIPTION))) - return 0; - - mutex_lock(&mc->lock); - - if (msg_seqnum && (what & KDBUS_ATTACH_TIMESTAMP) && - !(mc->collected & KDBUS_ATTACH_TIMESTAMP)) { - kdbus_meta_conn_collect_timestamp(mc, msg_seqnum); - 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; -} - -static void kdbus_meta_export_caps(struct kdbus_meta_caps *out, - const struct kdbus_meta_proc *mp, - struct user_namespace *user_ns) -{ - 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 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 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 = 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(struct user_namespace *ns, kuid_t uid) -{ - 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(struct user_namespace *ns, kgid_t gid) -{ - return gid_valid(gid) ? from_kgid_munged(ns, gid) : ((gid_t)-1); -} - -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->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; - - /* 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; -} - -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_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 - * - * 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_msg_mask(const struct kdbus_conn *snd, - const struct kdbus_conn *rcv) -{ - 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 deleted file mode 100644 index dba7cc7fd..000000000 --- a/ipc/kdbus/metadata.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * 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_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); - -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); -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_conn *conn, - u64 msg_seqnum, u64 what); - -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_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 diff --git a/ipc/kdbus/names.c b/ipc/kdbus/names.c deleted file mode 100644 index bf44ca3f1..000000000 --- a/ipc/kdbus/names.c +++ /dev/null @@ -1,854 +0,0 @@ -/* - * 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" - -#define KDBUS_NAME_SAVED_MASK (KDBUS_NAME_ALLOW_REPLACEMENT | \ - KDBUS_NAME_QUEUE) - -static bool kdbus_name_owner_is_used(struct kdbus_name_owner *owner) -{ - return !list_empty(&owner->name_entry) || - owner == owner->name->activator; -} - -static struct kdbus_name_owner * -kdbus_name_owner_new(struct kdbus_conn *conn, struct kdbus_name_entry *name, - u64 flags) -{ - struct kdbus_name_owner *owner; - - kdbus_conn_assert_active(conn); - - if (conn->name_count >= KDBUS_CONN_MAX_NAMES) - return ERR_PTR(-E2BIG); - - owner = kmalloc(sizeof(*owner), GFP_KERNEL); - if (!owner) - return ERR_PTR(-ENOMEM); - - 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); - - ++conn->name_count; - return owner; -} - -static void kdbus_name_owner_free(struct kdbus_name_owner *owner) -{ - if (!owner) - return; - - WARN_ON(kdbus_name_owner_is_used(owner)); - --owner->conn->name_count; - list_del(&owner->conn_entry); - kfree(owner); -} - -static struct kdbus_name_owner * -kdbus_name_owner_find(struct kdbus_name_entry *name, struct kdbus_conn *conn) -{ - struct kdbus_name_owner *owner; - - /* - * 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 bool kdbus_name_entry_is_used(struct kdbus_name_entry *name) -{ - return !list_empty(&name->queue) || name->activator; -} - -static struct kdbus_name_owner * -kdbus_name_entry_first(struct kdbus_name_entry *name) -{ - return list_first_entry_or_null(&name->queue, struct kdbus_name_owner, - name_entry); -} - -static struct kdbus_name_entry * -kdbus_name_entry_new(struct kdbus_name_registry *r, u32 hash, - const char *name_str) -{ - struct kdbus_name_entry *name; - size_t namelen; - - lockdep_assert_held(&r->rwlock); - - namelen = strlen(name_str); - - name = kmalloc(sizeof(*name) + namelen + 1, GFP_KERNEL); - if (!name) - return ERR_PTR(-ENOMEM); - - 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); - - return name; -} - -static void kdbus_name_entry_free(struct kdbus_name_entry *name) -{ - if (!name) - return; - - WARN_ON(kdbus_name_entry_is_used(name)); - hash_del(&name->hentry); - kfree(name); -} - -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; - - 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; -} - -/** - * 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() - free name registry - * @r: name registry to free, or NULL - * - * 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 *r) -{ - if (!r) - return; - - WARN_ON(!hash_empty(r->entries_hash)); - kfree(r); -} - -/** - * 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_entry_find(reg, kdbus_strhash(name), name); -} - -static int kdbus_name_become_activator(struct kdbus_name_owner *owner, - u64 *return_flags) -{ - 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 { - 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, - 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; - 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); - owner->flags |= KDBUS_NAME_PRIMARY; - nflags |= KDBUS_NAME_ACQUIRED; - - /* 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_PRIMARY; - 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); - } - - } else if (owner == primary) { - /* - * Already the primary owner of the name, flags were already - * updated. Nothing to do. - */ - - owner->flags |= KDBUS_NAME_PRIMARY; - - } 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); - owner->flags |= KDBUS_NAME_PRIMARY; - nflags |= KDBUS_NAME_ACQUIRED; - - 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_PRIMARY; - primary->flags |= KDBUS_NAME_IN_QUEUE; - } else { - list_del_init(&primary->name_entry); - kdbus_name_owner_free(primary); - } - - } else if (flags & KDBUS_NAME_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); - nflags |= KDBUS_NAME_ACQUIRED; - } - } 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); - } else { - /* - * Name is already claimed and queueing is not requested. - * Return error to the caller. - */ - - ret = -EEXIST; - } - - if (return_flags) - *return_flags = owner->flags | nflags; - - return ret; -} - -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, return_flags); - else - ret = kdbus_name_update(owner, flags, return_flags); - if (ret < 0) - goto exit; - -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_owner *owner) -{ - 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; - next->flags |= KDBUS_NAME_PRIMARY; - 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_str) -{ - struct kdbus_name_owner *owner; - struct kdbus_name_entry *name; - int ret = 0; - - down_write(®->rwlock); - 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 = -ESRCH; - } - 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_owner *owner; - - down_write(®->rwlock); - - 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_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 - * - * 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; - } - - ret = kdbus_name_acquire(conn->ep->bus->name_registry, conn, item_name, - cmd->flags, &cmd->return_flags); - -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_owner *o, - 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 (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 (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 = o->flags; - - kdbus_kvec_set(&kvec[cnt++], &h, sizeof(h), &info.size); - kdbus_kvec_set(&kvec[cnt++], o->name->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; - - /* all names the connection owns */ - if (flags & (KDBUS_LIST_NAMES | - KDBUS_LIST_ACTIVATORS | - KDBUS_LIST_QUEUED)) { - struct kdbus_name_owner *o; - - list_for_each_entry(o, &c->names_list, conn_entry) { - if (o->flags & KDBUS_NAME_ACTIVATOR) { - if (!(flags & KDBUS_LIST_ACTIVATORS)) - continue; - - 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; - - ret = kdbus_list_write(conn, c, slice, - &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; - } - - 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 deleted file mode 100644 index edac59ddd..000000000 --- a/ipc/kdbus/names.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * 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_entry; -struct kdbus_name_owner; -struct kdbus_name_registry; - -/** - * 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 - * @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; - struct kdbus_name_owner *activator; - struct list_head queue; - 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); -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); - -/** - * 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 diff --git a/ipc/kdbus/node.c b/ipc/kdbus/node.c deleted file mode 100644 index 986aca39c..000000000 --- a/ipc/kdbus/node.c +++ /dev/null @@ -1,948 +0,0 @@ -/* - * 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. Furthermore, all children will be deactivated - * recursively as well. If a node is deactivated, there might still be active - * references that were acquired before calling kdbus_node_deactivate(). The - * owner of an object must call kdbus_node_drain() (which is a superset of - * kdbus_node_deactivate()) before dropping their reference. This will - * deactivate the node and also synchronously wait for all active references to - * be dropped. Hence, once kdbus_node_drain() returns, the node is fully - * released and no active references exist, anymore. - * kdbus_node_drain() can be called at any times, multiple times, and in - * parallel on multiple threads. All calls are synchronized internally and will - * return only once the node is fully drained. The only restriction is, you - * must not hold an active reference when calling kdbus_node_drain() (unlike - * deactivation, which allows the caller to hold an active reference). - * - * 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 if the - * node really was activated). This allows callers to link+activate a child node - * and then drop all refs. This has the effect that nobody owns a reference to - * the node, except for the parent node. Hence, if the parent is deactivated - * (and thus all children are deactivated, too), this will automatically - * release the child node. - * - * 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 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. - * 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 can freely access - * this field, but it may be NULL (root node). - * * 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 */ -DEFINE_IDA(kdbus_node_ida); - -/** - * 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 - * - * This compares a query string against a kdbus node. If the kdbus node has the - * given name, this returns 0. Otherwise, this returns >0 / <0 depending - * whether the query string is greater / less than the node. - * - * Note: If @node is drained but has the name @name, this returns 1. The - * reason for this is that we treat drained nodes as "renamed". The - * slot of such nodes is no longer occupied and new nodes can claim it. - * Obviously, this has the side-effect that you cannot match drained - * nodes, as they will never return 0 on name-matches. But this is - * intentional, as there is no reason why anyone would ever want to match - * on drained nodes. - * - * 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) -{ - int ret; - - if (hash != node->hash) - return hash - node->hash; - - ret = strcmp(name, node->name); - if (ret != 0) - return ret; - - return atomic_read(&node->active) == KDBUS_NODE_DRAINED; -} - -/** - * 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_drain() 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); - } - - ret = ida_simple_get(&kdbus_node_ida, 1, 0, GFP_KERNEL); - if (ret < 0) - return ret; - - node->id = 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 (apart from node->parent->lock). - * - * 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); - - if (node->parent) { - mutex_lock(&node->parent->lock); - if (!RB_EMPTY_NODE(&node->rb)) { - rb_erase(&node->rb, - &node->parent->children); - RB_CLEAR_NODE(&node->rb); - } - mutex_unlock(&node->parent->lock); - } - - if (node->free_cb) - node->free_cb(node); - if (safe.id > 0) - ida_simple_remove(&kdbus_node_ida, safe.id); - - kfree(safe.name); - 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_recurse_unlock() - advance iterator on a tree - * @start: node at which the iteration started - * @node: previously visited node - * - * This helper advances an iterator by one, when traversing a node tree. It is - * supposed to be used like this: - * - * struct kdbus_node *n; - * - * n = start; - * while (n) { - * mutex_lock(&n->lock); - * ... visit @n ... - * n = kdbus_node_recurse_unlock(start, n); - * } - * - * This helpers takes as input the start-node of the iteration and the current - * position. It returns a pointer to the next node to visit. The caller must - * hold a reference to @start during the whole iteration. Furthermore, @node - * must be locked when entering this helper. On return, the lock is released. - * - * The order of visit is pre-order traversal. - * - * If @node is deactivated before recursing its children, then it is guaranteed - * that all children will be visited. If @node is still active, new nodes might - * be inserted during traversal, and thus might be missed. - * - * Also note that the node-locks are released while traversing children. You - * must not rely on the locks to be held during the whole traversal. Each node - * that is visited is pinned by this helper, so the caller can rely on owning a - * reference. It is dropped, once all of the children of the node have been - * visited (recursively). - * - * You *must not* bail out of a traversal early, otherwise you'll leak - * ref-counts to all nodes in the current depth-path. - * - * Return: Reference to next node, or NULL. - */ -static struct kdbus_node *kdbus_node_recurse_unlock(struct kdbus_node *start, - struct kdbus_node *node) -{ - struct kdbus_node *t, *prev = NULL; - struct rb_node *rb; - - lockdep_assert_held(&node->lock); - - rb = rb_first(&node->children); - if (!rb) { - do { - mutex_unlock(&node->lock); - kdbus_node_unref(prev); - - if (node == start) - return NULL; - - prev = node; - node = node->parent; - - mutex_lock(&node->lock); - rb = rb_next(&prev->rb); - } while (!rb); - } - - t = kdbus_node_ref(kdbus_node_from_rb(rb)); - mutex_unlock(&node->lock); - kdbus_node_unref(prev); - return t; -} - -/** - * kdbus_node_deactivate() - deactivate a node - * @node: node to deactivate - * - * This recursively deactivates the passed node and all its children. The nodes - * are marked as deactivated, but they're not drained. Hence, even after this - * call returns, there might still be someone holding an active reference to - * any of the nodes. However, no new active references can be acquired after - * this returns. - * - * It is safe to call this multiple times (even in parallel). Each call is - * guaranteed to only return after _all_ nodes have been deactivated. - */ -void kdbus_node_deactivate(struct kdbus_node *node) -{ - struct kdbus_node *pos; - int v; - - pos = node; - while (pos) { - mutex_lock(&pos->lock); - - /* - * Add BIAS to pos->active to mark it as inactive. If it was - * never active before, immediately mark it as RELEASE_INACTIVE - * so that this case can be detected later on. - * If the node was already deactivated, make sure to still - * recurse into the children. Otherwise, we might return before - * a racing thread finished deactivating all children. But we - * want to guarantee that the whole tree is deactivated once - * this returns. - */ - v = atomic_read(&pos->active); - if (v >= 0) - atomic_add_return(KDBUS_NODE_BIAS, &pos->active); - else if (v == KDBUS_NODE_NEW) - atomic_set(&pos->active, KDBUS_NODE_RELEASE_DIRECT); - - pos = kdbus_node_recurse_unlock(node, pos); - } -} - -/** - * kdbus_node_drain() - drain a node - * @node: node to drain - * - * This function recursively deactivates this node and all its children and - * then waits for all active references to be dropped. This function is a - * superset of kdbus_node_deactivate(), as it additionally drains all nodes. It - * returns only once all children and the node itself were recursively drained - * (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_drain(struct kdbus_node *node) -{ - struct kdbus_node *pos; - int v; - - kdbus_node_deactivate(node); - - pos = node; - while (pos) { - /* wait until all active references were dropped */ - wait_event(pos->waitq, - atomic_read(&pos->active) <= KDBUS_NODE_BIAS); - - /* mark object as RELEASE */ - mutex_lock(&pos->lock); - v = atomic_read(&pos->active); - if (v == KDBUS_NODE_BIAS || v == 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 == KDBUS_NODE_BIAS || v == KDBUS_NODE_RELEASE_DIRECT) { - if (pos->release_cb) - pos->release_cb(pos, v == KDBUS_NODE_BIAS); - - /* 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 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(). - * 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 == KDBUS_NODE_BIAS) - kdbus_node_unref(pos); - } else { - /* wait until object is DRAINED */ - wait_event(pos->waitq, - atomic_read(&pos->active) == KDBUS_NODE_DRAINED); - } - - mutex_lock(&pos->lock); - pos = kdbus_node_recurse_unlock(node, pos); - } -} - -/** - * 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 { - /* - * 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 deleted file mode 100644 index 16c6fd574..000000000 --- a/ipc/kdbus/node.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * 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 { - struct mutex lock; - 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 */ - struct rb_node rb; - - /* dynamic list of children */ - struct rb_root children; -}; - -#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, - 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); -void kdbus_node_drain(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 diff --git a/ipc/kdbus/notify.c b/ipc/kdbus/notify.c deleted file mode 100644 index 375758c48..000000000 --- a/ipc/kdbus/notify.c +++ /dev/null @@ -1,204 +0,0 @@ -/* - * 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_staging *staging, - struct kdbus_bus *bus) -{ - spin_lock(&bus->notify_lock); - 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_staging *s; - - s = kdbus_staging_new_kernel(bus, id, cookie, 0, msg_type); - if (IS_ERR(s)) - return PTR_ERR(s); - - kdbus_notify_add_tail(s, 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) -{ - size_t name_len, extra_size; - struct kdbus_staging *s; - - name_len = strlen(name) + 1; - extra_size = sizeof(struct kdbus_notify_name_change) + name_len; - - s = kdbus_staging_new_kernel(bus, KDBUS_DST_ID_BROADCAST, 0, - extra_size, type); - if (IS_ERR(s)) - return PTR_ERR(s); - - 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(s, 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_staging *s; - size_t extra_size; - - extra_size = sizeof(struct kdbus_notify_id_change); - s = kdbus_staging_new_kernel(bus, KDBUS_DST_ID_BROADCAST, 0, - extra_size, type); - if (IS_ERR(s)) - return PTR_ERR(s); - - s->notify->id_change.id = id; - s->notify->id_change.flags = flags; - - kdbus_notify_add_tail(s, 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_staging *s, *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(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, s->msg->dst_id); - if (conn) { - 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, s); - } - - list_del(&s->notify_entry); - kdbus_staging_free(s); - } - - 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_staging *s, *tmp; - - 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/notify.h b/ipc/kdbus/notify.h deleted file mode 100644 index 03df464cb..000000000 --- a/ipc/kdbus/notify.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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 diff --git a/ipc/kdbus/policy.c b/ipc/kdbus/policy.c deleted file mode 100644 index f2618e15e..000000000 --- a/ipc/kdbus/policy.c +++ /dev/null @@ -1,489 +0,0 @@ -/* - * 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 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. - * - * 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 deleted file mode 100644 index 15dd7bc12..000000000 --- a/ipc/kdbus/policy.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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 diff --git a/ipc/kdbus/pool.c b/ipc/kdbus/pool.c deleted file mode 100644 index c65043e8c..000000000 --- a/ipc/kdbus/pool.c +++ /dev/null @@ -1,728 +0,0 @@ -/* - * 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 directly 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, 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 = __vfs_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 deleted file mode 100644 index a9038213a..000000000 --- a/ipc/kdbus/pool.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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 diff --git a/ipc/kdbus/queue.c b/ipc/kdbus/queue.c deleted file mode 100644 index f9c44d7ba..000000000 --- a/ipc/kdbus/queue.c +++ /dev/null @@ -1,363 +0,0 @@ -/* - * 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 - * @src: source connection, or NULL - * @dst: destination connection - * @s: staging object carrying the message - * - * 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 *src, - struct kdbus_conn *dst, - struct kdbus_staging *s) -{ - struct kdbus_queue_entry *entry; - int ret; - - entry = kzalloc(sizeof(*entry), GFP_KERNEL); - if (!entry) - return ERR_PTR(-ENOMEM); - - INIT_LIST_HEAD(&entry->entry); - entry->priority = s->msg->priority; - entry->conn = kdbus_conn_ref(dst); - entry->gaps = kdbus_gaps_ref(s->gaps); - - entry->slice = kdbus_staging_emit(s, src, dst); - if (IS_ERR(entry->slice)) { - ret = PTR_ERR(entry->slice); - entry->slice = NULL; - goto error; - } - - entry->user = src ? kdbus_user_ref(src->user) : NULL; - return entry; - -error: - 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->gaps ? entry->gaps->n_fds : 0); - kdbus_pool_slice_release(entry->slice); - } - - kdbus_user_unref(entry->user); - kdbus_gaps_unref(entry->gaps); - kdbus_conn_unref(entry->conn); - 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 - * - * Return: 0 on success. - */ -int kdbus_queue_entry_install(struct kdbus_queue_entry *entry, - u64 *return_flags, bool install_fds) -{ - bool incomplete_fds = false; - int ret; - - lockdep_assert_held(&entry->conn->lock); - - ret = kdbus_gaps_install(entry->gaps, entry->slice, &incomplete_fds); - 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(list_empty(&e->entry))) - return -EINVAL; - if (src == dst) - return 0; - - size = kdbus_pool_slice_size(e->slice); - fds = e->gaps ? e->gaps->n_fds : 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 deleted file mode 100644 index bf686d182..000000000 --- a/ipc/kdbus/queue.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * 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 - -#include <linux/list.h> -#include <linux/rbtree.h> - -struct kdbus_conn; -struct kdbus_pool_slice; -struct kdbus_reply; -struct kdbus_staging; -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 - * @priority: Message priority - * @dst_name_id: The sequence number of the name this message is - * addressed to, 0 for messages sent to an ID - * @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; - - s64 priority; - u64 dst_name_id; - - struct kdbus_conn *conn; - struct kdbus_gaps *gaps; - struct kdbus_user *user; - struct kdbus_pool_slice *slice; - struct kdbus_reply *reply; -}; - -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 *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); -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 deleted file mode 100644 index e6791d86e..000000000 --- a/ipc/kdbus/reply.c +++ /dev/null @@ -1,252 +0,0 @@ -#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; - - 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; - } - - return r; - -exit_dec_request_count: - atomic_dec(&reply_dst->request_count); - return ERR_PTR(ret); -} - -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 - * - * 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; - - list_for_each_entry(r, &reply_dst->reply_list, entry) { - if (r->cookie == cookie && - (!replying || r->reply_src == replying)) - return r; - } - - return NULL; -} - -/** - * 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; - u64 now; - - now = ktime_get_ns(); - - 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 deleted file mode 100644 index 68d52321a..000000000 --- a/ipc/kdbus/reply.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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.c b/ipc/kdbus/util.c deleted file mode 100644 index 72b188330..000000000 --- a/ipc/kdbus/util.c +++ /dev/null @@ -1,156 +0,0 @@ -/* - * 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_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 deleted file mode 100644 index 529716669..000000000 --- a/ipc/kdbus/util.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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 <uapi/linux/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, FIELD_SIZEOF(_t, _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); - -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 diff --git a/kernel/panic.c b/kernel/panic.c index 4b150bc0c..41e2b54f3 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -157,8 +157,7 @@ void panic(const char *fmt, ...) * panic() is not being callled from OOPS. */ debug_locks_off(); - console_trylock(); - console_unlock(); + console_flush_on_panic(); if (!panic_blink) panic_blink = no_blink; diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index f9b746700..8362f1979 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -2248,13 +2248,24 @@ void console_unlock(void) static u64 seen_seq; unsigned long flags; bool wake_klogd = false; - bool retry; + bool do_cond_resched, retry; if (console_suspended) { up_console_sem(); return; } + /* + * Console drivers are called under logbuf_lock, so + * @console_may_schedule should be cleared before; however, we may + * end up dumping a lot of lines, for example, if called from + * console registration path, and should invoke cond_resched() + * between lines if allowable. Not doing so can cause a very long + * scheduling stall on a slow console leading to RCU stall and + * softlockup warnings which exacerbate the issue with more + * messages practically incapacitating the system. + */ + do_cond_resched = console_may_schedule; console_may_schedule = 0; /* flush buffered message fragment immediately to console */ @@ -2326,6 +2337,9 @@ skip: call_console_drivers(level, ext_text, ext_len, text, len); start_critical_timings(); local_irq_restore(flags); + + if (do_cond_resched) + cond_resched(); } console_locked = 0; @@ -2393,6 +2407,25 @@ void console_unblank(void) console_unlock(); } +/** + * console_flush_on_panic - flush console content on panic + * + * Immediately output all pending messages no matter what. + */ +void console_flush_on_panic(void) +{ + /* + * If someone else is holding the console lock, trylock will fail + * and may_schedule may be set. Ignore and proceed to unlock so + * that messages are flushed out. As this can be called from any + * context and we don't want to get preempted while flushing, + * ensure may_schedule is cleared. + */ + console_trylock(); + console_may_schedule = 0; + console_unlock(); +} + /* * Return the console tty driver structure and its associated index */ diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 732e993b5..eb70592f0 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -6738,7 +6738,7 @@ static void sched_init_numa(void) sched_domains_numa_masks[i][j] = mask; - for (k = 0; k < nr_node_ids; k++) { + for_each_node(k) { if (node_distance(j, k) > sched_domains_numa_distance[i]) continue; diff --git a/kernel/task_work.c b/kernel/task_work.c index 53fa971d0..f80d564c7 100644 --- a/kernel/task_work.c +++ b/kernel/task_work.c @@ -118,3 +118,4 @@ void task_work_run(void) } while (work); } } +EXPORT_SYMBOL(task_work_run); diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c index 435b8850d..fa909f9fd 100644 --- a/kernel/time/hrtimer.c +++ b/kernel/time/hrtimer.c @@ -897,10 +897,10 @@ static int enqueue_hrtimer(struct hrtimer *timer, */ static void __remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base, - unsigned long newstate, int reprogram) + u8 newstate, int reprogram) { struct hrtimer_cpu_base *cpu_base = base->cpu_base; - unsigned int state = timer->state; + u8 state = timer->state; timer->state = newstate; if (!(state & HRTIMER_STATE_ENQUEUED)) @@ -930,7 +930,7 @@ static inline int remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base, bool restart) { if (hrtimer_is_queued(timer)) { - unsigned long state = timer->state; + u8 state = timer->state; int reprogram; /* @@ -954,6 +954,22 @@ remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base, bool rest return 0; } +static inline ktime_t hrtimer_update_lowres(struct hrtimer *timer, ktime_t tim, + const enum hrtimer_mode mode) +{ +#ifdef CONFIG_TIME_LOW_RES + /* + * CONFIG_TIME_LOW_RES indicates that the system has no way to return + * granular time values. For relative timers we add hrtimer_resolution + * (i.e. one jiffie) to prevent short timeouts. + */ + timer->is_rel = mode & HRTIMER_MODE_REL; + if (timer->is_rel) + tim = ktime_add_safe(tim, ktime_set(0, hrtimer_resolution)); +#endif + return tim; +} + /** * hrtimer_start_range_ns - (re)start an hrtimer on the current CPU * @timer: the timer to be added @@ -974,19 +990,10 @@ void hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, /* Remove an active timer from the queue: */ remove_hrtimer(timer, base, true); - if (mode & HRTIMER_MODE_REL) { + if (mode & HRTIMER_MODE_REL) tim = ktime_add_safe(tim, base->get_time()); - /* - * CONFIG_TIME_LOW_RES is a temporary way for architectures - * to signal that they simply return xtime in - * do_gettimeoffset(). In this case we want to round up by - * resolution when starting a relative timer, to avoid short - * timeouts. This will go away with the GTOD framework. - */ -#ifdef CONFIG_TIME_LOW_RES - tim = ktime_add_safe(tim, ktime_set(0, hrtimer_resolution)); -#endif - } + + tim = hrtimer_update_lowres(timer, tim, mode); hrtimer_set_expires_range_ns(timer, tim, delta_ns); @@ -1074,19 +1081,23 @@ EXPORT_SYMBOL_GPL(hrtimer_cancel); /** * hrtimer_get_remaining - get remaining time for the timer * @timer: the timer to read + * @adjust: adjust relative timers when CONFIG_TIME_LOW_RES=y */ -ktime_t hrtimer_get_remaining(const struct hrtimer *timer) +ktime_t __hrtimer_get_remaining(const struct hrtimer *timer, bool adjust) { unsigned long flags; ktime_t rem; lock_hrtimer_base(timer, &flags); - rem = hrtimer_expires_remaining(timer); + if (IS_ENABLED(CONFIG_TIME_LOW_RES) && adjust) + rem = hrtimer_expires_remaining_adjusted(timer); + else + rem = hrtimer_expires_remaining(timer); unlock_hrtimer_base(timer, &flags); return rem; } -EXPORT_SYMBOL_GPL(hrtimer_get_remaining); +EXPORT_SYMBOL_GPL(__hrtimer_get_remaining); #ifdef CONFIG_NO_HZ_COMMON /** @@ -1220,6 +1231,14 @@ static void __run_hrtimer(struct hrtimer_cpu_base *cpu_base, fn = timer->function; /* + * Clear the 'is relative' flag for the TIME_LOW_RES case. If the + * timer is restarted with a period then it becomes an absolute + * timer. If its not restarted it does not matter. + */ + if (IS_ENABLED(CONFIG_TIME_LOW_RES)) + timer->is_rel = false; + + /* * Because we run timers from hardirq context, there is no chance * they get migrated to another cpu, therefore its safe to unlock * the timer base. diff --git a/kernel/time/timer_list.c b/kernel/time/timer_list.c index f75e35b60..ba7d8b288 100644 --- a/kernel/time/timer_list.c +++ b/kernel/time/timer_list.c @@ -69,7 +69,7 @@ print_timer(struct seq_file *m, struct hrtimer *taddr, struct hrtimer *timer, print_name_offset(m, taddr); SEQ_printf(m, ", "); print_name_offset(m, timer->function); - SEQ_printf(m, ", S:%02lx", timer->state); + SEQ_printf(m, ", S:%02x", timer->state); #ifdef CONFIG_TIMER_STATS SEQ_printf(m, ", "); print_name_offset(m, timer->start_site); diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 87fb9801b..d9293402e 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -1751,7 +1751,7 @@ void trace_buffer_unlock_commit_regs(struct trace_array *tr, { __buffer_unlock_commit(buffer, event); - ftrace_trace_stack(tr, buffer, flags, 6, pc, regs); + ftrace_trace_stack(tr, buffer, flags, 0, pc, regs); ftrace_trace_userstack(buffer, flags, pc); } EXPORT_SYMBOL_GPL(trace_buffer_unlock_commit_regs); diff --git a/kernel/trace/trace_stack.c b/kernel/trace/trace_stack.c index dda9e6742..202df6cff 100644 --- a/kernel/trace/trace_stack.c +++ b/kernel/trace/trace_stack.c @@ -126,6 +126,13 @@ check_stack(unsigned long ip, unsigned long *stack) } /* + * Some archs may not have the passed in ip in the dump. + * If that happens, we need to show everything. + */ + if (i == stack_trace_max.nr_entries) + i = 0; + + /* * Now find where in the stack these are. */ x = 0; diff --git a/lib/libcrc32c.c b/lib/libcrc32c.c index 6a08ce7d6..acf9da449 100644 --- a/lib/libcrc32c.c +++ b/lib/libcrc32c.c @@ -74,3 +74,4 @@ module_exit(libcrc32c_mod_fini); MODULE_AUTHOR("Clay Haapala <chaapala@cisco.com>"); MODULE_DESCRIPTION("CRC32c (Castagnoli) calculations"); MODULE_LICENSE("GPL"); +MODULE_SOFTDEP("pre: crc32c"); diff --git a/mm/backing-dev.c b/mm/backing-dev.c index 7340353f8..cbe6f0b96 100644 --- a/mm/backing-dev.c +++ b/mm/backing-dev.c @@ -989,7 +989,7 @@ long wait_iff_congested(struct zone *zone, int sync, long timeout) * here rather than calling cond_resched(). */ if (current->flags & PF_WQ_WORKER) - schedule_timeout(1); + schedule_timeout_uninterruptible(1); else cond_resched(); diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c index 9f15bdd91..fc083996e 100644 --- a/mm/zsmalloc.c +++ b/mm/zsmalloc.c @@ -309,7 +309,12 @@ static void free_handle(struct zs_pool *pool, unsigned long handle) static void record_obj(unsigned long handle, unsigned long obj) { - *(unsigned long *)handle = obj; + /* + * lsb of @obj represents handle lock while other bits + * represent object value the handle is pointing so + * updating shouldn't do store tearing. + */ + WRITE_ONCE(*(unsigned long *)handle, obj); } /* zpool driver */ @@ -1635,6 +1640,13 @@ static int migrate_zspage(struct zs_pool *pool, struct size_class *class, free_obj = obj_malloc(d_page, class, handle); zs_object_copy(free_obj, used_obj, class); index++; + /* + * record_obj updates handle's value to free_obj and it will + * invalidate lock bit(ie, HANDLE_PIN_BIT) of handle, which + * breaks synchronization using pin_tag(e,g, zs_free) so + * let's keep the lock bit. + */ + free_obj |= BIT(HANDLE_PIN_BIT); record_obj(handle, free_obj); unpin_tag(handle); obj_free(pool, class, used_obj); diff --git a/samples/Kconfig b/samples/Kconfig index 72051e348..d54f28c6d 100644 --- a/samples/Kconfig +++ b/samples/Kconfig @@ -55,13 +55,6 @@ 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/Makefile b/samples/Makefile index d0c9b3c67..48001d7e2 100644 --- a/samples/Makefile +++ b/samples/Makefile @@ -1,5 +1,5 @@ # Makefile for Linux samples code obj-$(CONFIG_SAMPLES) += kobject/ kprobes/ trace_events/ livepatch/ \ - hw_breakpoint/ kfifo/ kdb/ kdbus/ hidraw/ rpmsg/ \ - seccomp/ configfs/ + hw_breakpoint/ kfifo/ kdb/ hidraw/ rpmsg/ seccomp/ \ + configfs/ diff --git a/samples/kdbus/.gitignore b/samples/kdbus/.gitignore deleted file mode 100644 index ee07d9857..000000000 --- a/samples/kdbus/.gitignore +++ /dev/null @@ -1 +0,0 @@ -kdbus-workers diff --git a/samples/kdbus/Makefile b/samples/kdbus/Makefile deleted file mode 100644 index 137f84272..000000000 --- a/samples/kdbus/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# kbuild trick to avoid linker error. Can be omitted if a module is built. -obj- := dummy.o - -hostprogs-$(CONFIG_SAMPLE_KDBUS) += kdbus-workers - -always := $(hostprogs-y) - -HOSTCFLAGS_kdbus-workers.o += -I$(objtree)/usr/include -HOSTLOADLIBES_kdbus-workers := -lrt diff --git a/samples/kdbus/kdbus-api.h b/samples/kdbus/kdbus-api.h deleted file mode 100644 index 7f3abae18..000000000 --- a/samples/kdbus/kdbus-api.h +++ /dev/null @@ -1,114 +0,0 @@ -#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 deleted file mode 100644 index 5a6dfdce3..000000000 --- a/samples/kdbus/kdbus-workers.c +++ /dev/null @@ -1,1346 +0,0 @@ -/* - * 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 <stdio.h> -#include <stdlib.h> -#include <sys/syscall.h> - -/* glibc < 2.7 does not ship sys/signalfd.h */ -/* we require kernels with __NR_memfd_create */ -#if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 7 && defined(__NR_memfd_create) - -#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 <string.h> -#include <sys/mman.h> -#include <sys/poll.h> -#include <sys/signalfd.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 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; - 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; -} - -#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 */ diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c index 1334e02ae..3d145a3ff 100644 --- a/security/integrity/evm/evm_main.c +++ b/security/integrity/evm/evm_main.c @@ -23,6 +23,7 @@ #include <linux/integrity.h> #include <linux/evm.h> #include <crypto/hash.h> +#include <crypto/algapi.h> #include "evm.h" int evm_initialized; @@ -148,7 +149,7 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, xattr_value_len, calc.digest); if (rc) break; - rc = memcmp(xattr_data->digest, calc.digest, + rc = crypto_memneq(xattr_data->digest, calc.digest, sizeof(calc.digest)); if (rc) rc = -EINVAL; diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index b123c42e7..b554d7f9e 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c @@ -44,6 +44,13 @@ #include <sound/compress_offload.h> #include <sound/compress_driver.h> +/* struct snd_compr_codec_caps overflows the ioctl bit size for some + * architectures, so we need to disable the relevant ioctls. + */ +#if _IOC_SIZEBITS < 14 +#define COMPR_CODEC_CAPS_OVERFLOW +#endif + /* TODO: * - add substream support for multiple devices in case of * SND_DYNAMIC_MINORS is not used @@ -438,6 +445,7 @@ out: return retval; } +#ifndef COMPR_CODEC_CAPS_OVERFLOW static int snd_compr_get_codec_caps(struct snd_compr_stream *stream, unsigned long arg) { @@ -461,6 +469,7 @@ out: kfree(caps); return retval; } +#endif /* !COMPR_CODEC_CAPS_OVERFLOW */ /* revisit this with snd_pcm_preallocate_xxx */ static int snd_compr_allocate_buffer(struct snd_compr_stream *stream, @@ -799,9 +808,11 @@ static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg) case _IOC_NR(SNDRV_COMPRESS_GET_CAPS): retval = snd_compr_get_caps(stream, arg); break; +#ifndef COMPR_CODEC_CAPS_OVERFLOW case _IOC_NR(SNDRV_COMPRESS_GET_CODEC_CAPS): retval = snd_compr_get_codec_caps(stream, arg); break; +#endif case _IOC_NR(SNDRV_COMPRESS_SET_PARAMS): retval = snd_compr_set_params(stream, arg); break; diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 58550cc93..33e72c809 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -834,7 +834,8 @@ static int choose_rate(struct snd_pcm_substream *substream, return snd_pcm_hw_param_near(substream, params, SNDRV_PCM_HW_PARAM_RATE, best_rate, NULL); } -static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream) +static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream, + bool trylock) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_hw_params *params, *sparams; @@ -848,7 +849,10 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream) struct snd_mask sformat_mask; struct snd_mask mask; - if (mutex_lock_interruptible(&runtime->oss.params_lock)) + if (trylock) { + if (!(mutex_trylock(&runtime->oss.params_lock))) + return -EAGAIN; + } else if (mutex_lock_interruptible(&runtime->oss.params_lock)) return -EINTR; sw_params = kmalloc(sizeof(*sw_params), GFP_KERNEL); params = kmalloc(sizeof(*params), GFP_KERNEL); @@ -1092,7 +1096,7 @@ static int snd_pcm_oss_get_active_substream(struct snd_pcm_oss_file *pcm_oss_fil if (asubstream == NULL) asubstream = substream; if (substream->runtime->oss.params) { - err = snd_pcm_oss_change_params(substream); + err = snd_pcm_oss_change_params(substream, false); if (err < 0) return err; } @@ -1132,7 +1136,7 @@ static int snd_pcm_oss_make_ready(struct snd_pcm_substream *substream) return 0; runtime = substream->runtime; if (runtime->oss.params) { - err = snd_pcm_oss_change_params(substream); + err = snd_pcm_oss_change_params(substream, false); if (err < 0) return err; } @@ -2163,7 +2167,7 @@ static int snd_pcm_oss_get_space(struct snd_pcm_oss_file *pcm_oss_file, int stre runtime = substream->runtime; if (runtime->oss.params && - (err = snd_pcm_oss_change_params(substream)) < 0) + (err = snd_pcm_oss_change_params(substream, false)) < 0) return err; info.fragsize = runtime->oss.period_bytes; @@ -2800,7 +2804,12 @@ static int snd_pcm_oss_mmap(struct file *file, struct vm_area_struct *area) return -EIO; if (runtime->oss.params) { - if ((err = snd_pcm_oss_change_params(substream)) < 0) + /* use mutex_trylock() for params_lock for avoiding a deadlock + * between mmap_sem and params_lock taken by + * copy_from/to_user() in snd_pcm_oss_write/read() + */ + err = snd_pcm_oss_change_params(substream, true); + if (err < 0) return err; } #ifdef CONFIG_SND_PCM_OSS_PLUGINS diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index a7759846f..795437b10 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -942,31 +942,36 @@ static long snd_rawmidi_kernel_read1(struct snd_rawmidi_substream *substream, unsigned long flags; long result = 0, count1; struct snd_rawmidi_runtime *runtime = substream->runtime; + unsigned long appl_ptr; + spin_lock_irqsave(&runtime->lock, flags); while (count > 0 && runtime->avail) { count1 = runtime->buffer_size - runtime->appl_ptr; if (count1 > count) count1 = count; - spin_lock_irqsave(&runtime->lock, flags); if (count1 > (int)runtime->avail) count1 = runtime->avail; + + /* update runtime->appl_ptr before unlocking for userbuf */ + appl_ptr = runtime->appl_ptr; + runtime->appl_ptr += count1; + runtime->appl_ptr %= runtime->buffer_size; + runtime->avail -= count1; + if (kernelbuf) - memcpy(kernelbuf + result, runtime->buffer + runtime->appl_ptr, count1); + memcpy(kernelbuf + result, runtime->buffer + appl_ptr, count1); if (userbuf) { spin_unlock_irqrestore(&runtime->lock, flags); if (copy_to_user(userbuf + result, - runtime->buffer + runtime->appl_ptr, count1)) { + runtime->buffer + appl_ptr, count1)) { return result > 0 ? result : -EFAULT; } spin_lock_irqsave(&runtime->lock, flags); } - runtime->appl_ptr += count1; - runtime->appl_ptr %= runtime->buffer_size; - runtime->avail -= count1; - spin_unlock_irqrestore(&runtime->lock, flags); result += count1; count -= count1; } + spin_unlock_irqrestore(&runtime->lock, flags); return result; } @@ -1055,23 +1060,16 @@ int snd_rawmidi_transmit_empty(struct snd_rawmidi_substream *substream) EXPORT_SYMBOL(snd_rawmidi_transmit_empty); /** - * snd_rawmidi_transmit_peek - copy data from the internal buffer + * __snd_rawmidi_transmit_peek - copy data from the internal buffer * @substream: the rawmidi substream * @buffer: the buffer pointer * @count: data size to transfer * - * Copies data from the internal output buffer to the given buffer. - * - * Call this in the interrupt handler when the midi output is ready, - * and call snd_rawmidi_transmit_ack() after the transmission is - * finished. - * - * Return: The size of copied data, or a negative error code on failure. + * This is a variant of snd_rawmidi_transmit_peek() without spinlock. */ -int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, +int __snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, unsigned char *buffer, int count) { - unsigned long flags; int result, count1; struct snd_rawmidi_runtime *runtime = substream->runtime; @@ -1081,7 +1079,6 @@ int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, return -EINVAL; } result = 0; - spin_lock_irqsave(&runtime->lock, flags); if (runtime->avail >= runtime->buffer_size) { /* warning: lowlevel layer MUST trigger down the hardware */ goto __skip; @@ -1106,25 +1103,47 @@ int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, } } __skip: + return result; +} +EXPORT_SYMBOL(__snd_rawmidi_transmit_peek); + +/** + * snd_rawmidi_transmit_peek - copy data from the internal buffer + * @substream: the rawmidi substream + * @buffer: the buffer pointer + * @count: data size to transfer + * + * Copies data from the internal output buffer to the given buffer. + * + * Call this in the interrupt handler when the midi output is ready, + * and call snd_rawmidi_transmit_ack() after the transmission is + * finished. + * + * Return: The size of copied data, or a negative error code on failure. + */ +int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, + unsigned char *buffer, int count) +{ + struct snd_rawmidi_runtime *runtime = substream->runtime; + int result; + unsigned long flags; + + spin_lock_irqsave(&runtime->lock, flags); + result = __snd_rawmidi_transmit_peek(substream, buffer, count); spin_unlock_irqrestore(&runtime->lock, flags); return result; } EXPORT_SYMBOL(snd_rawmidi_transmit_peek); /** - * snd_rawmidi_transmit_ack - acknowledge the transmission + * __snd_rawmidi_transmit_ack - acknowledge the transmission * @substream: the rawmidi substream * @count: the transferred count * - * Advances the hardware pointer for the internal output buffer with - * the given size and updates the condition. - * Call after the transmission is finished. - * - * Return: The advanced size if successful, or a negative error code on failure. + * This is a variant of __snd_rawmidi_transmit_ack() without spinlock. */ -int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count) +int __snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count) { - unsigned long flags; struct snd_rawmidi_runtime *runtime = substream->runtime; if (runtime->buffer == NULL) { @@ -1132,7 +1151,6 @@ int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count) "snd_rawmidi_transmit_ack: output is not active!!!\n"); return -EINVAL; } - spin_lock_irqsave(&runtime->lock, flags); snd_BUG_ON(runtime->avail + count > runtime->buffer_size); runtime->hw_ptr += count; runtime->hw_ptr %= runtime->buffer_size; @@ -1142,9 +1160,32 @@ int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count) if (runtime->drain || snd_rawmidi_ready(substream)) wake_up(&runtime->sleep); } - spin_unlock_irqrestore(&runtime->lock, flags); return count; } +EXPORT_SYMBOL(__snd_rawmidi_transmit_ack); + +/** + * snd_rawmidi_transmit_ack - acknowledge the transmission + * @substream: the rawmidi substream + * @count: the transferred count + * + * Advances the hardware pointer for the internal output buffer with + * the given size and updates the condition. + * Call after the transmission is finished. + * + * Return: The advanced size if successful, or a negative error code on failure. + */ +int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count) +{ + struct snd_rawmidi_runtime *runtime = substream->runtime; + int result; + unsigned long flags; + + spin_lock_irqsave(&runtime->lock, flags); + result = __snd_rawmidi_transmit_ack(substream, count); + spin_unlock_irqrestore(&runtime->lock, flags); + return result; +} EXPORT_SYMBOL(snd_rawmidi_transmit_ack); /** @@ -1160,12 +1201,22 @@ EXPORT_SYMBOL(snd_rawmidi_transmit_ack); int snd_rawmidi_transmit(struct snd_rawmidi_substream *substream, unsigned char *buffer, int count) { + struct snd_rawmidi_runtime *runtime = substream->runtime; + int result; + unsigned long flags; + + spin_lock_irqsave(&runtime->lock, flags); if (!substream->opened) - return -EBADFD; - count = snd_rawmidi_transmit_peek(substream, buffer, count); - if (count < 0) - return count; - return snd_rawmidi_transmit_ack(substream, count); + result = -EBADFD; + else { + count = __snd_rawmidi_transmit_peek(substream, buffer, count); + if (count <= 0) + result = count; + else + result = __snd_rawmidi_transmit_ack(substream, count); + } + spin_unlock_irqrestore(&runtime->lock, flags); + return result; } EXPORT_SYMBOL(snd_rawmidi_transmit); @@ -1177,8 +1228,9 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, unsigned long flags; long count1, result; struct snd_rawmidi_runtime *runtime = substream->runtime; + unsigned long appl_ptr; - if (snd_BUG_ON(!kernelbuf && !userbuf)) + if (!kernelbuf && !userbuf) return -EINVAL; if (snd_BUG_ON(!runtime->buffer)) return -EINVAL; @@ -1197,12 +1249,19 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, count1 = count; if (count1 > (long)runtime->avail) count1 = runtime->avail; + + /* update runtime->appl_ptr before unlocking for userbuf */ + appl_ptr = runtime->appl_ptr; + runtime->appl_ptr += count1; + runtime->appl_ptr %= runtime->buffer_size; + runtime->avail -= count1; + if (kernelbuf) - memcpy(runtime->buffer + runtime->appl_ptr, + memcpy(runtime->buffer + appl_ptr, kernelbuf + result, count1); else if (userbuf) { spin_unlock_irqrestore(&runtime->lock, flags); - if (copy_from_user(runtime->buffer + runtime->appl_ptr, + if (copy_from_user(runtime->buffer + appl_ptr, userbuf + result, count1)) { spin_lock_irqsave(&runtime->lock, flags); result = result > 0 ? result : -EFAULT; @@ -1210,9 +1269,6 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, } spin_lock_irqsave(&runtime->lock, flags); } - runtime->appl_ptr += count1; - runtime->appl_ptr %= runtime->buffer_size; - runtime->avail -= count1; result += count1; count -= count1; } diff --git a/sound/core/seq/oss/seq_oss_init.c b/sound/core/seq/oss/seq_oss_init.c index b1221b297..6779e82b4 100644 --- a/sound/core/seq/oss/seq_oss_init.c +++ b/sound/core/seq/oss/seq_oss_init.c @@ -202,7 +202,7 @@ snd_seq_oss_open(struct file *file, int level) dp->index = i; if (i >= SNDRV_SEQ_OSS_MAX_CLIENTS) { - pr_err("ALSA: seq_oss: too many applications\n"); + pr_debug("ALSA: seq_oss: too many applications\n"); rc = -ENOMEM; goto _error; } diff --git a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c index 0f3b38184..b16dbef04 100644 --- a/sound/core/seq/oss/seq_oss_synth.c +++ b/sound/core/seq/oss/seq_oss_synth.c @@ -308,7 +308,7 @@ snd_seq_oss_synth_cleanup(struct seq_oss_devinfo *dp) struct seq_oss_synth *rec; struct seq_oss_synthinfo *info; - if (snd_BUG_ON(dp->max_synthdev >= SNDRV_SEQ_OSS_MAX_SYNTH_DEVS)) + if (snd_BUG_ON(dp->max_synthdev > SNDRV_SEQ_OSS_MAX_SYNTH_DEVS)) return; for (i = 0; i < dp->max_synthdev; i++) { info = &dp->synths[i]; diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 13cfa8157..58e79e02f 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -678,6 +678,9 @@ static int deliver_to_subscribers(struct snd_seq_client *client, else down_read(&grp->list_mutex); list_for_each_entry(subs, &grp->list_head, src_list) { + /* both ports ready? */ + if (atomic_read(&subs->ref_count) != 2) + continue; event->dest = subs->info.dest; if (subs->info.flags & SNDRV_SEQ_PORT_SUBS_TIMESTAMP) /* convert time according to flag with subscription */ diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c index 55170a20a..921fb2bd8 100644 --- a/sound/core/seq/seq_ports.c +++ b/sound/core/seq/seq_ports.c @@ -173,10 +173,6 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client, } /* */ -enum group_type { - SRC_LIST, DEST_LIST -}; - static int subscribe_port(struct snd_seq_client *client, struct snd_seq_client_port *port, struct snd_seq_port_subs_info *grp, @@ -203,6 +199,20 @@ static struct snd_seq_client_port *get_client_port(struct snd_seq_addr *addr, return NULL; } +static void delete_and_unsubscribe_port(struct snd_seq_client *client, + struct snd_seq_client_port *port, + struct snd_seq_subscribers *subs, + bool is_src, bool ack); + +static inline struct snd_seq_subscribers * +get_subscriber(struct list_head *p, bool is_src) +{ + if (is_src) + return list_entry(p, struct snd_seq_subscribers, src_list); + else + return list_entry(p, struct snd_seq_subscribers, dest_list); +} + /* * remove all subscribers on the list * this is called from port_delete, for each src and dest list. @@ -210,7 +220,7 @@ static struct snd_seq_client_port *get_client_port(struct snd_seq_addr *addr, static void clear_subscriber_list(struct snd_seq_client *client, struct snd_seq_client_port *port, struct snd_seq_port_subs_info *grp, - int grptype) + int is_src) { struct list_head *p, *n; @@ -219,15 +229,13 @@ static void clear_subscriber_list(struct snd_seq_client *client, struct snd_seq_client *c; struct snd_seq_client_port *aport; - if (grptype == SRC_LIST) { - subs = list_entry(p, struct snd_seq_subscribers, src_list); + subs = get_subscriber(p, is_src); + if (is_src) aport = get_client_port(&subs->info.dest, &c); - } else { - subs = list_entry(p, struct snd_seq_subscribers, dest_list); + else aport = get_client_port(&subs->info.sender, &c); - } - list_del(p); - unsubscribe_port(client, port, grp, &subs->info, 0); + delete_and_unsubscribe_port(client, port, subs, is_src, false); + if (!aport) { /* looks like the connected port is being deleted. * we decrease the counter, and when both ports are deleted @@ -235,21 +243,14 @@ static void clear_subscriber_list(struct snd_seq_client *client, */ if (atomic_dec_and_test(&subs->ref_count)) kfree(subs); - } else { - /* ok we got the connected port */ - struct snd_seq_port_subs_info *agrp; - agrp = (grptype == SRC_LIST) ? &aport->c_dest : &aport->c_src; - down_write(&agrp->list_mutex); - if (grptype == SRC_LIST) - list_del(&subs->dest_list); - else - list_del(&subs->src_list); - up_write(&agrp->list_mutex); - unsubscribe_port(c, aport, agrp, &subs->info, 1); - kfree(subs); - snd_seq_port_unlock(aport); - snd_seq_client_unlock(c); + continue; } + + /* ok we got the connected port */ + delete_and_unsubscribe_port(c, aport, subs, !is_src, true); + kfree(subs); + snd_seq_port_unlock(aport); + snd_seq_client_unlock(c); } } @@ -262,8 +263,8 @@ static int port_delete(struct snd_seq_client *client, snd_use_lock_sync(&port->use_lock); /* clear subscribers info */ - clear_subscriber_list(client, port, &port->c_src, SRC_LIST); - clear_subscriber_list(client, port, &port->c_dest, DEST_LIST); + clear_subscriber_list(client, port, &port->c_src, true); + clear_subscriber_list(client, port, &port->c_dest, false); if (port->private_free) port->private_free(port->private_data); @@ -479,85 +480,120 @@ static int match_subs_info(struct snd_seq_port_subscribe *r, return 0; } - -/* connect two ports */ -int snd_seq_port_connect(struct snd_seq_client *connector, - struct snd_seq_client *src_client, - struct snd_seq_client_port *src_port, - struct snd_seq_client *dest_client, - struct snd_seq_client_port *dest_port, - struct snd_seq_port_subscribe *info) +static int check_and_subscribe_port(struct snd_seq_client *client, + struct snd_seq_client_port *port, + struct snd_seq_subscribers *subs, + bool is_src, bool exclusive, bool ack) { - struct snd_seq_port_subs_info *src = &src_port->c_src; - struct snd_seq_port_subs_info *dest = &dest_port->c_dest; - struct snd_seq_subscribers *subs, *s; - int err, src_called = 0; - unsigned long flags; - int exclusive; + struct snd_seq_port_subs_info *grp; + struct list_head *p; + struct snd_seq_subscribers *s; + int err; - subs = kzalloc(sizeof(*subs), GFP_KERNEL); - if (! subs) - return -ENOMEM; - - subs->info = *info; - atomic_set(&subs->ref_count, 2); - - down_write(&src->list_mutex); - down_write_nested(&dest->list_mutex, SINGLE_DEPTH_NESTING); - - exclusive = info->flags & SNDRV_SEQ_PORT_SUBS_EXCLUSIVE ? 1 : 0; + grp = is_src ? &port->c_src : &port->c_dest; err = -EBUSY; + down_write(&grp->list_mutex); if (exclusive) { - if (! list_empty(&src->list_head) || ! list_empty(&dest->list_head)) + if (!list_empty(&grp->list_head)) goto __error; } else { - if (src->exclusive || dest->exclusive) + if (grp->exclusive) goto __error; /* check whether already exists */ - list_for_each_entry(s, &src->list_head, src_list) { - if (match_subs_info(info, &s->info)) - goto __error; - } - list_for_each_entry(s, &dest->list_head, dest_list) { - if (match_subs_info(info, &s->info)) + list_for_each(p, &grp->list_head) { + s = get_subscriber(p, is_src); + if (match_subs_info(&subs->info, &s->info)) goto __error; } } - if ((err = subscribe_port(src_client, src_port, src, info, - connector->number != src_client->number)) < 0) - goto __error; - src_called = 1; - - if ((err = subscribe_port(dest_client, dest_port, dest, info, - connector->number != dest_client->number)) < 0) + err = subscribe_port(client, port, grp, &subs->info, ack); + if (err < 0) { + grp->exclusive = 0; goto __error; + } /* add to list */ - write_lock_irqsave(&src->list_lock, flags); - // write_lock(&dest->list_lock); // no other lock yet - list_add_tail(&subs->src_list, &src->list_head); - list_add_tail(&subs->dest_list, &dest->list_head); - // write_unlock(&dest->list_lock); // no other lock yet - write_unlock_irqrestore(&src->list_lock, flags); + write_lock_irq(&grp->list_lock); + if (is_src) + list_add_tail(&subs->src_list, &grp->list_head); + else + list_add_tail(&subs->dest_list, &grp->list_head); + grp->exclusive = exclusive; + atomic_inc(&subs->ref_count); + write_unlock_irq(&grp->list_lock); + err = 0; + + __error: + up_write(&grp->list_mutex); + return err; +} - src->exclusive = dest->exclusive = exclusive; +static void delete_and_unsubscribe_port(struct snd_seq_client *client, + struct snd_seq_client_port *port, + struct snd_seq_subscribers *subs, + bool is_src, bool ack) +{ + struct snd_seq_port_subs_info *grp; + + grp = is_src ? &port->c_src : &port->c_dest; + down_write(&grp->list_mutex); + write_lock_irq(&grp->list_lock); + if (is_src) + list_del(&subs->src_list); + else + list_del(&subs->dest_list); + grp->exclusive = 0; + write_unlock_irq(&grp->list_lock); + up_write(&grp->list_mutex); + + unsubscribe_port(client, port, grp, &subs->info, ack); +} + +/* connect two ports */ +int snd_seq_port_connect(struct snd_seq_client *connector, + struct snd_seq_client *src_client, + struct snd_seq_client_port *src_port, + struct snd_seq_client *dest_client, + struct snd_seq_client_port *dest_port, + struct snd_seq_port_subscribe *info) +{ + struct snd_seq_subscribers *subs; + bool exclusive; + int err; + + subs = kzalloc(sizeof(*subs), GFP_KERNEL); + if (!subs) + return -ENOMEM; + + subs->info = *info; + atomic_set(&subs->ref_count, 0); + INIT_LIST_HEAD(&subs->src_list); + INIT_LIST_HEAD(&subs->dest_list); + + exclusive = !!(info->flags & SNDRV_SEQ_PORT_SUBS_EXCLUSIVE); + + err = check_and_subscribe_port(src_client, src_port, subs, true, + exclusive, + connector->number != src_client->number); + if (err < 0) + goto error; + err = check_and_subscribe_port(dest_client, dest_port, subs, false, + exclusive, + connector->number != dest_client->number); + if (err < 0) + goto error_dest; - up_write(&dest->list_mutex); - up_write(&src->list_mutex); return 0; - __error: - if (src_called) - unsubscribe_port(src_client, src_port, src, info, - connector->number != src_client->number); + error_dest: + delete_and_unsubscribe_port(src_client, src_port, subs, true, + connector->number != src_client->number); + error: kfree(subs); - up_write(&dest->list_mutex); - up_write(&src->list_mutex); return err; } - /* remove the connection */ int snd_seq_port_disconnect(struct snd_seq_client *connector, struct snd_seq_client *src_client, @@ -567,37 +603,28 @@ int snd_seq_port_disconnect(struct snd_seq_client *connector, struct snd_seq_port_subscribe *info) { struct snd_seq_port_subs_info *src = &src_port->c_src; - struct snd_seq_port_subs_info *dest = &dest_port->c_dest; struct snd_seq_subscribers *subs; int err = -ENOENT; - unsigned long flags; down_write(&src->list_mutex); - down_write_nested(&dest->list_mutex, SINGLE_DEPTH_NESTING); - /* look for the connection */ list_for_each_entry(subs, &src->list_head, src_list) { if (match_subs_info(info, &subs->info)) { - write_lock_irqsave(&src->list_lock, flags); - // write_lock(&dest->list_lock); // no lock yet - list_del(&subs->src_list); - list_del(&subs->dest_list); - // write_unlock(&dest->list_lock); - write_unlock_irqrestore(&src->list_lock, flags); - src->exclusive = dest->exclusive = 0; - unsubscribe_port(src_client, src_port, src, info, - connector->number != src_client->number); - unsubscribe_port(dest_client, dest_port, dest, info, - connector->number != dest_client->number); - kfree(subs); + atomic_dec(&subs->ref_count); /* mark as not ready */ err = 0; break; } } - - up_write(&dest->list_mutex); up_write(&src->list_mutex); - return err; + if (err < 0) + return err; + + delete_and_unsubscribe_port(src_client, src_port, subs, true, + connector->number != src_client->number); + delete_and_unsubscribe_port(dest_client, dest_port, subs, false, + connector->number != dest_client->number); + kfree(subs); + return 0; } diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c index 82b220c76..293104926 100644 --- a/sound/core/seq/seq_timer.c +++ b/sound/core/seq/seq_timer.c @@ -90,6 +90,9 @@ void snd_seq_timer_delete(struct snd_seq_timer **tmr) void snd_seq_timer_defaults(struct snd_seq_timer * tmr) { + unsigned long flags; + + spin_lock_irqsave(&tmr->lock, flags); /* setup defaults */ tmr->ppq = 96; /* 96 PPQ */ tmr->tempo = 500000; /* 120 BPM */ @@ -105,21 +108,25 @@ void snd_seq_timer_defaults(struct snd_seq_timer * tmr) tmr->preferred_resolution = seq_default_timer_resolution; tmr->skew = tmr->skew_base = SKEW_BASE; + spin_unlock_irqrestore(&tmr->lock, flags); } -void snd_seq_timer_reset(struct snd_seq_timer * tmr) +static void seq_timer_reset(struct snd_seq_timer *tmr) { - unsigned long flags; - - spin_lock_irqsave(&tmr->lock, flags); - /* reset time & songposition */ tmr->cur_time.tv_sec = 0; tmr->cur_time.tv_nsec = 0; tmr->tick.cur_tick = 0; tmr->tick.fraction = 0; +} + +void snd_seq_timer_reset(struct snd_seq_timer *tmr) +{ + unsigned long flags; + spin_lock_irqsave(&tmr->lock, flags); + seq_timer_reset(tmr); spin_unlock_irqrestore(&tmr->lock, flags); } @@ -138,8 +145,11 @@ static void snd_seq_timer_interrupt(struct snd_timer_instance *timeri, tmr = q->timer; if (tmr == NULL) return; - if (!tmr->running) + spin_lock_irqsave(&tmr->lock, flags); + if (!tmr->running) { + spin_unlock_irqrestore(&tmr->lock, flags); return; + } resolution *= ticks; if (tmr->skew != tmr->skew_base) { @@ -148,8 +158,6 @@ static void snd_seq_timer_interrupt(struct snd_timer_instance *timeri, (((resolution & 0xffff) * tmr->skew) >> 16); } - spin_lock_irqsave(&tmr->lock, flags); - /* update timer */ snd_seq_inc_time_nsec(&tmr->cur_time, resolution); @@ -296,26 +304,30 @@ int snd_seq_timer_open(struct snd_seq_queue *q) t->callback = snd_seq_timer_interrupt; t->callback_data = q; t->flags |= SNDRV_TIMER_IFLG_AUTO; + spin_lock_irq(&tmr->lock); tmr->timeri = t; + spin_unlock_irq(&tmr->lock); return 0; } int snd_seq_timer_close(struct snd_seq_queue *q) { struct snd_seq_timer *tmr; + struct snd_timer_instance *t; tmr = q->timer; if (snd_BUG_ON(!tmr)) return -EINVAL; - if (tmr->timeri) { - snd_timer_stop(tmr->timeri); - snd_timer_close(tmr->timeri); - tmr->timeri = NULL; - } + spin_lock_irq(&tmr->lock); + t = tmr->timeri; + tmr->timeri = NULL; + spin_unlock_irq(&tmr->lock); + if (t) + snd_timer_close(t); return 0; } -int snd_seq_timer_stop(struct snd_seq_timer * tmr) +static int seq_timer_stop(struct snd_seq_timer *tmr) { if (! tmr->timeri) return -EINVAL; @@ -326,6 +338,17 @@ int snd_seq_timer_stop(struct snd_seq_timer * tmr) return 0; } +int snd_seq_timer_stop(struct snd_seq_timer *tmr) +{ + unsigned long flags; + int err; + + spin_lock_irqsave(&tmr->lock, flags); + err = seq_timer_stop(tmr); + spin_unlock_irqrestore(&tmr->lock, flags); + return err; +} + static int initialize_timer(struct snd_seq_timer *tmr) { struct snd_timer *t; @@ -358,13 +381,13 @@ static int initialize_timer(struct snd_seq_timer *tmr) return 0; } -int snd_seq_timer_start(struct snd_seq_timer * tmr) +static int seq_timer_start(struct snd_seq_timer *tmr) { if (! tmr->timeri) return -EINVAL; if (tmr->running) - snd_seq_timer_stop(tmr); - snd_seq_timer_reset(tmr); + seq_timer_stop(tmr); + seq_timer_reset(tmr); if (initialize_timer(tmr) < 0) return -EINVAL; snd_timer_start(tmr->timeri, tmr->ticks); @@ -373,14 +396,25 @@ int snd_seq_timer_start(struct snd_seq_timer * tmr) return 0; } -int snd_seq_timer_continue(struct snd_seq_timer * tmr) +int snd_seq_timer_start(struct snd_seq_timer *tmr) +{ + unsigned long flags; + int err; + + spin_lock_irqsave(&tmr->lock, flags); + err = seq_timer_start(tmr); + spin_unlock_irqrestore(&tmr->lock, flags); + return err; +} + +static int seq_timer_continue(struct snd_seq_timer *tmr) { if (! tmr->timeri) return -EINVAL; if (tmr->running) return -EBUSY; if (! tmr->initialized) { - snd_seq_timer_reset(tmr); + seq_timer_reset(tmr); if (initialize_timer(tmr) < 0) return -EINVAL; } @@ -390,11 +424,24 @@ int snd_seq_timer_continue(struct snd_seq_timer * tmr) return 0; } +int snd_seq_timer_continue(struct snd_seq_timer *tmr) +{ + unsigned long flags; + int err; + + spin_lock_irqsave(&tmr->lock, flags); + err = seq_timer_continue(tmr); + spin_unlock_irqrestore(&tmr->lock, flags); + return err; +} + /* return current 'real' time. use timeofday() to get better granularity. */ snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr) { snd_seq_real_time_t cur_time; + unsigned long flags; + spin_lock_irqsave(&tmr->lock, flags); cur_time = tmr->cur_time; if (tmr->running) { struct timeval tm; @@ -410,7 +457,7 @@ snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr) } snd_seq_sanity_real_time(&cur_time); } - + spin_unlock_irqrestore(&tmr->lock, flags); return cur_time; } diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c index 56e0f4cd3..81134e067 100644 --- a/sound/core/seq/seq_virmidi.c +++ b/sound/core/seq/seq_virmidi.c @@ -155,21 +155,26 @@ static void snd_virmidi_output_trigger(struct snd_rawmidi_substream *substream, struct snd_virmidi *vmidi = substream->runtime->private_data; int count, res; unsigned char buf[32], *pbuf; + unsigned long flags; if (up) { vmidi->trigger = 1; if (vmidi->seq_mode == SNDRV_VIRMIDI_SEQ_DISPATCH && !(vmidi->rdev->flags & SNDRV_VIRMIDI_SUBSCRIBE)) { - snd_rawmidi_transmit_ack(substream, substream->runtime->buffer_size - substream->runtime->avail); - return; /* ignored */ + while (snd_rawmidi_transmit(substream, buf, + sizeof(buf)) > 0) { + /* ignored */ + } + return; } if (vmidi->event.type != SNDRV_SEQ_EVENT_NONE) { if (snd_seq_kernel_client_dispatch(vmidi->client, &vmidi->event, in_atomic(), 0) < 0) return; vmidi->event.type = SNDRV_SEQ_EVENT_NONE; } + spin_lock_irqsave(&substream->runtime->lock, flags); while (1) { - count = snd_rawmidi_transmit_peek(substream, buf, sizeof(buf)); + count = __snd_rawmidi_transmit_peek(substream, buf, sizeof(buf)); if (count <= 0) break; pbuf = buf; @@ -179,16 +184,18 @@ static void snd_virmidi_output_trigger(struct snd_rawmidi_substream *substream, snd_midi_event_reset_encode(vmidi->parser); continue; } - snd_rawmidi_transmit_ack(substream, res); + __snd_rawmidi_transmit_ack(substream, res); pbuf += res; count -= res; if (vmidi->event.type != SNDRV_SEQ_EVENT_NONE) { if (snd_seq_kernel_client_dispatch(vmidi->client, &vmidi->event, in_atomic(), 0) < 0) - return; + goto out; vmidi->event.type = SNDRV_SEQ_EVENT_NONE; } } } + out: + spin_unlock_irqrestore(&substream->runtime->lock, flags); } else { vmidi->trigger = 0; } @@ -254,9 +261,13 @@ static int snd_virmidi_output_open(struct snd_rawmidi_substream *substream) */ static int snd_virmidi_input_close(struct snd_rawmidi_substream *substream) { + struct snd_virmidi_dev *rdev = substream->rmidi->private_data; struct snd_virmidi *vmidi = substream->runtime->private_data; - snd_midi_event_free(vmidi->parser); + + write_lock_irq(&rdev->filelist_lock); list_del(&vmidi->list); + write_unlock_irq(&rdev->filelist_lock); + snd_midi_event_free(vmidi->parser); substream->runtime->private_data = NULL; kfree(vmidi); return 0; diff --git a/sound/core/timer.c b/sound/core/timer.c index 0a049c457..f24c9fccf 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -305,8 +305,7 @@ int snd_timer_open(struct snd_timer_instance **ti, return 0; } -static int _snd_timer_stop(struct snd_timer_instance *timeri, - int keep_flag, int event); +static int _snd_timer_stop(struct snd_timer_instance *timeri, int event); /* * close a timer instance @@ -348,7 +347,7 @@ int snd_timer_close(struct snd_timer_instance *timeri) spin_unlock_irq(&timer->lock); mutex_lock(®ister_mutex); list_del(&timeri->open_list); - if (timer && list_empty(&timer->open_list_head) && + if (list_empty(&timer->open_list_head) && timer->hw.close) timer->hw.close(timer); /* remove slave links */ @@ -423,7 +422,7 @@ static void snd_timer_notify1(struct snd_timer_instance *ti, int event) spin_lock_irqsave(&timer->lock, flags); list_for_each_entry(ts, &ti->slave_active_head, active_list) if (ts->ccallback) - ts->ccallback(ti, event + 100, &tstamp, resolution); + ts->ccallback(ts, event + 100, &tstamp, resolution); spin_unlock_irqrestore(&timer->lock, flags); } @@ -452,6 +451,10 @@ static int snd_timer_start_slave(struct snd_timer_instance *timeri) unsigned long flags; spin_lock_irqsave(&slave_active_lock, flags); + if (timeri->flags & SNDRV_TIMER_IFLG_RUNNING) { + spin_unlock_irqrestore(&slave_active_lock, flags); + return -EBUSY; + } timeri->flags |= SNDRV_TIMER_IFLG_RUNNING; if (timeri->master && timeri->timer) { spin_lock(&timeri->timer->lock); @@ -476,7 +479,8 @@ int snd_timer_start(struct snd_timer_instance *timeri, unsigned int ticks) return -EINVAL; if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) { result = snd_timer_start_slave(timeri); - snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START); + if (result >= 0) + snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START); return result; } timer = timeri->timer; @@ -485,16 +489,22 @@ int snd_timer_start(struct snd_timer_instance *timeri, unsigned int ticks) if (timer->card && timer->card->shutdown) return -ENODEV; spin_lock_irqsave(&timer->lock, flags); + if (timeri->flags & (SNDRV_TIMER_IFLG_RUNNING | + SNDRV_TIMER_IFLG_START)) { + result = -EBUSY; + goto unlock; + } timeri->ticks = timeri->cticks = ticks; timeri->pticks = 0; result = snd_timer_start1(timer, timeri, ticks); + unlock: spin_unlock_irqrestore(&timer->lock, flags); - snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START); + if (result >= 0) + snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START); return result; } -static int _snd_timer_stop(struct snd_timer_instance * timeri, - int keep_flag, int event) +static int _snd_timer_stop(struct snd_timer_instance *timeri, int event) { struct snd_timer *timer; unsigned long flags; @@ -503,19 +513,30 @@ static int _snd_timer_stop(struct snd_timer_instance * timeri, return -ENXIO; if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) { - if (!keep_flag) { - spin_lock_irqsave(&slave_active_lock, flags); - timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING; - list_del_init(&timeri->ack_list); - list_del_init(&timeri->active_list); + spin_lock_irqsave(&slave_active_lock, flags); + if (!(timeri->flags & SNDRV_TIMER_IFLG_RUNNING)) { spin_unlock_irqrestore(&slave_active_lock, flags); + return -EBUSY; } + if (timeri->timer) + spin_lock(&timeri->timer->lock); + timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING; + list_del_init(&timeri->ack_list); + list_del_init(&timeri->active_list); + if (timeri->timer) + spin_unlock(&timeri->timer->lock); + spin_unlock_irqrestore(&slave_active_lock, flags); goto __end; } timer = timeri->timer; if (!timer) return -EINVAL; spin_lock_irqsave(&timer->lock, flags); + if (!(timeri->flags & (SNDRV_TIMER_IFLG_RUNNING | + SNDRV_TIMER_IFLG_START))) { + spin_unlock_irqrestore(&timer->lock, flags); + return -EBUSY; + } list_del_init(&timeri->ack_list); list_del_init(&timeri->active_list); if (timer->card && timer->card->shutdown) { @@ -534,9 +555,7 @@ static int _snd_timer_stop(struct snd_timer_instance * timeri, } } } - if (!keep_flag) - timeri->flags &= - ~(SNDRV_TIMER_IFLG_RUNNING | SNDRV_TIMER_IFLG_START); + timeri->flags &= ~(SNDRV_TIMER_IFLG_RUNNING | SNDRV_TIMER_IFLG_START); spin_unlock_irqrestore(&timer->lock, flags); __end: if (event != SNDRV_TIMER_EVENT_RESOLUTION) @@ -555,7 +574,7 @@ int snd_timer_stop(struct snd_timer_instance *timeri) unsigned long flags; int err; - err = _snd_timer_stop(timeri, 0, SNDRV_TIMER_EVENT_STOP); + err = _snd_timer_stop(timeri, SNDRV_TIMER_EVENT_STOP); if (err < 0) return err; timer = timeri->timer; @@ -587,10 +606,15 @@ int snd_timer_continue(struct snd_timer_instance *timeri) if (timer->card && timer->card->shutdown) return -ENODEV; spin_lock_irqsave(&timer->lock, flags); + if (timeri->flags & SNDRV_TIMER_IFLG_RUNNING) { + result = -EBUSY; + goto unlock; + } if (!timeri->cticks) timeri->cticks = 1; timeri->pticks = 0; result = snd_timer_start1(timer, timeri, timer->sticks); + unlock: spin_unlock_irqrestore(&timer->lock, flags); snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_CONTINUE); return result; @@ -601,7 +625,7 @@ int snd_timer_continue(struct snd_timer_instance *timeri) */ int snd_timer_pause(struct snd_timer_instance * timeri) { - return _snd_timer_stop(timeri, 0, SNDRV_TIMER_EVENT_PAUSE); + return _snd_timer_stop(timeri, SNDRV_TIMER_EVENT_PAUSE); } /* @@ -724,8 +748,8 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) ti->cticks = ti->ticks; } else { ti->flags &= ~SNDRV_TIMER_IFLG_RUNNING; - if (--timer->running) - list_del_init(&ti->active_list); + --timer->running; + list_del_init(&ti->active_list); } if ((timer->hw.flags & SNDRV_TIMER_HW_TASKLET) || (ti->flags & SNDRV_TIMER_IFLG_FAST)) @@ -1900,6 +1924,7 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer, { struct snd_timer_user *tu; long result = 0, unit; + int qhead; int err = 0; tu = file->private_data; @@ -1911,7 +1936,7 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer, if ((file->f_flags & O_NONBLOCK) != 0 || result > 0) { err = -EAGAIN; - break; + goto _error; } set_current_state(TASK_INTERRUPTIBLE); @@ -1926,42 +1951,37 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer, if (tu->disconnected) { err = -ENODEV; - break; + goto _error; } if (signal_pending(current)) { err = -ERESTARTSYS; - break; + goto _error; } } + qhead = tu->qhead++; + tu->qhead %= tu->queue_size; spin_unlock_irq(&tu->qlock); - if (err < 0) - goto _error; if (tu->tread) { - if (copy_to_user(buffer, &tu->tqueue[tu->qhead++], - sizeof(struct snd_timer_tread))) { + if (copy_to_user(buffer, &tu->tqueue[qhead], + sizeof(struct snd_timer_tread))) err = -EFAULT; - goto _error; - } } else { - if (copy_to_user(buffer, &tu->queue[tu->qhead++], - sizeof(struct snd_timer_read))) { + if (copy_to_user(buffer, &tu->queue[qhead], + sizeof(struct snd_timer_read))) err = -EFAULT; - goto _error; - } } - tu->qhead %= tu->queue_size; - - result += unit; - buffer += unit; - spin_lock_irq(&tu->qlock); tu->qused--; + if (err < 0) + goto _error; + result += unit; + buffer += unit; } - spin_unlock_irq(&tu->qlock); _error: + spin_unlock_irq(&tu->qlock); return result > 0 ? result : err; } diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index 016e451ed..a9f7a7570 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c @@ -109,6 +109,9 @@ struct dummy_timer_ops { snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *); }; +#define get_dummy_ops(substream) \ + (*(const struct dummy_timer_ops **)(substream)->runtime->private_data) + struct dummy_model { const char *name; int (*playback_constraints)(struct snd_pcm_runtime *runtime); @@ -137,7 +140,6 @@ struct snd_dummy { int iobox; struct snd_kcontrol *cd_volume_ctl; struct snd_kcontrol *cd_switch_ctl; - const struct dummy_timer_ops *timer_ops; }; /* @@ -231,6 +233,8 @@ static struct dummy_model *dummy_models[] = { */ struct dummy_systimer_pcm { + /* ops must be the first item */ + const struct dummy_timer_ops *timer_ops; spinlock_t lock; struct timer_list timer; unsigned long base_time; @@ -366,6 +370,8 @@ static struct dummy_timer_ops dummy_systimer_ops = { */ struct dummy_hrtimer_pcm { + /* ops must be the first item */ + const struct dummy_timer_ops *timer_ops; ktime_t base_time; ktime_t period_time; atomic_t running; @@ -492,31 +498,25 @@ static struct dummy_timer_ops dummy_hrtimer_ops = { static int dummy_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { - struct snd_dummy *dummy = snd_pcm_substream_chip(substream); - switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: - return dummy->timer_ops->start(substream); + return get_dummy_ops(substream)->start(substream); case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: - return dummy->timer_ops->stop(substream); + return get_dummy_ops(substream)->stop(substream); } return -EINVAL; } static int dummy_pcm_prepare(struct snd_pcm_substream *substream) { - struct snd_dummy *dummy = snd_pcm_substream_chip(substream); - - return dummy->timer_ops->prepare(substream); + return get_dummy_ops(substream)->prepare(substream); } static snd_pcm_uframes_t dummy_pcm_pointer(struct snd_pcm_substream *substream) { - struct snd_dummy *dummy = snd_pcm_substream_chip(substream); - - return dummy->timer_ops->pointer(substream); + return get_dummy_ops(substream)->pointer(substream); } static struct snd_pcm_hardware dummy_pcm_hardware = { @@ -562,17 +562,19 @@ static int dummy_pcm_open(struct snd_pcm_substream *substream) struct snd_dummy *dummy = snd_pcm_substream_chip(substream); struct dummy_model *model = dummy->model; struct snd_pcm_runtime *runtime = substream->runtime; + const struct dummy_timer_ops *ops; int err; - dummy->timer_ops = &dummy_systimer_ops; + ops = &dummy_systimer_ops; #ifdef CONFIG_HIGH_RES_TIMERS if (hrtimer) - dummy->timer_ops = &dummy_hrtimer_ops; + ops = &dummy_hrtimer_ops; #endif - err = dummy->timer_ops->create(substream); + err = ops->create(substream); if (err < 0) return err; + get_dummy_ops(substream) = ops; runtime->hw = dummy->pcm_hw; if (substream->pcm->device & 1) { @@ -594,7 +596,7 @@ static int dummy_pcm_open(struct snd_pcm_substream *substream) err = model->capture_constraints(substream->runtime); } if (err < 0) { - dummy->timer_ops->free(substream); + get_dummy_ops(substream)->free(substream); return err; } return 0; @@ -602,8 +604,7 @@ static int dummy_pcm_open(struct snd_pcm_substream *substream) static int dummy_pcm_close(struct snd_pcm_substream *substream) { - struct snd_dummy *dummy = snd_pcm_substream_chip(substream); - dummy->timer_ops->free(substream); + get_dummy_ops(substream)->free(substream); return 0; } diff --git a/sound/firewire/bebob/bebob_stream.c b/sound/firewire/bebob/bebob_stream.c index 926e5dcbb..5022c9b97 100644 --- a/sound/firewire/bebob/bebob_stream.c +++ b/sound/firewire/bebob/bebob_stream.c @@ -47,14 +47,16 @@ static const unsigned int bridgeco_freq_table[] = { [6] = 0x07, }; -static unsigned int -get_formation_index(unsigned int rate) +static int +get_formation_index(unsigned int rate, unsigned int *index) { unsigned int i; for (i = 0; i < ARRAY_SIZE(snd_bebob_rate_table); i++) { - if (snd_bebob_rate_table[i] == rate) - return i; + if (snd_bebob_rate_table[i] == rate) { + *index = i; + return 0; + } } return -EINVAL; } @@ -425,7 +427,9 @@ make_both_connections(struct snd_bebob *bebob, unsigned int rate) goto end; /* confirm params for both streams */ - index = get_formation_index(rate); + err = get_formation_index(rate, &index); + if (err < 0) + goto end; pcm_channels = bebob->tx_stream_formations[index].pcm; midi_channels = bebob->tx_stream_formations[index].midi; err = amdtp_am824_set_parameters(&bebob->tx_stream, rate, diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index 403050a1c..b3e1db976 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig @@ -3,6 +3,7 @@ config SND_WSS_LIB tristate select SND_PCM + select SND_TIMER config SND_SB_COMMON tristate @@ -42,6 +43,7 @@ config SND_AD1816A select SND_OPL3_LIB select SND_MPU401_UART select SND_PCM + select SND_TIMER help Say Y here to include support for Analog Devices SoundPort AD1816A or compatible sound chips. @@ -209,6 +211,7 @@ config SND_GUSCLASSIC tristate "Gravis UltraSound Classic" select SND_RAWMIDI select SND_PCM + select SND_TIMER help Say Y here to include support for Gravis UltraSound Classic soundcards. @@ -221,6 +224,7 @@ config SND_GUSEXTREME select SND_OPL3_LIB select SND_MPU401_UART select SND_PCM + select SND_TIMER help Say Y here to include support for Gravis UltraSound Extreme soundcards. diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 656ce39bd..8f6594a7d 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -155,6 +155,7 @@ config SND_AZT3328 select SND_PCM select SND_RAWMIDI select SND_AC97_CODEC + select SND_TIMER depends on ZONE_DMA help Say Y here to include support for Aztech AZF3328 (PCI168) @@ -463,6 +464,7 @@ config SND_EMU10K1 select SND_HWDEP select SND_RAWMIDI select SND_AC97_CODEC + select SND_TIMER depends on ZONE_DMA help Say Y to include support for Sound Blaster PCI 512, Live!, @@ -889,6 +891,7 @@ config SND_YMFPCI select SND_OPL3_LIB select SND_MPU401_UART select SND_AC97_CODEC + select SND_TIMER help Say Y here to include support for Yamaha PCI audio chips - YMF724, YMF724F, YMF740, YMF740C, YMF744, YMF754. diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index c6e8a651c..5c4fa8eba 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -771,9 +771,6 @@ static void activate_amp(struct hda_codec *codec, hda_nid_t nid, int dir, unsigned int caps; unsigned int mask, val; - if (!enable && is_active_nid(codec, nid, dir, idx_to_check)) - return; - caps = query_amp_caps(codec, nid, dir); val = get_amp_val_to_activate(codec, nid, dir, caps, enable); mask = get_amp_mask_to_modify(codec, nid, dir, idx_to_check, caps); @@ -784,12 +781,22 @@ static void activate_amp(struct hda_codec *codec, hda_nid_t nid, int dir, update_amp(codec, nid, dir, idx, mask, val); } +static void check_and_activate_amp(struct hda_codec *codec, hda_nid_t nid, + int dir, int idx, int idx_to_check, + bool enable) +{ + /* check whether the given amp is still used by others */ + if (!enable && is_active_nid(codec, nid, dir, idx_to_check)) + return; + activate_amp(codec, nid, dir, idx, idx_to_check, enable); +} + static void activate_amp_out(struct hda_codec *codec, struct nid_path *path, int i, bool enable) { hda_nid_t nid = path->path[i]; init_amp(codec, nid, HDA_OUTPUT, 0); - activate_amp(codec, nid, HDA_OUTPUT, 0, 0, enable); + check_and_activate_amp(codec, nid, HDA_OUTPUT, 0, 0, enable); } static void activate_amp_in(struct hda_codec *codec, struct nid_path *path, @@ -817,9 +824,16 @@ static void activate_amp_in(struct hda_codec *codec, struct nid_path *path, * when aa-mixer is available, we need to enable the path as well */ for (n = 0; n < nums; n++) { - if (n != idx && (!add_aamix || conn[n] != spec->mixer_merge_nid)) - continue; - activate_amp(codec, nid, HDA_INPUT, n, idx, enable); + if (n != idx) { + if (conn[n] != spec->mixer_merge_nid) + continue; + /* when aamix is disabled, force to off */ + if (!add_aamix) { + activate_amp(codec, nid, HDA_INPUT, n, n, false); + continue; + } + } + check_and_activate_amp(codec, nid, HDA_INPUT, n, idx, enable); } } @@ -1580,6 +1594,12 @@ static bool map_singles(struct hda_codec *codec, int outs, return found; } +static inline bool has_aamix_out_paths(struct hda_gen_spec *spec) +{ + return spec->aamix_out_paths[0] || spec->aamix_out_paths[1] || + spec->aamix_out_paths[2]; +} + /* create a new path including aamix if available, and return its index */ static int check_aamix_out_path(struct hda_codec *codec, int path_idx) { @@ -2422,25 +2442,51 @@ static void update_aamix_paths(struct hda_codec *codec, bool do_mix, } } +/* re-initialize the output paths; only called from loopback_mixing_put() */ +static void update_output_paths(struct hda_codec *codec, int num_outs, + const int *paths) +{ + struct hda_gen_spec *spec = codec->spec; + struct nid_path *path; + int i; + + for (i = 0; i < num_outs; i++) { + path = snd_hda_get_path_from_idx(codec, paths[i]); + if (path) + snd_hda_activate_path(codec, path, path->active, + spec->aamix_mode); + } +} + static int loopback_mixing_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct hda_gen_spec *spec = codec->spec; + const struct auto_pin_cfg *cfg = &spec->autocfg; unsigned int val = ucontrol->value.enumerated.item[0]; if (val == spec->aamix_mode) return 0; spec->aamix_mode = val; - update_aamix_paths(codec, val, spec->out_paths[0], - spec->aamix_out_paths[0], - spec->autocfg.line_out_type); - update_aamix_paths(codec, val, spec->hp_paths[0], - spec->aamix_out_paths[1], - AUTO_PIN_HP_OUT); - update_aamix_paths(codec, val, spec->speaker_paths[0], - spec->aamix_out_paths[2], - AUTO_PIN_SPEAKER_OUT); + if (has_aamix_out_paths(spec)) { + update_aamix_paths(codec, val, spec->out_paths[0], + spec->aamix_out_paths[0], + cfg->line_out_type); + update_aamix_paths(codec, val, spec->hp_paths[0], + spec->aamix_out_paths[1], + AUTO_PIN_HP_OUT); + update_aamix_paths(codec, val, spec->speaker_paths[0], + spec->aamix_out_paths[2], + AUTO_PIN_SPEAKER_OUT); + } else { + update_output_paths(codec, cfg->line_outs, spec->out_paths); + if (cfg->line_out_type != AUTO_PIN_HP_OUT) + update_output_paths(codec, cfg->hp_outs, spec->hp_paths); + if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) + update_output_paths(codec, cfg->speaker_outs, + spec->speaker_paths); + } return 1; } @@ -2458,12 +2504,13 @@ static int create_loopback_mixing_ctl(struct hda_codec *codec) if (!spec->mixer_nid) return 0; - if (!(spec->aamix_out_paths[0] || spec->aamix_out_paths[1] || - spec->aamix_out_paths[2])) - return 0; if (!snd_hda_gen_add_kctl(spec, NULL, &loopback_mixing_enum)) return -ENOMEM; spec->have_aamix_ctl = 1; + /* if no explicit aamix path is present (e.g. for Realtek codecs), + * enable aamix as default -- just for compatibility + */ + spec->aamix_mode = !has_aamix_out_paths(spec); return 0; } @@ -3998,9 +4045,9 @@ static void pin_power_callback(struct hda_codec *codec, struct hda_jack_callback *jack, bool on) { - if (jack && jack->tbl->nid) + if (jack && jack->nid) sync_power_state_change(codec, - set_pin_power_jack(codec, jack->tbl->nid, on)); + set_pin_power_jack(codec, jack->nid, on)); } /* callback only doing power up -- called at first */ @@ -5664,6 +5711,8 @@ static void init_aamix_paths(struct hda_codec *codec) if (!spec->have_aamix_ctl) return; + if (!has_aamix_out_paths(spec)) + return; update_aamix_paths(codec, spec->aamix_mode, spec->out_paths[0], spec->aamix_out_paths[0], spec->autocfg.line_out_type); diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 614baff1f..02a86ba5b 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -90,6 +90,8 @@ enum { #define NVIDIA_HDA_ENABLE_COHBIT 0x01 /* Defines for Intel SCH HDA snoop control */ +#define INTEL_HDA_CGCTL 0x48 +#define INTEL_HDA_CGCTL_MISCBDCGE (0x1 << 6) #define INTEL_SCH_HDA_DEVC 0x78 #define INTEL_SCH_HDA_DEVC_NOSNOOP (0x1<<11) @@ -528,10 +530,21 @@ static void hda_intel_init_chip(struct azx *chip, bool full_reset) { struct hdac_bus *bus = azx_bus(chip); struct pci_dev *pci = chip->pci; + u32 val; if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) snd_hdac_set_codec_wakeup(bus, true); + if (IS_BROXTON(pci)) { + pci_read_config_dword(pci, INTEL_HDA_CGCTL, &val); + val = val & ~INTEL_HDA_CGCTL_MISCBDCGE; + pci_write_config_dword(pci, INTEL_HDA_CGCTL, val); + } azx_init_chip(chip, full_reset); + if (IS_BROXTON(pci)) { + pci_read_config_dword(pci, INTEL_HDA_CGCTL, &val); + val = val | INTEL_HDA_CGCTL_MISCBDCGE; + pci_write_config_dword(pci, INTEL_HDA_CGCTL, val); + } if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) snd_hdac_set_codec_wakeup(bus, false); diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c index c945e257d..a33234e04 100644 --- a/sound/pci/hda/hda_jack.c +++ b/sound/pci/hda/hda_jack.c @@ -259,7 +259,7 @@ snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid, if (!callback) return ERR_PTR(-ENOMEM); callback->func = func; - callback->tbl = jack; + callback->nid = jack->nid; callback->next = jack->callback; jack->callback = callback; } diff --git a/sound/pci/hda/hda_jack.h b/sound/pci/hda/hda_jack.h index 858708a04..e9814c016 100644 --- a/sound/pci/hda/hda_jack.h +++ b/sound/pci/hda/hda_jack.h @@ -21,7 +21,7 @@ struct hda_jack_callback; typedef void (*hda_jack_callback_fn) (struct hda_codec *, struct hda_jack_callback *); struct hda_jack_callback { - struct hda_jack_tbl *tbl; + hda_nid_t nid; hda_jack_callback_fn func; unsigned int private_data; /* arbitrary data */ struct hda_jack_callback *next; diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 89f48a987..8080bfd82 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -4427,13 +4427,16 @@ static void ca0132_process_dsp_response(struct hda_codec *codec, static void hp_callback(struct hda_codec *codec, struct hda_jack_callback *cb) { struct ca0132_spec *spec = codec->spec; + struct hda_jack_tbl *tbl; /* Delay enabling the HP amp, to let the mic-detection * state machine run. */ cancel_delayed_work_sync(&spec->unsol_hp_work); schedule_delayed_work(&spec->unsol_hp_work, msecs_to_jiffies(500)); - cb->tbl->block_report = 1; + tbl = snd_hda_jack_tbl_get(codec, cb->nid); + if (tbl) + tbl->block_report = 1; } static void amic_callback(struct hda_codec *codec, struct hda_jack_callback *cb) diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index a12ae8ac0..c1c855a6c 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -614,6 +614,7 @@ enum { CS4208_MAC_AUTO, CS4208_MBA6, CS4208_MBP11, + CS4208_MACMINI, CS4208_GPIO0, }; @@ -621,6 +622,7 @@ static const struct hda_model_fixup cs4208_models[] = { { .id = CS4208_GPIO0, .name = "gpio0" }, { .id = CS4208_MBA6, .name = "mba6" }, { .id = CS4208_MBP11, .name = "mbp11" }, + { .id = CS4208_MACMINI, .name = "macmini" }, {} }; @@ -632,6 +634,7 @@ static const struct snd_pci_quirk cs4208_fixup_tbl[] = { /* codec SSID matching */ static const struct snd_pci_quirk cs4208_mac_fixup_tbl[] = { SND_PCI_QUIRK(0x106b, 0x5e00, "MacBookPro 11,2", CS4208_MBP11), + SND_PCI_QUIRK(0x106b, 0x6c00, "MacMini 7,1", CS4208_MACMINI), SND_PCI_QUIRK(0x106b, 0x7100, "MacBookAir 6,1", CS4208_MBA6), SND_PCI_QUIRK(0x106b, 0x7200, "MacBookAir 6,2", CS4208_MBA6), SND_PCI_QUIRK(0x106b, 0x7b00, "MacBookPro 12,1", CS4208_MBP11), @@ -666,6 +669,24 @@ static void cs4208_fixup_mac(struct hda_codec *codec, snd_hda_apply_fixup(codec, action); } +/* MacMini 7,1 has the inverted jack detection */ +static void cs4208_fixup_macmini(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + static const struct hda_pintbl pincfgs[] = { + { 0x18, 0x00ab9150 }, /* mic (audio-in) jack: disable detect */ + { 0x21, 0x004be140 }, /* SPDIF: disable detect */ + { } + }; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + /* HP pin (0x10) has an inverted detection */ + codec->inv_jack_detect = 1; + /* disable the bogus Mic and SPDIF jack detections */ + snd_hda_apply_pincfgs(codec, pincfgs); + } +} + static int cs4208_spdif_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -709,6 +730,12 @@ static const struct hda_fixup cs4208_fixups[] = { .chained = true, .chain_id = CS4208_GPIO0, }, + [CS4208_MACMINI] = { + .type = HDA_FIXUP_FUNC, + .v.func = cs4208_fixup_macmini, + .chained = true, + .chain_id = CS4208_GPIO0, + }, [CS4208_GPIO0] = { .type = HDA_FIXUP_FUNC, .v.func = cs4208_fixup_gpio0, diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 4b6fb668c..70c945603 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -438,7 +438,8 @@ static int hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol, eld = &per_pin->sink_eld; mutex_lock(&per_pin->lock); - if (eld->eld_size > ARRAY_SIZE(ucontrol->value.bytes.data)) { + if (eld->eld_size > ARRAY_SIZE(ucontrol->value.bytes.data) || + eld->eld_size > ELD_MAX_SIZE) { mutex_unlock(&per_pin->lock); snd_BUG(); return -EINVAL; @@ -1183,7 +1184,7 @@ static void check_presence_and_report(struct hda_codec *codec, hda_nid_t nid) static void jack_callback(struct hda_codec *codec, struct hda_jack_callback *jack) { - check_presence_and_report(codec, jack->tbl->nid); + check_presence_and_report(codec, jack->nid); } static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 33753244f..efd4980cf 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -282,7 +282,7 @@ static void alc_update_knob_master(struct hda_codec *codec, uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); if (!uctl) return; - val = snd_hda_codec_read(codec, jack->tbl->nid, 0, + val = snd_hda_codec_read(codec, jack->nid, 0, AC_VERB_GET_VOLUME_KNOB_CONTROL, 0); val &= HDA_AMP_VOLMASK; uctl->value.integer.value[0] = val; @@ -327,6 +327,7 @@ static void alc_fill_eapd_coef(struct hda_codec *codec) case 0x10ec0292: alc_update_coef_idx(codec, 0x4, 1<<15, 0); break; + case 0x10ec0225: case 0x10ec0233: case 0x10ec0255: case 0x10ec0256: @@ -900,6 +901,7 @@ static struct alc_codec_rename_pci_table rename_pci_tbl[] = { { 0x10ec0899, 0x1028, 0, "ALC3861" }, { 0x10ec0298, 0x1028, 0, "ALC3266" }, { 0x10ec0256, 0x1028, 0, "ALC3246" }, + { 0x10ec0225, 0x1028, 0, "ALC3253" }, { 0x10ec0670, 0x1025, 0, "ALC669X" }, { 0x10ec0676, 0x1025, 0, "ALC679X" }, { 0x10ec0282, 0x1043, 0, "ALC3229" }, @@ -1785,7 +1787,6 @@ enum { ALC882_FIXUP_NO_PRIMARY_HP, ALC887_FIXUP_ASUS_BASS, ALC887_FIXUP_BASS_CHMAP, - ALC882_FIXUP_DISABLE_AAMIX, }; static void alc889_fixup_coef(struct hda_codec *codec, @@ -1947,8 +1948,6 @@ static void alc882_fixup_no_primary_hp(struct hda_codec *codec, static void alc_fixup_bass_chmap(struct hda_codec *codec, const struct hda_fixup *fix, int action); -static void alc_fixup_disable_aamix(struct hda_codec *codec, - const struct hda_fixup *fix, int action); static const struct hda_fixup alc882_fixups[] = { [ALC882_FIXUP_ABIT_AW9D_MAX] = { @@ -2186,10 +2185,6 @@ static const struct hda_fixup alc882_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_bass_chmap, }, - [ALC882_FIXUP_DISABLE_AAMIX] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc_fixup_disable_aamix, - }, }; static const struct snd_pci_quirk alc882_fixup_tbl[] = { @@ -2228,6 +2223,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC889_FIXUP_VAIO_TT), SND_PCI_QUIRK(0x104d, 0x905a, "Sony Vaio Z", ALC882_FIXUP_NO_PRIMARY_HP), SND_PCI_QUIRK(0x104d, 0x9043, "Sony Vaio VGC-LN51JGB", ALC882_FIXUP_NO_PRIMARY_HP), + SND_PCI_QUIRK(0x104d, 0x9044, "Sony VAIO AiO", ALC882_FIXUP_NO_PRIMARY_HP), /* All Apple entries are in codec SSIDs */ SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC889_FIXUP_MBP_VREF), @@ -2257,7 +2253,6 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK(0x1462, 0x7350, "MSI-7350", ALC889_FIXUP_CD), SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3), SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte EP45-DS3/Z87X-UD3H", ALC889_FIXUP_FRONT_HP_NO_PRESENCE), - SND_PCI_QUIRK(0x1458, 0xa182, "Gigabyte Z170X-UD3", ALC882_FIXUP_DISABLE_AAMIX), SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", ALC882_FIXUP_ABIT_AW9D_MAX), SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC882_FIXUP_EAPD), SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_FIXUP_EAPD), @@ -2651,6 +2646,7 @@ enum { ALC269_TYPE_ALC298, ALC269_TYPE_ALC255, ALC269_TYPE_ALC256, + ALC269_TYPE_ALC225, }; /* @@ -2680,6 +2676,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec) case ALC269_TYPE_ALC298: case ALC269_TYPE_ALC255: case ALC269_TYPE_ALC256: + case ALC269_TYPE_ALC225: ssids = alc269_ssids; break; default: @@ -3658,6 +3655,16 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec) WRITE_COEF(0xb7, 0x802b), {} }; + static struct coef_fw coef0225[] = { + UPDATE_COEF(0x4a, 1<<8, 0), + UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), + UPDATE_COEF(0x63, 3<<14, 3<<14), + UPDATE_COEF(0x4a, 3<<4, 2<<4), + UPDATE_COEF(0x4a, 3<<10, 3<<10), + UPDATE_COEF(0x45, 0x3f<<10, 0x34<<10), + UPDATE_COEF(0x4a, 3<<10, 0), + {} + }; switch (codec->core.vendor_id) { case 0x10ec0255: @@ -3682,6 +3689,9 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec) case 0x10ec0668: alc_process_coef_fw(codec, coef0668); break; + case 0x10ec0225: + alc_process_coef_fw(codec, coef0225); + break; } codec_dbg(codec, "Headset jack set to unplugged mode.\n"); } @@ -3727,6 +3737,13 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, UPDATE_COEF(0xc3, 0, 1<<12), {} }; + static struct coef_fw coef0225[] = { + UPDATE_COEFEX(0x57, 0x05, 1<<14, 1<<14), + UPDATE_COEF(0x4a, 3<<4, 2<<4), + UPDATE_COEF(0x63, 3<<14, 0), + {} + }; + switch (codec->core.vendor_id) { case 0x10ec0255: @@ -3772,6 +3789,12 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, alc_process_coef_fw(codec, coef0688); snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); break; + case 0x10ec0225: + alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x31<<10); + snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); + alc_process_coef_fw(codec, coef0225); + snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); + break; } codec_dbg(codec, "Headset jack set to mic-in mode.\n"); } @@ -3884,6 +3907,13 @@ static void alc_headset_mode_ctia(struct hda_codec *codec) WRITE_COEF(0xc3, 0x0000), {} }; + static struct coef_fw coef0225[] = { + UPDATE_COEF(0x45, 0x3f<<10, 0x35<<10), + UPDATE_COEF(0x49, 1<<8, 1<<8), + UPDATE_COEF(0x4a, 7<<6, 7<<6), + UPDATE_COEF(0x4a, 3<<4, 3<<4), + {} + }; switch (codec->core.vendor_id) { case 0x10ec0255: @@ -3912,6 +3942,9 @@ static void alc_headset_mode_ctia(struct hda_codec *codec) case 0x10ec0668: alc_process_coef_fw(codec, coef0688); break; + case 0x10ec0225: + alc_process_coef_fw(codec, coef0225); + break; } codec_dbg(codec, "Headset jack set to iPhone-style headset mode.\n"); } @@ -3955,6 +3988,13 @@ static void alc_headset_mode_omtp(struct hda_codec *codec) WRITE_COEF(0xc3, 0x0000), {} }; + static struct coef_fw coef0225[] = { + UPDATE_COEF(0x45, 0x3f<<10, 0x39<<10), + UPDATE_COEF(0x49, 1<<8, 1<<8), + UPDATE_COEF(0x4a, 7<<6, 7<<6), + UPDATE_COEF(0x4a, 3<<4, 3<<4), + {} + }; switch (codec->core.vendor_id) { case 0x10ec0255: @@ -3983,6 +4023,9 @@ static void alc_headset_mode_omtp(struct hda_codec *codec) case 0x10ec0668: alc_process_coef_fw(codec, coef0688); break; + case 0x10ec0225: + alc_process_coef_fw(codec, coef0225); + break; } codec_dbg(codec, "Headset jack set to Nokia-style headset mode.\n"); } @@ -4014,6 +4057,11 @@ static void alc_determine_headset_type(struct hda_codec *codec) WRITE_COEF(0xc3, 0x0c00), {} }; + static struct coef_fw coef0225[] = { + UPDATE_COEF(0x45, 0x3f<<10, 0x34<<10), + UPDATE_COEF(0x49, 1<<8, 1<<8), + {} + }; switch (codec->core.vendor_id) { case 0x10ec0255: @@ -4058,6 +4106,12 @@ static void alc_determine_headset_type(struct hda_codec *codec) val = alc_read_coef_idx(codec, 0xbe); is_ctia = (val & 0x1c02) == 0x1c02; break; + case 0x10ec0225: + alc_process_coef_fw(codec, coef0225); + msleep(800); + val = alc_read_coef_idx(codec, 0x46); + is_ctia = (val & 0x00f0) == 0x00f0; + break; } codec_dbg(codec, "Headset jack detected iPhone-style headset: %s\n", @@ -5560,6 +5614,9 @@ static const struct hda_model_fixup alc269_fixup_models[] = { {.id = ALC292_FIXUP_TPT440, .name = "tpt440"}, {} }; +#define ALC225_STANDARD_PINS \ + {0x12, 0xb7a60130}, \ + {0x21, 0x04211020} #define ALC256_STANDARD_PINS \ {0x12, 0x90a60140}, \ @@ -5581,6 +5638,12 @@ static const struct hda_model_fixup alc269_fixup_models[] = { {0x21, 0x03211020} static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { + SND_HDA_PIN_QUIRK(0x10ec0225, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, + ALC225_STANDARD_PINS, + {0x14, 0x901701a0}), + SND_HDA_PIN_QUIRK(0x10ec0225, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, + ALC225_STANDARD_PINS, + {0x14, 0x901701b0}), SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE, {0x14, 0x90170110}, {0x21, 0x02211020}), @@ -5906,6 +5969,9 @@ static int patch_alc269(struct hda_codec *codec) spec->gen.mixer_nid = 0; /* ALC256 does not have any loopback mixer path */ alc_update_coef_idx(codec, 0x36, 1 << 13, 1 << 5); /* Switch pcbeep path to Line in path*/ break; + case 0x10ec0225: + spec->codec_variant = ALC269_TYPE_ALC225; + break; } if (snd_hda_codec_read(codec, 0x51, 0, AC_VERB_PARAMETERS, 0) == 0x10ec5505) { @@ -6796,6 +6862,7 @@ static int patch_alc680(struct hda_codec *codec) */ static const struct hda_device_id snd_hda_id_realtek[] = { HDA_CODEC_ENTRY(0x10ec0221, "ALC221", patch_alc269), + HDA_CODEC_ENTRY(0x10ec0225, "ALC225", patch_alc269), HDA_CODEC_ENTRY(0x10ec0231, "ALC231", patch_alc269), HDA_CODEC_ENTRY(0x10ec0233, "ALC233", patch_alc269), HDA_CODEC_ENTRY(0x10ec0235, "ALC233", patch_alc269), diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 2c7c5eb8b..37b70f8e8 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -493,9 +493,9 @@ static void jack_update_power(struct hda_codec *codec, if (!spec->num_pwrs) return; - if (jack && jack->tbl->nid) { - stac_toggle_power_map(codec, jack->tbl->nid, - snd_hda_jack_detect(codec, jack->tbl->nid), + if (jack && jack->nid) { + stac_toggle_power_map(codec, jack->nid, + snd_hda_jack_detect(codec, jack->nid), true); return; } diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 3e3c7f6be..b74840b5b 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -621,7 +621,7 @@ static const struct snd_kcontrol_new rt5645_snd_controls[] = { /* IN1/IN2 Control */ SOC_SINGLE_TLV("IN1 Boost", RT5645_IN1_CTRL1, - RT5645_BST_SFT1, 8, 0, bst_tlv), + RT5645_BST_SFT1, 12, 0, bst_tlv), SOC_SINGLE_TLV("IN2 Boost", RT5645_IN2_CTRL, RT5645_BST_SFT2, 8, 0, bst_tlv), diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index c86dc96e8..65b936e25 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1743,7 +1743,8 @@ int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream) (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) && (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) && (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED) && - (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP)) + (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) && + (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND)) continue; dev_dbg(be->dev, "ASoC: hw_free BE %s\n", diff --git a/sound/sparc/Kconfig b/sound/sparc/Kconfig index d75deba56..dfcd38647 100644 --- a/sound/sparc/Kconfig +++ b/sound/sparc/Kconfig @@ -22,6 +22,7 @@ config SND_SUN_AMD7930 config SND_SUN_CS4231 tristate "Sun CS4231" select SND_PCM + select SND_TIMER help Say Y here to include support for CS4231 sound device on Sun. diff --git a/sound/usb/midi.c b/sound/usb/midi.c index 5b4c58c3e..b21b76690 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -2454,7 +2454,6 @@ int snd_usbmidi_create(struct snd_card *card, else err = snd_usbmidi_create_endpoints(umidi, endpoints); if (err < 0) { - snd_usbmidi_free(umidi); return err; } diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 23ea6d800..4f6ce1cac 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1121,6 +1121,7 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip) switch (chip->usb_id) { case USB_ID(0x045E, 0x075D): /* MS Lifecam Cinema */ case USB_ID(0x045E, 0x076D): /* MS Lifecam HD-5000 */ + case USB_ID(0x045E, 0x076F): /* MS Lifecam HD-6000 */ case USB_ID(0x045E, 0x0772): /* MS Lifecam Studio */ case USB_ID(0x045E, 0x0779): /* MS Lifecam HD-3000 */ case USB_ID(0x04D8, 0xFEEA): /* Benchmark DAC1 Pre */ @@ -1205,8 +1206,12 @@ void snd_usb_set_interface_quirk(struct usb_device *dev) * "Playback Design" products need a 50ms delay after setting the * USB interface. */ - if (le16_to_cpu(dev->descriptor.idVendor) == 0x23ba) + switch (le16_to_cpu(dev->descriptor.idVendor)) { + case 0x23ba: /* Playback Design */ + case 0x0644: /* TEAC Corp. */ mdelay(50); + break; + } } void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe, @@ -1221,6 +1226,14 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe, (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS) mdelay(20); + /* + * "TEAC Corp." products need a 20ms delay after each + * class compliant request + */ + if ((le16_to_cpu(dev->descriptor.idVendor) == 0x0644) && + (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS) + mdelay(20); + /* Marantz/Denon devices with USB DAC functionality need a delay * after each class compliant request */ @@ -1269,7 +1282,7 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, case USB_ID(0x20b1, 0x3008): /* iFi Audio micro/nano iDSD */ case USB_ID(0x20b1, 0x2008): /* Matrix Audio X-Sabre */ case USB_ID(0x20b1, 0x300a): /* Matrix Audio Mini-i Pro */ - case USB_ID(0x22d8, 0x0416): /* OPPO HA-1*/ + case USB_ID(0x22d9, 0x0416): /* OPPO HA-1 */ if (fp->altsetting == 2) return SNDRV_PCM_FMTBIT_DSD_U32_BE; break; @@ -1278,6 +1291,7 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, case USB_ID(0x20b1, 0x2009): /* DIYINHK DSD DXD 384kHz USB to I2S/DSD */ case USB_ID(0x20b1, 0x2023): /* JLsounds I2SoverUSB */ case USB_ID(0x20b1, 0x3023): /* Aune X1S 32BIT/384 DSD DAC */ + case USB_ID(0x2616, 0x0106): /* PS Audio NuWave DAC */ if (fp->altsetting == 3) return SNDRV_PCM_FMTBIT_DSD_U32_BE; break; diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index bf4ece67a..c8edff680 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -6,7 +6,6 @@ TARGETS += firmware TARGETS += ftrace TARGETS += futex TARGETS += kcmp -TARGETS += kdbus TARGETS += lib TARGETS += membarrier TARGETS += memfd diff --git a/tools/testing/selftests/kdbus/.gitignore b/tools/testing/selftests/kdbus/.gitignore deleted file mode 100644 index d3ef42f6a..000000000 --- a/tools/testing/selftests/kdbus/.gitignore +++ /dev/null @@ -1 +0,0 @@ -kdbus-test diff --git a/tools/testing/selftests/kdbus/Makefile b/tools/testing/selftests/kdbus/Makefile deleted file mode 100644 index 8f36cb566..000000000 --- a/tools/testing/selftests/kdbus/Makefile +++ /dev/null @@ -1,49 +0,0 @@ -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-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 - -include ../lib.mk - -%.o: %.c kdbus-enum.h kdbus-test.h kdbus-util.h - $(CC) $(CFLAGS) -c $< -o $@ - -kdbus-test: $(OBJS) - $(CC) $(CFLAGS) $^ $(LDLIBS) -o $@ - -TEST_PROGS := kdbus-test - -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 deleted file mode 100644 index 4f1e57978..000000000 --- a/tools/testing/selftests/kdbus/kdbus-enum.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 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 deleted file mode 100644 index ed28cca26..000000000 --- a/tools/testing/selftests/kdbus/kdbus-enum.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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 deleted file mode 100644 index db5738157..000000000 --- a/tools/testing/selftests/kdbus/kdbus-test.c +++ /dev/null @@ -1,905 +0,0 @@ -#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; -}; - -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 = "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, - .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, - }, -}; - -#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, &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; - - 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; - static char fspath[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; - } - - /* 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 deleted file mode 100644 index ee937f9a8..000000000 --- a/tools/testing/selftests/kdbus/kdbus-test.h +++ /dev/null @@ -1,84 +0,0 @@ -#ifndef _TEST_KDBUS_H_ -#define _TEST_KDBUS_H_ - -struct kdbus_test_env { - char *buspath; - const char *root; - const char *module; - 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_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_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); -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 deleted file mode 100644 index 82fa89b1a..000000000 --- a/tools/testing/selftests/kdbus/kdbus-util.c +++ /dev/null @@ -1,1612 +0,0 @@ -/* - * 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 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; - - /* owner metadata items */ - struct { - uint64_t size; - uint64_t type; - uint64_t flags; - } attach; - - /* 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.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 + - 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.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; - - fd = syscall(__NR_memfd_create, name, MFD_ALLOW_SEALING); - if (fd < 0) - return fd; - - 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 = NULL; - struct kdbus_msg *msg = NULL; - 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) + 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; - 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"); - goto out; - } - - ret = sys_memfd_seal_set(memfd); - if (ret < 0) { - ret = -errno; - kdbus_printf("memfd sealing failed: %m\n"); - goto out; - } - - 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"); - goto out; - } - - 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) - goto out; - - 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); - 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; - - 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 (ret < 0) { - kdbus_printf("error sending message: %d (%m)\n", ret); - goto out; - } - - 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) - goto out; - } - -out: - free(msg); - free(cmd); - - if (memfd >= 0) - close(memfd); - - return ret < 0 ? ret : 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(void) -{ - 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 (!caps) { - 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 deleted file mode 100644 index e1e18b92f..000000000 --- a/tools/testing/selftests/kdbus/kdbus-util.h +++ /dev/null @@ -1,218 +0,0 @@ -/* - * 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 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(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 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 deleted file mode 100644 index c576a30ad..000000000 --- a/tools/testing/selftests/kdbus/test-activator.c +++ /dev/null @@ -1,321 +0,0 @@ -#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; - 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, ({ - 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); - - /* 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, ({ - flags = KDBUS_NAME_REPLACE_EXISTING; - 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-benchmark.c b/tools/testing/selftests/kdbus/test-benchmark.c deleted file mode 100644 index 8a9744b00..000000000 --- a/tools/testing/selftests/kdbus/test-benchmark.c +++ /dev/null @@ -1,451 +0,0 @@ -#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 deleted file mode 100644 index 762fb3039..000000000 --- a/tools/testing/selftests/kdbus/test-bus.c +++ /dev/null @@ -1,175 +0,0 @@ -#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 deleted file mode 100644 index 41e5b53fe..000000000 --- a/tools/testing/selftests/kdbus/test-chat.c +++ /dev/null @@ -1,124 +0,0 @@ -#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); - - 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); - - 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 deleted file mode 100644 index 4688ce8ec..000000000 --- a/tools/testing/selftests/kdbus/test-connection.c +++ /dev/null @@ -1,597 +0,0 @@ -#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; - - 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; - struct kdbus_info *info; - struct kdbus_conn *conn; - struct kdbus_conn *privileged; - const struct kdbus_item *item; - 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_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 & 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 & 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 & 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 & 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 & 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 & 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 & 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 & 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 & 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 & KDBUS_ATTACH_CGROUP) { - ASSERT_EXIT(cnt == 1); - } else { - ASSERT_EXIT(cnt == 0); - } - - cnt = kdbus_count_item(info, KDBUS_ITEM_CAPS); - if (invalid_flags & 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 & 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 deleted file mode 100644 index 8bc238619..000000000 --- a/tools/testing/selftests/kdbus/test-daemon.c +++ /dev/null @@ -1,65 +0,0 @@ -#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 deleted file mode 100644 index 34a7be49c..000000000 --- a/tools/testing/selftests/kdbus/test-endpoint.c +++ /dev/null @@ -1,352 +0,0 @@ -#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); - - /* 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 - * 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 the name notification */ - 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); - - /* 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); - - 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 deleted file mode 100644 index 2ae0f5ae8..000000000 --- a/tools/testing/selftests/kdbus/test-fd.c +++ /dev/null @@ -1,789 +0,0 @@ -#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 deleted file mode 100644 index f666da3e8..000000000 --- a/tools/testing/selftests/kdbus/test-free.c +++ /dev/null @@ -1,64 +0,0 @@ -#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 deleted file mode 100644 index 2360dc1d7..000000000 --- a/tools/testing/selftests/kdbus/test-match.c +++ /dev/null @@ -1,441 +0,0 @@ -#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 deleted file mode 100644 index 33d349bb2..000000000 --- a/tools/testing/selftests/kdbus/test-message.c +++ /dev/null @@ -1,736 +0,0 @@ -#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 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); - 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 == -EBADSLT); - - 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; - 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 */ - flags = KDBUS_NAME_REPLACE_EXISTING; - 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 */ - flags = KDBUS_NAME_REPLACE_EXISTING; - 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 deleted file mode 100644 index 1f6edc090..000000000 --- a/tools/testing/selftests/kdbus/test-metadata-ns.c +++ /dev/null @@ -1,500 +0,0 @@ -/* - * 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); - - item = kdbus_get_item(msg, KDBUS_ITEM_CAPS); - ASSERT_EXIT(item); - - /* 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); - - item = kdbus_get_item(msg, KDBUS_ITEM_CAPS); - ASSERT_EXIT(item); - - /* 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, status, efd; - pid_t pid, ppid; - 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; - - 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; - - item = kdbus_get_item(msg, KDBUS_ITEM_CAPS); - ASSERT_RETURN(item); - - /* - * 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 deleted file mode 100644 index e00d738a3..000000000 --- a/tools/testing/selftests/kdbus/test-monitor.c +++ /dev/null @@ -1,176 +0,0 @@ -#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 deleted file mode 100644 index e400dc86a..000000000 --- a/tools/testing/selftests/kdbus/test-names.c +++ /dev/null @@ -1,272 +0,0 @@ -#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" - -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 = {}; - struct kdbus_info *name, *list; - unsigned int i; - int ret; - - 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); - - 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; - - 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) - return false; - } - - 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 conn_test_names(conn, &t, 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_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_primary_owner(env->conn, name); - ASSERT_RETURN(ret == false); - - /* 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_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); - 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; - struct test_name t[2]; - const char *name; - uint64_t flags; - int ret; - - name = "foo.bla.blaz"; - - flags = 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 */ - /* acquire name from the 1st connection */ - ret = kdbus_name_acquire(env->conn, name, &flags); - 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; - ret = kdbus_name_acquire(conn, name, &flags); - 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 */ - 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; -} diff --git a/tools/testing/selftests/kdbus/test-policy-ns.c b/tools/testing/selftests/kdbus/test-policy-ns.c deleted file mode 100644 index 3437012f9..000000000 --- a/tools/testing/selftests/kdbus/test-policy-ns.c +++ /dev/null @@ -1,632 +0,0 @@ -/* - * 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 deleted file mode 100644 index 0208638a7..000000000 --- a/tools/testing/selftests/kdbus/test-policy-priv.c +++ /dev/null @@ -1,1285 +0,0 @@ -#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); - - /* 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); - 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); - - /* 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); - 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. - */ - - /* 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_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); - - /* 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 deleted file mode 100644 index 96d20d5e9..000000000 --- a/tools/testing/selftests/kdbus/test-policy.c +++ /dev/null @@ -1,80 +0,0 @@ -#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 deleted file mode 100644 index 0655a545f..000000000 --- a/tools/testing/selftests/kdbus/test-sync.c +++ /dev/null @@ -1,369 +0,0 @@ -#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 != -EBADSLT) { - 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 deleted file mode 100644 index cfd193066..000000000 --- a/tools/testing/selftests/kdbus/test-timeout.c +++ /dev/null @@ -1,99 +0,0 @@ -#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; -} |