diff options
author | Josh Boyer <jwboyer@fedoraproject.org> | 2015-07-15 09:11:25 -0400 |
---|---|---|
committer | Josh Boyer <jwboyer@fedoraproject.org> | 2015-07-15 09:11:25 -0400 |
commit | 2079802473df0b249968a32467dbf43f2076fa87 (patch) | |
tree | 98ea883873e77b19dd7a2ddc7d8944a4c3d6d009 /kdbus.patch | |
parent | c3a494ca7b138539d5e74d2d0ab894dccae9bcfe (diff) | |
download | kernel-2079802473df0b249968a32467dbf43f2076fa87.tar.gz kernel-2079802473df0b249968a32467dbf43f2076fa87.tar.xz kernel-2079802473df0b249968a32467dbf43f2076fa87.zip |
Update kdbus to latest upstream kdbus-next
Grab the larger rework and fixes from David Herrmann (up to commit
eee8b5b3ceaeca1b1b998552cd6c9f9dea8938e5)
Diffstat (limited to 'kdbus.patch')
-rw-r--r-- | kdbus.patch | 8579 |
1 files changed, 8579 insertions, 0 deletions
diff --git a/kdbus.patch b/kdbus.patch index 896819d9c..a37878c26 100644 --- a/kdbus.patch +++ b/kdbus.patch @@ -40479,3 +40479,8582 @@ index 707be05..9993753 100644 } -- 2.4.3 +From 7d894da303164a38522eaac6e95ee558423b9272 Mon Sep 17 00:00:00 2001 +From: Markus Elfring <elfring@users.sourceforge.net> +Date: Wed, 24 Jun 2015 14:30:17 +0200 +Subject: [PATCH 01/34] kdbus: delete unnecessary check before + kdbus_domain_unref + +The kdbus_domain_unref() function tests whether its argument is NULL +and then returns immediately. Thus the test around the call is not needed. + +This issue was detected by using the Coccinelle software. + +Signed-off-by: Markus Elfring <elfring@users.sourceforge.net> +Reviewed-by: David Herrmann <dh.herrmann@gmail.com> +(shorten commit-message-head slightly) +Signed-off-by: David Herrmann <dh.herrmann@gmail.com> +--- + ipc/kdbus/fs.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/ipc/kdbus/fs.c b/ipc/kdbus/fs.c +index d01f33baaa0d..205a3adaa2ab 100644 +--- a/ipc/kdbus/fs.c ++++ b/ipc/kdbus/fs.c +@@ -325,9 +325,7 @@ static void fs_super_kill(struct super_block *sb) + } + + kill_anon_super(sb); +- +- if (domain) +- kdbus_domain_unref(domain); ++ kdbus_domain_unref(domain); + } + + static int fs_super_set(struct super_block *sb, void *data) +-- +2.4.3 + + +From b57a271a7a2c5bac0fdfa848481bca55dc1d1336 Mon Sep 17 00:00:00 2001 +From: Sergei Zviagintsev <sergei@s15v.net> +Date: Sun, 28 Jun 2015 16:17:30 +0300 +Subject: [PATCH 02/34] kdbus: fix typos in kdbus_conn_quota_inc() + +Signed-off-by: Sergei Zviagintsev <sergei@s15v.net> +Reviewed-by: David Herrmann <dh.herrmann@gmail.com> +Signed-off-by: David Herrmann <dh.herrmann@gmail.com> +--- + ipc/kdbus/connection.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c +index 9993753d11de..df072487e23c 100644 +--- a/ipc/kdbus/connection.c ++++ b/ipc/kdbus/connection.c +@@ -646,7 +646,7 @@ int kdbus_conn_quota_inc(struct kdbus_conn *c, struct kdbus_user *u, + * allocation schemes. Furthermore, resource utilization should be + * maximized, so only minimal resources stay reserved. However, we need + * to adapt to a dynamic number of users, as we cannot know how many +- * users will talk to a connection. Therefore, the current allocations ++ * users will talk to a connection. Therefore, the current allocation + * works like this: + * We limit the number of bytes in a destination's pool per sending + * user. The space available for a user is 33% of the unused pool space +@@ -688,7 +688,7 @@ int kdbus_conn_quota_inc(struct kdbus_conn *c, struct kdbus_user *u, + + /* + * Pool owner slices are un-accounted slices; they can claim more +- * than 50% of the queue. However, the slice we're dealing with here ++ * than 50% of the queue. However, the slices we're dealing with here + * belong to the incoming queue, hence they are 'accounted' slices + * to which the 50%-limit applies. + */ +-- +2.4.3 + + +From c1bddc44862c977384e66aea1d2be7ded9fb0f0e Mon Sep 17 00:00:00 2001 +From: Sergei Zviagintsev <sergei@s15v.net> +Date: Sun, 28 Jun 2015 16:17:31 +0300 +Subject: [PATCH 03/34] kdbus: use standard kernel types in struct kdbus_quota + +uint{8,16,32}_t -> u{8,16,32} + +Signed-off-by: Sergei Zviagintsev <sergei@s15v.net> +Reviewed-by: David Herrmann <dh.herrmann@gmail.com> +Signed-off-by: David Herrmann <dh.herrmann@gmail.com> +--- + ipc/kdbus/connection.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c +index df072487e23c..af044f93c14f 100644 +--- a/ipc/kdbus/connection.c ++++ b/ipc/kdbus/connection.c +@@ -606,9 +606,9 @@ bool kdbus_conn_has_name(struct kdbus_conn *conn, const char *name) + } + + struct kdbus_quota { +- uint32_t memory; +- uint16_t msgs; +- uint8_t fds; ++ u32 memory; ++ u16 msgs; ++ u8 fds; + }; + + /** +-- +2.4.3 + + +From eb526cf227f121c8320275dde32d18495631a622 Mon Sep 17 00:00:00 2001 +From: David Herrmann <dh.herrmann@gmail.com> +Date: Tue, 9 Jun 2015 09:41:40 +0200 +Subject: [PATCH 04/34] kdbus/selftests: fix CAP translation tests + +We now support CAP translations. Make sure our tests reflect that. So far +they made sure we drop CAPS on namespace borders. This is wrong, though. +We really need to just make sure that no _or_ the correctly translated +caps are returned. Fix this. + +Signed-off-by: David Herrmann <dh.herrmann@gmail.com> +--- + tools/testing/selftests/kdbus/test-metadata-ns.c | 9 +++------ + 1 file changed, 3 insertions(+), 6 deletions(-) + +diff --git a/tools/testing/selftests/kdbus/test-metadata-ns.c b/tools/testing/selftests/kdbus/test-metadata-ns.c +index ccdfae06922b..1f6edc09008a 100644 +--- a/tools/testing/selftests/kdbus/test-metadata-ns.c ++++ b/tools/testing/selftests/kdbus/test-metadata-ns.c +@@ -168,9 +168,8 @@ static int __kdbus_clone_userns_test(const char *bus, + ASSERT_EXIT(ret == 0); + ASSERT_EXIT(msg->dst_id == userns_conn->id); + +- /* Different namespaces no CAPS */ + item = kdbus_get_item(msg, KDBUS_ITEM_CAPS); +- ASSERT_EXIT(item == NULL); ++ ASSERT_EXIT(item); + + /* uid/gid not mapped, so we have unpriv cached creds */ + ret = kdbus_match_kdbus_creds(msg, &unmapped_creds); +@@ -196,9 +195,8 @@ static int __kdbus_clone_userns_test(const char *bus, + ASSERT_EXIT(ret == 0); + ASSERT_EXIT(msg->dst_id == KDBUS_DST_ID_BROADCAST); + +- /* Different namespaces no CAPS */ + item = kdbus_get_item(msg, KDBUS_ITEM_CAPS); +- ASSERT_EXIT(item == NULL); ++ ASSERT_EXIT(item); + + /* uid/gid not mapped, so we have unpriv cached creds */ + ret = kdbus_match_kdbus_creds(msg, &unmapped_creds); +@@ -358,9 +356,8 @@ static int kdbus_clone_userns_test(const char *bus, + + userns_conn_id = msg->src_id; + +- /* We do not share the userns, os no KDBUS_ITEM_CAPS */ + item = kdbus_get_item(msg, KDBUS_ITEM_CAPS); +- ASSERT_RETURN(item == NULL); ++ ASSERT_RETURN(item); + + /* + * Compare received items, creds must be translated into +-- +2.4.3 + + +From 42c6f60d15f3a359e0d779f7af4a8ee51144e16d Mon Sep 17 00:00:00 2001 +From: David Herrmann <dh.herrmann@gmail.com> +Date: Mon, 15 Jun 2015 12:20:28 +0200 +Subject: [PATCH 05/34] kdbus: drop redundant KDBUS_MSG_MAX_ITEMS + +We already limit the size of the message object, there's no reason to add +an arbitrary additional limit on the number of items. We don't do this for +other item-arrays, so lets stop restricting the messages in this way. + +Signed-off-by: David Herrmann <dh.herrmann@gmail.com> +--- + ipc/kdbus/limits.h | 3 --- + ipc/kdbus/message.c | 12 ++++-------- + 2 files changed, 4 insertions(+), 11 deletions(-) + +diff --git a/ipc/kdbus/limits.h b/ipc/kdbus/limits.h +index 6450f58cffcf..c54925a25971 100644 +--- a/ipc/kdbus/limits.h ++++ b/ipc/kdbus/limits.h +@@ -19,9 +19,6 @@ + /* maximum size of message header and items */ + #define KDBUS_MSG_MAX_SIZE SZ_8K + +-/* maximum number of message items */ +-#define KDBUS_MSG_MAX_ITEMS 128 +- + /* maximum number of memfd items per message */ + #define KDBUS_MSG_MAX_MEMFD_ITEMS 16 + +diff --git a/ipc/kdbus/message.c b/ipc/kdbus/message.c +index 066e816dfdea..e9da67229eb1 100644 +--- a/ipc/kdbus/message.c ++++ b/ipc/kdbus/message.c +@@ -214,7 +214,7 @@ static int kdbus_msg_scan_items(struct kdbus_kmsg *kmsg, + struct kdbus_msg_resources *res = kmsg->res; + const struct kdbus_msg *msg = &kmsg->msg; + const struct kdbus_item *item; +- size_t n, n_vecs, n_memfds; ++ size_t n_res, n_vecs, n_memfds; + bool has_bloom = false; + bool has_name = false; + bool has_fds = false; +@@ -243,9 +243,9 @@ static int kdbus_msg_scan_items(struct kdbus_kmsg *kmsg, + } + } + +- n = n_vecs + n_memfds; +- if (n > 0) { +- res->data = kcalloc(n, sizeof(*res->data), GFP_KERNEL); ++ n_res = n_vecs + n_memfds; ++ if (n_res > 0) { ++ res->data = kcalloc(n_res, sizeof(*res->data), GFP_KERNEL); + if (!res->data) + return -ENOMEM; + } +@@ -257,15 +257,11 @@ static int kdbus_msg_scan_items(struct kdbus_kmsg *kmsg, + } + + /* import data payloads */ +- n = 0; + vec_size = 0; + KDBUS_ITEMS_FOREACH(item, msg->items, KDBUS_ITEMS_SIZE(msg, items)) { + size_t payload_size = KDBUS_ITEM_PAYLOAD_SIZE(item); + struct iovec *iov = kmsg->iov + kmsg->iov_count; + +- if (++n > KDBUS_MSG_MAX_ITEMS) +- return -E2BIG; +- + switch (item->type) { + case KDBUS_ITEM_PAYLOAD_VEC: { + struct kdbus_msg_data *d = res->data + res->data_count; +-- +2.4.3 + + +From 80c15dbf8b5eff74a41ceae7d83e9fcf8abf9df9 Mon Sep 17 00:00:00 2001 +From: David Herrmann <dh.herrmann@gmail.com> +Date: Fri, 19 Jun 2015 17:08:08 +0200 +Subject: [PATCH 06/34] kdbus: drop unused 'bloom_generation' field + +This field is never used, drop it. + +Signed-off-by: David Herrmann <dh.herrmann@gmail.com> +--- + ipc/kdbus/message.h | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/ipc/kdbus/message.h b/ipc/kdbus/message.h +index cdaa65c4e6ae..3b733474f335 100644 +--- a/ipc/kdbus/message.h ++++ b/ipc/kdbus/message.h +@@ -88,7 +88,6 @@ kdbus_msg_resources_unref(struct kdbus_msg_resources *r); + * @notify_name: Short-cut for faster lookup + * @dst_name_id: Short-cut to msg for faster lookup + * @bloom_filter: Bloom filter to match message properties +- * @bloom_generation: Generation of bloom element set + * @notify_entry: List of kernel-generated notifications + * @iov: Array of iovec, describing the payload to copy + * @iov_count: Number of array members in @iov +@@ -107,7 +106,6 @@ struct kdbus_kmsg { + + u64 dst_name_id; + const struct kdbus_bloom_filter *bloom_filter; +- u64 bloom_generation; + struct list_head notify_entry; + + struct iovec *iov; +-- +2.4.3 + + +From fb1fa875dc1df36250e92085b914d9d5c5e952d3 Mon Sep 17 00:00:00 2001 +From: David Herrmann <dh.herrmann@gmail.com> +Date: Fri, 5 Jun 2015 15:30:40 +0200 +Subject: [PATCH 07/34] kdbus: drop support for required attach-flags on buses + +This drops the KDBUS_ITEM_ATTACH_FLAGS_RECV item from KDBUS_CMD_BUS_MAKE. +This item was used to provide an attach-flags mask which defines metadata +items that all connections must have in their send-mask. Hence, +effectively forcing the transmission of such items in case the receiver +wants them. + +This was never used by any code and is of questionable use. With our new +effort to make sure metadata items are only transmitted if the receiver +has actual access to the same data via /proc, this is no longer needed. +Drop support for this item now. + +Signed-off-by: David Herrmann <dh.herrmann@gmail.com> +--- + Documentation/kdbus/kdbus.bus.xml | 15 --------------- + Documentation/kdbus/kdbus.connection.xml | 8 +------- + ipc/kdbus/bus.c | 10 ---------- + ipc/kdbus/bus.h | 2 -- + ipc/kdbus/connection.c | 10 ---------- + tools/testing/selftests/kdbus/kdbus-test.c | 1 - + tools/testing/selftests/kdbus/kdbus-util.c | 20 +++++++------------- + tools/testing/selftests/kdbus/kdbus-util.h | 3 +-- + tools/testing/selftests/kdbus/test-connection.c | 9 --------- + 9 files changed, 9 insertions(+), 69 deletions(-) + +diff --git a/Documentation/kdbus/kdbus.bus.xml b/Documentation/kdbus/kdbus.bus.xml +index 4b9a0ac1b351..83f1198bc6a1 100644 +--- a/Documentation/kdbus/kdbus.bus.xml ++++ b/Documentation/kdbus/kdbus.bus.xml +@@ -198,21 +198,6 @@ struct kdbus_cmd { + </varlistentry> + + <varlistentry> +- <term><constant>KDBUS_ITEM_ATTACH_FLAGS_RECV</constant></term> +- <listitem> +- <para> +- An optional item that contains a set of required attach flags +- that connections must allow. This item is used as a +- negotiation measure during connection creation. If connections +- do not satisfy the bus requirements, they are not allowed on +- the bus. If not set, the bus does not require any metadata to +- be attached; in this case connections are free to set their +- own attach flags. +- </para> +- </listitem> +- </varlistentry> +- +- <varlistentry> + <term><constant>KDBUS_ITEM_ATTACH_FLAGS_SEND</constant></term> + <listitem> + <para> +diff --git a/Documentation/kdbus/kdbus.connection.xml b/Documentation/kdbus/kdbus.connection.xml +index cefb419f1093..4bb5f30f379a 100644 +--- a/Documentation/kdbus/kdbus.connection.xml ++++ b/Documentation/kdbus/kdbus.connection.xml +@@ -355,13 +355,7 @@ struct kdbus_cmd_hello { + Set the bits for metadata this connection permits to be sent to the + receiving peer. Only metadata items that are both allowed to be sent + by the sender and that are requested by the receiver will be attached +- to the message. Note, however, that the bus may optionally require +- some of those bits to be set. If the match fails, the ioctl will fail +- with <varname>errno</varname> set to +- <constant>ECONNREFUSED</constant>. In either case, when returning the +- field will be set to the mask of metadata items that are enforced by +- the bus with the <constant>KDBUS_FLAGS_KERNEL</constant> bit set as +- well. ++ to the message. + </para></listitem> + </varlistentry> + +diff --git a/ipc/kdbus/bus.c b/ipc/kdbus/bus.c +index bbdf0f2f391e..7d2c336213ad 100644 +--- a/ipc/kdbus/bus.c ++++ b/ipc/kdbus/bus.c +@@ -66,23 +66,16 @@ static struct kdbus_bus *kdbus_bus_new(struct kdbus_domain *domain, + const char *name, + struct kdbus_bloom_parameter *bloom, + const u64 *pattach_owner, +- const u64 *pattach_recv, + u64 flags, kuid_t uid, kgid_t gid) + { + struct kdbus_bus *b; + u64 attach_owner; +- u64 attach_recv; + int ret; + + if (bloom->size < 8 || bloom->size > KDBUS_BUS_BLOOM_MAX_SIZE || + !KDBUS_IS_ALIGNED8(bloom->size) || bloom->n_hash < 1) + return ERR_PTR(-EINVAL); + +- ret = kdbus_sanitize_attach_flags(pattach_recv ? *pattach_recv : 0, +- &attach_recv); +- if (ret < 0) +- return ERR_PTR(ret); +- + ret = kdbus_sanitize_attach_flags(pattach_owner ? *pattach_owner : 0, + &attach_owner); + if (ret < 0) +@@ -111,7 +104,6 @@ static struct kdbus_bus *kdbus_bus_new(struct kdbus_domain *domain, + + b->id = atomic64_inc_return(&domain->last_id); + b->bus_flags = flags; +- b->attach_flags_req = attach_recv; + b->attach_flags_owner = attach_owner; + generate_random_uuid(b->id128); + b->bloom = *bloom; +@@ -380,7 +372,6 @@ struct kdbus_bus *kdbus_cmd_bus_make(struct kdbus_domain *domain, + { .type = KDBUS_ITEM_MAKE_NAME, .mandatory = true }, + { .type = KDBUS_ITEM_BLOOM_PARAMETER, .mandatory = true }, + { .type = KDBUS_ITEM_ATTACH_FLAGS_SEND }, +- { .type = KDBUS_ITEM_ATTACH_FLAGS_RECV }, + }; + struct kdbus_args args = { + .allowed_flags = KDBUS_FLAG_NEGOTIATE | +@@ -399,7 +390,6 @@ struct kdbus_bus *kdbus_cmd_bus_make(struct kdbus_domain *domain, + bus = kdbus_bus_new(domain, + argv[1].item->str, &argv[2].item->bloom_parameter, + argv[3].item ? argv[3].item->data64 : NULL, +- argv[4].item ? argv[4].item->data64 : NULL, + cmd->flags, current_euid(), current_egid()); + if (IS_ERR(bus)) { + ret = PTR_ERR(bus); +diff --git a/ipc/kdbus/bus.h b/ipc/kdbus/bus.h +index 5bea5ef768f1..e019ef34534c 100644 +--- a/ipc/kdbus/bus.h ++++ b/ipc/kdbus/bus.h +@@ -37,7 +37,6 @@ struct kdbus_user; + * @node: kdbus_node + * @id: ID of this bus in the domain + * @bus_flags: Simple pass-through flags from userspace to userspace +- * @attach_flags_req: KDBUS_ATTACH_* flags required by connecting peers + * @attach_flags_owner: KDBUS_ATTACH_* flags of bus creator that other + * connections can see or query + * @id128: Unique random 128 bit ID of this bus +@@ -60,7 +59,6 @@ struct kdbus_bus { + /* static */ + u64 id; + u64 bus_flags; +- u64 attach_flags_req; + u64 attach_flags_owner; + u8 id128[16]; + struct kdbus_bloom_parameter bloom; +diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c +index af044f93c14f..02e3ce735034 100644 +--- a/ipc/kdbus/connection.c ++++ b/ipc/kdbus/connection.c +@@ -112,10 +112,6 @@ static struct kdbus_conn *kdbus_conn_new(struct kdbus_ep *ep, bool privileged, + if (ret < 0) + return ERR_PTR(ret); + +- /* The attach flags must always satisfy the bus requirements. */ +- if (bus->attach_flags_req & ~attach_flags_send) +- return ERR_PTR(-ECONNREFUSED); +- + conn = kzalloc(sizeof(*conn), GFP_KERNEL); + if (!conn) + return ERR_PTR(-ENOMEM); +@@ -1835,7 +1831,6 @@ exit: + */ + int kdbus_cmd_update(struct kdbus_conn *conn, void __user *argp) + { +- struct kdbus_bus *bus = conn->ep->bus; + struct kdbus_item *item_policy; + u64 *item_attach_send = NULL; + u64 *item_attach_recv = NULL; +@@ -1876,11 +1871,6 @@ int kdbus_cmd_update(struct kdbus_conn *conn, void __user *argp) + &attach_send); + if (ret < 0) + goto exit; +- +- if (bus->attach_flags_req & ~attach_send) { +- ret = -EINVAL; +- goto exit; +- } + } + + if (item_attach_recv) { +diff --git a/tools/testing/selftests/kdbus/kdbus-test.c b/tools/testing/selftests/kdbus/kdbus-test.c +index 294e82a83ab6..db732e59650a 100644 +--- a/tools/testing/selftests/kdbus/kdbus-test.c ++++ b/tools/testing/selftests/kdbus/kdbus-test.c +@@ -299,7 +299,6 @@ static int test_prepare_env(const struct kdbus_test *t, + + ret = kdbus_create_bus(env->control_fd, + args->busname ?: n, +- _KDBUS_ATTACH_ALL, + _KDBUS_ATTACH_ALL, &s); + free(n); + ASSERT_RETURN(ret == 0); +diff --git a/tools/testing/selftests/kdbus/kdbus-util.c b/tools/testing/selftests/kdbus/kdbus-util.c +index 29a0cb1aace2..a5e54ca3a492 100644 +--- a/tools/testing/selftests/kdbus/kdbus-util.c ++++ b/tools/testing/selftests/kdbus/kdbus-util.c +@@ -114,8 +114,7 @@ int kdbus_sysfs_set_parameter_mask(const char *path, uint64_t mask) + } + + int kdbus_create_bus(int control_fd, const char *name, +- uint64_t req_meta, uint64_t owner_meta, +- char **path) ++ uint64_t owner_meta, char **path) + { + struct { + struct kdbus_cmd cmd; +@@ -127,12 +126,12 @@ int kdbus_create_bus(int control_fd, const char *name, + struct kdbus_bloom_parameter bloom; + } bp; + +- /* required and owner metadata items */ ++ /* owner metadata items */ + struct { + uint64_t size; + uint64_t type; + uint64_t flags; +- } attach[2]; ++ } attach; + + /* name item */ + struct { +@@ -152,13 +151,9 @@ int kdbus_create_bus(int control_fd, const char *name, + snprintf(bus_make.name.str, sizeof(bus_make.name.str), + "%u-%s", getuid(), name); + +- bus_make.attach[0].type = KDBUS_ITEM_ATTACH_FLAGS_RECV; +- bus_make.attach[0].size = sizeof(bus_make.attach[0]); +- bus_make.attach[0].flags = req_meta; +- +- bus_make.attach[1].type = KDBUS_ITEM_ATTACH_FLAGS_SEND; +- bus_make.attach[1].size = sizeof(bus_make.attach[0]); +- bus_make.attach[1].flags = owner_meta; ++ bus_make.attach.type = KDBUS_ITEM_ATTACH_FLAGS_SEND; ++ bus_make.attach.size = sizeof(bus_make.attach); ++ bus_make.attach.flags = owner_meta; + + bus_make.name.type = KDBUS_ITEM_MAKE_NAME; + bus_make.name.size = KDBUS_ITEM_HEADER_SIZE + +@@ -167,8 +162,7 @@ int kdbus_create_bus(int control_fd, const char *name, + bus_make.cmd.flags = KDBUS_MAKE_ACCESS_WORLD; + bus_make.cmd.size = sizeof(bus_make.cmd) + + bus_make.bp.size + +- bus_make.attach[0].size + +- bus_make.attach[1].size + ++ bus_make.attach.size + + bus_make.name.size; + + kdbus_printf("Creating bus with name >%s< on control fd %d ...\n", +diff --git a/tools/testing/selftests/kdbus/kdbus-util.h b/tools/testing/selftests/kdbus/kdbus-util.h +index d1a0f1b4d0eb..e1e18b92f425 100644 +--- a/tools/testing/selftests/kdbus/kdbus-util.h ++++ b/tools/testing/selftests/kdbus/kdbus-util.h +@@ -168,8 +168,7 @@ int kdbus_free(const struct kdbus_conn *conn, uint64_t offset); + int kdbus_msg_dump(const struct kdbus_conn *conn, + const struct kdbus_msg *msg); + int kdbus_create_bus(int control_fd, const char *name, +- uint64_t req_meta, uint64_t owner_meta, +- char **path); ++ uint64_t owner_meta, char **path); + int kdbus_msg_send(const struct kdbus_conn *conn, const char *name, + uint64_t cookie, uint64_t flags, uint64_t timeout, + int64_t priority, uint64_t dst_id); +diff --git a/tools/testing/selftests/kdbus/test-connection.c b/tools/testing/selftests/kdbus/test-connection.c +index e7c486621b04..4688ce8ec40b 100644 +--- a/tools/testing/selftests/kdbus/test-connection.c ++++ b/tools/testing/selftests/kdbus/test-connection.c +@@ -70,15 +70,6 @@ int kdbus_test_hello(struct kdbus_test_env *env) + + hello.pool_size = POOL_SIZE; + +- /* +- * The connection created by the core requires ALL meta flags +- * to be sent. An attempt to send less than that should result in +- * -ECONNREFUSED. +- */ +- hello.attach_flags_send = _KDBUS_ATTACH_ALL & ~KDBUS_ATTACH_TIMESTAMP; +- ret = kdbus_cmd_hello(fd, &hello); +- ASSERT_RETURN(ret == -ECONNREFUSED); +- + hello.attach_flags_send = _KDBUS_ATTACH_ALL; + hello.offset = (__u64)-1; + +-- +2.4.3 + + +From c2bc012ac7da42acdeb079cc1ef4ea25b67d0b74 Mon Sep 17 00:00:00 2001 +From: David Herrmann <dh.herrmann@gmail.com> +Date: Tue, 9 Jun 2015 09:43:47 +0200 +Subject: [PATCH 08/34] kdbus: pin namespaces on HELLO + +Whenever we send messages to a target connection, all we know about the +target is the 'struct file' associated with the kdbus connection. Hence, +we cannot know which namespaces a receiving process will be in when it +calls KDBUS_CMD_RECV on the message. So far, we pinned all metadata we +wanna send and translate it on RECV-time, since we then know the exact +namespaces to translate into. + +This has several drawbacks: + - Depending on the process calling RECV, the behavior is different (as + multiple processes might be in different namespaces but share the same + fd). This is unwanted behavior, as described by Eric here: + http://www.spinics.net/lists/netdev/msg329322.html + - We need to pin metadata with a message instead of translating it right + away. + - We cannot prep a message at SEND time as we don't know the size of the + translated metadata. Hence, we need to do all that at RECV time. + +This patch changes the namespace behavior. Instead of using the namespaces +at RECV time, we now pin the namespaces at HELLO (i.e., open()). So +regardless who calls RECV on this file-descriptor, the same namespaces +will be used. +This gives us the advantage that we now always know the target namespaces +for a message. Hence, we can now properly prep a message at SEND time and +never have to carry any metadata pins around. + +Signed-off-by: David Herrmann <dh.herrmann@gmail.com> +--- + ipc/kdbus/bus.c | 2 +- + ipc/kdbus/connection.c | 8 +++++++- + ipc/kdbus/connection.h | 6 ++++++ + ipc/kdbus/metadata.c | 54 ++++++++++++++++++++++++++------------------------ + ipc/kdbus/metadata.h | 1 + + ipc/kdbus/queue.c | 1 + + 6 files changed, 44 insertions(+), 28 deletions(-) + +diff --git a/ipc/kdbus/bus.c b/ipc/kdbus/bus.c +index 7d2c336213ad..8fffc2f594a8 100644 +--- a/ipc/kdbus/bus.c ++++ b/ipc/kdbus/bus.c +@@ -507,7 +507,7 @@ int kdbus_cmd_bus_creator_info(struct kdbus_conn *conn, void __user *argp) + goto exit; + } + +- ret = kdbus_meta_export(bus->creator_meta, NULL, attach_flags, ++ ret = kdbus_meta_export(bus->creator_meta, NULL, conn, attach_flags, + slice, hdr_size, &meta_size); + if (ret < 0) + goto exit; +diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c +index 02e3ce735034..ca241fcf19f7 100644 +--- a/ipc/kdbus/connection.c ++++ b/ipc/kdbus/connection.c +@@ -130,6 +130,9 @@ static struct kdbus_conn *kdbus_conn_new(struct kdbus_ep *ep, bool privileged, + atomic_set(&conn->lost_count, 0); + INIT_DELAYED_WORK(&conn->work, kdbus_reply_list_scan_work); + conn->cred = get_current_cred(); ++ conn->user_ns = get_user_ns(current_user_ns()); ++ conn->pid_ns = get_pid_ns(task_active_pid_ns(current)); ++ get_fs_root(current->fs, &conn->root_path); + init_waitqueue_head(&conn->wait); + kdbus_queue_init(&conn->queue); + conn->privileged = privileged; +@@ -271,6 +274,9 @@ static void __kdbus_conn_free(struct kref *kref) + kdbus_match_db_free(conn->match_db); + kdbus_pool_free(conn->pool); + kdbus_ep_unref(conn->ep); ++ path_put(&conn->root_path); ++ put_pid_ns(conn->pid_ns); ++ put_user_ns(conn->user_ns); + put_cred(conn->cred); + kfree(conn->description); + kfree(conn->quota); +@@ -1792,7 +1798,7 @@ int kdbus_cmd_conn_info(struct kdbus_conn *conn, void __user *argp) + goto exit; + } + +- ret = kdbus_meta_export(owner_conn->meta, conn_meta, attach_flags, ++ ret = kdbus_meta_export(owner_conn->meta, conn_meta, conn, attach_flags, + slice, sizeof(info), &meta_size); + if (ret < 0) + goto exit; +diff --git a/ipc/kdbus/connection.h b/ipc/kdbus/connection.h +index d1ffe909cb31..226f3ff60e31 100644 +--- a/ipc/kdbus/connection.h ++++ b/ipc/kdbus/connection.h +@@ -59,6 +59,9 @@ struct kdbus_kmsg; + * @pool: The user's buffer to receive messages + * @user: Owner of the connection + * @cred: The credentials of the connection at creation time ++ * @user_ns: User namespace at creation time ++ * @pid_ns: Pid namespace at creation time ++ * @root_path: Root path at creation time + * @name_count: Number of owned well-known names + * @request_count: Number of pending requests issued by this + * connection that are waiting for replies from +@@ -97,6 +100,9 @@ struct kdbus_conn { + struct kdbus_pool *pool; + struct kdbus_user *user; + const struct cred *cred; ++ struct user_namespace *user_ns; ++ struct pid_namespace *pid_ns; ++ struct path root_path; + atomic_t name_count; + atomic_t request_count; + atomic_t lost_count; +diff --git a/ipc/kdbus/metadata.c b/ipc/kdbus/metadata.c +index c36b9cc67637..79f0e8c7f4a3 100644 +--- a/ipc/kdbus/metadata.c ++++ b/ipc/kdbus/metadata.c +@@ -888,7 +888,8 @@ static int kdbus_meta_push_kvec(struct kvec *kvec, + } + + static void kdbus_meta_export_caps(struct kdbus_meta_caps *out, +- struct kdbus_meta_proc *mp) ++ struct kdbus_meta_proc *mp, ++ struct user_namespace *user_ns) + { + struct user_namespace *iter; + const struct cred *cred = mp->cred; +@@ -896,18 +897,18 @@ static void kdbus_meta_export_caps(struct kdbus_meta_caps *out, + int i; + + /* +- * This translates the effective capabilities of 'cred' into the current +- * user-namespace. If the current user-namespace is a child-namespace of ++ * This translates the effective capabilities of 'cred' into the given ++ * user-namespace. If the given user-namespace is a child-namespace of + * the user-namespace of 'cred', the mask can be copied verbatim. If + * not, the mask is cleared. + * There's one exception: If 'cred' is the owner of any user-namespace +- * in the path between the current user-namespace and the user-namespace ++ * in the path between the given user-namespace and the user-namespace + * of 'cred', then it has all effective capabilities set. This means, + * the user who created a user-namespace always has all effective + * capabilities in any child namespaces. Note that this is based on the + * uid of the namespace creator, not the task hierarchy. + */ +- for (iter = current_user_ns(); iter; iter = iter->parent) { ++ for (iter = user_ns; iter; iter = iter->parent) { + if (iter == cred->user_ns) { + parent = true; + break; +@@ -951,23 +952,22 @@ static void kdbus_meta_export_caps(struct kdbus_meta_caps *out, + } + + /* This is equivalent to from_kuid_munged(), but maps INVALID_UID to itself */ +-static uid_t kdbus_from_kuid_keep(kuid_t uid) ++static uid_t kdbus_from_kuid_keep(struct user_namespace *ns, kuid_t uid) + { +- return uid_valid(uid) ? +- from_kuid_munged(current_user_ns(), uid) : ((uid_t)-1); ++ return uid_valid(uid) ? from_kuid_munged(ns, uid) : ((uid_t)-1); + } + + /* This is equivalent to from_kgid_munged(), but maps INVALID_GID to itself */ +-static gid_t kdbus_from_kgid_keep(kgid_t gid) ++static gid_t kdbus_from_kgid_keep(struct user_namespace *ns, kgid_t gid) + { +- return gid_valid(gid) ? +- from_kgid_munged(current_user_ns(), gid) : ((gid_t)-1); ++ return gid_valid(gid) ? from_kgid_munged(ns, gid) : ((gid_t)-1); + } + + /** + * kdbus_meta_export() - export information from metadata into a slice + * @mp: Process metadata, or NULL + * @mc: Connection metadata, or NULL ++ * @conn: Target connection to translate metadata into + * @mask: Mask of KDBUS_ATTACH_* flags to export + * @slice: The slice to export to + * @offset: The offset inside @slice to write to +@@ -983,18 +983,19 @@ static gid_t kdbus_from_kgid_keep(kgid_t gid) + * kdbus_meta_export_prepare(); depending on the namespaces in question, it + * might use up less than that. + * +- * All information will be translated using the current namespaces. ++ * All information will be translated using the namespaces of @conn. + * + * Return: 0 on success, negative error number otherwise. + */ + int kdbus_meta_export(struct kdbus_meta_proc *mp, + struct kdbus_meta_conn *mc, ++ struct kdbus_conn *conn, + u64 mask, + struct kdbus_pool_slice *slice, + off_t offset, + size_t *real_size) + { +- struct user_namespace *user_ns = current_user_ns(); ++ struct user_namespace *user_ns = conn->user_ns; + struct kdbus_item_header item_hdr[13], *hdr; + char *exe_pathname = NULL; + struct kdbus_creds creds; +@@ -1016,23 +1017,23 @@ int kdbus_meta_export(struct kdbus_meta_proc *mp, + /* process metadata */ + + if (mp && (mask & KDBUS_ATTACH_CREDS)) { +- creds.uid = kdbus_from_kuid_keep(mp->uid); +- creds.euid = kdbus_from_kuid_keep(mp->euid); +- creds.suid = kdbus_from_kuid_keep(mp->suid); +- creds.fsuid = kdbus_from_kuid_keep(mp->fsuid); +- creds.gid = kdbus_from_kgid_keep(mp->gid); +- creds.egid = kdbus_from_kgid_keep(mp->egid); +- creds.sgid = kdbus_from_kgid_keep(mp->sgid); +- creds.fsgid = kdbus_from_kgid_keep(mp->fsgid); ++ creds.uid = kdbus_from_kuid_keep(user_ns, mp->uid); ++ creds.euid = kdbus_from_kuid_keep(user_ns, mp->euid); ++ creds.suid = kdbus_from_kuid_keep(user_ns, mp->suid); ++ creds.fsuid = kdbus_from_kuid_keep(user_ns, mp->fsuid); ++ creds.gid = kdbus_from_kgid_keep(user_ns, mp->gid); ++ creds.egid = kdbus_from_kgid_keep(user_ns, mp->egid); ++ creds.sgid = kdbus_from_kgid_keep(user_ns, mp->sgid); ++ creds.fsgid = kdbus_from_kgid_keep(user_ns, mp->fsgid); + + cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, KDBUS_ITEM_CREDS, + &creds, sizeof(creds), &size); + } + + if (mp && (mask & KDBUS_ATTACH_PIDS)) { +- pids.pid = pid_vnr(mp->tgid); +- pids.tid = pid_vnr(mp->pid); +- pids.ppid = pid_vnr(mp->ppid); ++ pids.pid = pid_nr_ns(mp->tgid, conn->pid_ns); ++ pids.tid = pid_nr_ns(mp->pid, conn->pid_ns); ++ pids.ppid = pid_nr_ns(mp->ppid, conn->pid_ns); + + cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, KDBUS_ITEM_PIDS, + &pids, sizeof(pids), &size); +@@ -1078,7 +1079,8 @@ int kdbus_meta_export(struct kdbus_meta_proc *mp, + */ + + get_fs_root(current->fs, &p); +- if (path_equal(&p, &mp->root_path)) { ++ if (path_equal(&p, &mp->root_path) && ++ path_equal(&p, &conn->root_path)) { + exe_page = (void *)__get_free_page(GFP_TEMPORARY); + if (!exe_page) { + path_put(&p); +@@ -1116,7 +1118,7 @@ int kdbus_meta_export(struct kdbus_meta_proc *mp, + if (mp && (mask & KDBUS_ATTACH_CAPS)) { + struct kdbus_meta_caps caps = {}; + +- kdbus_meta_export_caps(&caps, mp); ++ kdbus_meta_export_caps(&caps, mp, user_ns); + cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, + KDBUS_ITEM_CAPS, &caps, + sizeof(caps), &size); +diff --git a/ipc/kdbus/metadata.h b/ipc/kdbus/metadata.h +index 79b6ac31c8ad..2dbbb3d78d97 100644 +--- a/ipc/kdbus/metadata.h ++++ b/ipc/kdbus/metadata.h +@@ -46,6 +46,7 @@ int kdbus_meta_export_prepare(struct kdbus_meta_proc *mp, + u64 *mask, size_t *sz); + int kdbus_meta_export(struct kdbus_meta_proc *mp, + struct kdbus_meta_conn *mc, ++ struct kdbus_conn *conn, + u64 mask, + struct kdbus_pool_slice *slice, + off_t offset, size_t *real_size); +diff --git a/ipc/kdbus/queue.c b/ipc/kdbus/queue.c +index 25bb3ad66b98..6650b7804d87 100644 +--- a/ipc/kdbus/queue.c ++++ b/ipc/kdbus/queue.c +@@ -479,6 +479,7 @@ int kdbus_queue_entry_install(struct kdbus_queue_entry *entry, + + ret = kdbus_meta_export(entry->proc_meta, + entry->conn_meta, ++ conn_dst, + entry->attach_flags, + entry->slice, + entry->meta_offset, +-- +2.4.3 + + +From 539d66c50c22a40a29c97c8f1e497769de75c078 Mon Sep 17 00:00:00 2001 +From: David Herrmann <dh.herrmann@gmail.com> +Date: Wed, 1 Jul 2015 17:15:14 +0200 +Subject: [PATCH 09/34] kdbus: fix NULL-deref in activator cleanup + +Right now, we always assume an activator has a valid name and +conn->activator_of is set. However, this assumption is not true if the +setup of the activator fails. In those cases, the ->flags field indicates +an activator, but the name might not have been claimed, yet. + +Fix the destructor of connections to not assume all activators have +claimed names. + +Signed-off-by: David Herrmann <dh.herrmann@gmail.com> +--- + ipc/kdbus/names.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ipc/kdbus/names.c b/ipc/kdbus/names.c +index d77ee08afeda..057f8061c20f 100644 +--- a/ipc/kdbus/names.c ++++ b/ipc/kdbus/names.c +@@ -444,7 +444,7 @@ void kdbus_name_release_all(struct kdbus_name_registry *reg, + + down_write(®->rwlock); + +- if (kdbus_conn_is_activator(conn)) { ++ if (conn->activator_of) { + activator = conn->activator_of->activator; + conn->activator_of->activator = NULL; + } +-- +2.4.3 + + +From 3c18b8a477e0eda28b3390cf9168dbdb3c7fdd56 Mon Sep 17 00:00:00 2001 +From: David Herrmann <dh.herrmann@gmail.com> +Date: Fri, 3 Jul 2015 11:10:22 +0200 +Subject: [PATCH 10/34] kdbus: allow building development modules + +If you run your system on kdbus.ko, but you want to run tests on your +development version of kdbus, you will have a hard-time debugging as you +need to boot your machine with it. You either have to boot with legacy +dbus-daemon or boot without dbus entirely (eg., /bin/sh). + +The kdbus module always used KBUILD_MODNAME as base for all exported +objects (like kdbusfs and file-system paths). Hence, we can easily build +kdbus2.ko and get an independent module of the first one. This patch makes +the kdbus Makefile read KDBUS_EXT= and appends it to the module name. + +Now you can get an independent kdbus2.ko, by simply running: + make KDBUS_EXT=2 M=ipc/kdbus + +Signed-off-by: David Herrmann <dh.herrmann@gmail.com> +--- + ipc/kdbus/Makefile | 15 +++++++++++++-- + 1 file changed, 13 insertions(+), 2 deletions(-) + +diff --git a/ipc/kdbus/Makefile b/ipc/kdbus/Makefile +index 7ee9271e1449..66663a124104 100644 +--- a/ipc/kdbus/Makefile ++++ b/ipc/kdbus/Makefile +@@ -1,4 +1,15 @@ +-kdbus-y := \ ++# ++# By setting KDBUS_EXT=2, the kdbus module will be built as kdbus2.ko, and ++# KBUILD_MODNAME=kdbus2. This has the effect that all exported objects have ++# different names than usually (kdbus2fs, /sys/fs/kdbus2/) and you can run ++# your test-infrastructure against the kdbus2.ko, while running your system ++# on kdbus.ko. ++# ++# To just build the module, use: ++# make KDBUS_EXT=2 M=ipc/kdbus ++# ++ ++kdbus$(KDBUS_EXT)-y := \ + bus.o \ + connection.o \ + endpoint.o \ +@@ -19,4 +30,4 @@ kdbus-y := \ + queue.o \ + util.o + +-obj-$(CONFIG_KDBUS) += kdbus.o ++obj-$(CONFIG_KDBUS) += kdbus$(KDBUS_EXT).o +-- +2.4.3 + + +From f8253aa89c645d1d979aa4743ebabe005f54f7df Mon Sep 17 00:00:00 2001 +From: David Herrmann <dh.herrmann@gmail.com> +Date: Mon, 15 Jun 2015 20:49:21 +0200 +Subject: [PATCH 11/34] kdbus: split off faked metadata into separate object + +Right now we treat faked metadata the same as process metadata. This has +the downside, that we cannot use "struct cred" to pin normal process +credentials, as we don't want to fake such structure for faked +credentials. + +Splitt off handling of faked metadata into a separate kdbus_meta_fake +object. As a side effect, faked metadata is now handled explicitly instead +of hidden in the process metadata. + +In follow-up patches, the kdbus_meta_proc state-tracking can be reduced +significantly by pinning "struct cred" instead of copying each field +individually. + +Signed-off-by: David Herrmann <dh.herrmann@gmail.com> +--- + ipc/kdbus/bus.c | 6 +- + ipc/kdbus/connection.c | 37 +++++---- + ipc/kdbus/connection.h | 9 +-- + ipc/kdbus/message.c | 2 +- + ipc/kdbus/metadata.c | 216 ++++++++++++++++++++++++++++++------------------- + ipc/kdbus/metadata.h | 43 +++++++++- + ipc/kdbus/queue.c | 2 + + 7 files changed, 206 insertions(+), 109 deletions(-) + +diff --git a/ipc/kdbus/bus.c b/ipc/kdbus/bus.c +index 8fffc2f594a8..dd1e600b8f01 100644 +--- a/ipc/kdbus/bus.c ++++ b/ipc/kdbus/bus.c +@@ -484,7 +484,7 @@ int kdbus_cmd_bus_creator_info(struct kdbus_conn *conn, void __user *argp) + + attach_flags &= bus->attach_flags_owner; + +- ret = kdbus_meta_export_prepare(bus->creator_meta, NULL, ++ ret = kdbus_meta_export_prepare(bus->creator_meta, NULL, NULL, + &attach_flags, &meta_size); + if (ret < 0) + goto exit; +@@ -507,8 +507,8 @@ int kdbus_cmd_bus_creator_info(struct kdbus_conn *conn, void __user *argp) + goto exit; + } + +- ret = kdbus_meta_export(bus->creator_meta, NULL, conn, attach_flags, +- slice, hdr_size, &meta_size); ++ ret = kdbus_meta_export(bus->creator_meta, NULL, NULL, conn, ++ attach_flags, slice, hdr_size, &meta_size); + if (ret < 0) + goto exit; + +diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c +index ca241fcf19f7..8976bb32ab69 100644 +--- a/ipc/kdbus/connection.c ++++ b/ipc/kdbus/connection.c +@@ -172,22 +172,28 @@ static struct kdbus_conn *kdbus_conn_new(struct kdbus_ep *ep, bool privileged, + BUILD_BUG_ON(sizeof(bus->id128) != sizeof(hello->id128)); + memcpy(hello->id128, bus->id128, sizeof(hello->id128)); + +- conn->meta = kdbus_meta_proc_new(); +- if (IS_ERR(conn->meta)) { +- ret = PTR_ERR(conn->meta); +- conn->meta = NULL; +- goto exit_unref; +- } +- + /* privileged processes can impersonate somebody else */ + if (creds || pids || seclabel) { +- ret = kdbus_meta_proc_fake(conn->meta, creds, pids, seclabel); +- if (ret < 0) ++ conn->meta_fake = kdbus_meta_fake_new(); ++ if (IS_ERR(conn->meta_fake)) { ++ ret = PTR_ERR(conn->meta_fake); ++ conn->meta_fake = NULL; + goto exit_unref; ++ } + +- conn->faked_meta = true; ++ ret = kdbus_meta_fake_collect(conn->meta_fake, ++ creds, pids, seclabel); ++ if (ret < 0) ++ goto exit_unref; + } else { +- ret = kdbus_meta_proc_collect(conn->meta, ++ conn->meta_proc = kdbus_meta_proc_new(); ++ if (IS_ERR(conn->meta_proc)) { ++ ret = PTR_ERR(conn->meta_proc); ++ conn->meta_proc = NULL; ++ goto exit_unref; ++ } ++ ++ ret = kdbus_meta_proc_collect(conn->meta_proc, + KDBUS_ATTACH_CREDS | + KDBUS_ATTACH_PIDS | + KDBUS_ATTACH_AUXGROUPS | +@@ -270,7 +276,8 @@ static void __kdbus_conn_free(struct kref *kref) + kdbus_user_unref(conn->user); + } + +- kdbus_meta_proc_unref(conn->meta); ++ kdbus_meta_fake_free(conn->meta_fake); ++ kdbus_meta_proc_unref(conn->meta_proc); + kdbus_match_db_free(conn->match_db); + kdbus_pool_free(conn->pool); + kdbus_ep_unref(conn->ep); +@@ -1785,7 +1792,8 @@ int kdbus_cmd_conn_info(struct kdbus_conn *conn, void __user *argp) + if (ret < 0) + goto exit; + +- ret = kdbus_meta_export_prepare(owner_conn->meta, conn_meta, ++ ret = kdbus_meta_export_prepare(owner_conn->meta_proc, ++ owner_conn->meta_fake, conn_meta, + &attach_flags, &meta_size); + if (ret < 0) + goto exit; +@@ -1798,7 +1806,8 @@ int kdbus_cmd_conn_info(struct kdbus_conn *conn, void __user *argp) + goto exit; + } + +- ret = kdbus_meta_export(owner_conn->meta, conn_meta, conn, attach_flags, ++ ret = kdbus_meta_export(owner_conn->meta_proc, owner_conn->meta_fake, ++ conn_meta, conn, attach_flags, + slice, sizeof(info), &meta_size); + if (ret < 0) + goto exit; +diff --git a/ipc/kdbus/connection.h b/ipc/kdbus/connection.h +index 226f3ff60e31..0eb3d2e70a5e 100644 +--- a/ipc/kdbus/connection.h ++++ b/ipc/kdbus/connection.h +@@ -54,8 +54,8 @@ struct kdbus_kmsg; + * @work: Delayed work to handle timeouts + * activator for + * @match_db: Subscription filter to broadcast messages +- * @meta: Active connection creator's metadata/credentials, +- * either from the handle or from HELLO ++ * @meta_proc: Process metadata of connection creator, or NULL ++ * @meta_fake: Faked metadata, or NULL + * @pool: The user's buffer to receive messages + * @user: Owner of the connection + * @cred: The credentials of the connection at creation time +@@ -75,7 +75,6 @@ struct kdbus_kmsg; + * @names_list: List of well-known names + * @names_queue_list: Well-known names this connection waits for + * @privileged: Whether this connection is privileged on the bus +- * @faked_meta: Whether the metadata was faked on HELLO + */ + struct kdbus_conn { + struct kref kref; +@@ -96,7 +95,8 @@ struct kdbus_conn { + struct list_head reply_list; + struct delayed_work work; + struct kdbus_match_db *match_db; +- struct kdbus_meta_proc *meta; ++ struct kdbus_meta_proc *meta_proc; ++ struct kdbus_meta_fake *meta_fake; + struct kdbus_pool *pool; + struct kdbus_user *user; + const struct cred *cred; +@@ -118,7 +118,6 @@ struct kdbus_conn { + struct list_head names_queue_list; + + bool privileged:1; +- bool faked_meta:1; + }; + + struct kdbus_conn *kdbus_conn_ref(struct kdbus_conn *conn); +diff --git a/ipc/kdbus/message.c b/ipc/kdbus/message.c +index e9da67229eb1..55e432397b93 100644 +--- a/ipc/kdbus/message.c ++++ b/ipc/kdbus/message.c +@@ -626,7 +626,7 @@ int kdbus_kmsg_collect_metadata(struct kdbus_kmsg *kmsg, struct kdbus_conn *src, + int ret; + + attach = kdbus_meta_calc_attach_flags(src, dst); +- if (!src->faked_meta) { ++ if (!src->meta_fake) { + ret = kdbus_meta_proc_collect(kmsg->proc_meta, attach); + if (ret < 0) + return ret; +diff --git a/ipc/kdbus/metadata.c b/ipc/kdbus/metadata.c +index 79f0e8c7f4a3..ac4135c507c4 100644 +--- a/ipc/kdbus/metadata.c ++++ b/ipc/kdbus/metadata.c +@@ -494,101 +494,116 @@ exit_unlock: + } + + /** +- * kdbus_meta_proc_fake() - Fill process metadata from faked credentials +- * @mp: Metadata ++ * kdbus_meta_fake_new() - Create fake metadata object ++ * ++ * Return: Pointer to new object on success, ERR_PTR on failure. ++ */ ++struct kdbus_meta_fake *kdbus_meta_fake_new(void) ++{ ++ struct kdbus_meta_fake *mf; ++ ++ mf = kzalloc(sizeof(*mf), GFP_KERNEL); ++ if (!mf) ++ return ERR_PTR(-ENOMEM); ++ ++ return mf; ++} ++ ++/** ++ * kdbus_meta_fake_free() - Free fake metadata object ++ * @mf: Fake metadata object ++ * ++ * Return: NULL ++ */ ++struct kdbus_meta_fake *kdbus_meta_fake_free(struct kdbus_meta_fake *mf) ++{ ++ if (mf) { ++ put_pid(mf->ppid); ++ put_pid(mf->tgid); ++ put_pid(mf->pid); ++ kfree(mf->seclabel); ++ kfree(mf); ++ } ++ ++ return NULL; ++} ++ ++/** ++ * kdbus_meta_fake_collect() - Fill fake metadata from faked credentials ++ * @mf: Fake metadata object + * @creds: Creds to set, may be %NULL + * @pids: PIDs to set, may be %NULL + * @seclabel: Seclabel to set, may be %NULL + * + * This function takes information stored in @creds, @pids and @seclabel and +- * resolves them to kernel-representations, if possible. A call to this function +- * is considered an alternative to calling kdbus_meta_add_current(), which +- * derives the same information from the 'current' task. +- * +- * This call uses the current task's namespaces to resolve the given +- * information. ++ * resolves them to kernel-representations, if possible. This call uses the ++ * current task's namespaces to resolve the given information. + * +- * Return: 0 on success, negative error number otherwise. ++ * Return: 0 on success, negative error code on failure. + */ +-int kdbus_meta_proc_fake(struct kdbus_meta_proc *mp, +- const struct kdbus_creds *creds, +- const struct kdbus_pids *pids, +- const char *seclabel) ++int kdbus_meta_fake_collect(struct kdbus_meta_fake *mf, ++ const struct kdbus_creds *creds, ++ const struct kdbus_pids *pids, ++ const char *seclabel) + { +- int ret; +- +- if (!mp) +- return 0; +- +- mutex_lock(&mp->lock); ++ if (mf->valid) ++ return -EALREADY; + +- if (creds && !(mp->collected & KDBUS_ATTACH_CREDS)) { ++ if (creds) { + struct user_namespace *ns = current_user_ns(); + +- mp->uid = make_kuid(ns, creds->uid); +- mp->euid = make_kuid(ns, creds->euid); +- mp->suid = make_kuid(ns, creds->suid); +- mp->fsuid = make_kuid(ns, creds->fsuid); +- +- mp->gid = make_kgid(ns, creds->gid); +- mp->egid = make_kgid(ns, creds->egid); +- mp->sgid = make_kgid(ns, creds->sgid); +- mp->fsgid = make_kgid(ns, creds->fsgid); +- +- if ((creds->uid != (uid_t)-1 && !uid_valid(mp->uid)) || +- (creds->euid != (uid_t)-1 && !uid_valid(mp->euid)) || +- (creds->suid != (uid_t)-1 && !uid_valid(mp->suid)) || +- (creds->fsuid != (uid_t)-1 && !uid_valid(mp->fsuid)) || +- (creds->gid != (gid_t)-1 && !gid_valid(mp->gid)) || +- (creds->egid != (gid_t)-1 && !gid_valid(mp->egid)) || +- (creds->sgid != (gid_t)-1 && !gid_valid(mp->sgid)) || +- (creds->fsgid != (gid_t)-1 && !gid_valid(mp->fsgid))) { +- ret = -EINVAL; +- goto exit_unlock; +- } +- +- mp->valid |= KDBUS_ATTACH_CREDS; +- mp->collected |= KDBUS_ATTACH_CREDS; ++ mf->uid = make_kuid(ns, creds->uid); ++ mf->euid = make_kuid(ns, creds->euid); ++ mf->suid = make_kuid(ns, creds->suid); ++ mf->fsuid = make_kuid(ns, creds->fsuid); ++ ++ mf->gid = make_kgid(ns, creds->gid); ++ mf->egid = make_kgid(ns, creds->egid); ++ mf->sgid = make_kgid(ns, creds->sgid); ++ mf->fsgid = make_kgid(ns, creds->fsgid); ++ ++ if ((creds->uid != (uid_t)-1 && !uid_valid(mf->uid)) || ++ (creds->euid != (uid_t)-1 && !uid_valid(mf->euid)) || ++ (creds->suid != (uid_t)-1 && !uid_valid(mf->suid)) || ++ (creds->fsuid != (uid_t)-1 && !uid_valid(mf->fsuid)) || ++ (creds->gid != (gid_t)-1 && !gid_valid(mf->gid)) || ++ (creds->egid != (gid_t)-1 && !gid_valid(mf->egid)) || ++ (creds->sgid != (gid_t)-1 && !gid_valid(mf->sgid)) || ++ (creds->fsgid != (gid_t)-1 && !gid_valid(mf->fsgid))) ++ return -EINVAL; ++ ++ mf->valid |= KDBUS_ATTACH_CREDS; + } + +- if (pids && !(mp->collected & KDBUS_ATTACH_PIDS)) { +- mp->pid = get_pid(find_vpid(pids->tid)); +- mp->tgid = get_pid(find_vpid(pids->pid)); +- mp->ppid = get_pid(find_vpid(pids->ppid)); +- +- if ((pids->tid != 0 && !mp->pid) || +- (pids->pid != 0 && !mp->tgid) || +- (pids->ppid != 0 && !mp->ppid)) { +- put_pid(mp->pid); +- put_pid(mp->tgid); +- put_pid(mp->ppid); +- mp->pid = NULL; +- mp->tgid = NULL; +- mp->ppid = NULL; +- ret = -EINVAL; +- goto exit_unlock; ++ if (pids) { ++ mf->pid = get_pid(find_vpid(pids->tid)); ++ mf->tgid = get_pid(find_vpid(pids->pid)); ++ mf->ppid = get_pid(find_vpid(pids->ppid)); ++ ++ if ((pids->tid != 0 && !mf->pid) || ++ (pids->pid != 0 && !mf->tgid) || ++ (pids->ppid != 0 && !mf->ppid)) { ++ put_pid(mf->pid); ++ put_pid(mf->tgid); ++ put_pid(mf->ppid); ++ mf->pid = NULL; ++ mf->tgid = NULL; ++ mf->ppid = NULL; ++ return -EINVAL; + } + +- mp->valid |= KDBUS_ATTACH_PIDS; +- mp->collected |= KDBUS_ATTACH_PIDS; ++ mf->valid |= KDBUS_ATTACH_PIDS; + } + +- if (seclabel && !(mp->collected & KDBUS_ATTACH_SECLABEL)) { +- mp->seclabel = kstrdup(seclabel, GFP_KERNEL); +- if (!mp->seclabel) { +- ret = -ENOMEM; +- goto exit_unlock; +- } ++ if (seclabel) { ++ mf->seclabel = kstrdup(seclabel, GFP_KERNEL); ++ if (!mf->seclabel) ++ return -ENOMEM; + +- mp->valid |= KDBUS_ATTACH_SECLABEL; +- mp->collected |= KDBUS_ATTACH_SECLABEL; ++ mf->valid |= KDBUS_ATTACH_SECLABEL; + } + +- ret = 0; +- +-exit_unlock: +- mutex_unlock(&mp->lock); +- return ret; ++ return 0; + } + + /** +@@ -768,6 +783,7 @@ exit_unlock: + /* + * kdbus_meta_export_prepare() - Prepare metadata for export + * @mp: Process metadata, or NULL ++ * @mf: Fake metadata, or NULL + * @mc: Connection metadata, or NULL + * @mask: Pointer to mask of KDBUS_ATTACH_* flags to export + * @sz: Pointer to return the size needed by the metadata +@@ -783,6 +799,7 @@ exit_unlock: + * Return: 0 on success, negative error number otherwise. + */ + int kdbus_meta_export_prepare(struct kdbus_meta_proc *mp, ++ struct kdbus_meta_fake *mf, + struct kdbus_meta_conn *mc, + u64 *mask, size_t *sz) + { +@@ -792,6 +809,12 @@ int kdbus_meta_export_prepare(struct kdbus_meta_proc *mp, + u64 valid = 0; + int ret = 0; + ++ if (WARN_ON(mf && mp)) ++ mp = NULL; ++ ++ if (mf) ++ valid |= mf->valid; ++ + if (mp) { + mutex_lock(&mp->lock); + valid |= mp->valid; +@@ -811,10 +834,10 @@ int kdbus_meta_export_prepare(struct kdbus_meta_proc *mp, + + /* process metadata */ + +- if (mp && (*mask & KDBUS_ATTACH_CREDS)) ++ if ((mp || mf) && (*mask & KDBUS_ATTACH_CREDS)) + size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_creds)); + +- if (mp && (*mask & KDBUS_ATTACH_PIDS)) ++ if ((mp || mf) && (*mask & KDBUS_ATTACH_PIDS)) + size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_pids)); + + if (mp && (*mask & KDBUS_ATTACH_AUXGROUPS)) +@@ -852,8 +875,9 @@ int kdbus_meta_export_prepare(struct kdbus_meta_proc *mp, + if (mp && (*mask & KDBUS_ATTACH_CAPS)) + size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_meta_caps)); + +- if (mp && (*mask & KDBUS_ATTACH_SECLABEL)) +- size += KDBUS_ITEM_SIZE(strlen(mp->seclabel) + 1); ++ if ((mp || mf) && (*mask & KDBUS_ATTACH_SECLABEL)) ++ size += KDBUS_ITEM_SIZE(strlen(mp ? mp->seclabel ++ : mf->seclabel) + 1); + + if (mp && (*mask & KDBUS_ATTACH_AUDIT)) + size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_audit)); +@@ -966,6 +990,7 @@ static gid_t kdbus_from_kgid_keep(struct user_namespace *ns, kgid_t gid) + /** + * kdbus_meta_export() - export information from metadata into a slice + * @mp: Process metadata, or NULL ++ * @mf: Fake metadata, or NULL + * @mc: Connection metadata, or NULL + * @conn: Target connection to translate metadata into + * @mask: Mask of KDBUS_ATTACH_* flags to export +@@ -988,6 +1013,7 @@ static gid_t kdbus_from_kgid_keep(struct user_namespace *ns, kgid_t gid) + * Return: 0 on success, negative error number otherwise. + */ + int kdbus_meta_export(struct kdbus_meta_proc *mp, ++ struct kdbus_meta_fake *mf, + struct kdbus_meta_conn *mc, + struct kdbus_conn *conn, + u64 mask, +@@ -1007,6 +1033,9 @@ int kdbus_meta_export(struct kdbus_meta_proc *mp, + u64 size = 0; + int ret = 0; + ++ if (WARN_ON(mf && mp)) ++ mp = NULL; ++ + hdr = &item_hdr[0]; + + if (mask == 0) { +@@ -1016,7 +1045,19 @@ int kdbus_meta_export(struct kdbus_meta_proc *mp, + + /* process metadata */ + +- if (mp && (mask & KDBUS_ATTACH_CREDS)) { ++ if (mf && (mask & KDBUS_ATTACH_CREDS)) { ++ creds.uid = kdbus_from_kuid_keep(user_ns, mf->uid); ++ creds.euid = kdbus_from_kuid_keep(user_ns, mf->euid); ++ creds.suid = kdbus_from_kuid_keep(user_ns, mf->suid); ++ creds.fsuid = kdbus_from_kuid_keep(user_ns, mf->fsuid); ++ creds.gid = kdbus_from_kgid_keep(user_ns, mf->gid); ++ creds.egid = kdbus_from_kgid_keep(user_ns, mf->egid); ++ creds.sgid = kdbus_from_kgid_keep(user_ns, mf->sgid); ++ creds.fsgid = kdbus_from_kgid_keep(user_ns, mf->fsgid); ++ ++ cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, KDBUS_ITEM_CREDS, ++ &creds, sizeof(creds), &size); ++ } else if (mp && (mask & KDBUS_ATTACH_CREDS)) { + creds.uid = kdbus_from_kuid_keep(user_ns, mp->uid); + creds.euid = kdbus_from_kuid_keep(user_ns, mp->euid); + creds.suid = kdbus_from_kuid_keep(user_ns, mp->suid); +@@ -1030,7 +1071,14 @@ int kdbus_meta_export(struct kdbus_meta_proc *mp, + &creds, sizeof(creds), &size); + } + +- if (mp && (mask & KDBUS_ATTACH_PIDS)) { ++ if (mf && (mask & KDBUS_ATTACH_PIDS)) { ++ pids.pid = pid_nr_ns(mf->tgid, conn->pid_ns); ++ pids.tid = pid_nr_ns(mf->pid, conn->pid_ns); ++ pids.ppid = pid_nr_ns(mf->ppid, conn->pid_ns); ++ ++ cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, KDBUS_ITEM_PIDS, ++ &pids, sizeof(pids), &size); ++ } else if (mp && (mask & KDBUS_ATTACH_PIDS)) { + pids.pid = pid_nr_ns(mp->tgid, conn->pid_ns); + pids.tid = pid_nr_ns(mp->pid, conn->pid_ns); + pids.ppid = pid_nr_ns(mp->ppid, conn->pid_ns); +@@ -1124,7 +1172,11 @@ int kdbus_meta_export(struct kdbus_meta_proc *mp, + sizeof(caps), &size); + } + +- if (mp && (mask & KDBUS_ATTACH_SECLABEL)) ++ if (mf && (mask & KDBUS_ATTACH_SECLABEL)) ++ cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, ++ KDBUS_ITEM_SECLABEL, mf->seclabel, ++ strlen(mf->seclabel) + 1, &size); ++ else if (mp && (mask & KDBUS_ATTACH_SECLABEL)) + cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, + KDBUS_ITEM_SECLABEL, mp->seclabel, + strlen(mp->seclabel) + 1, &size); +diff --git a/ipc/kdbus/metadata.h b/ipc/kdbus/metadata.h +index 2dbbb3d78d97..2fb04dad38d4 100644 +--- a/ipc/kdbus/metadata.h ++++ b/ipc/kdbus/metadata.h +@@ -24,14 +24,47 @@ struct kdbus_pool_slice; + struct kdbus_meta_proc; + struct kdbus_meta_conn; + ++/** ++ * struct kdbus_meta_fake - Fake metadata ++ * @valid: Bitmask of collected and valid items ++ * @uid: UID of process ++ * @euid: EUID of process ++ * @suid: SUID of process ++ * @fsuid: FSUID of process ++ * @gid: GID of process ++ * @egid: EGID of process ++ * @sgid: SGID of process ++ * @fsgid: FSGID of process ++ * @pid: PID of process ++ * @tgid: TGID of process ++ * @ppid: PPID of process ++ * @seclabel: Seclabel ++ */ ++struct kdbus_meta_fake { ++ u64 valid; ++ ++ /* KDBUS_ITEM_CREDS */ ++ kuid_t uid, euid, suid, fsuid; ++ kgid_t gid, egid, sgid, fsgid; ++ ++ /* KDBUS_ITEM_PIDS */ ++ struct pid *pid, *tgid, *ppid; ++ ++ /* KDBUS_ITEM_SECLABEL */ ++ char *seclabel; ++}; ++ + struct kdbus_meta_proc *kdbus_meta_proc_new(void); + struct kdbus_meta_proc *kdbus_meta_proc_ref(struct kdbus_meta_proc *mp); + struct kdbus_meta_proc *kdbus_meta_proc_unref(struct kdbus_meta_proc *mp); + int kdbus_meta_proc_collect(struct kdbus_meta_proc *mp, u64 what); +-int kdbus_meta_proc_fake(struct kdbus_meta_proc *mp, +- const struct kdbus_creds *creds, +- const struct kdbus_pids *pids, +- const char *seclabel); ++ ++struct kdbus_meta_fake *kdbus_meta_fake_new(void); ++struct kdbus_meta_fake *kdbus_meta_fake_free(struct kdbus_meta_fake *mf); ++int kdbus_meta_fake_collect(struct kdbus_meta_fake *mf, ++ const struct kdbus_creds *creds, ++ const struct kdbus_pids *pids, ++ const char *seclabel); + + struct kdbus_meta_conn *kdbus_meta_conn_new(void); + struct kdbus_meta_conn *kdbus_meta_conn_ref(struct kdbus_meta_conn *mc); +@@ -42,9 +75,11 @@ int kdbus_meta_conn_collect(struct kdbus_meta_conn *mc, + u64 what); + + int kdbus_meta_export_prepare(struct kdbus_meta_proc *mp, ++ struct kdbus_meta_fake *mf, + struct kdbus_meta_conn *mc, + u64 *mask, size_t *sz); + int kdbus_meta_export(struct kdbus_meta_proc *mp, ++ struct kdbus_meta_fake *mf, + struct kdbus_meta_conn *mc, + struct kdbus_conn *conn, + u64 mask, +diff --git a/ipc/kdbus/queue.c b/ipc/kdbus/queue.c +index 6650b7804d87..1e7916155036 100644 +--- a/ipc/kdbus/queue.c ++++ b/ipc/kdbus/queue.c +@@ -251,6 +251,7 @@ struct kdbus_queue_entry *kdbus_queue_entry_new(struct kdbus_conn *conn_dst, + atomic64_read(&conn_dst->attach_flags_recv); + + ret = kdbus_meta_export_prepare(entry->proc_meta, ++ NULL, + entry->conn_meta, + &entry->attach_flags, + &meta_size); +@@ -478,6 +479,7 @@ int kdbus_queue_entry_install(struct kdbus_queue_entry *entry, + size_t meta_size; + + ret = kdbus_meta_export(entry->proc_meta, ++ NULL, + entry->conn_meta, + conn_dst, + entry->attach_flags, +-- +2.4.3 + + +From 2bec5609205bc69f57c7bd27834b2637aa656f6d Mon Sep 17 00:00:00 2001 +From: David Herrmann <dh.herrmann@gmail.com> +Date: Mon, 15 Jun 2015 21:25:39 +0200 +Subject: [PATCH 12/34] kdbus: pin 'struct cred' in process metadata + +Instead of copying over all data from 'struct cred', pin it directly. This +reduces the memory footprint of kdbus_meta_proc considerably and speeds +up the fast-path. + +There's no change in behavior. We just change the level we pin data at. + +Signed-off-by: David Herrmann <dh.herrmann@gmail.com> +--- + ipc/kdbus/metadata.c | 131 +++++++++++++-------------------------------------- + 1 file changed, 34 insertions(+), 97 deletions(-) + +diff --git a/ipc/kdbus/metadata.c b/ipc/kdbus/metadata.c +index ac4135c507c4..1bac0dda72e0 100644 +--- a/ipc/kdbus/metadata.c ++++ b/ipc/kdbus/metadata.c +@@ -44,26 +44,16 @@ + * @lock: Object lock + * @collected: Bitmask of collected items + * @valid: Bitmask of collected and valid items +- * @uid: UID of process +- * @euid: EUID of process +- * @suid: SUID of process +- * @fsuid: FSUID of process +- * @gid: GID of process +- * @egid: EGID of process +- * @sgid: SGID of process +- * @fsgid: FSGID of process ++ * @cred: Credentials + * @pid: PID of process + * @tgid: TGID of process + * @ppid: PPID of process +- * @auxgrps: Auxiliary groups +- * @n_auxgrps: Number of items in @auxgrps + * @tid_comm: TID comm line + * @pid_comm: PID comm line + * @exe_path: Executable path + * @root_path: Root-FS path + * @cmdline: Command-line + * @cgroup: Full cgroup path +- * @cred: Credentials + * @seclabel: Seclabel + * @audit_loginuid: Audit login-UID + * @audit_sessionid: Audit session-ID +@@ -75,18 +65,15 @@ struct kdbus_meta_proc { + u64 valid; + + /* KDBUS_ITEM_CREDS */ +- kuid_t uid, euid, suid, fsuid; +- kgid_t gid, egid, sgid, fsgid; ++ /* KDBUS_ITEM_AUXGROUPS */ ++ /* KDBUS_ITEM_CAPS */ ++ const struct cred *cred; + + /* KDBUS_ITEM_PIDS */ + struct pid *pid; + struct pid *tgid; + struct pid *ppid; + +- /* KDBUS_ITEM_AUXGROUPS */ +- kgid_t *auxgrps; +- size_t n_auxgrps; +- + /* KDBUS_ITEM_TID_COMM */ + char tid_comm[TASK_COMM_LEN]; + /* KDBUS_ITEM_PID_COMM */ +@@ -102,9 +89,6 @@ struct kdbus_meta_proc { + /* KDBUS_ITEM_CGROUP */ + char *cgroup; + +- /* KDBUS_ITEM_CAPS */ +- const struct cred *cred; +- + /* KDBUS_ITEM_SECLABEL */ + char *seclabel; + +@@ -182,7 +166,6 @@ static void kdbus_meta_proc_free(struct kref *kref) + put_pid(mp->pid); + + kfree(mp->seclabel); +- kfree(mp->auxgrps); + kfree(mp->cmdline); + kfree(mp->cgroup); + kfree(mp); +@@ -214,21 +197,6 @@ struct kdbus_meta_proc *kdbus_meta_proc_unref(struct kdbus_meta_proc *mp) + return NULL; + } + +-static void kdbus_meta_proc_collect_creds(struct kdbus_meta_proc *mp) +-{ +- mp->uid = current_uid(); +- mp->euid = current_euid(); +- mp->suid = current_suid(); +- mp->fsuid = current_fsuid(); +- +- mp->gid = current_gid(); +- mp->egid = current_egid(); +- mp->sgid = current_sgid(); +- mp->fsgid = current_fsgid(); +- +- mp->valid |= KDBUS_ATTACH_CREDS; +-} +- + static void kdbus_meta_proc_collect_pids(struct kdbus_meta_proc *mp) + { + struct task_struct *parent; +@@ -244,30 +212,6 @@ static void kdbus_meta_proc_collect_pids(struct kdbus_meta_proc *mp) + mp->valid |= KDBUS_ATTACH_PIDS; + } + +-static int kdbus_meta_proc_collect_auxgroups(struct kdbus_meta_proc *mp) +-{ +- const struct group_info *info; +- size_t i; +- +- /* no need to lock/ref, current creds cannot change */ +- info = current_cred()->group_info; +- +- if (info->ngroups > 0) { +- mp->auxgrps = kmalloc_array(info->ngroups, sizeof(kgid_t), +- GFP_KERNEL); +- if (!mp->auxgrps) +- return -ENOMEM; +- +- for (i = 0; i < info->ngroups; i++) +- mp->auxgrps[i] = GROUP_AT(info, i); +- } +- +- mp->n_auxgrps = info->ngroups; +- mp->valid |= KDBUS_ATTACH_AUXGROUPS; +- +- return 0; +-} +- + static void kdbus_meta_proc_collect_tid_comm(struct kdbus_meta_proc *mp) + { + get_task_comm(mp->tid_comm, current); +@@ -340,12 +284,6 @@ static int kdbus_meta_proc_collect_cgroup(struct kdbus_meta_proc *mp) + return 0; + } + +-static void kdbus_meta_proc_collect_caps(struct kdbus_meta_proc *mp) +-{ +- mp->cred = get_current_cred(); +- mp->valid |= KDBUS_ATTACH_CAPS; +-} +- + static int kdbus_meta_proc_collect_seclabel(struct kdbus_meta_proc *mp) + { + #ifdef CONFIG_SECURITY +@@ -412,10 +350,17 @@ int kdbus_meta_proc_collect(struct kdbus_meta_proc *mp, u64 what) + + mutex_lock(&mp->lock); + +- if ((what & KDBUS_ATTACH_CREDS) && +- !(mp->collected & KDBUS_ATTACH_CREDS)) { +- kdbus_meta_proc_collect_creds(mp); +- mp->collected |= KDBUS_ATTACH_CREDS; ++ /* creds, auxgrps and caps share "struct cred" as context */ ++ { ++ const u64 m_cred = KDBUS_ATTACH_CREDS | ++ KDBUS_ATTACH_AUXGROUPS | ++ KDBUS_ATTACH_CAPS; ++ ++ if ((what & m_cred) && !(mp->collected & m_cred)) { ++ mp->cred = get_current_cred(); ++ mp->valid |= m_cred; ++ mp->collected |= m_cred; ++ } + } + + if ((what & KDBUS_ATTACH_PIDS) && +@@ -424,14 +369,6 @@ int kdbus_meta_proc_collect(struct kdbus_meta_proc *mp, u64 what) + mp->collected |= KDBUS_ATTACH_PIDS; + } + +- if ((what & KDBUS_ATTACH_AUXGROUPS) && +- !(mp->collected & KDBUS_ATTACH_AUXGROUPS)) { +- ret = kdbus_meta_proc_collect_auxgroups(mp); +- if (ret < 0) +- goto exit_unlock; +- mp->collected |= KDBUS_ATTACH_AUXGROUPS; +- } +- + if ((what & KDBUS_ATTACH_TID_COMM) && + !(mp->collected & KDBUS_ATTACH_TID_COMM)) { + kdbus_meta_proc_collect_tid_comm(mp); +@@ -466,12 +403,6 @@ int kdbus_meta_proc_collect(struct kdbus_meta_proc *mp, u64 what) + mp->collected |= KDBUS_ATTACH_CGROUP; + } + +- if ((what & KDBUS_ATTACH_CAPS) && +- !(mp->collected & KDBUS_ATTACH_CAPS)) { +- kdbus_meta_proc_collect_caps(mp); +- mp->collected |= KDBUS_ATTACH_CAPS; +- } +- + if ((what & KDBUS_ATTACH_SECLABEL) && + !(mp->collected & KDBUS_ATTACH_SECLABEL)) { + ret = kdbus_meta_proc_collect_seclabel(mp); +@@ -841,7 +772,8 @@ int kdbus_meta_export_prepare(struct kdbus_meta_proc *mp, + size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_pids)); + + if (mp && (*mask & KDBUS_ATTACH_AUXGROUPS)) +- size += KDBUS_ITEM_SIZE(mp->n_auxgrps * sizeof(u64)); ++ size += KDBUS_ITEM_SIZE(mp->cred->group_info->ngroups * ++ sizeof(u64)); + + if (mp && (*mask & KDBUS_ATTACH_TID_COMM)) + size += KDBUS_ITEM_SIZE(strlen(mp->tid_comm) + 1); +@@ -1058,14 +990,16 @@ int kdbus_meta_export(struct kdbus_meta_proc *mp, + cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, KDBUS_ITEM_CREDS, + &creds, sizeof(creds), &size); + } else if (mp && (mask & KDBUS_ATTACH_CREDS)) { +- creds.uid = kdbus_from_kuid_keep(user_ns, mp->uid); +- creds.euid = kdbus_from_kuid_keep(user_ns, mp->euid); +- creds.suid = kdbus_from_kuid_keep(user_ns, mp->suid); +- creds.fsuid = kdbus_from_kuid_keep(user_ns, mp->fsuid); +- creds.gid = kdbus_from_kgid_keep(user_ns, mp->gid); +- creds.egid = kdbus_from_kgid_keep(user_ns, mp->egid); +- creds.sgid = kdbus_from_kgid_keep(user_ns, mp->sgid); +- creds.fsgid = kdbus_from_kgid_keep(user_ns, mp->fsgid); ++ const struct cred *c = mp->cred; ++ ++ creds.uid = kdbus_from_kuid_keep(user_ns, c->uid); ++ creds.euid = kdbus_from_kuid_keep(user_ns, c->euid); ++ creds.suid = kdbus_from_kuid_keep(user_ns, c->suid); ++ creds.fsuid = kdbus_from_kuid_keep(user_ns, c->fsuid); ++ creds.gid = kdbus_from_kgid_keep(user_ns, c->gid); ++ creds.egid = kdbus_from_kgid_keep(user_ns, c->egid); ++ creds.sgid = kdbus_from_kgid_keep(user_ns, c->sgid); ++ creds.fsgid = kdbus_from_kgid_keep(user_ns, c->fsgid); + + cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, KDBUS_ITEM_CREDS, + &creds, sizeof(creds), &size); +@@ -1088,17 +1022,20 @@ int kdbus_meta_export(struct kdbus_meta_proc *mp, + } + + if (mp && (mask & KDBUS_ATTACH_AUXGROUPS)) { +- size_t payload_size = mp->n_auxgrps * sizeof(u64); +- int i; ++ const struct group_info *info = mp->cred->group_info; ++ size_t i, n, payload_size; + ++ n = info->ngroups; ++ payload_size = n * sizeof(u64); + auxgrps = kmalloc(payload_size, GFP_KERNEL); + if (!auxgrps) { + ret = -ENOMEM; + goto exit; + } + +- for (i = 0; i < mp->n_auxgrps; i++) +- auxgrps[i] = from_kgid_munged(user_ns, mp->auxgrps[i]); ++ for (i = 0; i < n; ++i) ++ auxgrps[i] = from_kgid_munged(user_ns, ++ GROUP_AT(info, i)); + + cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, + KDBUS_ITEM_AUXGROUPS, +-- +2.4.3 + + +From 46a0b5df61b398fc58897aaeb3c1e57f210057a7 Mon Sep 17 00:00:00 2001 +From: David Herrmann <dh.herrmann@gmail.com> +Date: Fri, 19 Jun 2015 15:33:34 +0200 +Subject: [PATCH 13/34] kdbus: pass msg-seqnum directly into meta-conn + +Instead of passing the kmsg object into kdbus_meta_conn_collect(), pass +the message sequence number directly. It is the only field that is used +there, so avoid introducing a "kdbus_kmsg" dependency from metadata.h. + +This is also a preparation for an upcoming change to drop 'kdbus_kmsg'. + +Signed-off-by: David Herrmann <dh.herrmann@gmail.com> +--- + ipc/kdbus/connection.c | 3 +-- + ipc/kdbus/message.c | 2 +- + ipc/kdbus/metadata.c | 18 +++++++++--------- + ipc/kdbus/metadata.h | 4 +--- + ipc/kdbus/notify.c | 2 +- + 5 files changed, 13 insertions(+), 16 deletions(-) + +diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c +index 8976bb32ab69..8fcff17ae2b6 100644 +--- a/ipc/kdbus/connection.c ++++ b/ipc/kdbus/connection.c +@@ -1787,8 +1787,7 @@ int kdbus_cmd_conn_info(struct kdbus_conn *conn, void __user *argp) + goto exit; + } + +- ret = kdbus_meta_conn_collect(conn_meta, NULL, owner_conn, +- attach_flags); ++ ret = kdbus_meta_conn_collect(conn_meta, owner_conn, 0, attach_flags); + if (ret < 0) + goto exit; + +diff --git a/ipc/kdbus/message.c b/ipc/kdbus/message.c +index 55e432397b93..974e8c4f6039 100644 +--- a/ipc/kdbus/message.c ++++ b/ipc/kdbus/message.c +@@ -632,5 +632,5 @@ int kdbus_kmsg_collect_metadata(struct kdbus_kmsg *kmsg, struct kdbus_conn *src, + return ret; + } + +- return kdbus_meta_conn_collect(kmsg->conn_meta, kmsg, src, attach); ++ return kdbus_meta_conn_collect(kmsg->conn_meta, src, kmsg->seq, attach); + } +diff --git a/ipc/kdbus/metadata.c b/ipc/kdbus/metadata.c +index 1bac0dda72e0..dcb603798aba 100644 +--- a/ipc/kdbus/metadata.c ++++ b/ipc/kdbus/metadata.c +@@ -589,13 +589,13 @@ struct kdbus_meta_conn *kdbus_meta_conn_unref(struct kdbus_meta_conn *mc) + } + + static void kdbus_meta_conn_collect_timestamp(struct kdbus_meta_conn *mc, +- struct kdbus_kmsg *kmsg) ++ u64 msg_seqnum) + { + mc->ts.monotonic_ns = ktime_get_ns(); + mc->ts.realtime_ns = ktime_get_real_ns(); + +- if (kmsg) +- mc->ts.seqnum = kmsg->seq; ++ if (msg_seqnum) ++ mc->ts.seqnum = msg_seqnum; + + mc->valid |= KDBUS_ATTACH_TIMESTAMP; + } +@@ -657,11 +657,12 @@ static int kdbus_meta_conn_collect_description(struct kdbus_meta_conn *mc, + /** + * kdbus_meta_conn_collect() - Collect connection metadata + * @mc: Message metadata object +- * @kmsg: Kmsg to collect data from + * @conn: Connection to collect data from ++ * @msg_seqnum: Sequence number of the message to send + * @what: Attach flags to collect + * +- * This collects connection metadata from @kmsg and @conn and saves it in @mc. ++ * This collects connection metadata from @msg_seqnum and @conn and saves it ++ * in @mc. + * + * If KDBUS_ATTACH_NAMES is set in @what and @conn is non-NULL, the caller must + * hold the name-registry read-lock of conn->ep->bus->registry. +@@ -669,9 +670,8 @@ static int kdbus_meta_conn_collect_description(struct kdbus_meta_conn *mc, + * Return: 0 on success, negative error code on failure. + */ + int kdbus_meta_conn_collect(struct kdbus_meta_conn *mc, +- struct kdbus_kmsg *kmsg, + struct kdbus_conn *conn, +- u64 what) ++ u64 msg_seqnum, u64 what) + { + int ret; + +@@ -682,9 +682,9 @@ int kdbus_meta_conn_collect(struct kdbus_meta_conn *mc, + + mutex_lock(&mc->lock); + +- if (kmsg && (what & KDBUS_ATTACH_TIMESTAMP) && ++ if (msg_seqnum && (what & KDBUS_ATTACH_TIMESTAMP) && + !(mc->collected & KDBUS_ATTACH_TIMESTAMP)) { +- kdbus_meta_conn_collect_timestamp(mc, kmsg); ++ kdbus_meta_conn_collect_timestamp(mc, msg_seqnum); + mc->collected |= KDBUS_ATTACH_TIMESTAMP; + } + +diff --git a/ipc/kdbus/metadata.h b/ipc/kdbus/metadata.h +index 2fb04dad38d4..c33315d0b82b 100644 +--- a/ipc/kdbus/metadata.h ++++ b/ipc/kdbus/metadata.h +@@ -18,7 +18,6 @@ + #include <linux/kernel.h> + + struct kdbus_conn; +-struct kdbus_kmsg; + struct kdbus_pool_slice; + + struct kdbus_meta_proc; +@@ -70,9 +69,8 @@ struct kdbus_meta_conn *kdbus_meta_conn_new(void); + struct kdbus_meta_conn *kdbus_meta_conn_ref(struct kdbus_meta_conn *mc); + struct kdbus_meta_conn *kdbus_meta_conn_unref(struct kdbus_meta_conn *mc); + int kdbus_meta_conn_collect(struct kdbus_meta_conn *mc, +- struct kdbus_kmsg *kmsg, + struct kdbus_conn *conn, +- u64 what); ++ u64 msg_seqnum, u64 what); + + int kdbus_meta_export_prepare(struct kdbus_meta_proc *mp, + struct kdbus_meta_fake *mf, +diff --git a/ipc/kdbus/notify.c b/ipc/kdbus/notify.c +index e4a454222f09..216720fc26ff 100644 +--- a/ipc/kdbus/notify.c ++++ b/ipc/kdbus/notify.c +@@ -209,7 +209,7 @@ void kdbus_notify_flush(struct kdbus_bus *bus) + spin_unlock(&bus->notify_lock); + + list_for_each_entry_safe(kmsg, tmp, ¬ify_list, notify_entry) { +- kdbus_meta_conn_collect(kmsg->conn_meta, kmsg, NULL, ++ kdbus_meta_conn_collect(kmsg->conn_meta, NULL, kmsg->seq, + KDBUS_ATTACH_TIMESTAMP); + + if (kmsg->msg.dst_id != KDBUS_DST_ID_BROADCAST) { +-- +2.4.3 + + +From 9b7d557456bf4528daaad686b545cd6285602d69 Mon Sep 17 00:00:00 2001 +From: David Herrmann <dh.herrmann@gmail.com> +Date: Fri, 19 Jun 2015 15:37:03 +0200 +Subject: [PATCH 14/34] kdbus: don't include padding in mc->owned_names_size + +Whenever we deal with kdbus-items, we have to distinguish the size of the +items (as written in item->size) and the offset of the next item (which +includes any padding). The KDBUS_ITEM_SIZE() macro always computes the +size *plus* padding, which is a bit misleading. In most cases it's what +you want, but in case of mc->owned_names_size it is not. + +Right now, mc->owned_names_size includes the padding after the last item, +even though that is not strictly part of the items. Furthermore, since we +merge all the OWNED_NAME items into an array, it is not possible to +compute the actual size (minus padding) in O(1). Therefore, change the +collector to *NOT* include the final padding. + +The reason we need this is to make sure msg->size does never include the +padding after the last item. Right now it does, which will be fixed in +follow-up patches. This patch just makes sure we actually know the real +size of the owned_names_items array. + +Signed-off-by: David Herrmann <dh.herrmann@gmail.com> +--- + ipc/kdbus/metadata.c | 15 +++++++++------ + 1 file changed, 9 insertions(+), 6 deletions(-) + +diff --git a/ipc/kdbus/metadata.c b/ipc/kdbus/metadata.c +index dcb603798aba..beb7dbb73d08 100644 +--- a/ipc/kdbus/metadata.c ++++ b/ipc/kdbus/metadata.c +@@ -610,14 +610,16 @@ static int kdbus_meta_conn_collect_names(struct kdbus_meta_conn *mc, + lockdep_assert_held(&conn->ep->bus->name_registry->rwlock); + + size = 0; ++ /* open-code length calculation to avoid final padding */ + list_for_each_entry(e, &conn->names_list, conn_entry) +- size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_name) + +- strlen(e->name) + 1); ++ size = KDBUS_ALIGN8(size) + KDBUS_ITEM_HEADER_SIZE + ++ sizeof(struct kdbus_name) + strlen(e->name) + 1; + + if (!size) + return 0; + +- item = kmalloc(size, GFP_KERNEL); ++ /* make sure we include zeroed padding for convenience helpers */ ++ item = kmalloc(KDBUS_ALIGN8(size), GFP_KERNEL); + if (!item) + return -ENOMEM; + +@@ -634,7 +636,8 @@ static int kdbus_meta_conn_collect_names(struct kdbus_meta_conn *mc, + } + + /* sanity check: the buffer should be completely written now */ +- WARN_ON((u8 *)item != (u8 *)mc->owned_names_items + size); ++ WARN_ON((u8 *)item != ++ (u8 *)mc->owned_names_items + KDBUS_ALIGN8(size)); + + mc->valid |= KDBUS_ATTACH_NAMES; + return 0; +@@ -817,7 +820,7 @@ int kdbus_meta_export_prepare(struct kdbus_meta_proc *mp, + /* connection metadata */ + + if (mc && (*mask & KDBUS_ATTACH_NAMES)) +- size += mc->owned_names_size; ++ size += KDBUS_ALIGN8(mc->owned_names_size); + + if (mc && (*mask & KDBUS_ATTACH_CONN_DESCRIPTION)) + size += KDBUS_ITEM_SIZE(strlen(mc->conn_description) + 1); +@@ -1132,7 +1135,7 @@ int kdbus_meta_export(struct kdbus_meta_proc *mp, + + if (mc && (mask & KDBUS_ATTACH_NAMES)) + kdbus_kvec_set(&kvec[cnt++], mc->owned_names_items, +- mc->owned_names_size, &size); ++ KDBUS_ALIGN8(mc->owned_names_size), &size); + + if (mc && (mask & KDBUS_ATTACH_CONN_DESCRIPTION)) + cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, +-- +2.4.3 + + +From 8c9a45e352f84382e773cec71e8ce5e936f01db5 Mon Sep 17 00:00:00 2001 +From: David Herrmann <dh.herrmann@gmail.com> +Date: Fri, 19 Jun 2015 16:16:30 +0200 +Subject: [PATCH 15/34] kdbus: re-introduce metadata buffers + +This re-introduces the old way of managing metadata. The new +kdbus_meta_emit() function takes metadata sources from the caller and +emits an item buffer of the requested metadata items. The buffer is +allocated dynamically and can be directly used to copy the metadata items +into the pool slice. + +Unlike kdbus_meta_export(), this new function avoids calling into +kdbus_pool_slice and as such the metadata items can be integrated into the +copy-operation of the surrounding objects. We trade one slice-copy for one +kmalloc(), which should speed up most use-cases we care about +significantly. + +Signed-off-by: David Herrmann <dh.herrmann@gmail.com> +--- + ipc/kdbus/metadata.c | 368 ++++++++++++++++++++++++++++++++++++++++++++++++++- + ipc/kdbus/metadata.h | 7 + + 2 files changed, 374 insertions(+), 1 deletion(-) + +diff --git a/ipc/kdbus/metadata.c b/ipc/kdbus/metadata.c +index beb7dbb73d08..70ce5d15fc98 100644 +--- a/ipc/kdbus/metadata.c ++++ b/ipc/kdbus/metadata.c +@@ -847,7 +847,7 @@ static int kdbus_meta_push_kvec(struct kvec *kvec, + } + + static void kdbus_meta_export_caps(struct kdbus_meta_caps *out, +- struct kdbus_meta_proc *mp, ++ const struct kdbus_meta_proc *mp, + struct user_namespace *user_ns) + { + struct user_namespace *iter; +@@ -1161,6 +1161,372 @@ exit: + return ret; + } + ++struct kdbus_meta_staging { ++ const struct kdbus_meta_proc *mp; ++ const struct kdbus_meta_fake *mf; ++ const struct kdbus_meta_conn *mc; ++ const struct kdbus_conn *conn; ++ u64 mask; ++ ++ void *exe; ++ const char *exe_path; ++}; ++ ++static size_t kdbus_meta_measure(struct kdbus_meta_staging *staging) ++{ ++ const struct kdbus_meta_proc *mp = staging->mp; ++ const struct kdbus_meta_fake *mf = staging->mf; ++ const struct kdbus_meta_conn *mc = staging->mc; ++ const u64 mask = staging->mask; ++ size_t size = 0; ++ ++ /* process metadata */ ++ ++ if (mf && (mask & KDBUS_ATTACH_CREDS)) ++ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_creds)); ++ else if (mp && (mask & KDBUS_ATTACH_CREDS)) ++ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_creds)); ++ ++ if (mf && (mask & KDBUS_ATTACH_PIDS)) ++ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_pids)); ++ else if (mp && (mask & KDBUS_ATTACH_PIDS)) ++ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_pids)); ++ ++ if (mp && (mask & KDBUS_ATTACH_AUXGROUPS)) ++ size += KDBUS_ITEM_SIZE(mp->cred->group_info->ngroups * ++ sizeof(u64)); ++ ++ if (mp && (mask & KDBUS_ATTACH_TID_COMM)) ++ size += KDBUS_ITEM_SIZE(strlen(mp->tid_comm) + 1); ++ ++ if (mp && (mask & KDBUS_ATTACH_PID_COMM)) ++ size += KDBUS_ITEM_SIZE(strlen(mp->pid_comm) + 1); ++ ++ if (staging->exe_path && (mask & KDBUS_ATTACH_EXE)) ++ size += KDBUS_ITEM_SIZE(strlen(staging->exe_path) + 1); ++ ++ if (mp && (mask & KDBUS_ATTACH_CMDLINE)) ++ size += KDBUS_ITEM_SIZE(strlen(mp->cmdline) + 1); ++ ++ if (mp && (mask & KDBUS_ATTACH_CGROUP)) ++ size += KDBUS_ITEM_SIZE(strlen(mp->cgroup) + 1); ++ ++ if (mp && (mask & KDBUS_ATTACH_CAPS)) ++ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_meta_caps)); ++ ++ if (mf && (mask & KDBUS_ATTACH_SECLABEL)) ++ size += KDBUS_ITEM_SIZE(strlen(mf->seclabel) + 1); ++ else if (mp && (mask & KDBUS_ATTACH_SECLABEL)) ++ size += KDBUS_ITEM_SIZE(strlen(mp->seclabel) + 1); ++ ++ if (mp && (mask & KDBUS_ATTACH_AUDIT)) ++ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_audit)); ++ ++ /* connection metadata */ ++ ++ if (mc && (mask & KDBUS_ATTACH_NAMES)) ++ size += KDBUS_ALIGN8(mc->owned_names_size); ++ ++ if (mc && (mask & KDBUS_ATTACH_CONN_DESCRIPTION)) ++ size += KDBUS_ITEM_SIZE(strlen(mc->conn_description) + 1); ++ ++ if (mc && (mask & KDBUS_ATTACH_TIMESTAMP)) ++ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_timestamp)); ++ ++ return size; ++} ++ ++static struct kdbus_item *kdbus_write_head(struct kdbus_item **iter, ++ u64 type, u64 size) ++{ ++ struct kdbus_item *item = *iter; ++ size_t padding; ++ ++ item->type = type; ++ item->size = KDBUS_ITEM_HEADER_SIZE + size; ++ ++ /* clear padding */ ++ padding = KDBUS_ALIGN8(item->size) - item->size; ++ if (padding) ++ memset(item->data + size, 0, padding); ++ ++ *iter = KDBUS_ITEM_NEXT(item); ++ return item; ++} ++ ++static struct kdbus_item *kdbus_write_full(struct kdbus_item **iter, ++ u64 type, u64 size, const void *data) ++{ ++ struct kdbus_item *item; ++ ++ item = kdbus_write_head(iter, type, size); ++ memcpy(item->data, data, size); ++ return item; ++} ++ ++static size_t kdbus_meta_write(struct kdbus_meta_staging *staging, void *mem, ++ size_t size) ++{ ++ struct user_namespace *user_ns = staging->conn->user_ns; ++ struct pid_namespace *pid_ns = staging->conn->pid_ns; ++ struct kdbus_item *item = NULL, *items = mem; ++ u8 *end, *owned_names_end = NULL; ++ ++ /* process metadata */ ++ ++ if (staging->mf && (staging->mask & KDBUS_ATTACH_CREDS)) { ++ const struct kdbus_meta_fake *mf = staging->mf; ++ ++ item = kdbus_write_head(&items, KDBUS_ITEM_CREDS, ++ sizeof(struct kdbus_creds)); ++ item->creds = (struct kdbus_creds){ ++ .uid = kdbus_from_kuid_keep(user_ns, mf->uid), ++ .euid = kdbus_from_kuid_keep(user_ns, mf->euid), ++ .suid = kdbus_from_kuid_keep(user_ns, mf->suid), ++ .fsuid = kdbus_from_kuid_keep(user_ns, mf->fsuid), ++ .gid = kdbus_from_kgid_keep(user_ns, mf->gid), ++ .egid = kdbus_from_kgid_keep(user_ns, mf->egid), ++ .sgid = kdbus_from_kgid_keep(user_ns, mf->sgid), ++ .fsgid = kdbus_from_kgid_keep(user_ns, mf->fsgid), ++ }; ++ } else if (staging->mp && (staging->mask & KDBUS_ATTACH_CREDS)) { ++ const struct cred *c = staging->mp->cred; ++ ++ item = kdbus_write_head(&items, KDBUS_ITEM_CREDS, ++ sizeof(struct kdbus_creds)); ++ item->creds = (struct kdbus_creds){ ++ .uid = kdbus_from_kuid_keep(user_ns, c->uid), ++ .euid = kdbus_from_kuid_keep(user_ns, c->euid), ++ .suid = kdbus_from_kuid_keep(user_ns, c->suid), ++ .fsuid = kdbus_from_kuid_keep(user_ns, c->fsuid), ++ .gid = kdbus_from_kgid_keep(user_ns, c->gid), ++ .egid = kdbus_from_kgid_keep(user_ns, c->egid), ++ .sgid = kdbus_from_kgid_keep(user_ns, c->sgid), ++ .fsgid = kdbus_from_kgid_keep(user_ns, c->fsgid), ++ }; ++ } ++ ++ if (staging->mf && (staging->mask & KDBUS_ATTACH_PIDS)) { ++ item = kdbus_write_head(&items, KDBUS_ITEM_PIDS, ++ sizeof(struct kdbus_pids)); ++ item->pids = (struct kdbus_pids){ ++ .pid = pid_nr_ns(staging->mf->tgid, pid_ns), ++ .tid = pid_nr_ns(staging->mf->pid, pid_ns), ++ .ppid = pid_nr_ns(staging->mf->ppid, pid_ns), ++ }; ++ } else if (staging->mp && (staging->mask & KDBUS_ATTACH_PIDS)) { ++ item = kdbus_write_head(&items, KDBUS_ITEM_PIDS, ++ sizeof(struct kdbus_pids)); ++ item->pids = (struct kdbus_pids){ ++ .pid = pid_nr_ns(staging->mp->tgid, pid_ns), ++ .tid = pid_nr_ns(staging->mp->pid, pid_ns), ++ .ppid = pid_nr_ns(staging->mp->ppid, pid_ns), ++ }; ++ } ++ ++ if (staging->mp && (staging->mask & KDBUS_ATTACH_AUXGROUPS)) { ++ const struct group_info *info = staging->mp->cred->group_info; ++ size_t i; ++ ++ item = kdbus_write_head(&items, KDBUS_ITEM_AUXGROUPS, ++ info->ngroups * sizeof(u64)); ++ for (i = 0; i < info->ngroups; ++i) ++ item->data64[i] = from_kgid_munged(user_ns, ++ GROUP_AT(info, i)); ++ } ++ ++ if (staging->mp && (staging->mask & KDBUS_ATTACH_TID_COMM)) ++ item = kdbus_write_full(&items, KDBUS_ITEM_TID_COMM, ++ strlen(staging->mp->tid_comm) + 1, ++ staging->mp->tid_comm); ++ ++ if (staging->mp && (staging->mask & KDBUS_ATTACH_PID_COMM)) ++ item = kdbus_write_full(&items, KDBUS_ITEM_PID_COMM, ++ strlen(staging->mp->pid_comm) + 1, ++ staging->mp->pid_comm); ++ ++ if (staging->exe_path && (staging->mask & KDBUS_ATTACH_EXE)) ++ item = kdbus_write_full(&items, KDBUS_ITEM_EXE, ++ strlen(staging->exe_path) + 1, ++ staging->exe_path); ++ ++ if (staging->mp && (staging->mask & KDBUS_ATTACH_CMDLINE)) ++ item = kdbus_write_full(&items, KDBUS_ITEM_CMDLINE, ++ strlen(staging->mp->cmdline) + 1, ++ staging->mp->cmdline); ++ ++ if (staging->mp && (staging->mask & KDBUS_ATTACH_CGROUP)) ++ item = kdbus_write_full(&items, KDBUS_ITEM_CGROUP, ++ strlen(staging->mp->cgroup) + 1, ++ staging->mp->cgroup); ++ ++ if (staging->mp && (staging->mask & KDBUS_ATTACH_CAPS)) { ++ item = kdbus_write_head(&items, KDBUS_ITEM_CAPS, ++ sizeof(struct kdbus_meta_caps)); ++ kdbus_meta_export_caps((void*)&item->caps, staging->mp, ++ user_ns); ++ } ++ ++ if (staging->mf && (staging->mask & KDBUS_ATTACH_SECLABEL)) ++ item = kdbus_write_full(&items, KDBUS_ITEM_SECLABEL, ++ strlen(staging->mf->seclabel) + 1, ++ staging->mf->seclabel); ++ else if (staging->mp && (staging->mask & KDBUS_ATTACH_SECLABEL)) ++ item = kdbus_write_full(&items, KDBUS_ITEM_SECLABEL, ++ strlen(staging->mp->seclabel) + 1, ++ staging->mp->seclabel); ++ ++ if (staging->mp && (staging->mask & KDBUS_ATTACH_AUDIT)) { ++ item = kdbus_write_head(&items, KDBUS_ITEM_AUDIT, ++ sizeof(struct kdbus_audit)); ++ item->audit = (struct kdbus_audit){ ++ .loginuid = from_kuid(user_ns, ++ staging->mp->audit_loginuid), ++ .sessionid = staging->mp->audit_sessionid, ++ }; ++ } ++ ++ /* connection metadata */ ++ ++ if (staging->mc && (staging->mask & KDBUS_ATTACH_NAMES)) { ++ memcpy(items, staging->mc->owned_names_items, ++ KDBUS_ALIGN8(staging->mc->owned_names_size)); ++ owned_names_end = (u8 *)items + staging->mc->owned_names_size; ++ items = (void *)KDBUS_ALIGN8((unsigned long)owned_names_end); ++ } ++ ++ if (staging->mc && (staging->mask & KDBUS_ATTACH_CONN_DESCRIPTION)) ++ item = kdbus_write_full(&items, KDBUS_ITEM_CONN_DESCRIPTION, ++ strlen(staging->mc->conn_description) + 1, ++ staging->mc->conn_description); ++ ++ if (staging->mc && (staging->mask & KDBUS_ATTACH_TIMESTAMP)) ++ item = kdbus_write_full(&items, KDBUS_ITEM_TIMESTAMP, ++ sizeof(staging->mc->ts), ++ &staging->mc->ts); ++ ++ /* ++ * Return real size (minus trailing padding). In case of 'owned_names' ++ * we cannot deduce it from item->size, so treat it special. ++ */ ++ ++ if (items == (void *)KDBUS_ALIGN8((unsigned long)owned_names_end)) ++ end = owned_names_end; ++ else if (item) ++ end = (u8 *)item + item->size; ++ else ++ end = mem; ++ ++ WARN_ON((u8 *)items - (u8 *)mem != size); ++ WARN_ON((void *)KDBUS_ALIGN8((unsigned long)end) != (void *)items); ++ ++ return end - (u8 *)mem; ++} ++ ++int kdbus_meta_emit(struct kdbus_meta_proc *mp, ++ struct kdbus_meta_fake *mf, ++ struct kdbus_meta_conn *mc, ++ struct kdbus_conn *conn, ++ u64 mask, ++ struct kdbus_item **out_items, ++ size_t *out_size) ++{ ++ struct kdbus_meta_staging staging = {}; ++ struct kdbus_item *items = NULL; ++ size_t size = 0; ++ int ret; ++ ++ if (WARN_ON(mf && mp)) ++ mp = NULL; ++ ++ staging.mp = mp; ++ staging.mf = mf; ++ staging.mc = mc; ++ staging.conn = conn; ++ ++ /* get mask of valid items */ ++ if (mf) ++ staging.mask |= mf->valid; ++ if (mp) { ++ mutex_lock(&mp->lock); ++ staging.mask |= mp->valid; ++ mutex_unlock(&mp->lock); ++ } ++ if (mc) { ++ mutex_lock(&mc->lock); ++ staging.mask |= mc->valid; ++ mutex_unlock(&mc->lock); ++ } ++ ++ staging.mask &= mask; ++ ++ if (!staging.mask) { /* bail out if nothing to do */ ++ ret = 0; ++ goto exit; ++ } ++ ++ /* EXE is special as it needs a temporary page to assemble */ ++ if (mp && (staging.mask & KDBUS_ATTACH_EXE)) { ++ struct path p; ++ ++ /* ++ * XXX: We need access to __d_path() so we can write the path ++ * relative to conn->root_path. Once upstream, we need ++ * EXPORT_SYMBOL(__d_path) or an equivalent of d_path() that ++ * takes the root path directly. Until then, we drop this item ++ * if the root-paths differ. ++ */ ++ ++ get_fs_root(current->fs, &p); ++ if (path_equal(&p, &conn->root_path)) { ++ staging.exe = (void *)__get_free_page(GFP_TEMPORARY); ++ if (!staging.exe) { ++ path_put(&p); ++ ret = -ENOMEM; ++ goto exit; ++ } ++ ++ staging.exe_path = d_path(&mp->exe_path, staging.exe, ++ PAGE_SIZE); ++ if (IS_ERR(staging.exe_path)) { ++ path_put(&p); ++ ret = PTR_ERR(staging.exe_path); ++ goto exit; ++ } ++ } ++ path_put(&p); ++ } ++ ++ size = kdbus_meta_measure(&staging); ++ if (!size) { /* bail out if nothing to do */ ++ ret = 0; ++ goto exit; ++ } ++ ++ items = kmalloc(size, GFP_KERNEL); ++ if (!items) { ++ ret = -ENOMEM; ++ goto exit; ++ } ++ ++ size = kdbus_meta_write(&staging, items, size); ++ if (!size) { ++ kfree(items); ++ items = NULL; ++ } ++ ++ ret = 0; ++ ++exit: ++ if (staging.exe) ++ free_page((unsigned long)staging.exe); ++ if (ret >= 0) { ++ *out_items = items; ++ *out_size = size; ++ } ++ return ret; ++} ++ + /** + * kdbus_meta_calc_attach_flags() - calculate attach flags for a sender + * and a receiver +diff --git a/ipc/kdbus/metadata.h b/ipc/kdbus/metadata.h +index c33315d0b82b..a30b0ad26af2 100644 +--- a/ipc/kdbus/metadata.h ++++ b/ipc/kdbus/metadata.h +@@ -83,6 +83,13 @@ int kdbus_meta_export(struct kdbus_meta_proc *mp, + u64 mask, + struct kdbus_pool_slice *slice, + off_t offset, size_t *real_size); ++int kdbus_meta_emit(struct kdbus_meta_proc *mp, ++ struct kdbus_meta_fake *mf, ++ struct kdbus_meta_conn *mc, ++ struct kdbus_conn *conn, ++ u64 mask, ++ struct kdbus_item **out_items, ++ size_t *out_size); + u64 kdbus_meta_calc_attach_flags(const struct kdbus_conn *sender, + const struct kdbus_conn *receiver); + +-- +2.4.3 + + +From fd856bf056f3737c73aefe34f55799b34919699b Mon Sep 17 00:00:00 2001 +From: David Herrmann <dh.herrmann@gmail.com> +Date: Fri, 19 Jun 2015 16:46:30 +0200 +Subject: [PATCH 16/34] kdbus: speed up KDBUS_CMD_*_INFO by using meta_emit() + +Avoid using kdbus_meta_export*() and switch to kdbus_meta_emit(). This +adds one kmalloc(), but on the other hand drops a call to +kdbus_pool_slice_copy_kvec(). As the latter is way more expensive, this +speeds up KDBUS_CMD_*_INFO ioctls by approx. 10%. + +Signed-off-by: David Herrmann <dh.herrmann@gmail.com> +--- + ipc/kdbus/bus.c | 40 +++++++++++++++++++--------------------- + ipc/kdbus/connection.c | 42 +++++++++++++++++++++--------------------- + 2 files changed, 40 insertions(+), 42 deletions(-) + +diff --git a/ipc/kdbus/bus.c b/ipc/kdbus/bus.c +index dd1e600b8f01..82b7171f1fdb 100644 +--- a/ipc/kdbus/bus.c ++++ b/ipc/kdbus/bus.c +@@ -456,13 +456,12 @@ int kdbus_cmd_bus_creator_info(struct kdbus_conn *conn, void __user *argp) + struct kdbus_cmd_info *cmd; + struct kdbus_bus *bus = conn->ep->bus; + struct kdbus_pool_slice *slice = NULL; ++ struct kdbus_item *meta_items = NULL; + struct kdbus_item_header item_hdr; + struct kdbus_info info = {}; +- size_t meta_size, name_len; +- struct kvec kvec[5]; +- u64 hdr_size = 0; +- u64 attach_flags; +- size_t cnt = 0; ++ size_t meta_size, name_len, cnt = 0; ++ struct kvec kvec[6]; ++ u64 attach_flags, size = 0; + int ret; + + struct kdbus_arg argv[] = { +@@ -484,8 +483,8 @@ int kdbus_cmd_bus_creator_info(struct kdbus_conn *conn, void __user *argp) + + attach_flags &= bus->attach_flags_owner; + +- ret = kdbus_meta_export_prepare(bus->creator_meta, NULL, NULL, +- &attach_flags, &meta_size); ++ ret = kdbus_meta_emit(bus->creator_meta, NULL, NULL, conn, ++ attach_flags, &meta_items, &meta_size); + if (ret < 0) + goto exit; + +@@ -495,26 +494,25 @@ int kdbus_cmd_bus_creator_info(struct kdbus_conn *conn, void __user *argp) + item_hdr.type = KDBUS_ITEM_MAKE_NAME; + item_hdr.size = KDBUS_ITEM_HEADER_SIZE + name_len; + +- kdbus_kvec_set(&kvec[cnt++], &info, sizeof(info), &hdr_size); +- kdbus_kvec_set(&kvec[cnt++], &item_hdr, sizeof(item_hdr), &hdr_size); +- kdbus_kvec_set(&kvec[cnt++], bus->node.name, name_len, &hdr_size); +- cnt += !!kdbus_kvec_pad(&kvec[cnt], &hdr_size); ++ kdbus_kvec_set(&kvec[cnt++], &info, sizeof(info), &size); ++ kdbus_kvec_set(&kvec[cnt++], &item_hdr, sizeof(item_hdr), &size); ++ kdbus_kvec_set(&kvec[cnt++], bus->node.name, name_len, &size); ++ cnt += !!kdbus_kvec_pad(&kvec[cnt], &size); ++ if (meta_size > 0) { ++ kdbus_kvec_set(&kvec[cnt++], meta_items, meta_size, &size); ++ cnt += !!kdbus_kvec_pad(&kvec[cnt], &size); ++ } ++ ++ info.size = size; + +- slice = kdbus_pool_slice_alloc(conn->pool, hdr_size + meta_size, false); ++ slice = kdbus_pool_slice_alloc(conn->pool, size, false); + if (IS_ERR(slice)) { + ret = PTR_ERR(slice); + slice = NULL; + goto exit; + } + +- ret = kdbus_meta_export(bus->creator_meta, NULL, NULL, conn, +- attach_flags, slice, hdr_size, &meta_size); +- if (ret < 0) +- goto exit; +- +- info.size = hdr_size + meta_size; +- +- ret = kdbus_pool_slice_copy_kvec(slice, 0, kvec, cnt, hdr_size); ++ ret = kdbus_pool_slice_copy_kvec(slice, 0, kvec, cnt, size); + if (ret < 0) + goto exit; + +@@ -527,6 +525,6 @@ int kdbus_cmd_bus_creator_info(struct kdbus_conn *conn, void __user *argp) + + exit: + kdbus_pool_slice_release(slice); +- ++ kfree(meta_items); + return kdbus_args_clear(&args, ret); + } +diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c +index 8fcff17ae2b6..7b800b299caf 100644 +--- a/ipc/kdbus/connection.c ++++ b/ipc/kdbus/connection.c +@@ -1718,13 +1718,14 @@ int kdbus_cmd_conn_info(struct kdbus_conn *conn, void __user *argp) + struct kdbus_pool_slice *slice = NULL; + struct kdbus_name_entry *entry = NULL; + struct kdbus_conn *owner_conn = NULL; ++ struct kdbus_item *meta_items = NULL; + struct kdbus_info info = {}; + struct kdbus_cmd_info *cmd; + struct kdbus_bus *bus = conn->ep->bus; +- struct kvec kvec; +- size_t meta_size; ++ struct kvec kvec[3]; ++ size_t meta_size, cnt = 0; + const char *name; +- u64 attach_flags; ++ u64 attach_flags, size = 0; + int ret; + + struct kdbus_arg argv[] = { +@@ -1774,10 +1775,6 @@ int kdbus_cmd_conn_info(struct kdbus_conn *conn, void __user *argp) + goto exit; + } + +- info.id = owner_conn->id; +- info.flags = owner_conn->flags; +- kdbus_kvec_set(&kvec, &info, sizeof(info), &info.size); +- + attach_flags &= atomic64_read(&owner_conn->attach_flags_send); + + conn_meta = kdbus_meta_conn_new(); +@@ -1791,29 +1788,31 @@ int kdbus_cmd_conn_info(struct kdbus_conn *conn, void __user *argp) + if (ret < 0) + goto exit; + +- ret = kdbus_meta_export_prepare(owner_conn->meta_proc, +- owner_conn->meta_fake, conn_meta, +- &attach_flags, &meta_size); ++ ret = kdbus_meta_emit(owner_conn->meta_proc, owner_conn->meta_fake, ++ conn_meta, conn, attach_flags, ++ &meta_items, &meta_size); + if (ret < 0) + goto exit; + +- slice = kdbus_pool_slice_alloc(conn->pool, +- info.size + meta_size, false); ++ info.id = owner_conn->id; ++ info.flags = owner_conn->flags; ++ ++ kdbus_kvec_set(&kvec[cnt++], &info, sizeof(info), &size); ++ if (meta_size > 0) { ++ kdbus_kvec_set(&kvec[cnt++], meta_items, meta_size, &size); ++ cnt += !!kdbus_kvec_pad(&kvec[cnt], &size); ++ } ++ ++ info.size = size; ++ ++ slice = kdbus_pool_slice_alloc(conn->pool, size, false); + if (IS_ERR(slice)) { + ret = PTR_ERR(slice); + slice = NULL; + goto exit; + } + +- ret = kdbus_meta_export(owner_conn->meta_proc, owner_conn->meta_fake, +- conn_meta, conn, attach_flags, +- slice, sizeof(info), &meta_size); +- if (ret < 0) +- goto exit; +- +- info.size += meta_size; +- +- ret = kdbus_pool_slice_copy_kvec(slice, 0, &kvec, 1, sizeof(info)); ++ ret = kdbus_pool_slice_copy_kvec(slice, 0, kvec, cnt, size); + if (ret < 0) + goto exit; + +@@ -1831,6 +1830,7 @@ int kdbus_cmd_conn_info(struct kdbus_conn *conn, void __user *argp) + exit: + up_read(&bus->name_registry->rwlock); + kdbus_pool_slice_release(slice); ++ kfree(meta_items); + kdbus_meta_conn_unref(conn_meta); + kdbus_conn_unref(owner_conn); + return kdbus_args_clear(&args, ret); +-- +2.4.3 + + +From b410b7c6a9e90977dd14d6da72f8e5fd39f04e0b Mon Sep 17 00:00:00 2001 +From: David Herrmann <dh.herrmann@gmail.com> +Date: Fri, 19 Jun 2015 21:34:08 +0200 +Subject: [PATCH 17/34] kdbus: simplify kdbus_match_rules() + +Split up the huge kdbus_match_rules() helper into 3 helper functions. This +reduces the code size almost by half, as we no longer have to maintain 4 +levels of indentation. + +No functional change. + +Signed-off-by: David Herrmann <dh.herrmann@gmail.com> +--- + ipc/kdbus/match.c | 123 +++++++++++++++++++++--------------------------------- + 1 file changed, 48 insertions(+), 75 deletions(-) + +diff --git a/ipc/kdbus/match.c b/ipc/kdbus/match.c +index cc083b4211de..869a9fbce37d 100644 +--- a/ipc/kdbus/match.c ++++ b/ipc/kdbus/match.c +@@ -204,87 +204,60 @@ static bool kdbus_match_bloom(const struct kdbus_bloom_filter *filter, + return true; + } + +-static bool kdbus_match_rules(const struct kdbus_match_entry *entry, +- struct kdbus_conn *conn_src, +- struct kdbus_kmsg *kmsg) ++static bool kdbus_match_rule_conn(const struct kdbus_match_rule *r, ++ struct kdbus_conn *c, ++ const struct kdbus_kmsg *kmsg) + { +- struct kdbus_match_rule *r; +- +- if (conn_src) +- lockdep_assert_held(&conn_src->ep->bus->name_registry->rwlock); +- +- /* +- * Walk all the rules and bail out immediately +- * if any of them is unsatisfied. +- */ +- +- list_for_each_entry(r, &entry->rules_list, rules_entry) { +- if (conn_src) { +- /* messages from userspace */ +- +- switch (r->type) { +- case KDBUS_ITEM_BLOOM_MASK: +- if (!kdbus_match_bloom(kmsg->bloom_filter, +- &r->bloom_mask, +- conn_src)) +- return false; +- break; +- +- case KDBUS_ITEM_ID: +- if (r->src_id != conn_src->id && +- r->src_id != KDBUS_MATCH_ID_ANY) +- return false; +- +- break; ++ lockdep_assert_held(&c->ep->bus->name_registry->rwlock); + +- case KDBUS_ITEM_NAME: +- if (!kdbus_conn_has_name(conn_src, r->name)) +- return false; +- +- break; +- +- default: +- return false; +- } +- } else { +- /* kernel notifications */ +- +- if (kmsg->notify_type != r->type) +- return false; +- +- switch (r->type) { +- case KDBUS_ITEM_ID_ADD: +- if (r->new_id != KDBUS_MATCH_ID_ANY && +- r->new_id != kmsg->notify_new_id) +- return false; +- +- break; +- +- case KDBUS_ITEM_ID_REMOVE: +- if (r->old_id != KDBUS_MATCH_ID_ANY && +- r->old_id != kmsg->notify_old_id) +- return false; ++ switch (r->type) { ++ case KDBUS_ITEM_BLOOM_MASK: ++ return kdbus_match_bloom(kmsg->bloom_filter, &r->bloom_mask, c); ++ case KDBUS_ITEM_ID: ++ return r->src_id == c->id || r->src_id == KDBUS_MATCH_ID_ANY; ++ case KDBUS_ITEM_NAME: ++ return kdbus_conn_has_name(c, r->name); ++ default: ++ return false; ++ } ++} + +- break; ++static bool kdbus_match_rule_kernel(const struct kdbus_match_rule *r, ++ const struct kdbus_kmsg *kmsg) ++{ ++ if (kmsg->notify_type != r->type) ++ return false; + +- case KDBUS_ITEM_NAME_ADD: +- case KDBUS_ITEM_NAME_CHANGE: +- case KDBUS_ITEM_NAME_REMOVE: +- if ((r->old_id != KDBUS_MATCH_ID_ANY && +- r->old_id != kmsg->notify_old_id) || +- (r->new_id != KDBUS_MATCH_ID_ANY && +- r->new_id != kmsg->notify_new_id) || +- (r->name && kmsg->notify_name && +- strcmp(r->name, kmsg->notify_name) != 0)) +- return false; ++ switch (r->type) { ++ case KDBUS_ITEM_ID_ADD: ++ return r->new_id == KDBUS_MATCH_ID_ANY || ++ r->new_id == kmsg->notify_new_id; ++ case KDBUS_ITEM_ID_REMOVE: ++ return r->old_id == KDBUS_MATCH_ID_ANY || ++ r->old_id == kmsg->notify_old_id; ++ case KDBUS_ITEM_NAME_ADD: ++ case KDBUS_ITEM_NAME_CHANGE: ++ case KDBUS_ITEM_NAME_REMOVE: ++ return (r->old_id == KDBUS_MATCH_ID_ANY || ++ r->old_id == kmsg->notify_old_id) && ++ (r->new_id == KDBUS_MATCH_ID_ANY || ++ r->new_id == kmsg->notify_new_id) && ++ (!r->name || !strcmp(r->name, kmsg->notify_name)); ++ default: ++ return false; ++ } ++} + +- break; ++static bool kdbus_match_rules(const struct kdbus_match_entry *entry, ++ struct kdbus_conn *c, ++ const struct kdbus_kmsg *kmsg) ++{ ++ struct kdbus_match_rule *r; + +- default: +- return false; +- } +- } +- } ++ list_for_each_entry(r, &entry->rules_list, rules_entry) ++ if ((c && !kdbus_match_rule_conn(r, c, kmsg)) || ++ (!c && !kdbus_match_rule_kernel(r, kmsg))) ++ return false; + + return true; + } +-- +2.4.3 + + +From c4146fd608177530fb3f6c6ad6e395d3fb0eee4e Mon Sep 17 00:00:00 2001 +From: David Herrmann <dh.herrmann@gmail.com> +Date: Fri, 19 Jun 2015 21:39:25 +0200 +Subject: [PATCH 18/34] kdbus: pass notification details directly into policy + wrapper + +Avoid passing the kmsg into the policy wrapper, but pass the notification +details directly. This reduces the scope of 'struct kdbus_kmsg' and avoids +accessing its members directly. This will ease the introduction of the +kmsg rework later on. + +Signed-off-by: David Herrmann <dh.herrmann@gmail.com> +--- + ipc/kdbus/bus.c | 3 ++- + ipc/kdbus/connection.c | 18 ++++++++---------- + ipc/kdbus/connection.h | 2 +- + 3 files changed, 11 insertions(+), 12 deletions(-) + +diff --git a/ipc/kdbus/bus.c b/ipc/kdbus/bus.c +index 82b7171f1fdb..3c33339cf332 100644 +--- a/ipc/kdbus/bus.c ++++ b/ipc/kdbus/bus.c +@@ -298,7 +298,8 @@ void kdbus_bus_broadcast(struct kdbus_bus *bus, + * notification + */ + if (!kdbus_conn_policy_see_notification(conn_dst, NULL, +- kmsg)) ++ kmsg->notify_type, ++ kmsg->notify_name)) + continue; + } + +diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c +index 7b800b299caf..73cad58d2acd 100644 +--- a/ipc/kdbus/connection.c ++++ b/ipc/kdbus/connection.c +@@ -1542,19 +1542,18 @@ static bool kdbus_conn_policy_see(struct kdbus_conn *conn, + * receive a given kernel notification + * @conn: Connection + * @conn_creds: Credentials of @conn to use for policy check +- * @kmsg: The message carrying the notification ++ * @type: Type of notification ++ * @name: Well-known name this notification is about, or NULL + * +- * This checks whether @conn is allowed to see the kernel notification @kmsg. ++ * This checks whether @conn is allowed to see the kernel notification of type ++ * @type for well-known name @name. + * + * Return: true if allowed, false if not. + */ + bool kdbus_conn_policy_see_notification(struct kdbus_conn *conn, + const struct cred *conn_creds, +- const struct kdbus_kmsg *kmsg) ++ u64 type, const char *name) + { +- if (WARN_ON(kmsg->msg.src_id != KDBUS_SRC_ID_KERNEL)) +- return false; +- + /* + * Depending on the notification type, broadcasted kernel notifications + * have to be filtered: +@@ -1567,12 +1566,11 @@ bool kdbus_conn_policy_see_notification(struct kdbus_conn *conn, + * broadcast to everyone, to allow tracking peers. + */ + +- switch (kmsg->notify_type) { ++ switch (type) { + case KDBUS_ITEM_NAME_ADD: + case KDBUS_ITEM_NAME_REMOVE: + case KDBUS_ITEM_NAME_CHANGE: +- return kdbus_conn_policy_see_name(conn, conn_creds, +- kmsg->notify_name); ++ return kdbus_conn_policy_see_name(conn, conn_creds, name); + + case KDBUS_ITEM_ID_ADD: + case KDBUS_ITEM_ID_REMOVE: +@@ -1580,7 +1578,7 @@ bool kdbus_conn_policy_see_notification(struct kdbus_conn *conn, + + default: + WARN(1, "Invalid type for notification broadcast: %llu\n", +- (unsigned long long)kmsg->notify_type); ++ (unsigned long long)type); + return false; + } + } +diff --git a/ipc/kdbus/connection.h b/ipc/kdbus/connection.h +index 0eb3d2e70a5e..aa4234a4e3e4 100644 +--- a/ipc/kdbus/connection.h ++++ b/ipc/kdbus/connection.h +@@ -152,7 +152,7 @@ bool kdbus_conn_policy_see_name_unlocked(struct kdbus_conn *conn, + const char *name); + bool kdbus_conn_policy_see_notification(struct kdbus_conn *conn, + const struct cred *curr_creds, +- const struct kdbus_kmsg *kmsg); ++ u64 type, const char *name); + + /* command dispatcher */ + struct kdbus_conn *kdbus_cmd_hello(struct kdbus_ep *ep, bool privileged, +-- +2.4.3 + + +From bdac38baecf3b1af14b647f791a795a91ef7f6c6 Mon Sep 17 00:00:00 2001 +From: David Herrmann <dh.herrmann@gmail.com> +Date: Fri, 19 Jun 2015 21:46:39 +0200 +Subject: [PATCH 19/34] kdbus: pass source connection to queue handling + +Make sure we always pass the source-connection of a message along. Right +now we drop it for queue allocation, which prevents us from accessing any +source details in the queue helpers. We work around this, by passing +everything manually, but that just makes things more complex. + +Pass the source connection down to the queue helpers to allow further +cleanups in follow up patches. + +Signed-off-by: David Herrmann <dh.herrmann@gmail.com> +--- + ipc/kdbus/connection.c | 15 +++++++-------- + ipc/kdbus/queue.c | 9 +++++---- + ipc/kdbus/queue.h | 6 +++--- + 3 files changed, 15 insertions(+), 15 deletions(-) + +diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c +index 73cad58d2acd..f1667df70b7f 100644 +--- a/ipc/kdbus/connection.c ++++ b/ipc/kdbus/connection.c +@@ -779,9 +779,9 @@ void kdbus_conn_lost_message(struct kdbus_conn *c) + + /* Callers should take the conn_dst lock */ + static struct kdbus_queue_entry * +-kdbus_conn_entry_make(struct kdbus_conn *conn_dst, +- const struct kdbus_kmsg *kmsg, +- struct kdbus_user *user) ++kdbus_conn_entry_make(struct kdbus_conn *conn_src, ++ struct kdbus_conn *conn_dst, ++ const struct kdbus_kmsg *kmsg) + { + /* The remote connection was disconnected */ + if (!kdbus_conn_active(conn_dst)) +@@ -799,7 +799,7 @@ kdbus_conn_entry_make(struct kdbus_conn *conn_dst, + kmsg->res && kmsg->res->fds_count > 0) + return ERR_PTR(-ECOMM); + +- return kdbus_queue_entry_new(conn_dst, kmsg, user); ++ return kdbus_queue_entry_new(conn_src, conn_dst, kmsg); + } + + /* +@@ -822,8 +822,8 @@ static int kdbus_conn_entry_sync_attach(struct kdbus_conn *conn_dst, + * entry and attach it to the reply object + */ + if (reply_wake->waiting) { +- entry = kdbus_conn_entry_make(conn_dst, kmsg, +- reply_wake->reply_src->user); ++ entry = kdbus_conn_entry_make(reply_wake->reply_src, conn_dst, ++ kmsg); + if (IS_ERR(entry)) + ret = PTR_ERR(entry); + else +@@ -879,8 +879,7 @@ int kdbus_conn_entry_insert(struct kdbus_conn *conn_src, + + kdbus_conn_lock2(conn_src, conn_dst); + +- entry = kdbus_conn_entry_make(conn_dst, kmsg, +- conn_src ? conn_src->user : NULL); ++ entry = kdbus_conn_entry_make(conn_src, conn_dst, kmsg); + if (IS_ERR(entry)) { + ret = PTR_ERR(entry); + goto exit_unlock; +diff --git a/ipc/kdbus/queue.c b/ipc/kdbus/queue.c +index 1e7916155036..43824c93fb03 100644 +--- a/ipc/kdbus/queue.c ++++ b/ipc/kdbus/queue.c +@@ -171,9 +171,9 @@ static void kdbus_queue_entry_unlink(struct kdbus_queue_entry *entry) + + /** + * kdbus_queue_entry_new() - allocate a queue entry ++ * @conn_src: source connection + * @conn_dst: destination connection + * @kmsg: kmsg object the queue entry should track +- * @user: user to account message on (or NULL for kernel messages) + * + * Allocates a queue entry based on a given kmsg and allocate space for + * the message payload and the requested metadata in the connection's pool. +@@ -181,10 +181,11 @@ static void kdbus_queue_entry_unlink(struct kdbus_queue_entry *entry) + * + * Return: the allocated entry on success, or an ERR_PTR on failures. + */ +-struct kdbus_queue_entry *kdbus_queue_entry_new(struct kdbus_conn *conn_dst, +- const struct kdbus_kmsg *kmsg, +- struct kdbus_user *user) ++struct kdbus_queue_entry *kdbus_queue_entry_new(struct kdbus_conn *conn_src, ++ struct kdbus_conn *conn_dst, ++ const struct kdbus_kmsg *kmsg) + { ++ struct kdbus_user *user = conn_src ? conn_src->user : NULL; + struct kdbus_msg_resources *res = kmsg->res; + const struct kdbus_msg *msg = &kmsg->msg; + struct kdbus_queue_entry *entry; +diff --git a/ipc/kdbus/queue.h b/ipc/kdbus/queue.h +index 7f2db96fe308..ac471d0c809d 100644 +--- a/ipc/kdbus/queue.h ++++ b/ipc/kdbus/queue.h +@@ -78,9 +78,9 @@ void kdbus_queue_init(struct kdbus_queue *queue); + struct kdbus_queue_entry *kdbus_queue_peek(struct kdbus_queue *queue, + s64 priority, bool use_priority); + +-struct kdbus_queue_entry *kdbus_queue_entry_new(struct kdbus_conn *conn_dst, +- const struct kdbus_kmsg *kmsg, +- struct kdbus_user *user); ++struct kdbus_queue_entry *kdbus_queue_entry_new(struct kdbus_conn *conn_src, ++ struct kdbus_conn *conn_dst, ++ const struct kdbus_kmsg *kmsg); + void kdbus_queue_entry_free(struct kdbus_queue_entry *entry); + int kdbus_queue_entry_install(struct kdbus_queue_entry *entry, + u64 *return_flags, bool install_fds); +-- +2.4.3 + + +From 5347bdd081c75f847c9739fc50e43f71440687bb Mon Sep 17 00:00:00 2001 +From: David Herrmann <dh.herrmann@gmail.com> +Date: Fri, 19 Jun 2015 21:56:25 +0200 +Subject: [PATCH 20/34] kdbus: remove redundant kmsg->dst_name_id + +Right now we store the dst_name_id in "struct kdbus_kmsg" just to make +sure it's available when we allocate the "struct kdbus_queue_entry". This +is really not needed and we can easily get rid of this field by passing +the kdbus_name_entry to the queue allocator. + +No change in behavior. + +This change allows us to make "kmsg" constant in kdbus_pin_dst() and avoid +touching it ever outside of kmsg-allocation. + +Signed-off-by: David Herrmann <dh.herrmann@gmail.com> +--- + ipc/kdbus/bus.c | 6 ++++-- + ipc/kdbus/connection.c | 29 ++++++++++++++++------------- + ipc/kdbus/connection.h | 3 ++- + ipc/kdbus/message.h | 2 -- + ipc/kdbus/notify.c | 3 ++- + ipc/kdbus/queue.c | 1 - + 6 files changed, 24 insertions(+), 20 deletions(-) + +diff --git a/ipc/kdbus/bus.c b/ipc/kdbus/bus.c +index 3c33339cf332..16f69acfec8a 100644 +--- a/ipc/kdbus/bus.c ++++ b/ipc/kdbus/bus.c +@@ -303,7 +303,8 @@ void kdbus_bus_broadcast(struct kdbus_bus *bus, + continue; + } + +- ret = kdbus_conn_entry_insert(conn_src, conn_dst, kmsg, NULL); ++ ret = kdbus_conn_entry_insert(conn_src, conn_dst, kmsg, NULL, ++ NULL); + if (ret < 0) + kdbus_conn_lost_message(conn_dst); + } +@@ -346,7 +347,8 @@ void kdbus_bus_eavesdrop(struct kdbus_bus *bus, + } + } + +- ret = kdbus_conn_entry_insert(conn_src, conn_dst, kmsg, NULL); ++ ret = kdbus_conn_entry_insert(conn_src, conn_dst, kmsg, NULL, ++ NULL); + if (ret < 0) + kdbus_conn_lost_message(conn_dst); + } +diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c +index f1667df70b7f..2ce63ccca3b4 100644 +--- a/ipc/kdbus/connection.c ++++ b/ipc/kdbus/connection.c +@@ -866,13 +866,15 @@ static int kdbus_conn_entry_sync_attach(struct kdbus_conn *conn_dst, + * @conn_dst: The connection to queue into + * @kmsg: The kmsg to queue + * @reply: The reply tracker to attach to the queue entry ++ * @name: Destination name this msg is sent to, or NULL + * + * Return: 0 on success. negative error otherwise. + */ + int kdbus_conn_entry_insert(struct kdbus_conn *conn_src, + struct kdbus_conn *conn_dst, + const struct kdbus_kmsg *kmsg, +- struct kdbus_reply *reply) ++ struct kdbus_reply *reply, ++ const struct kdbus_name_entry *name) + { + struct kdbus_queue_entry *entry; + int ret; +@@ -891,6 +893,14 @@ int kdbus_conn_entry_insert(struct kdbus_conn *conn_src, + schedule_delayed_work(&conn_src->work, 0); + } + ++ /* ++ * Record the sequence number of the registered name; it will ++ * be remembered by the queue, in case messages addressed to a ++ * name need to be moved from or to an activator. ++ */ ++ if (name) ++ entry->dst_name_id = name->name_id; ++ + kdbus_queue_entry_enqueue(entry, reply); + wake_up_interruptible(&conn_dst->wait); + +@@ -1023,14 +1033,14 @@ static int kdbus_conn_wait_reply(struct kdbus_conn *conn_src, + } + + static int kdbus_pin_dst(struct kdbus_bus *bus, +- struct kdbus_kmsg *kmsg, ++ const struct kdbus_kmsg *kmsg, + struct kdbus_name_entry **out_name, + struct kdbus_conn **out_dst) + { + struct kdbus_msg_resources *res = kmsg->res; ++ const struct kdbus_msg *msg = &kmsg->msg; + struct kdbus_name_entry *name = NULL; + struct kdbus_conn *dst = NULL; +- struct kdbus_msg *msg = &kmsg->msg; + int ret; + + if (WARN_ON(!res)) +@@ -1075,13 +1085,6 @@ static int kdbus_pin_dst(struct kdbus_bus *bus, + ret = -EADDRNOTAVAIL; + goto error; + } +- +- /* +- * Record the sequence number of the registered name; it will +- * be passed on to the queue, in case messages addressed to a +- * name need to be moved from or to an activator. +- */ +- kmsg->dst_name_id = name->name_id; + } + + *out_name = name; +@@ -1142,7 +1145,7 @@ static int kdbus_conn_reply(struct kdbus_conn *src, struct kdbus_kmsg *kmsg) + if (wake) + ret = kdbus_conn_entry_sync_attach(dst, kmsg, wake); + else +- ret = kdbus_conn_entry_insert(src, dst, kmsg, NULL); ++ ret = kdbus_conn_entry_insert(src, dst, kmsg, NULL, name); + + exit: + up_read(&bus->name_registry->rwlock); +@@ -1217,7 +1220,7 @@ static struct kdbus_reply *kdbus_conn_call(struct kdbus_conn *src, + + kdbus_bus_eavesdrop(bus, src, kmsg); + +- ret = kdbus_conn_entry_insert(src, dst, kmsg, wait); ++ ret = kdbus_conn_entry_insert(src, dst, kmsg, wait, name); + if (ret < 0) + goto exit; + +@@ -1287,7 +1290,7 @@ static int kdbus_conn_unicast(struct kdbus_conn *src, struct kdbus_kmsg *kmsg) + if (!is_signal) + kdbus_bus_eavesdrop(bus, src, kmsg); + +- ret = kdbus_conn_entry_insert(src, dst, kmsg, wait); ++ ret = kdbus_conn_entry_insert(src, dst, kmsg, wait, name); + if (ret < 0 && !is_signal) + goto exit; + +diff --git a/ipc/kdbus/connection.h b/ipc/kdbus/connection.h +index aa4234a4e3e4..8cffba94a564 100644 +--- a/ipc/kdbus/connection.h ++++ b/ipc/kdbus/connection.h +@@ -135,7 +135,8 @@ void kdbus_conn_lost_message(struct kdbus_conn *c); + int kdbus_conn_entry_insert(struct kdbus_conn *conn_src, + struct kdbus_conn *conn_dst, + const struct kdbus_kmsg *kmsg, +- struct kdbus_reply *reply); ++ struct kdbus_reply *reply, ++ const struct kdbus_name_entry *name); + void kdbus_conn_move_messages(struct kdbus_conn *conn_dst, + struct kdbus_conn *conn_src, + u64 name_id); +diff --git a/ipc/kdbus/message.h b/ipc/kdbus/message.h +index 3b733474f335..88e2366e49b6 100644 +--- a/ipc/kdbus/message.h ++++ b/ipc/kdbus/message.h +@@ -86,7 +86,6 @@ kdbus_msg_resources_unref(struct kdbus_msg_resources *r); + * @notify_old_id: Short-cut for faster lookup + * @notify_new_id: Short-cut for faster lookup + * @notify_name: Short-cut for faster lookup +- * @dst_name_id: Short-cut to msg for faster lookup + * @bloom_filter: Bloom filter to match message properties + * @notify_entry: List of kernel-generated notifications + * @iov: Array of iovec, describing the payload to copy +@@ -104,7 +103,6 @@ struct kdbus_kmsg { + u64 notify_new_id; + const char *notify_name; + +- u64 dst_name_id; + const struct kdbus_bloom_filter *bloom_filter; + struct list_head notify_entry; + +diff --git a/ipc/kdbus/notify.c b/ipc/kdbus/notify.c +index 216720fc26ff..bcf7555e386a 100644 +--- a/ipc/kdbus/notify.c ++++ b/ipc/kdbus/notify.c +@@ -218,7 +218,8 @@ void kdbus_notify_flush(struct kdbus_bus *bus) + conn = kdbus_bus_find_conn_by_id(bus, kmsg->msg.dst_id); + if (conn) { + kdbus_bus_eavesdrop(bus, NULL, kmsg); +- kdbus_conn_entry_insert(NULL, conn, kmsg, NULL); ++ kdbus_conn_entry_insert(NULL, conn, kmsg, NULL, ++ NULL); + kdbus_conn_unref(conn); + } + } else { +diff --git a/ipc/kdbus/queue.c b/ipc/kdbus/queue.c +index 43824c93fb03..4749b23a4f14 100644 +--- a/ipc/kdbus/queue.c ++++ b/ipc/kdbus/queue.c +@@ -203,7 +203,6 @@ struct kdbus_queue_entry *kdbus_queue_entry_new(struct kdbus_conn *conn_src, + + INIT_LIST_HEAD(&entry->entry); + entry->priority = msg->priority; +- entry->dst_name_id = kmsg->dst_name_id; + entry->msg_res = kdbus_msg_resources_ref(res); + entry->proc_meta = kdbus_meta_proc_ref(kmsg->proc_meta); + entry->conn_meta = kdbus_meta_conn_ref(kmsg->conn_meta); +-- +2.4.3 + + +From 462d196d27840d84e1ff686c481fbbd99509864e Mon Sep 17 00:00:00 2001 +From: David Herrmann <dh.herrmann@gmail.com> +Date: Fri, 19 Jun 2015 23:04:49 +0200 +Subject: [PATCH 21/34] kdbus: simplify collecting metadata on messages + +Instead of collecting metadata on the call-side for each message origin, +move it to the core: Handle it directly before allocating the message +slice. + +The number of times we call into the helper stays exactly the same, but +the code paths are reduced significantly. + +Signed-off-by: David Herrmann <dh.herrmann@gmail.com> +--- + ipc/kdbus/bus.c | 16 ---------------- + ipc/kdbus/connection.c | 31 ++++++++++++------------------- + ipc/kdbus/message.c | 4 ++-- + ipc/kdbus/message.h | 4 ++-- + 4 files changed, 16 insertions(+), 39 deletions(-) + +diff --git a/ipc/kdbus/bus.c b/ipc/kdbus/bus.c +index 16f69acfec8a..bc3c3c0383cb 100644 +--- a/ipc/kdbus/bus.c ++++ b/ipc/kdbus/bus.c +@@ -284,13 +284,6 @@ void kdbus_bus_broadcast(struct kdbus_bus *bus, + */ + if (!kdbus_conn_policy_talk(conn_dst, NULL, conn_src)) + continue; +- +- ret = kdbus_kmsg_collect_metadata(kmsg, conn_src, +- conn_dst); +- if (ret < 0) { +- kdbus_conn_lost_message(conn_dst); +- continue; +- } + } else { + /* + * Check if there is a policy db that prevents the +@@ -338,15 +331,6 @@ void kdbus_bus_eavesdrop(struct kdbus_bus *bus, + + down_read(&bus->conn_rwlock); + list_for_each_entry(conn_dst, &bus->monitors_list, monitor_entry) { +- if (conn_src) { +- ret = kdbus_kmsg_collect_metadata(kmsg, conn_src, +- conn_dst); +- if (ret < 0) { +- kdbus_conn_lost_message(conn_dst); +- continue; +- } +- } +- + ret = kdbus_conn_entry_insert(conn_src, conn_dst, kmsg, NULL, + NULL); + if (ret < 0) +diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c +index 2ce63ccca3b4..25e49455b24b 100644 +--- a/ipc/kdbus/connection.c ++++ b/ipc/kdbus/connection.c +@@ -813,7 +813,12 @@ static int kdbus_conn_entry_sync_attach(struct kdbus_conn *conn_dst, + { + struct kdbus_queue_entry *entry; + int remote_ret; +- int ret = 0; ++ int ret; ++ ++ ret = kdbus_kmsg_collect_metadata(kmsg, reply_wake->reply_src, ++ conn_dst); ++ if (ret < 0) ++ return ret; + + mutex_lock(&reply_wake->reply_dst->lock); + +@@ -879,6 +884,12 @@ int kdbus_conn_entry_insert(struct kdbus_conn *conn_src, + struct kdbus_queue_entry *entry; + int ret; + ++ if (conn_src) { ++ ret = kdbus_kmsg_collect_metadata(kmsg, conn_src, conn_dst); ++ if (ret < 0) ++ return ret; ++ } ++ + kdbus_conn_lock2(conn_src, conn_dst); + + entry = kdbus_conn_entry_make(conn_src, conn_dst, kmsg); +@@ -1132,12 +1143,6 @@ static int kdbus_conn_reply(struct kdbus_conn *src, struct kdbus_kmsg *kmsg) + goto exit; + } + +- /* attach metadata */ +- +- ret = kdbus_kmsg_collect_metadata(kmsg, src, dst); +- if (ret < 0) +- goto exit; +- + /* send message */ + + kdbus_bus_eavesdrop(bus, src, kmsg); +@@ -1210,12 +1215,6 @@ static struct kdbus_reply *kdbus_conn_call(struct kdbus_conn *src, + goto exit; + } + +- /* attach metadata */ +- +- ret = kdbus_kmsg_collect_metadata(kmsg, src, dst); +- if (ret < 0) +- goto exit; +- + /* send message */ + + kdbus_bus_eavesdrop(bus, src, kmsg); +@@ -1279,12 +1278,6 @@ static int kdbus_conn_unicast(struct kdbus_conn *src, struct kdbus_kmsg *kmsg) + } + } + +- /* attach metadata */ +- +- ret = kdbus_kmsg_collect_metadata(kmsg, src, dst); +- if (ret < 0) +- goto exit; +- + /* send message */ + + if (!is_signal) +diff --git a/ipc/kdbus/message.c b/ipc/kdbus/message.c +index 974e8c4f6039..9346a04e10ef 100644 +--- a/ipc/kdbus/message.c ++++ b/ipc/kdbus/message.c +@@ -619,8 +619,8 @@ exit_free: + * + * Return: 0 on success, negative error code on failure. + */ +-int kdbus_kmsg_collect_metadata(struct kdbus_kmsg *kmsg, struct kdbus_conn *src, +- struct kdbus_conn *dst) ++int kdbus_kmsg_collect_metadata(const struct kdbus_kmsg *kmsg, ++ struct kdbus_conn *src, struct kdbus_conn *dst) + { + u64 attach; + int ret; +diff --git a/ipc/kdbus/message.h b/ipc/kdbus/message.h +index 88e2366e49b6..9a11389d9f27 100644 +--- a/ipc/kdbus/message.h ++++ b/ipc/kdbus/message.h +@@ -125,7 +125,7 @@ struct kdbus_kmsg *kdbus_kmsg_new(struct kdbus_bus *bus, size_t extra_size); + struct kdbus_kmsg *kdbus_kmsg_new_from_cmd(struct kdbus_conn *conn, + struct kdbus_cmd_send *cmd_send); + void kdbus_kmsg_free(struct kdbus_kmsg *kmsg); +-int kdbus_kmsg_collect_metadata(struct kdbus_kmsg *kmsg, struct kdbus_conn *src, +- struct kdbus_conn *dst); ++int kdbus_kmsg_collect_metadata(const struct kdbus_kmsg *kmsg, ++ struct kdbus_conn *src, struct kdbus_conn *dst); + + #endif +-- +2.4.3 + + +From 6d75879b543c4eeb9544547e87174bba1be3a173 Mon Sep 17 00:00:00 2001 +From: David Herrmann <dh.herrmann@gmail.com> +Date: Fri, 19 Jun 2015 23:38:19 +0200 +Subject: [PATCH 22/34] kdbus: simplify notification shortcuts + +Right now, we have a bunch of shortcuts in "struct kdbus_kmsg" that cache +the values of the first kdbus-item, _iff_ the message is a kernel +notification. These are then used during match-db lookups and policy +lookups. + +These shortcuts make the actually more complex and in no way faster. Drop +them in favor of a simple "struct kdbus_item *notify" shortcut which +points to the notification item (to distinguish it from normal +user-supplied messages). This way, we save a bunch of code and can even +simplify the notification message setup (as it is now fully generic). + +Signed-off-by: David Herrmann <dh.herrmann@gmail.com> +--- + ipc/kdbus/bus.c | 3 +- + ipc/kdbus/connection.c | 15 +++++----- + ipc/kdbus/connection.h | 2 +- + ipc/kdbus/match.c | 14 +++++---- + ipc/kdbus/message.c | 54 ++++++++++++++++++---------------- + ipc/kdbus/message.h | 14 ++++----- + ipc/kdbus/notify.c | 78 ++++++++++++-------------------------------------- + 7 files changed, 69 insertions(+), 111 deletions(-) + +diff --git a/ipc/kdbus/bus.c b/ipc/kdbus/bus.c +index bc3c3c0383cb..4f51723f8780 100644 +--- a/ipc/kdbus/bus.c ++++ b/ipc/kdbus/bus.c +@@ -291,8 +291,7 @@ void kdbus_bus_broadcast(struct kdbus_bus *bus, + * notification + */ + if (!kdbus_conn_policy_see_notification(conn_dst, NULL, +- kmsg->notify_type, +- kmsg->notify_name)) ++ &kmsg->msg)) + continue; + } + +diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c +index 25e49455b24b..29b99c023bfe 100644 +--- a/ipc/kdbus/connection.c ++++ b/ipc/kdbus/connection.c +@@ -1537,17 +1537,15 @@ static bool kdbus_conn_policy_see(struct kdbus_conn *conn, + * receive a given kernel notification + * @conn: Connection + * @conn_creds: Credentials of @conn to use for policy check +- * @type: Type of notification +- * @name: Well-known name this notification is about, or NULL ++ * @msg: Notification message + * +- * This checks whether @conn is allowed to see the kernel notification of type +- * @type for well-known name @name. ++ * This checks whether @conn is allowed to see the kernel notification. + * + * Return: true if allowed, false if not. + */ + bool kdbus_conn_policy_see_notification(struct kdbus_conn *conn, + const struct cred *conn_creds, +- u64 type, const char *name) ++ const struct kdbus_msg *msg) + { + /* + * Depending on the notification type, broadcasted kernel notifications +@@ -1561,11 +1559,12 @@ bool kdbus_conn_policy_see_notification(struct kdbus_conn *conn, + * broadcast to everyone, to allow tracking peers. + */ + +- switch (type) { ++ switch (msg->items[0].type) { + case KDBUS_ITEM_NAME_ADD: + case KDBUS_ITEM_NAME_REMOVE: + case KDBUS_ITEM_NAME_CHANGE: +- return kdbus_conn_policy_see_name(conn, conn_creds, name); ++ return kdbus_conn_policy_see_name(conn, conn_creds, ++ msg->items[0].name_change.name); + + case KDBUS_ITEM_ID_ADD: + case KDBUS_ITEM_ID_REMOVE: +@@ -1573,7 +1572,7 @@ bool kdbus_conn_policy_see_notification(struct kdbus_conn *conn, + + default: + WARN(1, "Invalid type for notification broadcast: %llu\n", +- (unsigned long long)type); ++ (unsigned long long)msg->items[0].type); + return false; + } + } +diff --git a/ipc/kdbus/connection.h b/ipc/kdbus/connection.h +index 8cffba94a564..90c1bcc91fe6 100644 +--- a/ipc/kdbus/connection.h ++++ b/ipc/kdbus/connection.h +@@ -153,7 +153,7 @@ bool kdbus_conn_policy_see_name_unlocked(struct kdbus_conn *conn, + const char *name); + bool kdbus_conn_policy_see_notification(struct kdbus_conn *conn, + const struct cred *curr_creds, +- u64 type, const char *name); ++ const struct kdbus_msg *msg); + + /* command dispatcher */ + struct kdbus_conn *kdbus_cmd_hello(struct kdbus_ep *ep, bool privileged, +diff --git a/ipc/kdbus/match.c b/ipc/kdbus/match.c +index 869a9fbce37d..3f86e4c81468 100644 +--- a/ipc/kdbus/match.c ++++ b/ipc/kdbus/match.c +@@ -225,24 +225,26 @@ static bool kdbus_match_rule_conn(const struct kdbus_match_rule *r, + static bool kdbus_match_rule_kernel(const struct kdbus_match_rule *r, + const struct kdbus_kmsg *kmsg) + { +- if (kmsg->notify_type != r->type) ++ struct kdbus_item *n = kmsg->notify; ++ ++ if (WARN_ON(!n) || n->type != r->type) + return false; + + switch (r->type) { + case KDBUS_ITEM_ID_ADD: + return r->new_id == KDBUS_MATCH_ID_ANY || +- r->new_id == kmsg->notify_new_id; ++ r->new_id == n->id_change.id; + case KDBUS_ITEM_ID_REMOVE: + return r->old_id == KDBUS_MATCH_ID_ANY || +- r->old_id == kmsg->notify_old_id; ++ r->old_id == n->id_change.id; + case KDBUS_ITEM_NAME_ADD: + case KDBUS_ITEM_NAME_CHANGE: + case KDBUS_ITEM_NAME_REMOVE: + return (r->old_id == KDBUS_MATCH_ID_ANY || +- r->old_id == kmsg->notify_old_id) && ++ r->old_id == n->name_change.old_id.id) && + (r->new_id == KDBUS_MATCH_ID_ANY || +- r->new_id == kmsg->notify_new_id) && +- (!r->name || !strcmp(r->name, kmsg->notify_name)); ++ r->new_id == n->name_change.new_id.id) && ++ (!r->name || !strcmp(r->name, n->name_change.name)); + default: + return false; + } +diff --git a/ipc/kdbus/message.c b/ipc/kdbus/message.c +index 9346a04e10ef..7f23e5c857dd 100644 +--- a/ipc/kdbus/message.c ++++ b/ipc/kdbus/message.c +@@ -124,46 +124,50 @@ void kdbus_kmsg_free(struct kdbus_kmsg *kmsg) + kfree(kmsg); + } + +-/** +- * kdbus_kmsg_new() - allocate message +- * @bus: Bus this message is allocated on +- * @extra_size: Additional size to reserve for data +- * +- * Return: new kdbus_kmsg on success, ERR_PTR on failure. +- */ +-struct kdbus_kmsg *kdbus_kmsg_new(struct kdbus_bus *bus, size_t extra_size) ++struct kdbus_kmsg *kdbus_kmsg_new_kernel(struct kdbus_bus *bus, ++ u64 dst, u64 cookie_timeout, ++ size_t it_size, size_t it_type) + { +- struct kdbus_kmsg *m; ++ struct kdbus_kmsg *kmsg; + size_t size; + int ret; + +- size = sizeof(struct kdbus_kmsg) + KDBUS_ITEM_SIZE(extra_size); +- m = kzalloc(size, GFP_KERNEL); +- if (!m) ++ size = sizeof(struct kdbus_kmsg) + KDBUS_ITEM_SIZE(it_size); ++ kmsg = kzalloc(size, GFP_KERNEL); ++ if (!kmsg) + return ERR_PTR(-ENOMEM); + +- m->seq = atomic64_inc_return(&bus->domain->last_id); +- m->msg.size = size - KDBUS_KMSG_HEADER_SIZE; +- m->msg.items[0].size = KDBUS_ITEM_SIZE(extra_size); ++ kmsg->seq = atomic64_inc_return(&bus->domain->last_id); + +- m->proc_meta = kdbus_meta_proc_new(); +- if (IS_ERR(m->proc_meta)) { +- ret = PTR_ERR(m->proc_meta); +- m->proc_meta = NULL; ++ kmsg->proc_meta = kdbus_meta_proc_new(); ++ if (IS_ERR(kmsg->proc_meta)) { ++ ret = PTR_ERR(kmsg->proc_meta); ++ kmsg->proc_meta = NULL; + goto exit; + } + +- m->conn_meta = kdbus_meta_conn_new(); +- if (IS_ERR(m->conn_meta)) { +- ret = PTR_ERR(m->conn_meta); +- m->conn_meta = NULL; ++ kmsg->conn_meta = kdbus_meta_conn_new(); ++ if (IS_ERR(kmsg->conn_meta)) { ++ ret = PTR_ERR(kmsg->conn_meta); ++ kmsg->conn_meta = NULL; + goto exit; + } + +- return m; ++ kmsg->msg.size = size - KDBUS_KMSG_HEADER_SIZE; ++ kmsg->msg.flags = (dst == KDBUS_DST_ID_BROADCAST) ? ++ KDBUS_MSG_SIGNAL : 0; ++ kmsg->msg.dst_id = dst; ++ kmsg->msg.src_id = KDBUS_SRC_ID_KERNEL; ++ kmsg->msg.payload_type = KDBUS_PAYLOAD_KERNEL; ++ kmsg->msg.cookie_reply = cookie_timeout; ++ kmsg->notify = kmsg->msg.items; ++ kmsg->notify->size = KDBUS_ITEM_HEADER_SIZE + it_size; ++ kmsg->notify->type = it_type; ++ ++ return kmsg; + + exit: +- kdbus_kmsg_free(m); ++ kdbus_kmsg_free(kmsg); + return ERR_PTR(ret); + } + +diff --git a/ipc/kdbus/message.h b/ipc/kdbus/message.h +index 9a11389d9f27..5755ad4c9fd9 100644 +--- a/ipc/kdbus/message.h ++++ b/ipc/kdbus/message.h +@@ -82,10 +82,7 @@ kdbus_msg_resources_unref(struct kdbus_msg_resources *r); + /** + * struct kdbus_kmsg - internal message handling data + * @seq: Domain-global message sequence number +- * @notify_type: Short-cut for faster lookup +- * @notify_old_id: Short-cut for faster lookup +- * @notify_new_id: Short-cut for faster lookup +- * @notify_name: Short-cut for faster lookup ++ * @notify: Short-cut to notify-item for kernel notifications + * @bloom_filter: Bloom filter to match message properties + * @notify_entry: List of kernel-generated notifications + * @iov: Array of iovec, describing the payload to copy +@@ -98,10 +95,7 @@ kdbus_msg_resources_unref(struct kdbus_msg_resources *r); + */ + struct kdbus_kmsg { + u64 seq; +- u64 notify_type; +- u64 notify_old_id; +- u64 notify_new_id; +- const char *notify_name; ++ struct kdbus_item *notify; + + const struct kdbus_bloom_filter *bloom_filter; + struct list_head notify_entry; +@@ -121,7 +115,9 @@ struct kdbus_kmsg { + struct kdbus_bus; + struct kdbus_conn; + +-struct kdbus_kmsg *kdbus_kmsg_new(struct kdbus_bus *bus, size_t extra_size); ++struct kdbus_kmsg *kdbus_kmsg_new_kernel(struct kdbus_bus *bus, ++ u64 dst, u64 cookie_timeout, ++ size_t it_size, size_t it_type); + struct kdbus_kmsg *kdbus_kmsg_new_from_cmd(struct kdbus_conn *conn, + struct kdbus_cmd_send *cmd_send); + void kdbus_kmsg_free(struct kdbus_kmsg *kmsg); +diff --git a/ipc/kdbus/notify.c b/ipc/kdbus/notify.c +index bcf7555e386a..a07d242d0470 100644 +--- a/ipc/kdbus/notify.c ++++ b/ipc/kdbus/notify.c +@@ -39,29 +39,13 @@ static inline void kdbus_notify_add_tail(struct kdbus_kmsg *kmsg, + static int kdbus_notify_reply(struct kdbus_bus *bus, u64 id, + u64 cookie, u64 msg_type) + { +- struct kdbus_kmsg *kmsg = NULL; ++ struct kdbus_kmsg *kmsg; + +- WARN_ON(id == 0); +- +- kmsg = kdbus_kmsg_new(bus, 0); ++ kmsg = kdbus_kmsg_new_kernel(bus, id, cookie, 0, msg_type); + if (IS_ERR(kmsg)) + return PTR_ERR(kmsg); + +- /* +- * a kernel-generated notification can only contain one +- * struct kdbus_item, so make a shortcut here for +- * faster lookup in the match db. +- */ +- kmsg->notify_type = msg_type; +- kmsg->msg.flags = KDBUS_MSG_SIGNAL; +- kmsg->msg.dst_id = id; +- kmsg->msg.src_id = KDBUS_SRC_ID_KERNEL; +- kmsg->msg.payload_type = KDBUS_PAYLOAD_KERNEL; +- kmsg->msg.cookie_reply = cookie; +- kmsg->msg.items[0].type = msg_type; +- + kdbus_notify_add_tail(kmsg, bus); +- + return 0; + } + +@@ -115,32 +99,24 @@ int kdbus_notify_name_change(struct kdbus_bus *bus, u64 type, + u64 old_flags, u64 new_flags, + const char *name) + { +- struct kdbus_kmsg *kmsg = NULL; + size_t name_len, extra_size; ++ struct kdbus_kmsg *kmsg; + + name_len = strlen(name) + 1; + extra_size = sizeof(struct kdbus_notify_name_change) + name_len; +- kmsg = kdbus_kmsg_new(bus, extra_size); ++ ++ kmsg = kdbus_kmsg_new_kernel(bus, KDBUS_DST_ID_BROADCAST, 0, ++ extra_size, type); + if (IS_ERR(kmsg)) + return PTR_ERR(kmsg); + +- kmsg->msg.flags = KDBUS_MSG_SIGNAL; +- kmsg->msg.dst_id = KDBUS_DST_ID_BROADCAST; +- kmsg->msg.src_id = KDBUS_SRC_ID_KERNEL; +- kmsg->msg.payload_type = KDBUS_PAYLOAD_KERNEL; +- kmsg->notify_type = type; +- kmsg->notify_old_id = old_id; +- kmsg->notify_new_id = new_id; +- kmsg->msg.items[0].type = type; +- kmsg->msg.items[0].name_change.old_id.id = old_id; +- kmsg->msg.items[0].name_change.old_id.flags = old_flags; +- kmsg->msg.items[0].name_change.new_id.id = new_id; +- kmsg->msg.items[0].name_change.new_id.flags = new_flags; +- memcpy(kmsg->msg.items[0].name_change.name, name, name_len); +- kmsg->notify_name = kmsg->msg.items[0].name_change.name; ++ kmsg->notify->name_change.old_id.id = old_id; ++ kmsg->notify->name_change.old_id.flags = old_flags; ++ kmsg->notify->name_change.new_id.id = new_id; ++ kmsg->notify->name_change.new_id.flags = new_flags; ++ memcpy(kmsg->notify->name_change.name, name, name_len); + + kdbus_notify_add_tail(kmsg, bus); +- + return 0; + } + +@@ -156,37 +132,19 @@ int kdbus_notify_name_change(struct kdbus_bus *bus, u64 type, + */ + int kdbus_notify_id_change(struct kdbus_bus *bus, u64 type, u64 id, u64 flags) + { +- struct kdbus_kmsg *kmsg = NULL; ++ struct kdbus_kmsg *kmsg; ++ size_t extra_size; + +- kmsg = kdbus_kmsg_new(bus, sizeof(struct kdbus_notify_id_change)); ++ extra_size = sizeof(struct kdbus_notify_id_change); ++ kmsg = kdbus_kmsg_new_kernel(bus, KDBUS_DST_ID_BROADCAST, 0, ++ extra_size, type); + if (IS_ERR(kmsg)) + return PTR_ERR(kmsg); + +- kmsg->msg.flags = KDBUS_MSG_SIGNAL; +- kmsg->msg.dst_id = KDBUS_DST_ID_BROADCAST; +- kmsg->msg.src_id = KDBUS_SRC_ID_KERNEL; +- kmsg->msg.payload_type = KDBUS_PAYLOAD_KERNEL; +- kmsg->notify_type = type; +- +- switch (type) { +- case KDBUS_ITEM_ID_ADD: +- kmsg->notify_new_id = id; +- break; +- +- case KDBUS_ITEM_ID_REMOVE: +- kmsg->notify_old_id = id; +- break; +- +- default: +- BUG(); +- } +- +- kmsg->msg.items[0].type = type; +- kmsg->msg.items[0].id_change.id = id; +- kmsg->msg.items[0].id_change.flags = flags; ++ kmsg->notify->id_change.id = id; ++ kmsg->notify->id_change.flags = flags; + + kdbus_notify_add_tail(kmsg, bus); +- + return 0; + } + +-- +2.4.3 + + +From 2e3c15be5c1f48a9082b47a5cf825dc7c9592b12 Mon Sep 17 00:00:00 2001 +From: David Herrmann <dh.herrmann@gmail.com> +Date: Fri, 19 Jun 2015 23:56:19 +0200 +Subject: [PATCH 23/34] kdbus: rewrite message importer + +This is a complete rewrite of the message importer (currently known as +'kmsg'). I did some benchmarks on the old code, and our many calls into +kdbus_pool_slice_copy_iovec/kvec() are by far the biggest CPU consumers. +As it turns out, we can reduce the number of calls into that function to +*one* (and one additional call per FD-set transmitted). Compared to our +10x (?) calls we do right now, this reduces the time spent on a message +transaction significantly. + +The new message importer uses a new structure called "struct +kdbus_staging". This structure is solely used to import the "kdbus_msg" +object into the kernel, parse it, create some helper data and then use it +to allocate messages in each receivers pool. The staging object thus is +only used at SEND time and its sole purpose is to prepare for the real +message we allocate (as part of the queue_entry). Hence, the rename to +kdbus_staging, instead of kdbus_kmsg (which was really misleading). + +Furthermore, this patch replaces "struct kdbus_msg_resources". The old +resources contained far more data than was really necessary. There is no +reason to pin VECs until RECV time. This can all be dropped. All that +needs to be pinned is memfds and fds. + +This patch only introduces the new infrastructure. It is not hooked up, +yet. Follow-up patches will make sure it's actually used. + +Signed-off-by: David Herrmann <dh.herrmann@gmail.com> +--- + ipc/kdbus/message.c | 990 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + ipc/kdbus/message.h | 93 +++++ + 2 files changed, 1083 insertions(+) + +diff --git a/ipc/kdbus/message.c b/ipc/kdbus/message.c +index 7f23e5c857dd..f1ec69f3697f 100644 +--- a/ipc/kdbus/message.c ++++ b/ipc/kdbus/message.c +@@ -638,3 +638,993 @@ int kdbus_kmsg_collect_metadata(const struct kdbus_kmsg *kmsg, + + return kdbus_meta_conn_collect(kmsg->conn_meta, src, kmsg->seq, attach); + } ++ ++static struct kdbus_gaps *kdbus_gaps_new(size_t n_memfds, size_t n_fds) ++{ ++ size_t size_offsets, size_memfds, size_fds, size; ++ struct kdbus_gaps *gaps; ++ ++ size_offsets = n_memfds * sizeof(*gaps->memfd_offsets); ++ size_memfds = n_memfds * sizeof(*gaps->memfd_files); ++ size_fds = n_fds * sizeof(*gaps->fd_files); ++ size = sizeof(*gaps) + size_offsets + size_memfds + size_fds; ++ ++ gaps = kzalloc(size, GFP_KERNEL); ++ if (!gaps) ++ return ERR_PTR(-ENOMEM); ++ ++ kref_init(&gaps->kref); ++ gaps->n_memfds = 0; /* we reserve n_memfds, but don't enforce them */ ++ gaps->memfd_offsets = (void *)(gaps + 1); ++ gaps->memfd_files = (void *)((u8 *)gaps->memfd_offsets + size_offsets); ++ gaps->n_fds = 0; /* we reserve n_fds, but don't enforce them */ ++ gaps->fd_files = (void *)((u8 *)gaps->memfd_files + size_memfds); ++ ++ return gaps; ++} ++ ++static void kdbus_gaps_free(struct kref *kref) ++{ ++ struct kdbus_gaps *gaps = container_of(kref, struct kdbus_gaps, kref); ++ size_t i; ++ ++ for (i = 0; i < gaps->n_fds; ++i) ++ if (gaps->fd_files[i]) ++ fput(gaps->fd_files[i]); ++ for (i = 0; i < gaps->n_memfds; ++i) ++ if (gaps->memfd_files[i]) ++ fput(gaps->memfd_files[i]); ++ ++ kfree(gaps); ++} ++ ++/** ++ * kdbus_gaps_ref() - gain reference ++ * @gaps: gaps object ++ * ++ * Return: @gaps is returned ++ */ ++struct kdbus_gaps *kdbus_gaps_ref(struct kdbus_gaps *gaps) ++{ ++ if (gaps) ++ kref_get(&gaps->kref); ++ return gaps; ++} ++ ++/** ++ * kdbus_gaps_unref() - drop reference ++ * @gaps: gaps object ++ * ++ * Return: NULL ++ */ ++struct kdbus_gaps *kdbus_gaps_unref(struct kdbus_gaps *gaps) ++{ ++ if (gaps) ++ kref_put(&gaps->kref, kdbus_gaps_free); ++ return NULL; ++} ++ ++/** ++ * kdbus_gaps_install() - install file-descriptors ++ * @gaps: gaps object, or NULL ++ * @slice: pool slice that contains the message ++ * @out_incomplete output variable to note incomplete fds ++ * ++ * This function installs all file-descriptors of @gaps into the current ++ * process and copies the file-descriptor numbers into the target pool slice. ++ * ++ * If the file-descriptors were only partially installed, then @out_incomplete ++ * will be set to true. Otherwise, it's set to false. ++ * ++ * Return: 0 on success, negative error code on failure ++ */ ++int kdbus_gaps_install(struct kdbus_gaps *gaps, struct kdbus_pool_slice *slice, ++ bool *out_incomplete) ++{ ++ bool incomplete_fds = false; ++ struct kvec kvec; ++ size_t i, n_fds; ++ int ret, *fds; ++ ++ if (!gaps) { ++ /* nothing to do */ ++ *out_incomplete = incomplete_fds; ++ return 0; ++ } ++ ++ n_fds = gaps->n_fds + gaps->n_memfds; ++ if (n_fds < 1) { ++ /* nothing to do */ ++ *out_incomplete = incomplete_fds; ++ return 0; ++ } ++ ++ fds = kmalloc_array(n_fds, sizeof(*fds), GFP_TEMPORARY); ++ n_fds = 0; ++ if (!fds) ++ return -ENOMEM; ++ ++ /* 1) allocate fds and copy them over */ ++ ++ if (gaps->n_fds > 0) { ++ for (i = 0; i < gaps->n_fds; ++i) { ++ int fd; ++ ++ fd = get_unused_fd_flags(O_CLOEXEC); ++ if (fd < 0) ++ incomplete_fds = true; ++ ++ WARN_ON(!gaps->fd_files[i]); ++ ++ fds[n_fds++] = fd < 0 ? -1 : fd; ++ } ++ ++ /* ++ * The file-descriptor array can only be present once per ++ * message. Hence, prepare all fds and then copy them over with ++ * a single kvec. ++ */ ++ ++ WARN_ON(!gaps->fd_offset); ++ ++ kvec.iov_base = fds; ++ kvec.iov_len = gaps->n_fds * sizeof(*fds); ++ ret = kdbus_pool_slice_copy_kvec(slice, gaps->fd_offset, ++ &kvec, 1, kvec.iov_len); ++ if (ret < 0) ++ goto exit; ++ } ++ ++ for (i = 0; i < gaps->n_memfds; ++i) { ++ int memfd; ++ ++ memfd = get_unused_fd_flags(O_CLOEXEC); ++ if (memfd < 0) { ++ incomplete_fds = true; ++ /* memfds are initialized to -1, skip copying it */ ++ continue; ++ } ++ ++ fds[n_fds++] = memfd; ++ ++ /* ++ * memfds have to be copied individually as they each are put ++ * into a separate item. This should not be an issue, though, ++ * as usually there is no need to send more than one memfd per ++ * message. ++ */ ++ ++ WARN_ON(!gaps->memfd_offsets[i]); ++ WARN_ON(!gaps->memfd_files[i]); ++ ++ kvec.iov_base = &memfd; ++ kvec.iov_len = sizeof(memfd); ++ ret = kdbus_pool_slice_copy_kvec(slice, gaps->memfd_offsets[i], ++ &kvec, 1, kvec.iov_len); ++ if (ret < 0) ++ goto exit; ++ } ++ ++ /* 2) install fds now that everything was successful */ ++ ++ for (i = 0; i < gaps->n_fds; ++i) ++ if (fds[i] >= 0) ++ fd_install(fds[i], get_file(gaps->fd_files[i])); ++ for (i = 0; i < gaps->n_memfds; ++i) ++ if (fds[gaps->n_fds + i] >= 0) ++ fd_install(fds[gaps->n_fds + i], ++ get_file(gaps->memfd_files[i])); ++ ++ ret = 0; ++ ++exit: ++ if (ret < 0) ++ for (i = 0; i < n_fds; ++i) ++ put_unused_fd(fds[i]); ++ kfree(fds); ++ *out_incomplete = incomplete_fds; ++ return ret; ++} ++ ++static struct file *kdbus_get_fd(int fd) ++{ ++ struct file *f, *ret; ++ struct inode *inode; ++ struct socket *sock; ++ ++ if (fd < 0) ++ return ERR_PTR(-EBADF); ++ ++ f = fget_raw(fd); ++ if (!f) ++ return ERR_PTR(-EBADF); ++ ++ inode = file_inode(f); ++ sock = S_ISSOCK(inode->i_mode) ? SOCKET_I(inode) : NULL; ++ ++ if (f->f_mode & FMODE_PATH) ++ ret = f; /* O_PATH is always allowed */ ++ else if (f->f_op == &kdbus_handle_ops) ++ ret = ERR_PTR(-EOPNOTSUPP); /* disallow kdbus-fd over kdbus */ ++ else if (sock && sock->sk && sock->ops && sock->ops->family == PF_UNIX) ++ ret = ERR_PTR(-EOPNOTSUPP); /* disallow UDS over kdbus */ ++ else ++ ret = f; /* all other are allowed */ ++ ++ if (f != ret) ++ fput(f); ++ ++ return ret; ++} ++ ++static struct file *kdbus_get_memfd(const struct kdbus_memfd *memfd) ++{ ++ const int m = F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL; ++ struct file *f, *ret; ++ int s; ++ ++ if (memfd->fd < 0) ++ return ERR_PTR(-EBADF); ++ ++ f = fget(memfd->fd); ++ if (!f) ++ return ERR_PTR(-EBADF); ++ ++ s = shmem_get_seals(f); ++ if (s < 0) ++ ret = ERR_PTR(-EMEDIUMTYPE); ++ else if ((s & m) != m) ++ ret = ERR_PTR(-ETXTBSY); ++ else if (memfd->start + memfd->size > (u64)i_size_read(file_inode(f))) ++ ret = ERR_PTR(-EFAULT); ++ else ++ ret = f; ++ ++ if (f != ret) ++ fput(f); ++ ++ return ret; ++} ++ ++static int kdbus_msg_examine(struct kdbus_msg *msg, struct kdbus_bus *bus, ++ struct kdbus_cmd_send *cmd, size_t *out_n_memfds, ++ size_t *out_n_fds, size_t *out_n_parts) ++{ ++ struct kdbus_item *item, *fds = NULL, *bloom = NULL, *dstname = NULL; ++ u64 n_parts, n_memfds, n_fds, vec_size; ++ ++ /* ++ * Step 1: ++ * Validate the message and command parameters. ++ */ ++ ++ /* KDBUS_PAYLOAD_KERNEL is reserved to kernel messages */ ++ if (msg->payload_type == KDBUS_PAYLOAD_KERNEL) ++ return -EINVAL; ++ ++ if (msg->dst_id == KDBUS_DST_ID_BROADCAST) { ++ /* broadcasts must be marked as signals */ ++ if (!(msg->flags & KDBUS_MSG_SIGNAL)) ++ return -EBADMSG; ++ /* broadcasts cannot have timeouts */ ++ if (msg->timeout_ns > 0) ++ return -ENOTUNIQ; ++ } ++ ++ if (msg->flags & KDBUS_MSG_EXPECT_REPLY) { ++ /* if you expect a reply, you must specify a timeout */ ++ if (msg->timeout_ns == 0) ++ return -EINVAL; ++ /* signals cannot have replies */ ++ if (msg->flags & KDBUS_MSG_SIGNAL) ++ return -ENOTUNIQ; ++ } else { ++ /* must expect reply if sent as synchronous call */ ++ if (cmd->flags & KDBUS_SEND_SYNC_REPLY) ++ return -EINVAL; ++ /* cannot mark replies as signal */ ++ if (msg->cookie_reply && (msg->flags & KDBUS_MSG_SIGNAL)) ++ return -EINVAL; ++ } ++ ++ /* ++ * Step 2: ++ * Validate all passed items. While at it, select some statistics that ++ * are required to allocate state objects later on. ++ * ++ * Generic item validation has already been done via ++ * kdbus_item_validate(). Furthermore, the number of items is naturally ++ * limited by the maximum message size. Hence, only non-generic item ++ * checks are performed here (mainly integer overflow tests). ++ */ ++ ++ n_parts = 0; ++ n_memfds = 0; ++ n_fds = 0; ++ vec_size = 0; ++ ++ KDBUS_ITEMS_FOREACH(item, msg->items, KDBUS_ITEMS_SIZE(msg, items)) { ++ switch (item->type) { ++ case KDBUS_ITEM_PAYLOAD_VEC: { ++ void __force __user *ptr = KDBUS_PTR(item->vec.address); ++ u64 size = item->vec.size; ++ ++ if (vec_size + size < vec_size) ++ return -EMSGSIZE; ++ if (vec_size + size > KDBUS_MSG_MAX_PAYLOAD_VEC_SIZE) ++ return -EMSGSIZE; ++ if (ptr && unlikely(!access_ok(VERIFY_READ, ptr, size))) ++ return -EFAULT; ++ ++ if (ptr || size % 8) /* data or padding */ ++ ++n_parts; ++ break; ++ } ++ case KDBUS_ITEM_PAYLOAD_MEMFD: { ++ u64 start = item->memfd.start; ++ u64 size = item->memfd.size; ++ ++ if (start + size < start) ++ return -EMSGSIZE; ++ if (n_memfds >= KDBUS_MSG_MAX_MEMFD_ITEMS) ++ return -E2BIG; ++ ++ ++n_memfds; ++ if (size % 8) /* vec-padding required */ ++ ++n_parts; ++ break; ++ } ++ case KDBUS_ITEM_FDS: { ++ if (fds) ++ return -EEXIST; ++ ++ fds = item; ++ n_fds = KDBUS_ITEM_PAYLOAD_SIZE(item) / sizeof(int); ++ if (n_fds > KDBUS_CONN_MAX_FDS_PER_USER) ++ return -EMFILE; ++ ++ break; ++ } ++ case KDBUS_ITEM_BLOOM_FILTER: { ++ u64 bloom_size; ++ ++ if (bloom) ++ return -EEXIST; ++ ++ bloom = item; ++ bloom_size = KDBUS_ITEM_PAYLOAD_SIZE(item) - ++ offsetof(struct kdbus_bloom_filter, data); ++ if (!KDBUS_IS_ALIGNED8(bloom_size)) ++ return -EFAULT; ++ if (bloom_size != bus->bloom.size) ++ return -EDOM; ++ ++ break; ++ } ++ case KDBUS_ITEM_DST_NAME: { ++ if (dstname) ++ return -EEXIST; ++ ++ dstname = item; ++ if (!kdbus_name_is_valid(item->str, false)) ++ return -EINVAL; ++ if (msg->dst_id == KDBUS_DST_ID_BROADCAST) ++ return -EBADMSG; ++ ++ break; ++ } ++ default: ++ return -EINVAL; ++ } ++ } ++ ++ /* ++ * Step 3: ++ * Validate that required items were actually passed, and that no item ++ * contradicts the message flags. ++ */ ++ ++ /* bloom filters must be attached _iff_ it's a signal */ ++ if (!(msg->flags & KDBUS_MSG_SIGNAL) != !bloom) ++ return -EBADMSG; ++ /* destination name is required if no ID is given */ ++ if (msg->dst_id == KDBUS_DST_ID_NAME && !dstname) ++ return -EDESTADDRREQ; ++ /* cannot send file-descriptors attached to broadcasts */ ++ if (msg->dst_id == KDBUS_DST_ID_BROADCAST && fds) ++ return -ENOTUNIQ; ++ ++ *out_n_memfds = n_memfds; ++ *out_n_fds = n_fds; ++ *out_n_parts = n_parts; ++ ++ return 0; ++} ++ ++static bool kdbus_staging_merge_vecs(struct kdbus_staging *staging, ++ struct kdbus_item **prev_item, ++ struct iovec **prev_vec, ++ const struct kdbus_item *merge) ++{ ++ void __user *ptr = (void __user *)KDBUS_PTR(merge->vec.address); ++ u64 padding = merge->vec.size % 8; ++ struct kdbus_item *prev = *prev_item; ++ struct iovec *vec = *prev_vec; ++ ++ /* XXX: merging is disabled so far */ ++ if (0 && prev && prev->type == KDBUS_ITEM_PAYLOAD_OFF && ++ !merge->vec.address == !prev->vec.address) { ++ /* ++ * If we merge two VECs, we can always drop the second ++ * PAYLOAD_VEC item. Hence, include its size in the previous ++ * one. ++ */ ++ prev->vec.size += merge->vec.size; ++ ++ if (ptr) { ++ /* ++ * If we merge two data VECs, we need two iovecs to copy ++ * the data. But the items can be easily merged by ++ * summing their lengths. ++ */ ++ vec = &staging->parts[staging->n_parts++]; ++ vec->iov_len = merge->vec.size; ++ vec->iov_base = ptr; ++ staging->n_payload += vec->iov_len; ++ } else if (padding) { ++ /* ++ * If we merge two 0-vecs with the second 0-vec ++ * requiring padding, we need to insert an iovec to copy ++ * the 0-padding. We try merging it with the previous ++ * 0-padding iovec. This might end up with an ++ * iov_len==0, in which case we simply drop the iovec. ++ */ ++ if (vec) { ++ staging->n_payload -= vec->iov_len; ++ vec->iov_len = prev->vec.size % 8; ++ if (!vec->iov_len) { ++ --staging->n_parts; ++ vec = NULL; ++ } else { ++ staging->n_payload += vec->iov_len; ++ } ++ } else { ++ vec = &staging->parts[staging->n_parts++]; ++ vec->iov_len = padding; ++ vec->iov_base = (char __user *)zeros; ++ staging->n_payload += vec->iov_len; ++ } ++ } else { ++ /* ++ * If we merge two 0-vecs with the second 0-vec having ++ * no padding, we know the padding of the first stays ++ * the same. Hence, @vec needs no adjustment. ++ */ ++ } ++ ++ /* successfully merged with previous item */ ++ merge = prev; ++ } else { ++ /* ++ * If we cannot merge the payload item with the previous one, ++ * we simply insert a new iovec for the data/padding. ++ */ ++ if (ptr) { ++ vec = &staging->parts[staging->n_parts++]; ++ vec->iov_len = merge->vec.size; ++ vec->iov_base = ptr; ++ staging->n_payload += vec->iov_len; ++ } else if (padding) { ++ vec = &staging->parts[staging->n_parts++]; ++ vec->iov_len = padding; ++ vec->iov_base = (char __user *)zeros; ++ staging->n_payload += vec->iov_len; ++ } else { ++ vec = NULL; ++ } ++ } ++ ++ *prev_item = (struct kdbus_item *)merge; ++ *prev_vec = vec; ++ ++ return merge == prev; ++} ++ ++static int kdbus_staging_import(struct kdbus_staging *staging) ++{ ++ struct kdbus_item *it, *item, *last, *prev_payload; ++ struct kdbus_gaps *gaps = staging->gaps; ++ struct kdbus_msg *msg = staging->msg; ++ struct iovec *part, *prev_part; ++ bool drop_item; ++ ++ drop_item = false; ++ last = NULL; ++ prev_payload = NULL; ++ prev_part = NULL; ++ ++ /* ++ * We modify msg->items along the way; make sure to use @item as offset ++ * to the next item (instead of the iterator @it). ++ */ ++ for (it = item = msg->items; ++ it >= msg->items && ++ (u8 *)it < (u8 *)msg + msg->size && ++ (u8 *)it + it->size <= (u8 *)msg + msg->size; ) { ++ /* ++ * If we dropped items along the way, move current item to ++ * front. We must not access @it afterwards, but use @item ++ * instead! ++ */ ++ if (it != item) ++ memmove(item, it, it->size); ++ it = (void *)((u8 *)it + KDBUS_ALIGN8(item->size)); ++ ++ switch (item->type) { ++ case KDBUS_ITEM_PAYLOAD_VEC: { ++ size_t offset = staging->n_payload; ++ ++ if (kdbus_staging_merge_vecs(staging, &prev_payload, ++ &prev_part, item)) { ++ drop_item = true; ++ } else if (item->vec.address) { ++ /* real offset is patched later on */ ++ item->type = KDBUS_ITEM_PAYLOAD_OFF; ++ item->vec.offset = offset; ++ } else { ++ item->type = KDBUS_ITEM_PAYLOAD_OFF; ++ item->vec.offset = ~0ULL; ++ } ++ ++ break; ++ } ++ case KDBUS_ITEM_PAYLOAD_MEMFD: { ++ struct file *f; ++ ++ f = kdbus_get_memfd(&item->memfd); ++ if (IS_ERR(f)) ++ return PTR_ERR(f); ++ ++ gaps->memfd_files[gaps->n_memfds] = f; ++ gaps->memfd_offsets[gaps->n_memfds] = ++ (u8 *)&item->memfd.fd - (u8 *)msg; ++ ++gaps->n_memfds; ++ ++ /* memfds cannot be merged */ ++ prev_payload = item; ++ prev_part = NULL; ++ ++ /* insert padding to make following VECs aligned */ ++ if (item->memfd.size % 8) { ++ part = &staging->parts[staging->n_parts++]; ++ part->iov_len = item->memfd.size % 8; ++ part->iov_base = (char __user *)zeros; ++ staging->n_payload += part->iov_len; ++ } ++ ++ break; ++ } ++ case KDBUS_ITEM_FDS: { ++ size_t i, n_fds; ++ ++ n_fds = KDBUS_ITEM_PAYLOAD_SIZE(item) / sizeof(int); ++ for (i = 0; i < n_fds; ++i) { ++ struct file *f; ++ ++ f = kdbus_get_fd(item->fds[i]); ++ if (IS_ERR(f)) ++ return PTR_ERR(f); ++ ++ gaps->fd_files[gaps->n_fds++] = f; ++ } ++ ++ gaps->fd_offset = (u8 *)item->fds - (u8 *)msg; ++ ++ break; ++ } ++ case KDBUS_ITEM_BLOOM_FILTER: ++ staging->bloom_filter = &item->bloom_filter; ++ break; ++ case KDBUS_ITEM_DST_NAME: ++ staging->dst_name = item->str; ++ break; ++ } ++ ++ /* drop item if we merged it with a previous one */ ++ if (drop_item) { ++ drop_item = false; ++ } else { ++ last = item; ++ item = KDBUS_ITEM_NEXT(item); ++ } ++ } ++ ++ /* adjust message size regarding dropped items */ ++ msg->size = offsetof(struct kdbus_msg, items); ++ if (last) ++ msg->size += ((u8 *)last - (u8 *)msg->items) + last->size; ++ ++ return 0; ++} ++ ++static void kdbus_staging_reserve(struct kdbus_staging *staging) ++{ ++ struct iovec *part; ++ ++ part = &staging->parts[staging->n_parts++]; ++ part->iov_base = (void __user *)zeros; ++ part->iov_len = 0; ++} ++ ++static struct kdbus_staging *kdbus_staging_new(struct kdbus_bus *bus, ++ size_t n_parts, ++ size_t msg_extra_size) ++{ ++ const size_t reserved_parts = 5; /* see below for explanation */ ++ struct kdbus_staging *staging; ++ int ret; ++ ++ n_parts += reserved_parts; ++ ++ staging = kzalloc(sizeof(*staging) + n_parts * sizeof(*staging->parts) + ++ msg_extra_size, GFP_TEMPORARY); ++ if (!staging) ++ return ERR_PTR(-ENOMEM); ++ ++ staging->msg_seqnum = atomic64_inc_return(&bus->domain->last_id); ++ staging->n_parts = 0; /* we reserve n_parts, but don't enforce them */ ++ staging->parts = (void *)(staging + 1); ++ ++ if (msg_extra_size) /* if requested, allocate message, too */ ++ staging->msg = (void *)((u8 *)staging->parts + ++ n_parts * sizeof(*staging->parts)); ++ ++ staging->meta_proc = kdbus_meta_proc_new(); ++ if (IS_ERR(staging->meta_proc)) { ++ ret = PTR_ERR(staging->meta_proc); ++ staging->meta_proc = NULL; ++ goto error; ++ } ++ ++ staging->meta_conn = kdbus_meta_conn_new(); ++ if (IS_ERR(staging->meta_conn)) { ++ ret = PTR_ERR(staging->meta_conn); ++ staging->meta_conn = NULL; ++ goto error; ++ } ++ ++ /* ++ * Prepare iovecs to copy the message into the target pool. We use the ++ * following iovecs: ++ * * iovec to copy "kdbus_msg.size" ++ * * iovec to copy "struct kdbus_msg" (minus size) plus items ++ * * iovec for possible padding after the items ++ * * iovec for metadata items ++ * * iovec for possible padding after the items ++ * ++ * Make sure to update @reserved_parts if you add more parts here. ++ */ ++ ++ kdbus_staging_reserve(staging); /* msg.size */ ++ kdbus_staging_reserve(staging); /* msg (minus msg.size) plus items */ ++ kdbus_staging_reserve(staging); /* msg padding */ ++ kdbus_staging_reserve(staging); /* meta */ ++ kdbus_staging_reserve(staging); /* meta padding */ ++ ++ return staging; ++ ++error: ++ kdbus_staging_free(staging); ++ return ERR_PTR(ret); ++} ++ ++struct kdbus_staging *kdbus_staging_new_kernel(struct kdbus_bus *bus, ++ u64 dst, u64 cookie_timeout, ++ size_t it_size, size_t it_type) ++{ ++ struct kdbus_staging *staging; ++ size_t size; ++ ++ size = offsetof(struct kdbus_msg, items) + ++ KDBUS_ITEM_HEADER_SIZE + it_size; ++ ++ staging = kdbus_staging_new(bus, 0, KDBUS_ALIGN8(size)); ++ if (IS_ERR(staging)) ++ return ERR_CAST(staging); ++ ++ staging->msg->size = size; ++ staging->msg->flags = (dst == KDBUS_DST_ID_BROADCAST) ? ++ KDBUS_MSG_SIGNAL : 0; ++ staging->msg->dst_id = dst; ++ staging->msg->src_id = KDBUS_SRC_ID_KERNEL; ++ staging->msg->payload_type = KDBUS_PAYLOAD_KERNEL; ++ staging->msg->cookie_reply = cookie_timeout; ++ staging->notify = staging->msg->items; ++ staging->notify->size = KDBUS_ITEM_HEADER_SIZE + it_size; ++ staging->notify->type = it_type; ++ ++ return staging; ++} ++ ++struct kdbus_staging *kdbus_staging_new_user(struct kdbus_bus *bus, ++ struct kdbus_cmd_send *cmd, ++ struct kdbus_msg *msg) ++{ ++ const size_t reserved_parts = 1; /* see below for explanation */ ++ size_t n_memfds, n_fds, n_parts; ++ struct kdbus_staging *staging; ++ int ret; ++ ++ /* ++ * Examine user-supplied message and figure out how many resources we ++ * need to allocate in our staging area. This requires us to iterate ++ * the message twice, but saves us from re-allocating our resources ++ * all the time. ++ */ ++ ++ ret = kdbus_msg_examine(msg, bus, cmd, &n_memfds, &n_fds, &n_parts); ++ if (ret < 0) ++ return ERR_PTR(ret); ++ ++ n_parts += reserved_parts; ++ ++ /* ++ * Allocate staging area with the number of required resources. Make ++ * sure that we have enough iovecs for all required parts pre-allocated ++ * so this will hopefully be the only memory allocation for this ++ * message transaction. ++ */ ++ ++ staging = kdbus_staging_new(bus, n_parts, 0); ++ if (IS_ERR(staging)) ++ return ERR_CAST(staging); ++ ++ staging->msg = msg; ++ ++ /* ++ * If the message contains memfds or fd items, we need to remember some ++ * state so we can fill in the requested information at RECV time. ++ * File-descriptors cannot be passed at SEND time. Hence, allocate a ++ * gaps-object to remember that state. That gaps object is linked to ++ * from the staging area, but will also be linked to from the message ++ * queue of each peer. Hence, each receiver owns a reference to it, and ++ * it will later be used to fill the 'gaps' in message that couldn't be ++ * filled at SEND time. ++ * Note that the 'gaps' object is read-only once the staging-allocator ++ * returns. There might be connections receiving a queued message while ++ * the sender still broadcasts the message to other receivers. ++ */ ++ ++ if (n_memfds > 0 || n_fds > 0) { ++ staging->gaps = kdbus_gaps_new(n_memfds, n_fds); ++ if (IS_ERR(staging->gaps)) { ++ ret = PTR_ERR(staging->gaps); ++ staging->gaps = NULL; ++ kdbus_staging_free(staging); ++ return ERR_PTR(ret); ++ } ++ } ++ ++ /* ++ * kdbus_staging_new() already reserves parts for message setup. For ++ * user-supplied messages, we add the following iovecs: ++ * ... variable number of iovecs for payload ... ++ * * final iovec for possible padding of payload ++ * ++ * Make sure to update @reserved_parts if you add more parts here. ++ */ ++ ++ ret = kdbus_staging_import(staging); /* payload */ ++ kdbus_staging_reserve(staging); /* payload padding */ ++ ++ if (ret < 0) ++ goto error; ++ ++ return staging; ++ ++error: ++ kdbus_staging_free(staging); ++ return ERR_PTR(ret); ++} ++ ++struct kdbus_staging *kdbus_staging_free(struct kdbus_staging *staging) ++{ ++ if (!staging) ++ return NULL; ++ ++ kdbus_meta_conn_unref(staging->meta_conn); ++ kdbus_meta_proc_unref(staging->meta_proc); ++ kdbus_gaps_unref(staging->gaps); ++ kfree(staging); ++ ++ return NULL; ++} ++ ++static int kdbus_staging_collect_metadata(struct kdbus_staging *staging, ++ struct kdbus_conn *src, ++ struct kdbus_conn *dst, ++ u64 *out_attach) ++{ ++ u64 attach; ++ int ret; ++ ++ if (src) ++ attach = kdbus_meta_calc_attach_flags(src, dst); ++ else ++ attach = KDBUS_ATTACH_TIMESTAMP; /* metadata for kernel msgs */ ++ ++ if (src && !src->meta_fake) { ++ ret = kdbus_meta_proc_collect(staging->meta_proc, attach); ++ if (ret < 0) ++ return ret; ++ } ++ ++ ret = kdbus_meta_conn_collect(staging->meta_conn, src, ++ staging->msg_seqnum, attach); ++ if (ret < 0) ++ return ret; ++ ++ *out_attach = attach; ++ return 0; ++} ++ ++/** ++ * kdbus_staging_emit() - emit linearized message in target pool ++ * @staging: staging object to create message from ++ * @src: sender of the message (or NULL) ++ * @dst: target connection to allocate message for ++ * ++ * This allocates a pool-slice for @dst and copies the message provided by ++ * @staging into it. The new slice is then returned to the caller for further ++ * processing. It's not linked into any queue, yet. ++ * ++ * Return: Newly allocated slice or ERR_PTR on failure. ++ */ ++struct kdbus_pool_slice *kdbus_staging_emit(struct kdbus_staging *staging, ++ struct kdbus_conn *src, ++ struct kdbus_conn *dst) ++{ ++ struct kdbus_item *item, *meta_items = NULL; ++ struct kdbus_pool_slice *slice = NULL; ++ size_t off, size, msg_size, meta_size; ++ struct iovec *v; ++ u64 attach; ++ int ret; ++ ++ /* ++ * Step 1: ++ * Collect metadata from @src depending on the attach-flags allowed for ++ * @dst. Translate it into the namespaces pinned by @dst. ++ */ ++ ++ ret = kdbus_staging_collect_metadata(staging, src, dst, &attach); ++ if (ret < 0) ++ goto error; ++ ++ ret = kdbus_meta_emit(staging->meta_proc, NULL, staging->meta_conn, ++ dst, attach, &meta_items, &meta_size); ++ if (ret < 0) ++ goto error; ++ ++ /* ++ * Step 2: ++ * Setup iovecs for the message. See kdbus_staging_new() for allocation ++ * of those iovecs. All reserved iovecs have been initialized with ++ * iov_len=0 + iov_base=zeros. Furthermore, the iovecs to copy the ++ * actual message payload have already been initialized and need not be ++ * touched. ++ */ ++ ++ v = staging->parts; ++ msg_size = staging->msg->size; ++ ++ /* msg.size */ ++ v->iov_len = sizeof(msg_size); ++ v->iov_base = &msg_size; ++ ++v; ++ ++ /* msg (after msg.size) plus items */ ++ v->iov_len = staging->msg->size - sizeof(staging->msg->size); ++ v->iov_base = (void __user *)((u8 *)staging->msg + ++ sizeof(staging->msg->size)); ++ ++v; ++ ++ /* padding after msg */ ++ v->iov_len = KDBUS_ALIGN8(staging->msg->size) - staging->msg->size; ++ v->iov_base = (void __user *)zeros; ++ ++v; ++ ++ if (meta_size > 0) { ++ /* metadata items */ ++ v->iov_len = meta_size; ++ v->iov_base = meta_items; ++ ++v; ++ ++ /* padding after metadata */ ++ v->iov_len = KDBUS_ALIGN8(meta_size) - meta_size; ++ v->iov_base = (void __user *)zeros; ++ ++v; ++ ++ msg_size = KDBUS_ALIGN8(msg_size) + meta_size; ++ } ++ ++ /* ... payload iovecs are already filled in ... */ ++ ++ /* compute overall size and fill in padding after payload */ ++ size = KDBUS_ALIGN8(msg_size); ++ ++ if (staging->n_payload > 0) { ++ size += staging->n_payload; ++ ++ v = &staging->parts[staging->n_parts - 1]; ++ v->iov_len = KDBUS_ALIGN8(size) - size; ++ v->iov_base = (void __user *)zeros; ++ ++ size = KDBUS_ALIGN8(size); ++ } ++ ++ /* ++ * Step 3: ++ * The PAYLOAD_OFF items in the message contain a relative 'offset' ++ * field that tells the receiver where to find the actual payload. This ++ * offset is relative to the start of the message, and as such depends ++ * on the size of the metadata items we inserted. This size is variable ++ * and changes for each peer we send the message to. Hence, we remember ++ * the last relative offset that was used to calculate the 'offset' ++ * fields. For each message, we re-calculate it and patch all items, in ++ * case it changed. ++ */ ++ ++ off = KDBUS_ALIGN8(msg_size); ++ ++ if (off != staging->i_payload) { ++ KDBUS_ITEMS_FOREACH(item, staging->msg->items, ++ KDBUS_ITEMS_SIZE(staging->msg, items)) { ++ if (item->type != KDBUS_ITEM_PAYLOAD_OFF) ++ continue; ++ ++ item->vec.offset -= staging->i_payload; ++ item->vec.offset += off; ++ } ++ ++ staging->i_payload = off; ++ } ++ ++ /* ++ * Step 4: ++ * Allocate pool slice and copy over all data. Make sure to properly ++ * account on user quota. ++ */ ++ ++ ret = kdbus_conn_quota_inc(dst, src ? src->user : NULL, size, ++ staging->gaps ? staging->gaps->n_fds : 0); ++ if (ret < 0) ++ goto error; ++ ++ slice = kdbus_pool_slice_alloc(dst->pool, size, true); ++ if (IS_ERR(slice)) { ++ ret = PTR_ERR(slice); ++ slice = NULL; ++ goto error; ++ } ++ ++ WARN_ON(kdbus_pool_slice_size(slice) != size); ++ ++ ret = kdbus_pool_slice_copy_iovec(slice, 0, staging->parts, ++ staging->n_parts, size); ++ if (ret < 0) ++ goto error; ++ ++ /* all done, return slice to caller */ ++ goto exit; ++ ++error: ++ if (slice) ++ kdbus_conn_quota_dec(dst, src ? src->user : NULL, size, ++ staging->gaps ? staging->gaps->n_fds : 0); ++ kdbus_pool_slice_release(slice); ++ slice = ERR_PTR(ret); ++exit: ++ kfree(meta_items); ++ return slice; ++} +diff --git a/ipc/kdbus/message.h b/ipc/kdbus/message.h +index 5755ad4c9fd9..8fe49a961834 100644 +--- a/ipc/kdbus/message.h ++++ b/ipc/kdbus/message.h +@@ -124,4 +124,97 @@ void kdbus_kmsg_free(struct kdbus_kmsg *kmsg); + int kdbus_kmsg_collect_metadata(const struct kdbus_kmsg *kmsg, + struct kdbus_conn *src, struct kdbus_conn *dst); + ++/** ++ * struct kdbus_gaps - gaps in message to be filled later ++ * @kref: Reference counter ++ * @n_memfd_offs: Number of memfds ++ * @memfd_offs: Offsets of kdbus_memfd items in target slice ++ * @n_fds: Number of fds ++ * @fds: Array of sent fds ++ * @fds_offset: Offset of fd-array in target slice ++ * ++ * The 'gaps' object is used to track data that is needed to fill gaps in a ++ * message at RECV time. Usually, we try to compile the whole message at SEND ++ * time. This has the advantage, that we don't have to cache any information and ++ * can keep the memory consumption small. Furthermore, all copy operations can ++ * be combined into a single function call, which speeds up transactions ++ * considerably. ++ * However, things like file-descriptors can only be fully installed at RECV ++ * time. The gaps object tracks this data and pins it until a message is ++ * received. The gaps object is shared between all receivers of the same ++ * message. ++ */ ++struct kdbus_gaps { ++ struct kref kref; ++ ++ /* state tracking for KDBUS_ITEM_PAYLOAD_MEMFD entries */ ++ size_t n_memfds; ++ u64 *memfd_offsets; ++ struct file **memfd_files; ++ ++ /* state tracking for KDBUS_ITEM_FDS */ ++ size_t n_fds; ++ struct file **fd_files; ++ u64 fd_offset; ++}; ++ ++struct kdbus_gaps *kdbus_gaps_ref(struct kdbus_gaps *gaps); ++struct kdbus_gaps *kdbus_gaps_unref(struct kdbus_gaps *gaps); ++int kdbus_gaps_install(struct kdbus_gaps *gaps, struct kdbus_pool_slice *slice, ++ bool *out_incomplete); ++ ++/** ++ * struct kdbus_staging - staging area to import messages ++ * @msg: User-supplied message ++ * @gaps: Gaps-object created during import (or NULL if empty) ++ * @msg_seqnum: Message sequence number ++ * @notify_entry: Entry into list of kernel-generated notifications ++ * @i_payload: Current relative index of start of payload ++ * @n_payload: Total number of bytes needed for payload ++ * @n_parts: Number of parts ++ * @parts: Array of iovecs that make up the whole message ++ * @meta_proc: Process metadata of the sender (or NULL if empty) ++ * @meta_conn: Connection metadata of the sender (or NULL if empty) ++ * @bloom_filter: Pointer to the bloom-item in @msg, or NULL ++ * @dst_name: Pointer to the dst-name-item in @msg, or NULL ++ * @notify: Pointer to the notification item in @msg, or NULL ++ * ++ * The kdbus_staging object is a temporary staging area to import user-supplied ++ * messages into the kernel. It is only used during SEND and dropped once the ++ * message is queued. Any data that cannot be collected during SEND, is ++ * collected in a kdbus_gaps object and attached to the message queue. ++ */ ++struct kdbus_staging { ++ struct kdbus_msg *msg; ++ struct kdbus_gaps *gaps; ++ u64 msg_seqnum; ++ struct list_head notify_entry; ++ ++ /* crafted iovecs to copy the message */ ++ size_t i_payload; ++ size_t n_payload; ++ size_t n_parts; ++ struct iovec *parts; ++ ++ /* metadata state */ ++ struct kdbus_meta_proc *meta_proc; ++ struct kdbus_meta_conn *meta_conn; ++ ++ /* cached pointers into @msg */ ++ const struct kdbus_bloom_filter *bloom_filter; ++ const char *dst_name; ++ struct kdbus_item *notify; ++}; ++ ++struct kdbus_staging *kdbus_staging_new_kernel(struct kdbus_bus *bus, ++ u64 dst, u64 cookie_timeout, ++ size_t it_size, size_t it_type); ++struct kdbus_staging *kdbus_staging_new_user(struct kdbus_bus *bus, ++ struct kdbus_cmd_send *cmd, ++ struct kdbus_msg *msg); ++struct kdbus_staging *kdbus_staging_free(struct kdbus_staging *staging); ++struct kdbus_pool_slice *kdbus_staging_emit(struct kdbus_staging *staging, ++ struct kdbus_conn *src, ++ struct kdbus_conn *dst); ++ + #endif +-- +2.4.3 + + +From 5eb3ea76d55f52ff6f5abdb88f925e2a695c2732 Mon Sep 17 00:00:00 2001 +From: David Herrmann <dh.herrmann@gmail.com> +Date: Sat, 20 Jun 2015 00:53:58 +0200 +Subject: [PATCH 24/34] kdbus: remove unused code + +kdbus_item_get() and kdbus_item_get_str() are not used anywhere. Drop +them. They probably got obsoleted during the introduction of kdbus_args. + +Signed-off-by: David Herrmann <dh.herrmann@gmail.com> +--- + ipc/kdbus/item.c | 41 ----------------------------------------- + ipc/kdbus/item.h | 3 --- + 2 files changed, 44 deletions(-) + +diff --git a/ipc/kdbus/item.c b/ipc/kdbus/item.c +index 1ee72c2ad7c3..e763083cc16c 100644 +--- a/ipc/kdbus/item.c ++++ b/ipc/kdbus/item.c +@@ -260,47 +260,6 @@ int kdbus_items_validate(const struct kdbus_item *items, size_t items_size) + return 0; + } + +-static struct kdbus_item *kdbus_items_get(const struct kdbus_item *items, +- size_t items_size, +- unsigned int item_type) +-{ +- const struct kdbus_item *iter, *found = NULL; +- +- KDBUS_ITEMS_FOREACH(iter, items, items_size) { +- if (iter->type == item_type) { +- if (found) +- return ERR_PTR(-EEXIST); +- found = iter; +- } +- } +- +- return (struct kdbus_item *)found ? : ERR_PTR(-EBADMSG); +-} +- +-/** +- * kdbus_items_get_str() - get string from a list of items +- * @items: The items to walk +- * @items_size: The size of all items +- * @item_type: The item type to look for +- * +- * This function walks a list of items and searches for items of type +- * @item_type. If it finds exactly one such item, @str_ret will be set to +- * the .str member of the item. +- * +- * Return: the string, if the item was found exactly once, ERR_PTR(-EEXIST) +- * if the item was found more than once, and ERR_PTR(-EBADMSG) if there was +- * no item of the given type. +- */ +-const char *kdbus_items_get_str(const struct kdbus_item *items, +- size_t items_size, +- unsigned int item_type) +-{ +- const struct kdbus_item *item; +- +- item = kdbus_items_get(items, items_size, item_type); +- return IS_ERR(item) ? ERR_CAST(item) : item->str; +-} +- + /** + * kdbus_item_set() - Set item content + * @item: The item to modify +diff --git a/ipc/kdbus/item.h b/ipc/kdbus/item.h +index bca63b4e6e80..3a7e6ccc253c 100644 +--- a/ipc/kdbus/item.h ++++ b/ipc/kdbus/item.h +@@ -55,9 +55,6 @@ struct kdbus_item_header { + int kdbus_item_validate_name(const struct kdbus_item *item); + int kdbus_item_validate(const struct kdbus_item *item); + int kdbus_items_validate(const struct kdbus_item *items, size_t items_size); +-const char *kdbus_items_get_str(const struct kdbus_item *items, +- size_t items_size, +- unsigned int item_type); + struct kdbus_item *kdbus_item_set(struct kdbus_item *item, u64 type, + const void *data, size_t len); + +-- +2.4.3 + + +From 992775c9c377ca14c6dcd2890283602a3fb36213 Mon Sep 17 00:00:00 2001 +From: David Herrmann <dh.herrmann@gmail.com> +Date: Sat, 20 Jun 2015 11:37:58 +0200 +Subject: [PATCH 25/34] kdbus: import messages via kdbus_args + +The kdbus_args helpers take care of copying command payloads into +kernel-space, verifying item validity and implementing negotiation. So +far, we use it for all user-space interaction but messages. This patch +adds support for kdbus-messages via kdbus_args so all user-space +interaction will now use kdbus_args. + +This has the benefit that we now support negotiation for messages, +stack-placement in case the messages are small enough, and unify the item +handling across all callers. + +This patch does *not* remove the old message importer. Instead, follow-up +patches will slowly perform the transition to the new one. It will be +removed once the transition is done. + +Signed-off-by: David Herrmann <dh.herrmann@gmail.com> +--- + ipc/kdbus/connection.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++--- + ipc/kdbus/handle.c | 15 +++++++++---- + ipc/kdbus/handle.h | 17 ++++++++++++-- + 3 files changed, 84 insertions(+), 9 deletions(-) + +diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c +index 29b99c023bfe..20bb083aa2b4 100644 +--- a/ipc/kdbus/connection.c ++++ b/ipc/kdbus/connection.c +@@ -1929,10 +1929,13 @@ exit: + int kdbus_cmd_send(struct kdbus_conn *conn, struct file *f, void __user *argp) + { + struct kdbus_cmd_send *cmd; ++ struct kdbus_staging *staging = NULL; + struct kdbus_kmsg *kmsg = NULL; ++ struct kdbus_msg *msg = NULL; + struct file *cancel_fd = NULL; +- int ret; ++ int ret, ret2; + ++ /* command arguments */ + struct kdbus_arg argv[] = { + { .type = KDBUS_ITEM_NEGOTIATE }, + { .type = KDBUS_ITEM_CANCEL_FD }, +@@ -1944,12 +1947,48 @@ int kdbus_cmd_send(struct kdbus_conn *conn, struct file *f, void __user *argp) + .argc = ARRAY_SIZE(argv), + }; + ++ /* message arguments */ ++ struct kdbus_arg msg_argv[] = { ++ { .type = KDBUS_ITEM_NEGOTIATE }, ++ { .type = KDBUS_ITEM_PAYLOAD_VEC, .multiple = true }, ++ { .type = KDBUS_ITEM_PAYLOAD_MEMFD, .multiple = true }, ++ { .type = KDBUS_ITEM_FDS }, ++ { .type = KDBUS_ITEM_BLOOM_FILTER }, ++ { .type = KDBUS_ITEM_DST_NAME }, ++ }; ++ struct kdbus_args msg_args = { ++ .allowed_flags = KDBUS_FLAG_NEGOTIATE | ++ KDBUS_MSG_EXPECT_REPLY | ++ KDBUS_MSG_NO_AUTO_START | ++ KDBUS_MSG_SIGNAL, ++ .argv = msg_argv, ++ .argc = ARRAY_SIZE(msg_argv), ++ }; ++ + if (!kdbus_conn_is_ordinary(conn)) + return -EOPNOTSUPP; + ++ /* make sure to parse both, @cmd and @msg on negotiation */ ++ + ret = kdbus_args_parse(&args, argp, &cmd); +- if (ret != 0) +- return ret; ++ if (ret < 0) ++ goto exit; ++ else if (ret > 0 && !cmd->msg_address) /* negotiation without msg */ ++ goto exit; ++ ++ ret2 = kdbus_args_parse_msg(&msg_args, KDBUS_PTR(cmd->msg_address), ++ &msg); ++ if (ret2 < 0) { /* cannot parse message */ ++ ret = ret2; ++ goto exit; ++ } else if (ret2 > 0 && !ret) { /* msg-negot implies cmd-negot */ ++ ret = -EINVAL; ++ goto exit; ++ } else if (ret > 0) { /* negotiation */ ++ goto exit; ++ } ++ ++ /* here we parsed both, @cmd and @msg, and neither wants negotiation */ + + cmd->reply.return_flags = 0; + kdbus_pool_publish_empty(conn->pool, &cmd->reply.offset, +@@ -1968,6 +2007,20 @@ int kdbus_cmd_send(struct kdbus_conn *conn, struct file *f, void __user *argp) + } + } + ++ /* patch-in the source of this message */ ++ if (msg->src_id > 0 && msg->src_id != conn->id) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ msg->src_id = conn->id; ++ ++ staging = kdbus_staging_new_user(conn->ep->bus, cmd, msg); ++ if (IS_ERR(staging)) { ++ ret = PTR_ERR(staging); ++ staging = NULL; ++ goto exit; ++ } ++ + kmsg = kdbus_kmsg_new_from_cmd(conn, cmd); + if (IS_ERR(kmsg)) { + ret = PTR_ERR(kmsg); +@@ -2012,6 +2065,8 @@ exit: + if (cancel_fd) + fput(cancel_fd); + kdbus_kmsg_free(kmsg); ++ kdbus_staging_free(staging); ++ ret = kdbus_args_clear(&msg_args, ret); + return kdbus_args_clear(&args, ret); + } + +diff --git a/ipc/kdbus/handle.c b/ipc/kdbus/handle.c +index 07527990a051..e0e06b0e1114 100644 +--- a/ipc/kdbus/handle.c ++++ b/ipc/kdbus/handle.c +@@ -126,6 +126,7 @@ static int kdbus_args_negotiate(struct kdbus_args *args) + /** + * __kdbus_args_parse() - parse payload of kdbus command + * @args: object to parse data into ++ * @is_cmd: whether this is a command or msg payload + * @argp: user-space location of command payload to parse + * @type_size: overall size of command payload to parse + * @items_offset: offset of items array in command payload +@@ -140,10 +141,14 @@ static int kdbus_args_negotiate(struct kdbus_args *args) + * If this function succeeded, you must call kdbus_args_clear() to release + * allocated resources before destroying @args. + * ++ * This can also be used to import kdbus_msg objects. In that case, @is_cmd must ++ * be set to 'false' and the 'return_flags' field will not be touched (as it ++ * doesn't exist on kdbus_msg). ++ * + * Return: On failure a negative error code is returned. Otherwise, 1 is + * returned if negotiation was requested, 0 if not. + */ +-int __kdbus_args_parse(struct kdbus_args *args, void __user *argp, ++int __kdbus_args_parse(struct kdbus_args *args, bool is_cmd, void __user *argp, + size_t type_size, size_t items_offset, void **out) + { + u64 user_size; +@@ -173,10 +178,12 @@ int __kdbus_args_parse(struct kdbus_args *args, void __user *argp, + goto error; + } + +- args->cmd->return_flags = 0; ++ if (is_cmd) ++ args->cmd->return_flags = 0; + args->user = argp; + args->items = (void *)((u8 *)args->cmd + items_offset); + args->items_size = args->cmd->size - items_offset; ++ args->is_cmd = is_cmd; + + if (args->cmd->flags & ~args->allowed_flags) { + ret = -EINVAL; +@@ -225,8 +232,8 @@ int kdbus_args_clear(struct kdbus_args *args, int ret) + return ret; + + if (!IS_ERR_OR_NULL(args->cmd)) { +- if (put_user(args->cmd->return_flags, +- &args->user->return_flags)) ++ if (args->is_cmd && put_user(args->cmd->return_flags, ++ &args->user->return_flags)) + ret = -EFAULT; + if (args->cmd != (void*)args->cmd_buf) + kfree(args->cmd); +diff --git a/ipc/kdbus/handle.h b/ipc/kdbus/handle.h +index 13c59d975728..8a36c0595091 100644 +--- a/ipc/kdbus/handle.h ++++ b/ipc/kdbus/handle.h +@@ -48,6 +48,7 @@ struct kdbus_arg { + * @cmd_buf: 512 bytes inline buf to avoid kmalloc() on small cmds + * @items: points to item array in @cmd + * @items_size: size of @items in bytes ++ * @is_cmd: whether this is a command-payload or msg-payload + * + * This structure is used to parse ioctl command payloads on each invocation. + * The ioctl handler has to pre-fill the flags and allowed items before passing +@@ -68,9 +69,10 @@ struct kdbus_args { + + struct kdbus_item *items; + size_t items_size; ++ bool is_cmd : 1; + }; + +-int __kdbus_args_parse(struct kdbus_args *args, void __user *argp, ++int __kdbus_args_parse(struct kdbus_args *args, bool is_cmd, void __user *argp, + size_t type_size, size_t items_offset, void **out); + int kdbus_args_clear(struct kdbus_args *args, int ret); + +@@ -82,7 +84,18 @@ int kdbus_args_clear(struct kdbus_args *args, int ret); + offsetof(struct kdbus_cmd, flags)); \ + BUILD_BUG_ON(offsetof(typeof(**(_v)), return_flags) != \ + offsetof(struct kdbus_cmd, return_flags)); \ +- __kdbus_args_parse((_args), (_argp), sizeof(**(_v)), \ ++ __kdbus_args_parse((_args), 1, (_argp), sizeof(**(_v)), \ ++ offsetof(typeof(**(_v)), items), \ ++ (void **)(_v)); \ ++ }) ++ ++#define kdbus_args_parse_msg(_args, _argp, _v) \ ++ ({ \ ++ BUILD_BUG_ON(offsetof(typeof(**(_v)), size) != \ ++ offsetof(struct kdbus_cmd, size)); \ ++ BUILD_BUG_ON(offsetof(typeof(**(_v)), flags) != \ ++ offsetof(struct kdbus_cmd, flags)); \ ++ __kdbus_args_parse((_args), 0, (_argp), sizeof(**(_v)), \ + offsetof(typeof(**(_v)), items), \ + (void **)(_v)); \ + }) +-- +2.4.3 + + +From c7bd78731b3a709a6d7d83f4851e30dc1ebf5cca Mon Sep 17 00:00:00 2001 +From: David Herrmann <dh.herrmann@gmail.com> +Date: Wed, 24 Jun 2015 15:27:03 +0200 +Subject: [PATCH 26/34] kdbus: switch to kdbus_staging + +This switches the existing infrastructure to use "kdbus_staging" in favor +of "kdbus_kmsg" and "kdbus_msg_resources". As described during the +introduction of kdbus_staging, it reduces the number of calls into shmem +during each message, and also minimizes the resources we pin until +RECV-time. + +This patch improves the pure message transaction speed by ~30% for empty +payloads. + +Signed-off-by: David Herrmann <dh.herrmann@gmail.com> +--- + ipc/kdbus/bus.c | 30 ++-- + ipc/kdbus/bus.h | 6 +- + ipc/kdbus/connection.c | 134 ++++++++---------- + ipc/kdbus/connection.h | 4 +- + ipc/kdbus/match.c | 26 ++-- + ipc/kdbus/match.h | 8 +- + ipc/kdbus/message.h | 6 + + ipc/kdbus/notify.c | 77 +++++------ + ipc/kdbus/queue.c | 362 +++---------------------------------------------- + ipc/kdbus/queue.h | 42 +++--- + 10 files changed, 176 insertions(+), 519 deletions(-) + +diff --git a/ipc/kdbus/bus.c b/ipc/kdbus/bus.c +index 4f51723f8780..e7e17a7f7edd 100644 +--- a/ipc/kdbus/bus.c ++++ b/ipc/kdbus/bus.c +@@ -232,9 +232,9 @@ struct kdbus_conn *kdbus_bus_find_conn_by_id(struct kdbus_bus *bus, u64 id) + * kdbus_bus_broadcast() - send a message to all subscribed connections + * @bus: The bus the connections are connected to + * @conn_src: The source connection, may be %NULL for kernel notifications +- * @kmsg: The message to send. ++ * @staging: Staging object containing the message to send + * +- * Send @kmsg to all connections that are currently active on the bus. ++ * Send message to all connections that are currently active on the bus. + * Connections must still have matches installed in order to let the message + * pass. + * +@@ -242,7 +242,7 @@ struct kdbus_conn *kdbus_bus_find_conn_by_id(struct kdbus_bus *bus, u64 id) + */ + void kdbus_bus_broadcast(struct kdbus_bus *bus, + struct kdbus_conn *conn_src, +- struct kdbus_kmsg *kmsg) ++ struct kdbus_staging *staging) + { + struct kdbus_conn *conn_dst; + unsigned int i; +@@ -259,11 +259,11 @@ void kdbus_bus_broadcast(struct kdbus_bus *bus, + * can re-construct order via sequence numbers), but we should at least + * try to avoid re-ordering for monitors. + */ +- kdbus_bus_eavesdrop(bus, conn_src, kmsg); ++ kdbus_bus_eavesdrop(bus, conn_src, staging); + + down_read(&bus->conn_rwlock); + hash_for_each(bus->conn_hash, i, conn_dst, hentry) { +- if (conn_dst->id == kmsg->msg.src_id) ++ if (conn_dst->id == staging->msg->src_id) + continue; + if (!kdbus_conn_is_ordinary(conn_dst)) + continue; +@@ -272,8 +272,8 @@ void kdbus_bus_broadcast(struct kdbus_bus *bus, + * Check if there is a match for the kmsg object in + * the destination connection match db + */ +- if (!kdbus_match_db_match_kmsg(conn_dst->match_db, conn_src, +- kmsg)) ++ if (!kdbus_match_db_match_msg(conn_dst->match_db, conn_src, ++ staging)) + continue; + + if (conn_src) { +@@ -291,12 +291,12 @@ void kdbus_bus_broadcast(struct kdbus_bus *bus, + * notification + */ + if (!kdbus_conn_policy_see_notification(conn_dst, NULL, +- &kmsg->msg)) ++ staging->msg)) + continue; + } + +- ret = kdbus_conn_entry_insert(conn_src, conn_dst, kmsg, NULL, +- NULL); ++ ret = kdbus_conn_entry_insert(conn_src, conn_dst, staging, ++ NULL, NULL); + if (ret < 0) + kdbus_conn_lost_message(conn_dst); + } +@@ -307,16 +307,16 @@ void kdbus_bus_broadcast(struct kdbus_bus *bus, + * kdbus_bus_eavesdrop() - send a message to all subscribed monitors + * @bus: The bus the monitors are connected to + * @conn_src: The source connection, may be %NULL for kernel notifications +- * @kmsg: The message to send. ++ * @staging: Staging object containing the message to send + * +- * Send @kmsg to all monitors that are currently active on the bus. Monitors ++ * Send message to all monitors that are currently active on the bus. Monitors + * must still have matches installed in order to let the message pass. + * + * The caller must hold the name-registry lock of @bus. + */ + void kdbus_bus_eavesdrop(struct kdbus_bus *bus, + struct kdbus_conn *conn_src, +- struct kdbus_kmsg *kmsg) ++ struct kdbus_staging *staging) + { + struct kdbus_conn *conn_dst; + int ret; +@@ -330,8 +330,8 @@ void kdbus_bus_eavesdrop(struct kdbus_bus *bus, + + down_read(&bus->conn_rwlock); + list_for_each_entry(conn_dst, &bus->monitors_list, monitor_entry) { +- ret = kdbus_conn_entry_insert(conn_src, conn_dst, kmsg, NULL, +- NULL); ++ ret = kdbus_conn_entry_insert(conn_src, conn_dst, staging, ++ NULL, NULL); + if (ret < 0) + kdbus_conn_lost_message(conn_dst); + } +diff --git a/ipc/kdbus/bus.h b/ipc/kdbus/bus.h +index e019ef34534c..238986eff92f 100644 +--- a/ipc/kdbus/bus.h ++++ b/ipc/kdbus/bus.h +@@ -29,7 +29,7 @@ + + struct kdbus_conn; + struct kdbus_domain; +-struct kdbus_kmsg; ++struct kdbus_staging; + struct kdbus_user; + + /** +@@ -87,10 +87,10 @@ struct kdbus_bus *kdbus_bus_unref(struct kdbus_bus *bus); + struct kdbus_conn *kdbus_bus_find_conn_by_id(struct kdbus_bus *bus, u64 id); + void kdbus_bus_broadcast(struct kdbus_bus *bus, + struct kdbus_conn *conn_src, +- struct kdbus_kmsg *kmsg); ++ struct kdbus_staging *staging); + void kdbus_bus_eavesdrop(struct kdbus_bus *bus, + struct kdbus_conn *conn_src, +- struct kdbus_kmsg *kmsg); ++ struct kdbus_staging *staging); + + struct kdbus_bus *kdbus_cmd_bus_make(struct kdbus_domain *domain, + void __user *argp); +diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c +index 20bb083aa2b4..2b334b04dd9d 100644 +--- a/ipc/kdbus/connection.c ++++ b/ipc/kdbus/connection.c +@@ -781,7 +781,7 @@ void kdbus_conn_lost_message(struct kdbus_conn *c) + static struct kdbus_queue_entry * + kdbus_conn_entry_make(struct kdbus_conn *conn_src, + struct kdbus_conn *conn_dst, +- const struct kdbus_kmsg *kmsg) ++ struct kdbus_staging *staging) + { + /* The remote connection was disconnected */ + if (!kdbus_conn_active(conn_dst)) +@@ -796,10 +796,10 @@ kdbus_conn_entry_make(struct kdbus_conn *conn_src, + */ + if (!kdbus_conn_is_monitor(conn_dst) && + !(conn_dst->flags & KDBUS_HELLO_ACCEPT_FD) && +- kmsg->res && kmsg->res->fds_count > 0) ++ staging->gaps && staging->gaps->n_fds > 0) + return ERR_PTR(-ECOMM); + +- return kdbus_queue_entry_new(conn_src, conn_dst, kmsg); ++ return kdbus_queue_entry_new(conn_src, conn_dst, staging); + } + + /* +@@ -808,17 +808,11 @@ kdbus_conn_entry_make(struct kdbus_conn *conn_src, + * The connection's queue will never get to see it. + */ + static int kdbus_conn_entry_sync_attach(struct kdbus_conn *conn_dst, +- const struct kdbus_kmsg *kmsg, ++ struct kdbus_staging *staging, + struct kdbus_reply *reply_wake) + { + struct kdbus_queue_entry *entry; +- int remote_ret; +- int ret; +- +- ret = kdbus_kmsg_collect_metadata(kmsg, reply_wake->reply_src, +- conn_dst); +- if (ret < 0) +- return ret; ++ int remote_ret, ret = 0; + + mutex_lock(&reply_wake->reply_dst->lock); + +@@ -828,7 +822,7 @@ static int kdbus_conn_entry_sync_attach(struct kdbus_conn *conn_dst, + */ + if (reply_wake->waiting) { + entry = kdbus_conn_entry_make(reply_wake->reply_src, conn_dst, +- kmsg); ++ staging); + if (IS_ERR(entry)) + ret = PTR_ERR(entry); + else +@@ -869,7 +863,7 @@ static int kdbus_conn_entry_sync_attach(struct kdbus_conn *conn_dst, + * kdbus_conn_entry_insert() - enqueue a message into the receiver's pool + * @conn_src: The sending connection + * @conn_dst: The connection to queue into +- * @kmsg: The kmsg to queue ++ * @staging: Message to send + * @reply: The reply tracker to attach to the queue entry + * @name: Destination name this msg is sent to, or NULL + * +@@ -877,22 +871,16 @@ static int kdbus_conn_entry_sync_attach(struct kdbus_conn *conn_dst, + */ + int kdbus_conn_entry_insert(struct kdbus_conn *conn_src, + struct kdbus_conn *conn_dst, +- const struct kdbus_kmsg *kmsg, ++ struct kdbus_staging *staging, + struct kdbus_reply *reply, + const struct kdbus_name_entry *name) + { + struct kdbus_queue_entry *entry; + int ret; + +- if (conn_src) { +- ret = kdbus_kmsg_collect_metadata(kmsg, conn_src, conn_dst); +- if (ret < 0) +- return ret; +- } +- + kdbus_conn_lock2(conn_src, conn_dst); + +- entry = kdbus_conn_entry_make(conn_src, conn_dst, kmsg); ++ entry = kdbus_conn_entry_make(conn_src, conn_dst, staging); + if (IS_ERR(entry)) { + ret = PTR_ERR(entry); + goto exit_unlock; +@@ -1044,22 +1032,18 @@ static int kdbus_conn_wait_reply(struct kdbus_conn *conn_src, + } + + static int kdbus_pin_dst(struct kdbus_bus *bus, +- const struct kdbus_kmsg *kmsg, ++ struct kdbus_staging *staging, + struct kdbus_name_entry **out_name, + struct kdbus_conn **out_dst) + { +- struct kdbus_msg_resources *res = kmsg->res; +- const struct kdbus_msg *msg = &kmsg->msg; ++ const struct kdbus_msg *msg = staging->msg; + struct kdbus_name_entry *name = NULL; + struct kdbus_conn *dst = NULL; + int ret; + +- if (WARN_ON(!res)) +- return -EINVAL; +- + lockdep_assert_held(&bus->name_registry->rwlock); + +- if (!res->dst_name) { ++ if (!staging->dst_name) { + dst = kdbus_bus_find_conn_by_id(bus, msg->dst_id); + if (!dst) + return -ENXIO; +@@ -1070,7 +1054,7 @@ static int kdbus_pin_dst(struct kdbus_bus *bus, + } + } else { + name = kdbus_name_lookup_unlocked(bus->name_registry, +- res->dst_name); ++ staging->dst_name); + if (!name) + return -ESRCH; + +@@ -1107,17 +1091,19 @@ error: + return ret; + } + +-static int kdbus_conn_reply(struct kdbus_conn *src, struct kdbus_kmsg *kmsg) ++static int kdbus_conn_reply(struct kdbus_conn *src, ++ struct kdbus_staging *staging) + { ++ const struct kdbus_msg *msg = staging->msg; + struct kdbus_name_entry *name = NULL; + struct kdbus_reply *reply, *wake = NULL; + struct kdbus_conn *dst = NULL; + struct kdbus_bus *bus = src->ep->bus; + int ret; + +- if (WARN_ON(kmsg->msg.dst_id == KDBUS_DST_ID_BROADCAST) || +- WARN_ON(kmsg->msg.flags & KDBUS_MSG_EXPECT_REPLY) || +- WARN_ON(kmsg->msg.flags & KDBUS_MSG_SIGNAL)) ++ if (WARN_ON(msg->dst_id == KDBUS_DST_ID_BROADCAST) || ++ WARN_ON(msg->flags & KDBUS_MSG_EXPECT_REPLY) || ++ WARN_ON(msg->flags & KDBUS_MSG_SIGNAL)) + return -EINVAL; + + /* name-registry must be locked for lookup *and* collecting data */ +@@ -1125,12 +1111,12 @@ static int kdbus_conn_reply(struct kdbus_conn *src, struct kdbus_kmsg *kmsg) + + /* find and pin destination */ + +- ret = kdbus_pin_dst(bus, kmsg, &name, &dst); ++ ret = kdbus_pin_dst(bus, staging, &name, &dst); + if (ret < 0) + goto exit; + + mutex_lock(&dst->lock); +- reply = kdbus_reply_find(src, dst, kmsg->msg.cookie_reply); ++ reply = kdbus_reply_find(src, dst, msg->cookie_reply); + if (reply) { + if (reply->sync) + wake = kdbus_reply_ref(reply); +@@ -1145,12 +1131,12 @@ static int kdbus_conn_reply(struct kdbus_conn *src, struct kdbus_kmsg *kmsg) + + /* send message */ + +- kdbus_bus_eavesdrop(bus, src, kmsg); ++ kdbus_bus_eavesdrop(bus, src, staging); + + if (wake) +- ret = kdbus_conn_entry_sync_attach(dst, kmsg, wake); ++ ret = kdbus_conn_entry_sync_attach(dst, staging, wake); + else +- ret = kdbus_conn_entry_insert(src, dst, kmsg, NULL, name); ++ ret = kdbus_conn_entry_insert(src, dst, staging, NULL, name); + + exit: + up_read(&bus->name_registry->rwlock); +@@ -1160,24 +1146,25 @@ exit: + } + + static struct kdbus_reply *kdbus_conn_call(struct kdbus_conn *src, +- struct kdbus_kmsg *kmsg, ++ struct kdbus_staging *staging, + ktime_t exp) + { ++ const struct kdbus_msg *msg = staging->msg; + struct kdbus_name_entry *name = NULL; + struct kdbus_reply *wait = NULL; + struct kdbus_conn *dst = NULL; + struct kdbus_bus *bus = src->ep->bus; + int ret; + +- if (WARN_ON(kmsg->msg.dst_id == KDBUS_DST_ID_BROADCAST) || +- WARN_ON(kmsg->msg.flags & KDBUS_MSG_SIGNAL) || +- WARN_ON(!(kmsg->msg.flags & KDBUS_MSG_EXPECT_REPLY))) ++ if (WARN_ON(msg->dst_id == KDBUS_DST_ID_BROADCAST) || ++ WARN_ON(msg->flags & KDBUS_MSG_SIGNAL) || ++ WARN_ON(!(msg->flags & KDBUS_MSG_EXPECT_REPLY))) + return ERR_PTR(-EINVAL); + + /* resume previous wait-context, if available */ + + mutex_lock(&src->lock); +- wait = kdbus_reply_find(NULL, src, kmsg->msg.cookie); ++ wait = kdbus_reply_find(NULL, src, msg->cookie); + if (wait) { + if (wait->interrupted) { + kdbus_reply_ref(wait); +@@ -1199,7 +1186,7 @@ static struct kdbus_reply *kdbus_conn_call(struct kdbus_conn *src, + + /* find and pin destination */ + +- ret = kdbus_pin_dst(bus, kmsg, &name, &dst); ++ ret = kdbus_pin_dst(bus, staging, &name, &dst); + if (ret < 0) + goto exit; + +@@ -1208,7 +1195,7 @@ static struct kdbus_reply *kdbus_conn_call(struct kdbus_conn *src, + goto exit; + } + +- wait = kdbus_reply_new(dst, src, &kmsg->msg, name, true); ++ wait = kdbus_reply_new(dst, src, msg, name, true); + if (IS_ERR(wait)) { + ret = PTR_ERR(wait); + wait = NULL; +@@ -1217,9 +1204,9 @@ static struct kdbus_reply *kdbus_conn_call(struct kdbus_conn *src, + + /* send message */ + +- kdbus_bus_eavesdrop(bus, src, kmsg); ++ kdbus_bus_eavesdrop(bus, src, staging); + +- ret = kdbus_conn_entry_insert(src, dst, kmsg, wait, name); ++ ret = kdbus_conn_entry_insert(src, dst, staging, wait, name); + if (ret < 0) + goto exit; + +@@ -1235,18 +1222,20 @@ exit: + return wait; + } + +-static int kdbus_conn_unicast(struct kdbus_conn *src, struct kdbus_kmsg *kmsg) ++static int kdbus_conn_unicast(struct kdbus_conn *src, ++ struct kdbus_staging *staging) + { ++ const struct kdbus_msg *msg = staging->msg; + struct kdbus_name_entry *name = NULL; + struct kdbus_reply *wait = NULL; + struct kdbus_conn *dst = NULL; + struct kdbus_bus *bus = src->ep->bus; +- bool is_signal = (kmsg->msg.flags & KDBUS_MSG_SIGNAL); ++ bool is_signal = (msg->flags & KDBUS_MSG_SIGNAL); + int ret = 0; + +- if (WARN_ON(kmsg->msg.dst_id == KDBUS_DST_ID_BROADCAST) || +- WARN_ON(!(kmsg->msg.flags & KDBUS_MSG_EXPECT_REPLY) && +- kmsg->msg.cookie_reply != 0)) ++ if (WARN_ON(msg->dst_id == KDBUS_DST_ID_BROADCAST) || ++ WARN_ON(!(msg->flags & KDBUS_MSG_EXPECT_REPLY) && ++ msg->cookie_reply != 0)) + return -EINVAL; + + /* name-registry must be locked for lookup *and* collecting data */ +@@ -1254,23 +1243,23 @@ static int kdbus_conn_unicast(struct kdbus_conn *src, struct kdbus_kmsg *kmsg) + + /* find and pin destination */ + +- ret = kdbus_pin_dst(bus, kmsg, &name, &dst); ++ ret = kdbus_pin_dst(bus, staging, &name, &dst); + if (ret < 0) + goto exit; + + if (is_signal) { + /* like broadcasts we eavesdrop even if the msg is dropped */ +- kdbus_bus_eavesdrop(bus, src, kmsg); ++ kdbus_bus_eavesdrop(bus, src, staging); + + /* drop silently if peer is not interested or not privileged */ +- if (!kdbus_match_db_match_kmsg(dst->match_db, src, kmsg) || ++ if (!kdbus_match_db_match_msg(dst->match_db, src, staging) || + !kdbus_conn_policy_talk(dst, NULL, src)) + goto exit; + } else if (!kdbus_conn_policy_talk(src, current_cred(), dst)) { + ret = -EPERM; + goto exit; +- } else if (kmsg->msg.flags & KDBUS_MSG_EXPECT_REPLY) { +- wait = kdbus_reply_new(dst, src, &kmsg->msg, name, false); ++ } else if (msg->flags & KDBUS_MSG_EXPECT_REPLY) { ++ wait = kdbus_reply_new(dst, src, msg, name, false); + if (IS_ERR(wait)) { + ret = PTR_ERR(wait); + wait = NULL; +@@ -1281,9 +1270,9 @@ static int kdbus_conn_unicast(struct kdbus_conn *src, struct kdbus_kmsg *kmsg) + /* send message */ + + if (!is_signal) +- kdbus_bus_eavesdrop(bus, src, kmsg); ++ kdbus_bus_eavesdrop(bus, src, staging); + +- ret = kdbus_conn_entry_insert(src, dst, kmsg, wait, name); ++ ret = kdbus_conn_entry_insert(src, dst, staging, wait, name); + if (ret < 0 && !is_signal) + goto exit; + +@@ -1353,7 +1342,7 @@ void kdbus_conn_move_messages(struct kdbus_conn *conn_dst, + continue; + + if (!(conn_dst->flags & KDBUS_HELLO_ACCEPT_FD) && +- e->msg_res && e->msg_res->fds_count > 0) { ++ e->gaps && e->gaps->n_fds > 0) { + kdbus_conn_lost_message(conn_dst); + kdbus_queue_entry_free(e); + continue; +@@ -1930,7 +1919,6 @@ int kdbus_cmd_send(struct kdbus_conn *conn, struct file *f, void __user *argp) + { + struct kdbus_cmd_send *cmd; + struct kdbus_staging *staging = NULL; +- struct kdbus_kmsg *kmsg = NULL; + struct kdbus_msg *msg = NULL; + struct file *cancel_fd = NULL; + int ret, ret2; +@@ -2021,23 +2009,16 @@ int kdbus_cmd_send(struct kdbus_conn *conn, struct file *f, void __user *argp) + goto exit; + } + +- kmsg = kdbus_kmsg_new_from_cmd(conn, cmd); +- if (IS_ERR(kmsg)) { +- ret = PTR_ERR(kmsg); +- kmsg = NULL; +- goto exit; +- } +- +- if (kmsg->msg.dst_id == KDBUS_DST_ID_BROADCAST) { ++ if (msg->dst_id == KDBUS_DST_ID_BROADCAST) { + down_read(&conn->ep->bus->name_registry->rwlock); +- kdbus_bus_broadcast(conn->ep->bus, conn, kmsg); ++ kdbus_bus_broadcast(conn->ep->bus, conn, staging); + up_read(&conn->ep->bus->name_registry->rwlock); + } else if (cmd->flags & KDBUS_SEND_SYNC_REPLY) { + struct kdbus_reply *r; + ktime_t exp; + +- exp = ns_to_ktime(kmsg->msg.timeout_ns); +- r = kdbus_conn_call(conn, kmsg, exp); ++ exp = ns_to_ktime(msg->timeout_ns); ++ r = kdbus_conn_call(conn, staging, exp); + if (IS_ERR(r)) { + ret = PTR_ERR(r); + goto exit; +@@ -2047,13 +2028,13 @@ int kdbus_cmd_send(struct kdbus_conn *conn, struct file *f, void __user *argp) + kdbus_reply_unref(r); + if (ret < 0) + goto exit; +- } else if ((kmsg->msg.flags & KDBUS_MSG_EXPECT_REPLY) || +- kmsg->msg.cookie_reply == 0) { +- ret = kdbus_conn_unicast(conn, kmsg); ++ } else if ((msg->flags & KDBUS_MSG_EXPECT_REPLY) || ++ msg->cookie_reply == 0) { ++ ret = kdbus_conn_unicast(conn, staging); + if (ret < 0) + goto exit; + } else { +- ret = kdbus_conn_reply(conn, kmsg); ++ ret = kdbus_conn_reply(conn, staging); + if (ret < 0) + goto exit; + } +@@ -2064,7 +2045,6 @@ int kdbus_cmd_send(struct kdbus_conn *conn, struct file *f, void __user *argp) + exit: + if (cancel_fd) + fput(cancel_fd); +- kdbus_kmsg_free(kmsg); + kdbus_staging_free(staging); + ret = kdbus_args_clear(&msg_args, ret); + return kdbus_args_clear(&args, ret); +diff --git a/ipc/kdbus/connection.h b/ipc/kdbus/connection.h +index 90c1bcc91fe6..b1769b877504 100644 +--- a/ipc/kdbus/connection.h ++++ b/ipc/kdbus/connection.h +@@ -31,7 +31,7 @@ + KDBUS_HELLO_MONITOR) + + struct kdbus_quota; +-struct kdbus_kmsg; ++struct kdbus_staging; + + /** + * struct kdbus_conn - connection to a bus +@@ -134,7 +134,7 @@ void kdbus_conn_quota_dec(struct kdbus_conn *c, struct kdbus_user *u, + void kdbus_conn_lost_message(struct kdbus_conn *c); + int kdbus_conn_entry_insert(struct kdbus_conn *conn_src, + struct kdbus_conn *conn_dst, +- const struct kdbus_kmsg *kmsg, ++ struct kdbus_staging *staging, + struct kdbus_reply *reply, + const struct kdbus_name_entry *name); + void kdbus_conn_move_messages(struct kdbus_conn *conn_dst, +diff --git a/ipc/kdbus/match.c b/ipc/kdbus/match.c +index 3f86e4c81468..3ae224ff9f3f 100644 +--- a/ipc/kdbus/match.c ++++ b/ipc/kdbus/match.c +@@ -206,13 +206,13 @@ static bool kdbus_match_bloom(const struct kdbus_bloom_filter *filter, + + static bool kdbus_match_rule_conn(const struct kdbus_match_rule *r, + struct kdbus_conn *c, +- const struct kdbus_kmsg *kmsg) ++ const struct kdbus_staging *s) + { + lockdep_assert_held(&c->ep->bus->name_registry->rwlock); + + switch (r->type) { + case KDBUS_ITEM_BLOOM_MASK: +- return kdbus_match_bloom(kmsg->bloom_filter, &r->bloom_mask, c); ++ return kdbus_match_bloom(s->bloom_filter, &r->bloom_mask, c); + case KDBUS_ITEM_ID: + return r->src_id == c->id || r->src_id == KDBUS_MATCH_ID_ANY; + case KDBUS_ITEM_NAME: +@@ -223,9 +223,9 @@ static bool kdbus_match_rule_conn(const struct kdbus_match_rule *r, + } + + static bool kdbus_match_rule_kernel(const struct kdbus_match_rule *r, +- const struct kdbus_kmsg *kmsg) ++ const struct kdbus_staging *s) + { +- struct kdbus_item *n = kmsg->notify; ++ struct kdbus_item *n = s->notify; + + if (WARN_ON(!n) || n->type != r->type) + return false; +@@ -252,23 +252,23 @@ static bool kdbus_match_rule_kernel(const struct kdbus_match_rule *r, + + static bool kdbus_match_rules(const struct kdbus_match_entry *entry, + struct kdbus_conn *c, +- const struct kdbus_kmsg *kmsg) ++ const struct kdbus_staging *s) + { + struct kdbus_match_rule *r; + + list_for_each_entry(r, &entry->rules_list, rules_entry) +- if ((c && !kdbus_match_rule_conn(r, c, kmsg)) || +- (!c && !kdbus_match_rule_kernel(r, kmsg))) ++ if ((c && !kdbus_match_rule_conn(r, c, s)) || ++ (!c && !kdbus_match_rule_kernel(r, s))) + return false; + + return true; + } + + /** +- * kdbus_match_db_match_kmsg() - match a kmsg object agains the database entries ++ * kdbus_match_db_match_msg() - match a msg object agains the database entries + * @mdb: The match database + * @conn_src: The connection object originating the message +- * @kmsg: The kmsg to perform the match on ++ * @staging: Staging object containing the message to match against + * + * This function will walk through all the database entries previously uploaded + * with kdbus_match_db_add(). As soon as any of them has an all-satisfied rule +@@ -279,16 +279,16 @@ static bool kdbus_match_rules(const struct kdbus_match_entry *entry, + * + * Return: true if there was a matching database entry, false otherwise. + */ +-bool kdbus_match_db_match_kmsg(struct kdbus_match_db *mdb, +- struct kdbus_conn *conn_src, +- struct kdbus_kmsg *kmsg) ++bool kdbus_match_db_match_msg(struct kdbus_match_db *mdb, ++ struct kdbus_conn *conn_src, ++ const struct kdbus_staging *staging) + { + struct kdbus_match_entry *entry; + bool matched = false; + + down_read(&mdb->mdb_rwlock); + list_for_each_entry(entry, &mdb->entries_list, list_entry) { +- matched = kdbus_match_rules(entry, conn_src, kmsg); ++ matched = kdbus_match_rules(entry, conn_src, staging); + if (matched) + break; + } +diff --git a/ipc/kdbus/match.h b/ipc/kdbus/match.h +index ea4292938deb..ceb492f8e51c 100644 +--- a/ipc/kdbus/match.h ++++ b/ipc/kdbus/match.h +@@ -16,8 +16,8 @@ + #define __KDBUS_MATCH_H + + struct kdbus_conn; +-struct kdbus_kmsg; + struct kdbus_match_db; ++struct kdbus_staging; + + struct kdbus_match_db *kdbus_match_db_new(void); + void kdbus_match_db_free(struct kdbus_match_db *db); +@@ -25,9 +25,9 @@ int kdbus_match_db_add(struct kdbus_conn *conn, + struct kdbus_cmd_match *cmd); + int kdbus_match_db_remove(struct kdbus_conn *conn, + struct kdbus_cmd_match *cmd); +-bool kdbus_match_db_match_kmsg(struct kdbus_match_db *db, +- struct kdbus_conn *conn_src, +- struct kdbus_kmsg *kmsg); ++bool kdbus_match_db_match_msg(struct kdbus_match_db *db, ++ struct kdbus_conn *conn_src, ++ const struct kdbus_staging *staging); + + int kdbus_cmd_match_add(struct kdbus_conn *conn, void __user *argp); + int kdbus_cmd_match_remove(struct kdbus_conn *conn, void __user *argp); +diff --git a/ipc/kdbus/message.h b/ipc/kdbus/message.h +index 8fe49a961834..e0c4f2e324b3 100644 +--- a/ipc/kdbus/message.h ++++ b/ipc/kdbus/message.h +@@ -14,6 +14,9 @@ + #ifndef __KDBUS_MESSAGE_H + #define __KDBUS_MESSAGE_H + ++#include <linux/fs.h> ++#include <linux/kref.h> ++#include <uapi/linux/kdbus.h> + #include "util.h" + #include "metadata.h" + +@@ -114,6 +117,9 @@ struct kdbus_kmsg { + + struct kdbus_bus; + struct kdbus_conn; ++struct kdbus_meta_conn; ++struct kdbus_meta_proc; ++struct kdbus_pool_slice; + + struct kdbus_kmsg *kdbus_kmsg_new_kernel(struct kdbus_bus *bus, + u64 dst, u64 cookie_timeout, +diff --git a/ipc/kdbus/notify.c b/ipc/kdbus/notify.c +index a07d242d0470..375758c4896a 100644 +--- a/ipc/kdbus/notify.c ++++ b/ipc/kdbus/notify.c +@@ -28,24 +28,24 @@ + #include "message.h" + #include "notify.h" + +-static inline void kdbus_notify_add_tail(struct kdbus_kmsg *kmsg, ++static inline void kdbus_notify_add_tail(struct kdbus_staging *staging, + struct kdbus_bus *bus) + { + spin_lock(&bus->notify_lock); +- list_add_tail(&kmsg->notify_entry, &bus->notify_list); ++ list_add_tail(&staging->notify_entry, &bus->notify_list); + spin_unlock(&bus->notify_lock); + } + + static int kdbus_notify_reply(struct kdbus_bus *bus, u64 id, + u64 cookie, u64 msg_type) + { +- struct kdbus_kmsg *kmsg; ++ struct kdbus_staging *s; + +- kmsg = kdbus_kmsg_new_kernel(bus, id, cookie, 0, msg_type); +- if (IS_ERR(kmsg)) +- return PTR_ERR(kmsg); ++ s = kdbus_staging_new_kernel(bus, id, cookie, 0, msg_type); ++ if (IS_ERR(s)) ++ return PTR_ERR(s); + +- kdbus_notify_add_tail(kmsg, bus); ++ kdbus_notify_add_tail(s, bus); + return 0; + } + +@@ -100,23 +100,23 @@ int kdbus_notify_name_change(struct kdbus_bus *bus, u64 type, + const char *name) + { + size_t name_len, extra_size; +- struct kdbus_kmsg *kmsg; ++ struct kdbus_staging *s; + + name_len = strlen(name) + 1; + extra_size = sizeof(struct kdbus_notify_name_change) + name_len; + +- kmsg = kdbus_kmsg_new_kernel(bus, KDBUS_DST_ID_BROADCAST, 0, ++ s = kdbus_staging_new_kernel(bus, KDBUS_DST_ID_BROADCAST, 0, + extra_size, type); +- if (IS_ERR(kmsg)) +- return PTR_ERR(kmsg); ++ if (IS_ERR(s)) ++ return PTR_ERR(s); + +- kmsg->notify->name_change.old_id.id = old_id; +- kmsg->notify->name_change.old_id.flags = old_flags; +- kmsg->notify->name_change.new_id.id = new_id; +- kmsg->notify->name_change.new_id.flags = new_flags; +- memcpy(kmsg->notify->name_change.name, name, name_len); ++ s->notify->name_change.old_id.id = old_id; ++ s->notify->name_change.old_id.flags = old_flags; ++ s->notify->name_change.new_id.id = new_id; ++ s->notify->name_change.new_id.flags = new_flags; ++ memcpy(s->notify->name_change.name, name, name_len); + +- kdbus_notify_add_tail(kmsg, bus); ++ kdbus_notify_add_tail(s, bus); + return 0; + } + +@@ -132,19 +132,19 @@ int kdbus_notify_name_change(struct kdbus_bus *bus, u64 type, + */ + int kdbus_notify_id_change(struct kdbus_bus *bus, u64 type, u64 id, u64 flags) + { +- struct kdbus_kmsg *kmsg; ++ struct kdbus_staging *s; + size_t extra_size; + + extra_size = sizeof(struct kdbus_notify_id_change); +- kmsg = kdbus_kmsg_new_kernel(bus, KDBUS_DST_ID_BROADCAST, 0, ++ s = kdbus_staging_new_kernel(bus, KDBUS_DST_ID_BROADCAST, 0, + extra_size, type); +- if (IS_ERR(kmsg)) +- return PTR_ERR(kmsg); ++ if (IS_ERR(s)) ++ return PTR_ERR(s); + +- kmsg->notify->id_change.id = id; +- kmsg->notify->id_change.flags = flags; ++ s->notify->id_change.id = id; ++ s->notify->id_change.flags = flags; + +- kdbus_notify_add_tail(kmsg, bus); ++ kdbus_notify_add_tail(s, bus); + return 0; + } + +@@ -157,7 +157,7 @@ int kdbus_notify_id_change(struct kdbus_bus *bus, u64 type, u64 id, u64 flags) + void kdbus_notify_flush(struct kdbus_bus *bus) + { + LIST_HEAD(notify_list); +- struct kdbus_kmsg *kmsg, *tmp; ++ struct kdbus_staging *s, *tmp; + + mutex_lock(&bus->notify_flush_lock); + down_read(&bus->name_registry->rwlock); +@@ -166,26 +166,23 @@ void kdbus_notify_flush(struct kdbus_bus *bus) + list_splice_init(&bus->notify_list, ¬ify_list); + spin_unlock(&bus->notify_lock); + +- list_for_each_entry_safe(kmsg, tmp, ¬ify_list, notify_entry) { +- kdbus_meta_conn_collect(kmsg->conn_meta, NULL, kmsg->seq, +- KDBUS_ATTACH_TIMESTAMP); +- +- if (kmsg->msg.dst_id != KDBUS_DST_ID_BROADCAST) { ++ list_for_each_entry_safe(s, tmp, ¬ify_list, notify_entry) { ++ if (s->msg->dst_id != KDBUS_DST_ID_BROADCAST) { + struct kdbus_conn *conn; + +- conn = kdbus_bus_find_conn_by_id(bus, kmsg->msg.dst_id); ++ conn = kdbus_bus_find_conn_by_id(bus, s->msg->dst_id); + if (conn) { +- kdbus_bus_eavesdrop(bus, NULL, kmsg); +- kdbus_conn_entry_insert(NULL, conn, kmsg, NULL, ++ kdbus_bus_eavesdrop(bus, NULL, s); ++ kdbus_conn_entry_insert(NULL, conn, s, NULL, + NULL); + kdbus_conn_unref(conn); + } + } else { +- kdbus_bus_broadcast(bus, NULL, kmsg); ++ kdbus_bus_broadcast(bus, NULL, s); + } + +- list_del(&kmsg->notify_entry); +- kdbus_kmsg_free(kmsg); ++ list_del(&s->notify_entry); ++ kdbus_staging_free(s); + } + + up_read(&bus->name_registry->rwlock); +@@ -198,10 +195,10 @@ void kdbus_notify_flush(struct kdbus_bus *bus) + */ + void kdbus_notify_free(struct kdbus_bus *bus) + { +- struct kdbus_kmsg *kmsg, *tmp; ++ struct kdbus_staging *s, *tmp; + +- list_for_each_entry_safe(kmsg, tmp, &bus->notify_list, notify_entry) { +- list_del(&kmsg->notify_entry); +- kdbus_kmsg_free(kmsg); ++ list_for_each_entry_safe(s, tmp, &bus->notify_list, notify_entry) { ++ list_del(&s->notify_entry); ++ kdbus_staging_free(s); + } + } +diff --git a/ipc/kdbus/queue.c b/ipc/kdbus/queue.c +index 4749b23a4f14..f9c44d7bae6d 100644 +--- a/ipc/kdbus/queue.c ++++ b/ipc/kdbus/queue.c +@@ -171,243 +171,43 @@ static void kdbus_queue_entry_unlink(struct kdbus_queue_entry *entry) + + /** + * kdbus_queue_entry_new() - allocate a queue entry +- * @conn_src: source connection +- * @conn_dst: destination connection +- * @kmsg: kmsg object the queue entry should track ++ * @src: source connection, or NULL ++ * @dst: destination connection ++ * @s: staging object carrying the message + * +- * Allocates a queue entry based on a given kmsg and allocate space for ++ * Allocates a queue entry based on a given msg and allocate space for + * the message payload and the requested metadata in the connection's pool. + * The entry is not actually added to the queue's lists at this point. + * + * Return: the allocated entry on success, or an ERR_PTR on failures. + */ +-struct kdbus_queue_entry *kdbus_queue_entry_new(struct kdbus_conn *conn_src, +- struct kdbus_conn *conn_dst, +- const struct kdbus_kmsg *kmsg) ++struct kdbus_queue_entry *kdbus_queue_entry_new(struct kdbus_conn *src, ++ struct kdbus_conn *dst, ++ struct kdbus_staging *s) + { +- struct kdbus_user *user = conn_src ? conn_src->user : NULL; +- struct kdbus_msg_resources *res = kmsg->res; +- const struct kdbus_msg *msg = &kmsg->msg; + struct kdbus_queue_entry *entry; +- size_t memfd_cnt = 0; +- struct kvec kvec[2]; +- size_t meta_size; +- size_t msg_size; +- u64 payload_off; +- u64 size = 0; +- int ret = 0; ++ int ret; + + entry = kzalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) + return ERR_PTR(-ENOMEM); + + INIT_LIST_HEAD(&entry->entry); +- entry->priority = msg->priority; +- entry->msg_res = kdbus_msg_resources_ref(res); +- entry->proc_meta = kdbus_meta_proc_ref(kmsg->proc_meta); +- entry->conn_meta = kdbus_meta_conn_ref(kmsg->conn_meta); +- entry->conn = kdbus_conn_ref(conn_dst); +- +- if (kmsg->msg.src_id == KDBUS_SRC_ID_KERNEL) +- msg_size = msg->size; +- else +- msg_size = offsetof(struct kdbus_msg, items); +- +- /* sum up the size of the needed slice */ +- size = msg_size; +- +- if (res) { +- size += res->vec_count * +- KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec)); +- +- if (res->memfd_count) { +- entry->memfd_offset = +- kcalloc(res->memfd_count, sizeof(size_t), +- GFP_KERNEL); +- if (!entry->memfd_offset) { +- ret = -ENOMEM; +- goto exit_free_entry; +- } +- +- size += res->memfd_count * +- KDBUS_ITEM_SIZE(sizeof(struct kdbus_memfd)); +- } +- +- if (res->fds_count) +- size += KDBUS_ITEM_SIZE(sizeof(int) * res->fds_count); +- +- if (res->dst_name) +- size += KDBUS_ITEM_SIZE(strlen(res->dst_name) + 1); +- } +- +- /* +- * Remember the offset of the metadata part, so we can override +- * this part later during kdbus_queue_entry_install(). +- */ +- entry->meta_offset = size; +- +- if (entry->proc_meta || entry->conn_meta) { +- entry->attach_flags = +- atomic64_read(&conn_dst->attach_flags_recv); +- +- ret = kdbus_meta_export_prepare(entry->proc_meta, +- NULL, +- entry->conn_meta, +- &entry->attach_flags, +- &meta_size); +- if (ret < 0) +- goto exit_free_entry; +- +- size += meta_size; +- } ++ entry->priority = s->msg->priority; ++ entry->conn = kdbus_conn_ref(dst); ++ entry->gaps = kdbus_gaps_ref(s->gaps); + +- payload_off = size; +- size += kmsg->pool_size; +- size = KDBUS_ALIGN8(size); +- +- ret = kdbus_conn_quota_inc(conn_dst, user, size, +- res ? res->fds_count : 0); +- if (ret < 0) +- goto exit_free_entry; +- +- entry->slice = kdbus_pool_slice_alloc(conn_dst->pool, size, true); ++ entry->slice = kdbus_staging_emit(s, src, dst); + if (IS_ERR(entry->slice)) { + ret = PTR_ERR(entry->slice); + entry->slice = NULL; +- kdbus_conn_quota_dec(conn_dst, user, size, +- res ? res->fds_count : 0); +- goto exit_free_entry; +- } +- +- /* we accounted for exactly 'size' bytes, make sure it didn't grow */ +- WARN_ON(kdbus_pool_slice_size(entry->slice) != size); +- entry->user = kdbus_user_ref(user); +- +- /* copy message header */ +- kvec[0].iov_base = (char *)msg; +- kvec[0].iov_len = msg_size; +- +- ret = kdbus_pool_slice_copy_kvec(entry->slice, 0, kvec, 1, msg_size); +- if (ret < 0) +- goto exit_free_entry; +- +- /* 'size' will now track the write position */ +- size = msg_size; +- +- /* create message payload items */ +- if (res) { +- size_t dst_name_len = 0; +- unsigned int i; +- size_t sz = 0; +- +- if (res->dst_name) { +- dst_name_len = strlen(res->dst_name) + 1; +- sz += KDBUS_ITEM_SIZE(dst_name_len); +- } +- +- for (i = 0; i < res->data_count; ++i) { +- struct kdbus_vec v; +- struct kdbus_memfd m; +- +- switch (res->data[i].type) { +- case KDBUS_MSG_DATA_VEC: +- sz += KDBUS_ITEM_SIZE(sizeof(v)); +- break; +- +- case KDBUS_MSG_DATA_MEMFD: +- sz += KDBUS_ITEM_SIZE(sizeof(m)); +- break; +- } +- } +- +- if (sz) { +- struct kdbus_item *items, *item; +- +- items = kmalloc(sz, GFP_KERNEL); +- if (!items) { +- ret = -ENOMEM; +- goto exit_free_entry; +- } +- +- item = items; +- +- if (res->dst_name) +- item = kdbus_item_set(item, KDBUS_ITEM_DST_NAME, +- res->dst_name, +- dst_name_len); +- +- for (i = 0; i < res->data_count; ++i) { +- struct kdbus_msg_data *d = res->data + i; +- struct kdbus_memfd m = {}; +- struct kdbus_vec v = {}; +- +- switch (d->type) { +- case KDBUS_MSG_DATA_VEC: +- v.size = d->size; +- v.offset = d->vec.off; +- if (v.offset != ~0ULL) +- v.offset += payload_off; +- +- item = kdbus_item_set(item, +- KDBUS_ITEM_PAYLOAD_OFF, +- &v, sizeof(v)); +- break; +- +- case KDBUS_MSG_DATA_MEMFD: +- /* +- * Remember the location of memfds, so +- * we can override the content from +- * kdbus_queue_entry_install(). +- */ +- entry->memfd_offset[memfd_cnt++] = +- msg_size + +- (char *)item - (char *)items + +- offsetof(struct kdbus_item, +- memfd); +- +- item = kdbus_item_set(item, +- KDBUS_ITEM_PAYLOAD_MEMFD, +- &m, sizeof(m)); +- break; +- } +- } +- +- kvec[0].iov_base = items; +- kvec[0].iov_len = sz; +- +- ret = kdbus_pool_slice_copy_kvec(entry->slice, size, +- kvec, 1, sz); +- kfree(items); +- +- if (ret < 0) +- goto exit_free_entry; +- +- size += sz; +- } +- +- /* +- * Remember the location of the FD part, so we can override the +- * content in kdbus_queue_entry_install(). +- */ +- if (res->fds_count) { +- entry->fds_offset = size; +- size += KDBUS_ITEM_SIZE(sizeof(int) * res->fds_count); +- } +- } +- +- /* finally, copy over the actual message payload */ +- if (kmsg->iov_count) { +- ret = kdbus_pool_slice_copy_iovec(entry->slice, payload_off, +- kmsg->iov, +- kmsg->iov_count, +- kmsg->pool_size); +- if (ret < 0) +- goto exit_free_entry; ++ goto error; + } + ++ entry->user = src ? kdbus_user_ref(src->user) : NULL; + return entry; + +-exit_free_entry: ++error: + kdbus_queue_entry_free(entry); + return ERR_PTR(ret); + } +@@ -432,17 +232,13 @@ void kdbus_queue_entry_free(struct kdbus_queue_entry *entry) + if (entry->slice) { + kdbus_conn_quota_dec(entry->conn, entry->user, + kdbus_pool_slice_size(entry->slice), +- entry->msg_res ? +- entry->msg_res->fds_count : 0); ++ entry->gaps ? entry->gaps->n_fds : 0); + kdbus_pool_slice_release(entry->slice); +- kdbus_user_unref(entry->user); + } + +- kdbus_msg_resources_unref(entry->msg_res); +- kdbus_meta_conn_unref(entry->conn_meta); +- kdbus_meta_proc_unref(entry->proc_meta); ++ kdbus_user_unref(entry->user); ++ kdbus_gaps_unref(entry->gaps); + kdbus_conn_unref(entry->conn); +- kfree(entry->memfd_offset); + kfree(entry); + } + +@@ -453,136 +249,22 @@ void kdbus_queue_entry_free(struct kdbus_queue_entry *entry) + * @return_flags: Pointer to store the return flags for userspace + * @install_fds: Whether or not to install associated file descriptors + * +- * This function will create a slice to transport the message header, the +- * metadata items and other items for information stored in @entry, and +- * store it as entry->slice. +- * +- * If @install_fds is %true, file descriptors will as well be installed. +- * This function must always be called from the task context of the receiver. +- * + * Return: 0 on success. + */ + int kdbus_queue_entry_install(struct kdbus_queue_entry *entry, + u64 *return_flags, bool install_fds) + { +- u64 msg_size = entry->meta_offset; +- struct kdbus_conn *conn_dst = entry->conn; +- struct kdbus_msg_resources *res; + bool incomplete_fds = false; +- struct kvec kvec[2]; +- size_t memfds = 0; +- int i, ret; +- +- lockdep_assert_held(&conn_dst->lock); +- +- if (entry->proc_meta || entry->conn_meta) { +- size_t meta_size; +- +- ret = kdbus_meta_export(entry->proc_meta, +- NULL, +- entry->conn_meta, +- conn_dst, +- entry->attach_flags, +- entry->slice, +- entry->meta_offset, +- &meta_size); +- if (ret < 0) +- return ret; +- +- msg_size += meta_size; +- } ++ int ret; + +- /* Update message size at offset 0 */ +- kvec[0].iov_base = &msg_size; +- kvec[0].iov_len = sizeof(msg_size); ++ lockdep_assert_held(&entry->conn->lock); + +- ret = kdbus_pool_slice_copy_kvec(entry->slice, 0, kvec, 1, +- sizeof(msg_size)); ++ ret = kdbus_gaps_install(entry->gaps, entry->slice, &incomplete_fds); + if (ret < 0) + return ret; + +- res = entry->msg_res; +- +- if (!res) +- return 0; +- +- if (res->fds_count) { +- struct kdbus_item_header hdr; +- size_t off; +- int *fds; +- +- fds = kmalloc_array(res->fds_count, sizeof(int), GFP_KERNEL); +- if (!fds) +- return -ENOMEM; +- +- for (i = 0; i < res->fds_count; i++) { +- if (install_fds) { +- fds[i] = get_unused_fd_flags(O_CLOEXEC); +- if (fds[i] >= 0) +- fd_install(fds[i], +- get_file(res->fds[i])); +- else +- incomplete_fds = true; +- } else { +- fds[i] = -1; +- } +- } +- +- off = entry->fds_offset; +- +- hdr.type = KDBUS_ITEM_FDS; +- hdr.size = KDBUS_ITEM_HEADER_SIZE + +- sizeof(int) * res->fds_count; +- +- kvec[0].iov_base = &hdr; +- kvec[0].iov_len = sizeof(hdr); +- +- kvec[1].iov_base = fds; +- kvec[1].iov_len = sizeof(int) * res->fds_count; +- +- ret = kdbus_pool_slice_copy_kvec(entry->slice, off, +- kvec, 2, hdr.size); +- kfree(fds); +- +- if (ret < 0) +- return ret; +- } +- +- for (i = 0; i < res->data_count; ++i) { +- struct kdbus_msg_data *d = res->data + i; +- struct kdbus_memfd m; +- +- if (d->type != KDBUS_MSG_DATA_MEMFD) +- continue; +- +- m.start = d->memfd.start; +- m.size = d->size; +- m.fd = -1; +- +- if (install_fds) { +- m.fd = get_unused_fd_flags(O_CLOEXEC); +- if (m.fd < 0) { +- m.fd = -1; +- incomplete_fds = true; +- } else { +- fd_install(m.fd, +- get_file(d->memfd.file)); +- } +- } +- +- kvec[0].iov_base = &m; +- kvec[0].iov_len = sizeof(m); +- +- ret = kdbus_pool_slice_copy_kvec(entry->slice, +- entry->memfd_offset[memfds++], +- kvec, 1, sizeof(m)); +- if (ret < 0) +- return ret; +- } +- + if (incomplete_fds) + *return_flags |= KDBUS_RECV_RETURN_INCOMPLETE_FDS; +- + return 0; + } + +@@ -646,7 +328,7 @@ int kdbus_queue_entry_move(struct kdbus_queue_entry *e, + return 0; + + size = kdbus_pool_slice_size(e->slice); +- fds = e->msg_res ? e->msg_res->fds_count : 0; ++ fds = e->gaps ? e->gaps->n_fds : 0; + + ret = kdbus_conn_quota_inc(dst, e->user, size, fds); + if (ret < 0) +diff --git a/ipc/kdbus/queue.h b/ipc/kdbus/queue.h +index ac471d0c809d..bf686d182ce1 100644 +--- a/ipc/kdbus/queue.h ++++ b/ipc/kdbus/queue.h +@@ -15,6 +15,13 @@ + #ifndef __KDBUS_QUEUE_H + #define __KDBUS_QUEUE_H + ++#include <linux/list.h> ++#include <linux/rbtree.h> ++ ++struct kdbus_conn; ++struct kdbus_pool_slice; ++struct kdbus_reply; ++struct kdbus_staging; + struct kdbus_user; + + /** +@@ -35,52 +42,37 @@ struct kdbus_queue { + * @entry: Entry in the connection's list + * @prio_node: Entry in the priority queue tree + * @prio_entry: Queue tree node entry in the list of one priority +- * @slice: Slice in the receiver's pool for the message +- * @attach_flags: Attach flags used during slice allocation +- * @meta_offset: Offset of first metadata item in slice +- * @fds_offset: Offset of FD item in slice +- * @memfd_offset: Array of slice-offsets for all memfd items + * @priority: Message priority + * @dst_name_id: The sequence number of the name this message is + * addressed to, 0 for messages sent to an ID +- * @msg_res: Message resources +- * @proc_meta: Process metadata, captured at message arrival +- * @conn_meta: Connection metadata, captured at message arrival +- * @reply: The reply block if a reply to this message is expected ++ * @conn: Connection this entry is queued on ++ * @gaps: Gaps object to fill message gaps at RECV time + * @user: User used for accounting ++ * @slice: Slice in the receiver's pool for the message ++ * @reply: The reply block if a reply to this message is expected + */ + struct kdbus_queue_entry { + struct list_head entry; + struct rb_node prio_node; + struct list_head prio_entry; + +- struct kdbus_pool_slice *slice; +- +- u64 attach_flags; +- size_t meta_offset; +- size_t fds_offset; +- size_t *memfd_offset; +- + s64 priority; + u64 dst_name_id; + +- struct kdbus_msg_resources *msg_res; +- struct kdbus_meta_proc *proc_meta; +- struct kdbus_meta_conn *conn_meta; +- struct kdbus_reply *reply; + struct kdbus_conn *conn; ++ struct kdbus_gaps *gaps; + struct kdbus_user *user; ++ struct kdbus_pool_slice *slice; ++ struct kdbus_reply *reply; + }; + +-struct kdbus_kmsg; +- + void kdbus_queue_init(struct kdbus_queue *queue); + struct kdbus_queue_entry *kdbus_queue_peek(struct kdbus_queue *queue, + s64 priority, bool use_priority); + +-struct kdbus_queue_entry *kdbus_queue_entry_new(struct kdbus_conn *conn_src, +- struct kdbus_conn *conn_dst, +- const struct kdbus_kmsg *kmsg); ++struct kdbus_queue_entry *kdbus_queue_entry_new(struct kdbus_conn *src, ++ struct kdbus_conn *dst, ++ struct kdbus_staging *s); + void kdbus_queue_entry_free(struct kdbus_queue_entry *entry); + int kdbus_queue_entry_install(struct kdbus_queue_entry *entry, + u64 *return_flags, bool install_fds); +-- +2.4.3 + + +From 149fd9e2deb3fc394cf37f6f848ccb1ea34358d2 Mon Sep 17 00:00:00 2001 +From: David Herrmann <dh.herrmann@gmail.com> +Date: Wed, 24 Jun 2015 15:29:53 +0200 +Subject: [PATCH 27/34] kdbus: drop unused metadata code + +Now that we switched to the new kdbus_staging infrastructure, the old +RECV-time metadata helpers are no longer needed. Drop them. + +Signed-off-by: David Herrmann <dh.herrmann@gmail.com> +--- + ipc/kdbus/metadata.c | 371 --------------------------------------------------- + ipc/kdbus/metadata.h | 11 -- + 2 files changed, 382 deletions(-) + +diff --git a/ipc/kdbus/metadata.c b/ipc/kdbus/metadata.c +index 70ce5d15fc98..43e5f4564925 100644 +--- a/ipc/kdbus/metadata.c ++++ b/ipc/kdbus/metadata.c +@@ -714,138 +714,6 @@ exit_unlock: + return ret; + } + +-/* +- * kdbus_meta_export_prepare() - Prepare metadata for export +- * @mp: Process metadata, or NULL +- * @mf: Fake metadata, or NULL +- * @mc: Connection metadata, or NULL +- * @mask: Pointer to mask of KDBUS_ATTACH_* flags to export +- * @sz: Pointer to return the size needed by the metadata +- * +- * Does a conservative calculation of how much space metadata information +- * will take up during export. It is 'conservative' because for string +- * translations in namespaces, it will use the kernel namespaces, which is +- * the longest possible version. +- * +- * The actual size consumed by kdbus_meta_export() may hence vary from the +- * one reported here, but it is guaranteed never to be greater. +- * +- * Return: 0 on success, negative error number otherwise. +- */ +-int kdbus_meta_export_prepare(struct kdbus_meta_proc *mp, +- struct kdbus_meta_fake *mf, +- struct kdbus_meta_conn *mc, +- u64 *mask, size_t *sz) +-{ +- char *exe_pathname = NULL; +- void *exe_page = NULL; +- size_t size = 0; +- u64 valid = 0; +- int ret = 0; +- +- if (WARN_ON(mf && mp)) +- mp = NULL; +- +- if (mf) +- valid |= mf->valid; +- +- if (mp) { +- mutex_lock(&mp->lock); +- valid |= mp->valid; +- mutex_unlock(&mp->lock); +- } +- +- if (mc) { +- mutex_lock(&mc->lock); +- valid |= mc->valid; +- mutex_unlock(&mc->lock); +- } +- +- *mask &= valid; +- +- if (!*mask) +- goto exit; +- +- /* process metadata */ +- +- if ((mp || mf) && (*mask & KDBUS_ATTACH_CREDS)) +- size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_creds)); +- +- if ((mp || mf) && (*mask & KDBUS_ATTACH_PIDS)) +- size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_pids)); +- +- if (mp && (*mask & KDBUS_ATTACH_AUXGROUPS)) +- size += KDBUS_ITEM_SIZE(mp->cred->group_info->ngroups * +- sizeof(u64)); +- +- if (mp && (*mask & KDBUS_ATTACH_TID_COMM)) +- size += KDBUS_ITEM_SIZE(strlen(mp->tid_comm) + 1); +- +- if (mp && (*mask & KDBUS_ATTACH_PID_COMM)) +- size += KDBUS_ITEM_SIZE(strlen(mp->pid_comm) + 1); +- +- if (mp && (*mask & KDBUS_ATTACH_EXE)) { +- exe_page = (void *)__get_free_page(GFP_TEMPORARY); +- if (!exe_page) { +- ret = -ENOMEM; +- goto exit; +- } +- +- exe_pathname = d_path(&mp->exe_path, exe_page, PAGE_SIZE); +- if (IS_ERR(exe_pathname)) { +- ret = PTR_ERR(exe_pathname); +- goto exit; +- } +- +- size += KDBUS_ITEM_SIZE(strlen(exe_pathname) + 1); +- free_page((unsigned long)exe_page); +- } +- +- if (mp && (*mask & KDBUS_ATTACH_CMDLINE)) +- size += KDBUS_ITEM_SIZE(strlen(mp->cmdline) + 1); +- +- if (mp && (*mask & KDBUS_ATTACH_CGROUP)) +- size += KDBUS_ITEM_SIZE(strlen(mp->cgroup) + 1); +- +- if (mp && (*mask & KDBUS_ATTACH_CAPS)) +- size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_meta_caps)); +- +- if ((mp || mf) && (*mask & KDBUS_ATTACH_SECLABEL)) +- size += KDBUS_ITEM_SIZE(strlen(mp ? mp->seclabel +- : mf->seclabel) + 1); +- +- if (mp && (*mask & KDBUS_ATTACH_AUDIT)) +- size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_audit)); +- +- /* connection metadata */ +- +- if (mc && (*mask & KDBUS_ATTACH_NAMES)) +- size += KDBUS_ALIGN8(mc->owned_names_size); +- +- if (mc && (*mask & KDBUS_ATTACH_CONN_DESCRIPTION)) +- size += KDBUS_ITEM_SIZE(strlen(mc->conn_description) + 1); +- +- if (mc && (*mask & KDBUS_ATTACH_TIMESTAMP)) +- size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_timestamp)); +- +-exit: +- *sz = size; +- +- return ret; +-} +- +-static int kdbus_meta_push_kvec(struct kvec *kvec, +- struct kdbus_item_header *hdr, +- u64 type, void *payload, +- size_t payload_size, u64 *size) +-{ +- hdr->type = type; +- hdr->size = KDBUS_ITEM_HEADER_SIZE + payload_size; +- kdbus_kvec_set(kvec++, hdr, sizeof(*hdr), size); +- kdbus_kvec_set(kvec++, payload, payload_size, size); +- return 2 + !!kdbus_kvec_pad(kvec++, size); +-} +- + static void kdbus_meta_export_caps(struct kdbus_meta_caps *out, + const struct kdbus_meta_proc *mp, + struct user_namespace *user_ns) +@@ -922,245 +790,6 @@ static gid_t kdbus_from_kgid_keep(struct user_namespace *ns, kgid_t gid) + return gid_valid(gid) ? from_kgid_munged(ns, gid) : ((gid_t)-1); + } + +-/** +- * kdbus_meta_export() - export information from metadata into a slice +- * @mp: Process metadata, or NULL +- * @mf: Fake metadata, or NULL +- * @mc: Connection metadata, or NULL +- * @conn: Target connection to translate metadata into +- * @mask: Mask of KDBUS_ATTACH_* flags to export +- * @slice: The slice to export to +- * @offset: The offset inside @slice to write to +- * @real_size: The real size the metadata consumed +- * +- * This function exports information from metadata into @slice at offset +- * @offset inside that slice. Only information that is requested in @mask +- * and that has been collected before is exported. +- * +- * In order to make sure not to write out of bounds, @mask must be the same +- * value that was previously returned from kdbus_meta_export_prepare(). The +- * function will, however, not necessarily write as many bytes as returned by +- * kdbus_meta_export_prepare(); depending on the namespaces in question, it +- * might use up less than that. +- * +- * All information will be translated using the namespaces of @conn. +- * +- * Return: 0 on success, negative error number otherwise. +- */ +-int kdbus_meta_export(struct kdbus_meta_proc *mp, +- struct kdbus_meta_fake *mf, +- struct kdbus_meta_conn *mc, +- struct kdbus_conn *conn, +- u64 mask, +- struct kdbus_pool_slice *slice, +- off_t offset, +- size_t *real_size) +-{ +- struct user_namespace *user_ns = conn->user_ns; +- struct kdbus_item_header item_hdr[13], *hdr; +- char *exe_pathname = NULL; +- struct kdbus_creds creds; +- struct kdbus_pids pids; +- void *exe_page = NULL; +- struct kvec kvec[40]; +- u64 *auxgrps = NULL; +- size_t cnt = 0; +- u64 size = 0; +- int ret = 0; +- +- if (WARN_ON(mf && mp)) +- mp = NULL; +- +- hdr = &item_hdr[0]; +- +- if (mask == 0) { +- *real_size = 0; +- return 0; +- } +- +- /* process metadata */ +- +- if (mf && (mask & KDBUS_ATTACH_CREDS)) { +- creds.uid = kdbus_from_kuid_keep(user_ns, mf->uid); +- creds.euid = kdbus_from_kuid_keep(user_ns, mf->euid); +- creds.suid = kdbus_from_kuid_keep(user_ns, mf->suid); +- creds.fsuid = kdbus_from_kuid_keep(user_ns, mf->fsuid); +- creds.gid = kdbus_from_kgid_keep(user_ns, mf->gid); +- creds.egid = kdbus_from_kgid_keep(user_ns, mf->egid); +- creds.sgid = kdbus_from_kgid_keep(user_ns, mf->sgid); +- creds.fsgid = kdbus_from_kgid_keep(user_ns, mf->fsgid); +- +- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, KDBUS_ITEM_CREDS, +- &creds, sizeof(creds), &size); +- } else if (mp && (mask & KDBUS_ATTACH_CREDS)) { +- const struct cred *c = mp->cred; +- +- creds.uid = kdbus_from_kuid_keep(user_ns, c->uid); +- creds.euid = kdbus_from_kuid_keep(user_ns, c->euid); +- creds.suid = kdbus_from_kuid_keep(user_ns, c->suid); +- creds.fsuid = kdbus_from_kuid_keep(user_ns, c->fsuid); +- creds.gid = kdbus_from_kgid_keep(user_ns, c->gid); +- creds.egid = kdbus_from_kgid_keep(user_ns, c->egid); +- creds.sgid = kdbus_from_kgid_keep(user_ns, c->sgid); +- creds.fsgid = kdbus_from_kgid_keep(user_ns, c->fsgid); +- +- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, KDBUS_ITEM_CREDS, +- &creds, sizeof(creds), &size); +- } +- +- if (mf && (mask & KDBUS_ATTACH_PIDS)) { +- pids.pid = pid_nr_ns(mf->tgid, conn->pid_ns); +- pids.tid = pid_nr_ns(mf->pid, conn->pid_ns); +- pids.ppid = pid_nr_ns(mf->ppid, conn->pid_ns); +- +- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, KDBUS_ITEM_PIDS, +- &pids, sizeof(pids), &size); +- } else if (mp && (mask & KDBUS_ATTACH_PIDS)) { +- pids.pid = pid_nr_ns(mp->tgid, conn->pid_ns); +- pids.tid = pid_nr_ns(mp->pid, conn->pid_ns); +- pids.ppid = pid_nr_ns(mp->ppid, conn->pid_ns); +- +- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, KDBUS_ITEM_PIDS, +- &pids, sizeof(pids), &size); +- } +- +- if (mp && (mask & KDBUS_ATTACH_AUXGROUPS)) { +- const struct group_info *info = mp->cred->group_info; +- size_t i, n, payload_size; +- +- n = info->ngroups; +- payload_size = n * sizeof(u64); +- auxgrps = kmalloc(payload_size, GFP_KERNEL); +- if (!auxgrps) { +- ret = -ENOMEM; +- goto exit; +- } +- +- for (i = 0; i < n; ++i) +- auxgrps[i] = from_kgid_munged(user_ns, +- GROUP_AT(info, i)); +- +- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, +- KDBUS_ITEM_AUXGROUPS, +- auxgrps, payload_size, &size); +- } +- +- if (mp && (mask & KDBUS_ATTACH_TID_COMM)) +- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, +- KDBUS_ITEM_TID_COMM, mp->tid_comm, +- strlen(mp->tid_comm) + 1, &size); +- +- if (mp && (mask & KDBUS_ATTACH_PID_COMM)) +- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, +- KDBUS_ITEM_PID_COMM, mp->pid_comm, +- strlen(mp->pid_comm) + 1, &size); +- +- if (mp && (mask & KDBUS_ATTACH_EXE)) { +- struct path p; +- +- /* +- * TODO: We need access to __d_path() so we can write the path +- * relative to conn->root_path. Once upstream, we need +- * EXPORT_SYMBOL(__d_path) or an equivalent of d_path() that +- * takes the root path directly. Until then, we drop this item +- * if the root-paths differ. +- */ +- +- get_fs_root(current->fs, &p); +- if (path_equal(&p, &mp->root_path) && +- path_equal(&p, &conn->root_path)) { +- exe_page = (void *)__get_free_page(GFP_TEMPORARY); +- if (!exe_page) { +- path_put(&p); +- ret = -ENOMEM; +- goto exit; +- } +- +- exe_pathname = d_path(&mp->exe_path, exe_page, +- PAGE_SIZE); +- if (IS_ERR(exe_pathname)) { +- path_put(&p); +- ret = PTR_ERR(exe_pathname); +- goto exit; +- } +- +- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, +- KDBUS_ITEM_EXE, +- exe_pathname, +- strlen(exe_pathname) + 1, +- &size); +- } +- path_put(&p); +- } +- +- if (mp && (mask & KDBUS_ATTACH_CMDLINE)) +- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, +- KDBUS_ITEM_CMDLINE, mp->cmdline, +- strlen(mp->cmdline) + 1, &size); +- +- if (mp && (mask & KDBUS_ATTACH_CGROUP)) +- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, +- KDBUS_ITEM_CGROUP, mp->cgroup, +- strlen(mp->cgroup) + 1, &size); +- +- if (mp && (mask & KDBUS_ATTACH_CAPS)) { +- struct kdbus_meta_caps caps = {}; +- +- kdbus_meta_export_caps(&caps, mp, user_ns); +- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, +- KDBUS_ITEM_CAPS, &caps, +- sizeof(caps), &size); +- } +- +- if (mf && (mask & KDBUS_ATTACH_SECLABEL)) +- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, +- KDBUS_ITEM_SECLABEL, mf->seclabel, +- strlen(mf->seclabel) + 1, &size); +- else if (mp && (mask & KDBUS_ATTACH_SECLABEL)) +- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, +- KDBUS_ITEM_SECLABEL, mp->seclabel, +- strlen(mp->seclabel) + 1, &size); +- +- if (mp && (mask & KDBUS_ATTACH_AUDIT)) { +- struct kdbus_audit a = { +- .loginuid = from_kuid(user_ns, mp->audit_loginuid), +- .sessionid = mp->audit_sessionid, +- }; +- +- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, KDBUS_ITEM_AUDIT, +- &a, sizeof(a), &size); +- } +- +- /* connection metadata */ +- +- if (mc && (mask & KDBUS_ATTACH_NAMES)) +- kdbus_kvec_set(&kvec[cnt++], mc->owned_names_items, +- KDBUS_ALIGN8(mc->owned_names_size), &size); +- +- if (mc && (mask & KDBUS_ATTACH_CONN_DESCRIPTION)) +- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, +- KDBUS_ITEM_CONN_DESCRIPTION, +- mc->conn_description, +- strlen(mc->conn_description) + 1, +- &size); +- +- if (mc && (mask & KDBUS_ATTACH_TIMESTAMP)) +- cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, +- KDBUS_ITEM_TIMESTAMP, &mc->ts, +- sizeof(mc->ts), &size); +- +- ret = kdbus_pool_slice_copy_kvec(slice, offset, kvec, cnt, size); +- *real_size = size; +- +-exit: +- kfree(auxgrps); +- +- if (exe_page) +- free_page((unsigned long)exe_page); +- +- return ret; +-} +- + struct kdbus_meta_staging { + const struct kdbus_meta_proc *mp; + const struct kdbus_meta_fake *mf; +diff --git a/ipc/kdbus/metadata.h b/ipc/kdbus/metadata.h +index a30b0ad26af2..8fb2a9f7f82e 100644 +--- a/ipc/kdbus/metadata.h ++++ b/ipc/kdbus/metadata.h +@@ -72,17 +72,6 @@ int kdbus_meta_conn_collect(struct kdbus_meta_conn *mc, + struct kdbus_conn *conn, + u64 msg_seqnum, u64 what); + +-int kdbus_meta_export_prepare(struct kdbus_meta_proc *mp, +- struct kdbus_meta_fake *mf, +- struct kdbus_meta_conn *mc, +- u64 *mask, size_t *sz); +-int kdbus_meta_export(struct kdbus_meta_proc *mp, +- struct kdbus_meta_fake *mf, +- struct kdbus_meta_conn *mc, +- struct kdbus_conn *conn, +- u64 mask, +- struct kdbus_pool_slice *slice, +- off_t offset, size_t *real_size); + int kdbus_meta_emit(struct kdbus_meta_proc *mp, + struct kdbus_meta_fake *mf, + struct kdbus_meta_conn *mc, +-- +2.4.3 + + +From 5c9d1e5ee20da087dee20f20d5fa312249a163e4 Mon Sep 17 00:00:00 2001 +From: David Herrmann <dh.herrmann@gmail.com> +Date: Wed, 24 Jun 2015 15:31:10 +0200 +Subject: [PATCH 28/34] kdbus: drop unused message handling + +Now that we switched to kdbus_staging, the old message importer and +handling is no longer needed. Drop it. + +Signed-off-by: David Herrmann <dh.herrmann@gmail.com> +--- + ipc/kdbus/message.c | 600 ---------------------------------------------------- + ipc/kdbus/message.h | 106 ---------- + 2 files changed, 706 deletions(-) + +diff --git a/ipc/kdbus/message.c b/ipc/kdbus/message.c +index f1ec69f3697f..72fb5908c927 100644 +--- a/ipc/kdbus/message.c ++++ b/ipc/kdbus/message.c +@@ -37,608 +37,8 @@ + #include "names.h" + #include "policy.h" + +-#define KDBUS_KMSG_HEADER_SIZE offsetof(struct kdbus_kmsg, msg) +- +-static struct kdbus_msg_resources *kdbus_msg_resources_new(void) +-{ +- struct kdbus_msg_resources *r; +- +- r = kzalloc(sizeof(*r), GFP_KERNEL); +- if (!r) +- return ERR_PTR(-ENOMEM); +- +- kref_init(&r->kref); +- +- return r; +-} +- +-static void __kdbus_msg_resources_free(struct kref *kref) +-{ +- struct kdbus_msg_resources *r = +- container_of(kref, struct kdbus_msg_resources, kref); +- size_t i; +- +- for (i = 0; i < r->data_count; ++i) { +- switch (r->data[i].type) { +- case KDBUS_MSG_DATA_VEC: +- /* nothing to do */ +- break; +- case KDBUS_MSG_DATA_MEMFD: +- if (r->data[i].memfd.file) +- fput(r->data[i].memfd.file); +- break; +- } +- } +- +- for (i = 0; i < r->fds_count; i++) +- if (r->fds[i]) +- fput(r->fds[i]); +- +- kfree(r->dst_name); +- kfree(r->data); +- kfree(r->fds); +- kfree(r); +-} +- +-/** +- * kdbus_msg_resources_ref() - Acquire reference to msg resources +- * @r: resources to acquire ref to +- * +- * Return: The acquired resource +- */ +-struct kdbus_msg_resources * +-kdbus_msg_resources_ref(struct kdbus_msg_resources *r) +-{ +- if (r) +- kref_get(&r->kref); +- return r; +-} +- +-/** +- * kdbus_msg_resources_unref() - Drop reference to msg resources +- * @r: resources to drop reference of +- * +- * Return: NULL +- */ +-struct kdbus_msg_resources * +-kdbus_msg_resources_unref(struct kdbus_msg_resources *r) +-{ +- if (r) +- kref_put(&r->kref, __kdbus_msg_resources_free); +- return NULL; +-} +- +-/** +- * kdbus_kmsg_free() - free allocated message +- * @kmsg: Message +- */ +-void kdbus_kmsg_free(struct kdbus_kmsg *kmsg) +-{ +- if (!kmsg) +- return; +- +- kdbus_msg_resources_unref(kmsg->res); +- kdbus_meta_conn_unref(kmsg->conn_meta); +- kdbus_meta_proc_unref(kmsg->proc_meta); +- kfree(kmsg->iov); +- kfree(kmsg); +-} +- +-struct kdbus_kmsg *kdbus_kmsg_new_kernel(struct kdbus_bus *bus, +- u64 dst, u64 cookie_timeout, +- size_t it_size, size_t it_type) +-{ +- struct kdbus_kmsg *kmsg; +- size_t size; +- int ret; +- +- size = sizeof(struct kdbus_kmsg) + KDBUS_ITEM_SIZE(it_size); +- kmsg = kzalloc(size, GFP_KERNEL); +- if (!kmsg) +- return ERR_PTR(-ENOMEM); +- +- kmsg->seq = atomic64_inc_return(&bus->domain->last_id); +- +- kmsg->proc_meta = kdbus_meta_proc_new(); +- if (IS_ERR(kmsg->proc_meta)) { +- ret = PTR_ERR(kmsg->proc_meta); +- kmsg->proc_meta = NULL; +- goto exit; +- } +- +- kmsg->conn_meta = kdbus_meta_conn_new(); +- if (IS_ERR(kmsg->conn_meta)) { +- ret = PTR_ERR(kmsg->conn_meta); +- kmsg->conn_meta = NULL; +- goto exit; +- } +- +- kmsg->msg.size = size - KDBUS_KMSG_HEADER_SIZE; +- kmsg->msg.flags = (dst == KDBUS_DST_ID_BROADCAST) ? +- KDBUS_MSG_SIGNAL : 0; +- kmsg->msg.dst_id = dst; +- kmsg->msg.src_id = KDBUS_SRC_ID_KERNEL; +- kmsg->msg.payload_type = KDBUS_PAYLOAD_KERNEL; +- kmsg->msg.cookie_reply = cookie_timeout; +- kmsg->notify = kmsg->msg.items; +- kmsg->notify->size = KDBUS_ITEM_HEADER_SIZE + it_size; +- kmsg->notify->type = it_type; +- +- return kmsg; +- +-exit: +- kdbus_kmsg_free(kmsg); +- return ERR_PTR(ret); +-} +- +-static int kdbus_handle_check_file(struct file *file) +-{ +- struct inode *inode = file_inode(file); +- struct socket *sock; +- +- /* +- * Don't allow file descriptors in the transport that themselves allow +- * file descriptor queueing. This will eventually be allowed once both +- * unix domain sockets and kdbus share a generic garbage collector. +- */ +- +- if (file->f_op == &kdbus_handle_ops) +- return -EOPNOTSUPP; +- +- if (!S_ISSOCK(inode->i_mode)) +- return 0; +- +- if (file->f_mode & FMODE_PATH) +- return 0; +- +- sock = SOCKET_I(inode); +- if (sock->sk && sock->ops && sock->ops->family == PF_UNIX) +- return -EOPNOTSUPP; +- +- return 0; +-} +- + static const char * const zeros = "\0\0\0\0\0\0\0"; + +-/* +- * kdbus_msg_scan_items() - validate incoming data and prepare parsing +- * @kmsg: Message +- * @bus: Bus the message is sent over +- * +- * Return: 0 on success, negative errno on failure. +- * +- * Files references in MEMFD or FDS items are pinned. +- * +- * On errors, the caller should drop any taken reference with +- * kdbus_kmsg_free() +- */ +-static int kdbus_msg_scan_items(struct kdbus_kmsg *kmsg, +- struct kdbus_bus *bus) +-{ +- struct kdbus_msg_resources *res = kmsg->res; +- const struct kdbus_msg *msg = &kmsg->msg; +- const struct kdbus_item *item; +- size_t n_res, n_vecs, n_memfds; +- bool has_bloom = false; +- bool has_name = false; +- bool has_fds = false; +- bool is_broadcast; +- bool is_signal; +- u64 vec_size; +- +- is_broadcast = (msg->dst_id == KDBUS_DST_ID_BROADCAST); +- is_signal = !!(msg->flags & KDBUS_MSG_SIGNAL); +- +- /* count data payloads */ +- n_vecs = 0; +- n_memfds = 0; +- KDBUS_ITEMS_FOREACH(item, msg->items, KDBUS_ITEMS_SIZE(msg, items)) { +- switch (item->type) { +- case KDBUS_ITEM_PAYLOAD_VEC: +- ++n_vecs; +- break; +- case KDBUS_ITEM_PAYLOAD_MEMFD: +- ++n_memfds; +- if (item->memfd.size % 8) +- ++n_vecs; +- break; +- default: +- break; +- } +- } +- +- n_res = n_vecs + n_memfds; +- if (n_res > 0) { +- res->data = kcalloc(n_res, sizeof(*res->data), GFP_KERNEL); +- if (!res->data) +- return -ENOMEM; +- } +- +- if (n_vecs > 0) { +- kmsg->iov = kcalloc(n_vecs, sizeof(*kmsg->iov), GFP_KERNEL); +- if (!kmsg->iov) +- return -ENOMEM; +- } +- +- /* import data payloads */ +- vec_size = 0; +- KDBUS_ITEMS_FOREACH(item, msg->items, KDBUS_ITEMS_SIZE(msg, items)) { +- size_t payload_size = KDBUS_ITEM_PAYLOAD_SIZE(item); +- struct iovec *iov = kmsg->iov + kmsg->iov_count; +- +- switch (item->type) { +- case KDBUS_ITEM_PAYLOAD_VEC: { +- struct kdbus_msg_data *d = res->data + res->data_count; +- void __force __user *ptr = KDBUS_PTR(item->vec.address); +- size_t size = item->vec.size; +- +- if (vec_size + size < vec_size) +- return -EMSGSIZE; +- if (vec_size + size > KDBUS_MSG_MAX_PAYLOAD_VEC_SIZE) +- return -EMSGSIZE; +- +- d->type = KDBUS_MSG_DATA_VEC; +- d->size = size; +- +- if (ptr) { +- if (unlikely(!access_ok(VERIFY_READ, ptr, +- size))) +- return -EFAULT; +- +- d->vec.off = kmsg->pool_size; +- iov->iov_base = ptr; +- iov->iov_len = size; +- } else { +- d->vec.off = ~0ULL; +- iov->iov_base = (char __user *)zeros; +- iov->iov_len = size % 8; +- } +- +- if (kmsg->pool_size + iov->iov_len < kmsg->pool_size) +- return -EMSGSIZE; +- +- kmsg->pool_size += iov->iov_len; +- ++kmsg->iov_count; +- ++res->vec_count; +- ++res->data_count; +- vec_size += size; +- +- break; +- } +- +- case KDBUS_ITEM_PAYLOAD_MEMFD: { +- struct kdbus_msg_data *d = res->data + res->data_count; +- u64 start = item->memfd.start; +- u64 size = item->memfd.size; +- size_t pad = size % 8; +- int seals, mask; +- struct file *f; +- +- if (kmsg->pool_size + size % 8 < kmsg->pool_size) +- return -EMSGSIZE; +- if (start + size < start) +- return -EMSGSIZE; +- +- if (item->memfd.fd < 0) +- return -EBADF; +- +- if (res->memfd_count >= KDBUS_MSG_MAX_MEMFD_ITEMS) +- return -E2BIG; +- +- f = fget(item->memfd.fd); +- if (!f) +- return -EBADF; +- +- if (pad) { +- iov->iov_base = (char __user *)zeros; +- iov->iov_len = pad; +- +- kmsg->pool_size += pad; +- ++kmsg->iov_count; +- } +- +- ++res->data_count; +- ++res->memfd_count; +- +- d->type = KDBUS_MSG_DATA_MEMFD; +- d->size = size; +- d->memfd.start = start; +- d->memfd.file = f; +- +- /* +- * We only accept a sealed memfd file whose content +- * cannot be altered by the sender or anybody else +- * while it is shared or in-flight. Other files need +- * to be passed with KDBUS_MSG_FDS. +- */ +- seals = shmem_get_seals(f); +- if (seals < 0) +- return -EMEDIUMTYPE; +- +- mask = F_SEAL_SHRINK | F_SEAL_GROW | +- F_SEAL_WRITE | F_SEAL_SEAL; +- if ((seals & mask) != mask) +- return -ETXTBSY; +- +- if (start + size > (u64)i_size_read(file_inode(f))) +- return -EBADF; +- +- break; +- } +- +- case KDBUS_ITEM_FDS: { +- unsigned int i; +- unsigned int fds_count = payload_size / sizeof(int); +- +- /* do not allow multiple fd arrays */ +- if (has_fds) +- return -EEXIST; +- has_fds = true; +- +- /* Do not allow to broadcast file descriptors */ +- if (is_broadcast) +- return -ENOTUNIQ; +- +- if (fds_count > KDBUS_CONN_MAX_FDS_PER_USER) +- return -EMFILE; +- +- res->fds = kcalloc(fds_count, sizeof(struct file *), +- GFP_KERNEL); +- if (!res->fds) +- return -ENOMEM; +- +- for (i = 0; i < fds_count; i++) { +- int fd = item->fds[i]; +- int ret; +- +- /* +- * Verify the fd and increment the usage count. +- * Use fget_raw() to allow passing O_PATH fds. +- */ +- if (fd < 0) +- return -EBADF; +- +- res->fds[i] = fget_raw(fd); +- if (!res->fds[i]) +- return -EBADF; +- +- res->fds_count++; +- +- ret = kdbus_handle_check_file(res->fds[i]); +- if (ret < 0) +- return ret; +- } +- +- break; +- } +- +- case KDBUS_ITEM_BLOOM_FILTER: { +- u64 bloom_size; +- +- /* do not allow multiple bloom filters */ +- if (has_bloom) +- return -EEXIST; +- has_bloom = true; +- +- bloom_size = payload_size - +- offsetof(struct kdbus_bloom_filter, data); +- +- /* +- * Allow only bloom filter sizes of a multiple of 64bit. +- */ +- if (!KDBUS_IS_ALIGNED8(bloom_size)) +- return -EFAULT; +- +- /* do not allow mismatching bloom filter sizes */ +- if (bloom_size != bus->bloom.size) +- return -EDOM; +- +- kmsg->bloom_filter = &item->bloom_filter; +- break; +- } +- +- case KDBUS_ITEM_DST_NAME: +- /* do not allow multiple names */ +- if (has_name) +- return -EEXIST; +- has_name = true; +- +- if (!kdbus_name_is_valid(item->str, false)) +- return -EINVAL; +- +- res->dst_name = kstrdup(item->str, GFP_KERNEL); +- if (!res->dst_name) +- return -ENOMEM; +- break; +- +- default: +- return -EINVAL; +- } +- } +- +- /* name is needed if no ID is given */ +- if (msg->dst_id == KDBUS_DST_ID_NAME && !has_name) +- return -EDESTADDRREQ; +- +- if (is_broadcast) { +- /* Broadcasts can't take names */ +- if (has_name) +- return -EBADMSG; +- +- /* All broadcasts have to be signals */ +- if (!is_signal) +- return -EBADMSG; +- +- /* Timeouts are not allowed for broadcasts */ +- if (msg->timeout_ns > 0) +- return -ENOTUNIQ; +- } +- +- /* +- * Signal messages require a bloom filter, and bloom filters are +- * only valid with signals. +- */ +- if (is_signal ^ has_bloom) +- return -EBADMSG; +- +- return 0; +-} +- +-/** +- * kdbus_kmsg_new_from_cmd() - create kernel message from send payload +- * @conn: Connection +- * @cmd_send: Payload of KDBUS_CMD_SEND +- * +- * Return: a new kdbus_kmsg on success, ERR_PTR on failure. +- */ +-struct kdbus_kmsg *kdbus_kmsg_new_from_cmd(struct kdbus_conn *conn, +- struct kdbus_cmd_send *cmd_send) +-{ +- struct kdbus_kmsg *m; +- u64 size; +- int ret; +- +- ret = kdbus_copy_from_user(&size, KDBUS_PTR(cmd_send->msg_address), +- sizeof(size)); +- if (ret < 0) +- return ERR_PTR(ret); +- +- if (size < sizeof(struct kdbus_msg) || size > KDBUS_MSG_MAX_SIZE) +- return ERR_PTR(-EINVAL); +- +- m = kmalloc(size + KDBUS_KMSG_HEADER_SIZE, GFP_KERNEL); +- if (!m) +- return ERR_PTR(-ENOMEM); +- +- memset(m, 0, KDBUS_KMSG_HEADER_SIZE); +- m->seq = atomic64_inc_return(&conn->ep->bus->domain->last_id); +- +- m->proc_meta = kdbus_meta_proc_new(); +- if (IS_ERR(m->proc_meta)) { +- ret = PTR_ERR(m->proc_meta); +- m->proc_meta = NULL; +- goto exit_free; +- } +- +- m->conn_meta = kdbus_meta_conn_new(); +- if (IS_ERR(m->conn_meta)) { +- ret = PTR_ERR(m->conn_meta); +- m->conn_meta = NULL; +- goto exit_free; +- } +- +- if (copy_from_user(&m->msg, KDBUS_PTR(cmd_send->msg_address), size)) { +- ret = -EFAULT; +- goto exit_free; +- } +- +- if (m->msg.size != size) { +- ret = -EINVAL; +- goto exit_free; +- } +- +- if (m->msg.flags & ~(KDBUS_MSG_EXPECT_REPLY | +- KDBUS_MSG_NO_AUTO_START | +- KDBUS_MSG_SIGNAL)) { +- ret = -EINVAL; +- goto exit_free; +- } +- +- ret = kdbus_items_validate(m->msg.items, +- KDBUS_ITEMS_SIZE(&m->msg, items)); +- if (ret < 0) +- goto exit_free; +- +- m->res = kdbus_msg_resources_new(); +- if (IS_ERR(m->res)) { +- ret = PTR_ERR(m->res); +- m->res = NULL; +- goto exit_free; +- } +- +- /* do not accept kernel-generated messages */ +- if (m->msg.payload_type == KDBUS_PAYLOAD_KERNEL) { +- ret = -EINVAL; +- goto exit_free; +- } +- +- if (m->msg.flags & KDBUS_MSG_EXPECT_REPLY) { +- /* requests for replies need timeout and cookie */ +- if (m->msg.timeout_ns == 0 || m->msg.cookie == 0) { +- ret = -EINVAL; +- goto exit_free; +- } +- +- /* replies may not be expected for broadcasts */ +- if (m->msg.dst_id == KDBUS_DST_ID_BROADCAST) { +- ret = -ENOTUNIQ; +- goto exit_free; +- } +- +- /* replies may not be expected for signals */ +- if (m->msg.flags & KDBUS_MSG_SIGNAL) { +- ret = -EINVAL; +- goto exit_free; +- } +- } else { +- /* +- * KDBUS_SEND_SYNC_REPLY is only valid together with +- * KDBUS_MSG_EXPECT_REPLY +- */ +- if (cmd_send->flags & KDBUS_SEND_SYNC_REPLY) { +- ret = -EINVAL; +- goto exit_free; +- } +- +- /* replies cannot be signals */ +- if (m->msg.cookie_reply && (m->msg.flags & KDBUS_MSG_SIGNAL)) { +- ret = -EINVAL; +- goto exit_free; +- } +- } +- +- ret = kdbus_msg_scan_items(m, conn->ep->bus); +- if (ret < 0) +- goto exit_free; +- +- /* patch-in the source of this message */ +- if (m->msg.src_id > 0 && m->msg.src_id != conn->id) { +- ret = -EINVAL; +- goto exit_free; +- } +- m->msg.src_id = conn->id; +- +- return m; +- +-exit_free: +- kdbus_kmsg_free(m); +- return ERR_PTR(ret); +-} +- +-/** +- * kdbus_kmsg_collect_metadata() - collect metadata +- * @kmsg: message to collect metadata on +- * @src: source connection of message +- * @dst: destination connection of message +- * +- * Return: 0 on success, negative error code on failure. +- */ +-int kdbus_kmsg_collect_metadata(const struct kdbus_kmsg *kmsg, +- struct kdbus_conn *src, struct kdbus_conn *dst) +-{ +- u64 attach; +- int ret; +- +- attach = kdbus_meta_calc_attach_flags(src, dst); +- if (!src->meta_fake) { +- ret = kdbus_meta_proc_collect(kmsg->proc_meta, attach); +- if (ret < 0) +- return ret; +- } +- +- return kdbus_meta_conn_collect(kmsg->conn_meta, src, kmsg->seq, attach); +-} +- + static struct kdbus_gaps *kdbus_gaps_new(size_t n_memfds, size_t n_fds) + { + size_t size_offsets, size_memfds, size_fds, size; +diff --git a/ipc/kdbus/message.h b/ipc/kdbus/message.h +index e0c4f2e324b3..298f9c99dfcf 100644 +--- a/ipc/kdbus/message.h ++++ b/ipc/kdbus/message.h +@@ -17,103 +17,6 @@ + #include <linux/fs.h> + #include <linux/kref.h> + #include <uapi/linux/kdbus.h> +-#include "util.h" +-#include "metadata.h" +- +-/** +- * enum kdbus_msg_data_type - Type of kdbus_msg_data payloads +- * @KDBUS_MSG_DATA_VEC: Data vector provided by user-space +- * @KDBUS_MSG_DATA_MEMFD: Memfd payload +- */ +-enum kdbus_msg_data_type { +- KDBUS_MSG_DATA_VEC, +- KDBUS_MSG_DATA_MEMFD, +-}; +- +-/** +- * struct kdbus_msg_data - Data payload as stored by messages +- * @type: Type of payload (KDBUS_MSG_DATA_*) +- * @size: Size of the described payload +- * @off: The offset, relative to the vec slice +- * @start: Offset inside the memfd +- * @file: Backing file referenced by the memfd +- */ +-struct kdbus_msg_data { +- unsigned int type; +- u64 size; +- +- union { +- struct { +- u64 off; +- } vec; +- struct { +- u64 start; +- struct file *file; +- } memfd; +- }; +-}; +- +-/** +- * struct kdbus_kmsg_resources - resources of a message +- * @kref: Reference counter +- * @dst_name: Short-cut to msg for faster lookup +- * @fds: Array of file descriptors to pass +- * @fds_count: Number of file descriptors to pass +- * @data: Array of data payloads +- * @vec_count: Number of VEC entries +- * @memfd_count: Number of MEMFD entries in @data +- * @data_count: Sum of @vec_count + @memfd_count +- */ +-struct kdbus_msg_resources { +- struct kref kref; +- const char *dst_name; +- +- struct file **fds; +- unsigned int fds_count; +- +- struct kdbus_msg_data *data; +- size_t vec_count; +- size_t memfd_count; +- size_t data_count; +-}; +- +-struct kdbus_msg_resources * +-kdbus_msg_resources_ref(struct kdbus_msg_resources *r); +-struct kdbus_msg_resources * +-kdbus_msg_resources_unref(struct kdbus_msg_resources *r); +- +-/** +- * struct kdbus_kmsg - internal message handling data +- * @seq: Domain-global message sequence number +- * @notify: Short-cut to notify-item for kernel notifications +- * @bloom_filter: Bloom filter to match message properties +- * @notify_entry: List of kernel-generated notifications +- * @iov: Array of iovec, describing the payload to copy +- * @iov_count: Number of array members in @iov +- * @pool_size: Overall size of inlined data referenced by @iov +- * @proc_meta: Appended SCM-like metadata of the sending process +- * @conn_meta: Appended SCM-like metadata of the sending connection +- * @res: Message resources +- * @msg: Message from or to userspace +- */ +-struct kdbus_kmsg { +- u64 seq; +- struct kdbus_item *notify; +- +- const struct kdbus_bloom_filter *bloom_filter; +- struct list_head notify_entry; +- +- struct iovec *iov; +- size_t iov_count; +- u64 pool_size; +- +- struct kdbus_meta_proc *proc_meta; +- struct kdbus_meta_conn *conn_meta; +- struct kdbus_msg_resources *res; +- +- /* variable size, must be the last member */ +- struct kdbus_msg msg; +-}; + + struct kdbus_bus; + struct kdbus_conn; +@@ -121,15 +24,6 @@ struct kdbus_meta_conn; + struct kdbus_meta_proc; + struct kdbus_pool_slice; + +-struct kdbus_kmsg *kdbus_kmsg_new_kernel(struct kdbus_bus *bus, +- u64 dst, u64 cookie_timeout, +- size_t it_size, size_t it_type); +-struct kdbus_kmsg *kdbus_kmsg_new_from_cmd(struct kdbus_conn *conn, +- struct kdbus_cmd_send *cmd_send); +-void kdbus_kmsg_free(struct kdbus_kmsg *kmsg); +-int kdbus_kmsg_collect_metadata(const struct kdbus_kmsg *kmsg, +- struct kdbus_conn *src, struct kdbus_conn *dst); +- + /** + * struct kdbus_gaps - gaps in message to be filled later + * @kref: Reference counter +-- +2.4.3 + + +From 5b2ae5600065167040dd6d61466cce345568c68e Mon Sep 17 00:00:00 2001 +From: David Herrmann <dh.herrmann@gmail.com> +Date: Mon, 6 Jul 2015 11:29:05 +0200 +Subject: [PATCH 29/34] kdbus: allow senders to receive own broadcasts + +The dbus1 spec does not place a restriction on who can receive broadcasts. +As long as the sender has a MATCH-rule on itself, it can as well receive +its own broadcasts. + +As it turns out, user-space currently relies on this feature. So make sure +to allow this just like dbus1. If we find some client that does not work +with this, we will have to turn it into a HELLO-flag. Until then, just try +to adjust the default behavior. + +Signed-off-by: David Herrmann <dh.herrmann@gmail.com> +--- + ipc/kdbus/bus.c | 2 -- + tools/testing/selftests/kdbus/test-message.c | 9 +++++--- + tools/testing/selftests/kdbus/test-policy-priv.c | 26 +++++++++++++++++++----- + 3 files changed, 27 insertions(+), 10 deletions(-) + +diff --git a/ipc/kdbus/bus.c b/ipc/kdbus/bus.c +index e7e17a7f7edd..a67f825bdeaf 100644 +--- a/ipc/kdbus/bus.c ++++ b/ipc/kdbus/bus.c +@@ -263,8 +263,6 @@ void kdbus_bus_broadcast(struct kdbus_bus *bus, + + down_read(&bus->conn_rwlock); + hash_for_each(bus->conn_hash, i, conn_dst, hentry) { +- if (conn_dst->id == staging->msg->src_id) +- continue; + if (!kdbus_conn_is_ordinary(conn_dst)) + continue; + +diff --git a/tools/testing/selftests/kdbus/test-message.c b/tools/testing/selftests/kdbus/test-message.c +index f1615dafb7f1..ddc1e0af877b 100644 +--- a/tools/testing/selftests/kdbus/test-message.c ++++ b/tools/testing/selftests/kdbus/test-message.c +@@ -54,9 +54,12 @@ int kdbus_test_message_basic(struct kdbus_test_env *env) + KDBUS_DST_ID_BROADCAST); + ASSERT_RETURN(ret == 0); + +- /* Make sure that we do not get our own broadcasts */ +- ret = kdbus_msg_recv(sender, NULL, NULL); +- ASSERT_RETURN(ret == -EAGAIN); ++ /* Make sure that we do get our own broadcasts */ ++ ret = kdbus_msg_recv(sender, &msg, &offset); ++ ASSERT_RETURN(ret == 0); ++ ASSERT_RETURN(msg->cookie == cookie); ++ ++ kdbus_msg_free(msg); + + /* ... and receive on the 2nd */ + ret = kdbus_msg_recv_poll(conn, 100, &msg, &offset); +diff --git a/tools/testing/selftests/kdbus/test-policy-priv.c b/tools/testing/selftests/kdbus/test-policy-priv.c +index a318cccad0d5..0208638a7245 100644 +--- a/tools/testing/selftests/kdbus/test-policy-priv.c ++++ b/tools/testing/selftests/kdbus/test-policy-priv.c +@@ -110,6 +110,12 @@ static int test_policy_priv_by_broadcast(const char *bus, + KDBUS_DST_ID_BROADCAST); + ASSERT_RETURN(ret == 0); + ++ /* drop own broadcast */ ++ ret = kdbus_msg_recv(child_2, &msg, NULL); ++ ASSERT_RETURN(ret == 0); ++ ASSERT_RETURN(msg->src_id == child_2->id); ++ kdbus_msg_free(msg); ++ + /* Use a little bit high time */ + ret = kdbus_msg_recv_poll(child_2, 1000, + &msg, NULL); +@@ -145,6 +151,12 @@ static int test_policy_priv_by_broadcast(const char *bus, + KDBUS_DST_ID_BROADCAST); + ASSERT_EXIT(ret == 0); + ++ /* drop own broadcast */ ++ ret = kdbus_msg_recv(child_2, &msg, NULL); ++ ASSERT_RETURN(ret == 0); ++ ASSERT_RETURN(msg->src_id == child_2->id); ++ kdbus_msg_free(msg); ++ + /* Use a little bit high time */ + ret = kdbus_msg_recv_poll(child_2, 1000, + &msg, NULL); +@@ -313,11 +325,6 @@ static int test_broadcast_after_policy_upload(struct kdbus_test_env *env) + * receiver is not able to TALK to that name. + */ + +- ret = test_policy_priv_by_broadcast(env->buspath, owner_a, +- DO_NOT_DROP, +- -ETIMEDOUT, -ETIMEDOUT); +- ASSERT_RETURN(ret == 0); +- + /* Activate matching for a privileged connection */ + ret = kdbus_add_match_empty(owner_a); + ASSERT_RETURN(ret == 0); +@@ -408,6 +415,15 @@ static int test_broadcast_after_policy_upload(struct kdbus_test_env *env) + 0, 0, KDBUS_DST_ID_BROADCAST); + ASSERT_RETURN(ret == 0); + ++ ret = kdbus_msg_recv_poll(owner_a, 100, &msg, NULL); ++ ASSERT_RETURN(ret == 0); ++ ASSERT_RETURN(msg->cookie == expected_cookie); ++ ++ /* Check src ID */ ++ ASSERT_RETURN(msg->src_id == owner_a->id); ++ ++ kdbus_msg_free(msg); ++ + ret = kdbus_msg_recv_poll(owner_b, 100, &msg, NULL); + ASSERT_RETURN(ret == 0); + ASSERT_RETURN(msg->cookie == expected_cookie); +-- +2.4.3 + + +From ebca68e897b944559d77d7165bf3d1b173257e72 Mon Sep 17 00:00:00 2001 +From: David Herrmann <dh.herrmann@gmail.com> +Date: Sat, 4 Jul 2015 19:41:28 +0200 +Subject: [PATCH 30/34] kdbus: pass metadata which a receiver could read via + /proc + +Current kdbus behavior is to only pass metadata to a receiver if the +sender actively agreed on sending the metadata (via send-attach-flags). +We now extend this logic in 2 ways: + + - Implicit metadata is always sent, if requested by the receiver. This + includes basic process credentials, pids and connection metadata. The + latter is kdbus-specific information and always public (as it can be + retrieved via other means), and basic process credentials and pids are + required for compatibility to UDS. + + - Any extended process credentials were only passed if told by the + sender. We now extend this logic to pass them also if the receiver + could have read that information via /proc. We verify that the sending + process has a pid in the pid-namespace of the receiver (i.e., it shows + up in /proc mounted in the receiver namespace) and verify the hide_pid + restrictions. + +With this change, we make kdbus in-line with /proc access checks. We +basically say that we assume anyone with access to kdbusfs also has access +to /proc of its *own* pid-namespace (which should be given in any system +setup). We then automatically pass all information *as if* the receiver +would read them immediately on message-retrieval via /proc. But kdbus now +fixes the race-gap between message transmittal and /proc access. + +Signed-off-by: David Herrmann <dh.herrmann@gmail.com> +--- + ipc/kdbus/connection.c | 2 + + ipc/kdbus/connection.h | 2 + + ipc/kdbus/message.c | 2 +- + ipc/kdbus/metadata.c | 189 ++++++++++++++++++++++++++++++++++++++++++++++--- + ipc/kdbus/metadata.h | 5 +- + 5 files changed, 187 insertions(+), 13 deletions(-) + +diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c +index 2b334b04dd9d..461b8d66b2b9 100644 +--- a/ipc/kdbus/connection.c ++++ b/ipc/kdbus/connection.c +@@ -132,6 +132,7 @@ static struct kdbus_conn *kdbus_conn_new(struct kdbus_ep *ep, bool privileged, + conn->cred = get_current_cred(); + conn->user_ns = get_user_ns(current_user_ns()); + conn->pid_ns = get_pid_ns(task_active_pid_ns(current)); ++ conn->pid = get_pid(task_pid(current)); + get_fs_root(current->fs, &conn->root_path); + init_waitqueue_head(&conn->wait); + kdbus_queue_init(&conn->queue); +@@ -282,6 +283,7 @@ static void __kdbus_conn_free(struct kref *kref) + kdbus_pool_free(conn->pool); + kdbus_ep_unref(conn->ep); + path_put(&conn->root_path); ++ put_pid(conn->pid); + put_pid_ns(conn->pid_ns); + put_user_ns(conn->user_ns); + put_cred(conn->cred); +diff --git a/ipc/kdbus/connection.h b/ipc/kdbus/connection.h +index b1769b877504..9a1b13d69085 100644 +--- a/ipc/kdbus/connection.h ++++ b/ipc/kdbus/connection.h +@@ -61,6 +61,7 @@ struct kdbus_staging; + * @cred: The credentials of the connection at creation time + * @user_ns: User namespace at creation time + * @pid_ns: Pid namespace at creation time ++ * @pid: Pid at creation time + * @root_path: Root path at creation time + * @name_count: Number of owned well-known names + * @request_count: Number of pending requests issued by this +@@ -102,6 +103,7 @@ struct kdbus_conn { + const struct cred *cred; + struct user_namespace *user_ns; + struct pid_namespace *pid_ns; ++ struct pid *pid; + struct path root_path; + atomic_t name_count; + atomic_t request_count; +diff --git a/ipc/kdbus/message.c b/ipc/kdbus/message.c +index 72fb5908c927..64763ead693c 100644 +--- a/ipc/kdbus/message.c ++++ b/ipc/kdbus/message.c +@@ -849,7 +849,7 @@ static int kdbus_staging_collect_metadata(struct kdbus_staging *staging, + int ret; + + if (src) +- attach = kdbus_meta_calc_attach_flags(src, dst); ++ attach = kdbus_meta_msg_mask(src, dst); + else + attach = KDBUS_ATTACH_TIMESTAMP; /* metadata for kernel msgs */ + +diff --git a/ipc/kdbus/metadata.c b/ipc/kdbus/metadata.c +index 43e5f4564925..5150932cb257 100644 +--- a/ipc/kdbus/metadata.c ++++ b/ipc/kdbus/metadata.c +@@ -1156,18 +1156,187 @@ exit: + return ret; + } + ++enum { ++ KDBUS_META_PROC_NONE, ++ KDBUS_META_PROC_NORMAL, ++}; ++ ++/** ++ * kdbus_proc_permission() - check /proc permissions on target pid ++ * @pid_ns: namespace we operate in ++ * @cred: credentials of requestor ++ * @target: target process ++ * ++ * This checks whether a process with credentials @cred can access information ++ * of @target in the namespace @pid_ns. This tries to follow /proc permissions, ++ * but is slightly more restrictive. ++ * ++ * Return: The /proc access level (KDBUS_META_PROC_*) is returned. ++ */ ++static unsigned int kdbus_proc_permission(const struct pid_namespace *pid_ns, ++ const struct cred *cred, ++ struct pid *target) ++{ ++ if (pid_ns->hide_pid < 1) ++ return KDBUS_META_PROC_NORMAL; ++ ++ /* XXX: we need groups_search() exported for aux-groups */ ++ if (gid_eq(cred->egid, pid_ns->pid_gid)) ++ return KDBUS_META_PROC_NORMAL; ++ ++ /* ++ * XXX: If ptrace_may_access(PTRACE_MODE_READ) is granted, you can ++ * overwrite hide_pid. However, ptrace_may_access() only supports ++ * checking 'current', hence, we cannot use this here. But we ++ * simply decide to not support this override, so no need to worry. ++ */ ++ ++ return KDBUS_META_PROC_NONE; ++} ++ ++/** ++ * kdbus_meta_proc_mask() - calculate which metadata would be visible to ++ * a connection via /proc ++ * @prv_pid: pid of metadata provider ++ * @req_pid: pid of metadata requestor ++ * @req_cred: credentials of metadata reqeuestor ++ * @wanted: metadata that is requested ++ * ++ * This checks which metadata items of @prv_pid can be read via /proc by the ++ * requestor @req_pid. ++ * ++ * Return: Set of metadata flags the requestor can see (limited by @wanted). ++ */ ++static u64 kdbus_meta_proc_mask(struct pid *prv_pid, ++ struct pid *req_pid, ++ const struct cred *req_cred, ++ u64 wanted) ++{ ++ struct pid_namespace *prv_ns, *req_ns; ++ unsigned int proc; ++ ++ prv_ns = ns_of_pid(prv_pid); ++ req_ns = ns_of_pid(req_pid); ++ ++ /* ++ * If the sender is not visible in the receiver namespace, then the ++ * receiver cannot access the sender via its own procfs. Hence, we do ++ * not attach any additional metadata. ++ */ ++ if (!pid_nr_ns(prv_pid, req_ns)) ++ return 0; ++ ++ /* ++ * If the pid-namespace of the receiver has hide_pid set, it cannot see ++ * any process but its own. We shortcut this /proc permission check if ++ * provider and requestor are the same. If not, we perform rather ++ * expensive /proc permission checks. ++ */ ++ if (prv_pid == req_pid) ++ proc = KDBUS_META_PROC_NORMAL; ++ else ++ proc = kdbus_proc_permission(req_ns, req_cred, prv_pid); ++ ++ /* you need /proc access to read standard process attributes */ ++ if (proc < KDBUS_META_PROC_NORMAL) ++ wanted &= ~(KDBUS_ATTACH_TID_COMM | ++ KDBUS_ATTACH_PID_COMM | ++ KDBUS_ATTACH_SECLABEL | ++ KDBUS_ATTACH_CMDLINE | ++ KDBUS_ATTACH_CGROUP | ++ KDBUS_ATTACH_AUDIT | ++ KDBUS_ATTACH_CAPS | ++ KDBUS_ATTACH_EXE); ++ ++ /* clear all non-/proc flags */ ++ return wanted & (KDBUS_ATTACH_TID_COMM | ++ KDBUS_ATTACH_PID_COMM | ++ KDBUS_ATTACH_SECLABEL | ++ KDBUS_ATTACH_CMDLINE | ++ KDBUS_ATTACH_CGROUP | ++ KDBUS_ATTACH_AUDIT | ++ KDBUS_ATTACH_CAPS | ++ KDBUS_ATTACH_EXE); ++} ++ + /** +- * kdbus_meta_calc_attach_flags() - calculate attach flags for a sender +- * and a receiver +- * @sender: Sending connection +- * @receiver: Receiving connection ++ * kdbus_meta_get_mask() - calculate attach flags mask for metadata request ++ * @prv_pid: pid of metadata provider ++ * @prv_mask: mask of metadata the provide grants unchecked ++ * @req_pid: pid of metadata requestor ++ * @req_cred: credentials of metadata requestor ++ * @req_mask: mask of metadata that is requested + * +- * Return: the attach flags both the sender and the receiver have opted-in +- * for. ++ * This calculates the metadata items that the requestor @req_pid can access ++ * from the metadata provider @prv_pid. This permission check consists of ++ * several different parts: ++ * - Providers can grant metadata items unchecked. Regardless of their type, ++ * they're always granted to the requestor. This mask is passed as @prv_mask. ++ * - Basic items (credentials and connection metadata) are granted implicitly ++ * to everyone. They're publicly available to any bus-user that can see the ++ * provider. ++ * - Process credentials that are not granted implicitly follow the same ++ * permission checks as /proc. This means, we always assume a requestor ++ * process has access to their *own* /proc mount, if they have access to ++ * kdbusfs. ++ * ++ * Return: Mask of metadata that is granted. ++ */ ++static u64 kdbus_meta_get_mask(struct pid *prv_pid, u64 prv_mask, ++ struct pid *req_pid, ++ const struct cred *req_cred, u64 req_mask) ++{ ++ u64 missing, impl_mask, proc_mask = 0; ++ ++ /* ++ * Connection metadata and basic unix process credentials are ++ * transmitted implicitly, and cannot be suppressed. Both are required ++ * to perform user-space policies on the receiver-side. Furthermore, ++ * connection metadata is public state, anyway, and unix credentials ++ * are needed for UDS-compatibility. We extend them slightly by ++ * auxiliary groups and additional uids/gids/pids. ++ */ ++ impl_mask = /* connection metadata */ ++ KDBUS_ATTACH_CONN_DESCRIPTION | ++ KDBUS_ATTACH_TIMESTAMP | ++ KDBUS_ATTACH_NAMES | ++ /* credentials and pids */ ++ KDBUS_ATTACH_AUXGROUPS | ++ KDBUS_ATTACH_CREDS | ++ KDBUS_ATTACH_PIDS; ++ ++ /* ++ * Calculate the set of metadata that is not granted implicitly nor by ++ * the sender, but still requested by the receiver. If any are left, ++ * perform rather expensive /proc access checks for them. ++ */ ++ missing = req_mask & ~((prv_mask | impl_mask) & req_mask); ++ if (missing) ++ proc_mask = kdbus_meta_proc_mask(prv_pid, req_pid, req_cred, ++ missing); ++ ++ return (prv_mask | impl_mask | proc_mask) & req_mask; ++} ++ ++/** ++ */ ++u64 kdbus_meta_info_mask(const struct kdbus_conn *conn, u64 mask) ++{ ++ return kdbus_meta_get_mask(conn->pid, ++ atomic64_read(&conn->attach_flags_send), ++ task_pid(current), ++ current_cred(), ++ mask); ++} ++ ++/** + */ +-u64 kdbus_meta_calc_attach_flags(const struct kdbus_conn *sender, +- const struct kdbus_conn *receiver) ++u64 kdbus_meta_msg_mask(const struct kdbus_conn *snd, ++ const struct kdbus_conn *rcv) + { +- return atomic64_read(&sender->attach_flags_send) & +- atomic64_read(&receiver->attach_flags_recv); ++ return kdbus_meta_get_mask(task_pid(current), ++ atomic64_read(&snd->attach_flags_send), ++ rcv->pid, ++ rcv->cred, ++ atomic64_read(&rcv->attach_flags_recv)); + } +diff --git a/ipc/kdbus/metadata.h b/ipc/kdbus/metadata.h +index 8fb2a9f7f82e..dba7cc7fdbcb 100644 +--- a/ipc/kdbus/metadata.h ++++ b/ipc/kdbus/metadata.h +@@ -79,7 +79,8 @@ int kdbus_meta_emit(struct kdbus_meta_proc *mp, + u64 mask, + struct kdbus_item **out_items, + size_t *out_size); +-u64 kdbus_meta_calc_attach_flags(const struct kdbus_conn *sender, +- const struct kdbus_conn *receiver); ++u64 kdbus_meta_info_mask(const struct kdbus_conn *conn, u64 mask); ++u64 kdbus_meta_msg_mask(const struct kdbus_conn *snd, ++ const struct kdbus_conn *rcv); + + #endif +-- +2.4.3 + + +From 087d17ac489a3c8f7c35bb5faf4c1bc858fc0978 Mon Sep 17 00:00:00 2001 +From: David Herrmann <dh.herrmann@gmail.com> +Date: Mon, 6 Jul 2015 16:52:44 +0200 +Subject: [PATCH 31/34] kdbus: drop redundant ns pointers + +We already pin 'cred' and 'pid', so they provide the same information as +we store in 'user_ns' and 'pid_ns'. Drop the redundant information to +reduce memory consumption of kdbus_conn. + +Signed-off-by: David Herrmann <dh.herrmann@gmail.com> +--- + ipc/kdbus/connection.c | 4 ---- + ipc/kdbus/connection.h | 4 ---- + ipc/kdbus/metadata.c | 4 ++-- + 3 files changed, 2 insertions(+), 10 deletions(-) + +diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c +index 461b8d66b2b9..d94b417e0f32 100644 +--- a/ipc/kdbus/connection.c ++++ b/ipc/kdbus/connection.c +@@ -130,8 +130,6 @@ static struct kdbus_conn *kdbus_conn_new(struct kdbus_ep *ep, bool privileged, + atomic_set(&conn->lost_count, 0); + INIT_DELAYED_WORK(&conn->work, kdbus_reply_list_scan_work); + conn->cred = get_current_cred(); +- conn->user_ns = get_user_ns(current_user_ns()); +- conn->pid_ns = get_pid_ns(task_active_pid_ns(current)); + conn->pid = get_pid(task_pid(current)); + get_fs_root(current->fs, &conn->root_path); + init_waitqueue_head(&conn->wait); +@@ -284,8 +282,6 @@ static void __kdbus_conn_free(struct kref *kref) + kdbus_ep_unref(conn->ep); + path_put(&conn->root_path); + put_pid(conn->pid); +- put_pid_ns(conn->pid_ns); +- put_user_ns(conn->user_ns); + put_cred(conn->cred); + kfree(conn->description); + kfree(conn->quota); +diff --git a/ipc/kdbus/connection.h b/ipc/kdbus/connection.h +index 9a1b13d69085..5ee864eb0e41 100644 +--- a/ipc/kdbus/connection.h ++++ b/ipc/kdbus/connection.h +@@ -59,8 +59,6 @@ struct kdbus_staging; + * @pool: The user's buffer to receive messages + * @user: Owner of the connection + * @cred: The credentials of the connection at creation time +- * @user_ns: User namespace at creation time +- * @pid_ns: Pid namespace at creation time + * @pid: Pid at creation time + * @root_path: Root path at creation time + * @name_count: Number of owned well-known names +@@ -101,8 +99,6 @@ struct kdbus_conn { + struct kdbus_pool *pool; + struct kdbus_user *user; + const struct cred *cred; +- struct user_namespace *user_ns; +- struct pid_namespace *pid_ns; + struct pid *pid; + struct path root_path; + atomic_t name_count; +diff --git a/ipc/kdbus/metadata.c b/ipc/kdbus/metadata.c +index 5150932cb257..d4973a90a81e 100644 +--- a/ipc/kdbus/metadata.c ++++ b/ipc/kdbus/metadata.c +@@ -896,8 +896,8 @@ static struct kdbus_item *kdbus_write_full(struct kdbus_item **iter, + static size_t kdbus_meta_write(struct kdbus_meta_staging *staging, void *mem, + size_t size) + { +- struct user_namespace *user_ns = staging->conn->user_ns; +- struct pid_namespace *pid_ns = staging->conn->pid_ns; ++ struct user_namespace *user_ns = staging->conn->cred->user_ns; ++ struct pid_namespace *pid_ns = ns_of_pid(staging->conn->pid); + struct kdbus_item *item = NULL, *items = mem; + u8 *end, *owned_names_end = NULL; + +-- +2.4.3 + + +From c61382ef278eb8569c87e4be3077f3f9f1f2fc49 Mon Sep 17 00:00:00 2001 +From: David Herrmann <dh.herrmann@gmail.com> +Date: Mon, 6 Jul 2015 16:54:36 +0200 +Subject: [PATCH 32/34] kdbus: allow match rules on msg->dst_id + +This patch extends kdbus MATCH rules to allow matching on the destination +of a message. We add a KDBUS_ITEM_DST_ID type which takes a u64 and +matches on msg->dst_id. + +This is required for dbus1 compatibility, as dbus1 does not apply MATCH +rules to unicast signals. Therefore, this field allows to match on +unicasts directed to the owning connection. + +Signed-off-by: David Herrmann <dh.herrmann@gmail.com> +--- + include/uapi/linux/kdbus.h | 1 + + ipc/kdbus/item.c | 1 + + ipc/kdbus/match.c | 18 +++++++++++++++--- + 3 files changed, 17 insertions(+), 3 deletions(-) + +diff --git a/include/uapi/linux/kdbus.h b/include/uapi/linux/kdbus.h +index 00a6e142c977..ecffc6b13c3e 100644 +--- a/include/uapi/linux/kdbus.h ++++ b/include/uapi/linux/kdbus.h +@@ -374,6 +374,7 @@ enum kdbus_item_type { + KDBUS_ITEM_ATTACH_FLAGS_RECV, + KDBUS_ITEM_ID, + KDBUS_ITEM_NAME, ++ KDBUS_ITEM_DST_ID, + + /* keep these item types in sync with KDBUS_ATTACH_* flags */ + _KDBUS_ITEM_ATTACH_BASE = 0x1000, +diff --git a/ipc/kdbus/item.c b/ipc/kdbus/item.c +index e763083cc16c..ce78dba03426 100644 +--- a/ipc/kdbus/item.c ++++ b/ipc/kdbus/item.c +@@ -147,6 +147,7 @@ int kdbus_item_validate(const struct kdbus_item *item) + case KDBUS_ITEM_ATTACH_FLAGS_SEND: + case KDBUS_ITEM_ATTACH_FLAGS_RECV: + case KDBUS_ITEM_ID: ++ case KDBUS_ITEM_DST_ID: + if (payload_size != sizeof(u64)) + return -EINVAL; + break; +diff --git a/ipc/kdbus/match.c b/ipc/kdbus/match.c +index 3ae224ff9f3f..d1b300769014 100644 +--- a/ipc/kdbus/match.c ++++ b/ipc/kdbus/match.c +@@ -78,6 +78,7 @@ struct kdbus_bloom_mask { + * KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE}, + * KDBUS_ITEM_ID_REMOVE + * @src_id: ID to match against, used with KDBUS_ITEM_ID ++ * @dst_id: Message destination ID, used with KDBUS_ITEM_DST_ID + * @rules_entry: Entry in the entry's rules list + */ + struct kdbus_match_rule { +@@ -90,6 +91,7 @@ struct kdbus_match_rule { + u64 new_id; + }; + u64 src_id; ++ u64 dst_id; + }; + struct list_head rules_entry; + }; +@@ -112,6 +114,7 @@ static void kdbus_match_rule_free(struct kdbus_match_rule *rule) + break; + + case KDBUS_ITEM_ID: ++ case KDBUS_ITEM_DST_ID: + case KDBUS_ITEM_ID_ADD: + case KDBUS_ITEM_ID_REMOVE: + break; +@@ -215,6 +218,9 @@ static bool kdbus_match_rule_conn(const struct kdbus_match_rule *r, + return kdbus_match_bloom(s->bloom_filter, &r->bloom_mask, c); + case KDBUS_ITEM_ID: + return r->src_id == c->id || r->src_id == KDBUS_MATCH_ID_ANY; ++ case KDBUS_ITEM_DST_ID: ++ return r->dst_id == s->msg->dst_id || ++ r->dst_id == KDBUS_MATCH_ID_ANY; + case KDBUS_ITEM_NAME: + return kdbus_conn_has_name(c, r->name); + default: +@@ -328,6 +334,7 @@ static int kdbus_match_db_remove_unlocked(struct kdbus_match_db *mdb, + * KDBUS_ITEM_BLOOM_MASK: A bloom mask + * KDBUS_ITEM_NAME: A connection's source name + * KDBUS_ITEM_ID: A connection ID ++ * KDBUS_ITEM_DST_ID: A connection ID + * KDBUS_ITEM_NAME_ADD: + * KDBUS_ITEM_NAME_REMOVE: + * KDBUS_ITEM_NAME_CHANGE: Well-known name changes, carry +@@ -339,9 +346,9 @@ static int kdbus_match_db_remove_unlocked(struct kdbus_match_db *mdb, + * For kdbus_notify_{id,name}_change structs, only the ID and name fields + * are looked at when adding an entry. The flags are unused. + * +- * Also note that KDBUS_ITEM_BLOOM_MASK, KDBUS_ITEM_NAME and KDBUS_ITEM_ID +- * are used to match messages from userspace, while the others apply to +- * kernel-generated notifications. ++ * Also note that KDBUS_ITEM_BLOOM_MASK, KDBUS_ITEM_NAME, KDBUS_ITEM_ID, ++ * and KDBUS_ITEM_DST_ID are used to match messages from userspace, while the ++ * others apply to kernel-generated notifications. + * + * Return: >=0 on success, negative error code on failure. + */ +@@ -358,6 +365,7 @@ int kdbus_cmd_match_add(struct kdbus_conn *conn, void __user *argp) + { .type = KDBUS_ITEM_BLOOM_MASK, .multiple = true }, + { .type = KDBUS_ITEM_NAME, .multiple = true }, + { .type = KDBUS_ITEM_ID, .multiple = true }, ++ { .type = KDBUS_ITEM_DST_ID, .multiple = true }, + { .type = KDBUS_ITEM_NAME_ADD, .multiple = true }, + { .type = KDBUS_ITEM_NAME_REMOVE, .multiple = true }, + { .type = KDBUS_ITEM_NAME_CHANGE, .multiple = true }, +@@ -440,6 +448,10 @@ int kdbus_cmd_match_add(struct kdbus_conn *conn, void __user *argp) + rule->src_id = item->id; + break; + ++ case KDBUS_ITEM_DST_ID: ++ rule->dst_id = item->id; ++ break; ++ + case KDBUS_ITEM_NAME_ADD: + case KDBUS_ITEM_NAME_REMOVE: + case KDBUS_ITEM_NAME_CHANGE: +-- +2.4.3 + + +From cf23304185c5787d875971cc730e29637d3f4d7e Mon Sep 17 00:00:00 2001 +From: Masanari Iida <standby24x7@gmail.com> +Date: Fri, 10 Jul 2015 21:55:33 +0900 +Subject: [PATCH 33/34] kdbus: Fix typo in ipc/kdbus + +This patch fix spelling typos found in ipc/kdbus + +Signed-off-by: Masanari Iida <standby24x7@gmail.com> +Reviewed-by: David Herrmann <dh.herrmann@gmail.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + ipc/kdbus/endpoint.c | 2 +- + ipc/kdbus/endpoint.h | 4 ++-- + ipc/kdbus/fs.c | 2 +- + ipc/kdbus/match.c | 2 +- + ipc/kdbus/node.c | 4 ++-- + ipc/kdbus/policy.c | 2 +- + ipc/kdbus/pool.c | 2 +- + 7 files changed, 9 insertions(+), 9 deletions(-) + +diff --git a/ipc/kdbus/endpoint.c b/ipc/kdbus/endpoint.c +index 9a95a5ea84d7..977964dbb44a 100644 +--- a/ipc/kdbus/endpoint.c ++++ b/ipc/kdbus/endpoint.c +@@ -78,7 +78,7 @@ static void kdbus_ep_release(struct kdbus_node *node, bool was_active) + * @gid: The gid of the node + * @is_custom: Whether this is a custom endpoint + * +- * This function will create a new enpoint with the given ++ * This function will create a new endpoint with the given + * name and properties for a given bus. + * + * Return: a new kdbus_ep on success, ERR_PTR on failure. +diff --git a/ipc/kdbus/endpoint.h b/ipc/kdbus/endpoint.h +index d31954bfba2c..bc1b94a70f93 100644 +--- a/ipc/kdbus/endpoint.h ++++ b/ipc/kdbus/endpoint.h +@@ -25,7 +25,7 @@ struct kdbus_bus; + struct kdbus_user; + + /** +- * struct kdbus_ep - enpoint to access a bus ++ * struct kdbus_ep - endpoint to access a bus + * @node: The kdbus node + * @lock: Endpoint data lock + * @bus: Bus behind this endpoint +@@ -33,7 +33,7 @@ struct kdbus_user; + * @policy_db: Uploaded policy + * @conn_list: Connections of this endpoint + * +- * An enpoint offers access to a bus; the default endpoint node name is "bus". ++ * An endpoint offers access to a bus; the default endpoint node name is "bus". + * Additional custom endpoints to the same bus can be created and they can + * carry their own policies/filters. + */ +diff --git a/ipc/kdbus/fs.c b/ipc/kdbus/fs.c +index 205a3adaa2ab..09c480924b9e 100644 +--- a/ipc/kdbus/fs.c ++++ b/ipc/kdbus/fs.c +@@ -74,7 +74,7 @@ static int fs_dir_fop_iterate(struct file *file, struct dir_context *ctx) + * closest node to that position and cannot use our node pointer. This + * means iterating the rb-tree to find the closest match and start over + * from there. +- * Note that hash values are not neccessarily unique. Therefore, llseek ++ * Note that hash values are not necessarily unique. Therefore, llseek + * is not guaranteed to seek to the same node that you got when you + * retrieved the position. Seeking to 0, 1, 2 and >=INT_MAX is safe, + * though. We could use the inode-number as position, but this would +diff --git a/ipc/kdbus/match.c b/ipc/kdbus/match.c +index d1b300769014..4ee6a1f2e1bc 100644 +--- a/ipc/kdbus/match.c ++++ b/ipc/kdbus/match.c +@@ -66,7 +66,7 @@ struct kdbus_bloom_mask { + + /** + * struct kdbus_match_rule - a rule appended to a match entry +- * @type: An item type to match agains ++ * @type: An item type to match against + * @bloom_mask: Bloom mask to match a message's filter against, used + * with KDBUS_ITEM_BLOOM_MASK + * @name: Name to match against, used with KDBUS_ITEM_NAME, +diff --git a/ipc/kdbus/node.c b/ipc/kdbus/node.c +index 0d65c65d2bde..89f58bc85433 100644 +--- a/ipc/kdbus/node.c ++++ b/ipc/kdbus/node.c +@@ -120,7 +120,7 @@ + * new active references can be acquired. + * Once all active references are dropped, the node is considered 'drained'. Now + * kdbus_node_deactivate() is called on each child of the node before we +- * continue deactvating our node. That is, once all children are entirely ++ * continue deactivating our node. That is, once all children are entirely + * deactivated, we call ->release_cb() of our node. ->release_cb() can release + * any resources on that node which are bound to the "active" state of a node. + * When done, we unlink the node from its parent rb-tree, mark it as +@@ -637,7 +637,7 @@ void kdbus_node_deactivate(struct kdbus_node *node) + kdbus_fs_flush(pos); + + /* +- * If the node was activated and somone subtracted BIAS ++ * If the node was activated and someone subtracted BIAS + * from it to deactivate it, we, and only us, are + * responsible to release the extra ref-count that was + * taken once in kdbus_node_activate(). +diff --git a/ipc/kdbus/policy.c b/ipc/kdbus/policy.c +index dd7fffaafa84..f2618e15e78d 100644 +--- a/ipc/kdbus/policy.c ++++ b/ipc/kdbus/policy.c +@@ -344,7 +344,7 @@ err: + * In order to allow atomic replacement of rules, the function first removes + * all entries that have been created for the given owner previously. + * +- * Callers to this function must make sur that the owner is a custom ++ * Callers to this function must make sure that the owner is a custom + * endpoint, or if the endpoint is a default endpoint, then it must be + * either a policy holder or an activator. + * +diff --git a/ipc/kdbus/pool.c b/ipc/kdbus/pool.c +index 45dcdea505f4..63ccd55713c7 100644 +--- a/ipc/kdbus/pool.c ++++ b/ipc/kdbus/pool.c +@@ -44,7 +44,7 @@ + * The receiver's buffer, managed as a pool of allocated and free + * slices containing the queued messages. + * +- * Messages sent with KDBUS_CMD_SEND are copied direcly by the ++ * Messages sent with KDBUS_CMD_SEND are copied directly by the + * sending process into the receiver's pool. + * + * Messages received with KDBUS_CMD_RECV just return the offset +-- +2.4.3 + + +From eee8b5b3ceaeca1b1b998552cd6c9f9dea8938e5 Mon Sep 17 00:00:00 2001 +From: David Herrmann <dh.herrmann@gmail.com> +Date: Tue, 14 Jul 2015 20:12:28 +0200 +Subject: [PATCH 34/34] kdbus: properly reset metadata iovecs on multicasts + +If a message is sent to multiple destinations, each destination might +request a different set of metadata. Hence, we cannot rely on each one +requesting at least a single bit. + +Fix the message exporter to properly reset the metadata iovec on each +emit-iteration. Otherwise, we might end up scanning random heap memory if +a following destination does not request metadata. + +Reported-by: Jan Alexander Steffens <jan.steffens@gmail.com> +Signed-off-by: David Herrmann <dh.herrmann@gmail.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + ipc/kdbus/message.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/ipc/kdbus/message.c b/ipc/kdbus/message.c +index 64763ead693c..3520f45875df 100644 +--- a/ipc/kdbus/message.c ++++ b/ipc/kdbus/message.c +@@ -946,6 +946,16 @@ struct kdbus_pool_slice *kdbus_staging_emit(struct kdbus_staging *staging, + ++v; + + msg_size = KDBUS_ALIGN8(msg_size) + meta_size; ++ } else { ++ /* metadata items */ ++ v->iov_len = 0; ++ v->iov_base = (void __user *)zeros; ++ ++v; ++ ++ /* padding after metadata */ ++ v->iov_len = 0; ++ v->iov_base = (void __user *)zeros; ++ ++v; + } + + /* ... payload iovecs are already filled in ... */ +-- +2.4.3 + |