From a56ea6a790e7768a5af3d186c25a9547642979b2 Mon Sep 17 00:00:00 2001 From: Djalal Harouni Date: Mon, 20 Oct 2014 17:12:12 +0100 Subject: [PATCH] test-fd: add tests for fd and memfd accounting Signed-off-by: Djalal Harouni --- test/test-fd.c | 262 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 213 insertions(+), 49 deletions(-) diff --git a/test/test-fd.c b/test/test-fd.c index 031c6ad..89117db 100644 --- a/test/test-fd.c +++ b/test/test-fd.c @@ -15,60 +15,104 @@ #include "kdbus-util.h" #include "kdbus-enum.h" +#define KDBUS_MSG_MAX_ITEMS 128 +#define KDBUS_MSG_MAX_FDS 253 #define KDBUS_USER_MAX_CONN 256 -static int send_memfd(struct kdbus_conn *conn, uint64_t dst_id) +static int make_msg_payload_dbus(uint64_t src_id, uint64_t dst_id, + uint64_t msg_size, + struct kdbus_msg **msg_dbus) { - struct kdbus_item *item; struct kdbus_msg *msg; - uint64_t size; - time_t now; - int ret, memfd; - now = time(NULL); + msg = malloc(msg_size); + ASSERT_RETURN_VAL(msg, -ENOMEM); - size = sizeof(struct kdbus_msg); - size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_memfd)); + memset(msg, 0, msg_size); + msg->size = msg_size; + msg->src_id = src_id; + msg->dst_id = dst_id; + msg->payload_type = KDBUS_PAYLOAD_DBUS; + + *msg_dbus = msg; + + return 0; +} + +static void make_item_memfds(struct kdbus_item *item, + int *memfds, size_t memfd_size) +{ + size_t i; + + for (i = 0; i < memfd_size; i++) { + item->type = KDBUS_ITEM_PAYLOAD_MEMFD; + item->size = KDBUS_ITEM_HEADER_SIZE + + sizeof(struct kdbus_memfd); + item->memfd.fd = memfds[i]; + item->memfd.size = sizeof(uint64_t); /* const size */ + item = KDBUS_ITEM_NEXT(item); + } +} - memfd = sys_memfd_create("memfd-name", 0); +static void make_item_fds(struct kdbus_item *item, + int *fd_array, size_t fd_size) +{ + size_t i; + item->type = KDBUS_ITEM_FDS; + item->size = KDBUS_ITEM_HEADER_SIZE + (sizeof(int) * fd_size); + + for (i = 0; i < fd_size; i++) + item->fds[i] = fd_array[i]; +} + +static int memfd_write(const char *name, void *buf, size_t bufsize) +{ + ssize_t ret; + int memfd; + + memfd = sys_memfd_create(name, 0); ASSERT_RETURN_VAL(memfd >= 0, memfd); - ret = write(memfd, &now, sizeof(now)); - ASSERT_RETURN_VAL(ret == sizeof(now), -EAGAIN); + ret = write(memfd, buf, bufsize); + ASSERT_RETURN_VAL(ret == (ssize_t)bufsize, -EAGAIN); ret = sys_memfd_seal_set(memfd); ASSERT_RETURN_VAL(ret == 0, -errno); - msg = malloc(size); - ASSERT_RETURN_VAL(msg, -ENOMEM); + return memfd; +} - memset(msg, 0, size); - msg->size = size; - msg->src_id = conn->id; - msg->dst_id = dst_id; - msg->payload_type = KDBUS_PAYLOAD_DBUS; +static int send_memfds(struct kdbus_conn *conn, uint64_t dst_id, + int *memfds_array, size_t memfd_count) +{ + struct kdbus_item *item; + struct kdbus_msg *msg; + uint64_t size; + int ret; + + size = sizeof(struct kdbus_msg); + size += memfd_count * KDBUS_ITEM_SIZE(sizeof(struct kdbus_memfd)); + + ret = make_msg_payload_dbus(conn->id, dst_id, size, &msg); + ASSERT_RETURN_VAL(ret == 0, ret); item = msg->items; - item->type = KDBUS_ITEM_PAYLOAD_MEMFD; - item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_memfd); - item->memfd.size = sizeof(now); - item->memfd.fd = memfd; + make_item_memfds(item, memfds_array, memfd_count); ret = ioctl(conn->fd, KDBUS_CMD_MSG_SEND, msg); - if (ret) { - kdbus_printf("error sending message: %d err %d (%m)\n", - ret, errno); - return -errno; + if (ret < 0) { + ret = -errno; + kdbus_printf("error sending message: %d (%m)\n", ret); + return ret; } - close(memfd); free(msg); - return 0; } -static int send_fd(struct kdbus_conn *conn, uint64_t dst_id, int fd) +static int send_fds(struct kdbus_conn *conn, uint64_t dst_id, + int *fd_array, size_t fd_count) { struct kdbus_item *item; struct kdbus_msg *msg; @@ -76,29 +120,132 @@ static int send_fd(struct kdbus_conn *conn, uint64_t dst_id, int fd) int ret; size = sizeof(struct kdbus_msg); - size += KDBUS_ITEM_SIZE(sizeof(int[2])); + size += KDBUS_ITEM_SIZE(sizeof(int) * fd_count); - msg = alloca(size); + ret = make_msg_payload_dbus(conn->id, dst_id, size, &msg); + ASSERT_RETURN_VAL(ret == 0, ret); - memset(msg, 0, size); - msg->size = size; - msg->src_id = conn->id; - msg->dst_id = dst_id; - msg->payload_type = KDBUS_PAYLOAD_DBUS; + item = msg->items; + + make_item_fds(item, fd_array, fd_count); + + ret = ioctl(conn->fd, KDBUS_CMD_MSG_SEND, msg); + if (ret < 0) { + ret = -errno; + kdbus_printf("error sending message: %d (%m)\n", ret); + return ret; + } + + free(msg); + return ret; +} + +static int send_fds_memfds(struct kdbus_conn *conn, uint64_t dst_id, + int *fds_array, size_t fd_count, + int *memfds_array, size_t memfd_count) +{ + struct kdbus_item *item; + struct kdbus_msg *msg; + uint64_t size; + int ret; + + size = sizeof(struct kdbus_msg); + size += memfd_count * KDBUS_ITEM_SIZE(sizeof(struct kdbus_memfd)); + size += KDBUS_ITEM_SIZE(sizeof(int) * fd_count); + + ret = make_msg_payload_dbus(conn->id, dst_id, size, &msg); + ASSERT_RETURN_VAL(ret == 0, ret); item = msg->items; - item->type = KDBUS_ITEM_FDS; - item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(int); - item->fds[0] = fd; + make_item_fds(item, fds_array, fd_count); + item = KDBUS_ITEM_NEXT(item); + make_item_memfds(item, memfds_array, memfd_count); ret = ioctl(conn->fd, KDBUS_CMD_MSG_SEND, msg); - if (ret) { - kdbus_printf("error sending message: %d err %d (%m)\n", - ret, errno); - return -errno; + if (ret < 0) { + ret = -errno; + kdbus_printf("error sending message: %d (%m)\n", ret); + return ret; + } + + free(msg); + return ret; +} + +static int kdbus_send_multiple_fds(struct kdbus_conn *conn_src, + struct kdbus_conn *conn_dst) +{ + int ret, i; + int fds[KDBUS_MSG_MAX_FDS + 1]; + int memfds[KDBUS_MSG_MAX_ITEMS + 1]; + struct kdbus_msg *msg; + uint64_t dummy_value; + + dummy_value = time(NULL); + + for (i = 0; i < KDBUS_MSG_MAX_FDS + 1; i++) { + fds[i] = open("/dev/null", O_RDWR|O_CLOEXEC); + ASSERT_RETURN_VAL(fds[i] >= 0, -errno); } + /* Send KDBUS_MSG_MAX_FDS with one more fd */ + ret = send_fds(conn_src, conn_dst->id, fds, KDBUS_MSG_MAX_FDS + 1); + ASSERT_RETURN(ret == -EMFILE); + + /* Retry with the correct KDBUS_MSG_MAX_FDS */ + ret = send_fds(conn_src, conn_dst->id, fds, KDBUS_MSG_MAX_FDS); + ASSERT_RETURN(ret == 0); + + ret = kdbus_msg_recv(conn_dst, &msg, NULL); + ASSERT_RETURN(ret == 0); + + kdbus_msg_free(msg); + + for (i = 0; i < KDBUS_MSG_MAX_ITEMS + 1; i++, dummy_value++) { + memfds[i] = memfd_write("memfd-name", + &dummy_value, + sizeof(dummy_value)); + ASSERT_RETURN_VAL(memfds[i] >= 0, memfds[i]); + } + + /* Send KDBUS_MSG_MAX_FDS with one more memfd */ + ret = send_memfds(conn_src, conn_dst->id, + memfds, KDBUS_MSG_MAX_ITEMS + 1); + ASSERT_RETURN(ret == -E2BIG); + + /* Retry with the correct KDBUS_MSG_MAX_ITEMS */ + ret = send_memfds(conn_src, conn_dst->id, + memfds, KDBUS_MSG_MAX_ITEMS); + ASSERT_RETURN(ret == 0); + + ret = kdbus_msg_recv(conn_dst, &msg, NULL); + ASSERT_RETURN(ret == 0); + + kdbus_msg_free(msg); + + + /* Combine multiple 154 fds and 100 memfds */ + ret = send_fds_memfds(conn_src, conn_dst->id, + fds, 154, memfds, 100); + ASSERT_RETURN(ret == -EMFILE); + + ret = send_fds_memfds(conn_src, conn_dst->id, + fds, 153, memfds, 100); + ASSERT_RETURN(ret == 0); + + ret = kdbus_msg_recv(conn_dst, &msg, NULL); + ASSERT_RETURN(ret == 0); + + kdbus_msg_free(msg); + + + for (i = 0; i < KDBUS_MSG_MAX_FDS + 1; i++) + close(fds[i]); + + for (i = 0; i < KDBUS_MSG_MAX_ITEMS + 1; i++) + close(memfds[i]); + return 0; } @@ -109,22 +256,30 @@ int kdbus_test_fd_passing(struct kdbus_test_env *env) const struct kdbus_item *item; struct kdbus_msg *msg; unsigned int i; + time_t now; + int fds_conn[2]; int fds[2]; + int memfd; int ret; + now = time(NULL); + /* create two connections */ conn_src = kdbus_hello(env->buspath, 0, NULL, 0); conn_dst = kdbus_hello(env->buspath, 0, NULL, 0); ASSERT_RETURN(conn_src && conn_dst); + fds_conn[0] = conn_src->fd; + fds_conn[1] = conn_dst->fd; + /* * Try to ass the handle of a connection as message payload. * This must fail. */ - ret = send_fd(conn_src, conn_dst->id, conn_src->fd); + ret = send_fds(conn_src, conn_dst->id, fds_conn, 2); ASSERT_RETURN(ret == -ENOTSUP); - ret = send_fd(conn_src, conn_dst->id, conn_dst->fd); + ret = send_fds(conn_src, conn_dst->id, fds_conn, 2); ASSERT_RETURN(ret == -ENOTSUP); ret = pipe(fds); @@ -134,10 +289,10 @@ int kdbus_test_fd_passing(struct kdbus_test_env *env) ASSERT_RETURN(i == strlen(str)); /* Try to broadcast file descriptors. This must fail. */ - ret = send_fd(conn_src, KDBUS_DST_ID_BROADCAST, fds[0]); + ret = send_fds(conn_src, KDBUS_DST_ID_BROADCAST, fds, 1); ASSERT_RETURN(ret == -ENOTUNIQ); - ret = send_fd(conn_src, conn_dst->id, fds[0]); + ret = send_fds(conn_src, conn_dst->id, fds, 1); ASSERT_RETURN(ret == 0); ret = kdbus_msg_recv(conn_dst, &msg, NULL); @@ -148,7 +303,6 @@ int kdbus_test_fd_passing(struct kdbus_test_env *env) char tmp[14]; int nfds = (item->size - KDBUS_ITEM_HEADER_SIZE) / sizeof(int); - ASSERT_RETURN(nfds == 1); i = read(item->fds[0], tmp, sizeof(tmp)); @@ -159,12 +313,22 @@ int kdbus_test_fd_passing(struct kdbus_test_env *env) } } + kdbus_msg_free(msg); + + memfd = memfd_write("memfd-name", &now, sizeof(now)); + ASSERT_RETURN(memfd >= 0); + /* Try to broadcast memfd. This must fail. */ - ret = send_memfd(conn_src, KDBUS_DST_ID_BROADCAST); + ret = send_memfds(conn_src, KDBUS_DST_ID_BROADCAST, + (int *)&memfd, 1); ASSERT_RETURN(ret == -ENOTUNIQ); + ret = kdbus_send_multiple_fds(conn_src, conn_dst); + ASSERT_RETURN(ret == 0); + close(fds[0]); close(fds[1]); + close(memfd); kdbus_conn_free(conn_src); kdbus_conn_free(conn_dst); -- 2.34.1