Skip to content

Commit

Permalink
test(drivers): add some tests for ia32 syscalls
Browse files Browse the repository at this point in the history
Signed-off-by: Andrea Terzolo <[email protected]>
  • Loading branch information
Andreagit97 committed May 16, 2024
1 parent 4c993d6 commit 84fb36d
Show file tree
Hide file tree
Showing 3 changed files with 271 additions and 13 deletions.
3 changes: 1 addition & 2 deletions test/drivers/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand All @@ -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})


158 changes: 147 additions & 11 deletions test/drivers/helpers/ia32.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
#include <sys/socket.h>
#include <sys/mman.h>
#include <linux/net.h> /* Definition of SYS_* constants */
#include <arpa/inet.h>
#include <errno.h>
#include <event_class/network_utils.h>

#ifdef __NR_openat2
#include <linux/openat2.h> /* Definition of RESOLVE_* constants */
Expand Down Expand Up @@ -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;
Expand Down
123 changes: 123 additions & 0 deletions test/drivers/test_suites/actions_suite/ia32.cpp.in
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit 84fb36d

Please sign in to comment.