Esempio n. 1
0
static int kdbus_clone_userns_test(const char *bus,
				   const char *name,
				   struct kdbus_conn **conn_db,
				   int expected_status)
{
	pid_t pid;
	int ret = 0;
	int status;

	pid = fork();
	ASSERT_RETURN_VAL(pid >= 0, -errno);

	if (pid == 0) {
		ret = prctl(PR_SET_PDEATHSIG, SIGKILL);
		if (ret < 0)
			_exit(EXIT_FAILURE);

		ret = __kdbus_clone_userns_test(bus, name, conn_db,
						expected_status);
		_exit(ret);
	}

	/*
	 * Receive in the original (root privileged) user namespace,
	 * must fail with -ETIMEDOUT.
	 */
	ret = kdbus_msg_recv_poll(conn_db[0], 100, NULL, NULL);
	ASSERT_RETURN_VAL(ret == -ETIMEDOUT, ret);

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

	return (status == EXIT_SUCCESS) ? TEST_OK : TEST_ERR;
}
Esempio 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;
}
Esempio n. 3
0
/*
 * Return: TEST_OK, TEST_ERR or TEST_SKIP
 * we return TEST_OK only if the children return with the expected
 * 'expected_status' that is specified as an argument.
 */
static int kdbus_fork_test(const char *bus, const char *name,
			   struct kdbus_conn **conn_db, int expected_status)
{
	pid_t pid;
	int ret = 0;
	int status = 0;

	pid = fork();
	ASSERT_RETURN_VAL(pid >= 0, pid);

	if (pid == 0) {
		ret = prctl(PR_SET_PDEATHSIG, SIGKILL);
		ASSERT_EXIT(ret == 0);

		ret = drop_privileges(65534, 65534);
		ASSERT_EXIT(ret == 0);

		ret = kdbus_recv_in_threads(bus, name, conn_db);
		_exit(ret == expected_status ? EXIT_SUCCESS : EXIT_FAILURE);
	}

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

	return (status == EXIT_SUCCESS) ? TEST_OK : TEST_ERR;
}
Esempio n. 4
0
static int no_cancel_sync(struct kdbus_conn *conn_src,
			  struct kdbus_conn *conn_dst)
{
	pid_t pid;
	int cancel_fd;
	int ret, status;
	struct kdbus_msg *msg = NULL;

	/* pass eventfd, but never signal it so it shouldn't have any effect */

	cancel_fd = eventfd(0, 0);
	ASSERT_RETURN_VAL(cancel_fd >= 0, cancel_fd);

	cookie++;
	pid = fork();
	ASSERT_RETURN_VAL(pid >= 0, pid);

	if (pid == 0) {
		ret = kdbus_msg_send_sync(conn_dst, NULL, cookie,
					  KDBUS_MSG_EXPECT_REPLY,
					  100000000ULL, 0, conn_src->id,
					  cancel_fd);
		ASSERT_EXIT(ret == 0);

		_exit(EXIT_SUCCESS);
	}

	ret = kdbus_msg_recv_poll(conn_src, 100, &msg, NULL);
	ASSERT_RETURN_VAL(ret == 0 && msg->cookie == cookie, -1);

	kdbus_msg_free(msg);

	ret = kdbus_msg_send_reply(conn_src, cookie, conn_dst->id);
	ASSERT_RETURN_VAL(ret >= 0, ret);

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

	if (WIFSIGNALED(status))
		return -1;

	return (status == EXIT_SUCCESS) ? 0 : -1;
}
Esempio n. 5
0
static int cancel_fd_sync(struct kdbus_conn *conn_src,
			  struct kdbus_conn *conn_dst)
{
	pid_t pid;
	int cancel_fd;
	int ret, status;
	uint64_t counter = 1;
	struct kdbus_msg *msg = NULL;

	cancel_fd = eventfd(0, 0);
	ASSERT_RETURN_VAL(cancel_fd >= 0, cancel_fd);

	cookie++;
	pid = fork();
	ASSERT_RETURN_VAL(pid >= 0, pid);

	if (pid == 0) {
		ret = kdbus_msg_send_sync(conn_dst, NULL, cookie,
					  KDBUS_MSG_EXPECT_REPLY,
					  100000000ULL, 0, conn_src->id,
					  cancel_fd);
		ASSERT_EXIT(ret == -ECANCELED);

		_exit(EXIT_SUCCESS);
	}

	ret = kdbus_msg_recv_poll(conn_src, 100, &msg, NULL);
	ASSERT_RETURN(ret == 0 && msg->cookie == cookie);

	kdbus_msg_free(msg);

	ret = write(cancel_fd, &counter, sizeof(counter));
	ASSERT_RETURN(ret == sizeof(counter));

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

	if (WIFSIGNALED(status))
		return TEST_ERR;

	return (status == EXIT_SUCCESS) ? TEST_OK : TEST_ERR;
}
Esempio n. 6
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;
}
Esempio n. 7
0
static int kdbus_fork_test_by_id(const char *bus,
				 struct kdbus_conn **conn_db,
				 int parent_status, int child_status)
{
	int ret;
	pid_t pid;
	uint64_t cookie = 0x9876ecba;
	struct kdbus_msg *msg = NULL;
	uint64_t offset = 0;
	int status = 0;

	/*
	 * If the child_status is not EXIT_SUCCESS, then we expect
	 * that sending from the child will fail, thus receiving
	 * from parent must error with -ETIMEDOUT, and vice versa.
	 */
	bool parent_timedout = !!child_status;
	bool child_timedout = !!parent_status;

	pid = fork();
	ASSERT_RETURN_VAL(pid >= 0, pid);

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

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

		ret = drop_privileges(65534, 65534);
		ASSERT_EXIT(ret == 0);

		conn_src = kdbus_hello(bus, 0, NULL, 0);
		ASSERT_EXIT(conn_src);

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

		/*
		 * child_status is always checked against send
		 * operations, in case it fails always return
		 * EXIT_FAILURE.
		 */
		ret = kdbus_msg_send(conn_src, NULL, cookie,
				     0, 0, 0, conn_db[0]->id);
		ASSERT_EXIT(ret == child_status);

		ret = kdbus_msg_recv_poll(conn_src, 100, NULL, NULL);

		kdbus_conn_free(conn_src);

		/*
		 * Child kdbus_msg_recv_poll() should timeout since
		 * the parent_status was set to a non EXIT_SUCCESS
		 * value.
		 */
		if (child_timedout)
			_exit(ret == -ETIMEDOUT ? EXIT_SUCCESS : EXIT_FAILURE);

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

	ret = kdbus_msg_recv_poll(conn_db[0], 100, &msg, &offset);
	/*
	 * If parent_timedout is set then this should fail with
	 * -ETIMEDOUT since the child_status was set to a non
	 * EXIT_SUCCESS value. Otherwise, assume
	 * that kdbus_msg_recv_poll() has succeeded.
	 */
	if (parent_timedout) {
		ASSERT_RETURN_VAL(ret == -ETIMEDOUT, TEST_ERR);

		/* timedout no need to continue, we don't have the
		 * child connection ID, so just terminate. */
		goto out;
	} else {
		ASSERT_RETURN_VAL(ret == 0, ret);
	}

	ret = kdbus_msg_send(conn_db[0], NULL, ++cookie,
			     0, 0, 0, msg->src_id);
	/*
	 * parent_status is checked against send operations,
	 * on failures always return TEST_ERR.
	 */
	ASSERT_RETURN_VAL(ret == parent_status, TEST_ERR);

	kdbus_msg_free(msg);
	kdbus_free(conn_db[0], offset);

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

	return (status == EXIT_SUCCESS) ? TEST_OK : TEST_ERR;
}
Esempio n. 8
0
static int interrupt_sync(struct kdbus_conn *conn_src,
			  struct kdbus_conn *conn_dst)
{
	pid_t pid;
	int ret, status;
	struct kdbus_msg *msg = NULL;
	struct sigaction sa = {
		.sa_handler = nop_handler,
		.sa_flags = SA_NOCLDSTOP|SA_RESTART,
	};

	cookie++;
	pid = fork();
	ASSERT_RETURN_VAL(pid >= 0, pid);

	if (pid == 0) {
		ret = sigaction(SIGINT, &sa, NULL);
		ASSERT_EXIT(ret == 0);

		ret = kdbus_msg_send_sync(conn_dst, NULL, cookie,
					  KDBUS_MSG_EXPECT_REPLY,
					  100000000ULL, 0, conn_src->id, -1);
		ASSERT_EXIT(ret == -ETIMEDOUT);

		_exit(EXIT_SUCCESS);
	}

	ret = kdbus_msg_recv_poll(conn_src, 100, &msg, NULL);
	ASSERT_RETURN(ret == 0 && msg->cookie == cookie);

	kdbus_msg_free(msg);

	ret = kill(pid, SIGINT);
	ASSERT_RETURN_VAL(ret == 0, ret);

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

	if (WIFSIGNALED(status))
		return TEST_ERR;

	ret = kdbus_msg_recv_poll(conn_src, 100, NULL, NULL);
	ASSERT_RETURN(ret == -ETIMEDOUT);

	return (status == EXIT_SUCCESS) ? TEST_OK : TEST_ERR;
}

static int close_epipe_sync(const char *bus)
{
	pid_t pid;
	int ret, status;
	struct kdbus_conn *conn_src;
	struct kdbus_conn *conn_dst;
	struct kdbus_msg *msg = NULL;

	conn_src = kdbus_hello(bus, 0, NULL, 0);
	ASSERT_RETURN(conn_src);

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

	conn_dst = kdbus_hello(bus, 0, NULL, 0);
	ASSERT_RETURN(conn_dst);

	cookie++;
	pid = fork();
	ASSERT_RETURN_VAL(pid >= 0, pid);

	if (pid == 0) {
		uint64_t dst_id;

		/* close our reference */
		dst_id = conn_dst->id;
		kdbus_conn_free(conn_dst);

		ret = kdbus_msg_recv_poll(conn_src, 100, &msg, NULL);
		ASSERT_EXIT(ret == 0 && msg->cookie == cookie);
		ASSERT_EXIT(msg->src_id == dst_id);

		cookie++;
		ret = kdbus_msg_send_sync(conn_src, NULL, cookie,
					  KDBUS_MSG_EXPECT_REPLY,
					  100000000ULL, 0, dst_id, -1);
		ASSERT_EXIT(ret == -EPIPE);

		_exit(EXIT_SUCCESS);
	}

	ret = kdbus_msg_send(conn_dst, NULL, cookie, 0, 0, 0,
			     KDBUS_DST_ID_BROADCAST);
	ASSERT_RETURN(ret == 0);

	cookie++;
	ret = kdbus_msg_recv_poll(conn_dst, 100, &msg, NULL);
	ASSERT_RETURN(ret == 0 && msg->cookie == cookie);

	kdbus_msg_free(msg);

	/* destroy connection */
	kdbus_conn_free(conn_dst);
	kdbus_conn_free(conn_src);

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

	if (!WIFEXITED(status))
		return TEST_ERR;

	return (status == EXIT_SUCCESS) ? TEST_OK : TEST_ERR;
}