kdbus: test suite changed to common format
[platform/kernel/linux-rpi.git] / tools / testing / selftests / kdbus / kdbus-util.c
index 6677dad..49aa4b7 100644 (file)
@@ -29,7 +29,6 @@
 #include <sys/stat.h>
 #include <sys/time.h>
 #include <linux/unistd.h>
-#include <linux/memfd.h>
 
 #ifndef __NR_memfd_create
   #ifdef __x86_64__
@@ -44,6 +43,7 @@
 #include "kdbus-api.h"
 #include "kdbus-util.h"
 #include "kdbus-enum.h"
+#include "kdbus-test.h"
 
 #ifndef F_ADD_SEALS
 #define F_LINUX_SPECIFIC_BASE  1024
 #define F_SEAL_WRITE    0x0008  /* prevent writes */
 #endif
 
+/* maximum number of well-known names per connection */
+#define KDBUS_CONN_MAX_NAMES                   256
+
 int kdbus_util_verbose = true;
 
-int kdbus_sysfs_get_parameter_mask(const char *path, uint64_t *mask)
+wur int kdbus_sysfs_get_parameter_mask(const char *path, uint64_t *mask)
 {
        int ret;
        FILE *file;
@@ -90,7 +93,7 @@ int kdbus_sysfs_get_parameter_mask(const char *path, uint64_t *mask)
        return 0;
 }
 
-int kdbus_sysfs_set_parameter_mask(const char *path, uint64_t mask)
+wur int kdbus_sysfs_set_parameter_mask(const char *path, uint64_t mask)
 {
        int ret;
        FILE *file;
@@ -113,9 +116,8 @@ int kdbus_sysfs_set_parameter_mask(const char *path, uint64_t mask)
        return ret > 0 ? 0 : ret;
 }
 
-int kdbus_create_bus(int control_fd, const char *name,
-                    uint64_t req_meta, uint64_t owner_meta,
-                    char **path)
+wur int kdbus_create_bus(int control_fd, const char *name,
+                    uint64_t owner_meta, char **path)
 {
        struct {
                struct kdbus_cmd cmd;
@@ -127,12 +129,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 {
@@ -141,7 +143,7 @@ int kdbus_create_bus(int control_fd, const char *name,
                        char str[64];
                } name;
        } bus_make;
-       int ret = 0;
+       int ret;
 
        memset(&bus_make, 0, sizeof(bus_make));
        bus_make.bp.size = sizeof(bus_make.bp);
@@ -152,13 +154,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,21 +165,16 @@ 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;
 
-       if (control_fd != -1) {
-               kdbus_printf(
-                       "Creating bus with name >%s< on control fd %d ...\n",
-                       name, control_fd);
+       kdbus_printf("Creating bus with name >%s< on control fd %d ...\n",
+                    name, control_fd);
 
-               ret = kdbus_cmd_bus_make(control_fd, &bus_make.cmd);
-               if (ret < 0) {
-                       kdbus_printf("--- error when making bus: %d (%m)\n",
-                                    ret);
-                       return ret;
-               }
+       ret = kdbus_cmd_bus_make(control_fd, &bus_make.cmd);
+       if (ret < 0) {
+               kdbus_printf("--- error when making bus: %d (%m)\n", ret);
+               return ret;
        }
 
        if (ret == 0 && path)
@@ -190,7 +183,7 @@ int kdbus_create_bus(int control_fd, const char *name,
        return ret;
 }
 
-struct kdbus_conn *
+wur struct kdbus_conn *
 kdbus_hello(const char *path, uint64_t flags,
            const struct kdbus_item *item, size_t item_size)
 {
@@ -247,28 +240,34 @@ kdbus_hello(const char *path, uint64_t flags,
 
        cmd_free.size = sizeof(cmd_free);
        cmd_free.offset = h.hello.offset;
-       kdbus_cmd_free(fd, &cmd_free);
+       ret = kdbus_cmd_free(fd, &cmd_free);
+       if (ret < 0 && !(flags & KDBUS_HELLO_POLICY_HOLDER && -EOPNOTSUPP == ret)) { /* free not supported for policy holders */
+               print("hello: KDBUS_CMD_FREE err(%d)\n", ret);
+               return NULL;
+       }
 
-       conn = malloc(sizeof(*conn));
+       conn = alloc(sizeof(*conn));
        if (!conn) {
-               kdbus_printf("unable to malloc()!?\n");
+               kdbus_printf("unable to alloc()!?\n");
                return NULL;
        }
 
        conn->buf = mmap(NULL, POOL_SIZE, PROT_READ, MAP_SHARED, fd, 0);
        if (conn->buf == MAP_FAILED) {
                free(conn);
-               close(fd);
+               CLOSE(fd);
                kdbus_printf("--- error mmap (%m)\n");
                return NULL;
        }
 
        conn->fd = fd;
        conn->id = h.hello.id;
+       _Static_assert((typeof(conn->attach_flags_recv))_KDBUS_ATTACH_ALL == _KDBUS_ATTACH_ALL, "kdbus_conn::attach_flags_recv too narrow for _KDBUS_ATTACH_ALL");
+       conn->attach_flags_recv = _KDBUS_ATTACH_ALL;
        return conn;
 }
 
-struct kdbus_conn *
+wur struct kdbus_conn *
 kdbus_hello_registrar(const char *path, const char *name,
                      const struct kdbus_policy_access *access,
                      size_t num_access, uint64_t flags)
@@ -302,7 +301,7 @@ kdbus_hello_registrar(const char *path, const char *name,
        return kdbus_hello(path, flags, items, size);
 }
 
-struct kdbus_conn *kdbus_hello_activator(const char *path, const char *name,
+wur struct kdbus_conn *kdbus_hello_activator(const char *path, const char *name,
                                   const struct kdbus_policy_access *access,
                                   size_t num_access)
 {
@@ -310,7 +309,7 @@ struct kdbus_conn *kdbus_hello_activator(const char *path, const char *name,
                                     KDBUS_HELLO_ACTIVATOR);
 }
 
-bool kdbus_item_in_message(struct kdbus_msg *msg, uint64_t type)
+wur bool kdbus_item_in_message(struct kdbus_msg *msg, uint64_t type)
 {
        const struct kdbus_item *item;
 
@@ -321,7 +320,7 @@ bool kdbus_item_in_message(struct kdbus_msg *msg, uint64_t type)
        return false;
 }
 
-int kdbus_bus_creator_info(struct kdbus_conn *conn,
+wur int kdbus_bus_creator_info(struct kdbus_conn *conn,
                           uint64_t flags,
                           uint64_t *offset)
 {
@@ -343,55 +342,85 @@ int kdbus_bus_creator_info(struct kdbus_conn *conn,
        if (offset)
                *offset = cmd->offset;
        else
-               kdbus_free(conn, cmd->offset);
+               ret = kdbus_free(conn, cmd->offset);
 
-       return 0;
+       return ret;
 }
 
-int kdbus_conn_info(struct kdbus_conn *conn, uint64_t id,
+wur static int kdbus_info_verify(struct kdbus_info *info, unsigned attach_flags);
+
+wur int kdbus_conn_info(struct kdbus_conn *conn, uint64_t id,
                    const char *name, uint64_t flags,
                    uint64_t *offset)
 {
        struct kdbus_cmd_info *cmd;
        size_t size = sizeof(*cmd);
+       size_t full_size;
        struct kdbus_info *info;
        int ret;
 
+       /*print("call prepared 0\n");*/
+
        if (name)
                size += KDBUS_ITEM_HEADER_SIZE + strlen(name) + 1;
 
-       cmd = alloca(size);
-       memset(cmd, 0, size);
+       /*print("call prepared 1\n");*/
+
+       full_size = KDBUS_ALIGN8(size) + 1000;
+
+       /*print("call prepared 2\n");*/
+
+       cmd = malloc(full_size);
+       if (!cmd)
+               return -ENOMEM;
+       /*print("call prepared 3\n");*/
+       memset(cmd, 0, full_size);
+       /*print("call prepared 4\n");*/
        cmd->size = size;
+       /*print("call prepared 5\n");*/
        cmd->attach_flags = flags;
+       /*print("call prepared 6\n");*/
 
        if (name) {
+               /*print("call prepared 7\n");*/
                cmd->items[0].size = KDBUS_ITEM_HEADER_SIZE + strlen(name) + 1;
+               /*print("call prepared 8\n");*/
                cmd->items[0].type = KDBUS_ITEM_NAME;
-               strcpy(cmd->items[0].str, name);
+               /*print("call prepared 9 cmd(%p) cmd->items[0].str(%p) full_size(%u) len(%u) name(%s)\n", cmd, cmd->items[0].str, (unsigned)full_size, (unsigned)strlen(name), name);*/
+
+               /* tizen 3.0 strcpy reports buffer overflow for no apparent reason - memcpy doesn't */
+               memcpy(cmd->items[0].str, name, strlen(name));
+               /*strcpy(cmd->items[0].str, name);*/
        } else {
+               /*print("call prepared 10\n");*/
                cmd->id = id;
        }
 
+       /*print("call prepared 11\n");*/
+
        ret = kdbus_cmd_conn_info(conn->fd, cmd);
        if (ret < 0) {
                kdbus_printf("--- error when requesting info: %d (%m)\n", ret);
+               free(cmd);
                return ret;
        }
 
        info = (struct kdbus_info *) (conn->buf + cmd->offset);
-       if (info->size != cmd->info_size) {
+       if (KDBUS_ALIGN8(info->size) != cmd->info_size) {
                kdbus_printf("%s(): size mismatch: %d != %d\n", __func__,
                                (int) info->size, (int) cmd->info_size);
+               free(cmd);
                return -EIO;
        }
 
-       if (offset)
+       if (offset) {
                *offset = cmd->offset;
-       else
-               kdbus_free(conn, cmd->offset);
+               ASSERT_ZERO(kdbus_info_verify(info, flags));
+       } else
+               ret = kdbus_free(conn, cmd->offset);
 
-       return 0;
+       free(cmd);
+       return ret;
 }
 
 void kdbus_conn_free(struct kdbus_conn *conn)
@@ -399,41 +428,39 @@ void kdbus_conn_free(struct kdbus_conn *conn)
        if (!conn)
                return;
 
-       if (conn->buf)
-               munmap(conn->buf, POOL_SIZE);
+       if (conn->buf && munmap(conn->buf, POOL_SIZE))
+               fail("munmap(%p) err(%d)", conn->buf, errno);
 
-       if (conn->fd >= 0)
-               close(conn->fd);
+       if (conn->fd >= 0 && close(conn->fd))
+               fail("close(%d) err(%d)", conn->fd, errno);
 
        free(conn);
 }
 
-int sys_memfd_create(const char *name, __u64 size)
+wur int sys_memfd_create(const char *name, __u64 size)
 {
        int ret, fd;
 
-       ret = syscall(__NR_memfd_create, name, MFD_ALLOW_SEALING);
-       if (ret < 0)
-               return ret;
-
-       fd = ret;
+       fd = syscall(__NR_memfd_create, name, 2/*MFD_ALLOW_SEALING*/);
+       if (fd < 0)
+               return fd;
 
        ret = ftruncate(fd, size);
        if (ret < 0) {
-               close(fd);
+               CLOSE(fd);
                return ret;
        }
 
        return fd;
 }
 
-int sys_memfd_seal_set(int fd)
+wur int sys_memfd_seal_set(int fd)
 {
        return fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK |
                         F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL);
 }
 
-off_t sys_memfd_get_size(int fd, off_t *size)
+wur off_t sys_memfd_get_size(int fd, off_t *size)
 {
        struct stat stat;
        int ret;
@@ -448,7 +475,7 @@ off_t sys_memfd_get_size(int fd, off_t *size)
        return 0;
 }
 
-static int __kdbus_msg_send(const struct kdbus_conn *conn,
+static wur int __kdbus_msg_send(const struct kdbus_conn *conn,
                            const char *name,
                            uint64_t cookie,
                            uint64_t flags,
@@ -456,12 +483,10 @@ static int __kdbus_msg_send(const struct kdbus_conn *conn,
                            int64_t priority,
                            uint64_t dst_id,
                            uint64_t cmd_flags,
-                           int cancel_fd,
-                           int fds_count,
-                           int fds[])
+                           int cancel_fd)
 {
-       struct kdbus_cmd_send *cmd;
-       struct kdbus_msg *msg;
+       struct kdbus_cmd_send *cmd = NULL;
+       struct kdbus_msg *msg = NULL;
        const char ref1[1024 * 128 + 3] = "0123456789_0";
        const char ref2[] = "0123456789_1";
        struct kdbus_item *item;
@@ -470,11 +495,7 @@ static int __kdbus_msg_send(const struct kdbus_conn *conn,
        int memfd = -1;
        int ret;
 
-       size = sizeof(*msg);
-       size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec));
-       size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec));
-       size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec));
-       size += fds_count > 0 ? KDBUS_ITEM_SIZE(sizeof(int) * fds_count) : 0;
+       size = sizeof(*msg) + 3 * KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec));
 
        if (dst_id == KDBUS_DST_ID_BROADCAST)
                size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_bloom_filter)) + 64;
@@ -488,14 +509,14 @@ static int __kdbus_msg_send(const struct kdbus_conn *conn,
                if (write(memfd, "kdbus memfd 1234567", 19) != 19) {
                        ret = -errno;
                        kdbus_printf("writing to memfd failed: %m\n");
-                       return ret;
+                       goto out;
                }
 
                ret = sys_memfd_seal_set(memfd);
                if (ret < 0) {
                        ret = -errno;
                        kdbus_printf("memfd sealing failed: %m\n");
-                       return ret;
+                       goto out;
                }
 
                size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_memfd));
@@ -504,11 +525,11 @@ static int __kdbus_msg_send(const struct kdbus_conn *conn,
        if (name)
                size += KDBUS_ITEM_SIZE(strlen(name) + 1);
 
-       msg = malloc(size);
+       msg = alloc(size);
        if (!msg) {
                ret = -errno;
-               kdbus_printf("unable to malloc()!?\n");
-               return ret;
+               kdbus_printf("unable to alloc()!?\n");
+               goto out;
        }
 
        if (dst_id == KDBUS_DST_ID_BROADCAST)
@@ -526,7 +547,7 @@ static int __kdbus_msg_send(const struct kdbus_conn *conn,
        if (timeout) {
                ret = clock_gettime(CLOCK_MONOTONIC_COARSE, &now);
                if (ret < 0)
-                       return ret;
+                       goto out;
 
                msg->timeout_ns = now.tv_sec * 1000000000ULL +
                                  now.tv_nsec + timeout;
@@ -572,23 +593,17 @@ static int __kdbus_msg_send(const struct kdbus_conn *conn,
        }
        item = KDBUS_ITEM_NEXT(item);
 
-       if (fds_count > 0) {
-               item->type = KDBUS_ITEM_FDS;
-               item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(int) * fds_count;
-               memcpy(&item->fds, fds, sizeof(int) * fds_count);
-               item = KDBUS_ITEM_NEXT(item);
-       }
-
        size = sizeof(*cmd);
        if (cancel_fd != -1)
                size += KDBUS_ITEM_SIZE(sizeof(cancel_fd));
 
-       cmd = malloc(size);
+       cmd = alloc(size);
        if (!cmd) {
                ret = -errno;
-               kdbus_printf("unable to malloc(%ld)!?\n", (long)size);
-               return ret;
+               kdbus_printf("unable to alloc()!?\n");
+               goto out;
        }
+
        cmd->size = size;
        cmd->flags = cmd_flags;
        cmd->msg_address = (uintptr_t)msg;
@@ -602,54 +617,54 @@ static int __kdbus_msg_send(const struct kdbus_conn *conn,
                item = KDBUS_ITEM_NEXT(item);
        }
 
-
        ret = kdbus_cmd_send(conn->fd, cmd);
-       if (memfd >= 0)
-               close(memfd);
-
        if (ret < 0) {
                kdbus_printf("error sending message: %d (%m)\n", ret);
-               return ret;
+               goto out;
        }
 
        if (cmd_flags & KDBUS_SEND_SYNC_REPLY) {
                struct kdbus_msg *reply;
+               int dumpret;
 
                kdbus_printf("SYNC REPLY @offset %llu:\n", cmd->reply.offset);
                reply = (struct kdbus_msg *)(conn->buf + cmd->reply.offset);
-               kdbus_msg_dump(conn, reply);
+               dumpret = kdbus_msg_dump(reply);
 
                kdbus_msg_free(reply);
 
                ret = kdbus_free(conn, cmd->reply.offset);
-               if (ret < 0)
-                       return ret;
+               if (!ret)
+                       ret = dumpret;
        }
 
+out:
        free(msg);
        free(cmd);
 
-       return 0;
+       if (memfd >= 0)
+               CLOSE(memfd);
+
+       return ret < 0 ? ret : 0;
 }
 
-int kdbus_msg_send(const struct kdbus_conn *conn, const char *name,
+wur int kdbus_msg_send(const struct kdbus_conn *conn, const char *name,
                   uint64_t cookie, uint64_t flags, uint64_t timeout,
-                  int64_t priority, uint64_t dst_id, int fds_count, int fds[])
+                  int64_t priority, uint64_t dst_id)
 {
        return __kdbus_msg_send(conn, name, cookie, flags, timeout, priority,
-                               dst_id, 0, -1, fds_count, fds);
+                               dst_id, 0, -1);
 }
 
-int kdbus_msg_send_sync(const struct kdbus_conn *conn, const char *name,
+wur int kdbus_msg_send_sync(const struct kdbus_conn *conn, const char *name,
                        uint64_t cookie, uint64_t flags, uint64_t timeout,
                        int64_t priority, uint64_t dst_id, int cancel_fd)
 {
        return __kdbus_msg_send(conn, name, cookie, flags, timeout, priority,
-                               dst_id, KDBUS_SEND_SYNC_REPLY, cancel_fd,
-                               0, NULL);
+                               dst_id, KDBUS_SEND_SYNC_REPLY, cancel_fd);
 }
 
-int kdbus_msg_send_reply(const struct kdbus_conn *conn,
+wur int kdbus_msg_send_reply(const struct kdbus_conn *conn,
                         uint64_t reply_cookie,
                         uint64_t dst_id)
 {
@@ -663,9 +678,9 @@ int kdbus_msg_send_reply(const struct kdbus_conn *conn,
        size = sizeof(struct kdbus_msg);
        size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec));
 
-       msg = malloc(size);
+       msg = alloc(size);
        if (!msg) {
-               kdbus_printf("unable to malloc()!?\n");
+               kdbus_printf("unable to alloc()!?\n");
                return -ENOMEM;
        }
 
@@ -696,7 +711,7 @@ int kdbus_msg_send_reply(const struct kdbus_conn *conn,
        return ret;
 }
 
-static char *msg_id(uint64_t id, char *buf)
+static wur char *msg_id(uint64_t id, char *buf)
 {
        if (id == 0)
                return "KERNEL";
@@ -706,8 +721,7 @@ static char *msg_id(uint64_t id, char *buf)
        return buf;
 }
 
-int kdbus_msg_dump(const struct kdbus_conn *conn, const struct kdbus_msg *msg)
-{
+wur int kdbus_msg_dump(const struct kdbus_msg *msg) {
        const struct kdbus_item *item = msg->items;
        char buf_src[32];
        char buf_dst[32];
@@ -720,8 +734,9 @@ int kdbus_msg_dump(const struct kdbus_conn *conn, const struct kdbus_msg *msg)
        else
                cookie_reply = msg->cookie_reply;
 
-       kdbus_printf("MESSAGE: %s (%llu bytes) flags=0x%08llx, %s â†’ %s, "
+       kdbus_printf("MESSAGE(%p): %s (%llu bytes) flags=0x%08llx, %s â†’ %s, "
                     "cookie=%llu, timeout=%llu cookie_reply=%llu priority=%lli\n",
+               msg,
                enum_PAYLOAD(msg->payload_type), (unsigned long long)msg->size,
                (unsigned long long)msg->flags,
                msg_id(msg->src_id, buf_src), msg_id(msg->dst_id, buf_dst),
@@ -732,8 +747,7 @@ int kdbus_msg_dump(const struct kdbus_conn *conn, const struct kdbus_msg *msg)
                if (item->size < KDBUS_ITEM_HEADER_SIZE) {
                        kdbus_printf("  +%s (%llu bytes) invalid data record\n",
                                     enum_MSG(item->type), item->size);
-                       ret = -EINVAL;
-                       break;
+                       return -EINVAL;
                }
 
                switch (item->type) {
@@ -783,10 +797,10 @@ int kdbus_msg_dump(const struct kdbus_conn *conn, const struct kdbus_msg *msg)
                                break;
                        }
 
-                       kdbus_printf("  +%s (%llu bytes) fd=%i size=%llu filesize=%llu '%s'\n",
+                       kdbus_printf("  +%s (%llu bytes) fd=%i size=%llu filesize=%llu '0x%llx'\n",
                               enum_MSG(item->type), item->size, item->memfd.fd,
                               (unsigned long long)item->memfd.size,
-                              (unsigned long long)size, buf);
+                              (unsigned long long)size, (unsigned long long)(size >= 8 ? *(unsigned long long *)buf : size >= 4 ? *(unsigned *)buf : *buf));
                        munmap(buf, item->memfd.size);
                        break;
                }
@@ -966,21 +980,218 @@ void kdbus_msg_free(struct kdbus_msg *msg)
                switch (item->type) {
                /* close all memfds */
                case KDBUS_ITEM_PAYLOAD_MEMFD:
-                       close(item->memfd.fd);
+                       if (-1 != item->memfd.fd)
+                               CLOSE(item->memfd.fd);
                        break;
                case KDBUS_ITEM_FDS:
                        nfds = (item->size - KDBUS_ITEM_HEADER_SIZE) /
                                sizeof(int);
 
                        for (i = 0; i < nfds; i++)
-                               close(item->fds[i]);
+                               if (-1 != item->fds[i])
+                                       CLOSE(item->fds[i]);
 
                        break;
                }
        }
 }
 
-int kdbus_msg_recv(struct kdbus_conn *conn,
+wur static int verify_padding(char const *b, unsigned off)
+{
+       while (off%8) {
+               ASSERT_ZERO((unsigned)b[off]);
+               ++off;
+       }
+       return 0;
+}
+
+wur static int verify_string(unsigned size, char const *s)
+{
+       unsigned len;
+       ASSERT_NONZERO(size);
+       len = strlen(s)+1;
+       ASSERT_RETURN(len,==,size);
+       ASSERT_ZERO(verify_padding(s, len));
+       return 0;
+}
+wur static int verify_string_array(unsigned size, char const *s)
+{
+       unsigned off=0;
+       ASSERT_NONZERO(size);
+       while (size) {
+               unsigned len = strlen(s+off);
+               if (!len)
+                       break;
+               ++len;
+               ASSERT_RETURN(len,<=,size);
+               size -= len;
+               off += len;
+       }
+       ASSERT_ZERO(verify_padding(s, off));
+       return 0;
+}
+
+#define VERIFY_DECL\
+       const struct kdbus_item *item;\
+       unsigned item_count[14];\
+       unsigned i;\
+       memset(item_count, 0, sizeof(item_count));
+#define VERIFY_DECL_INLOOP\
+       unsigned idx;\
+       unsigned size;\
+       ASSERT_RETURN(item->size,>=,2*sizeof(uint64_t));\
+       ASSERT_RETURN((unsigned)item->size,==,item->size);\
+       size = item->size - 2*sizeof(uint64_t);
+#define VERIFY_META_CASES\
+       /* metadata */\
+       case KDBUS_ITEM_CREDS:\
+               ASSERT_RETURN(size,==,sizeof(struct kdbus_creds));\
+               break;\
+       case KDBUS_ITEM_PIDS:\
+               ASSERT_RETURN(size,==,sizeof(struct kdbus_pids));\
+               break;\
+       case KDBUS_ITEM_AUDIT:\
+               ASSERT_RETURN(size,==,sizeof(struct kdbus_audit));\
+               break;\
+       case KDBUS_ITEM_AUXGROUPS:\
+       case KDBUS_ITEM_CAPS:\
+               ASSERT_ZERO(size%sizeof(uint32_t));\
+               break;\
+       case KDBUS_ITEM_OWNED_NAME:\
+               ASSERT_ZERO(verify_string(size-offsetof(typeof(item->name), name), item->name.name));\
+               break;\
+       case KDBUS_ITEM_TID_COMM:\
+       case KDBUS_ITEM_PID_COMM:\
+       case KDBUS_ITEM_EXE:\
+       case KDBUS_ITEM_CGROUP:\
+       case KDBUS_ITEM_SECLABEL:\
+       case KDBUS_ITEM_CONN_DESCRIPTION:\
+               ASSERT_ZERO(verify_string(size, item->str));\
+               break;\
+       case KDBUS_ITEM_CMDLINE:\
+               ASSERT_ZERO(verify_string_array(size, item->str));\
+               break;
+#define VERIFY_META do {\
+       ASSERT_RETURN(item->type,>=,(uint64_t)_KDBUS_ITEM_ATTACH_BASE);\
+       idx = item->type - _KDBUS_ITEM_ATTACH_BASE;\
+       ASSERT_RETURN(idx,<,sizeof(item_count)/sizeof(*item_count));\
+       ASSERT_NONZERO(attach_flags & 1<<idx);\
+       if (KDBUS_ITEM_OWNED_NAME != item->type)\
+               ASSERT_ZERO(item_count[idx]);\
+       else\
+               ASSERT_RETURN(item_count[idx],<,(uint64_t)KDBUS_CONN_MAX_NAMES);\
+       ++item_count[idx];\
+} while (0)
+#define VERIFY_FINAL_ASSERT do {\
+       for (i=0; i<TABSIZE(item_count); ++i) {\
+               if (attach_flags & 1<<i &&\
+                       KDBUS_ITEM_TIMESTAMP-_KDBUS_ITEM_ATTACH_BASE != i && /* nameless connections happen */\
+                       KDBUS_ITEM_OWNED_NAME-_KDBUS_ITEM_ATTACH_BASE != i && /* nameless connections happen */\
+                       KDBUS_ITEM_CONN_DESCRIPTION-_KDBUS_ITEM_ATTACH_BASE != i && /* defining a connection description is optional */\
+                       KDBUS_ITEM_AUDIT-_KDBUS_ITEM_ATTACH_BASE != i) /* missing if CONFIG_AUDITSYSCALL not defined */\
+                       if (!item_count[i]) ASSERT_ZERO(i+1); /*hack to make i visible*/\
+       }\
+} while (0)
+
+wur static int kdbus_info_verify(struct kdbus_info *info, unsigned attach_flags)
+{
+       VERIFY_DECL;
+
+       KDBUS_ITEM_FOREACH(item, info, items) {
+               VERIFY_DECL_INLOOP;
+               switch(item->type) {
+                       VERIFY_META_CASES;
+                       default: ASSERT_ZERO(item->type ?: (uint64_t)-1);
+               }
+               VERIFY_META;
+       }
+
+       VERIFY_FINAL_ASSERT;
+
+       return 0;
+}
+
+wur static int kdbus_msg_verify(struct kdbus_msg *msg, unsigned attach_flags)
+{
+       bool user = false;
+
+       VERIFY_DECL;
+
+       if (msg->payload_type != KDBUS_PAYLOAD_KERNEL) {
+               ASSERT_RETURN(msg->payload_type,==,KDBUS_PAYLOAD_DBUS);
+               user = true;
+       }
+
+       KDBUS_ITEM_FOREACH(item, msg, items) {
+               VERIFY_DECL_INLOOP;
+
+               switch(item->type) {
+                       case KDBUS_ITEM_TIMESTAMP:
+                               ASSERT_RETURN(size,==,sizeof(struct kdbus_timestamp));
+                               break;
+                       VERIFY_META_CASES;
+
+                       /* user items */
+                       case KDBUS_ITEM_PAYLOAD_OFF:
+                               ASSERT_NONZERO(user);
+                               ASSERT_RETURN(size,==,sizeof(struct kdbus_vec));
+                               continue;
+                       case KDBUS_ITEM_PAYLOAD_MEMFD:
+                               ASSERT_NONZERO(user);
+                               ASSERT_RETURN(size,==,sizeof(struct kdbus_memfd));
+                               continue;
+                       case KDBUS_ITEM_FDS:
+                               ASSERT_NONZERO(user);
+                               ASSERT_ZERO(size%sizeof(int));
+                               continue;
+                       case KDBUS_ITEM_DST_NAME:
+                               ASSERT_NONZERO(user);
+                               ASSERT_ZERO(verify_string(size, item->str));
+                               continue;
+
+                       /* kernel items */
+                       case KDBUS_ITEM_NAME_ADD:
+                       case KDBUS_ITEM_NAME_REMOVE:
+                       case KDBUS_ITEM_NAME_CHANGE:
+                               ASSERT_ZERO(user);
+                               ASSERT_RETURN(size,>=,sizeof(struct kdbus_notify_name_change));
+                               ASSERT_ZERO(verify_string(size-sizeof(struct kdbus_notify_name_change), item->name_change.name));
+                               continue;
+                       case KDBUS_ITEM_ID_ADD:
+                       case KDBUS_ITEM_ID_REMOVE:
+                               ASSERT_ZERO(user);
+                               ASSERT_RETURN(size,==,sizeof(struct kdbus_notify_id_change));
+                               continue;
+                       case KDBUS_ITEM_REPLY_TIMEOUT:
+                       case KDBUS_ITEM_REPLY_DEAD:
+                               ASSERT_ZERO(user);
+                               ASSERT_ZERO(size);
+                               continue;
+
+                       case KDBUS_ITEM_BLOOM_FILTER:
+                               kdbus_printf("WARNING! KDBUS_ITEM_BLOOM_FILTER passed from the kernel\n");
+                               continue;
+
+                       default:
+                               ASSERT_ZERO(item->type ?: (uint64_t)-1);
+               }
+               if (KDBUS_ITEM_TIMESTAMP != item->type)
+                       ASSERT_NONZERO(user);
+               VERIFY_META;
+       }
+
+       /* we're requesting all metadata and that's what we mandate */
+       if (user) {
+               VERIFY_FINAL_ASSERT;
+               if (attach_flags & 1 << (KDBUS_ITEM_TIMESTAMP-_KDBUS_ITEM_ATTACH_BASE))
+                       ASSERT_NONZERO(item_count[KDBUS_ITEM_TIMESTAMP-_KDBUS_ITEM_ATTACH_BASE]);
+       } else if (attach_flags & 1 << (KDBUS_ITEM_TIMESTAMP-_KDBUS_ITEM_ATTACH_BASE))
+               ASSERT_NONZERO(item_count[KDBUS_ITEM_TIMESTAMP-_KDBUS_ITEM_ATTACH_BASE]);
+
+       return 0;
+}
+
+wur int kdbus_msg_recv(struct kdbus_conn *conn,
                   struct kdbus_msg **msg_out,
                   uint64_t *offset)
 {
@@ -993,7 +1204,8 @@ int kdbus_msg_recv(struct kdbus_conn *conn,
                return ret;
 
        msg = (struct kdbus_msg *)(conn->buf + recv.msg.offset);
-       ret = kdbus_msg_dump(conn, msg);
+       ret = kdbus_msg_dump(msg);
+       ASSERT_ZERO(kdbus_msg_verify(msg, conn->attach_flags_recv));
        if (ret < 0) {
                kdbus_msg_free(msg);
                return ret;
@@ -1021,7 +1233,7 @@ int kdbus_msg_recv(struct kdbus_conn *conn,
  * We must return -ETIMEDOUT, -ECONNREST, -EAGAIN and other errors.
  * We must return the result of kdbus_msg_recv()
  */
-int kdbus_msg_recv_poll(struct kdbus_conn *conn,
+wur int kdbus_msg_recv_poll(struct kdbus_conn *conn,
                        int timeout_ms,
                        struct kdbus_msg **msg_out,
                        uint64_t *offset)
@@ -1064,7 +1276,7 @@ int kdbus_msg_recv_poll(struct kdbus_conn *conn,
        return ret;
 }
 
-int kdbus_free(const struct kdbus_conn *conn, uint64_t offset)
+wur int kdbus_free(const struct kdbus_conn *conn, uint64_t offset)
 {
        struct kdbus_cmd_free cmd_free = {};
        int ret;
@@ -1082,7 +1294,12 @@ int kdbus_free(const struct kdbus_conn *conn, uint64_t offset)
        return 0;
 }
 
-int kdbus_name_acquire(struct kdbus_conn *conn,
+wur int kdbus_free_msg(struct kdbus_conn const *conn, struct kdbus_msg *msg)
+{
+       return kdbus_free(conn, (uintptr_t)msg - (uintptr_t)conn->buf);
+}
+
+wur int kdbus_name_acquire(struct kdbus_conn *conn,
                       const char *name, uint64_t *flags)
 {
        struct kdbus_cmd *cmd_name;
@@ -1106,7 +1323,7 @@ int kdbus_name_acquire(struct kdbus_conn *conn,
 
        ret = kdbus_cmd_name_acquire(conn->fd, cmd_name);
        if (ret < 0) {
-               kdbus_printf("error aquiring name: %s\n", strerror(-ret));
+               kdbus_printf("error acquiring name: %s\n", strerror(-ret));
                return ret;
        }
 
@@ -1119,7 +1336,7 @@ int kdbus_name_acquire(struct kdbus_conn *conn,
        return 0;
 }
 
-int kdbus_name_release(struct kdbus_conn *conn, const char *name)
+wur int kdbus_name_release(struct kdbus_conn *conn, const char *name)
 {
        struct kdbus_cmd *cmd_name;
        size_t name_len = strlen(name) + 1;
@@ -1150,7 +1367,7 @@ int kdbus_name_release(struct kdbus_conn *conn, const char *name)
        return 0;
 }
 
-int kdbus_list(struct kdbus_conn *conn, uint64_t flags)
+wur int kdbus_list(struct kdbus_conn *conn, uint64_t flags)
 {
        struct kdbus_cmd_list cmd_list = {};
        struct kdbus_info *list, *name;
@@ -1180,11 +1397,12 @@ int kdbus_list(struct kdbus_conn *conn, uint64_t flags)
                        if (item->type == KDBUS_ITEM_OWNED_NAME) {
                                n = item->name.name;
                                flags = item->name.flags;
-                       }
 
-               kdbus_printf("%8llu flags=0x%08llx conn=0x%08llx '%s'\n",
-                            name->id, (unsigned long long) flags,
-                            name->flags, n);
+                               kdbus_printf("%8llu flags=0x%08llx conn=0x%08llx '%s'\n",
+                                            name->id,
+                                            (unsigned long long) flags,
+                                            name->flags, n);
+                       }
        }
        kdbus_printf("\n");
 
@@ -1193,7 +1411,7 @@ int kdbus_list(struct kdbus_conn *conn, uint64_t flags)
        return ret;
 }
 
-int kdbus_conn_update_attach_flags(struct kdbus_conn *conn,
+wur int kdbus_conn_update_attach_flags(struct kdbus_conn *conn,
                                   uint64_t attach_flags_send,
                                   uint64_t attach_flags_recv)
 {
@@ -1205,9 +1423,9 @@ int kdbus_conn_update_attach_flags(struct kdbus_conn *conn,
        size = sizeof(struct kdbus_cmd);
        size += KDBUS_ITEM_SIZE(sizeof(uint64_t)) * 2;
 
-       update = malloc(size);
+       update = alloc(size);
        if (!update) {
-               kdbus_printf("error malloc: %m\n");
+               kdbus_printf("error alloc: %m\n");
                return -ENOMEM;
        }
 
@@ -1231,11 +1449,12 @@ int kdbus_conn_update_attach_flags(struct kdbus_conn *conn,
                kdbus_printf("error conn update: %d (%m)\n", ret);
 
        free(update);
+       conn->attach_flags_recv = attach_flags_recv;
 
        return ret;
 }
 
-int kdbus_conn_update_policy(struct kdbus_conn *conn, const char *name,
+wur int kdbus_conn_update_policy(struct kdbus_conn *conn, const char *name,
                             const struct kdbus_policy_access *access,
                             size_t num_access)
 {
@@ -1248,9 +1467,9 @@ int kdbus_conn_update_policy(struct kdbus_conn *conn, const char *name,
        size += KDBUS_ITEM_SIZE(strlen(name) + 1);
        size += num_access * KDBUS_ITEM_SIZE(sizeof(struct kdbus_policy_access));
 
-       update = malloc(size);
+       update = alloc(size);
        if (!update) {
-               kdbus_printf("error malloc: %m\n");
+               kdbus_printf("error alloc: %m\n");
                return -ENOMEM;
        }
 
@@ -1285,7 +1504,7 @@ int kdbus_conn_update_policy(struct kdbus_conn *conn, const char *name,
        return ret;
 }
 
-int kdbus_add_match_id(struct kdbus_conn *conn, uint64_t cookie,
+wur int kdbus_add_match_id(struct kdbus_conn *conn, uint64_t cookie,
                       uint64_t type, uint64_t id)
 {
        struct {
@@ -1313,7 +1532,7 @@ int kdbus_add_match_id(struct kdbus_conn *conn, uint64_t cookie,
        return ret;
 }
 
-int kdbus_add_match_empty(struct kdbus_conn *conn)
+wur int kdbus_add_match_empty(struct kdbus_conn *conn)
 {
        struct {
                struct kdbus_cmd_match cmd;
@@ -1336,7 +1555,7 @@ int kdbus_add_match_empty(struct kdbus_conn *conn)
        return ret;
 }
 
-static int all_ids_are_mapped(const char *path)
+static wur int all_ids_are_mapped(const char *path)
 {
        int ret;
        FILE *file;
@@ -1374,7 +1593,7 @@ static int all_ids_are_mapped(const char *path)
        return 0;
 }
 
-int all_uids_gids_are_mapped()
+wur int all_uids_gids_are_mapped(void)
 {
        int ret;
 
@@ -1393,7 +1612,7 @@ int all_uids_gids_are_mapped()
        return 1;
 }
 
-int drop_privileges(uid_t uid, gid_t gid)
+wur int drop_privileges(uid_t uid, gid_t gid)
 {
        int ret;
 
@@ -1421,7 +1640,7 @@ int drop_privileges(uid_t uid, gid_t gid)
        return ret;
 }
 
-uint64_t now(clockid_t clock)
+wur uint64_t now(clockid_t clock)
 {
        struct timespec spec;
 
@@ -1429,7 +1648,7 @@ uint64_t now(clockid_t clock)
        return spec.tv_sec * 1000ULL * 1000ULL * 1000ULL + spec.tv_nsec;
 }
 
-char *unique_name(const char *prefix)
+wur char *unique_name(const char *prefix)
 {
        unsigned int i;
        uint64_t u_now;
@@ -1464,8 +1683,7 @@ char *unique_name(const char *prefix)
        return str;
 }
 
-static int do_userns_map_id(pid_t pid,
-                           const char *map_file,
+static wur int do_userns_map_id(const char *map_file,
                            const char *map_id)
 {
        int ret;
@@ -1504,11 +1722,11 @@ static int do_userns_map_id(pid_t pid,
        ret = 0;
 
 out:
-       close(fd);
+       CLOSE(fd);
        return ret;
 }
 
-int userns_map_uid_gid(pid_t pid,
+wur int userns_map_uid_gid(pid_t pid,
                       const char *map_uid,
                       const char *map_gid)
 {
@@ -1518,7 +1736,7 @@ int userns_map_uid_gid(pid_t pid,
        snprintf(file_id, sizeof(file_id), "/proc/%ld/uid_map",
                 (long) pid);
 
-       ret = do_userns_map_id(pid, file_id, map_uid);
+       ret = do_userns_map_id(file_id, map_uid);
        if (ret < 0)
                return ret;
 
@@ -1527,17 +1745,19 @@ int userns_map_uid_gid(pid_t pid,
 
        fd = open(file_id, O_WRONLY);
        if (fd >= 0) {
-               write(fd, "deny\n", 5);
-               close(fd);
+               ret = write(fd, "deny\n", 5);
+               CLOSE(fd);
+               if (ret != 5)
+                       return ret<0 ? ret : -EIO;
        }
 
        snprintf(file_id, sizeof(file_id), "/proc/%ld/gid_map",
                 (long) pid);
 
-       return do_userns_map_id(pid, file_id, map_gid);
+       return do_userns_map_id(file_id, map_gid);
 }
 
-static int do_cap_get_flag(cap_t caps, cap_value_t cap)
+static wur int do_cap_get_flag(cap_t caps, cap_value_t cap)
 {
        int ret;
        cap_flag_value_t flag_set;
@@ -1561,14 +1781,14 @@ static int do_cap_get_flag(cap_t caps, cap_value_t cap)
  *
  *  Terminate args with a negative value.
  */
-int test_is_capable(int cap, ...)
+wur int test_is_capable(int cap, ...)
 {
        int ret;
        va_list ap;
        cap_t caps;
 
        caps = cap_get_proc();
-       if (!cap) {
+       if (!caps) {
                ret = -errno;
                kdbus_printf("error cap_get_proc(): %d (%m)\n", ret);
                return ret;
@@ -1591,22 +1811,22 @@ out:
        return ret;
 }
 
-int config_user_ns_is_enabled(void)
+wur int config_user_ns_is_enabled(void)
 {
        return (access("/proc/self/uid_map", F_OK) == 0);
 }
 
-int config_auditsyscall_is_enabled(void)
+wur int config_auditsyscall_is_enabled(void)
 {
        return (access("/proc/self/loginuid", F_OK) == 0);
 }
 
-int config_cgroups_is_enabled(void)
+wur int config_cgroups_is_enabled(void)
 {
        return (access("/proc/self/cgroup", F_OK) == 0);
 }
 
-int config_security_is_enabled(void)
+wur int config_security_is_enabled(void)
 {
        int fd;
        int ret;
@@ -1630,7 +1850,7 @@ int config_security_is_enabled(void)
        else
                ret = 1;
 
-       close(fd);
+       CLOSE(fd);
 
        return ret;
 }