Ejemplo n.º 1
0
int kdbus_name_list(struct kdbus_conn *conn, uint64_t flags)
{
	struct kdbus_cmd_name_list cmd_list;
	struct kdbus_name_list *list;
	struct kdbus_cmd_name *name;
	int ret;

	cmd_list.flags = flags;

	ret = ioctl(conn->fd, KDBUS_CMD_NAME_LIST, &cmd_list);
	if (ret < 0) {
		kdbus_printf("error listing names: %d (%m)\n", ret);
		return EXIT_FAILURE;
	}

	kdbus_printf("REGISTRY:\n");
	list = (struct kdbus_name_list *)(conn->buf + cmd_list.offset);
	KDBUS_ITEM_FOREACH(name, list, names)
		kdbus_printf("%8llu flags=0x%08llx conn=0x%08llx '%s'\n",
		       name->owner_id,
		       name->flags, name->conn_flags,
		       name->size > sizeof(struct kdbus_cmd_name) ? name->name : "");
	kdbus_printf("\n");

	ret = kdbus_free(conn, cmd_list.offset);

	return ret;
}
Ejemplo n.º 2
0
int timeout_msg_recv(struct kdbus_conn *conn)
{
	struct kdbus_cmd_recv recv = {};
	struct kdbus_msg *msg;
	int ret;

	ret = ioctl(conn->fd, KDBUS_CMD_MSG_RECV, &recv);
	if (ret < 0) {
		kdbus_printf("error receiving message: %d (%m)\n", ret);
		return -errno;
	}

	msg = (struct kdbus_msg *)(conn->buf + recv.offset);

	ASSERT_RETURN_VAL(msg->payload_type == KDBUS_PAYLOAD_KERNEL, -EINVAL);
	ASSERT_RETURN_VAL(msg->src_id == KDBUS_SRC_ID_KERNEL, -EINVAL);
	ASSERT_RETURN_VAL(msg->dst_id == conn->id, -EINVAL);

	expected &= ~(1ULL << msg->cookie_reply);
	kdbus_printf("Got message timeout for cookie %llu\n",
		     msg->cookie_reply);

	ret = kdbus_free(conn, recv.offset);
	if (ret < 0)
		return ret;

	return 0;
}
Ejemplo n.º 3
0
static int do_userns_map_id(pid_t pid,
			    const char *map_file,
			    const char *map_id)
{
	int ret;
	int fd;

	fd = open(map_file, O_RDWR);
	if (fd < 0) {
		ret = -errno;
		kdbus_printf("error open %s: %d (%m)\n",
			map_file, ret);
		return ret;
	}

	ret = write(fd, map_id, strlen(map_id));
	if (ret < 0) {
		ret = -errno;
		kdbus_printf("error write to %s: %d (%m)\n",
			     map_file, ret);
		goto out;
	}

	ret = 0;

out:
	close(fd);
	return ret;
}
Ejemplo n.º 4
0
int kdbus_name_acquire(struct kdbus_conn *conn,
		       const char *name, uint64_t flags)
{
	struct kdbus_cmd_name *cmd_name;
	int ret;
	uint64_t size = sizeof(*cmd_name) + strlen(name) + 1;

	cmd_name = alloca(size);

	memset(cmd_name, 0, size);
	strcpy(cmd_name->name, name);
	cmd_name->size = size;
	cmd_name->flags = flags;

	ret = ioctl(conn->fd, KDBUS_CMD_NAME_ACQUIRE, cmd_name);
	if (ret < 0) {
		ret = -errno;
		kdbus_printf("error aquiring name: %s\n", strerror(-ret));
		return ret;
	}

	kdbus_printf("%s(): flags after call: 0x%llx\n", __func__,
		     cmd_name->conn_flags);

	return 0;
}
Ejemplo n.º 5
0
int drop_privileges(uid_t uid, gid_t gid)
{
	int ret;

	ret = setgroups(0, NULL);
	if (ret < 0) {
		ret = -errno;
		kdbus_printf("error setgroups: %d (%m)\n", ret);
		return ret;
	}

	ret = setresgid(gid, gid, gid);
	if (ret < 0) {
		ret = -errno;
		kdbus_printf("error setresgid: %d (%m)\n", ret);
		return ret;
	}

	ret = setresuid(uid, uid, uid);
	if (ret < 0) {
		ret = -errno;
		kdbus_printf("error setresuid: %d (%m)\n", ret);
		return ret;
	}

	return ret;
}
Ejemplo n.º 6
0
int kdbus_conn_update_policy(struct kdbus_conn *conn, const char *name,
			     const struct kdbus_policy_access *access,
			     size_t num_access)
{
	struct kdbus_cmd_update *update;
	struct kdbus_item *item;
	size_t i, size;
	int ret;

	size = sizeof(struct kdbus_cmd_update);
	size += KDBUS_ITEM_SIZE(strlen(name) + 1);
	size += num_access * KDBUS_ITEM_SIZE(sizeof(struct kdbus_policy_access));

	update = malloc(size);
	if (!update) {
		ret = -errno;
		kdbus_printf("error malloc: %d (%m)\n", ret);
		return ret;
	}

	memset(update, 0, size);
	update->size = size;

	item = update->items;

	item->type = KDBUS_ITEM_NAME;
	item->size = KDBUS_ITEM_HEADER_SIZE + strlen(name) + 1;
	strcpy(item->str, name);
	item = KDBUS_ITEM_NEXT(item);

	for (i = 0; i < num_access; i++) {
		item->size = KDBUS_ITEM_HEADER_SIZE +
			     sizeof(struct kdbus_policy_access);
		item->type = KDBUS_ITEM_POLICY_ACCESS;

		item->policy_access.type = access[i].type;
		item->policy_access.access = access[i].access;
		item->policy_access.id = access[i].id;

		item = KDBUS_ITEM_NEXT(item);
	}

	ret = ioctl(conn->fd, KDBUS_CMD_CONN_UPDATE, update);
	if (ret < 0) {
		ret = -errno;
		kdbus_printf("error conn update: %d (%m)\n", ret);
	}

	free(update);

	return ret;
}
Ejemplo n.º 7
0
int kdbus_test_sync_reply(struct kdbus_test_env *env)
{
	pthread_t thread;
	int ret;

	conn_a = kdbus_hello(env->buspath, 0, NULL, 0);
	conn_b = kdbus_hello(env->buspath, 0, NULL, 0);
	ASSERT_RETURN(conn_a && conn_b);

	pthread_create(&thread, NULL, run_thread, NULL);

	ret = kdbus_msg_send(conn_b, NULL, cookie,
			     KDBUS_MSG_FLAGS_EXPECT_REPLY |
			     KDBUS_MSG_FLAGS_SYNC_REPLY,
			     5000000000ULL, 0, conn_a->id);

	pthread_join(thread, NULL);
	ASSERT_RETURN(ret == 0);

	kdbus_printf("-- closing bus connections\n");
	kdbus_conn_free(conn_a);
	kdbus_conn_free(conn_b);

	return TEST_OK;
}
Ejemplo n.º 8
0
static void *run_thread_reply(void *data)
{
	int ret;
	unsigned long status = TEST_OK;

	ret = kdbus_msg_recv_poll(conn_a, 3000, NULL, NULL);
	if (ret < 0)
		goto exit_thread;

	kdbus_printf("Thread received message, sending reply ...\n");

	/* using an unknown cookie must fail */
	ret = kdbus_msg_send_reply(conn_a, ~cookie, conn_b->id);
	if (ret != -EPERM) {
		status = TEST_ERR;
		goto exit_thread;
	}

	ret = kdbus_msg_send_reply(conn_a, cookie, conn_b->id);
	if (ret != 0) {
		status = TEST_ERR;
		goto exit_thread;
	}

exit_thread:
	pthread_exit(NULL);
	return (void *) status;
}
Ejemplo n.º 9
0
static int send_fd(struct kdbus_conn *conn, uint64_t dst_id, int fd)
{
	struct kdbus_item *item;
	struct kdbus_msg *msg;
	uint64_t size;
	int ret;

	size = sizeof(struct kdbus_msg);
	size += KDBUS_ITEM_SIZE(sizeof(int[2]));

	msg = alloca(size);

	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;

	item->type = KDBUS_ITEM_FDS;
	item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(int);
	item->fds[0] = fd;
	item = KDBUS_ITEM_NEXT(item);

	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;
	}

	return 0;
}
Ejemplo n.º 10
0
int kdbus_test_timeout(struct kdbus_test_env *env)
{
	struct kdbus_conn *conn_a, *conn_b;
	struct pollfd fd;
	int ret, i, n_msgs = 4;

	conn_a = kdbus_hello(env->buspath, 0, NULL, 0);
	conn_b = kdbus_hello(env->buspath, 0, NULL, 0);
	ASSERT_RETURN(conn_a && conn_b);

	fd.fd = conn_b->fd;

	/*
	 * send messages that expect a reply (within 100 msec),
	 * but never answer it.
	 */
	for (i = 0; i < n_msgs; i++) {
		kdbus_printf("Sending message with cookie %u ...\n", i);
		kdbus_msg_send(conn_b, NULL, i, KDBUS_MSG_FLAGS_EXPECT_REPLY,
			       (i + 1) * 100ULL * 1000000ULL, 0, conn_a->id);
		expected |= 1ULL << i;
	}

	for (;;) {
		fd.events = POLLIN | POLLPRI | POLLHUP;
		fd.revents = 0;

		ret = poll(&fd, 1, (n_msgs + 1) * 100);
		if (ret == 0)
			kdbus_printf("--- timeout\n");
		if (ret <= 0)
			break;

		if (fd.revents & POLLIN)
			timeout_msg_recv(conn_b);

		if (expected == 0)
			break;
	}

	ASSERT_RETURN(expected == 0);

	kdbus_conn_free(conn_a);
	kdbus_conn_free(conn_b);

	return TEST_OK;
}
Ejemplo n.º 11
0
/**
 * Create new threads for receiving from multiple senders,
 * The 'conn_db' will be populated by newly created connections.
 * Caller should free all allocated connections.
 *
 * return 0 on success, negative errno on failure.
 */
static int kdbus_recv_in_threads(const char *bus, const char *name,
				 struct kdbus_conn **conn_db)
{
	int ret;
	unsigned int i, tid;
	unsigned long dst_id;
	unsigned long cookie = 1;
	unsigned int thread_nr = MAX_CONN - 1;
	pthread_t thread_id[MAX_CONN - 1] = {'\0'};

	dst_id = name ? KDBUS_DST_ID_NAME : conn_db[0]->id;

	for (tid = 0, i = 1; tid < thread_nr; tid++, i++) {
		ret = pthread_create(&thread_id[tid], NULL,
				     kdbus_recv_echo, (void *)conn_db[0]);
		if (ret < 0) {
			ret = -errno;
			kdbus_printf("error pthread_create: %d err %d (%m)\n",
				      ret, errno);
			break;
		}

		/* just free before re-using */
		kdbus_conn_free(conn_db[i]);
		conn_db[i] = NULL;

		/* We need to create connections here */
		conn_db[i] = kdbus_hello(bus, 0, NULL, 0);
		if (!conn_db[i]) {
			ret = -errno;
			break;
		}

		ret = kdbus_add_match_empty(conn_db[i]);
		if (ret < 0)
			break;

		ret = kdbus_msg_send(conn_db[i], name, cookie++,
				     0, 0, 0, dst_id);
		if (ret < 0)
			break;
	}

	for (tid = 0; tid < thread_nr; tid++) {
		int thread_ret = 0;

		if (thread_id[tid]) {
			pthread_join(thread_id[tid], (void *)&thread_ret);
			if (thread_ret < 0 && ret == 0)
				ret = thread_ret;
		}
	}

	return ret;
}
Ejemplo n.º 12
0
int kdbus_free(const struct kdbus_conn *conn, uint64_t offset)
{
	int ret;

	ret = ioctl(conn->fd, KDBUS_CMD_FREE, &offset);
	if (ret < 0) {
		kdbus_printf("KDBUS_CMD_FREE failed: %d (%m)\n", ret);
		return -errno;
	}

	return 0;
}
Ejemplo n.º 13
0
off_t sys_memfd_get_size(int fd, off_t *size)
{
	struct stat stat;
	int ret;

	ret = fstat(fd, &stat);
	if (ret < 0) {
		kdbus_printf("stat() failed: %m\n");
		return ret;
	}

	*size = stat.st_size;
	return 0;
}
Ejemplo n.º 14
0
int kdbus_conn_update_attach_flags(struct kdbus_conn *conn, uint64_t flags)
{
	int ret;
	size_t size;
	struct kdbus_cmd_update *update;
	struct kdbus_item *item;

	size = sizeof(struct kdbus_cmd_update);
	size += KDBUS_ITEM_SIZE(sizeof(uint64_t));

	update = malloc(size);
	if (!update) {
		ret = -errno;
		kdbus_printf("error malloc: %d (%m)\n", ret);
		return ret;
	}

	memset(update, 0, size);
	update->size = size;

	item = update->items;

	item->type = KDBUS_ITEM_ATTACH_FLAGS;
	item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(uint64_t);
	item->data64[0] = flags;
	item = KDBUS_ITEM_NEXT(item);

	ret = ioctl(conn->fd, KDBUS_CMD_CONN_UPDATE, update);
	if (ret < 0) {
		ret = -errno;
		kdbus_printf("error conn update: %d (%m)\n", ret);
	}

	free(update);

	return ret;
}
Ejemplo n.º 15
0
int kdbus_name_release(struct kdbus_conn *conn, const char *name)
{
	struct kdbus_cmd_name *cmd_name;
	int ret;
	uint64_t size = sizeof(*cmd_name) + strlen(name) + 1;

	cmd_name = alloca(size);

	memset(cmd_name, 0, size);
	strcpy(cmd_name->name, name);
	cmd_name->size = size;

	kdbus_printf("conn %lld giving up name '%s'\n",
		     (unsigned long long) conn->id, name);

	ret = ioctl(conn->fd, KDBUS_CMD_NAME_RELEASE, cmd_name);
	if (ret < 0) {
		ret = -errno;
		kdbus_printf("error releasing name: %s\n", strerror(-ret));
		return ret;
	}

	return 0;
}
Ejemplo n.º 16
0
int kdbus_create_bus(int control_fd, const char *name, char **path)
{
	struct {
		struct kdbus_cmd_make head;

		/* bloom size item */
		struct {
			uint64_t size;
			uint64_t type;
			struct kdbus_bloom_parameter bloom;
		} bs;

		/* name item */
		uint64_t n_size;
		uint64_t n_type;
		char name[64];
	} bus_make;
	int ret;

	memset(&bus_make, 0, sizeof(bus_make));
	bus_make.bs.size = sizeof(bus_make.bs);
	bus_make.bs.type = KDBUS_ITEM_BLOOM_PARAMETER;
	bus_make.bs.bloom.size = 64;
	bus_make.bs.bloom.n_hash = 1;

	snprintf(bus_make.name, sizeof(bus_make.name), "%u-%s", getuid(), name);

	bus_make.n_type = KDBUS_ITEM_MAKE_NAME;
	bus_make.n_size = KDBUS_ITEM_HEADER_SIZE + strlen(bus_make.name) + 1;

	bus_make.head.flags = KDBUS_MAKE_ACCESS_WORLD;
	bus_make.head.size = sizeof(struct kdbus_cmd_make) +
			     sizeof(bus_make.bs) +
			     bus_make.n_size;

	kdbus_printf("Creating bus with name >%s< on control fd %d ...\n",
		     name, control_fd);

	ret = ioctl(control_fd, KDBUS_CMD_BUS_MAKE, &bus_make);

	if (ret == 0 && path)
		asprintf(path, "/dev/" KBUILD_MODNAME "/%s/bus", bus_make.name);

	return ret;
}
Ejemplo n.º 17
0
int kdbus_test_daemon(struct kdbus_test_env *env)
{
	struct pollfd fds[2];
	int count;
	int ret;

	/* This test doesn't make any sense in non-interactive mode */
	if (!kdbus_util_verbose)
		return TEST_OK;

	printf("Created connection %llu on bus '%s'\n",
		(unsigned long long) env->conn->id, env->buspath);

	kdbus_name_acquire(env->conn, "com.example.kdbus-test", 0);
	kdbus_printf("  Aquired name: com.example.kdbus-test\n");

	fds[0].fd = env->conn->fd;
	fds[1].fd = STDIN_FILENO;

	printf("Monitoring connections:\n");

	for (count = 0;; count++) {
		int i, nfds = sizeof(fds) / sizeof(fds[0]);

		for (i = 0; i < nfds; i++) {
			fds[i].events = POLLIN | POLLPRI | POLLHUP;
			fds[i].revents = 0;
		}

		ret = poll(fds, nfds, -1);
		if (ret <= 0)
			break;

		if (fds[0].revents & POLLIN)
			kdbus_msg_recv(env->conn, NULL);

		/* stdin */
		if (fds[1].revents & POLLIN)
			break;
	}

	printf("Closing bus connection\n");

	return TEST_OK;
}
Ejemplo n.º 18
0
static int create_endpoint(const char *buspath, uid_t uid, const char *name,
			   uint64_t flags)
{
	struct {
		struct kdbus_cmd cmd;

		/* name item */
		struct {
			uint64_t size;
			uint64_t type;
			/* max should be KDBUS_SYSNAME_MAX_LEN */
			char str[128];
		} name;
	} ep_make;
	int fd, ret;

	fd = open(buspath, O_RDWR);
	if (fd < 0)
		return fd;

	memset(&ep_make, 0, sizeof(ep_make));

	snprintf(ep_make.name.str,
		 /* Use the KDBUS_SYSNAME_MAX_LEN or sizeof(str) */
		 KDBUS_SYSNAME_MAX_LEN > strlen(name) ?
		 KDBUS_SYSNAME_MAX_LEN : sizeof(ep_make.name.str),
		 "%u-%s", uid, name);

	ep_make.name.type = KDBUS_ITEM_MAKE_NAME;
	ep_make.name.size = KDBUS_ITEM_HEADER_SIZE +
			    strlen(ep_make.name.str) + 1;

	ep_make.cmd.flags = flags;
	ep_make.cmd.size = sizeof(ep_make.cmd) + ep_make.name.size;

	ret = kdbus_cmd_endpoint_make(fd, &ep_make.cmd);
	if (ret < 0) {
		kdbus_printf("error creating endpoint: %d (%m)\n", ret);
		return ret;
	}

	return fd;
}
Ejemplo n.º 19
0
int kdbus_add_match_empty(struct kdbus_conn *conn)
{
	struct {
		struct kdbus_cmd_match cmd;
		struct kdbus_item item;
	} buf;
	int ret;

	memset(&buf, 0, sizeof(buf));

	buf.item.size = sizeof(uint64_t) * 3;
	buf.item.type = KDBUS_ITEM_ID;
	buf.item.id = KDBUS_MATCH_ID_ANY;

	buf.cmd.size = sizeof(buf.cmd) + buf.item.size;

	ret = ioctl(conn->fd, KDBUS_CMD_MATCH_ADD, &buf);
	if (ret < 0)
		kdbus_printf("--- error adding conn match: %d (%m)\n", ret);

	return ret;
}
Ejemplo n.º 20
0
int kdbus_test_sync_reply(struct kdbus_test_env *env)
{
	unsigned long status;
	pthread_t thread;
	int ret;

	conn_a = kdbus_hello(env->buspath, 0, NULL, 0);
	conn_b = kdbus_hello(env->buspath, 0, NULL, 0);
	ASSERT_RETURN(conn_a && conn_b);

	pthread_create(&thread, NULL, run_thread_reply, NULL);

	ret = kdbus_msg_send_sync(conn_b, NULL, cookie,
				  KDBUS_MSG_EXPECT_REPLY,
				  5000000000ULL, 0, conn_a->id, -1);

	pthread_join(thread, (void *) &status);
	ASSERT_RETURN(status == 0);
	ASSERT_RETURN(ret == 0);

	ret = interrupt_sync(conn_a, conn_b);
	ASSERT_RETURN(ret == 0);

	ret = close_epipe_sync(env->buspath);
	ASSERT_RETURN(ret == 0);

	ret = cancel_fd_sync(conn_a, conn_b);
	ASSERT_RETURN(ret == 0);

	ret = no_cancel_sync(conn_a, conn_b);
	ASSERT_RETURN(ret == 0);

	kdbus_printf("-- closing bus connections\n");

	kdbus_conn_free(conn_a);
	kdbus_conn_free(conn_b);

	return TEST_OK;
}
Ejemplo n.º 21
0
static void *run_thread(void *data)
{
	struct pollfd fd;
	int ret;

	fd.fd = conn_a->fd;
	fd.events = POLLIN | POLLPRI | POLLHUP;
	fd.revents = 0;

	ret = poll(&fd, 1, 3000);
	if (ret <= 0)
		goto thread_exit;

	if (fd.revents & POLLIN) {
		kdbus_printf("Thread received message, sending reply ...\n");
		kdbus_msg_recv(conn_a, NULL, NULL);
		kdbus_msg_send(conn_a, NULL, 0, 0, cookie, 0, conn_b->id);
	}

thread_exit:
	pthread_exit(NULL);
	return NULL;
}
Ejemplo n.º 22
0
/**
 * Create new threads for receiving from multiple senders,
 * The 'conn_db' will be populated by newly created connections.
 * Caller should free all allocated connections.
 *
 * return 0 on success, negative errno on failure.
 */
static int kdbus_recv_in_threads(const char *bus, const char *name,
				 struct kdbus_conn **conn_db)
{
	int ret;
	bool pool_full = false;
	unsigned int sent_packets = 0;
	unsigned int lost_packets = 0;
	unsigned int i, tid;
	unsigned long dst_id;
	unsigned long cookie = 1;
	unsigned int thread_nr = MAX_CONN - 1;
	pthread_t thread_id[MAX_CONN - 1] = {'\0'};

	dst_id = name ? KDBUS_DST_ID_NAME : conn_db[0]->id;

	for (tid = 0, i = 1; tid < thread_nr; tid++, i++) {
		ret = pthread_create(&thread_id[tid], NULL,
				     kdbus_recv_echo, (void *)conn_db[0]);
		if (ret < 0) {
			ret = -errno;
			kdbus_printf("error pthread_create: %d (%m)\n",
				      ret);
			break;
		}

		/* just free before re-using */
		kdbus_conn_free(conn_db[i]);
		conn_db[i] = NULL;

		/* We need to create connections here */
		conn_db[i] = kdbus_hello(bus, 0, NULL, 0);
		if (!conn_db[i]) {
			ret = -errno;
			break;
		}

		ret = kdbus_add_match_empty(conn_db[i]);
		if (ret < 0)
			break;

		ret = kdbus_msg_send(conn_db[i], name, cookie++,
				     0, 0, 0, dst_id);
		if (ret < 0) {
			/*
			 * Receivers are not reading their messages,
			 * not scheduled ?!
			 *
			 * So set the pool full here, perhaps the
			 * connection pool or queue was full, later
			 * recheck receivers errors
			 */
			if (ret == -ENOBUFS || ret == -EXFULL)
				pool_full = true;
			break;
		}

		sent_packets++;
	}

	for (tid = 0; tid < thread_nr; tid++) {
		int thread_ret = 0;

		if (thread_id[tid]) {
			pthread_join(thread_id[tid], (void *)&thread_ret);
			if (thread_ret < 0) {
				/* Update only if send did not fail */
				if (ret == 0)
					ret = thread_ret;

				lost_packets++;
			}
		}
	}

	/*
	 * When sending if we did fail with -ENOBUFS or -EXFULL
	 * then we should have set lost_packet and we should at
	 * least have sent_packets set to KDBUS_CONN_MAX_MSGS_PER_USER
	 */
	if (pool_full) {
		ASSERT_RETURN(lost_packets > 0);

		/*
		 * We should at least send KDBUS_CONN_MAX_MSGS_PER_USER
		 *
		 * For every send operation we create a thread to
		 * recv the packet, so we keep the queue clean
		 */
		ASSERT_RETURN(sent_packets >= KDBUS_CONN_MAX_MSGS_PER_USER);

		/*
		 * Set ret to zero since we only failed due to
		 * the receiving threads that have not been
		 * scheduled
		 */
		ret = 0;
	}

	return ret;
}
Ejemplo n.º 23
0
/* Return EXIT_SUCCESS, EXIT_FAILURE or negative errno */
static int __kdbus_clone_userns_test(const char *bus,
				     const char *name,
				     struct kdbus_conn **conn_db,
				     int expected_status)
{
	int efd;
	pid_t pid;
	int ret = 0;
	unsigned int uid = 65534;
	int status;

	ret = drop_privileges(uid, uid);
	ASSERT_RETURN_VAL(ret == 0, ret);

	/*
	 * Since we just dropped privileges, the dumpable flag was just
	 * cleared which makes the /proc/$clone_child/uid_map to be
	 * owned by root, hence any userns uid mapping will fail with
	 * -EPERM since the mapping will be done by uid 65534.
	 *
	 * To avoid this set the dumpable flag again which makes procfs
	 * update the /proc/$clone_child/ inodes owner to 65534.
	 *
	 * Using this we will be able write to /proc/$clone_child/uid_map
	 * as uid 65534 and map the uid 65534 to 0 inside the user
	 * namespace.
	 */
	ret = prctl(PR_SET_DUMPABLE, SUID_DUMP_USER);
	ASSERT_RETURN_VAL(ret == 0, ret);

	/* sync parent/child */
	efd = eventfd(0, EFD_CLOEXEC);
	ASSERT_RETURN_VAL(efd >= 0, efd);

	pid = syscall(__NR_clone, SIGCHLD|CLONE_NEWUSER, NULL);
	if (pid < 0) {
		ret = -errno;
		kdbus_printf("error clone: %d (%m)\n", ret);
		/*
		 * Normal user not allowed to create userns,
		 * so nothing to worry about ?
		 */
		if (ret == -EPERM) {
			kdbus_printf("-- CLONE_NEWUSER TEST Failed for uid: %u\n"
				"-- Make sure that your kernel do not allow "
				"CLONE_NEWUSER for unprivileged users\n"
				"-- Upstream Commit: "
				"https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=5eaf563e\n",
				uid);
			ret = 0;
		}

		return ret;
	}

	if (pid == 0) {
		struct kdbus_conn *conn_src;
		eventfd_t event_status = 0;

		ret = prctl(PR_SET_PDEATHSIG, SIGKILL);
		ASSERT_EXIT(ret == 0);

		ret = eventfd_read(efd, &event_status);
		ASSERT_EXIT(ret >= 0 && event_status == 1);

		/* ping connection from the new user namespace */
		conn_src = kdbus_hello(bus, 0, NULL, 0);
		ASSERT_EXIT(conn_src);

		ret = kdbus_add_match_empty(conn_src);
		ASSERT_EXIT(ret == 0);

		ret = kdbus_msg_send(conn_src, name, 0xabcd1234,
				     0, 0, 0, KDBUS_DST_ID_NAME);
		kdbus_conn_free(conn_src);

		_exit(ret == expected_status ? EXIT_SUCCESS : EXIT_FAILURE);
	}

	ret = userns_map_uid_gid(pid, "0 65534 1", "0 65534 1");
	ASSERT_RETURN_VAL(ret == 0, ret);

	/* Tell child we are ready */
	ret = eventfd_write(efd, 1);
	ASSERT_RETURN_VAL(ret == 0, ret);

	ret = waitpid(pid, &status, 0);
	ASSERT_RETURN_VAL(ret >= 0, ret);

	close(efd);

	return status == EXIT_SUCCESS ? TEST_OK : TEST_ERR;
}
Ejemplo n.º 24
0
static int msg_recv_prio(struct kdbus_conn *conn,
			 int64_t requested_prio,
			 int64_t expected_prio)
{
	struct kdbus_cmd_recv recv = {
		.size = sizeof(recv),
		.flags = KDBUS_RECV_USE_PRIORITY,
		.priority = requested_prio,
	};
	struct kdbus_msg *msg;
	int ret;

	ret = ioctl(conn->fd, KDBUS_CMD_RECV, &recv);
	if (ret < 0) {
		kdbus_printf("error receiving message: %d (%m)\n", -errno);
		return -errno;
	}

	msg = (struct kdbus_msg *)(conn->buf + recv.reply.offset);
	kdbus_msg_dump(conn, msg);

	if (msg->priority != expected_prio) {
		kdbus_printf("expected message prio %lld, got %lld\n",
			     (unsigned long long) expected_prio,
			     (unsigned long long) msg->priority);
		return -EINVAL;
	}

	kdbus_msg_free(msg);
	ret = kdbus_free(conn, recv.reply.offset);
	if (ret < 0)
		return ret;

	return 0;
}

int kdbus_test_message_prio(struct kdbus_test_env *env)
{
	struct kdbus_conn *a, *b;
	uint64_t cookie = 0;

	a = kdbus_hello(env->buspath, 0, NULL, 0);
	b = kdbus_hello(env->buspath, 0, NULL, 0);
	ASSERT_RETURN(a && b);

	ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0,   25, a->id) == 0);
	ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0, -600, a->id) == 0);
	ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0,   10, a->id) == 0);
	ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0,  -35, a->id) == 0);
	ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0, -100, a->id) == 0);
	ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0,   20, a->id) == 0);
	ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0,  -15, a->id) == 0);
	ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0, -800, a->id) == 0);
	ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0, -150, a->id) == 0);
	ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0,   10, a->id) == 0);
	ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0, -800, a->id) == 0);
	ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0,  -10, a->id) == 0);

	ASSERT_RETURN(msg_recv_prio(a, -200, -800) == 0);
	ASSERT_RETURN(msg_recv_prio(a, -100, -800) == 0);
	ASSERT_RETURN(msg_recv_prio(a, -400, -600) == 0);
	ASSERT_RETURN(msg_recv_prio(a, -400, -600) == -ENOMSG);
	ASSERT_RETURN(msg_recv_prio(a, 10, -150) == 0);
	ASSERT_RETURN(msg_recv_prio(a, 10, -100) == 0);

	kdbus_printf("--- get priority (all)\n");
	ASSERT_RETURN(kdbus_msg_recv(a, NULL, NULL) == 0);

	kdbus_conn_free(a);
	kdbus_conn_free(b);

	return TEST_OK;
}

static int kdbus_test_notify_kernel_quota(struct kdbus_test_env *env)
{
	int ret;
	unsigned int i;
	uint64_t offset;
	struct kdbus_conn *conn;
	struct kdbus_conn *reader;
	struct kdbus_msg *msg = NULL;

	reader = kdbus_hello(env->buspath, 0, NULL, 0);
	ASSERT_RETURN(reader);

	conn = kdbus_hello(env->buspath, 0, NULL, 0);
	ASSERT_RETURN(conn);

	/* Register for ID signals */
	ret = kdbus_add_match_id(reader, 0x1, KDBUS_ITEM_ID_ADD,
				 KDBUS_MATCH_ID_ANY);
	ASSERT_RETURN(ret == 0);

	ret = kdbus_add_match_id(reader, 0x2, KDBUS_ITEM_ID_REMOVE,
				 KDBUS_MATCH_ID_ANY);
	ASSERT_RETURN(ret == 0);

	/* Each iteration two notifications: add and remove ID */
	for (i = 0; i < KDBUS_CONN_MAX_MSGS / 2; i++) {
		struct kdbus_conn *notifier;

		notifier = kdbus_hello(env->buspath, 0, NULL, 0);
		ASSERT_RETURN(notifier);

		kdbus_conn_free(notifier);

	}

	/*
	 * Now the reader queue is full, message will be lost
	 * but it will not be accounted in dropped msgs
	 */
	ret = kdbus_msg_send(conn, NULL, 0xdeadbeef, 0, 0, 0, reader->id);
	ASSERT_RETURN(ret == -ENOBUFS);

	/* More ID kernel notifications that will be lost */
	kdbus_conn_free(conn);

	conn = kdbus_hello(env->buspath, 0, NULL, 0);
	ASSERT_RETURN(conn);

	kdbus_conn_free(conn);

	ret = kdbus_msg_recv(reader, &msg, &offset);
	ASSERT_RETURN(ret == -EOVERFLOW);

	/*
	 * We lost only 3 packet since only broadcast mesg
	 * are accounted. The connection ID add/remove notification
	 */
	ASSERT_RETURN(offset == 3);

	kdbus_msg_free(msg);

	/* Read our queue */
	for (i = 0; i < KDBUS_CONN_MAX_MSGS; i++) {
		ret = kdbus_msg_recv_poll(reader, 100, &msg, NULL);
		ASSERT_RETURN(ret == 0);

		kdbus_msg_free(msg);
	}

	ret = kdbus_msg_recv(reader, NULL, NULL);
	ASSERT_RETURN(ret == -EAGAIN);

	kdbus_conn_free(reader);

	return 0;
}
Ejemplo n.º 25
0
int kdbus_test_activator(struct kdbus_test_env *env)
{
	int ret;
	struct kdbus_conn *activator;
	struct pollfd fds[2];
	bool activator_done = false;
	struct kdbus_policy_access access[2];

	access[0].type = KDBUS_POLICY_ACCESS_USER;
	access[0].id = 1001;
	access[0].access = KDBUS_POLICY_OWN;

	access[1].type = KDBUS_POLICY_ACCESS_WORLD;
	access[1].access = KDBUS_POLICY_TALK;

	activator = kdbus_hello_activator(env->buspath, "foo.test.activator",
					  access, 2);
	ASSERT_RETURN(activator);

	ret = kdbus_add_match_empty(env->conn);
	ASSERT_RETURN(ret == 0);

	ret = kdbus_name_list(env->conn, KDBUS_NAME_LIST_NAMES |
					 KDBUS_NAME_LIST_UNIQUE |
					 KDBUS_NAME_LIST_ACTIVATORS |
					 KDBUS_NAME_LIST_QUEUED);
	ASSERT_RETURN(ret == 0);

	ret = kdbus_msg_send(env->conn, "foo.test.activator", 0xdeafbeef,
			     0, 0, 0, KDBUS_DST_ID_NAME);
	ASSERT_RETURN(ret == 0);

	fds[0].fd = activator->fd;
	fds[1].fd = env->conn->fd;

	kdbus_printf("-- entering poll loop ...\n");

	for (;;) {
		int i, nfds = sizeof(fds) / sizeof(fds[0]);

		for (i = 0; i < nfds; i++) {
			fds[i].events = POLLIN | POLLPRI;
			fds[i].revents = 0;
		}

		ret = poll(fds, nfds, 3000);
		ASSERT_RETURN(ret >= 0);

		ret = kdbus_name_list(env->conn, KDBUS_NAME_LIST_NAMES);
		ASSERT_RETURN(ret == 0);

		if ((fds[0].revents & POLLIN) && !activator_done) {
			kdbus_printf("Starter was called back!\n");

			ret = kdbus_name_acquire(env->conn,
						 "foo.test.activator",
						 KDBUS_NAME_REPLACE_EXISTING);
			ASSERT_RETURN(ret == 0);

			activator_done = true;
		}

		if (fds[1].revents & POLLIN) {
			kdbus_msg_recv(env->conn, NULL);
			break;
		}
	}

	kdbus_conn_free(activator);

	return TEST_OK;
}
Ejemplo n.º 26
0
static void *run_thread_byebye(void *data)
{
	struct kdbus_cmd cmd_byebye = { .size = sizeof(cmd_byebye) };
	int ret;

	ret = kdbus_msg_recv_poll(conn_a, 3000, NULL, NULL);
	if (ret == 0) {
		kdbus_printf("Thread received message, invoking BYEBYE ...\n");
		kdbus_msg_recv(conn_a, NULL, NULL);
		if (data == BYEBYE_ME)
			kdbus_cmd_byebye(conn_b->fd, &cmd_byebye);
		else if (data == BYEBYE_THEM)
			kdbus_cmd_byebye(conn_a->fd, &cmd_byebye);
	}

	pthread_exit(NULL);
	return NULL;
}

int kdbus_test_sync_byebye(struct kdbus_test_env *env)
{
	pthread_t thread;
	int ret;

	/*
	 * This sends a synchronous message to a thread, which waits until it
	 * received the message and then invokes BYEBYE on the *ORIGINAL*
	 * connection. That is, on the same connection that synchronously waits
	 * for an reply.
	 * This should properly wake the connection up and cause ECONNRESET as
	 * the connection is disconnected now.
	 *
	 * The second time, we do the same but invoke BYEBYE on the *TARGET*
	 * connection. This should also wake up the synchronous sender as the
	 * reply cannot be sent by a disconnected target.
	 */

	conn_a = kdbus_hello(env->buspath, 0, NULL, 0);
	conn_b = kdbus_hello(env->buspath, 0, NULL, 0);
	ASSERT_RETURN(conn_a && conn_b);

	pthread_create(&thread, NULL, run_thread_byebye, BYEBYE_ME);

	ret = kdbus_msg_send_sync(conn_b, NULL, cookie,
				  KDBUS_MSG_EXPECT_REPLY,
				  5000000000ULL, 0, conn_a->id, -1);

	ASSERT_RETURN(ret == -ECONNRESET);

	pthread_join(thread, NULL);

	kdbus_conn_free(conn_a);
	kdbus_conn_free(conn_b);

	conn_a = kdbus_hello(env->buspath, 0, NULL, 0);
	conn_b = kdbus_hello(env->buspath, 0, NULL, 0);
	ASSERT_RETURN(conn_a && conn_b);

	pthread_create(&thread, NULL, run_thread_byebye, BYEBYE_THEM);

	ret = kdbus_msg_send_sync(conn_b, NULL, cookie,
				  KDBUS_MSG_EXPECT_REPLY,
				  5000000000ULL, 0, conn_a->id, -1);

	ASSERT_RETURN(ret == -EPIPE);

	pthread_join(thread, NULL);

	kdbus_conn_free(conn_a);
	kdbus_conn_free(conn_b);

	return TEST_OK;
}
Ejemplo n.º 27
0
int kdbus_test_policy_ns(struct kdbus_test_env *env)
{
	int i;
	int ret;
	struct kdbus_conn *activator = NULL;
	struct kdbus_conn *policy_holder = NULL;
	char *bus = env->buspath;

	if (geteuid() > 0) {
		kdbus_printf("error geteuid() != 0, %s() needs root\n",
			     __func__);
		return TEST_SKIP;
	}

	/* we require user-namespaces */
	if (access("/proc/self/uid_map", F_OK) != 0)
		return TEST_SKIP;

	conn_db = calloc(MAX_CONN, sizeof(struct kdbus_conn *));
	ASSERT_RETURN(conn_db);

	memset(conn_db, 0, MAX_CONN * sizeof(struct kdbus_conn *));

	conn_db[0] = kdbus_hello(bus, 0, NULL, 0);
	ASSERT_RETURN(conn_db[0]);

	ret = kdbus_add_match_empty(conn_db[0]);
	ASSERT_RETURN(ret == 0);

	ret = kdbus_fork_test_by_id(bus, conn_db, -EPERM, -EPERM);
	ASSERT_EXIT(ret == 0);

	ret = kdbus_register_policy_holder(bus, POLICY_NAME,
					   &policy_holder);
	ASSERT_RETURN(ret == 0);

	/* Try to register the same name with an activator */
	ret = kdbus_register_same_activator(bus, POLICY_NAME,
					    &activator);
	ASSERT_RETURN(ret == 0);

	/* Acquire POLICY_NAME */
	ret = kdbus_name_acquire(conn_db[0], POLICY_NAME, NULL);
	ASSERT_RETURN(ret == 0);

	ret = kdbus_normal_test(bus, POLICY_NAME, conn_db);
	ASSERT_RETURN(ret == 0);

	ret = kdbus_name_list(conn_db[0], KDBUS_NAME_LIST_NAMES |
					  KDBUS_NAME_LIST_UNIQUE |
					  KDBUS_NAME_LIST_ACTIVATORS |
					  KDBUS_NAME_LIST_QUEUED);
	ASSERT_RETURN(ret == 0);

	ret = kdbus_fork_test(bus, POLICY_NAME, conn_db, EXIT_SUCCESS);
	ASSERT_RETURN(ret == 0);

	/*
	 * childs connections are able to talk to conn_db[0] since
	 * current POLICY_NAME TALK type is KDBUS_POLICY_ACCESS_WORLD,
	 * so expect EXIT_SUCCESS when sending from child. However,
	 * since the child's connection does not own any well-known
	 * name, The parent connection conn_db[0] should fail with
	 * -EPERM but since it is a privileged bus user the TALK is
	 *  allowed.
	 */
	ret = kdbus_fork_test_by_id(bus, conn_db,
				    EXIT_SUCCESS, EXIT_SUCCESS);
	ASSERT_EXIT(ret == 0);

	/*
	 * Connections that can talk are perhaps being destroyed now.
	 * Restrict the policy and purge cache entries where the
	 * conn_db[0] is the destination.
	 *
	 * Now only connections with uid == 0 are allowed to talk.
	 */
	ret = kdbus_set_policy_talk(policy_holder, POLICY_NAME,
				    geteuid(), KDBUS_POLICY_ACCESS_USER);
	ASSERT_RETURN(ret == 0);

	/*
	 * Testing connections (FORK+DROP) again:
	 * After setting the policy re-check connections
	 * we expect the childs to fail with -EPERM
	 */
	ret = kdbus_fork_test(bus, POLICY_NAME, conn_db, -EPERM);
	ASSERT_RETURN(ret == 0);

	/*
	 * Now expect that both parent and child to fail.
	 *
	 * Child should fail with -EPERM since we just restricted
	 * the POLICY_NAME TALK to uid 0 and its uid is 65534.
	 *
	 * Since the parent's connection will timeout when receiving
	 * from the child, we never continue. FWIW just put -EPERM.
	 */
	ret = kdbus_fork_test_by_id(bus, conn_db, -EPERM, -EPERM);
	ASSERT_EXIT(ret == 0);

	/* Check if the name can be reached in a new userns */
	ret = kdbus_clone_userns_test(bus, POLICY_NAME, conn_db, -EPERM);
	ASSERT_RETURN(ret == 0);

	for (i = 0; i < MAX_CONN; i++)
		kdbus_conn_free(conn_db[i]);

	kdbus_conn_free(activator);
	kdbus_conn_free(policy_holder);

	free(conn_db);

	return ret;
}
Ejemplo n.º 28
0
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)
{
	struct kdbus_msg *msg;
	const char ref1[1024 * 128 + 3] = "0123456789_0";
	const char ref2[] = "0123456789_1";
	struct kdbus_item *item;
	uint64_t size;
	int memfd = -1;
	int ret;

	size = sizeof(struct kdbus_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));

	if (dst_id == KDBUS_DST_ID_BROADCAST)
		size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_bloom_filter)) + 64;
	else {
		memfd = sys_memfd_create("my-name-is-nice", 1024 * 1024);
		if (memfd < 0) {
			kdbus_printf("failed to create memfd: %m\n");
			return memfd;
		}

		if (write(memfd, "kdbus memfd 1234567", 19) != 19) {
			ret = -errno;
			kdbus_printf("writing to memfd failed: %m\n");
			return ret;
		}

		ret = sys_memfd_seal_set(memfd);
		if (ret < 0) {
			ret = -errno;
			kdbus_printf("memfd sealing failed: %m\n");
			return ret;
		}

		size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_memfd));
	}

	if (name)
		size += KDBUS_ITEM_SIZE(strlen(name) + 1);

	msg = malloc(size);
	if (!msg) {
		ret = -errno;
		kdbus_printf("unable to malloc()!?\n");
		return ret;
	}

	memset(msg, 0, size);
	msg->flags = flags;
	msg->timeout_ns = timeout;
	msg->priority = priority;
	msg->size = size;
	msg->src_id = conn->id;
	msg->dst_id = name ? 0 : dst_id;
	msg->cookie = cookie;
	msg->payload_type = KDBUS_PAYLOAD_DBUS;

	item = msg->items;

	if (name) {
		item->type = KDBUS_ITEM_DST_NAME;
		item->size = KDBUS_ITEM_HEADER_SIZE + strlen(name) + 1;
		strcpy(item->str, name);
		item = KDBUS_ITEM_NEXT(item);
	}

	item->type = KDBUS_ITEM_PAYLOAD_VEC;
	item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_vec);
	item->vec.address = (uintptr_t)&ref1;
	item->vec.size = sizeof(ref1);
	item = KDBUS_ITEM_NEXT(item);

	/* data padding for ref1 */
	item->type = KDBUS_ITEM_PAYLOAD_VEC;
	item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_vec);
	item->vec.address = (uintptr_t)NULL;
	item->vec.size =  KDBUS_ALIGN8(sizeof(ref1)) - sizeof(ref1);
	item = KDBUS_ITEM_NEXT(item);

	item->type = KDBUS_ITEM_PAYLOAD_VEC;
	item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_vec);
	item->vec.address = (uintptr_t)&ref2;
	item->vec.size = sizeof(ref2);
	item = KDBUS_ITEM_NEXT(item);

	if (dst_id == KDBUS_DST_ID_BROADCAST) {
		item->type = KDBUS_ITEM_BLOOM_FILTER;
		item->size = KDBUS_ITEM_SIZE(sizeof(struct kdbus_bloom_filter)) + 64;
		item->bloom_filter.generation = 0;
	} else {
		item->type = KDBUS_ITEM_PAYLOAD_MEMFD;
		item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_memfd);
		item->memfd.size = 16;
		item->memfd.fd = memfd;
	}
	item = KDBUS_ITEM_NEXT(item);

	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;
	}

	if (memfd >= 0)
		close(memfd);

	if (flags & KDBUS_MSG_FLAGS_SYNC_REPLY) {
		struct kdbus_msg *reply;

		kdbus_printf("SYNC REPLY @offset %llu:\n", msg->offset_reply);
		reply = (struct kdbus_msg *)(conn->buf + msg->offset_reply);
		kdbus_msg_dump(conn, reply);

		ret = kdbus_free(conn, msg->offset_reply);
		if (ret < 0)
			return ret;
	}

	free(msg);

	return 0;
}
Ejemplo n.º 29
0
void kdbus_msg_dump(const struct kdbus_conn *conn, const struct kdbus_msg *msg)
{
	const struct kdbus_item *item = msg->items;
	char buf_src[32];
	char buf_dst[32];
	uint64_t timeout = 0;
	uint64_t cookie_reply = 0;

	if (msg->flags & KDBUS_MSG_FLAGS_EXPECT_REPLY)
		timeout = msg->timeout_ns;
	else
		cookie_reply = msg->cookie_reply;

	kdbus_printf("MESSAGE: %s (%llu bytes) flags=0x%08llx, %s → %s, "
		     "cookie=%llu, timeout=%llu cookie_reply=%llu priority=%lli\n",
		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),
		(unsigned long long)msg->cookie, (unsigned long long)timeout,
		(unsigned long long)cookie_reply, (long long)msg->priority);

	KDBUS_ITEM_FOREACH(item, msg, items) {
		if (item->size < KDBUS_ITEM_HEADER_SIZE) {
			kdbus_printf("  +%s (%llu bytes) invalid data record\n",
				     enum_MSG(item->type), item->size);
			break;
		}

		switch (item->type) {
		case KDBUS_ITEM_PAYLOAD_OFF: {
			char *s;

			if (item->vec.offset == ~0ULL)
				s = "[\\0-bytes]";
			else
				s = (char *)msg + item->vec.offset;

			kdbus_printf("  +%s (%llu bytes) off=%llu size=%llu '%s'\n",
			       enum_MSG(item->type), item->size,
			       (unsigned long long)item->vec.offset,
			       (unsigned long long)item->vec.size, s);
			break;
		}

		case KDBUS_ITEM_PAYLOAD_MEMFD: {
			char *buf;
			off_t size;

			buf = mmap(NULL, item->memfd.size, PROT_READ,
				   MAP_PRIVATE, item->memfd.fd, 0);
			if (buf == MAP_FAILED) {
				kdbus_printf("mmap() fd=%i size=%llu failed: %m\n",
					     item->memfd.fd, item->memfd.size);
				break;
			}

			if (sys_memfd_get_size(item->memfd.fd, &size) < 0) {
				kdbus_printf("KDBUS_CMD_MEMFD_SIZE_GET failed: %m\n");
				break;
			}

			kdbus_printf("  +%s (%llu bytes) fd=%i size=%llu filesize=%llu '%s'\n",
			       enum_MSG(item->type), item->size, item->memfd.fd,
			       (unsigned long long)item->memfd.size,
			       (unsigned long long)size, buf);
			munmap(buf, item->memfd.size);
			break;
		}

		case KDBUS_ITEM_CREDS:
			kdbus_printf("  +%s (%llu bytes) uid=%lld, gid=%lld, pid=%lld, tid=%lld, starttime=%lld\n",
				enum_MSG(item->type), item->size,
				item->creds.uid, item->creds.gid,
				item->creds.pid, item->creds.tid,
				item->creds.starttime);
			break;

		case KDBUS_ITEM_AUXGROUPS: {
			int i, n;

			kdbus_printf("  +%s (%llu bytes)\n",
				     enum_MSG(item->type), item->size);
			n = (item->size - KDBUS_ITEM_HEADER_SIZE) /
				sizeof(uint64_t);

			for (i = 0; i < n; i++)
				kdbus_printf("    gid[%d] = %lld\n",
					     i, item->data64[i]);
			break;
		}

		case KDBUS_ITEM_PID_COMM:
		case KDBUS_ITEM_TID_COMM:
		case KDBUS_ITEM_EXE:
		case KDBUS_ITEM_CGROUP:
		case KDBUS_ITEM_SECLABEL:
		case KDBUS_ITEM_DST_NAME:
		case KDBUS_ITEM_CONN_NAME:
			kdbus_printf("  +%s (%llu bytes) '%s' (%zu)\n",
				     enum_MSG(item->type), item->size,
				     item->str, strlen(item->str));
			break;

		case KDBUS_ITEM_NAME: {
			kdbus_printf("  +%s (%llu bytes) '%s' (%zu) flags=0x%08llx\n",
				     enum_MSG(item->type), item->size,
				     item->name.name, strlen(item->name.name),
				     item->name.flags);
			break;
		}

		case KDBUS_ITEM_CMDLINE: {
			size_t size = item->size - KDBUS_ITEM_HEADER_SIZE;
			const char *str = item->str;
			int count = 0;

			kdbus_printf("  +%s (%llu bytes) ",
				     enum_MSG(item->type), item->size);
			while (size) {
				kdbus_printf("'%s' ", str);
				size -= strlen(str) + 1;
				str += strlen(str) + 1;
				count++;
			}

			kdbus_printf("(%d string%s)\n",
				     count, (count == 1) ? "" : "s");
			break;
		}

		case KDBUS_ITEM_AUDIT:
			kdbus_printf("  +%s (%llu bytes) loginuid=%llu sessionid=%llu\n",
			       enum_MSG(item->type), item->size,
			       (unsigned long long)item->audit.loginuid,
			       (unsigned long long)item->audit.sessionid);
			break;

		case KDBUS_ITEM_CAPS: {
			int n;
			const uint32_t *cap;
			int i;

			kdbus_printf("  +%s (%llu bytes) len=%llu bytes\n",
			       enum_MSG(item->type), item->size,
			       (unsigned long long)item->size -
					KDBUS_ITEM_HEADER_SIZE);

			cap = item->data32;
			n = (item->size - KDBUS_ITEM_HEADER_SIZE) / 4 / sizeof(uint32_t);

			kdbus_printf("    CapInh=");
			for (i = 0; i < n; i++)
				kdbus_printf("%08x", cap[(0 * n) + (n - i - 1)]);

			kdbus_printf(" CapPrm=");
			for (i = 0; i < n; i++)
				kdbus_printf("%08x", cap[(1 * n) + (n - i - 1)]);

			kdbus_printf(" CapEff=");
			for (i = 0; i < n; i++)
				kdbus_printf("%08x", cap[(2 * n) + (n - i - 1)]);

			kdbus_printf(" CapBnd=");
			for (i = 0; i < n; i++)
				kdbus_printf("%08x", cap[(3 * n) + (n - i - 1)]);
			kdbus_printf("\n");
			break;
		}

		case KDBUS_ITEM_TIMESTAMP:
			kdbus_printf("  +%s (%llu bytes) seq=%llu realtime=%lluns monotonic=%lluns\n",
			       enum_MSG(item->type), item->size,
			       (unsigned long long)item->timestamp.seqnum,
			       (unsigned long long)item->timestamp.realtime_ns,
			       (unsigned long long)item->timestamp.monotonic_ns);
			break;

		case KDBUS_ITEM_REPLY_TIMEOUT:
			kdbus_printf("  +%s (%llu bytes) cookie=%llu\n",
			       enum_MSG(item->type), item->size,
			       msg->cookie_reply);
			break;

		case KDBUS_ITEM_NAME_ADD:
		case KDBUS_ITEM_NAME_REMOVE:
		case KDBUS_ITEM_NAME_CHANGE:
			kdbus_printf("  +%s (%llu bytes) '%s', old id=%lld, new id=%lld, old_flags=0x%llx new_flags=0x%llx\n",
				enum_MSG(item->type),
				(unsigned long long) item->size,
				item->name_change.name,
				item->name_change.old.id,
				item->name_change.new.id,
				item->name_change.old.flags,
				item->name_change.new.flags);
			break;

		case KDBUS_ITEM_ID_ADD:
		case KDBUS_ITEM_ID_REMOVE:
			kdbus_printf("  +%s (%llu bytes) id=%llu flags=%llu\n",
			       enum_MSG(item->type),
			       (unsigned long long) item->size,
			       (unsigned long long) item->id_change.id,
			       (unsigned long long) item->id_change.flags);
			break;

		default:
			kdbus_printf("  +%s (%llu bytes)\n",
				     enum_MSG(item->type), item->size);
			break;
		}
	}

	if ((char *)item - ((char *)msg + msg->size) >= 8)
		kdbus_printf("invalid padding at end of message\n");

	kdbus_printf("\n");
}
Ejemplo n.º 30
0
struct kdbus_conn *
kdbus_hello(const char *path, uint64_t flags,
	    const struct kdbus_item *item, size_t item_size)
{
	int fd, ret;
	struct {
		struct kdbus_cmd_hello hello;
		uint64_t size;
		uint64_t type;
		char comm[16];
		uint8_t extra_items[item_size];
	} h;
	struct kdbus_conn *conn;

	memset(&h, 0, sizeof(h));

	if (item_size > 0)
		memcpy(h.extra_items, item, item_size);

	kdbus_printf("-- opening bus connection %s\n", path);
	fd = open(path, O_RDWR|O_CLOEXEC);
	if (fd < 0) {
		kdbus_printf("--- error %d (%m)\n", fd);
		return NULL;
	}

	h.hello.conn_flags = flags | KDBUS_HELLO_ACCEPT_FD;
	h.hello.attach_flags = _KDBUS_ATTACH_ALL;
	h.type = KDBUS_ITEM_CONN_NAME;
	h.size = KDBUS_ITEM_HEADER_SIZE + sizeof(h.comm);
	strcpy(h.comm, "this-is-my-name");

	h.hello.size = sizeof(h);
	h.hello.pool_size = POOL_SIZE;

	ret = ioctl(fd, KDBUS_CMD_HELLO, &h.hello);
	if (ret < 0) {
		kdbus_printf("--- error when saying hello: %d (%m)\n", ret);
		return NULL;
	}
	kdbus_printf("-- Our peer ID for %s: %llu -- bus uuid: '%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x'\n",
		     path, (unsigned long long)h.hello.id,
		     h.hello.id128[0],  h.hello.id128[1],  h.hello.id128[2],
		     h.hello.id128[3],  h.hello.id128[4],  h.hello.id128[5],
		     h.hello.id128[6],  h.hello.id128[7],  h.hello.id128[8],
		     h.hello.id128[9],  h.hello.id128[10], h.hello.id128[11],
		     h.hello.id128[12], h.hello.id128[13], h.hello.id128[14],
		     h.hello.id128[15]);

	conn = malloc(sizeof(*conn));
	if (!conn) {
		kdbus_printf("unable to malloc()!?\n");
		return NULL;
	}

	conn->buf = mmap(NULL, POOL_SIZE, PROT_READ, MAP_PRIVATE, fd, 0);
	if (conn->buf == MAP_FAILED) {
		free(conn);
		close(fd);
		kdbus_printf("--- error mmap (%m)\n");
		return NULL;
	}

	conn->fd = fd;
	conn->id = h.hello.id;
	return conn;
}