From 590e10917770afa5a65e96d96a03e7df0f8517cd Mon Sep 17 00:00:00 2001 From: Andrea Terzolo Date: Thu, 16 May 2024 13:10:23 +0200 Subject: [PATCH] test(drivers): add some tests for ia32 syscalls Signed-off-by: Andrea Terzolo --- test/drivers/CMakeLists.txt | 3 +- test/drivers/helpers/ia32.c | 158 ++++++++++++++++-- .../test_suites/actions_suite/ia32.cpp.in | 123 ++++++++++++++ 3 files changed, 271 insertions(+), 13 deletions(-) diff --git a/test/drivers/CMakeLists.txt b/test/drivers/CMakeLists.txt index 4b88fc1bc5..a8ae4ad41a 100644 --- a/test/drivers/CMakeLists.txt +++ b/test/drivers/CMakeLists.txt @@ -53,6 +53,7 @@ set(DRIVERS_TEST_DEPENDECIES ## IA32 tests are only available on x86_64 if(${CMAKE_HOST_SYSTEM_PROCESSOR} STREQUAL "x86_64" AND ENABLE_IA32_TESTS) add_executable(ia32 ./helpers/ia32.c) + target_include_directories(ia32 PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}") set_target_properties(ia32 PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32") set(DRIVERS_TEST_DEPENDECIES ${DRIVERS_TEST_DEPENDECIES} @@ -66,5 +67,3 @@ add_executable(drivers_test ${DRIVERS_TEST_SOURCES}) target_include_directories(drivers_test ${DRIVERS_TEST_INCLUDE}) target_link_libraries(drivers_test ${DRIVERS_TEST_LINK_LIBRARIES}) add_dependencies(drivers_test ${DRIVERS_TEST_DEPENDECIES}) - - diff --git a/test/drivers/helpers/ia32.c b/test/drivers/helpers/ia32.c index 7b8dc6fc65..113d08fae4 100644 --- a/test/drivers/helpers/ia32.c +++ b/test/drivers/helpers/ia32.c @@ -13,6 +13,9 @@ #include #include #include /* Definition of SYS_* constants */ +#include +#include +#include #ifdef __NR_openat2 #include /* Definition of RESOLVE_* constants */ @@ -63,32 +66,165 @@ int main(int argc, char** argv) syscall(__NR_socketcall, -1, args); return 0; } - - if(argc != 2) + else if(argc == 2) { - fprintf(stderr, "we need exactly one single arg\n"); - return -1; - } - #ifdef __NR_write - TRY_SYSCALL(__NR_write, 17, NULL, 1013) + TRY_SYSCALL(__NR_write, 17, NULL, 1013) #endif #ifdef __NR_clock_gettime - TRY_SYSCALL(__NR_clock_gettime, 0, NULL) + TRY_SYSCALL(__NR_clock_gettime, 0, NULL) #endif #ifdef __NR_getcpu - TRY_SYSCALL(__NR_getcpu, NULL, NULL, NULL) + TRY_SYSCALL(__NR_getcpu, NULL, NULL, NULL) #endif #ifdef __NR_gettimeofday - TRY_SYSCALL(__NR_gettimeofday, NULL, NULL) + TRY_SYSCALL(__NR_gettimeofday, NULL, NULL) #endif #ifdef __NR_time - TRY_SYSCALL(__NR_time, NULL) + TRY_SYSCALL(__NR_time, NULL) #endif + } + else if(argc == 3) + { + /* This if case is used to manage socketcall, we look at argv[2] in this case */ + + // Create sockets + int32_t server_socket_fd = syscall(__NR_socket, AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); + if(server_socket_fd == -1) + { + fprintf(stderr, "socket server failed\n"); + return -1; + } + int32_t client_socket_fd = syscall(__NR_socket, AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); + if(client_socket_fd == -1) + { + fprintf(stderr, "socket client failed\n"); + return -1; + } + + // Reuse address and port + int option_value = 1; + if(syscall(__NR_setsockopt, server_socket_fd, SOL_SOCKET, SO_REUSEADDR, &option_value, + sizeof(option_value)) == -1) + { + fprintf(stderr, "setsockopt (server addr) failed\n"); + return -1; + } + if(syscall(__NR_setsockopt, server_socket_fd, SOL_SOCKET, SO_REUSEPORT, &option_value, + sizeof(option_value)) == -1) + { + fprintf(stderr, "setsockopt (server port) failed\n"); + return -1; + } + if(syscall(__NR_setsockopt, client_socket_fd, SOL_SOCKET, SO_REUSEADDR, &option_value, + sizeof(option_value)) == -1) + { + fprintf(stderr, "setsockopt (client addr) failed\n"); + return -1; + } + if(syscall(__NR_setsockopt, client_socket_fd, SOL_SOCKET, SO_REUSEPORT, &option_value, + sizeof(option_value)) == -1) + { + fprintf(stderr, "setsockopt (client port) failed\n"); + return -1; + } + + // populate info + struct sockaddr_in client_addr = {0}; + struct sockaddr_in server_addr = {0}; + + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(IPV4_PORT_SERVER); + if(inet_pton(AF_INET, IPV4_SERVER, &(server_addr.sin_addr)) == -1) + { + fprintf(stderr, "inet_pton server failed\n"); + return -1; + } + + client_addr.sin_family = AF_INET; + client_addr.sin_port = htons(IPV4_PORT_CLIENT); + if(inet_pton(AF_INET, IPV4_CLIENT, &(client_addr.sin_addr)) == -1) + { + fprintf(stderr, "inet_pton client failed\n"); + return -1; + } + + // Now we bind the server socket with the server address. + if(syscall(__NR_bind, server_socket_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) + { + fprintf(stderr, "bind (server) failed\n"); + return -1; + } + + if(syscall(__NR_listen, server_socket_fd, QUEUE_LENGTH) == -1) + { + fprintf(stderr, "listen failed\n"); + return -1; + } + + // We need to bind the client socket with an address otherwise we cannot assert against it. + if(syscall(__NR_bind, client_socket_fd, (struct sockaddr*)&client_addr, sizeof(client_addr)) == -1) + { + fprintf(stderr, "bind (client) failed\n"); + return -1; + } + + // The connection will be inprogress so we don't check the errno. + syscall(__NR_connect, client_socket_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)); + +#ifdef __NR_socketcall + if(strncmp("__NR_accept", argv[2], sizeof("__NR_accept")) == 0) + { + uint32_t args[3] = {0}; + args[0] = server_socket_fd; + args[1] = 0; + args[2] = 0; + + int connected_socket_fd = syscall(__NR_socketcall, SYS_ACCEPT, (uint32_t*)args); + if(connected_socket_fd == -1) + { + fprintf(stderr, "accept (server) failed\n"); + return -1; + } + syscall(__NR_shutdown, connected_socket_fd, 2); + syscall(__NR_close, connected_socket_fd); + } + + if(strncmp("__NR_sendto", argv[2], sizeof("__NR_sendto")) == 0) + { + char sent_data[NO_SNAPLEN_MESSAGE_LEN] = NO_SNAPLEN_MESSAGE; + uint32_t sendto_flags = 0; + + unsigned long args[6] = {0}; + args[0] = client_socket_fd; + args[1] = (unsigned long)sent_data; + args[2] = sizeof(sent_data); + args[3] = sendto_flags; + args[4] = (unsigned long)&server_addr; + args[5] = sizeof(server_addr); + int64_t sent_bytes = syscall(__NR_socketcall, SYS_SENDTO, args); + if(sent_bytes == -1) + { + fprintf(stderr, "sendto failed\n"); + return -1; + } + } +#endif + syscall(__NR_shutdown, server_socket_fd, 2); + syscall(__NR_shutdown, client_socket_fd, 2); + syscall(__NR_close, server_socket_fd); + syscall(__NR_close, client_socket_fd); + return 0; + } + else + { + fprintf(stderr, "wrong number of args\n"); + return -1; + } fprintf(stderr, "not managed syscall: '%s'\n", argv[1]); return -1; diff --git a/test/drivers/test_suites/actions_suite/ia32.cpp.in b/test/drivers/test_suites/actions_suite/ia32.cpp.in index e506b7aedb..a5ebbfdf41 100644 --- a/test/drivers/test_suites/actions_suite/ia32.cpp.in +++ b/test/drivers/test_suites/actions_suite/ia32.cpp.in @@ -652,4 +652,127 @@ TEST(Actions, ia32_time) } #endif +#ifdef __NR_accept +TEST(Actions, ia32_socketcall_accept) +{ + auto evt_test = get_syscall_event_test(__NR_accept, EXIT_EVENT); + + evt_test->enable_capture(); + + /*=============================== TRIGGER SYSCALL ===========================*/ + pid_t ret_pid = syscall(__NR_fork); + if(ret_pid == 0) + { + const char* argv[] = {"ia32", "__NR_socketcall","__NR_accept", NULL}; + const char* envp[] = {NULL}; + syscall(__NR_execve, "${CMAKE_CURRENT_BINARY_DIR}/ia32", argv, envp); + exit(EXIT_FAILURE); + } + assert_syscall_state(SYSCALL_SUCCESS, "fork", ret_pid, NOT_EQUAL, -1); + int status = 0; + int options = 0; + assert_syscall_state(SYSCALL_SUCCESS, "wait4", syscall(__NR_wait4, ret_pid, &status, options, NULL), NOT_EQUAL, + -1); + + if(__WEXITSTATUS(status) == EXIT_FAILURE || __WIFSIGNALED(status) != 0) + { + FAIL() << "Fork failed..." << std::endl; + } + + /* Disable the capture: no more events from now. */ + evt_test->disable_capture(); + + /* Retrieve events in order. */ + evt_test->assert_event_presence(ret_pid, PPME_SOCKET_ACCEPT_5_X); + + if(HasFatalFailure()) + { + return; + } + + evt_test->parse_event(); + evt_test->assert_header(); + + /*=============================== ASSERT PARAMETERS ===========================*/ + + + /* Parameter 1: fd (type: PT_FD) */ + evt_test->assert_numeric_param(1, (int64_t)0, GREATER_EQUAL); + + /* Parameter 2: tuple (type: PT_SOCKTUPLE) */ + /* The server performs an `accept` so the `client` is the src. */ + evt_test->assert_tuple_inet_param(2, PPM_AF_INET, IPV4_CLIENT, IPV4_SERVER, IPV4_PORT_CLIENT_STRING, IPV4_PORT_SERVER_STRING); + + /* Parameter 3: queuepct (type: PT_UINT8) */ + /* we expect 0 elements in the queue so 0%. */ + evt_test->assert_numeric_param(3, (uint8_t)0); + + /* Parameter 4: queuelen (type: PT_UINT32) */ + /* we expect 0 elements. */ + evt_test->assert_numeric_param(4, (uint32_t)0); + + /* Parameter 5: queuemax (type: PT_UINT32) */ + evt_test->assert_numeric_param(5, (uint32_t)QUEUE_LENGTH); + + /*=============================== ASSERT PARAMETERS ===========================*/ + + evt_test->assert_num_params_pushed(5); +} +#endif + +#ifdef __NR_sendto +TEST(Actions, ia32_socketcall_sendto) +{ + auto evt_test = get_syscall_event_test(__NR_sendto, EXIT_EVENT); + + evt_test->enable_capture(); + + /*=============================== TRIGGER SYSCALL ===========================*/ + pid_t ret_pid = syscall(__NR_fork); + if(ret_pid == 0) + { + const char* argv[] = {"ia32", "__NR_socketcall","__NR_sendto", NULL}; + const char* envp[] = {NULL}; + syscall(__NR_execve, "${CMAKE_CURRENT_BINARY_DIR}/ia32", argv, envp); + exit(EXIT_FAILURE); + } + assert_syscall_state(SYSCALL_SUCCESS, "fork", ret_pid, NOT_EQUAL, -1); + int status = 0; + int options = 0; + assert_syscall_state(SYSCALL_SUCCESS, "wait4", syscall(__NR_wait4, ret_pid, &status, options, NULL), NOT_EQUAL, + -1); + + if(__WEXITSTATUS(status) == EXIT_FAILURE || __WIFSIGNALED(status) != 0) + { + FAIL() << "Fork failed..." << std::endl; + } + + /* Disable the capture: no more events from now. */ + evt_test->disable_capture(); + + /* Retrieve events in order. */ + evt_test->assert_event_presence(ret_pid, PPME_SOCKET_SENDTO_X); + + if(HasFatalFailure()) + { + return; + } + + evt_test->parse_event(); + evt_test->assert_header(); + + /*=============================== ASSERT PARAMETERS ===========================*/ + + /* Parameter 1: res (type: PT_ERRNO) */ + evt_test->assert_numeric_param(1, (int64_t)NO_SNAPLEN_MESSAGE_LEN); + + /* Parameter 2: data (type: PT_BYTEBUF) */ + evt_test->assert_bytebuf_param(2, NO_SNAPLEN_MESSAGE, NO_SNAPLEN_MESSAGE_LEN); + + /*=============================== ASSERT PARAMETERS ===========================*/ + + evt_test->assert_num_params_pushed(2); +} +#endif + #endif