Test: unix socket: test credential passing
[lttng-tools.git] / tests / unit / test_unix_socket.c
index b32a5174aa772e844e4a660d48a8626defcf7bf6..0a96fb589021cc94d2305e7e744d5e3670e9b021 100644 (file)
 #include <stdio.h>
 #include <pthread.h>
 #include <unistd.h>
+#include <sys/wait.h>
+#include <stdlib.h>
 
 #define HIGH_FD_COUNT LTTCOMM_MAX_SEND_FDS
 #define MESSAGE_COUNT 4
 #define LARGE_PAYLOAD_SIZE 4 * 1024
 #define LARGE_PAYLOAD_RECV_SIZE        100
 
-static const int TEST_COUNT = 33;
+static const int TEST_COUNT = 37;
 
 /* For error.h */
 int lttng_opt_quiet;
@@ -499,6 +501,174 @@ error:
        lttng_payload_reset(&received_payload);
 }
 
+static
+void test_creds_passing(void)
+{
+       pid_t fork_ret = -1;
+       int ret, parent_socket = -1, child_connection_socket = -1;
+       ssize_t sock_ret;
+       char socket_dir_path[] = "/tmp/test.unix.socket.creds.passing.XXXXXX";
+       char socket_path[PATH_MAX] = {};
+       struct expected_creds {
+               uid_t euid;
+               gid_t egid;
+               pid_t pid;
+       } expected_creds;
+
+       diag("Receive peer's effective uid, effective gid, and pid from a unix socket");
+
+       if (!mkdtemp(socket_dir_path)) {
+               PERROR("Failed to generate temporary socket location");
+               goto error;
+       }
+
+       strncat(socket_path, socket_dir_path,
+                       sizeof(socket_path) - strlen(socket_path) - 1);
+       strncat(socket_path, "/test_unix_socket",
+                       sizeof(socket_path) - strlen(socket_path) - 1);
+
+       parent_socket = lttcomm_create_unix_sock(socket_path);
+       ok(parent_socket >= 0, "Created unix socket at path `%s`", socket_path);
+       if (parent_socket < 0) {
+               PERROR("Failed to create unix socket at path `%s`", socket_path);
+               goto error;
+       }
+
+       ret = lttcomm_listen_unix_sock(parent_socket);
+       if (ret < 0) {
+               PERROR("Failed to mark parent socket as a passive socket");
+               goto error;
+       }
+
+       ret = lttcomm_setsockopt_creds_unix_sock(parent_socket);
+       if (ret) {
+               PERROR("Failed to set SO_PASSCRED on parent socket");
+               goto error;
+       }
+
+       fork_ret = fork();
+       if (fork_ret < 0) {
+               PERROR("Failed to fork");
+               goto error;
+       }
+
+       if (fork_ret == 0) {
+               /* Child. */
+               int child_socket;
+
+               expected_creds = (struct expected_creds){
+                       .euid = geteuid(),
+                       .egid = getegid(),
+                       .pid = getpid(),
+               };
+
+               child_socket = lttcomm_connect_unix_sock(socket_path);
+               if (child_socket < 0) {
+                       PERROR("Failed to connect to parent socket");
+                       goto error;
+               }
+
+               ret = lttcomm_setsockopt_creds_unix_sock(child_socket);
+               if (ret) {
+                       PERROR("Failed to set SO_PASSCRED on child socket");
+               }
+
+               sock_ret = lttcomm_send_creds_unix_sock(child_socket, &expected_creds,
+                               sizeof(expected_creds));
+               if (sock_ret < 0) {
+                       PERROR("Failed to send expected credentials");
+               }
+
+               ret = close(child_socket);
+               if (ret) {
+                       PERROR("Failed to close child socket");
+               }
+       } else {
+               /* Parent. */
+               int child_status;
+               pid_t wait_pid_ret;
+               lttng_sock_cred received_creds = {};
+
+               child_connection_socket =
+                               lttcomm_accept_unix_sock(parent_socket);
+               if (child_connection_socket < 0) {
+                       PERROR();
+                       goto error;
+               }
+
+               ret = lttcomm_setsockopt_creds_unix_sock(
+                               child_connection_socket);
+               if (ret) {
+                       PERROR("Failed to set SO_PASSCRED on child connection socket");
+                       goto error;
+               }
+
+               sock_ret = lttcomm_recv_creds_unix_sock(child_connection_socket,
+                               &expected_creds, sizeof(expected_creds),
+                               &received_creds);
+               if (sock_ret < 0) {
+                       PERROR("Failed to receive credentials");
+                       goto error;
+               }
+
+               wait_pid_ret = waitpid(fork_ret, &child_status, 0);
+               if (wait_pid_ret == -1) {
+                       PERROR("Failed to wait for termination of child process");
+                       goto error;
+               }
+               if (!WIFEXITED(child_status) || WEXITSTATUS(child_status)) {
+                       diag("Child process reported an error, test failed");
+                       goto error;
+               }
+
+               ok(expected_creds.euid == received_creds.uid,
+                               "Received the expected effective uid (%d == %d)",
+                               expected_creds.euid, received_creds.uid);
+               ok(expected_creds.egid == received_creds.gid,
+                               "Received the expected effective gid (%d == %d)",
+                               expected_creds.egid, received_creds.gid);
+               ok(expected_creds.pid == received_creds.pid,
+                               "Received the expected pid (%d == %d)",
+                               expected_creds.pid, received_creds.pid);
+       }
+
+error:
+       if (parent_socket >= 0) {
+               ret = close(parent_socket);
+               if (ret) {
+                       PERROR("Failed to close parent socket");
+               }
+       }
+
+       if (fork_ret == 0) {
+               if (child_connection_socket >= 0) {
+                       ret = close(child_connection_socket);
+                       if (ret) {
+                               PERROR("Failed to close child connection socket");
+                       }
+               }
+
+               /* Prevent libtap from printing a result for the child. */
+               fclose(stdout);
+               fclose(stderr);
+
+               /* Child exits at the end of this test. */
+               exit(0);
+       } else if (parent_socket >= 0) {
+               ret = unlink(socket_path);
+               if (ret) {
+                       PERROR("Failed to unlink socket at path `%s`",
+                                       socket_path);
+               }
+
+               ret = rmdir(socket_dir_path);
+               if (ret) {
+                       PERROR("Failed to remove test directory at `%s`",
+                                       socket_dir_path);
+               }
+       }
+}
+
 int main(void)
 {
        plan_tests(TEST_COUNT);
@@ -506,6 +676,7 @@ int main(void)
        test_high_fd_count(HIGH_FD_COUNT);
        test_one_fd_per_message(MESSAGE_COUNT);
        test_receive_in_chunks(LARGE_PAYLOAD_SIZE, LARGE_PAYLOAD_RECV_SIZE);
+       test_creds_passing();
 
        return exit_status();
 }
This page took 0.025932 seconds and 5 git commands to generate.