From fc0d22e4f16b5a788a5465666d64032d8d5d0d2d Mon Sep 17 00:00:00 2001 From: tmatis Date: Tue, 10 Oct 2023 13:25:11 +0200 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor=20analysis=20rout?= =?UTF-8?q?ine?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 3 +- includes/syscall_strace.h | 28 +++++++- libft/srcs/string/ft_escape.c | 2 +- srcs/analysis/analysis_routine.c | 101 +++----------------------- srcs/syscall/syscall_handle.c | 120 +++++++++++++++++++++++++++++++ 5 files changed, 158 insertions(+), 96 deletions(-) create mode 100644 srcs/syscall/syscall_handle.c diff --git a/Makefile b/Makefile index 7a57e5b..cbd7de3 100644 --- a/Makefile +++ b/Makefile @@ -42,7 +42,8 @@ SRCS += syscall/syscall_get_description.c \ syscall/syscall_log.c \ syscall/syscall_log_param.c \ syscall/syscall_is_execve.c \ - syscall/param_log/param_log_memseg.c + syscall/param_log/param_log_memseg.c \ + syscall/syscall_handle.c # registers srcs diff --git a/includes/syscall_strace.h b/includes/syscall_strace.h index a7ace7a..8b57c1d 100644 --- a/includes/syscall_strace.h +++ b/includes/syscall_strace.h @@ -28,6 +28,23 @@ typedef struct { const arg_type_t arg_types[6]; } syscall_description_t; +#define MAX_SYSCALL_NO 0x17f + +typedef enum +{ + NOT_ENCOUNTERED, + ENCOUNTERED, + ERROR +} execve_status_t; + +typedef struct +{ + execve_status_t status; + register_type_t register_type; +} analysis_routine_data_t; + +#define NO_STATUS -1 + #define ELEM_COUNT(x) (sizeof(x) / sizeof(x[0])) /** @@ -85,4 +102,13 @@ void syscall_log_return(pid_t pid, user_regs_t *regs, register_type_t regs_type) * @param type * @return bool_t true if syscall is execve, false otherwise */ -bool_t syscall_is_execve(uint64_t syscall_no, register_type_t type); \ No newline at end of file +bool_t syscall_is_execve(uint64_t syscall_no, register_type_t type); + +/** + * @brief Handle a syscall + * + * @param pid the pid of the tracee + * @param data the data of the analysis routine + * @return int the status code of the tracee or NO_STATUS if no status code is available + */ +int syscall_handle(pid_t pid, analysis_routine_data_t *data); \ No newline at end of file diff --git a/libft/srcs/string/ft_escape.c b/libft/srcs/string/ft_escape.c index 3e4389f..b0b7d73 100644 --- a/libft/srcs/string/ft_escape.c +++ b/libft/srcs/string/ft_escape.c @@ -116,7 +116,7 @@ char *ft_escape(const char *str, size_t size) escaped_str + j, escaped_size - j, "\\%u", - (unsigned char)str[i] % 256); + (unsigned char)str[i]); if (added < 0) { free(escaped_str); diff --git a/srcs/analysis/analysis_routine.c b/srcs/analysis/analysis_routine.c index 66c9d03..4ba0203 100644 --- a/srcs/analysis/analysis_routine.c +++ b/srcs/analysis/analysis_routine.c @@ -1,104 +1,19 @@ #include -#include -#include -#include #include -#include #include #include #include #include #include -#include -#include -#include -#include #include -#define MAX_SYSCALL_NO 0x14c - -#define SYS_EXECVE 0x3b - -typedef enum -{ - NOT_ENCOUNTERED, - ENCOUNTERED, - ERROR -} execve_status_t; - -typedef struct -{ - execve_status_t status; - register_type_t register_type; -} analysis_routine_data_t; - -#define NO_STATUS -1 - -int handle_syscall(pid_t pid, analysis_routine_data_t *data) -{ - user_regs_t regs_before = {0}; - struct iovec regs_before_iov; - - regs_before_iov.iov_base = ®s_before; - regs_before_iov.iov_len = sizeof(regs_before); - if (ptrace(PTRACE_GETREGSET, pid, (void *)NT_PRSTATUS, ®s_before_iov) < 0) - { - log_error("handle_syscall", "ptrace(PTRACE_GETREGS)(1) failed", true); - return NO_STATUS; - } - register_type_t register_type_before = registers_get_type(regs_before_iov.iov_len); - if (data->register_type != register_type_before) - { - data->register_type = register_type_before; - ft_dprintf(STDERR_FILENO, "[ Process PID=%d runs in 32 bit mode. ]\n", pid); - } - uint64_t syscall_no = registers_get_syscall(®s_before, register_type_before); - if (syscall_no > MAX_SYSCALL_NO) - return NO_STATUS; - - if (ptrace(PTRACE_SYSCALL, pid, NULL, NULL) < 0) - { - log_error("handle_syscall", "ptrace failed", true); - return NO_STATUS; - } - bool_t is_execve = syscall_is_execve(syscall_no, register_type_before); - if (data->status == ERROR && !is_execve) - return NO_STATUS; - if (data->status == NOT_ENCOUNTERED && !is_execve) - return NO_STATUS; - bool_t should_log = data->status == ENCOUNTERED || (data->status != ERROR && is_execve); - if (should_log) - syscall_log_name_params(pid, ®s_before, register_type_before); - int status; - if (waitpid(pid, &status, 0) < 0) - { - log_error("handle_syscall", "waitpid failed", true); - return NO_STATUS; - } - if (WIFEXITED(status) || WIFSIGNALED(status)) - { - ft_dprintf(STDERR_FILENO, ") = ?\n"); - return status; - } - user_regs_t regs_after; - struct iovec regs_after_iov; - - regs_after_iov.iov_base = ®s_after; - regs_after_iov.iov_len = sizeof(regs_after); - if (ptrace(PTRACE_GETREGSET, pid, (void *)NT_PRSTATUS, ®s_after_iov) < 0) - { - log_error("handle_syscall", "ptrace(PTRACE_GETREGS)(2) failed", true); - return NO_STATUS; - } - register_type_t register_type_after = registers_get_type(regs_after_iov.iov_len); - if (data->status == NOT_ENCOUNTERED && syscall_no == SYS_EXECVE) - data->status = (int64_t)registers_get_return(®s_after, register_type_after) < 0 ? ERROR : ENCOUNTERED; - if (should_log) - syscall_log_params_return(pid, syscall_no, ®s_after, register_type_after); - return NO_STATUS; -} - -int handle_status(int status) +/** + * @brief Handle the status of the tracee + * + * @param status the status of the tracee + * @return int the status code of the tracee or NO_STATUS if no status code is available + */ +static int handle_status(int status) { if (status == NO_STATUS) return NO_STATUS; @@ -135,7 +50,7 @@ int analysis_routine(pid_t pid) int status_code = handle_status(status); if (status_code != NO_STATUS) return status_code; - status_code = handle_status(handle_syscall(pid, &data)); + status_code = handle_status(syscall_handle(pid, &data)); if (status_code != NO_STATUS) return status_code; if (ptrace(PTRACE_SYSCALL, pid, NULL, NULL) < 0) diff --git a/srcs/syscall/syscall_handle.c b/srcs/syscall/syscall_handle.c new file mode 100644 index 0000000..d531874 --- /dev/null +++ b/srcs/syscall/syscall_handle.c @@ -0,0 +1,120 @@ +#include +#include +#include +#include +#include +#include +#include + +/** + * @brief Handle the syscall before it is executed + * + * @param pid the pid of the tracee + * @param data the data of the analysis routine + * @param syscall_no the syscall number pointer to be filled + * @param is_execve pointer to be filled with whether the syscall is an execve + * @return int NO_STATUS if the caller must return, 1 if the syscall must be logged, 0 otherwise + */ +static int handle_before_syscall( + pid_t pid, + analysis_routine_data_t *data, + uint64_t *syscall_no, + bool_t *is_execve) +{ + user_regs_t regs_before; + struct iovec regs_before_iov; + + regs_before_iov.iov_base = ®s_before; + regs_before_iov.iov_len = sizeof(regs_before); + if (ptrace(PTRACE_GETREGSET, pid, (void *)NT_PRSTATUS, ®s_before_iov) < 0) + { + log_error("handle_syscall", "ptrace(PTRACE_GETREGS)(1) failed", true); + return NO_STATUS; + } + register_type_t register_type_before = registers_get_type(regs_before_iov.iov_len); + if (data->register_type != register_type_before) + { + data->register_type = register_type_before; + ft_dprintf(STDERR_FILENO, "[ Process PID=%d runs in 32 bit mode. ]\n", pid); + } + *syscall_no = registers_get_syscall(®s_before, register_type_before); + if (*syscall_no > MAX_SYSCALL_NO) + return NO_STATUS; + *is_execve = syscall_is_execve(*syscall_no, register_type_before); + if (data->status == ERROR && !*is_execve) + return NO_STATUS; + if (data->status == NOT_ENCOUNTERED && !*is_execve) + return NO_STATUS; + bool_t should_log = data->status == ENCOUNTERED || (data->status != ERROR && *is_execve); + if (should_log) + syscall_log_name_params(pid, ®s_before, register_type_before); + return should_log; +} + +/** + * @brief Handle the syscall after it is executed + * + * @param pid the pid of the tracee + * @param data the data of the analysis routine + * @param syscall_no the syscall number + * @param should_log whether the syscall should be logged + * @param is_execve whether the syscall is an execve + * @return int NO_STATUS in every case + */ +static int handle_syscall_after( + pid_t pid, + analysis_routine_data_t *data, + uint64_t syscall_no, + int should_log, + bool_t is_execve) +{ + user_regs_t regs_after; + struct iovec regs_after_iov; + + regs_after_iov.iov_base = ®s_after; + regs_after_iov.iov_len = sizeof(regs_after); + if (ptrace(PTRACE_GETREGSET, pid, (void *)NT_PRSTATUS, ®s_after_iov) < 0) + { + log_error("handle_syscall", "ptrace(PTRACE_GETREGS)(2) failed", true); + return NO_STATUS; + } + register_type_t register_type_after = registers_get_type(regs_after_iov.iov_len); + if (data->status == NOT_ENCOUNTERED && is_execve) + data->status = (int64_t)registers_get_return(®s_after, register_type_after) < 0 ? ERROR : ENCOUNTERED; + if (should_log) + syscall_log_params_return(pid, syscall_no, ®s_after, register_type_after); + return NO_STATUS; +} + +/** + * @brief Handle a syscall + * + * @param pid the pid of the tracee + * @param data the data of the analysis routine + * @return int the status code of the tracee or NO_STATUS if no status code is available + */ +int syscall_handle(pid_t pid, analysis_routine_data_t *data) +{ + uint64_t syscall_no; + bool_t is_execve; + int should_log = handle_before_syscall(pid, data, &syscall_no, &is_execve); + if (should_log == NO_STATUS) + return NO_STATUS; + if (ptrace(PTRACE_SYSCALL, pid, NULL, NULL) < 0) + { + log_error("handle_syscall", "ptrace failed", true); + return NO_STATUS; + } + int status; + if (waitpid(pid, &status, 0) < 0) + { + log_error("handle_syscall", "waitpid failed", true); + return NO_STATUS; + } + if (WIFEXITED(status) || WIFSIGNALED(status)) + { + ft_dprintf(STDERR_FILENO, ") = ?\n"); + return status; + } + return handle_syscall_after(pid, data, syscall_no, should_log, is_execve); +} \ No newline at end of file