summaryrefslogtreecommitdiff
path: root/message.c
diff options
context:
space:
mode:
Diffstat (limited to 'message.c')
-rw-r--r--message.c594
1 files changed, 89 insertions, 505 deletions
diff --git a/message.c b/message.c
index e87362a0b3c..616146bedbe 100644
--- a/message.c
+++ b/message.c
@@ -15,13 +15,12 @@
#include <linux/module.h>
#include <linux/device.h>
#include <linux/idr.h>
-#include <linux/fs.h>
#include <linux/slab.h>
+#include <linux/file.h>
#include <linux/sched.h>
#include <linux/mutex.h>
#include <linux/init.h>
#include <linux/poll.h>
-#include <linux/file.h>
#include <linux/cgroup.h>
#include <linux/cred.h>
#include <linux/capability.h>
@@ -35,61 +34,32 @@
#include "names.h"
#include "match.h"
-#define KDBUS_MSG_HEADER_SIZE offsetof(struct kdbus_msg, items)
#define KDBUS_KMSG_HEADER_SIZE offsetof(struct kdbus_kmsg, msg)
-static void kdbus_msg_dump(const struct kdbus_msg *msg);
-
-static void kdbus_kmsg_free(struct kdbus_kmsg *kmsg)
-{
- size_t size = 0;
-
- if (kmsg->fds_fp) {
- unsigned int i;
-
- for (i = 0; i < kmsg->fds_count; i++)
- fput(kmsg->fds_fp[i]);
- size += kmsg->fds_count * sizeof(struct file *);
- kfree(kmsg->fds_fp);
- }
-
- if (kmsg->fds) {
- size += KDBUS_ITEM_HEADER_SIZE + (kmsg->fds_count * sizeof(int));
- kfree(kmsg->fds);
- }
-
- if (kmsg->meta) {
- size += kmsg->meta_allocated_size;
- kfree(kmsg->meta);
- }
-
- if (kmsg->vecs) {
- size += kmsg->vecs_size;
- kfree(kmsg->vecs);
- }
-
- size += kmsg->msg.size + KDBUS_KMSG_HEADER_SIZE;
- kdbus_conn_sub_size_allocation(kmsg->conn_src, size);
-
- kfree(kmsg);
-}
-
-static void __kdbus_kmsg_free(struct kref *kref)
+static void __maybe_unused kdbus_msg_dump(const struct kdbus_msg *msg)
{
- struct kdbus_kmsg *kmsg = container_of(kref, struct kdbus_kmsg, kref);
+ const struct kdbus_item *item;
- return kdbus_kmsg_free(kmsg);
-}
+ pr_debug("msg size=%llu, flags=0x%llx, dst_id=%llu, src_id=%llu, "
+ "cookie=0x%llx payload_type=0x%llx, timeout=%llu\n",
+ (unsigned long long) msg->size,
+ (unsigned long long) msg->flags,
+ (unsigned long long) msg->dst_id,
+ (unsigned long long) msg->src_id,
+ (unsigned long long) msg->cookie,
+ (unsigned long long) msg->payload_type,
+ (unsigned long long) msg->timeout_ns);
-void kdbus_kmsg_unref(struct kdbus_kmsg *kmsg)
-{
- kref_put(&kmsg->kref, __kdbus_kmsg_free);
+ KDBUS_ITEM_FOREACH(item, msg)
+ pr_debug("`- msg_item size=%llu, type=0x%llx\n",
+ item->size, item->type);
}
-static struct kdbus_kmsg *kdbus_kmsg_ref(struct kdbus_kmsg *kmsg)
+void kdbus_kmsg_free(struct kdbus_kmsg *kmsg)
{
- kref_get(&kmsg->kref);
- return kmsg;
+ if (kmsg->meta)
+ kfree(kmsg->meta);
+ kfree(kmsg);
}
int kdbus_kmsg_new(size_t extra_size, struct kdbus_kmsg **m)
@@ -116,9 +86,8 @@ static int kdbus_msg_scan_items(struct kdbus_conn *conn, struct kdbus_kmsg *kmsg
const struct kdbus_item *item;
unsigned int num_items = 0;
unsigned int num_vecs = 0;
- unsigned int num_fds = 0;
+ unsigned int fds_count = 0;
size_t vecs_size = 0;
- bool needs_vec = false;
bool has_fds = false;
bool has_name = false;
bool has_bloom = false;
@@ -132,9 +101,6 @@ static int kdbus_msg_scan_items(struct kdbus_conn *conn, struct kdbus_kmsg *kmsg
return -E2BIG;
switch (item->type) {
- case KDBUS_MSG_PAYLOAD:
- break;
-
case KDBUS_MSG_PAYLOAD_VEC:
if (item->size != KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_vec))
return -EINVAL;
@@ -142,22 +108,12 @@ static int kdbus_msg_scan_items(struct kdbus_conn *conn, struct kdbus_kmsg *kmsg
if (++num_vecs > KDBUS_MSG_MAX_PAYLOAD_VECS)
return -E2BIG;
- if (item->vec.flags & KDBUS_VEC_ALIGNED) {
- /* enforce page alignment and page granularity */
- if (!KDBUS_IS_ALIGNED_PAGE(item->vec.address) ||
- !KDBUS_IS_ALIGNED_PAGE(item->vec.size))
- return -EFAULT;
-
- /* we always deliver aligned data as PAYLOAD_VEC */
- needs_vec = true;
- }
-
- vecs_size += KDBUS_ALIGN8(item->vec.size);
+ vecs_size += item->vec.size;
if (vecs_size > KDBUS_MSG_MAX_PAYLOAD_SIZE)
return -EMSGSIZE;
break;
- case KDBUS_MSG_UNIX_FDS:
+ case KDBUS_MSG_FDS:
/* do not allow multiple fd arrays */
if (has_fds)
return -EEXIST;
@@ -167,9 +123,12 @@ static int kdbus_msg_scan_items(struct kdbus_conn *conn, struct kdbus_kmsg *kmsg
if (msg->dst_id == KDBUS_DST_ID_BROADCAST)
return -ENOTUNIQ;
- num_fds = (item->size - KDBUS_ITEM_HEADER_SIZE) / sizeof(int);
- if (num_fds > KDBUS_MSG_MAX_FDS)
+ fds_count = (item->size - KDBUS_ITEM_HEADER_SIZE) / sizeof(int);
+ if (fds_count > KDBUS_MSG_MAX_FDS)
return -EMFILE;
+
+ kmsg->fds = item->fds;
+ kmsg->fds_count = fds_count;
break;
case KDBUS_MSG_BLOOM:
@@ -189,6 +148,8 @@ static int kdbus_msg_scan_items(struct kdbus_conn *conn, struct kdbus_kmsg *kmsg
/* do not allow mismatching bloom filter sizes */
if (item->size - KDBUS_ITEM_HEADER_SIZE != conn->ep->bus->bloom_size)
return -EDOM;
+
+ kmsg->bloom = item->data64;
break;
case KDBUS_MSG_DST_NAME:
@@ -203,6 +164,8 @@ static int kdbus_msg_scan_items(struct kdbus_conn *conn, struct kdbus_kmsg *kmsg
if (!kdbus_name_is_valid(item->str))
return -EINVAL;
+
+ kmsg->dst_name = item->str;
break;
default:
@@ -214,7 +177,7 @@ static int kdbus_msg_scan_items(struct kdbus_conn *conn, struct kdbus_kmsg *kmsg
if ((char *)item - ((char *)msg + msg->size) >= 8)
return -EINVAL;
- /* name is needed for broadcast */
+ /* name is needed if no ID is given */
if (msg->dst_id == KDBUS_DST_ID_WELL_KNOWN_NAME && !has_name)
return -EDESTADDRREQ;
@@ -223,128 +186,36 @@ static int kdbus_msg_scan_items(struct kdbus_conn *conn, struct kdbus_kmsg *kmsg
msg->dst_id < KDBUS_DST_ID_BROADCAST && has_name)
return -EBADMSG;
- /* broadcast messages require a bloom filter */
- if (msg->dst_id == KDBUS_DST_ID_BROADCAST && !has_bloom)
- return -EBADMSG;
+ if (msg->dst_id == KDBUS_DST_ID_BROADCAST) {
+ /* broadcast messages require a bloom filter */
+ if (!has_bloom)
+ return -EBADMSG;
+
+ /* timeouts are not allowed for broadcasts */
+ if (msg->timeout_ns)
+ return -ENOTUNIQ;
+ }
/* bloom filters are for undirected messages only */
if (has_name && has_bloom)
return -EBADMSG;
- /* allocate array for file descriptors */
- if (has_fds) {
- size_t size;
- unsigned int i;
- int ret;
-
- size = num_fds * sizeof(struct file *);
- ret = kdbus_conn_add_size_allocation(conn, size);
- if (ret < 0)
- return ret;
-
- kmsg->fds_fp = kzalloc(size, GFP_KERNEL);
- if (!kmsg->fds_fp)
- return -ENOMEM;
-
- size = KDBUS_ITEM_HEADER_SIZE + (num_fds * sizeof(int));
- ret = kdbus_conn_add_size_allocation(conn, size);
- if (ret < 0)
- return ret;
-
- kmsg->fds = kmalloc(size, GFP_KERNEL);
- if (!kmsg->fds)
- return -ENOMEM;
- for (i = 0; i < num_fds; i++)
- kmsg->fds->fds[i] = -1;
- }
-
- /* if we have only very small PAYLOAD_VECs, they get inlined */
- if (num_vecs > 0 && !needs_vec &&
- msg->size + vecs_size < KDBUS_MSG_MAX_INLINE_SIZE) {
- size_t size;
- int ret;
-
- size = (num_vecs * KDBUS_ITEM_HEADER_SIZE) + vecs_size;
- ret = kdbus_conn_add_size_allocation(conn, size);
- if (ret < 0)
- return ret;
-
- kmsg->vecs = kzalloc(size, GFP_KERNEL);
- if (!kmsg->vecs)
- return -ENOMEM;
- kmsg->vecs_size = size;
- }
-
- return 0;
-}
-
-static int kdbus_inline_user_vec(struct kdbus_kmsg *kmsg,
- struct kdbus_item *next,
- const struct kdbus_item *item)
-{
- void __user *user_addr;
-
- user_addr = (void __user *)(uintptr_t)item->vec.address;
- if (copy_from_user(next->data, user_addr, item->vec.size))
- return -EFAULT;
-
- next->type = KDBUS_MSG_PAYLOAD;
- next->size = KDBUS_ITEM_HEADER_SIZE + item->vec.size;
-
+ kmsg->vecs_size = vecs_size;
return 0;
}
-/*
- * Grab and keep references to passed files descriptors, to install
- * them in the receiving process at message delivery.
- */
-static int kdbus_copy_user_fds(struct kdbus_kmsg *kmsg,
- const struct kdbus_item *item)
-{
- unsigned int i;
- unsigned int count;
-
- count = (item->size - KDBUS_ITEM_HEADER_SIZE) / sizeof(int);
- for (i = 0; i < count; i++) {
- struct file *fp;
-
- fp = fget(item->fds[i]);
- if (!fp)
- goto unwind;
-
- kmsg->fds_fp[kmsg->fds_count++] = fp;
- }
-
- return 0;
-
-unwind:
- while (i >= 0) {
- fput(kmsg->fds_fp[i]);
- kmsg->fds_fp[i] = NULL;
- i--;
- }
-
- kmsg->fds_count = 0;
- return -EBADF;
-}
-
-/*
- * Check the validity of a message. The general layout of the received message
- * is not altered before it is delivered.
- */
-int kdbus_kmsg_new_from_user(struct kdbus_conn *conn, void __user *buf,
+int kdbus_kmsg_new_from_user(struct kdbus_conn *conn,
+ struct kdbus_msg __user *msg,
struct kdbus_kmsg **m)
{
struct kdbus_kmsg *kmsg;
- const struct kdbus_item *item;
- struct kdbus_item *vecs_next;
u64 size, alloc_size;
int ret;
- if (!KDBUS_IS_ALIGNED8((unsigned long)buf))
+ if (!KDBUS_IS_ALIGNED8((unsigned long)msg))
return -EFAULT;
- if (kdbus_size_get_user(size, buf, struct kdbus_msg))
+ if (kdbus_size_get_user(size, msg, struct kdbus_msg))
return -EFAULT;
if (size < sizeof(struct kdbus_msg) || size > KDBUS_MSG_MAX_SIZE)
@@ -357,61 +228,20 @@ int kdbus_kmsg_new_from_user(struct kdbus_conn *conn, void __user *buf,
return -ENOMEM;
memset(kmsg, 0, KDBUS_KMSG_HEADER_SIZE);
- ret = kdbus_conn_add_size_allocation(conn, alloc_size);
- if (ret < 0) {
- kfree(kmsg);
- return ret;
- }
-
- if (copy_from_user(&kmsg->msg, buf, size)) {
+ if (copy_from_user(&kmsg->msg, msg, size)) {
ret = -EFAULT;
goto exit_free;
}
- /* check validity and prepare handling of data records */
+ /* check validity and gather some values for processing */
ret = kdbus_msg_scan_items(conn, kmsg);
if (ret < 0)
goto exit_free;
- /* fill in sender ID */
+ /* patch-in the source of this message */
kmsg->msg.src_id = conn->id;
- /* keep a reference to the source connection, for accounting */
- kmsg->conn_src = conn;
-
- /* Iterate over the items, resolve external references to data
- * we need to pass to the receiver; ignore all items used by
- * the sender only. */
- vecs_next = kmsg->vecs;
- KDBUS_ITEM_FOREACH(item, &kmsg->msg) {
- switch (item->type) {
- case KDBUS_MSG_PAYLOAD_VEC:
- if (!kmsg->vecs) {
- ret = -ENOSYS;
- goto exit_free;
- }
-
- /* convert PAYLOAD_VEC to PAYLOAD */
- ret = kdbus_inline_user_vec(kmsg, vecs_next, item);
- if (ret < 0)
- goto exit_free;
- vecs_next = KDBUS_ITEM_NEXT(vecs_next);
- break;
-
- case KDBUS_MSG_UNIX_FDS:
- ret = kdbus_copy_user_fds(kmsg, item);
- if (ret < 0)
- goto exit_free;
- break;
-
- case KDBUS_MSG_BLOOM:
- //FIXME: store in kmsg
- break;
- }
- }
-
kref_init(&kmsg->kref);
-
*m = kmsg;
return 0;
@@ -420,51 +250,15 @@ exit_free:
return ret;
}
-const struct kdbus_item *
-kdbus_msg_get_item(const struct kdbus_msg *msg, u64 type, unsigned int index)
-{
- const struct kdbus_item *item;
-
- KDBUS_ITEM_FOREACH(item, msg)
- if (item->type == type && index-- == 0)
- return item;
-
- return NULL;
-}
-
-static void __maybe_unused kdbus_msg_dump(const struct kdbus_msg *msg)
-{
- const struct kdbus_item *item;
-
- pr_debug("msg size=%llu, flags=0x%llx, dst_id=%llu, src_id=%llu, "
- "cookie=0x%llx payload_type=0x%llx, timeout=%llu\n",
- (unsigned long long) msg->size,
- (unsigned long long) msg->flags,
- (unsigned long long) msg->dst_id,
- (unsigned long long) msg->src_id,
- (unsigned long long) msg->cookie,
- (unsigned long long) msg->payload_type,
- (unsigned long long) msg->timeout_ns);
-
- KDBUS_ITEM_FOREACH(item, msg)
- pr_debug("`- msg_item size=%llu, type=0x%llx\n",
- item->size, item->type);
-}
-
static struct kdbus_item *
kdbus_kmsg_append(struct kdbus_kmsg *kmsg, size_t extra_size)
{
struct kdbus_item *item;
size_t size;
- int ret;
/* get new metadata buffer, pre-allocate at least 512 bytes */
if (!kmsg->meta) {
size = roundup_pow_of_two(256 + KDBUS_ALIGN8(extra_size));
- ret = kdbus_conn_add_size_allocation(kmsg->conn_src, size);
- if (ret < 0)
- return ERR_PTR(ret);
-
kmsg->meta = kzalloc(size, GFP_KERNEL);
if (!kmsg->meta)
return ERR_PTR(-ENOMEM);
@@ -480,11 +274,6 @@ kdbus_kmsg_append(struct kdbus_kmsg *kmsg, size_t extra_size)
size = roundup_pow_of_two(size);
size_diff = size - kmsg->meta_allocated_size;
-
- ret = kdbus_conn_add_size_allocation(kmsg->conn_src, size_diff);
- if (ret < 0)
- return ERR_PTR(ret);
-
pr_debug("%s: grow to size=%zu\n", __func__, size);
meta = kmalloc(size, GFP_KERNEL);
if (!meta)
@@ -589,6 +378,9 @@ static int kdbus_kmsg_append_src_names(struct kdbus_kmsg *kmsg,
pos += strlen(name_entry->name) + 1;
}
+ kmsg->src_names = item->data;
+ kmsg->src_names_len = pos;
+
exit_unlock:
mutex_unlock(&conn->names_lock);
@@ -612,40 +404,6 @@ static int kdbus_kmsg_append_cred(struct kdbus_kmsg *kmsg,
return 0;
}
-static int kdbus_conn_enqueue_kmsg(struct kdbus_conn *conn,
- struct kdbus_kmsg *kmsg)
-{
- struct kdbus_msg_list_entry *entry;
- int ret = 0;
-
- if (!conn->active)
- return -ENOTCONN;
-
- if (kmsg->fds && !(conn->flags & KDBUS_HELLO_ACCEPT_FD))
- return -ECOMM;
-
- entry = kzalloc(sizeof(*entry), GFP_KERNEL);
- if (!entry)
- return -ENOMEM;
-
- entry->kmsg = kdbus_kmsg_ref(kmsg);
- INIT_LIST_HEAD(&entry->entry);
-
- mutex_lock(&conn->msg_lock);
- if (conn->msg_count > KDBUS_CONN_MAX_MSGS) {
- ret = -EXFULL;
- } else {
- list_add_tail(&entry->entry, &conn->msg_list);
- conn->msg_count++;
- }
- mutex_unlock(&conn->msg_lock);
-
- if (ret == 0)
- wake_up_interruptible(&conn->ep->wait);
-
- return ret;
-}
-
/*
* FIXME: dirty and unsafe version of:
* http://git.kernel.org/cgit/linux/kernel/git/tj/cgroup.git/commit/?h=review-task_cgroup_path_from_hierarchy
@@ -686,7 +444,7 @@ int task_cgroup_path_from_hierarchy(struct task_struct *task, int hierarchy_id,
return ret;
}
-static int kdbus_msg_append_for_dst(struct kdbus_kmsg *kmsg,
+static int kdbus_kmsg_append_for_dst(struct kdbus_kmsg *kmsg,
struct kdbus_conn *conn_src,
struct kdbus_conn *conn_dst)
{
@@ -855,6 +613,7 @@ int kdbus_kmsg_send(struct kdbus_ep *ep,
struct kdbus_conn *conn_dst = NULL;
const struct kdbus_msg *msg;
u64 now_ns = 0;
+ u64 deadline_ns = 0;
int ret;
/* augment incoming message */
@@ -873,70 +632,9 @@ int kdbus_kmsg_send(struct kdbus_ep *ep,
}
msg = &kmsg->msg;
-// kdbus_msg_dump(msg);
-
- if (msg->dst_id == KDBUS_DST_ID_WELL_KNOWN_NAME) {
- const struct kdbus_item *name_item;
- const struct kdbus_name_entry *name_entry;
-
- name_item = kdbus_msg_get_item(msg, KDBUS_MSG_DST_NAME, 0);
- if (!name_item)
- return -EDESTADDRREQ;
-
- /* lookup and determine conn_dst ... */
- name_entry = kdbus_name_lookup(ep->bus->name_registry,
- name_item->data);
- if (!name_entry)
- return -ESRCH;
-
- conn_dst = name_entry->conn;
-
- if ((msg->flags & KDBUS_MSG_FLAGS_NO_AUTO_START) &&
- (conn_dst->flags & KDBUS_HELLO_STARTER))
- return -EADDRNOTAVAIL;
-
- } else if (msg->dst_id != KDBUS_DST_ID_BROADCAST) {
- /* direct message */
- conn_dst = kdbus_bus_find_conn_by_id(ep->bus, msg->dst_id);
- if (!conn_dst)
- return -ENXIO;
- }
-
- if (conn_dst) {
- /* direct message */
-
- if (msg->timeout_ns)
- kmsg->deadline_ns = now_ns + msg->timeout_ns;
-
- /* check policy */
- if (ep->policy_db && conn_src) {
- ret = kdbus_policy_db_check_send_access(ep->policy_db,
- conn_src,
- conn_dst,
- kmsg->deadline_ns);
- if (ret < 0)
- return ret;
- }
-
- /* direct message */
- if (conn_src) {
- ret = kdbus_msg_append_for_dst(kmsg, conn_src, conn_dst);
- if (ret < 0)
- return ret;
- }
-
- ret = kdbus_conn_enqueue_kmsg(conn_dst, kmsg);
-
- if (msg->timeout_ns)
- kdbus_conn_schedule_timeout_scan(conn_dst);
- } else {
- /* broadcast */
- /* timeouts are not allowed for broadcasts */
- if (msg->timeout_ns)
- return -ENOTUNIQ;
-
- ret = 0;
+ /* broadcast message */
+ if (msg->dst_id == KDBUS_DST_ID_BROADCAST) {
list_for_each_entry(conn_dst, &ep->connection_list,
connection_entry) {
if (conn_dst->type != KDBUS_CONN_EP)
@@ -954,170 +652,56 @@ int kdbus_kmsg_send(struct kdbus_ep *ep,
kmsg))
continue;
- ret = kdbus_conn_enqueue_kmsg(conn_dst, kmsg);
+ ret = kdbus_conn_queue_insert(conn_dst, kmsg, 0);
if (ret < 0)
break;
}
- }
-
- return ret;
-}
-
-int kdbus_kmsg_recv(struct kdbus_conn *conn, void __user *buf)
-{
- struct kdbus_msg_list_entry *entry;
- const struct kdbus_kmsg *kmsg = NULL;
- const struct kdbus_msg *msg;
- const struct kdbus_item *item;
- const struct kdbus_item *vecs_next;
- u64 size, pos, max_size;
- int ret;
- if (!KDBUS_IS_ALIGNED8((unsigned long)buf))
- return -EFAULT;
-
- if (kdbus_size_get_user(size, buf, struct kdbus_msg))
- return -EFAULT;
-
- mutex_lock(&conn->msg_lock);
- if (conn->msg_count == 0) {
- ret = -EAGAIN;
- goto exit_unlock;
- }
-
- entry = list_first_entry(&conn->msg_list, struct kdbus_msg_list_entry, entry);
- kmsg = entry->kmsg;
- msg = &kmsg->msg;
-
- max_size = msg->size;
-
- if (kmsg->meta)
- max_size += kmsg->meta->size;
-
- if (kmsg->vecs)
- max_size += kmsg->vecs_size;
-
- /* reuturn needed buffer size to the receiver */
- if (size < max_size) {
- kdbus_size_set_user(max_size, buf, struct kdbus_msg);
- ret = -ENOBUFS;
- goto exit_unlock;
- }
-
- /* copy the message header */
- if (copy_to_user(buf, msg, KDBUS_MSG_HEADER_SIZE)) {
- ret = -EFAULT;
- goto exit_unlock;
+ return ret;
}
- pos = KDBUS_MSG_HEADER_SIZE;
-
- /* The order and sequence of PAYLOAD and PAYLOAD_VEC is always
- * preserved, it might have meaning in the sender/receiver contract;
- * one type is freely concerted to the other though, depending
- * on the actual copying strategy */
- vecs_next = kmsg->vecs;
- KDBUS_ITEM_FOREACH(item, msg) {
- switch (item->type) {
- case KDBUS_MSG_PAYLOAD:
- if (copy_to_user(buf + pos, item, item->size)) {
- ret = -EFAULT;
- goto exit_unlock;
- }
-
- pos += KDBUS_ALIGN8(item->size);
- break;
+ /* direct message */
+ if (msg->dst_id == KDBUS_DST_ID_WELL_KNOWN_NAME) {
+ const struct kdbus_name_entry *name_entry;
- case KDBUS_MSG_PAYLOAD_VEC:
- if (!kmsg->vecs) {
- /* copy PAYLOAD_VEC from the sender to the receiver */
- ret = -ENOSYS;
- goto exit_unlock;
- break;
- }
+ name_entry = kdbus_name_lookup(ep->bus->name_registry,
+ kmsg->dst_name);
+ if (!name_entry)
+ return -ESRCH;
+ conn_dst = name_entry->conn;
- /* copy PAYLOAD_VEC we converted to PAYLOAD */
- if (copy_to_user(buf + pos, vecs_next, vecs_next->size)) {
- ret = -EFAULT;
- goto exit_unlock;
- }
+ if ((msg->flags & KDBUS_MSG_FLAGS_NO_AUTO_START) &&
+ (conn_dst->flags & KDBUS_HELLO_STARTER))
+ return -EADDRNOTAVAIL;
- pos += KDBUS_ALIGN8(vecs_next->size);
- vecs_next = KDBUS_ITEM_NEXT(vecs_next);
- break;
- }
+ } else {
+ conn_dst = kdbus_bus_find_conn_by_id(ep->bus, msg->dst_id);
+ if (!conn_dst)
+ return -ENXIO;
}
- /* install file descriptors */
- if (kmsg->fds) {
- unsigned int i;
- size_t size;
-
- for (i = 0; i < kmsg->fds_count; i++) {
- int fd;
-
- fd = get_unused_fd();
- if (fd < 0) {
- ret = fd;
- goto exit_unlock_fds;
- }
-
- fd_install(fd, get_file(kmsg->fds_fp[i]));
- kmsg->fds->fds[i] = fd;
- }
+ if (msg->timeout_ns)
+ deadline_ns = now_ns + msg->timeout_ns;
- size = KDBUS_ITEM_HEADER_SIZE + (sizeof(int) * kmsg->fds_count);
- kmsg->fds->size = size;
- kmsg->fds->type = KDBUS_MSG_UNIX_FDS;
-
- if (copy_to_user(buf + pos, kmsg->fds, size)) {
- ret = -EFAULT;
- goto exit_unlock_fds;
- }
-
- pos += KDBUS_ALIGN8(size);
+ if (ep->policy_db && conn_src) {
+ ret = kdbus_policy_db_check_send_access(ep->policy_db,
+ conn_src,
+ conn_dst,
+ deadline_ns);
+ if (ret < 0)
+ return ret;
}
- /* append metadata records */
- if (kmsg->meta) {
- if (copy_to_user(buf + pos, kmsg->meta, kmsg->meta_size)) {
- ret = -EFAULT;
- goto exit_unlock_fds;
- }
-
- pos += KDBUS_ALIGN8(kmsg->meta_size);
+ if (conn_src) {
+ ret = kdbus_kmsg_append_for_dst(kmsg, conn_src, conn_dst);
+ if (ret < 0)
+ return ret;
}
- /* update the returned data size in the message header */
- ret = kdbus_size_set_user(pos, buf, struct kdbus_msg);
- if (ret)
- goto exit_unlock_fds;
-
- conn->msg_count--;
- list_del(&entry->entry);
- kdbus_kmsg_unref(entry->kmsg);
- kfree(entry);
- mutex_unlock(&conn->msg_lock);
-
- return 0;
+ ret = kdbus_conn_queue_insert(conn_dst, kmsg, deadline_ns);
-exit_unlock_fds:
- /* cleanup installed file descriptors */
- if (kmsg->fds) {
- unsigned int i;
-
- for (i = 0; i < kmsg->fds_count; i++) {
- if (kmsg->fds->fds[i] < 0)
- continue;
-
- fput(kmsg->fds_fp[i]);
- put_unused_fd(kmsg->fds->fds[i]);
- kmsg->fds->fds[i] = -1;
- }
- }
-
-exit_unlock:
- mutex_unlock(&conn->msg_lock);
+ if (msg->timeout_ns)
+ kdbus_conn_timeout_schedule_scan(conn_dst);
return ret;
}