[systemd-devel] [PATCH 1/2] test: some tests to enforce routing messages by connections ID

Djalal Harouni tixxdz at opendz.org
Tue Sep 16 19:12:32 PDT 2014


Add kdbus_fork_test_by_id() to test connections by id under different
uids. Currently we succeed at this test.

Update:
1) kdbus_msg_recv() to get the offset of the slice, so we can
release it later.

2) kdbus_msg_recv_poll() to pass the offset argument to
kdbus_msg_recv().

We do this to follow best practice and to be able to free the returned
kdbus_msg and the slice pointed by that offset.

Signed-off-by: Djalal Harouni <tixxdz at opendz.org>
---
Hi Daniel, before applying please make sure that we want this. It
follows what I've discussed in the other mail, otherwise just test it,
it will give a better view of the routing policy.

 test/kdbus-util.c       |  15 ++++-
 test/kdbus-util.h       |   7 ++-
 test/test-activator.c   |   2 +-
 test/test-chat.c        |   4 +-
 test/test-connection.c  |   4 +-
 test/test-daemon.c      |   2 +-
 test/test-fd.c          |   2 +-
 test/test-message.c     |   2 +-
 test/test-metadata-ns.c |   2 +-
 test/test-monitor.c     |   7 ++-
 test/test-policy-ns.c   | 160 ++++++++++++++++++++++++++++++++++++++++--------
 test/test-sync.c        |   2 +-
 12 files changed, 166 insertions(+), 43 deletions(-)

diff --git a/test/kdbus-util.c b/test/kdbus-util.c
index c72b8fe..fe4565c 100644
--- a/test/kdbus-util.c
+++ b/test/kdbus-util.c
@@ -630,6 +630,9 @@ void kdbus_msg_free(struct kdbus_msg *msg)
 	const struct kdbus_item *item;
 	int nfds, i;
 
+	if (!msg)
+		return;
+
 	KDBUS_ITEM_FOREACH(item, msg, items) {
 		switch (item->type) {
 		/* close all memfds */
@@ -648,7 +651,9 @@ void kdbus_msg_free(struct kdbus_msg *msg)
 	}
 }
 
-int kdbus_msg_recv(struct kdbus_conn *conn, struct kdbus_msg **msg_out)
+int kdbus_msg_recv(struct kdbus_conn *conn,
+		   struct kdbus_msg **msg_out,
+		   uint64_t *offset)
 {
 	struct kdbus_cmd_recv recv = {};
 	struct kdbus_msg *msg;
@@ -665,6 +670,9 @@ int kdbus_msg_recv(struct kdbus_conn *conn, struct kdbus_msg **msg_out)
 
 	if (msg_out) {
 		*msg_out = msg;
+
+		if (offset)
+			*offset = recv.offset;
 	} else {
 		kdbus_msg_free(msg);
 
@@ -677,13 +685,14 @@ int kdbus_msg_recv(struct kdbus_conn *conn, struct kdbus_msg **msg_out)
 }
 
 int kdbus_msg_recv_poll(struct kdbus_conn *conn,
+			unsigned int timeout_ms,
 			struct kdbus_msg **msg_out,
-			unsigned int timeout_ms)
+			uint64_t *offset)
 {
 	int ret;
 
 	for (; timeout_ms; timeout_ms--) {
-		ret = kdbus_msg_recv(conn, NULL);
+		ret = kdbus_msg_recv(conn, msg_out, offset);
 		if (ret == -EAGAIN) {
 			usleep(1000);
 			continue;
diff --git a/test/kdbus-util.h b/test/kdbus-util.h
index c2370e7..8e3d0a8 100644
--- a/test/kdbus-util.h
+++ b/test/kdbus-util.h
@@ -56,9 +56,10 @@ int kdbus_name_release(struct kdbus_conn *conn, const char *name);
 int kdbus_name_acquire(struct kdbus_conn *conn, const char *name,
 		       uint64_t flags);
 void kdbus_msg_free(struct kdbus_msg *msg);
-int kdbus_msg_recv(struct kdbus_conn *conn, struct kdbus_msg **msg);
-int kdbus_msg_recv_poll(struct kdbus_conn *conn, struct kdbus_msg **msg_out,
-			unsigned int timeout_ms);
+int kdbus_msg_recv(struct kdbus_conn *conn,
+		   struct kdbus_msg **msg, uint64_t *offset);
+int kdbus_msg_recv_poll(struct kdbus_conn *conn, unsigned int timeout_ms,
+			struct kdbus_msg **msg_out, uint64_t *offset);
 int kdbus_free(const struct kdbus_conn *conn, uint64_t offset);
 void kdbus_msg_dump(const struct kdbus_conn *conn,
 		    const struct kdbus_msg *msg);
diff --git a/test/test-activator.c b/test/test-activator.c
index eb57b52..7bdcbf3 100644
--- a/test/test-activator.c
+++ b/test/test-activator.c
@@ -79,7 +79,7 @@ int kdbus_test_activator(struct kdbus_test_env *env)
 		}
 
 		if (fds[1].revents & POLLIN) {
-			kdbus_msg_recv(env->conn, NULL);
+			kdbus_msg_recv(env->conn, NULL, NULL);
 			break;
 		}
 	}
diff --git a/test/test-chat.c b/test/test-chat.c
index 11c140d..b2bcc31 100644
--- a/test/test-chat.c
+++ b/test/test-chat.c
@@ -86,7 +86,7 @@ int kdbus_test_chat(struct kdbus_test_env *env)
 			if (count > 2)
 				kdbus_name_release(conn_a, "foo.bar.baz");
 
-			ret = kdbus_msg_recv(conn_a, NULL);
+			ret = kdbus_msg_recv(conn_a, NULL, NULL);
 			ASSERT_RETURN(ret == 0);
 			ret = kdbus_msg_send(conn_a, NULL,
 					     0xc0000000 | cookie++,
@@ -95,7 +95,7 @@ int kdbus_test_chat(struct kdbus_test_env *env)
 		}
 
 		if (fds[1].revents & POLLIN) {
-			ret = kdbus_msg_recv(conn_b, NULL);
+			ret = kdbus_msg_recv(conn_b, NULL, NULL);
 			ASSERT_RETURN(ret == 0);
 			ret = kdbus_msg_send(conn_b, NULL,
 					     0xc0000000 | cookie++,
diff --git a/test/test-connection.c b/test/test-connection.c
index 355e359..dccb1b3 100644
--- a/test/test-connection.c
+++ b/test/test-connection.c
@@ -245,7 +245,7 @@ int kdbus_test_conn_update(struct kdbus_test_env *env)
 	ret = kdbus_msg_send(env->conn, NULL, 0x12345678, 0, 0, 0, conn->id);
 	ASSERT_RETURN(ret == 0);
 
-	ret = kdbus_msg_recv(conn, &msg);
+	ret = kdbus_msg_recv(conn, &msg, NULL);
 	ASSERT_RETURN(ret == 0);
 
 	KDBUS_ITEM_FOREACH(item, msg, items)
@@ -267,7 +267,7 @@ int kdbus_test_conn_update(struct kdbus_test_env *env)
 	ret = kdbus_msg_send(env->conn, NULL, 0x12345678, 0, 0, 0, conn->id);
 	ASSERT_RETURN(ret == 0);
 
-	ret = kdbus_msg_recv(conn, &msg);
+	ret = kdbus_msg_recv(conn, &msg, NULL);
 	ASSERT_RETURN(ret == 0);
 
 	KDBUS_ITEM_FOREACH(item, msg, items)
diff --git a/test/test-daemon.c b/test/test-daemon.c
index 2ebb27d..fa79303 100644
--- a/test/test-daemon.c
+++ b/test/test-daemon.c
@@ -51,7 +51,7 @@ int kdbus_test_daemon(struct kdbus_test_env *env)
 			break;
 
 		if (fds[0].revents & POLLIN) {
-			ret = kdbus_msg_recv(env->conn, NULL);
+			ret = kdbus_msg_recv(env->conn, NULL, NULL);
 			ASSERT_RETURN(ret == 0);
 		}
 
diff --git a/test/test-fd.c b/test/test-fd.c
index aee5064..9ffdc35 100644
--- a/test/test-fd.c
+++ b/test/test-fd.c
@@ -87,7 +87,7 @@ int kdbus_test_fd_passing(struct kdbus_test_env *env)
 	ret = send_fd(conn_src, conn_dst->id, fds[0]);
 	ASSERT_RETURN(ret == 0);
 
-	ret = kdbus_msg_recv(conn_dst, &msg);
+	ret = kdbus_msg_recv(conn_dst, &msg, NULL);
 	ASSERT_RETURN(ret == 0);
 
 	KDBUS_ITEM_FOREACH(item, msg, items) {
diff --git a/test/test-message.c b/test/test-message.c
index 84962ff..387ef70 100644
--- a/test/test-message.c
+++ b/test/test-message.c
@@ -125,7 +125,7 @@ int kdbus_test_message_prio(struct kdbus_test_env *env)
 	ASSERT_RETURN(msg_recv_prio(conn_a, 10, -100) == 0);
 
 	kdbus_printf("--- get priority (all)\n");
-	ASSERT_RETURN(kdbus_msg_recv(conn_a, NULL) == 0);
+	ASSERT_RETURN(kdbus_msg_recv(conn_a, NULL, NULL) == 0);
 
 	kdbus_conn_free(conn_a);
 	kdbus_conn_free(conn_b);
diff --git a/test/test-metadata-ns.c b/test/test-metadata-ns.c
index 372cd5a..d83b8e1 100644
--- a/test/test-metadata-ns.c
+++ b/test/test-metadata-ns.c
@@ -166,7 +166,7 @@ static int kdbus_clone_userns_test(const char *bus, struct kdbus_conn *conn)
 	}
 
 	/* Receive in the original (root privileged) user namespace */
-	ret = kdbus_msg_recv_poll(conn, NULL, 1000);
+	ret = kdbus_msg_recv_poll(conn, 1000, NULL, NULL);
 	ASSERT_RETURN(ret == 0);
 
 	ret = waitpid(pid, &status, 0);
diff --git a/test/test-monitor.c b/test/test-monitor.c
index 90308af..db8fde6 100644
--- a/test/test-monitor.c
+++ b/test/test-monitor.c
@@ -26,6 +26,7 @@ int kdbus_test_monitor(struct kdbus_test_env *env)
 {
 	struct kdbus_conn *monitor, *conn;
 	unsigned int cookie = 0xdeadbeef;
+	uint64_t offset = 0;
 	struct kdbus_cmd_name *cmd_name;
 	struct kdbus_msg *msg;
 	size_t size;
@@ -56,16 +57,18 @@ int kdbus_test_monitor(struct kdbus_test_env *env)
 	ASSERT_RETURN(ret == 0);
 
 	/* the recipient should have got the message */
-	ret = kdbus_msg_recv(conn, &msg);
+	ret = kdbus_msg_recv(conn, &msg, &offset);
 	ASSERT_RETURN(ret == 0);
 	ASSERT_RETURN(msg->cookie == cookie);
 	kdbus_msg_free(msg);
+	kdbus_free(conn, offset);
 
 	/* and so should the monitor */
-	ret = kdbus_msg_recv(monitor, &msg);
+	ret = kdbus_msg_recv(monitor, &msg, &offset);
 	ASSERT_RETURN(ret == 0);
 	ASSERT_RETURN(msg->cookie == cookie);
 	kdbus_msg_free(msg);
+	kdbus_free(monitor, offset);
 
 	kdbus_conn_free(monitor);
 	kdbus_conn_free(conn);
diff --git a/test/test-policy-ns.c b/test/test-policy-ns.c
index 517278c..8b48d45 100644
--- a/test/test-policy-ns.c
+++ b/test/test-policy-ns.c
@@ -54,7 +54,7 @@ static void *kdbus_recv_echo(void *ptr)
 	int ret;
 	struct kdbus_conn *conn = ptr;
 
-	ret = kdbus_msg_recv_poll(conn, NULL, 1000);
+	ret = kdbus_msg_recv_poll(conn, 1000, NULL, NULL);
 
 	return (void *)(long)ret;
 }
@@ -124,27 +124,6 @@ static int kdbus_register_policy_holder(char *bus, const char *name,
 	return TEST_OK;
 }
 
-/* return TEST_OK or TEST_ERR on failure */
-static int kdbus_receiver_acquire_name(char *bus, const char *name,
-					struct kdbus_conn **conn)
-{
-	int ret;
-	struct kdbus_conn *c;
-
-	c = kdbus_hello(bus, 0, NULL, 0);
-	ASSERT_RETURN(c);
-
-	ret = kdbus_add_match_empty(c);
-	ASSERT_RETURN(ret == 0);
-
-	ret = kdbus_name_acquire(c, name, 0);
-	ASSERT_RETURN(ret == 0);
-
-	*conn = c;
-
-	return TEST_OK;
-}
-
 /**
  * Create new threads for receiving from multiple senders,
  * The 'conn_db' will be populated by newly created connections.
@@ -220,6 +199,102 @@ static int kdbus_normal_test(const char *bus, const char *name,
 	return TEST_OK;
 }
 
+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, 1000, 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], 1000, &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;
+}
+
 /*
  * Return: TEST_OK, TEST_ERR or TEST_SKIP
  * we return TEST_OK only if the childs return with the expected
@@ -239,7 +314,7 @@ static int kdbus_fork_test(const char *bus, const char *name,
 
 	if (pid == 0) {
 		ret = prctl(PR_SET_PDEATHSIG, SIGKILL);
-		ASSERT_EXIT(pid >= 0);
+		ASSERT_EXIT(ret == 0);
 
 		ret = drop_privileges(65534, 65534);
 		ASSERT_EXIT(ret == 0);
@@ -378,7 +453,7 @@ static int kdbus_clone_userns_test(const char *bus,
 	 * Receive in the original (root privileged) user namespace,
 	 * must fail with -ETIMEDOUT.
 	 */
-	ret = kdbus_msg_recv_poll(conn_db[0], NULL, 1000);
+	ret = kdbus_msg_recv_poll(conn_db[0], 1000, NULL, NULL);
 	ASSERT_RETURN_VAL(ret == -ETIMEDOUT, ret);
 
 	ret = waitpid(pid, &status, 0);
@@ -406,6 +481,16 @@ int kdbus_test_policy_ns(struct kdbus_test_env *env)
 
 	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,
+				    EXIT_SUCCESS, EXIT_SUCCESS);
+	ASSERT_EXIT(ret == 0);
+
 	ret = kdbus_register_policy_holder(bus, POLICY_NAME,
 					   &policy_holder);
 	ASSERT_RETURN(ret == 0);
@@ -415,7 +500,8 @@ int kdbus_test_policy_ns(struct kdbus_test_env *env)
 					    &activator);
 	ASSERT_RETURN(ret == 0);
 
-	ret = kdbus_receiver_acquire_name(bus, POLICY_NAME, &conn_db[0]);
+	/* Acquire POLICY_NAME */
+	ret = kdbus_name_acquire(conn_db[0], POLICY_NAME, 0);
 	ASSERT_RETURN(ret == 0);
 
 	ret = kdbus_normal_test(bus, POLICY_NAME, conn_db);
@@ -431,6 +517,18 @@ int kdbus_test_policy_ns(struct kdbus_test_env *env)
 	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 when sending to it.
+	 */
+	ret = kdbus_fork_test_by_id(bus, conn_db,
+				    -EPERM, 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.
@@ -449,6 +547,18 @@ int kdbus_test_policy_ns(struct kdbus_test_env *env)
 	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);
diff --git a/test/test-sync.c b/test/test-sync.c
index 55091be..66d41cf 100644
--- a/test/test-sync.c
+++ b/test/test-sync.c
@@ -35,7 +35,7 @@ static void *run_thread(void *data)
 
 	if (fd.revents & POLLIN) {
 		kdbus_printf("Thread received message, sending reply ...\n");
-		kdbus_msg_recv(conn_a, NULL);
+		kdbus_msg_recv(conn_a, NULL, NULL);
 		kdbus_msg_send(conn_a, NULL, 0, 0, cookie, 0, conn_b->id);
 	}
 
-- 
1.9.3



More information about the systemd-devel mailing list