diff --git a/Makefile b/Makefile index 5732580..11fa042 100644 --- a/Makefile +++ b/Makefile @@ -44,7 +44,10 @@ 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/log_memseg.c \ + syscall/param_log/log_string.c \ + syscall/param_log/log_open_flags.c \ + syscall/param_log/log_open_mode.c \ syscall/syscall_handle.c # registers srcs @@ -56,7 +59,8 @@ SRCS += registers/registers_get_param.c \ # signals srcs -SRCS += signals/signals_block.c +SRCS += signals/signals_block.c \ + signals/signals_handle.c OBJS_MAIN_RELEASE := $(addprefix $(OBJSDIR_RELEASE)/,$(SRCS_MAIN:.c=.o)) OBJS_MAIN_DEBUG := $(addprefix $(OBJSDIR_DEBUG)/,$(SRCS_MAIN:.c=.o)) diff --git a/includes/signals_strace.h b/includes/signals_strace.h index 57630cf..946a96c 100644 --- a/includes/signals_strace.h +++ b/includes/signals_strace.h @@ -1,5 +1,8 @@ #pragma once +#include +#include + /** * @brief Block signals * @@ -10,4 +13,11 @@ void signals_block(void); * @brief Unblock signals * */ -void signals_unblock(void); \ No newline at end of file +void signals_unblock(void); + +/** + * @brief Handle the signal raised by the tracee + * + * @param pid the pid of the tracee + */ +int signals_handle(pid_t pid, int *cont_signal, analysis_routine_data_t *data); \ No newline at end of file diff --git a/includes/syscall_strace.h b/includes/syscall_strace.h index 89cf3b7..1859f7c 100644 --- a/includes/syscall_strace.h +++ b/includes/syscall_strace.h @@ -15,6 +15,8 @@ #define HEX 3 #define STRING 4 #define MEMSEG 5 +#define OPEN_FLAGS 6 +#define OPEN_MODE 7 /** * @brief Negative if printed before the syscall, positive if printed after the @@ -111,4 +113,4 @@ bool_t syscall_is_execve(uint64_t syscall_no, register_type_t type); * @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, int cont_signal); \ No newline at end of file +int syscall_handle(pid_t pid, analysis_routine_data_t *data, int *cont_signal); \ No newline at end of file diff --git a/srcs/analysis/analysis_routine.c b/srcs/analysis/analysis_routine.c index 3229e9c..f9e4288 100644 --- a/srcs/analysis/analysis_routine.c +++ b/srcs/analysis/analysis_routine.c @@ -1,12 +1,14 @@ + #include #include #include #include +#include #include +#include #include #include #include -#include /** * @brief Handle the status of the tracee @@ -16,9 +18,8 @@ * @return int the status code of the tracee or NO_STATUS if no status code is * available */ -static int handle_status(int status, int *cont_signal) +static int handle_status(pid_t pid, int status, int *cont_signal, analysis_routine_data_t *data) { - *cont_signal = 0; if (status == NO_STATUS) return NO_STATUS; if (WIFEXITED(status)) @@ -32,38 +33,10 @@ static int handle_status(int status, int *cont_signal) return status; } if (WIFSTOPPED(status)) - { - int sig = WSTOPSIG(status); - if (sig == SIGTRAP || sig == SIGSTOP || sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU) - return NO_STATUS; - *cont_signal = sig; - return SIG_RAISED; - } + return signals_handle(pid, cont_signal, data); return NO_STATUS; } -/** - * @brief Handle the signal raised by the tracee - * - * @param pid the pid of the tracee - */ -static void handle_signal(pid_t pid) -{ - siginfo_t siginfo = {0}; - if (ptrace(PTRACE_GETSIGINFO, pid, 0, &siginfo) < 0) - { - log_error("handle_signal", "ptrace(PTRACE_GETSIGINFO) failed", true); - return; - } - ft_printf("--- %s {si_signo=%s, si_code=%s, si_pid=%d, si_uid=%d} ---\n", - ft_signalname(siginfo.si_signo), - ft_signalname(siginfo.si_signo), - ft_sicodename(siginfo.si_signo, siginfo.si_code), - siginfo.si_pid, - siginfo.si_uid); - -} - /** * @brief Analysis routine of the tracer * @@ -84,26 +57,22 @@ int analysis_routine(pid_t pid) log_error("analysis_routine", "ptrace failed", true); return ROUTINE_ERROR; } + cont_signal = 0; int status; if (waitpid(pid, &status, 0) < 0) { log_error("analysis_routine", "waitpid failed", true); return ROUTINE_ERROR; } - int status_code = handle_status(status, &cont_signal); + int status_code = handle_status(pid, status, &cont_signal, &data); if (status_code == SIG_RAISED) - { - handle_signal(pid); continue; - } if (status_code != NO_STATUS) return status_code; - status_code = handle_status(syscall_handle(pid, &data, cont_signal), &cont_signal); + status_code = + handle_status(pid, syscall_handle(pid, &data, &cont_signal), &cont_signal, &data); if (status_code == SIG_RAISED) - { - handle_signal(pid); continue; - } if (status_code != NO_STATUS) return status_code; } diff --git a/srcs/signals/signals_handle.c b/srcs/signals/signals_handle.c new file mode 100644 index 0000000..2176aa3 --- /dev/null +++ b/srcs/signals/signals_handle.c @@ -0,0 +1,40 @@ +#define _XOPEN_SOURCE +#define _XOPEN_SOURCE_EXTENDED 1 + +#include +#include +#include +#include +#include +#include +#include + +/** + * @brief Handle the signal raised by the tracee + * + * @param pid the pid of the tracee + */ +int signals_handle(pid_t pid, int *cont_signal, analysis_routine_data_t *data) +{ + siginfo_t siginfo = {0}; + if (ptrace(PTRACE_GETSIGINFO, pid, 0, &siginfo) < 0) + { + log_error("handle_signal", "ptrace(PTRACE_GETSIGINFO) failed", true); + return SIG_RAISED; + } + if (siginfo.si_signo == SIGTRAP && siginfo.si_code == TRAP_UNK) + { + return NO_STATUS; + } + if (siginfo.si_signo == SIGSTOP && siginfo.si_code != SI_TKILL) + { + *cont_signal = SIGSTOP; + return SIG_RAISED; + } + if (data->status == ENCOUNTERED) + ft_printf("--- %s {si_signo=%s, si_code=%s, si_pid=%d, si_uid=%d} ---\n", + ft_signalname(siginfo.si_signo), ft_signalname(siginfo.si_signo), + ft_sicodename(siginfo.si_signo, siginfo.si_code), siginfo.si_pid, siginfo.si_uid); + *cont_signal = siginfo.si_signo; + return SIG_RAISED; +} \ No newline at end of file diff --git a/srcs/signals/signals_raise.c b/srcs/signals/signals_raise.c deleted file mode 100644 index e69de29..0000000 diff --git a/srcs/syscall/param_log/param_log_memseg.c b/srcs/syscall/param_log/log_memseg.c similarity index 100% rename from srcs/syscall/param_log/param_log_memseg.c rename to srcs/syscall/param_log/log_memseg.c diff --git a/srcs/syscall/param_log/log_open_flags.c b/srcs/syscall/param_log/log_open_flags.c new file mode 100644 index 0000000..c281144 --- /dev/null +++ b/srcs/syscall/param_log/log_open_flags.c @@ -0,0 +1,58 @@ +#define _GNU_SOURCE + +#include "param_log.h" +#include +#include +#include +#include +#include + +typedef struct { + uint64_t flag; + const char *str; +} flag_str_t; + +#define FLAG_STR(flag) {flag, #flag} + +static const flag_str_t flags[] = { + FLAG_STR(O_RDONLY), + FLAG_STR(O_WRONLY), + FLAG_STR(O_RDWR), + FLAG_STR(O_CREAT), + FLAG_STR(O_EXCL), + FLAG_STR(O_NOCTTY), + FLAG_STR(O_TRUNC), + FLAG_STR(O_APPEND), + FLAG_STR(O_NONBLOCK), + FLAG_STR(O_DSYNC), + FLAG_STR(O_ASYNC), + FLAG_STR(O_DIRECT), + FLAG_STR(O_LARGEFILE), + FLAG_STR(O_DIRECTORY), + FLAG_STR(O_NOFOLLOW), + FLAG_STR(O_NOATIME), + FLAG_STR(O_CLOEXEC), + FLAG_STR(O_PATH), + FLAG_STR(O_TMPFILE), +}; + +/** + * @brief Log open flags + * + * @param value the value to log + */ +void log_OPEN_FLAGS(uint64_t value) +{ + bool_t first = true; + for (size_t i = 0; i < ELEM_COUNT(flags); i++) + { + if (value & flags[i].flag) + { + if (!first) + ft_dprintf(STDERR_FILENO, "|"); + ft_dprintf(STDERR_FILENO, "%s", flags[i].str); + first = false; + value &= ~flags[i].flag; + } + } +} \ No newline at end of file diff --git a/srcs/syscall/param_log/log_open_mode.c b/srcs/syscall/param_log/log_open_mode.c new file mode 100644 index 0000000..53cdfba --- /dev/null +++ b/srcs/syscall/param_log/log_open_mode.c @@ -0,0 +1,12 @@ +#include "param_log.h" +#include + +/** + * @brief Log open mode + * + * @param value the value to log + */ +void log_OPEN_MODE(uint64_t value) +{ + ft_dprintf(STDERR_FILENO, "%#o", value); +} \ No newline at end of file diff --git a/srcs/syscall/param_log/log_string.c b/srcs/syscall/param_log/log_string.c new file mode 100644 index 0000000..f03b61c --- /dev/null +++ b/srcs/syscall/param_log/log_string.c @@ -0,0 +1,65 @@ +#define _GNU_SOURCE + +#include "param_log.h" +#include +#include +#include +#include +#include + +#define DEFAULT_BUFFER_SIZE 32 + +typedef struct +{ + char *buffer; + size_t size_buffer; + size_t index; +} buffer_t; + +static void buffer_add_char(buffer_t *buffer, char c) +{ + if (buffer->index >= buffer->size_buffer) + { + buffer->size_buffer *= 2; + buffer->buffer = realloc(buffer->buffer, buffer->size_buffer); + } + buffer->buffer[buffer->index++] = c; +} + +/** + * @brief log memory segment + * + * @param value the value + * @param context the context + */ +void log_STRING(uint64_t value, syscall_log_param_t *context) +{ + buffer_t buffer = { + .buffer = malloc(DEFAULT_BUFFER_SIZE), + .size_buffer = DEFAULT_BUFFER_SIZE, + .index = 0, + }; + char c = 1; // dummy value that will be overwritten by the first read + while (c != '\0') + { + struct iovec local = { + .iov_base = &c, + .iov_len = 1, + }; + struct iovec remote = { + .iov_base = (void *)value + buffer.index, + .iov_len = 1, + }; + if (process_vm_readv(context->pid, &local, 1, &remote, 1, 0) < 0) + { + log_error("log_STRING", "process_vm_readv failed", true); + free(buffer.buffer); + return; + } + buffer_add_char(&buffer, c); + } + char *escaped_buffer = ft_escape(buffer.buffer, buffer.index - 1); + ft_dprintf(STDERR_FILENO, "\"%s\"", escaped_buffer); + free(escaped_buffer); + free(buffer.buffer); +} \ No newline at end of file diff --git a/srcs/syscall/param_log/param_log.h b/srcs/syscall/param_log/param_log.h index 0331b2a..772a845 100644 --- a/srcs/syscall/param_log/param_log.h +++ b/srcs/syscall/param_log/param_log.h @@ -20,6 +20,28 @@ typedef void (*log_function_t)(); * @brief log memory segment * * @param value the value - * @param context the context + * @param context the context of the syscall */ -void log_MEMSEG(uint64_t value, syscall_log_param_t *context); \ No newline at end of file +void log_MEMSEG(uint64_t value, syscall_log_param_t *context); + +/** + * @brief Log a string + * + * @param value the value + * @param context the context of the syscall + */ +void log_STRING(uint64_t value, syscall_log_param_t *context); + +/** + * @brief Log open flags + * + * @param value the value to log + */ +void log_OPEN_FLAGS(uint64_t value); + +/** + * @brief Log open mode + * + * @param value the value to log + */ +void log_OPEN_MODE(uint64_t value); \ No newline at end of file diff --git a/srcs/syscall/syscall_64.h b/srcs/syscall/syscall_64.h index 546cc8c..8fd04a6 100644 --- a/srcs/syscall/syscall_64.h +++ b/srcs/syscall/syscall_64.h @@ -11,4 +11,6 @@ * ARG_TYPE3, ARG_TYPE4, ARG_TYPE5, ARG_TYPE6 } } */ static const syscall_description_t x86_64_syscalls[] = { [0] = {"read", SIGNED_INT, {-SIGNED_INT, MEMSEG, INT, NONE}}, - [1] = {"write", SIGNED_INT, {-SIGNED_INT, -MEMSEG, -INT, NONE}}}; + [1] = {"write", SIGNED_INT, {-SIGNED_INT, -MEMSEG, -INT, NONE}}, + [2] = {"open", SIGNED_INT, {-STRING, -OPEN_FLAGS, -OPEN_MODE, NONE}}, + [3] = {"close", SIGNED_INT, {-INT, NONE}}}; diff --git a/srcs/syscall/syscall_handle.c b/srcs/syscall/syscall_handle.c index a143f98..bfffa28 100644 --- a/srcs/syscall/syscall_handle.c +++ b/srcs/syscall/syscall_handle.c @@ -5,6 +5,7 @@ #include #include #include +#include /** * @brief Handle the syscall before it is executed @@ -90,18 +91,19 @@ static int handle_syscall_after(pid_t pid, analysis_routine_data_t *data, uint64 * @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, int cont_signal) +int syscall_handle(pid_t pid, analysis_routine_data_t *data, int *cont_signal) { 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, cont_signal) < 0) + if (ptrace(PTRACE_SYSCALL, pid, NULL, *cont_signal) < 0) { log_error("handle_syscall", "ptrace failed", true); return NO_STATUS; } + *cont_signal = 0; int status; if (waitpid(pid, &status, 0) < 0) { diff --git a/srcs/syscall/syscall_log_param.c b/srcs/syscall/syscall_log_param.c index 21db305..15124e5 100644 --- a/srcs/syscall/syscall_log_param.c +++ b/srcs/syscall/syscall_log_param.c @@ -1,5 +1,6 @@ #include "param_log/param_log.h" #include +#include #include #include #include @@ -20,11 +21,6 @@ static void log_HEX(uint64_t value) ft_dprintf(STDERR_FILENO, "%#llx", value); } -static void log_STRING(uint64_t value) -{ - ft_dprintf(STDERR_FILENO, "%#llx", value); -} - static void log_NONE(uint64_t value) { (void)value; @@ -32,10 +28,12 @@ static void log_NONE(uint64_t value) } static const log_function_t log_functions[] = { - [NONE] = log_NONE, [INT] = log_INT, [SIGNED_INT] = log_UNSIGNED_INT, - [HEX] = log_HEX, [STRING] = log_STRING, [MEMSEG] = log_MEMSEG, + [NONE] = log_NONE, [INT] = log_INT, [SIGNED_INT] = log_UNSIGNED_INT, [HEX] = log_HEX, + [STRING] = log_STRING, [MEMSEG] = log_MEMSEG, [OPEN_FLAGS] = log_OPEN_FLAGS, + [OPEN_MODE] = log_OPEN_MODE, }; +typedef void (*log_function_with_param_t)(uint64_t value, syscall_log_param_t *context); /** * @brief Log a syscall parameter * @@ -63,7 +61,10 @@ void syscall_log_param(pid_t pid, user_regs_t *regs, register_type_t regs_type, .type = regs_type, .after_syscall = after_syscall, }; - log_functions[arg_type](arg, ¶m); + if (arg_type < (int)ELEM_COUNT(log_functions)) + ((log_function_with_param_t)log_functions[arg_type])(arg, ¶m); + else + ft_dprintf(STDERR_FILENO, "?"); } /** @@ -93,5 +94,8 @@ void syscall_log_return(pid_t pid, user_regs_t *regs, register_type_t regs_type) .type = regs_type, .after_syscall = true, }; - log_functions[return_type](return_value, ¶m); + if (return_type < (int)ELEM_COUNT(log_functions)) + ((log_function_with_param_t)log_functions[return_type])(return_value, ¶m); + else + ft_dprintf(STDERR_FILENO, "?"); } \ No newline at end of file