[RFC v1 11/14] bus1: implement message transmission
From: Tom GundersenWhile notifications already work and simply require linking bus1_handle objects into the destination queue, real messages require proper payloads. This implements two core objects: Message objects and factories. The message factory is similar to transaction contexts, and lives completely on the stack. It is used to import the parameters given by user-space in a SEND ioctl. It parses and validates them. With this message factors we can now instantiate many messages, one for each destination of a multicast. Messages need to carry a bunch of data, mainly: - metadata: This just matches what Unix-sockets do (uid, gid, pid, tid, and secctx) - payload: Random memory passed in as iovec-array by user-space - files: Set of file-descriptors, very similar to SCM_RIGHTS - handles: Set of local handles to transfer to the destination Signed-off-by: Tom Gundersen Signed-off-by: David Herrmann --- ipc/bus1/Makefile | 1 + ipc/bus1/message.c | 613 + ipc/bus1/message.h | 171 +++ ipc/bus1/peer.c| 2 + ipc/bus1/peer.h| 2 + ipc/bus1/util.c| 162 ++ ipc/bus1/util.h| 7 + 7 files changed, 958 insertions(+) create mode 100644 ipc/bus1/message.c create mode 100644 ipc/bus1/message.h diff --git a/ipc/bus1/Makefile b/ipc/bus1/Makefile index b87cddb..05434bda 100644 --- a/ipc/bus1/Makefile +++ b/ipc/bus1/Makefile @@ -1,6 +1,7 @@ bus1-y := \ handle.o\ main.o \ + message.o \ peer.o \ tx.o\ user.o \ diff --git a/ipc/bus1/message.c b/ipc/bus1/message.c new file mode 100644 index 000..4c5c905 --- /dev/null +++ b/ipc/bus1/message.c @@ -0,0 +1,613 @@ +/* + * Copyright (C) 2013-2016 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "handle.h" +#include "message.h" +#include "peer.h" +#include "tx.h" +#include "user.h" +#include "util.h" +#include "util/flist.h" +#include "util/pool.h" +#include "util/queue.h" + +static size_t bus1_factory_size(struct bus1_cmd_send *param) +{ + /* make sure @size cannot overflow */ + BUILD_BUG_ON(UIO_MAXIOV > U16_MAX); + BUILD_BUG_ON(BUS1_FD_MAX > U16_MAX); + + /* make sure we do not violate alignment rules */ + BUILD_BUG_ON(__alignof(struct bus1_flist) < __alignof(struct iovec)); + BUILD_BUG_ON(__alignof(struct iovec) < __alignof(struct file *)); + + return sizeof(struct bus1_factory) + + bus1_flist_inline_size(param->n_handles) + + param->n_vecs * sizeof(struct iovec) + + param->n_fds * sizeof(struct file *); +} + +/** + * bus1_factory_new() - create new message factory + * @peer: peer to operate as + * @param: factory parameters + * @stack: optional stack for factory, or NULL + * @n_stack: size of space at @stack + * + * This allocates a new message factory. It imports data from @param and + * prepares the factory for a transaction. From this factory, messages can be + * instantiated. This is used both for unicasts and multicasts. + * + * If @stack is given, this tries to place the factory on the specified stack + * space. The caller must guarantee that the factory does not outlive the stack + * frame. If this is not wanted, pass 0 as @n_stack. + * In either case, if the stack frame is too small, this will allocate the + * factory on the heap. + * + * Return: Pointer to factory, or ERR_PTR on failure. + */ +struct bus1_factory *bus1_factory_new(struct bus1_peer *peer, + struct bus1_cmd_send *param, + void *stack, + size_t n_stack) +{ + const struct iovec __user *ptr_vecs; + const u64 __user *ptr_handles; + const int __user *ptr_fds; + struct bus1_factory *f; + struct bus1_flist *e; + struct file *file; + size_t i, size; + bool is_new; + int r, fd; + u32 sid; + u64 id; + + lockdep_assert_held(>local.lock); + + size = bus1_factory_size(param); + if (unlikely(size > n_stack)) { + f = kmalloc(size, GFP_TEMPORARY); + if (!f) + return ERR_PTR(-ENOMEM); + + f->on_stack = false; +
[RFC v1 11/14] bus1: implement message transmission
From: Tom Gundersen While notifications already work and simply require linking bus1_handle objects into the destination queue, real messages require proper payloads. This implements two core objects: Message objects and factories. The message factory is similar to transaction contexts, and lives completely on the stack. It is used to import the parameters given by user-space in a SEND ioctl. It parses and validates them. With this message factors we can now instantiate many messages, one for each destination of a multicast. Messages need to carry a bunch of data, mainly: - metadata: This just matches what Unix-sockets do (uid, gid, pid, tid, and secctx) - payload: Random memory passed in as iovec-array by user-space - files: Set of file-descriptors, very similar to SCM_RIGHTS - handles: Set of local handles to transfer to the destination Signed-off-by: Tom Gundersen Signed-off-by: David Herrmann --- ipc/bus1/Makefile | 1 + ipc/bus1/message.c | 613 + ipc/bus1/message.h | 171 +++ ipc/bus1/peer.c| 2 + ipc/bus1/peer.h| 2 + ipc/bus1/util.c| 162 ++ ipc/bus1/util.h| 7 + 7 files changed, 958 insertions(+) create mode 100644 ipc/bus1/message.c create mode 100644 ipc/bus1/message.h diff --git a/ipc/bus1/Makefile b/ipc/bus1/Makefile index b87cddb..05434bda 100644 --- a/ipc/bus1/Makefile +++ b/ipc/bus1/Makefile @@ -1,6 +1,7 @@ bus1-y := \ handle.o\ main.o \ + message.o \ peer.o \ tx.o\ user.o \ diff --git a/ipc/bus1/message.c b/ipc/bus1/message.c new file mode 100644 index 000..4c5c905 --- /dev/null +++ b/ipc/bus1/message.c @@ -0,0 +1,613 @@ +/* + * Copyright (C) 2013-2016 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "handle.h" +#include "message.h" +#include "peer.h" +#include "tx.h" +#include "user.h" +#include "util.h" +#include "util/flist.h" +#include "util/pool.h" +#include "util/queue.h" + +static size_t bus1_factory_size(struct bus1_cmd_send *param) +{ + /* make sure @size cannot overflow */ + BUILD_BUG_ON(UIO_MAXIOV > U16_MAX); + BUILD_BUG_ON(BUS1_FD_MAX > U16_MAX); + + /* make sure we do not violate alignment rules */ + BUILD_BUG_ON(__alignof(struct bus1_flist) < __alignof(struct iovec)); + BUILD_BUG_ON(__alignof(struct iovec) < __alignof(struct file *)); + + return sizeof(struct bus1_factory) + + bus1_flist_inline_size(param->n_handles) + + param->n_vecs * sizeof(struct iovec) + + param->n_fds * sizeof(struct file *); +} + +/** + * bus1_factory_new() - create new message factory + * @peer: peer to operate as + * @param: factory parameters + * @stack: optional stack for factory, or NULL + * @n_stack: size of space at @stack + * + * This allocates a new message factory. It imports data from @param and + * prepares the factory for a transaction. From this factory, messages can be + * instantiated. This is used both for unicasts and multicasts. + * + * If @stack is given, this tries to place the factory on the specified stack + * space. The caller must guarantee that the factory does not outlive the stack + * frame. If this is not wanted, pass 0 as @n_stack. + * In either case, if the stack frame is too small, this will allocate the + * factory on the heap. + * + * Return: Pointer to factory, or ERR_PTR on failure. + */ +struct bus1_factory *bus1_factory_new(struct bus1_peer *peer, + struct bus1_cmd_send *param, + void *stack, + size_t n_stack) +{ + const struct iovec __user *ptr_vecs; + const u64 __user *ptr_handles; + const int __user *ptr_fds; + struct bus1_factory *f; + struct bus1_flist *e; + struct file *file; + size_t i, size; + bool is_new; + int r, fd; + u32 sid; + u64 id; + + lockdep_assert_held(>local.lock); + + size = bus1_factory_size(param); + if (unlikely(size > n_stack)) { + f = kmalloc(size, GFP_TEMPORARY); + if (!f) + return ERR_PTR(-ENOMEM); + + f->on_stack = false; + } else { + f = stack; +