diff --git a/CMakeLists.txt b/CMakeLists.txt index 55734aef..3c482f8d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -69,9 +69,11 @@ set(SOURCES_C src/disasm_wrapper.c src/intercept.c src/intercept_desc.c + src/intercept_log.c src/intercept_util.c src/patcher.c - src/magic_syscalls.c) + src/magic_syscalls.c + src/syscall_formats.c) set(SOURCES_ASM src/intercept_template.s diff --git a/src/intercept.c b/src/intercept.c index 301cad6b..a6bc1516 100644 --- a/src/intercept.c +++ b/src/intercept.c @@ -54,6 +54,7 @@ #include #include "intercept.h" +#include "intercept_log.h" #include "intercept_util.h" #include "libsyscall_intercept_hook_point.h" #include "disasm_wrapper.h" diff --git a/src/intercept_log.c b/src/intercept_log.c new file mode 100644 index 00000000..c6cf4fe9 --- /dev/null +++ b/src/intercept_log.c @@ -0,0 +1,935 @@ +/* + * Copyright 2016-2017, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "intercept_log.h" +#include "intercept.h" +#include "intercept_util.h" +#include "syscall_formats.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * print_cstr - similar to strcpy, but returns a pointer to the terminating + * null character in the destination string, instead of a count. This is done + * without calling into libc, which is part of an effort to eliminate as many + * libc calls in syscall_intercept as is possible in practice. + * + * Note: sprintf can result in a format string warning when given a variable + * as second argument. This is sort of an fputs for strings, an sputs. + */ +static char * +print_cstr(char *dst, const char *src) +{ + while (*src != '\0') + *dst++ = *src++; + + *dst = '\0'; + + return dst; +} + +/* + * print_number - prints a number in the given base + * A minimum number of digits can requested in the width argument. + * Returns a pointer to end of the destination string. + */ +static char * +print_number(char *dst, unsigned long n, int base, unsigned width) +{ + static const char digit_chars[] = "0123456789abcdef"; + char digits[0x20]; + + assert(base > 0 && (size_t)base < sizeof(digit_chars)); + + digits[sizeof(digits) - 1] = '\0'; + char *c = digits + sizeof(digits) - 1; + if (width >= sizeof(digits) - 1) + width = sizeof(digits) - 2; + + do { + c--; + *c = digit_chars[n % base]; + n /= base; + if (width > 0) + width--; + } while (n > 0 || width > 0); + + while (*c != '\0') + *dst++ = *c++; + + return dst; +} + +/* + * print_hex - prints a 64 but value as a hexadecimal number + */ +static char * +print_hex(char *c, long n) +{ + *c++ = '0'; + *c++ = 'x'; + return print_number(c, (unsigned long)n, 16, 1); +} + +/* + * print_hex - prints a 64 but value as a 16 digit hexadecimal number + * If the number is zero, prints "(null)". + */ +static char * +print_pointer(char *c, long pointer) +{ + if (pointer == 0) + return print_cstr(c, "(null)"); + + *c++ = '0'; + *c++ = 'x'; + return print_number(c, (unsigned long)pointer, 16, 16); +} + +/* + * print_signed_dec - prints a 64 but value as a signed decimal + */ +static char * +print_signed_dec(char *dst, long n) +{ + unsigned long abs_n; + + if (n >= 0) { + abs_n = (unsigned long)n; + } else { + *dst++ = '-'; + abs_n = -((unsigned long)n); + } + + return print_number(dst, abs_n, 10, 1); +} + +/* + * print_signed_dec - prints a 32 but value as a signed decimal + * + * Every syscall argument is captured from the value of the corresponding + * 64 bit register, which might or might not be zero extended. Since the + * print_signed_dec function is only implemented for 64 bit values, a 32 bit + * value must be sign extended before printing. + * Without the explicit sign extenstion (the casts to the second argument in + * the function), such erroneous results can appear in logs, when for example + * calling fstat and lseek with fd number -100: + * + * +--------------------------------------------------------------------+ + * | /lib/libc.so.6 0xf8260 -- fstat(-100, 0x00007ffec24b78f0) = ? | + * | /lib/libc.so.6 0xf8260 -- fstat(-100, 0x00007ffec24b78f0) = 77 | + * | /lib/libc.so.6 0x108da5 -- lseek(4294967196, 99999, SEEK_SET) = ? | + * | /lib/libc.so.6 0x108da5 -- lseek(4294967196, 99999, SEEK_SET) = 77 | + * +--------------------------------------------------------------------+ + * + * Which is the result of libc sign extending in the fstat implementation, but + * not in the lseek implementation. + */ +static char * +print_signed_dec32(char *dst, long n) +{ + return print_signed_dec(dst, (long)(int32_t)n); +} + +/* + * print_octal - prints as an octal number + */ +static char * +print_octal(char *dst, long n) +{ + *dst++ = '0'; + return print_number(dst, (unsigned long)n, 8, 1); +} + +/* + * print_flag - appends a vertical bar separated list of strings with a + * new one, returns a pointer to end of the resulting string. + * The buffer_start argument is expected to point to the beginning of + * the list (where no separator is needed), and the c argument is treated + * as current iterator in the list. + */ +static char * +print_flag(char *buffer_start, char *c, const char *flag_name) +{ + if (c != buffer_start) + c = print_cstr(c, " | "); + + return c = print_cstr(c, flag_name); +} + +struct flag_desc { + long flag; + const char *printable_name; +}; + +#define FLAG_ENTRY(flag_macro) \ + { .flag = flag_macro, .printable_name = #flag_macro } + +/* + * print_flag_set + * Prints a set of flags which are set in an integer. The names and values of + * the possible flags are taken from an array passed as the fourth argument. + * All flags in the array are expected to be distinct, and non-zero. + */ +static char * +print_flag_set(char *buffer_start, char *c, long flags, + const struct flag_desc *desc) +{ + while (flags != 0 && desc->flag != 0) { + if ((flags & desc->flag) != 0) { + c = print_flag(buffer_start, c, desc->printable_name); + flags &= ~desc->flag; + } + desc++; + } + + if (flags != 0) { + if (c != buffer_start) + c = print_cstr(c, " | "); + c = print_hex(c, flags); + } + + if (c == buffer_start) + c = print_cstr(c, "0"); + + return c; +} + +static const struct flag_desc clone_flags[] = { + FLAG_ENTRY(CLONE_CHILD_CLEARTID), + FLAG_ENTRY(CLONE_CHILD_SETTID), + FLAG_ENTRY(CLONE_FILES), + FLAG_ENTRY(CLONE_FS), + FLAG_ENTRY(CLONE_IO), +#ifdef CLONE_NEWCGROUP + FLAG_ENTRY(CLONE_NEWCGROUP), +#endif +#ifdef CLONE_NEWIPC + FLAG_ENTRY(CLONE_NEWIPC), +#endif +#ifdef CLONE_NEWNET + FLAG_ENTRY(CLONE_NEWNET), +#endif +#ifdef CLONE_NEWNS + FLAG_ENTRY(CLONE_NEWNS), +#endif +#ifdef CLONE_NEWPID + FLAG_ENTRY(CLONE_NEWPID), +#endif + FLAG_ENTRY(CLONE_NEWUSER), +#ifdef CLONE_NEWUTS + FLAG_ENTRY(CLONE_NEWUTS), +#endif + FLAG_ENTRY(CLONE_PARENT), + FLAG_ENTRY(CLONE_PARENT_SETTID), + FLAG_ENTRY(CLONE_PTRACE), + FLAG_ENTRY(CLONE_SETTLS), + FLAG_ENTRY(CLONE_SIGHAND), + FLAG_ENTRY(CLONE_SYSVSEM), + FLAG_ENTRY(CLONE_THREAD), + FLAG_ENTRY(CLONE_UNTRACED), + FLAG_ENTRY(CLONE_VFORK), + FLAG_ENTRY(CLONE_VM), + { .flag = 0, } +}; + +/* + * xprint_escape + * Prints a user provided buffer (in src) as printable characters (to dst). + * The zero_term argument specifies if it is a zero terminated buffer, e.g. + * used with SYS_open, SYS_stat, or a buffer with a specified length, e.g. + * used with SYS_write. + * No more than dst_size characters are written. + * + * Returns the pointer advanced while printing. + */ +static char * +xprint_escape(char *restrict dst, const char *restrict src, + size_t dst_size, bool zero_term, size_t src_size) +{ + char *dst_end = dst + dst_size - 5; + + if (src == NULL) + return print_cstr(dst, "(null)"); + + *dst++ = '"'; + while (dst < dst_end && (zero_term || src_size > 0)) { + if (zero_term && *src == 0) + break; + + if (*src == '\"') { + *dst++ = '\\'; + *dst++ = '"'; + } else if (*src == '\\') { + *dst++ = '\\'; + *dst++ = '\\'; + } else if (isprint(*src)) { + *dst++ = *src; + } else { + *dst++ = '\\'; + if (*src == '\n') { + *dst++ = 'n'; + } else if (*src == '\t') { + *dst++ = 't'; + } else if (*src == '\r') { + *dst++ = 'r'; + } else if (*src == '\a') { + *dst++ = 'a'; + } else if (*src == '\b') { + *dst++ = 'b'; + } else if (*src == '\f') { + *dst++ = 'f'; + } else if (*src == '\v') { + *dst++ = 'v'; + } else if (*src == '\0') { + *dst++ = '0'; + } else { + *dst++ = 'x'; + dst = print_number(dst, + (unsigned char)*src, 16, 2); + } + + } + + ++src; + + if (!zero_term) + --src_size; + } + + if ((src_size > 0 && !zero_term) || (zero_term && *src != 0)) + dst = print_cstr(dst, "..."); + + *dst++ = '"'; + *dst = 0; + + return dst; +} + +typedef char *(*arg_printer_func)(char *buffer, const struct syscall_desc *, + int arument_index, enum intercept_log_result, + long result); + +typedef char *(*return_value_printer_func)(char *buffer, long value); + +static char * +arg_print_signed_dec(char *buffer, const struct syscall_desc *desc, int i, + enum intercept_log_result result_status, + long result) +{ + (void) result_status; + (void) result; + + return print_signed_dec(buffer, desc->args[i]); +} + +static char * +arg_print_signed_dec32(char *buffer, const struct syscall_desc *desc, int i, + enum intercept_log_result result_status, + long result) +{ + (void) result_status; + (void) result; + + return print_signed_dec32(buffer, desc->args[i]); +} + +static char * +arg_print_octal_mode(char *buffer, const struct syscall_desc *desc, int i, + enum intercept_log_result result_status, + long result) +{ + (void) result_status; + (void) result; + + return print_octal(buffer, desc->args[i]); +} + +static char * +arg_print_pointer(char *buffer, const struct syscall_desc *desc, int i, + enum intercept_log_result result_status, + long result) +{ + (void) result_status; + (void) result; + + return print_pointer(buffer, desc->args[i]); +} + +static char * +arg_print_general(char *buffer, const struct syscall_desc *desc, int i, + enum intercept_log_result result_status, + long result) +{ + (void) result_status; + (void) result; + + return print_hex(buffer, desc->args[i]); +} + +static char * +arg_print_atfd(char *buffer, const struct syscall_desc *desc, int i, + enum intercept_log_result result_status, + long result) +{ + (void) result_status; + (void) result; + + int fd = (int32_t)desc->args[i]; + if (fd == AT_FDCWD) + return print_cstr(buffer, "AT_FDCWD"); + + return print_signed_dec32(buffer, fd); +} + +static const struct flag_desc open_flags[] = { +#ifdef O_EXEC + FLAG_ENTRY(O_EXEC), +#endif +#ifdef O_SEARCH + FLAG_ENTRY(O_SEARCH), +#endif + FLAG_ENTRY(O_APPEND), + FLAG_ENTRY(O_CLOEXEC), + FLAG_ENTRY(O_CREAT), + FLAG_ENTRY(O_DIRECTORY), + FLAG_ENTRY(O_DSYNC), + FLAG_ENTRY(O_EXCL), + FLAG_ENTRY(O_NOCTTY), + FLAG_ENTRY(O_NOFOLLOW), + FLAG_ENTRY(O_NONBLOCK), + FLAG_ENTRY(O_RSYNC), + FLAG_ENTRY(O_SYNC), + FLAG_ENTRY(O_TRUNC), +#ifdef O_TTY_INIT + FLAG_ENTRY(O_TTY_INIT), +#endif + { .flag = 0, } +}; + +static char * +arg_print_open_flags(char *buffer, const struct syscall_desc *desc, int i, + enum intercept_log_result result_status, + long result) +{ + (void) result_status; + (void) result; + + char *c = buffer; + int flags = (int)desc->args[i]; + + if (flags == 0) + return print_cstr(c, "O_RDONLY"); + + switch (flags & O_ACCMODE) { + case O_RDWR: + c = print_flag(buffer, c, "O_RDWR"); + break; + case O_WRONLY: + c = print_flag(buffer, c, "O_WRONLY"); + break; + case O_RDONLY: + c = print_flag(buffer, c, "O_RDONLY"); + break; + } + + flags &= ~(O_RDONLY | O_WRONLY | O_RDWR); + + buffer = print_flag_set(buffer, c, flags, open_flags); + + return buffer; +} + +static char * +arg_print_cstr(char *buffer, const struct syscall_desc *desc, int i, + enum intercept_log_result result_status, + long result) +{ + (void) result_status; + (void) result; + + if (desc->args[i] == 0) + return print_pointer(buffer, desc->args[i]); + + const char *str = (const char *)(uintptr_t)(desc->args[i]); + return xprint_escape(buffer, str, 0x80, true, 0); +} + +static char * +arg_print_input_buf(char *buffer, const struct syscall_desc *desc, int i, + enum intercept_log_result result_status, + long result) +{ + (void) result_status; + (void) result; + + if (desc->args[i] == 0) + return print_pointer(buffer, desc->args[i]); + + const char *output = (const char *)(uintptr_t)(desc->args[i]); + size_t size = (size_t)desc->args[i + 1]; + return xprint_escape(buffer, output, 0x80, false, size); +} + +static char * +arg_print_output_buf(char *buffer, const struct syscall_desc *desc, int i, + enum intercept_log_result result_status, + long result) +{ + if (buffer == 0 || result_status == UNKNOWN || result < 0) + return print_pointer(buffer, desc->args[i]); + + const char *input = (const char *)(uintptr_t)(desc->args[i]); + size_t size = (size_t)result; + return xprint_escape(buffer, input, 0x80, false, size); +} + +static const struct flag_desc pipe2_flags[] = { + FLAG_ENTRY(O_CLOEXEC), +#ifdef O_DIRECT + FLAG_ENTRY(O_DIRECT), +#endif + FLAG_ENTRY(O_NONBLOCK), + { .flag = 0, } +}; + +static const struct flag_desc access_modes[] = { + FLAG_ENTRY(R_OK), + FLAG_ENTRY(W_OK), + FLAG_ENTRY(X_OK), + { .flag = 0, } +}; + +static const struct flag_desc flock_type[] = { + FLAG_ENTRY(F_RDLCK), + FLAG_ENTRY(F_WRLCK), + FLAG_ENTRY(F_UNLCK), + { .flag = 0, } +}; + +static char * +print_seek_whence(char *buffer, int whence) +{ + switch (whence) { + case SEEK_SET: + return print_cstr(buffer, "SEEK_SET"); + case SEEK_CUR: + return print_cstr(buffer, "SEEK_CUR"); + case SEEK_END: + return print_cstr(buffer, "SEEK_END"); + case SEEK_DATA: + return print_cstr(buffer, "SEEK_DATA"); + case SEEK_HOLE: + return print_cstr(buffer, "SEEK_HOLE"); + default: + return print_hex(buffer, whence); + } +} + +static const struct flag_desc fcntl_cmds[] = { + FLAG_ENTRY(F_DUPFD), + FLAG_ENTRY(F_DUPFD_CLOEXEC), + FLAG_ENTRY(F_GETFD), + FLAG_ENTRY(F_SETFD), + FLAG_ENTRY(F_GETFL), + FLAG_ENTRY(F_SETFL), + FLAG_ENTRY(F_SETLK), + FLAG_ENTRY(F_SETLKW), + FLAG_ENTRY(F_GETLK), +#ifdef F_OFD_SETLK + FLAG_ENTRY(F_OFD_SETLK), + FLAG_ENTRY(F_OFD_SETLKW), + FLAG_ENTRY(F_OFD_GETLK), +#endif + FLAG_ENTRY(F_GETOWN), + FLAG_ENTRY(F_SETOWN), + FLAG_ENTRY(F_GETOWN_EX), + FLAG_ENTRY(F_SETOWN_EX), + FLAG_ENTRY(F_GETSIG), + FLAG_ENTRY(F_SETSIG), + FLAG_ENTRY(F_SETLEASE), + FLAG_ENTRY(F_GETLEASE), + FLAG_ENTRY(F_NOTIFY), + FLAG_ENTRY(F_SETPIPE_SZ), + FLAG_ENTRY(F_GETPIPE_SZ), +#ifdef F_ADD_SEALS + FLAG_ENTRY(F_ADD_SEALS), + FLAG_ENTRY(F_GET_SEALS), + FLAG_ENTRY(F_SEAL_SEAL), + FLAG_ENTRY(F_SEAL_SHRINK), + FLAG_ENTRY(F_SEAL_GROW), + FLAG_ENTRY(F_SEAL_WRITE), +#endif + { .flag = 0, } +}; + +static char * +print_fcntl_cmd(char *buffer, int cmd) +{ + for (const struct flag_desc *d = fcntl_cmds; d->flag != 0; ++d) { + if (d->flag == cmd) + return print_cstr(buffer, d->printable_name); + } + + return print_cstr(buffer, "unknown"); +} + +static char * +print_fcntl_flock(char *buffer, long arg) +{ + if (arg == 0) + return buffer; + + struct flock *fl = (struct flock *)arg; + + /* + * Printing in following format: + * " ({.l_type = %d (%s)," + * " .l_whence = %d (%s)," + * " .l_start = %ld, + * " .l_len = %ld, + * " .l_pid = %d})" + */ + buffer = print_cstr(buffer, " ({.l_type = "); + buffer = print_signed_dec(buffer, fl->l_type); + buffer = print_cstr(buffer, " ("); + buffer = print_flag_set(buffer, buffer, fl->l_type, flock_type); + buffer = print_cstr(buffer, " ), .l_whence = "); + buffer = print_signed_dec(buffer, fl->l_whence); + buffer = print_cstr(buffer, " ("); + buffer = print_seek_whence(buffer, fl->l_whence); + buffer = print_cstr(buffer, " ), .l_start = "); + buffer = print_signed_dec(buffer, fl->l_start); + buffer = print_cstr(buffer, ", .l_len = "); + buffer = print_signed_dec(buffer, fl->l_len); + buffer = print_cstr(buffer, ", .l_pid = "); + buffer = print_signed_dec(buffer, fl->l_pid); + buffer = print_cstr(buffer, "})"); + + return buffer; +} + + +static char * +arg_print_fcntl_args(char *buffer, const struct syscall_desc *desc, int i, + enum intercept_log_result result_status, + long result) +{ + (void) result_status; + (void) result; + + int cmd = (int)desc->args[i]; + + buffer = print_signed_dec(buffer, cmd); + buffer = print_cstr(buffer, " ("); + buffer = print_fcntl_cmd(buffer, cmd); + buffer = print_cstr(buffer, "), "); + buffer = print_pointer(buffer, desc->args[i + 1]); + + switch (cmd) { + case F_GETLK: + case F_SETLK: + case F_SETLKW: + case F_OFD_GETLK: + case F_OFD_SETLK: + case F_OFD_SETLKW: + buffer = print_fcntl_flock(buffer, desc->args[i + 1]); + break; + } + + return buffer; +} + +static char * +arg_print_clone_flags(char *buffer, const struct syscall_desc *desc, int i, + enum intercept_log_result result_status, + long result) +{ + (void) result_status; + (void) result; + long flags = desc->args[i]; + return print_flag_set(buffer, buffer, flags, clone_flags); +} + +static char * +arg_print_seek_whence(char *buffer, const struct syscall_desc *desc, int i, + enum intercept_log_result result_status, + long result) +{ + (void) result_status; + (void) result; + + return print_seek_whence(buffer, (int)desc->args[i]); +} + +static char * +arg_print_2fds(char *buffer, const struct syscall_desc *desc, int i, + enum intercept_log_result result_status, + long result) +{ + (void) result; + + if (buffer == NULL || result_status == UNKNOWN) + return print_pointer(buffer, desc->args[i]); + + int *fds = (int *)desc->args[i]; + buffer = print_cstr(buffer, "["); + buffer = print_signed_dec(buffer, fds[0]); + buffer = print_cstr(buffer, ", "); + buffer = print_signed_dec(buffer, fds[1]); + buffer = print_cstr(buffer, "]"); + + return buffer; +} + +static char * +arg_print_pipe2_flags(char *buffer, const struct syscall_desc *desc, int i, + enum intercept_log_result result_status, + long result) +{ + (void) result_status; + (void) result; + return print_flag_set(buffer, buffer, desc->args[i], pipe2_flags); +} + +static char * +arg_print_access_mode(char *buffer, const struct syscall_desc *desc, int i, + enum intercept_log_result result_status, + long result) +{ + (void) result_status; + (void) result; + int mode = desc->args[i]; + if (mode == F_OK) + return print_cstr(buffer, "F_OK"); + + return print_flag_set(buffer, buffer, mode, access_modes); +} + +static const arg_printer_func arg_printer_func_table[] = { + [arg_] = arg_print_general, + [arg_dec] = arg_print_signed_dec, + [arg_dec32] = arg_print_signed_dec32, + [arg_oct_mode] = arg_print_octal_mode, + [arg_pointer] = arg_print_pointer, + [arg_open_flags] = arg_print_open_flags, + [arg_fd] = arg_print_signed_dec32, + [arg_atfd] = arg_print_atfd, + [arg_cstr] = arg_print_cstr, + [arg_buf_in] = arg_print_input_buf, + [arg_buf_out] = arg_print_output_buf, + [arg_fcntl_args] = arg_print_fcntl_args, + [arg_clone_flags] = arg_print_clone_flags, + [arg_seek_whence] = arg_print_seek_whence, + [arg_2fds] = arg_print_2fds, + [arg_pipe2_flags] = arg_print_pipe2_flags, + [arg_access_mode] = arg_print_access_mode +}; + +static const return_value_printer_func return_value_printer_table[] = { + [rpointer] = print_pointer, + [rhex] = print_hex, + [rdec] = print_signed_dec, + [rmode] = print_octal +}; + +static int log_fd = -1; + +/* + * intercept_setup_log + * Open (create) a log file. If requested, the current processes pid + * number is attached to the path. + */ +void +intercept_setup_log(const char *path, const char *trunc) +{ + char full_path[PATH_MAX]; + + if (path == NULL || path[0] == '\0') + return; + + char *c = full_path; + while ((*c = *path) != '\0') { + c++; + path++; + } + + /* c points to the terminating null */ + if (c[-1] == '-') { + /* if the last char was '-', append the pid to the path */ + long pid = syscall_no_intercept(SYS_getpid); + if (pid < 0) + return; + + print_number(c, pid, 10, 0); + } + + int flags = O_CREAT | O_RDWR | O_APPEND | O_TRUNC; + if (trunc && trunc[0] == '0') + flags &= ~O_TRUNC; + + intercept_log_close(); /* in case a log was already open */ + + log_fd = (int)syscall_no_intercept(SYS_open, full_path, flags, 0700); + + xabort_on_syserror(log_fd, "opening log"); +} + +static char * +print_return_value(char *c, enum return_type type, long value) +{ + if (value > -4096 && value < 0) { + c = print_signed_dec(c, value); + *c++ = ' '; + return print_cstr(c, strerror_no_intercept(-value)); + } + + return return_value_printer_table[type](c, value); +} + +static char * +print_syscall(char *c, const struct syscall_desc *desc, + enum intercept_log_result result_known, long result) +{ + const struct syscall_format *format = get_syscall_format(desc); + + if (format->name != NULL) { + /* known syscall, e.g.: "open(" */ + c = print_cstr(c, format->name); + c = print_cstr(c, "("); + } else { + /* unknown syscall, e.g.: "syscall(456, " */ + c = print_cstr(c, "syscall("); + c = print_signed_dec(c, desc->nr); + c = print_cstr(c, ", "); + } + + for (int i = 0; format->args[i] != arg_none; ++i) { + if (i != 0) + c = print_cstr(c, ", "); + + arg_printer_func func = arg_printer_func_table[format->args[i]]; + c = func(c, desc, i, result_known, result); + } + c = print_cstr(c, ")"); + + if (format->return_type != rnoreturn) { + c = print_cstr(c, " = "); + if (result_known == KNOWN) + c = print_return_value(c, format->return_type, result); + else + *c++ = '?'; + } + + return c; +} + +/* + * Log syscalls after intercepting, in a human readable ( as much as possible ) + * format. The format is either: + * + * offset -- name(arguments...) = result + * + * where the name is known, or + * + * offset -- syscall(syscall_number, arguments...) = result + * + * where the name is not known. + * + * Each line starts with the offset of the syscall instruction in libc's ELF. + * This should be easy to pass to addr2line, to see in what symbol in libc + * the syscall was initiated. + * + * E.g.: + * 0xdaea2 -- fstat(1, 0x7ffd115206f0) = 0 + * + * Each syscall should be logged after being executed, so the result can be + * logged as well. + */ +void +intercept_log_syscall(const struct patch_desc *patch, + const struct syscall_desc *desc, + enum intercept_log_result result_known, long result) +{ + if (log_fd < 0) + return; + + char buffer[0x1000]; + char *c = buffer; + + /* prefix: "/lib/libc.so 0x1234 -- " */ + c = print_cstr(c, patch->containing_lib_path); + c = print_cstr(c, " "); + c = print_hex(c, patch->syscall_offset); + c = print_cstr(c, " -- "); + + c = print_syscall(c, desc, result_known, result); + + *c++ = '\n'; + + syscall_no_intercept(SYS_write, log_fd, buffer, c - buffer); +} + +/* + * intercept_log + * Write a buffer to the log, with a specified length. + * No conversion is done to make it human readable. + */ +void +intercept_log(const char *buffer, size_t len) +{ + if (log_fd >= 0) + syscall_no_intercept(SYS_write, log_fd, buffer, len); +} + +/* + * intercept_log_close + * Closes the log, if one was open. + */ +void +intercept_log_close(void) +{ + if (log_fd >= 0) { + syscall_no_intercept(SYS_close, log_fd); + log_fd = -1; + } +} diff --git a/src/intercept_log.h b/src/intercept_log.h new file mode 100644 index 00000000..9f500796 --- /dev/null +++ b/src/intercept_log.h @@ -0,0 +1,53 @@ +/* + * Copyright 2016-2017, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef INTERCEPT_LOG_H +#define INTERCEPT_LOG_H + +#include + +struct patch_desc; +struct syscall_desc; + +void intercept_setup_log(const char *path_base, const char *trunc); +void intercept_log(const char *buffer, size_t len); + +enum intercept_log_result { KNOWN, UNKNOWN }; + +void intercept_log_syscall(const struct patch_desc *, + const struct syscall_desc *, + enum intercept_log_result result_known, + long result); + +void intercept_log_close(void); + +#endif diff --git a/src/intercept_util.c b/src/intercept_util.c index 88fb5bc8..559ca5e4 100644 --- a/src/intercept_util.c +++ b/src/intercept_util.c @@ -35,6 +35,7 @@ #include "libsyscall_intercept_hook_point.h" #include +#include #include #include #include @@ -49,8 +50,6 @@ #include #include -static int log_fd = -1; - void * xmmap_anon(size_t size) { @@ -102,1502 +101,414 @@ xread(long fd, void *buffer, size_t size) xabort_errno(syscall_error_code(result), __func__); } -/* - * intercept_setup_log - * Open (create) a log file. If requested, the current processes pid - * number is attached to the path. - */ -void -intercept_setup_log(const char *path_base, const char *trunc) -{ - char full_path[PATH_MAX]; - const char *path = path_base; - - if (path_base == NULL) - return; - - if (path_base[strlen(path_base) - 1] == '-') { - snprintf(full_path, sizeof(full_path), "%s%ld", - path_base, - syscall_no_intercept(SYS_getpid)); - - path = full_path; - } - - int flags = O_CREAT | O_RDWR | O_APPEND | O_TRUNC; - if (trunc && trunc[0] == '0') - flags &= ~O_TRUNC; - - intercept_log_close(); - - log_fd = (int)syscall_no_intercept(SYS_open, path, flags, (mode_t)0700); - - xabort_on_syserror(log_fd, "opening log"); -} - -/* - * print_open_flags - * Parses and prints open syscall specific flags to the buffer passed as the - * first argument. - * Returns a pointer pointing to the first char right after the just - * printed strings. - */ -static char * -print_open_flags(char *buffer, int flags) -{ - char *c = buffer; - - *c = 0; - - if (flags == 0) - return c + sprintf(c, "O_RDONLY"); - -#ifdef O_EXEC - if ((flags & O_EXEC) == O_EXEC) - c += sprintf(c, "O_EXEC | "); -#endif - if ((flags & O_RDWR) == O_RDWR) - c += sprintf(c, "O_RDWR | "); - if ((flags & O_WRONLY) == O_WRONLY) - c += sprintf(c, "O_WRONLY | "); - if ((flags & (O_WRONLY|O_RDWR)) == 0) - c += sprintf(c, "O_RDONLY | "); -#ifdef O_SEARCH - if ((flags & O_SEARCH) = O_SEARCH) - c += sprintf(c, "O_SEARCH | "); -#endif - if ((flags & O_APPEND) == O_APPEND) - c += sprintf(c, "O_APPEND | "); - if ((flags & O_CLOEXEC) == O_CLOEXEC) - c += sprintf(c, "O_CLOEXEC | "); - if ((flags & O_CREAT) == O_CREAT) - c += sprintf(c, "O_CREAT | "); - if ((flags & O_DIRECTORY) == O_DIRECTORY) - c += sprintf(c, "O_DIRECTORY | "); - if ((flags & O_DSYNC) == O_DSYNC) - c += sprintf(c, "O_DSYNC | "); - if ((flags & O_EXCL) == O_EXCL) - c += sprintf(c, "O_EXCL | "); - if ((flags & O_NOCTTY) == O_NOCTTY) - c += sprintf(c, "O_NOCTTY | "); - if ((flags & O_NOFOLLOW) == O_NOFOLLOW) - c += sprintf(c, "O_NOFOLLOW | "); - if ((flags & O_NONBLOCK) == O_NONBLOCK) - c += sprintf(c, "O_NONBLOCK | "); - if ((flags & O_RSYNC) == O_RSYNC) - c += sprintf(c, "O_RSYNC | "); - if ((flags & O_SYNC) == O_SYNC) - c += sprintf(c, "O_SYNC | "); - if ((flags & O_TRUNC) == O_TRUNC) - c += sprintf(c, "O_TRUNC | "); -#ifdef O_TTY_INIT - if ((flags & O_TTY_INIT) == O_TTY_INIT) - c += sprintf(c, "O_TTY_INIT | "); +/* BEGIN CSTYLED */ +static const char *const error_strings[] = { +#ifdef EPERM + [EPERM] = "EPERM (Operation not permitted)", #endif - -#ifdef O_EXEC - flags &= ~O_EXEC; +#ifdef ENOENT + [ENOENT] = "ENOENT (No such file or directory)", #endif -#ifdef O_TTY_INIT - flags &= ~O_TTY_INIT; +#ifdef ESRCH + [ESRCH] = "ESRCH (No such process)", #endif -#ifdef O_SEARCH - flags &= ~O_SEARCH; +#ifdef EINTR + [EINTR] = "EINTR (Interrupted system call)", #endif +#ifdef EIO + [EIO] = "EIO (I/O error)", +#endif +#ifdef ENXIO + [ENXIO] = "ENXIO (No such device or address)", +#endif +#ifdef E2BIG + [E2BIG] = "E2BIG (Argument list too long)", +#endif +#ifdef ENOEXEC + [ENOEXEC] = "ENOEXEC (Exec format error)", +#endif +#ifdef EBADF + [EBADF] = "EBADF (Bad file number)", +#endif +#ifdef ECHILD + [ECHILD] = "ECHILD (No child processes)", +#endif +#ifdef EAGAIN + [EAGAIN] = "EAGAIN (Try again)", +#endif +#ifdef ENOMEM + [ENOMEM] = "ENOMEM (Out of memory)", +#endif +#ifdef EACCES + [EACCES] = "EACCES (Permission denied)", +#endif +#ifdef EFAULT + [EFAULT] = "EFAULT (Bad address)", +#endif +#ifdef ENOTBLK + [ENOTBLK] = "ENOTBLK (Block device required)", +#endif +#ifdef EBUSY + [EBUSY] = "EBUSY (Device or resource busy)", +#endif +#ifdef EEXIST + [EEXIST] = "EEXIST (File exists)", +#endif +#ifdef EXDEV + [EXDEV] = "EXDEV (Cross-device link)", +#endif +#ifdef ENODEV + [ENODEV] = "ENODEV (No such device)", +#endif +#ifdef ENOTDIR + [ENOTDIR] = "ENOTDIR (Not a directory)", +#endif +#ifdef EISDIR + [EISDIR] = "EISDIR (Is a directory)", +#endif +#ifdef EINVAL + [EINVAL] = "EINVAL (Invalid argument)", +#endif +#ifdef ENFILE + [ENFILE] = "ENFILE (File table overflow)", +#endif +#ifdef EMFILE + [EMFILE] = "EMFILE (Too many open files)", +#endif +#ifdef ENOTTY + [ENOTTY] = "ENOTTY (Not a typewriter)", +#endif +#ifdef ETXTBSY + [ETXTBSY] = "ETXTBSY (Text file busy)", +#endif +#ifdef EFBIG + [EFBIG] = "EFBIG (File too large)", +#endif +#ifdef ENOSPC + [ENOSPC] = "ENOSPC (No space left on device)", +#endif +#ifdef ESPIPE + [ESPIPE] = "ESPIPE (Illegal seek)", +#endif +#ifdef EROFS + [EROFS] = "EROFS (Read-only file system)", +#endif +#ifdef EMLINK + [EMLINK] = "EMLINK (Too many links)", +#endif +#ifdef EPIPE + [EPIPE] = "EPIPE (Broken pipe)", +#endif +#ifdef EDOM + [EDOM] = "EDOM (Math argument out of domain of func)", +#endif +#ifdef ERANGE + [ERANGE] = "ERANGE (Math result not representable)", +#endif +#ifdef EDEADLK + [EDEADLK] = "EDEADLK (Resource deadlock would occur)", +#endif +#ifdef ENAMETOOLONG + [ENAMETOOLONG] = "ENAMETOOLONG (File name too long)", +#endif +#ifdef ENOLCK + [ENOLCK] = "ENOLCK (No record locks available)", +#endif +#ifdef ENOSYS + [ENOSYS] = "ENOSYS (Invalid system call number)", +#endif +#ifdef ENOTEMPTY + [ENOTEMPTY] = "ENOTEMPTY (Directory not empty)", +#endif +#ifdef ELOOP + [ELOOP] = "ELOOP (Too many symbolic links encountered)", +#endif +#ifdef ENOMSG + [ENOMSG] = "ENOMSG (No message of desired type)", +#endif +#ifdef EIDRM + [EIDRM] = "EIDRM (Identifier removed)", +#endif +#ifdef ECHRNG + [ECHRNG] = "ECHRNG (Channel number out of range)", +#endif +#ifdef EL2NSYNC + [EL2NSYNC] = "EL2NSYNC (Level 2 not synchronized)", +#endif +#ifdef EL3HLT + [EL3HLT] = "EL3HLT (Level 3 halted)", +#endif +#ifdef EL3RST + [EL3RST] = "EL3RST (Level 3 reset)", +#endif +#ifdef ELNRNG + [ELNRNG] = "ELNRNG (Link number out of range)", +#endif +#ifdef EUNATCH + [EUNATCH] = "EUNATCH (Protocol driver not attached)", +#endif +#ifdef ENOCSI + [ENOCSI] = "ENOCSI (No CSI structure available)", +#endif +#ifdef EL2HLT + [EL2HLT] = "EL2HLT (Level 2 halted)", +#endif +#ifdef EBADE + [EBADE] = "EBADE (Invalid exchange)", +#endif +#ifdef EBADR + [EBADR] = "EBADR (Invalid request descriptor)", +#endif +#ifdef EXFULL + [EXFULL] = "EXFULL (Exchange full)", +#endif +#ifdef ENOANO + [ENOANO] = "ENOANO (No anode)", +#endif +#ifdef EBADRQC + [EBADRQC] = "EBADRQC (Invalid request code)", +#endif +#ifdef EBADSLT + [EBADSLT] = "EBADSLT (Invalid slot)", +#endif +#ifdef EBFONT + [EBFONT] = "EBFONT (Bad font file format)", +#endif +#ifdef ENOSTR + [ENOSTR] = "ENOSTR (Device not a stream)", +#endif +#ifdef ENODATA + [ENODATA] = "ENODATA (No data available)", +#endif +#ifdef ETIME + [ETIME] = "ETIME (Timer expired)", +#endif +#ifdef ENOSR + [ENOSR] = "ENOSR (Out of streams resources)", +#endif +#ifdef ENONET + [ENONET] = "ENONET (Machine is not on the network)", +#endif +#ifdef ENOPKG + [ENOPKG] = "ENOPKG (Package not installed)", +#endif +#ifdef EREMOTE + [EREMOTE] = "EREMOTE (Object is remote)", +#endif +#ifdef ENOLINK + [ENOLINK] = "ENOLINK (Link has been severed)", +#endif +#ifdef EADV + [EADV] = "EADV (Advertise error)", +#endif +#ifdef ESRMNT + [ESRMNT] = "ESRMNT (Srmount error)", +#endif +#ifdef ECOMM + [ECOMM] = "ECOMM (Communication error on send)", +#endif +#ifdef EPROTO + [EPROTO] = "EPROTO (Protocol error)", +#endif +#ifdef EMULTIHOP + [EMULTIHOP] = "EMULTIHOP (Multihop attempted)", +#endif +#ifdef EDOTDOT + [EDOTDOT] = "EDOTDOT (RFS specific error)", +#endif +#ifdef EBADMSG + [EBADMSG] = "EBADMSG (Not a data message)", +#endif +#ifdef EOVERFLOW + [EOVERFLOW] = "EOVERFLOW (Value too large for defined data type)", +#endif +#ifdef ENOTUNIQ + [ENOTUNIQ] = "ENOTUNIQ (Name not unique on network)", +#endif +#ifdef EBADFD + [EBADFD] = "EBADFD (File descriptor in bad state)", +#endif +#ifdef EREMCHG + [EREMCHG] = "EREMCHG (Remote address changed)", +#endif +#ifdef ELIBACC + [ELIBACC] = "ELIBACC (Can not access a needed shared library)", +#endif +#ifdef ELIBBAD + [ELIBBAD] = "ELIBBAD (Accessing a corrupted shared library)", +#endif +#ifdef ELIBSCN + [ELIBSCN] = "ELIBSCN (.lib section in a.out corrupted)", +#endif +#ifdef ELIBMAX + [ELIBMAX] = "ELIBMAX (Attempting to link in too many shared libraries)", +#endif +#ifdef ELIBEXEC + [ELIBEXEC] = "ELIBEXEC (Cannot exec a shared library directly)", +#endif +#ifdef EILSEQ + [EILSEQ] = "EILSEQ (Illegal byte sequence)", +#endif +#ifdef ERESTART + [ERESTART] = "ERESTART (Interrupted system call should be restarted)", +#endif +#ifdef ESTRPIPE + [ESTRPIPE] = "ESTRPIPE (Streams pipe error)", +#endif +#ifdef EUSERS + [EUSERS] = "EUSERS (Too many users)", +#endif +#ifdef ENOTSOCK + [ENOTSOCK] = "ENOTSOCK (Socket operation on non-socket)", +#endif +#ifdef EDESTADDRREQ + [EDESTADDRREQ] = "EDESTADDRREQ (Destination address required)", +#endif +#ifdef EMSGSIZE + [EMSGSIZE] = "EMSGSIZE (Message too long)", +#endif +#ifdef EPROTOTYPE + [EPROTOTYPE] = "EPROTOTYPE (Protocol wrong type for socket)", +#endif +#ifdef ENOPROTOOPT + [ENOPROTOOPT] = "ENOPROTOOPT (Protocol not available)", +#endif +#ifdef EPROTONOSUPPORT + [EPROTONOSUPPORT] = "EPROTONOSUPPORT (Protocol not supported)", +#endif +#ifdef ESOCKTNOSUPPORT + [ESOCKTNOSUPPORT] = "ESOCKTNOSUPPORT (Socket type not supported)", +#endif +#ifdef EOPNOTSUPP + [EOPNOTSUPP] = "EOPNOTSUPP (Operation not supported on transport endpoint)", +#endif +#ifdef EPFNOSUPPORT + [EPFNOSUPPORT] = "EPFNOSUPPORT (Protocol family not supported)", +#endif +#ifdef EAFNOSUPPORT + [EAFNOSUPPORT] = "EAFNOSUPPORT (Address family not supported by protocol)", +#endif +#ifdef EADDRINUSE + [EADDRINUSE] = "EADDRINUSE (Address already in use)", +#endif +#ifdef EADDRNOTAVAIL + [EADDRNOTAVAIL] = "EADDRNOTAVAIL (Cannot assign requested address)", +#endif +#ifdef ENETDOWN + [ENETDOWN] = "ENETDOWN (Network is down)", +#endif +#ifdef ENETUNREACH + [ENETUNREACH] = "ENETUNREACH (Network is unreachable)", +#endif +#ifdef ENETRESET + [ENETRESET] = "ENETRESET (Network dropped connection because of reset)", +#endif +#ifdef ECONNABORTED + [ECONNABORTED] = "ECONNABORTED (Software caused connection abort)", +#endif +#ifdef ECONNRESET + [ECONNRESET] = "ECONNRESET (Connection reset by peer)", +#endif +#ifdef ENOBUFS + [ENOBUFS] = "ENOBUFS (No buffer space available)", +#endif +#ifdef EISCONN + [EISCONN] = "EISCONN (Transport endpoint is already connected)", +#endif +#ifdef ENOTCONN + [ENOTCONN] = "ENOTCONN (Transport endpoint is not connected)", +#endif +#ifdef ESHUTDOWN + [ESHUTDOWN] = "ESHUTDOWN (Cannot send after transport endpoint shutdown)", +#endif +#ifdef ETOOMANYREFS + [ETOOMANYREFS] = "ETOOMANYREFS (Too many references: cannot splice)", +#endif +#ifdef ETIMEDOUT + [ETIMEDOUT] = "ETIMEDOUT (Connection timed out)", +#endif +#ifdef ECONNREFUSED + [ECONNREFUSED] = "ECONNREFUSED (Connection refused)", +#endif +#ifdef EHOSTDOWN + [EHOSTDOWN] = "EHOSTDOWN (Host is down)", +#endif +#ifdef EHOSTUNREACH + [EHOSTUNREACH] = "EHOSTUNREACH (No route to host)", +#endif +#ifdef EALREADY + [EALREADY] = "EALREADY (Operation already in progress)", +#endif +#ifdef EINPROGRESS + [EINPROGRESS] = "EINPROGRESS (Operation now in progress)", +#endif +#ifdef ESTALE + [ESTALE] = "ESTALE (Stale file handle)", +#endif +#ifdef EUCLEAN + [EUCLEAN] = "EUCLEAN (Structure needs cleaning)", +#endif +#ifdef ENOTNAM + [ENOTNAM] = "ENOTNAM (Not a XENIX named type file)", +#endif +#ifdef ENAVAIL + [ENAVAIL] = "ENAVAIL (No XENIX semaphores available)", +#endif +#ifdef EISNAM + [EISNAM] = "EISNAM (Is a named type file)", +#endif +#ifdef EREMOTEIO + [EREMOTEIO] = "EREMOTEIO (Remote I/O error)", +#endif +#ifdef EDQUOT + [EDQUOT] = "EDQUOT (Quota exceeded)", +#endif +#ifdef ENOMEDIUM + [ENOMEDIUM] = "ENOMEDIUM (No medium found)", +#endif +#ifdef EMEDIUMTYPE + [EMEDIUMTYPE] = "EMEDIUMTYPE (Wrong medium type)", +#endif +#ifdef ECANCELED + [ECANCELED] = "ECANCELED (Operation Canceled)", +#endif +#ifdef ENOKEY + [ENOKEY] = "ENOKEY (Required key not available)", +#endif +#ifdef EKEYEXPIRED + [EKEYEXPIRED] = "EKEYEXPIRED (Key has expired)", +#endif +#ifdef EKEYREVOKED + [EKEYREVOKED] = "EKEYREVOKED (Key has been revoked)", +#endif +#ifdef EKEYREJECTED + [EKEYREJECTED] = "EKEYREJECTED (Key was rejected by service)", +#endif +#ifdef EOWNERDEAD + [EOWNERDEAD] = "EOWNERDEAD (Owner died)", +#endif +#ifdef ENOTRECOVERABLE + [ENOTRECOVERABLE] = "ENOTRECOVERABLE (State not recoverable)", +#endif +#ifdef ERFKILL + [ERFKILL] = "ERFKILL (Operation not possible due to RF-kill)", +#endif +#ifdef EHWPOISON + [EHWPOISON] = "EHWPOISON (Memory page has hardware error)", +#endif +}; +/* END CSTYLED */ - flags &= ~(O_RDONLY | O_RDWR | O_WRONLY | O_APPEND | - O_CLOEXEC | O_CREAT | O_DIRECTORY | O_DSYNC | O_EXCL | - O_NOCTTY | O_NOFOLLOW | O_NONBLOCK | O_RSYNC | O_SYNC | - O_TRUNC); - - if (flags != 0) { - /* - * Some values in the flag were not recognized, just print the - * raw number. - * e.g.: "O_RDONLY | O_NONBLOCK | 0x9876" - */ - c += sprintf(c, "0x%dx", flags); - } else if (c != buffer) { - /* - * All bits in flag were parsed, and the pointer c does not - * point to the start of the buffer, therefore some text was - * written already, with a separator on the end. Remove the - * trailing three characters: " | " - * - * e.g.: "O_RDONLY | O_NONBLOCK | " -> "O_RDONLY | O_NONBLOCK" - */ - c -= 3; - *c = 0; - } - - return c; -} - -static const char * -desc_flock_type(short t) -{ -#define F(x) case x: return #x; - switch (t) { - F(F_RDLCK); - F(F_WRLCK); - F(F_UNLCK); - } -#undef F - return "?"; -} - -static const char * -desc_whence(short w) -{ -#define F(x) case x: return #x; - switch (w) { - F(SEEK_SET); - F(SEEK_CUR); - F(SEEK_END); - F(SEEK_DATA); - F(SEEK_HOLE); - } -#undef F - return "?"; -} - -/* - * fcntl_name - * Returns a pointer to string literal describing an fcntl command. - */ -static const char * -fcntl_name(long cmd) -{ -#define F(x) case x: return #x; - switch (cmd) { - F(F_DUPFD); - F(F_DUPFD_CLOEXEC); - F(F_GETFD); - F(F_SETFD); - F(F_GETFL); - F(F_SETFL); - F(F_SETLK); - F(F_SETLKW); - F(F_GETLK); -#ifdef F_OFD_SETLK - F(F_OFD_SETLK); - F(F_OFD_SETLKW); - F(F_OFD_GETLK); -#endif - F(F_GETOWN); - F(F_SETOWN); - F(F_GETOWN_EX); - F(F_SETOWN_EX); - F(F_GETSIG); - F(F_SETSIG); - F(F_SETLEASE); - F(F_GETLEASE); - F(F_NOTIFY); - F(F_SETPIPE_SZ); - F(F_GETPIPE_SZ); -#ifdef F_ADD_SEALS - F(F_ADD_SEALS); - F(F_GET_SEALS); - F(F_SEAL_SEAL); - F(F_SEAL_SHRINK); - F(F_SEAL_GROW); - F(F_SEAL_WRITE); -#endif - } - return "unknown"; -#undef F -} - -static int -print_fcntl_flock(char *buffer, struct flock *fl) -{ - return sprintf(buffer, - " ({.l_type = %d (%s), .l_whence = %d (%s), .l_start = %ld, .l_len = %ld, .l_pid = %d})", - fl->l_type, desc_flock_type(fl->l_type), fl->l_whence, - desc_whence(fl->l_whence), fl->l_start, fl->l_len, fl->l_pid); -} - -/* - * print_fcntl_cmd - * Prints an fcntl command in a human readable format to a buffer, - * advances to char pointer, and returns the pointer pointing right - * after the just printed text. - */ -static char * -print_fcntl_args(char *buffer, long cmd, void *ptr) -{ - buffer += sprintf(buffer, "%ld (%s), %p", cmd, fcntl_name(cmd), ptr); - switch (cmd) { - case F_GETLK: - case F_SETLK: - case F_SETLKW: - case F_OFD_GETLK: - case F_OFD_SETLK: - case F_OFD_SETLKW: - buffer += print_fcntl_flock(buffer, ptr); - break; - } - - return buffer; -} - -/* - * print_clone_flags - * Prints SYS_clone specific flags into the buffer provided. Does not return - * the to pointer advanced while printing. - */ -static char * -print_clone_flags(char buffer[static 0x100], long flags) -{ - char *c = buffer; - - *c = '\0'; - - if ((flags & CLONE_CHILD_CLEARTID) == CLONE_CHILD_CLEARTID) - c += sprintf(c, "CLONE_CHILD_CLEARTID | "); - if ((flags & CLONE_CHILD_SETTID) == CLONE_CHILD_SETTID) - c += sprintf(c, "CLONE_CHILD_SETTID | "); - if ((flags & CLONE_FILES) == CLONE_FILES) - c += sprintf(c, "CLONE_FILES | "); - if ((flags & CLONE_FS) == CLONE_FS) - c += sprintf(c, "CLONE_FS | "); - if ((flags & CLONE_IO) == CLONE_IO) - c += sprintf(c, "CLONE_IO | "); -#ifdef CLONE_NEWCGROUP - if ((flags & CLONE_NEWCGROUP) == CLONE_NEWCGROUP) - c += sprintf(c, "CLONE_NEWCGROUP | "); -#endif -#ifdef CLONE_NEWIPC - if ((flags & CLONE_NEWIPC) == CLONE_NEWIPC) - c += sprintf(c, "CLONE_NEWIPC | "); -#endif -#ifdef CLONE_NEWNET - if ((flags & CLONE_NEWNET) == CLONE_NEWNET) - c += sprintf(c, "CLONE_NEWNET | "); -#endif -#ifdef CLONE_NEWNS - if ((flags & CLONE_NEWNS) == CLONE_NEWNS) - c += sprintf(c, "CLONE_NEWNS | "); -#endif -#ifdef CLONE_NEWPID - if ((flags & CLONE_NEWPID) == CLONE_NEWPID) - c += sprintf(c, "CLONE_NEWPID | "); -#endif - if ((flags & CLONE_NEWUSER) == CLONE_NEWUSER) - c += sprintf(c, "CLONE_NEWUSER | "); -#ifdef CLONE_NEWUTS - if ((flags & CLONE_NEWUTS) == CLONE_NEWUTS) - c += sprintf(c, "CLONE_NEWUTS | "); -#endif - if ((flags & CLONE_PARENT) == CLONE_PARENT) - c += sprintf(c, "CLONE_PARENT | "); - if ((flags & CLONE_PARENT_SETTID) == CLONE_PARENT_SETTID) - c += sprintf(c, "CLONE_PARENT_SETTID | "); - if ((flags & CLONE_PTRACE) == CLONE_PTRACE) - c += sprintf(c, "CLONE_PTRACE | "); - if ((flags & CLONE_SETTLS) == CLONE_SETTLS) - c += sprintf(c, "CLONE_SETTLS | "); - if ((flags & CLONE_SIGHAND) == CLONE_SIGHAND) - c += sprintf(c, "CLONE_SIGHAND | "); - if ((flags & CLONE_SYSVSEM) == CLONE_SYSVSEM) - c += sprintf(c, "CLONE_SYSVSEM | "); - if ((flags & CLONE_THREAD) == CLONE_THREAD) - c += sprintf(c, "CLONE_THREAD | "); - if ((flags & CLONE_UNTRACED) == CLONE_UNTRACED) - c += sprintf(c, "CLONE_UNTRACED | "); - if ((flags & CLONE_VFORK) == CLONE_VFORK) - c += sprintf(c, "CLONE_VFORK | "); - if ((flags & CLONE_VM) == CLONE_VM) - c += sprintf(c, "CLONE_VM | "); - - if (c != buffer) { - c -= 3; - *c = '\0'; - } else { - c += sprintf(buffer, "%ld", flags); - } - - return c; -} - -/* - * The formats of syscall arguments, as they should appear in logs. - */ - -/* decimal number */ -#define F_DEC 1 - -/* mode_t, octal number ( open, chmod, etc.. ) */ -#define F_OCT_MODE 2 - -/* hexadecimal number, with zero padding e.g. pointers */ -#define F_HEX 3 - -/* zero terminated string */ -#define F_STR 4 - -/* buffer, with a given size */ -#define F_BUF 5 - -/* only used for oflags in open, openat */ -#define F_OPEN_FLAGS 6 - -/* 2nd and 3rd argument of fcntl */ -#define F_FCNTL_ARGS 7 - -/* 1st argument of clone */ -#define F_CLONE_FLAGS 8 - -/* last argument of lseek */ -#define F_LSEEK_WHENCE 9 - -/* array of two integers */ -#define F_2INT 10 - -/* - * xprint_escape - * Prints a user provided buffer (in src) as printable characters (to dst). - * The zero_term argument specifies if it is a zero terminated buffer, e.g. - * used with SYS_open, SYS_stat, or a buffer with a specified length, e.g. - * used with SYS_write. - * No more than dst_size characters are written. - * - * Returns the pointer advanced while printing. - */ -static char * -xprint_escape(char *restrict dst, const char *restrict src, - size_t dst_size, bool zero_term, size_t src_size) -{ - static const char xdigit[16] = "0123456789abcdef"; - - char *dst_end = dst + dst_size - 5; - - if (src == NULL) - return dst + sprintf(dst, "(null)"); - - *dst++ = '"'; - while (dst < dst_end && (zero_term || src_size > 0)) { - if (zero_term && *src == 0) - break; - - if (*src == '\"') { - *dst++ = '\\'; - *dst++ = '"'; - } else if (*src == '\\') { - *dst++ = '\\'; - *dst++ = '\\'; - } else if (isprint(*src)) { - *dst++ = *src; - } else { - *dst++ = '\\'; - if (*src == '\n') { - *dst++ = 'n'; - } else if (*src == '\t') { - *dst++ = 't'; - } else if (*src == '\r') { - *dst++ = 'r'; - } else if (*src == '\a') { - *dst++ = 'a'; - } else if (*src == '\b') { - *dst++ = 'b'; - } else if (*src == '\f') { - *dst++ = 'f'; - } else if (*src == '\v') { - *dst++ = 'v'; - } else if (*src == '\0') { - *dst++ = '0'; - } else { - *dst++ = 'x'; - *dst++ = xdigit[(unsigned char)(*src) / 16]; - *dst++ = xdigit[(unsigned char)(*src) % 16]; - } - - } - - ++src; - - if (!zero_term) - --src_size; - } - - if ((src_size > 0 && !zero_term) || (zero_term && *src != 0)) - dst += sprintf(dst, "..."); - - *dst++ = '"'; - *dst = 0; - - return dst; -} - -/* - * print_syscall - * A more general way of printing syscalls into a buffer. The args argument - * specifies the number of syscall arguments to be printed, the rest of the - * arguments specify their format. - * - * Returns a pointer pointing to right after the just printed text. - */ -static char * -print_syscall(char *b, const char *name, unsigned args, ...) -{ - bool first = true; - va_list ap; - - b += sprintf(b, "%s(", name); - - va_start(ap, args); - - while (args > 0) { - int format = va_arg(ap, int); - - if (!first) { - *b++ = ','; - *b++ = ' '; - } - - if (format == F_DEC) { - b += sprintf(b, "%ld", va_arg(ap, long)); - } else if (format == F_OCT_MODE) { - b += sprintf(b, "0%lo", va_arg(ap, unsigned long)); - } else if (format == F_HEX) { - b += sprintf(b, "0x%lx", va_arg(ap, unsigned long)); - } else if (format == F_STR) { - b = xprint_escape(b, va_arg(ap, char *), 0x80, true, 0); - } else if (format == F_BUF) { - size_t size = va_arg(ap, size_t); - const char *data = va_arg(ap, char *); - b = xprint_escape(b, data, 0x80, false, size); - } else if (format == F_OPEN_FLAGS) { - b = print_open_flags(b, va_arg(ap, int)); - } else if (format == F_FCNTL_ARGS) { - long cmd = va_arg(ap, long); - b = print_fcntl_args(b, cmd, va_arg(ap, void *)); - } else if (format == F_CLONE_FLAGS) { - b = print_clone_flags(b, va_arg(ap, long)); - } else if (format == F_LSEEK_WHENCE) { - long whence = va_arg(ap, long); - b += sprintf(b, "%ld (%s)", whence, - desc_whence(whence)); - } else if (format == F_2INT) { - int *ints = va_arg(ap, int *); - if (ints) - b += sprintf(b, "[%d, %d]", ints[0], ints[1]); - else - b += sprintf(b, "NULL"); - } - - --args; - first = false; - } - - if (va_arg(ap, enum intercept_log_result) == KNOWN) - b += sprintf(b, ") = %ld", va_arg(ap, long)); - else - b += sprintf(b, ") = ?"); - - va_end(ap); - - return b; -} - -/* - * Log syscalls after intercepting, in a human readable ( as much as possible ) - * format. The format is either: - * - * offset -- name(arguments...) = result - * - * where the name is known, or - * - * offset -- syscall(syscall_number, arguments...) = result - * - * where the name is not known. - * - * Each line starts with the offset of the syscall instruction in libc's ELF. - * This should be easy to pass to addr2line, to see in what symbol in libc - * the syscall was initiated. - * - * E.g.: - * 0xdaea2 -- fstat(1, 0x7ffd115206f0) = 0 - * - * Each syscall should be logged after being executed, so the result can be - * logged as well. - */ -void -intercept_log_syscall(const struct patch_desc *patch, - const struct syscall_desc *desc, - enum intercept_log_result result_known, long result) +const char * +strerror_no_intercept(long errnum) { - if (log_fd < 0) - return; - - char buffer[0x1000]; - char *buf = buffer; - - buf += sprintf(buf, "%s 0x%lx -- ", patch->containing_lib_path, - patch->syscall_offset); - - if (desc->nr == SYS_read) { - ssize_t print_size = (ssize_t)result; + static const char unkown[] = "Uknown error"; - if (result_known == UNKNOWN || result < 0) { - /* - * Avoid printing the buffer before the syscall. - * It is useless, and can trigger a message from - * valgrind. - */ - print_size = 0; - } + if (errnum < 0 || (size_t)errnum >= ARRAY_SIZE(error_strings)) + return unkown; - buf = print_syscall(buf, "read", 3, - F_DEC, desc->args[0], - F_BUF, print_size, desc->args[1], - F_DEC, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_write) { - buf = print_syscall(buf, "write", 3, - F_DEC, desc->args[0], - F_BUF, desc->args[2], desc->args[1], - F_DEC, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_open) { - buf = print_syscall(buf, "open", 3, - F_STR, desc->args[0], - F_OPEN_FLAGS, desc->args[1], - F_OCT_MODE, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_close) { - buf = print_syscall(buf, "close", 1, - F_DEC, desc->args[0], - result_known, result); - } else if (desc->nr == SYS_stat) { - buf = print_syscall(buf, "stat", 2, - F_STR, desc->args[0], - F_HEX, desc->args[1], - result_known, result); - } else if (desc->nr == SYS_fstat) { - buf = print_syscall(buf, "fstat", 2, - F_DEC, desc->args[0], - F_HEX, desc->args[1], - result_known, result); - } else if (desc->nr == SYS_lstat) { - buf = print_syscall(buf, "lstat", 2, - F_STR, desc->args[0], - F_HEX, desc->args[1], - result_known, result); - } else if (desc->nr == SYS_lseek) { - buf = print_syscall(buf, "lseek", 3, - F_DEC, desc->args[0], - F_DEC, desc->args[1], - F_LSEEK_WHENCE, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_mmap) { - buf = print_syscall(buf, "mmap", 6, - F_HEX, desc->args[0], - F_DEC, desc->args[1], - F_DEC, desc->args[2], - F_DEC, desc->args[3], - F_DEC, desc->args[4], - F_HEX, desc->args[5], - result_known, result); - } else if (desc->nr == SYS_mprotect) { - buf = print_syscall(buf, "mprotect", 3, - F_HEX, desc->args[0], - F_DEC, desc->args[1], - F_DEC, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_munmap) { - buf = print_syscall(buf, "munmap", 2, - F_HEX, desc->args[0], - F_DEC, desc->args[1], - result_known, result); - } else if (desc->nr == SYS_brk) { - buf = print_syscall(buf, "brk", 1, - F_DEC, desc->args[0], - result_known, result); - } else if (desc->nr == SYS_ioctl) { - buf = print_syscall(buf, "ioctl", 3, - F_DEC, desc->args[0], - F_DEC, desc->args[1], - F_DEC, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_pread64) { - buf = print_syscall(buf, "pread64", 4, - F_DEC, desc->args[0], - F_BUF, desc->args[2], desc->args[1], - F_DEC, desc->args[2], - F_DEC, desc->args[3], - result_known, result); - } else if (desc->nr == SYS_pwrite64) { - buf = print_syscall(buf, "pwrite64", 4, - F_DEC, desc->args[0], - F_BUF, desc->args[2], desc->args[1], - F_DEC, desc->args[2], - F_DEC, desc->args[3], - result_known, result); - } else if (desc->nr == SYS_readv) { - buf = print_syscall(buf, "readv", 3, - F_DEC, desc->args[0], - F_HEX, desc->args[1], - F_DEC, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_writev) { - buf = print_syscall(buf, "writev", 3, - F_DEC, desc->args[0], - F_HEX, desc->args[1], - F_DEC, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_access) { - buf = print_syscall(buf, "access", 2, - F_STR, desc->args[0], - F_DEC, desc->args[1], - result_known, result); - } else if (desc->nr == SYS_mremap) { - buf = print_syscall(buf, "mremap", 5, - F_HEX, desc->args[0], - F_DEC, desc->args[1], - F_DEC, desc->args[2], - F_DEC, desc->args[3], - F_HEX, desc->args[4], - result_known, result); - } else if (desc->nr == SYS_msync) { - buf = print_syscall(buf, "msync", 3, - F_HEX, desc->args[0], - F_DEC, desc->args[1], - F_DEC, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_dup) { - buf = print_syscall(buf, "dup", 1, - F_DEC, desc->args[0], - result_known, result); - } else if (desc->nr == SYS_dup2) { - buf = print_syscall(buf, "dup2", 2, - F_DEC, desc->args[0], - F_DEC, desc->args[1], - result_known, result); - } else if (desc->nr == SYS_fcntl) { - buf = print_syscall(buf, "fcntl", 2, - F_DEC, desc->args[0], - F_FCNTL_ARGS, desc->args[1], desc->args[2], - result_known, result); - } else if (desc->nr == SYS_flock) { - buf = print_syscall(buf, "flock", 2, - F_DEC, desc->args[0], - F_DEC, desc->args[1], - result_known, result); - } else if (desc->nr == SYS_fsync) { - buf = print_syscall(buf, "fsync", 1, - F_DEC, desc->args[0], - result_known, result); - } else if (desc->nr == SYS_fdatasync) { - buf = print_syscall(buf, "fdatasync", 1, - F_DEC, desc->args[0], - result_known, result); - } else if (desc->nr == SYS_truncate) { - buf = print_syscall(buf, "truncate", 2, - F_STR, desc->args[0], - F_DEC, desc->args[1], - result_known, result); - } else if (desc->nr == SYS_ftruncate) { - buf = print_syscall(buf, "ftruncate", 2, - F_DEC, desc->args[0], - F_DEC, desc->args[1], - result_known, result); - } else if (desc->nr == SYS_getdents) { - buf = print_syscall(buf, "getdents", 3, - F_DEC, desc->args[0], - F_HEX, desc->args[1], - F_DEC, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_getcwd) { - buf = print_syscall(buf, "getcwd", 2, - F_STR, result_known == KNOWN ? desc->args[0] : - (intptr_t)"???", - F_DEC, desc->args[1], - result_known, result); - } else if (desc->nr == SYS_chdir) { - buf = print_syscall(buf, "chdir", 1, - F_STR, desc->args[0], - result_known, result); - } else if (desc->nr == SYS_fchdir) { - buf = print_syscall(buf, "fchdir", 1, - F_DEC, desc->args[0], - result_known, result); - } else if (desc->nr == SYS_rename) { - buf = print_syscall(buf, "rename", 2, - F_STR, desc->args[0], - F_STR, desc->args[1], - result_known, result); - } else if (desc->nr == SYS_mkdir) { - buf = print_syscall(buf, "mkdir", 2, - F_STR, desc->args[0], - F_OCT_MODE, desc->args[1], - result_known, result); - } else if (desc->nr == SYS_rmdir) { - buf = print_syscall(buf, "rmdir", 1, - F_STR, desc->args[0], - result_known, result); - } else if (desc->nr == SYS_creat) { - buf = print_syscall(buf, "creat", 2, - F_STR, desc->args[0], - F_OCT_MODE, desc->args[1], - result_known, result); - } else if (desc->nr == SYS_link) { - buf = print_syscall(buf, "link", 2, - F_STR, desc->args[0], - F_STR, desc->args[1], - result_known, result); - } else if (desc->nr == SYS_unlink) { - buf = print_syscall(buf, "unlink", 1, - F_STR, desc->args[0], - result_known, result); - } else if (desc->nr == SYS_symlink) { - buf = print_syscall(buf, "symlink", 2, - F_STR, desc->args[0], - F_STR, desc->args[1], - result_known, result); - } else if (desc->nr == SYS_readlink) { - ssize_t print_size = (ssize_t)result; + if (error_strings[errnum] == NULL) + return unkown; - if (result_known == UNKNOWN || result < 0) - print_size = 0; - - buf = print_syscall(buf, "readlink", 3, - F_STR, desc->args[0], - F_BUF, print_size, desc->args[1], - F_DEC, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_chmod) { - buf = print_syscall(buf, "chmod", 2, - F_STR, desc->args[0], - F_OCT_MODE, desc->args[1], - result_known, result); - } else if (desc->nr == SYS_fchmod) { - buf = print_syscall(buf, "fchmod", 2, - F_DEC, desc->args[0], - F_OCT_MODE, desc->args[1], - result_known, result); - } else if (desc->nr == SYS_chown) { - buf = print_syscall(buf, "chown", 3, - F_STR, desc->args[0], - F_DEC, desc->args[1], - F_DEC, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_fchown) { - buf = print_syscall(buf, "fchown", 3, - F_DEC, desc->args[0], - F_DEC, desc->args[1], - F_DEC, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_lchown) { - buf = print_syscall(buf, "lchown", 3, - F_STR, desc->args[0], - F_DEC, desc->args[1], - F_DEC, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_umask) { - buf = print_syscall(buf, "umask", 1, - F_OCT_MODE, desc->args[0], - result_known, result); - } else if (desc->nr == SYS_mknod) { - buf = print_syscall(buf, "mknod", 3, - F_STR, desc->args[0], - F_OCT_MODE, desc->args[1], - F_DEC, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_statfs) { - buf = print_syscall(buf, "statfs", 2, - F_STR, desc->args[0], - F_HEX, desc->args[1], - result_known, result); - } else if (desc->nr == SYS_fstatfs) { - buf = print_syscall(buf, "fstatfs", 2, - F_DEC, desc->args[0], - F_HEX, desc->args[1], - result_known, result); - } else if (desc->nr == SYS_chroot) { - buf = print_syscall(buf, "chroot", 1, - F_STR, desc->args[0], - result_known, result); - } else if (desc->nr == SYS_readahead) { - buf = print_syscall(buf, "readahead", 3, - F_DEC, desc->args[0], - F_DEC, desc->args[1], - F_DEC, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_getdents64) { - buf = print_syscall(buf, "getdents64", 3, - F_DEC, desc->args[0], - F_HEX, desc->args[1], - F_DEC, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_fadvise64) { - buf = print_syscall(buf, "fadvise64", 4, - F_DEC, desc->args[0], - F_DEC, desc->args[1], - F_DEC, desc->args[2], - F_DEC, desc->args[3], - result_known, result); - } else if (desc->nr == SYS_openat) { - buf = print_syscall(buf, "openat", 4, - F_DEC, desc->args[0], - F_STR, desc->args[1], - F_OPEN_FLAGS, desc->args[2], - F_OCT_MODE, desc->args[3], - result_known, result); - } else if (desc->nr == SYS_mkdirat) { - buf = print_syscall(buf, "mkdirat", 4, - F_DEC, desc->args[0], - F_STR, desc->args[1], - F_OPEN_FLAGS, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_mknodat) { - buf = print_syscall(buf, "mknodat", 4, - F_DEC, desc->args[0], - F_STR, desc->args[1], - F_OCT_MODE, desc->args[2], - F_DEC, desc->args[3], - result_known, result); - } else if (desc->nr == SYS_fchownat) { - buf = print_syscall(buf, "fchownat", 5, - F_DEC, desc->args[0], - F_STR, desc->args[1], - F_DEC, desc->args[2], - F_DEC, desc->args[3], - F_DEC, desc->args[4], - result_known, result); - } else if (desc->nr == SYS_futimesat) { - buf = print_syscall(buf, "futimesat", 3, - F_DEC, desc->args[0], - F_STR, desc->args[1], - F_HEX, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_newfstatat) { - buf = print_syscall(buf, "newfstatat", 4, - F_DEC, desc->args[0], - F_STR, desc->args[1], - F_HEX, desc->args[2], - F_DEC, desc->args[3], - result_known, result); - } else if (desc->nr == SYS_unlinkat) { - buf = print_syscall(buf, "unlinkat", 3, - F_DEC, desc->args[0], - F_STR, desc->args[1], - F_DEC, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_renameat) { - buf = print_syscall(buf, "renameat", 4, - F_DEC, desc->args[0], - F_STR, desc->args[1], - F_DEC, desc->args[2], - F_STR, desc->args[3], - result_known, result); - } else if (desc->nr == SYS_linkat) { - buf = print_syscall(buf, "linkat", 5, - F_DEC, desc->args[0], - F_STR, desc->args[1], - F_DEC, desc->args[2], - F_STR, desc->args[3], - F_DEC, desc->args[4], - result_known, result); - } else if (desc->nr == SYS_symlinkat) { - buf = print_syscall(buf, "symlinkat", 3, - F_STR, desc->args[0], - F_DEC, desc->args[1], - F_STR, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_readlinkat) { - buf = print_syscall(buf, "readlinkat", 4, - F_DEC, desc->args[0], - F_STR, desc->args[1], - F_STR, desc->args[2], - F_DEC, desc->args[3], - result_known, result); - } else if (desc->nr == SYS_fchmodat) { - buf = print_syscall(buf, "fchmodat", 3, - F_DEC, desc->args[0], - F_STR, desc->args[1], - F_OCT_MODE, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_faccessat) { - buf = print_syscall(buf, "faccessat", 3, - F_DEC, desc->args[0], - F_STR, desc->args[1], - F_OCT_MODE, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_splice) { - buf = print_syscall(buf, "splice", 6, - F_DEC, desc->args[0], - F_HEX, desc->args[1], - F_DEC, desc->args[2], - F_HEX, desc->args[3], - F_DEC, desc->args[4], - F_DEC, desc->args[5], - result_known, result); - } else if (desc->nr == SYS_tee) { - buf = print_syscall(buf, "tee", 4, - F_DEC, desc->args[0], - F_DEC, desc->args[1], - F_DEC, desc->args[2], - F_DEC, desc->args[3], - result_known, result); - } else if (desc->nr == SYS_sync_file_range) { - buf = print_syscall(buf, "sync_file_range", 4, - F_DEC, desc->args[0], - F_DEC, desc->args[1], - F_DEC, desc->args[2], - F_DEC, desc->args[3], - result_known, result); - } else if (desc->nr == SYS_utimensat) { - buf = print_syscall(buf, "utimensat", 4, - F_DEC, desc->args[0], - F_STR, desc->args[1], - F_HEX, desc->args[2], - F_DEC, desc->args[3], - result_known, result); - } else if (desc->nr == SYS_fallocate) { - buf = print_syscall(buf, "fallocate", 4, - F_DEC, desc->args[0], - F_DEC, desc->args[1], - F_DEC, desc->args[2], - F_DEC, desc->args[3], - result_known, result); - } else if (desc->nr == SYS_dup3) { - buf = print_syscall(buf, "dup3", 3, - F_DEC, desc->args[0], - F_DEC, desc->args[1], - F_DEC, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_preadv) { - buf = print_syscall(buf, "preadv", 4, - F_DEC, desc->args[0], - F_HEX, desc->args[1], - F_DEC, desc->args[2], - F_DEC, desc->args[3], - result_known, result); - } else if (desc->nr == SYS_pwritev) { - buf = print_syscall(buf, "pwritev", 3, - F_DEC, desc->args[0], - F_HEX, desc->args[1], - F_DEC, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_name_to_handle_at) { - buf = print_syscall(buf, "name_to_handle_at", 5, - F_DEC, desc->args[0], - F_STR, desc->args[1], - F_HEX, desc->args[2], - F_HEX, desc->args[3], - F_DEC, desc->args[4], - result_known, result); - } else if (desc->nr == SYS_open_by_handle_at) { - buf = print_syscall(buf, "open_by_handle_at", 3, - F_DEC, desc->args[0], - F_HEX, desc->args[1], - F_DEC, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_syncfs) { - buf = print_syscall(buf, "syncfs", 1, - F_DEC, desc->args[0], - result_known, result); -#ifdef SYS_renameat2 - } else if (desc->nr == SYS_renameat2) { - buf = print_syscall(buf, "renameat2", 5, - F_DEC, desc->args[0], - F_STR, desc->args[1], - F_DEC, desc->args[2], - F_STR, desc->args[3], - F_DEC, desc->args[4], - result_known, result); -#endif - } else if (desc->nr == SYS_execve) { - buf = print_syscall(buf, "execve", 3, - F_STR, desc->args[0], - F_HEX, desc->args[1], - F_HEX, desc->args[2], - result_known, result); -#ifdef SYS_execveat - } else if (desc->nr == SYS_execveat) { - buf = print_syscall(buf, "execveat", 4, - F_DEC, desc->args[0], - F_STR, desc->args[1], - F_HEX, desc->args[2], - F_HEX, desc->args[3], - result_known, result); -#endif - } else if (desc->nr == SYS_exit_group) { - buf += sprintf(buf, "exit_group(%d)", (int)desc->args[0]); - } else if (desc->nr == SYS_exit) { - buf += sprintf(buf, "exit(%d)", (int)desc->args[0]); - } else if (desc->nr == SYS_clone) { - buf = print_syscall(buf, "clone", 5, - F_CLONE_FLAGS, desc->args[0], - F_HEX, desc->args[1], - F_HEX, desc->args[2], - F_HEX, desc->args[3], - F_HEX, desc->args[4], - result_known, result); - } else if (desc->nr == SYS_fork) { - buf = print_syscall(buf, "fork", 0, result_known, result); - } else if (desc->nr == SYS_vfork) { - buf += sprintf(buf, "vfork()"); - } else if (desc->nr == SYS_wait4) { - buf = print_syscall(buf, "wait4", 4, - F_DEC, desc->args[0], - F_HEX, desc->args[1], - F_HEX, desc->args[2], - F_HEX, desc->args[3], - result_known, result); - } else if (desc->nr == SYS_select) { - buf = print_syscall(buf, "select", 5, - F_DEC, desc->args[0], - F_HEX, desc->args[1], - F_HEX, desc->args[2], - F_HEX, desc->args[3], - F_HEX, desc->args[4], - result_known, result); - } else if (desc->nr == SYS_pselect6) { - buf = print_syscall(buf, "pselect6", 6, - F_DEC, desc->args[0], - F_HEX, desc->args[1], - F_HEX, desc->args[2], - F_HEX, desc->args[3], - F_HEX, desc->args[4], - F_HEX, desc->args[5], - result_known, result); - } else if (desc->nr == SYS_poll) { - buf = print_syscall(buf, "poll", 3, - F_HEX, desc->args[0], - F_DEC, desc->args[1], - F_DEC, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_ppoll) { - buf = print_syscall(buf, "ppoll", 4, - F_HEX, desc->args[0], - F_DEC, desc->args[1], - F_HEX, desc->args[2], - F_HEX, desc->args[3], - result_known, result); - } else if (desc->nr == SYS_epoll_wait) { - buf = print_syscall(buf, "epoll_wait", 4, - F_DEC, desc->args[0], - F_HEX, desc->args[1], - F_DEC, desc->args[2], - F_DEC, desc->args[3], - result_known, result); - } else if (desc->nr == SYS_epoll_pwait) { - buf = print_syscall(buf, "epoll_pwait", 5, - F_DEC, desc->args[0], - F_HEX, desc->args[1], - F_DEC, desc->args[2], - F_DEC, desc->args[3], - F_HEX, desc->args[4], - result_known, result); - } else if (desc->nr == SYS_epoll_ctl) { - buf = print_syscall(buf, "epoll_ctl", 4, - F_DEC, desc->args[0], - F_DEC, desc->args[1], - F_DEC, desc->args[2], - F_HEX, desc->args[3], - result_known, result); - } else if (desc->nr == SYS_rt_sigaction) { - buf = print_syscall(buf, "rt_sigaction", 3, - F_DEC, desc->args[0], - F_HEX, desc->args[1], - F_HEX, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_rt_sigprocmask) { - buf = print_syscall(buf, "rt_sigprocmask", 3, - F_DEC, desc->args[0], - F_HEX, desc->args[1], - F_HEX, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_rt_sigreturn) { - buf = print_syscall(buf, "rt_sigreturn", 1, - F_HEX, desc->args[0], - result_known, result); - } else if (desc->nr == SYS_getuid) { - buf = print_syscall(buf, "getuid", 0, result_known, result); - } else if (desc->nr == SYS_geteuid) { - buf = print_syscall(buf, "geteuid", 0, result_known, result); - } else if (desc->nr == SYS_getresuid) { - buf = print_syscall(buf, "getresuid", 3, - F_HEX, desc->args[0], - F_HEX, desc->args[1], - F_HEX, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_setuid) { - buf = print_syscall(buf, "setuid", 1, - F_DEC, desc->args[0], - result_known, result); - } else if (desc->nr == SYS_setreuid) { - buf = print_syscall(buf, "setreuid", 2, - F_DEC, desc->args[0], - F_DEC, desc->args[1], - result_known, result); - } else if (desc->nr == SYS_setresuid) { - buf = print_syscall(buf, "setresuid", 3, - F_DEC, desc->args[0], - F_DEC, desc->args[1], - F_DEC, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_setfsuid) { - buf = print_syscall(buf, "setfsuid", 1, - F_DEC, desc->args[0], - result_known, result); - } else if (desc->nr == SYS_getgid) { - buf = print_syscall(buf, "getgid", 0, result_known, result); - } else if (desc->nr == SYS_getegid) { - buf = print_syscall(buf, "getegid", 0, result_known, result); - } else if (desc->nr == SYS_getresgid) { - buf = print_syscall(buf, "getresgid", 3, - F_HEX, desc->args[0], - F_HEX, desc->args[1], - F_HEX, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_setgid) { - buf = print_syscall(buf, "setgid", 1, - F_DEC, desc->args[0], - result_known, result); - } else if (desc->nr == SYS_setregid) { - buf = print_syscall(buf, "setregid", 2, - F_DEC, desc->args[0], - F_DEC, desc->args[1], - result_known, result); - } else if (desc->nr == SYS_setresgid) { - buf = print_syscall(buf, "setresgid", 3, - F_DEC, desc->args[0], - F_DEC, desc->args[1], - F_DEC, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_setfsgid) { - buf = print_syscall(buf, "setfsgid", 1, - F_DEC, desc->args[0], - result_known, result); - } else if (desc->nr == SYS_getgroups) { - buf = print_syscall(buf, "getgroups", 2, - F_DEC, desc->args[0], - F_HEX, desc->args[1], - result_known, result); - } else if (desc->nr == SYS_setgroups) { - buf = print_syscall(buf, "setgroups", 2, - F_DEC, desc->args[0], - F_HEX, desc->args[1], - result_known, result); - } else if (desc->nr == SYS_setsid) { - buf = print_syscall(buf, "setsid", 0, result_known, result); - } else if (desc->nr == SYS_getsid) { - buf = print_syscall(buf, "getsid", 1, - F_DEC, desc->args[0], - result_known, result); - } else if (desc->nr == SYS_getpid) { - buf = print_syscall(buf, "getpid", 0, result_known, result); - } else if (desc->nr == SYS_getppid) { - buf = print_syscall(buf, "getppid", 0, result_known, result); - } else if (desc->nr == SYS_gettid) { - buf = print_syscall(buf, "gettid", 0, result_known, result); - } else if (desc->nr == SYS_uname) { - buf = print_syscall(buf, "uname", 1, - F_HEX, desc->args[0], - result_known, result); - } else if (desc->nr == SYS_futex) { - buf = print_syscall(buf, "futex", 6, - F_HEX, desc->args[0], - F_DEC, desc->args[1], - F_DEC, desc->args[2], - F_HEX, desc->args[3], - F_HEX, desc->args[4], - F_DEC, desc->args[5], - result_known, result); - } else if (desc->nr == SYS_get_robust_list) { - buf = print_syscall(buf, "get_robust_list", 3, - F_DEC, desc->args[0], - F_HEX, desc->args[1], - F_HEX, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_set_robust_list) { - buf = print_syscall(buf, "set_robust_list", 2, - F_HEX, desc->args[0], - F_DEC, desc->args[1], - result_known, result); - } else if (desc->nr == SYS_pipe) { - int fmt = result_known == KNOWN ? F_2INT : F_HEX; - buf = print_syscall(buf, "pipe", 1, - fmt, desc->args[0], - result_known, result); - } else if (desc->nr == SYS_pipe2) { - int fmt = result_known == KNOWN ? F_2INT : F_HEX; - buf = print_syscall(buf, "pipe2", 2, - fmt, desc->args[0], - F_HEX, desc->args[1], - result_known, result); - } else if (desc->nr == SYS_socket) { - buf = print_syscall(buf, "socket", 3, - F_DEC, desc->args[0], - F_DEC, desc->args[1], - F_DEC, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_connect) { - buf = print_syscall(buf, "connect", 3, - F_DEC, desc->args[0], - F_HEX, desc->args[1], - F_DEC, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_kill) { - buf = print_syscall(buf, "kill", 2, - F_DEC, desc->args[0], - F_DEC, desc->args[1], - result_known, result); - } else if (desc->nr == SYS_tkill) { - buf = print_syscall(buf, "tkill", 2, - F_DEC, desc->args[0], - F_DEC, desc->args[1], - result_known, result); - } else if (desc->nr == SYS_tgkill) { - buf = print_syscall(buf, "tgkill", 3, - F_DEC, desc->args[0], - F_DEC, desc->args[1], - F_DEC, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_sysinfo) { - buf = print_syscall(buf, "sysinfo", 1, - F_HEX, desc->args[0], - result_known, result); - } else if (desc->nr == SYS_getxattr) { - buf = print_syscall(buf, "getxattr", 4, - F_STR, desc->args[0], - F_STR, desc->args[1], - F_BUF, desc->args[3], desc->args[2], - F_DEC, desc->args[3], - result_known, result); - } else if (desc->nr == SYS_lgetxattr) { - buf = print_syscall(buf, "lgetxattr", 4, - F_STR, desc->args[0], - F_STR, desc->args[1], - F_BUF, desc->args[3], desc->args[2], - F_DEC, desc->args[3], - result_known, result); - } else if (desc->nr == SYS_fgetxattr) { - buf = print_syscall(buf, "fgetxattr", 4, - F_DEC, desc->args[0], - F_STR, desc->args[1], - F_BUF, desc->args[3], desc->args[2], - F_DEC, desc->args[3], - result_known, result); - } else if (desc->nr == SYS_setrlimit) { - buf = print_syscall(buf, "setrlimit", 2, - F_DEC, desc->args[0], - F_HEX, desc->args[1], - result_known, result); - } else if (desc->nr == SYS_getrlimit) { - buf = print_syscall(buf, "getrlimit", 2, - F_DEC, desc->args[0], - F_HEX, desc->args[1], - result_known, result); - } else if (desc->nr == SYS_getrusage) { - buf = print_syscall(buf, "getrusage", 2, - F_DEC, desc->args[0], - F_HEX, desc->args[1], - result_known, result); - } else if (desc->nr == SYS_bind) { - buf = print_syscall(buf, "bind", 3, - F_DEC, desc->args[0], - F_HEX, desc->args[1], - F_DEC, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_getpeername) { - buf = print_syscall(buf, "getpeername", 3, - F_DEC, desc->args[0], - F_HEX, desc->args[1], - F_HEX, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_getsockname) { - buf = print_syscall(buf, "getsockname", 3, - F_DEC, desc->args[0], - F_HEX, desc->args[1], - F_HEX, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_recvfrom) { - buf = print_syscall(buf, "recvfrom", 6, - F_DEC, desc->args[0], - F_HEX, desc->args[1], - F_DEC, desc->args[2], - F_DEC, desc->args[3], - F_HEX, desc->args[4], - F_HEX, desc->args[5], - result_known, result); - } else if (desc->nr == SYS_recvmsg) { - buf = print_syscall(buf, "recvmsg", 3, - F_DEC, desc->args[0], - F_HEX, desc->args[1], - F_DEC, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_sendto) { - buf = print_syscall(buf, "sendto", 6, - F_DEC, desc->args[0], - F_HEX, desc->args[1], - F_DEC, desc->args[2], - F_DEC, desc->args[3], - F_HEX, desc->args[4], - F_HEX, desc->args[5], - result_known, result); - } else if (desc->nr == SYS_sendmsg) { - buf = print_syscall(buf, "sendmsg", 3, - F_DEC, desc->args[0], - F_HEX, desc->args[1], - F_DEC, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_sendmmsg) { - buf = print_syscall(buf, "sendmmsg", 4, - F_DEC, desc->args[0], - F_HEX, desc->args[1], - F_DEC, desc->args[2], - F_DEC, desc->args[3], - result_known, result); - } else if (desc->nr == SYS_shutdown) { - buf = print_syscall(buf, "shutdown", 2, - F_DEC, desc->args[0], - F_DEC, desc->args[1], - result_known, result); - } else if (desc->nr == SYS_memfd_create) { - buf = print_syscall(buf, "memfd_create", 2, - F_STR, desc->args[0], - F_DEC, desc->args[1], - result_known, result); - } else if (desc->nr == SYS_madvise) { - buf = print_syscall(buf, "madvise", 3, - F_HEX, desc->args[0], - F_DEC, desc->args[1], - F_DEC, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_shmget) { - buf = print_syscall(buf, "shmget", 3, - F_DEC, desc->args[0], - F_DEC, desc->args[1], - F_DEC, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_shmat) { - buf = print_syscall(buf, "shmat", 3, - F_DEC, desc->args[0], - F_HEX, desc->args[1], - F_DEC, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_shmctl) { - buf = print_syscall(buf, "shmctl", 3, - F_DEC, desc->args[0], - F_DEC, desc->args[1], - F_HEX, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_shmdt) { - buf = print_syscall(buf, "shmdt", 1, - F_HEX, desc->args[0], - result_known, result); - } else if (desc->nr == SYS_setsockopt) { - buf = print_syscall(buf, "setsockopt", 5, - F_DEC, desc->args[0], - F_DEC, desc->args[1], - F_DEC, desc->args[2], - F_HEX, desc->args[3], - F_DEC, desc->args[4], - result_known, result); - } else if (desc->nr == SYS_getsockopt) { - buf = print_syscall(buf, "getsockopt", 5, - F_DEC, desc->args[0], - F_DEC, desc->args[1], - F_DEC, desc->args[2], - F_HEX, desc->args[3], - F_HEX, desc->args[4], - result_known, result); - } else if (desc->nr == SYS_getpriority) { - buf = print_syscall(buf, "getpriority", 2, - F_DEC, desc->args[0], - F_DEC, desc->args[1], - result_known, result); - } else if (desc->nr == SYS_setpriority) { - buf = print_syscall(buf, "setpriority", 3, - F_DEC, desc->args[0], - F_DEC, desc->args[1], - F_DEC, desc->args[2], - result_known, result); - } else if (desc->nr == SYS_prctl) { - buf = print_syscall(buf, "prctl", 5, - F_DEC, desc->args[0], - F_DEC, desc->args[1], - F_DEC, desc->args[2], - F_DEC, desc->args[3], - F_DEC, desc->args[4], - result_known, result); - } else if (desc->nr == SYS_quotactl) { - buf = print_syscall(buf, "quotactl", 4, - F_DEC, desc->args[0], - F_HEX, desc->args[1], - F_DEC, desc->args[2], - F_DEC, desc->args[3], - result_known, result); - } else if (desc->nr == SYS_clock_getres) { - buf = print_syscall(buf, "clock_getres", 2, - F_DEC, desc->args[0], - F_HEX, desc->args[1], - result_known, result); - } else if (desc->nr == SYS_clock_gettime) { - buf = print_syscall(buf, "clock_gettime", 2, - F_DEC, desc->args[0], - F_HEX, desc->args[1], - result_known, result); - } else if (desc->nr == SYS_clock_settime) { - buf = print_syscall(buf, "clock_settime", 2, - F_DEC, desc->args[0], - F_HEX, desc->args[1], - result_known, result); - } else if (desc->nr == SYS_clock_nanosleep) { - buf = print_syscall(buf, "clock_nanosleep", 4, - F_DEC, desc->args[0], - F_DEC, desc->args[1], - F_HEX, desc->args[2], - F_HEX, desc->args[3], - result_known, result); - } else if (desc->nr == SYS_eventfd2) { - buf = print_syscall(buf, "eventfd2", 2, - F_DEC, desc->args[0], - F_DEC, desc->args[1], - result_known, result); - } else { - buf = print_syscall(buf, "syscall", 7, - F_DEC, desc->nr, - F_HEX, desc->args[0], - F_HEX, desc->args[1], - F_HEX, desc->args[2], - F_HEX, desc->args[3], - F_HEX, desc->args[4], - F_HEX, desc->args[5], - result_known, result); - } - - *buf++ = '\n'; - - intercept_log(buffer, (size_t)(buf - buffer)); -} - -/* - * intercept_log - * Write a buffer to the log, with a specified length. - * No conversion is done to make it human readable. - */ -void -intercept_log(const char *buffer, size_t len) -{ - if (log_fd >= 0) - syscall_no_intercept(SYS_write, log_fd, - buffer, len); -} - -/* - * intercept_log_close - * Closes the log, if one was open. - */ -void -intercept_log_close(void) -{ - if (log_fd >= 0) { - syscall_no_intercept(SYS_close, log_fd); - log_fd = -1; - } + return error_strings[errnum]; } diff --git a/src/intercept_util.h b/src/intercept_util.h index 0b169b37..33ef2c1f 100644 --- a/src/intercept_util.h +++ b/src/intercept_util.h @@ -33,12 +33,9 @@ #ifndef INTERCEPT_UTIL_H #define INTERCEPT_UTIL_H -#include -#include #include -#include -#include "intercept.h" +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) /* * syscall_no_intercept - syscall without interception @@ -84,16 +81,11 @@ long xlseek(long fd, unsigned long off, int whence); */ void xread(long fd, void *buffer, size_t size); -void intercept_setup_log(const char *path_base, const char *trunc); -void intercept_log(const char *buffer, size_t len); - -enum intercept_log_result { KNOWN, UNKNOWN }; - -void intercept_log_syscall(const struct patch_desc *, - const struct syscall_desc *, - enum intercept_log_result result_known, - long result); - -void intercept_log_close(void); +/* + * strerror_no_intercept - returns a pointer to a C string associated with + * an errno value. + * Does not go through libc, MT-safe, signal-safe, never returns NULL. + */ +const char *strerror_no_intercept(long errnum); #endif diff --git a/src/magic_syscalls.c b/src/magic_syscalls.c index d37b4d3c..2308f11a 100644 --- a/src/magic_syscalls.c +++ b/src/magic_syscalls.c @@ -38,6 +38,7 @@ #include "magic_syscalls.h" #include "intercept.h" #include "intercept_util.h" +#include "intercept_log.h" /* * handle_magic_syscalls - this routine performs two tasks: diff --git a/src/patcher.c b/src/patcher.c index 19422b12..addf319d 100644 --- a/src/patcher.c +++ b/src/patcher.c @@ -70,6 +70,7 @@ #include "intercept.h" #include "intercept_util.h" +#include "intercept_log.h" #include #include diff --git a/src/syscall_formats.c b/src/syscall_formats.c new file mode 100644 index 00000000..10ce9ec5 --- /dev/null +++ b/src/syscall_formats.c @@ -0,0 +1,424 @@ +/* + * Copyright 2017, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "syscall_formats.h" +#include "intercept_util.h" + +#include +#include + +#define SARGS(name, r, ...) [SYS_##name] = {#name, r, {__VA_ARGS__}} + +/* Linux syscalls on X86_64 */ +/* BEGIN CSTYLED */ +static const struct syscall_format formats[] = { + SARGS(read, rdec, arg_fd, arg_buf_out, arg_dec), + SARGS(write, rdec, arg_fd, arg_buf_in, arg_dec), + SARGS(open, rdec, arg_cstr, arg_open_flags), + SARGS(close, rdec, arg_fd), + SARGS(stat, rdec, arg_cstr, arg_pointer), + SARGS(fstat, rdec, arg_fd, arg_pointer), + SARGS(lstat, rdec, arg_cstr, arg_pointer), + SARGS(poll, rdec, arg_pointer, arg_, arg_), + SARGS(lseek, rdec, arg_fd, arg_dec, arg_seek_whence), + SARGS(mmap, rpointer, arg_pointer, arg_, arg_, arg_, arg_fd, arg_), + SARGS(mprotect, rdec, arg_pointer, arg_, arg_), + SARGS(munmap, rdec, arg_pointer, arg_), + SARGS(brk, rdec, arg_dec), + SARGS(rt_sigaction, rdec, arg_dec32, arg_pointer, arg_pointer, arg_dec), + SARGS(rt_sigprocmask, rdec, arg_, arg_pointer, arg_pointer, arg_dec), + SARGS(rt_sigreturn, rnoreturn, arg_none), + SARGS(ioctl, rdec, arg_fd, arg_, arg_pointer), + SARGS(pread64, rdec, arg_fd, arg_buf_out, arg_dec, arg_dec), + SARGS(pwrite64, rdec, arg_fd, arg_buf_in, arg_dec, arg_dec), + SARGS(readv, rdec, arg_fd, arg_pointer, arg_dec), + SARGS(writev, rdec, arg_fd, arg_pointer, arg_dec), + SARGS(access, rdec, arg_cstr, arg_access_mode), + SARGS(pipe, rdec, arg_2fds), + SARGS(select, rdec, arg_dec32, arg_pointer, arg_pointer, arg_pointer, arg_pointer), + SARGS(sched_yield, rdec, arg_none), + SARGS(mremap, rpointer, arg_pointer, arg_dec, arg_dec, arg_dec32, arg_), + SARGS(msync, rdec, arg_pointer, arg_dec, arg_dec32), + SARGS(mincore, rdec, arg_pointer, arg_dec, arg_pointer), + SARGS(madvise, rdec, arg_pointer, arg_dec, arg_dec32), + SARGS(shmget, rdec, arg_, arg_, arg_), + SARGS(shmat, rhex, arg_, arg_, arg_), + SARGS(shmctl, rdec, arg_, arg_, arg_), + SARGS(dup, rdec, arg_fd), + SARGS(dup2, rdec, arg_fd, arg_fd), + SARGS(pause, rdec, arg_none), + SARGS(nanosleep, rdec, arg_, arg_), + SARGS(getitimer, rdec, arg_, arg_), + SARGS(alarm, rdec, arg_), + SARGS(setitimer, rdec, arg_, arg_, arg_), + SARGS(getpid, rdec, arg_none), + SARGS(sendfile, rdec, arg_fd, arg_fd, arg_, arg_), + SARGS(socket, rdec, arg_, arg_, arg_), + SARGS(connect, rdec, arg_fd, arg_, arg_), + SARGS(accept, rdec, arg_fd, arg_, arg_), + SARGS(sendto, rdec, arg_fd, arg_, arg_, arg_), + SARGS(recvfrom, rdec, arg_fd, arg_, arg_, arg_, arg_, arg_), + SARGS(sendmsg, rdec, arg_fd, arg_, arg_), + SARGS(recvmsg, rdec, arg_fd, arg_, arg_), + SARGS(shutdown, rdec, arg_fd, arg_), + SARGS(bind, rdec, arg_fd, arg_, arg_), + SARGS(listen, rdec, arg_fd, arg_), + SARGS(getsockname, rdec, arg_fd, arg_, arg_), + SARGS(getpeername, rdec, arg_fd, arg_, arg_), + SARGS(socketpair, rdec, arg_, arg_, arg_, arg_), + SARGS(setsockopt, rdec, arg_fd, arg_, arg_, arg_, arg_), + SARGS(getsockopt, rdec, arg_fd, arg_, arg_, arg_, arg_), + SARGS(clone, rdec, arg_clone_flags, arg_pointer, arg_pointer, arg_pointer, arg_), + SARGS(fork, rdec, arg_none), + SARGS(vfork, rdec, arg_none), + SARGS(execve, rdec, arg_, arg_, arg_), + SARGS(exit, rnoreturn, arg_), + SARGS(wait4, rdec, arg_dec, arg_, arg_, arg_), + SARGS(kill, rdec, arg_, arg_), + SARGS(uname, rdec, arg_), + SARGS(semget, rdec, arg_, arg_, arg_), + SARGS(semop, rdec, arg_, arg_, arg_), + SARGS(semctl, rdec, arg_, arg_, arg_, arg_, arg_, arg_), + SARGS(shmdt, rdec, arg_), + SARGS(msgget, rdec, arg_, arg_), + SARGS(msgsnd, rdec, arg_, arg_, arg_, arg_), + SARGS(msgrcv, rdec, arg_, arg_, arg_, arg_, arg_), + SARGS(msgctl, rdec, arg_, arg_, arg_), + SARGS(fcntl, rdec, arg_fd, arg_fcntl_args, arg_), + SARGS(flock, rdec, arg_fd, arg_), + SARGS(fsync, rdec, arg_fd), + SARGS(fdatasync, rdec, arg_fd), + SARGS(truncate, rdec, arg_cstr, arg_), + SARGS(ftruncate, rdec, arg_fd, arg_), + SARGS(getdents, rdec, arg_fd, arg_, arg_), + SARGS(getcwd, rdec, arg_, arg_), + SARGS(chdir, rdec, arg_cstr), + SARGS(fchdir, rdec, arg_fd), + SARGS(rename, rdec, arg_cstr, arg_cstr), + SARGS(mkdir, rdec, arg_cstr, arg_oct_mode), + SARGS(rmdir, rdec, arg_cstr), + SARGS(creat, rdec, arg_cstr, arg_oct_mode), + SARGS(link, rdec, arg_cstr, arg_cstr), + SARGS(unlink, rdec, arg_cstr), + SARGS(symlink, rdec, arg_cstr, arg_cstr), + SARGS(readlink, rdec, arg_cstr, arg_buf_out, arg_dec), + SARGS(chmod, rdec, arg_cstr, arg_oct_mode), + SARGS(fchmod, rdec, arg_fd, arg_oct_mode), + SARGS(chown, rdec, arg_cstr, arg_, arg_), + SARGS(fchown, rdec, arg_fd, arg_, arg_), + SARGS(lchown, rdec, arg_cstr, arg_, arg_), + SARGS(umask, rmode, arg_oct_mode), + SARGS(gettimeofday, rdec, arg_, arg_), + SARGS(getrlimit, rdec, arg_, arg_), + SARGS(getrusage, rdec, arg_, arg_), + SARGS(sysinfo, rdec, arg_, arg_), + SARGS(times, rdec, arg_), + SARGS(ptrace, rhex, arg_, arg_, arg_, arg_), + SARGS(getuid, rdec, arg_none), + SARGS(syslog, rdec, arg_, arg_, arg_), + SARGS(getgid, rdec, arg_none), + SARGS(setuid, rdec, arg_), + SARGS(setgid, rdec, arg_), + SARGS(geteuid, rdec, arg_none), + SARGS(getegid, rdec, arg_none), + SARGS(setpgid, rdec, arg_none), + SARGS(getpgrp, rdec, arg_none), + SARGS(setsid, rdec, arg_none), + SARGS(setreuid, rdec, arg_, arg_), + SARGS(setregid, rdec, arg_, arg_), + SARGS(getgroups, rdec, arg_, arg_), + SARGS(setgroups, rdec, arg_, arg_), + SARGS(setresuid, rdec, arg_, arg_, arg_), + SARGS(getresuid, rdec, arg_, arg_, arg_), + SARGS(setresgid, rdec, arg_, arg_, arg_), + SARGS(getresgid, rdec, arg_, arg_, arg_), + SARGS(getpgid, rdec, arg_), + SARGS(setfsuid, rdec, arg_), + SARGS(setfsgid, rdec, arg_), + SARGS(getsid, rdec, arg_), + SARGS(capget, rdec, arg_, arg_), + SARGS(capset, rdec, arg_, arg_), + SARGS(rt_sigpending, rdec, arg_), + SARGS(rt_sigtimedwait, rdec, arg_, arg_, arg_, arg_), + SARGS(rt_sigqueueinfo, rdec, arg_, arg_, arg_), + SARGS(rt_sigsuspend, rdec, arg_, arg_), + SARGS(sigaltstack, rdec, arg_, arg_), + SARGS(utime, rdec, arg_cstr, arg_), + SARGS(mknod, rdec, arg_cstr, arg_, arg_), + SARGS(uselib, rdec, arg_cstr), + SARGS(personality, rdec, arg_), + SARGS(ustat, rdec, arg_, arg_), + SARGS(statfs, rdec, arg_cstr, arg_), + SARGS(fstatfs, rdec, arg_fd, arg_), + SARGS(sysfs, rdec, arg_, arg_, arg_), + SARGS(getpriority, rdec, arg_, arg_), + SARGS(setpriority, rdec, arg_, arg_, arg_), + SARGS(sched_setparam, rdec, arg_, arg_), + SARGS(sched_getparam, rdec, arg_, arg_), + SARGS(sched_setscheduler, rdec, arg_, arg_, arg_), + SARGS(sched_getscheduler, rdec, arg_), + SARGS(sched_get_priority_max, rdec, arg_), + SARGS(sched_get_priority_min, rdec, arg_), + SARGS(sched_rr_get_interval, rdec, arg_, arg_), + SARGS(mlock, rdec, arg_, arg_), + SARGS(munlock, rdec, arg_, arg_), + SARGS(mlockall, rdec, arg_), + SARGS(munlockall, rdec, arg_none), + SARGS(vhangup, rdec, arg_none), + SARGS(modify_ldt, rdec, arg_, arg_, arg_), + SARGS(pivot_root, rdec, arg_cstr, arg_), + SARGS(_sysctl, rdec, arg_), + SARGS(prctl, rdec, arg_, arg_, arg_, arg_, arg_), + SARGS(arch_prctl, rdec, arg_, arg_, arg_), + SARGS(adjtimex, rdec, arg_), + SARGS(setrlimit, rdec, arg_, arg_), + SARGS(chroot, rdec, arg_cstr), + SARGS(sync, rdec, arg_none), + SARGS(acct, rdec, arg_cstr), + SARGS(settimeofday, rdec, arg_, arg_), + SARGS(mount, rdec, arg_cstr, arg_cstr, arg_, arg_, arg_), + SARGS(umount2, rdec, arg_cstr, arg_), + SARGS(swapon, rdec, arg_cstr, arg_), + SARGS(swapoff, rdec, arg_cstr), + SARGS(reboot, rdec, arg_, arg_, arg_, arg_), + SARGS(sethostname, rdec, arg_, arg_), + SARGS(setdomainname, rdec, arg_, arg_), + SARGS(iopl, rdec, arg_), + SARGS(ioperm, rdec, arg_, arg_, arg_), + SARGS(gettid, rdec, arg_none), + SARGS(readahead, rdec, arg_fd, arg_dec, arg_dec), + SARGS(setxattr, rdec, arg_cstr, arg_cstr, arg_buf_in, arg_dec, arg_), + SARGS(lsetxattr, rdec, arg_cstr, arg_cstr, arg_buf_in, arg_dec, arg_), + SARGS(fsetxattr, rdec, arg_fd, arg_cstr, arg_buf_in, arg_dec, arg_), + SARGS(getxattr, rdec, arg_cstr, arg_cstr, arg_dec, arg_), + SARGS(lgetxattr, rdec, arg_cstr, arg_cstr, arg_dec, arg_), + SARGS(fgetxattr, rdec, arg_fd, arg_cstr, arg_dec, arg_), + SARGS(listxattr, rdec, arg_cstr, arg_pointer, arg_dec), + SARGS(llistxattr, rdec, arg_cstr, arg_pointer, arg_dec), + SARGS(flistxattr, rdec, arg_fd, arg_pointer, arg_dec), + SARGS(removexattr, rdec, arg_cstr, arg_cstr), + SARGS(lremovexattr, rdec, arg_cstr, arg_cstr), + SARGS(fremovexattr, rdec, arg_fd, arg_cstr), + SARGS(tkill, rdec, arg_, arg_), + SARGS(time, rdec, arg_), + SARGS(futex, rdec, arg_, arg_, arg_, arg_, arg_, arg_), + SARGS(sched_setaffinity, rdec, arg_, arg_, arg_), + SARGS(sched_getaffinity, rdec, arg_, arg_, arg_), + SARGS(set_thread_area, rdec, arg_), + SARGS(io_setup, rdec, arg_, arg_), + SARGS(io_destroy, rdec, arg_), + SARGS(io_getevents, rdec, arg_, arg_, arg_, arg_, arg_), + SARGS(io_submit, rdec, arg_, arg_, arg_), + SARGS(io_cancel, rdec, arg_, arg_, arg_), + SARGS(get_thread_area, rdec, arg_), + SARGS(lookup_dcookie, rdec, arg_, arg_, arg_), + SARGS(epoll_create, rdec, arg_), + SARGS(getdents64, rdec, arg_fd, arg_, arg_), + SARGS(set_tid_address, rdec, arg_), + SARGS(semtimedop, rdec, arg_, arg_, arg_, arg_), + SARGS(fadvise64, rdec, arg_fd, arg_, arg_, arg_), + SARGS(timer_create, rdec, arg_, arg_, arg_), + SARGS(timer_settime, rdec, arg_, arg_, arg_, arg_), + SARGS(timer_gettime, rdec, arg_, arg_), + SARGS(timer_getoverrun, rdec, arg_), + SARGS(timer_delete, rdec, arg_), + SARGS(clock_settime, rdec, arg_, arg_), + SARGS(clock_gettime, rdec, arg_, arg_), + SARGS(clock_getres, rdec, arg_, arg_), + SARGS(clock_nanosleep, rdec, arg_, arg_, arg_, arg_), + SARGS(exit_group, rnoreturn, arg_), + SARGS(epoll_wait, rdec, arg_fd, arg_, arg_, arg_), + SARGS(epoll_ctl, rdec, arg_fd, arg_, arg_fd, arg_), + SARGS(tgkill, rdec, arg_, arg_, arg_), + SARGS(utimes, rdec, arg_cstr, arg_), + SARGS(mbind, rdec, arg_, arg_, arg_, arg_, arg_), + SARGS(set_mempolicy, rdec, arg_, arg_, arg_), + SARGS(get_mempolicy, rdec, arg_, arg_, arg_, arg_, arg_), + SARGS(mq_open, rdec, arg_cstr, arg_, arg_, arg_, arg_), + SARGS(mq_unlink, rdec, arg_cstr), + SARGS(mq_timedsend, rdec, arg_, arg_, arg_, arg_, arg_), + SARGS(mq_timedreceive, rdec, arg_, arg_, arg_, arg_, arg_), + SARGS(mq_notify, rdec, arg_, arg_), + SARGS(mq_getsetattr, rdec, arg_, arg_, arg_), + SARGS(kexec_load, rdec, arg_, arg_, arg_, arg_), + SARGS(waitid, rdec, arg_, arg_, arg_, arg_), + SARGS(add_key, rdec, arg_, arg_, arg_, arg_, arg_), + SARGS(request_key, rdec, arg_, arg_, arg_, arg_), + SARGS(keyctl, rdec, arg_, arg_, arg_, arg_, arg_), + SARGS(ioprio_set, rdec, arg_, arg_, arg_), + SARGS(ioprio_get, rdec, arg_, arg_), + SARGS(inotify_init, rdec, arg_none), + SARGS(inotify_add_watch, rdec, arg_fd, arg_cstr, arg_), + SARGS(inotify_rm_watch, rdec, arg_fd, arg_), + SARGS(migrate_pages, rdec, arg_, arg_, arg_, arg_), + SARGS(openat, rdec, arg_atfd, arg_cstr, arg_open_flags), + SARGS(mkdirat, rdec, arg_atfd, arg_cstr, arg_oct_mode), + SARGS(mknodat, rdec, arg_atfd, arg_cstr, arg_oct_mode, arg_), + SARGS(fchownat, rdec, arg_atfd, arg_cstr, arg_, arg_, arg_), + SARGS(futimesat, rdec, arg_atfd, arg_cstr, arg_), + SARGS(newfstatat, rdec, arg_atfd, arg_cstr, arg_, arg_), + SARGS(unlinkat, rdec, arg_atfd, arg_cstr, arg_), + SARGS(renameat, rdec, arg_atfd, arg_cstr, arg_atfd, arg_cstr), + SARGS(linkat, rdec, arg_atfd, arg_cstr, arg_atfd, arg_cstr, arg_), + SARGS(symlinkat, rdec, arg_atfd, arg_cstr, arg_cstr), + SARGS(readlinkat, rdec, arg_atfd, arg_cstr, arg_buf_out, arg_dec), + SARGS(fchmodat, rdec, arg_atfd, arg_cstr, arg_oct_mode), + SARGS(faccessat, rdec, arg_atfd, arg_cstr, arg_oct_mode), + SARGS(pselect6, rdec, arg_, arg_, arg_, arg_, arg_, arg_), + SARGS(ppoll, rdec, arg_, arg_, arg_, arg_, arg_), + SARGS(unshare, rdec, arg_), + SARGS(set_robust_list, rdec, arg_, arg_), + SARGS(get_robust_list, rdec, arg_, arg_, arg_), + SARGS(splice, rdec, arg_fd, arg_, arg_fd, arg_, arg_, arg_), + SARGS(tee, rdec, arg_fd, arg_fd, arg_, arg_), + SARGS(sync_file_range, rdec, arg_fd, arg_, arg_, arg_), + SARGS(vmsplice, rdec, arg_fd, arg_, arg_, arg_), + SARGS(move_pages, rdec, arg_, arg_, arg_, arg_, arg_, arg_), + SARGS(utimensat, rdec, arg_atfd, arg_cstr, arg_, arg_), + SARGS(epoll_pwait, rdec, arg_fd, arg_, arg_, arg_, arg_, arg_), + SARGS(signalfd, rdec, arg_fd, arg_, arg_), + SARGS(timerfd_create, rdec, arg_, arg_), + SARGS(eventfd, rdec, arg_), + SARGS(fallocate, rdec, arg_fd, arg_, arg_, arg_), + SARGS(timerfd_settime, rdec, arg_fd, arg_, arg_, arg_), + SARGS(timerfd_gettime, rdec, arg_fd, arg_), + SARGS(accept4, rdec, arg_fd, arg_, arg_, arg_, arg_), + SARGS(signalfd4, rdec, arg_fd, arg_, arg_, arg_, arg_), + SARGS(eventfd2, rdec, arg_, arg_), + SARGS(epoll_create1, rdec, arg_), + SARGS(dup3, rdec, arg_fd, arg_fd, arg_), + SARGS(pipe2, rdec, arg_2fds, arg_pipe2_flags), + SARGS(inotify_init1, rdec, arg_), + SARGS(preadv, rdec, arg_fd, arg_, arg_, arg_), + SARGS(pwritev, rdec, arg_fd, arg_, arg_, arg_), + SARGS(rt_tgsigqueueinfo, rdec, arg_, arg_, arg_, arg_), + SARGS(perf_event_open, rdec, arg_, arg_, arg_, arg_, arg_), + SARGS(recvmmsg, rdec, arg_fd, arg_, arg_, arg_, arg_), + SARGS(fanotify_init, rdec, arg_, arg_), + SARGS(fanotify_mark, rdec, arg_, arg_, arg_, arg_, arg_), + SARGS(prlimit64, rdec, arg_, arg_, arg_, arg_), + SARGS(name_to_handle_at, rdec, arg_atfd, arg_cstr, arg_, arg_, arg_), + SARGS(open_by_handle_at, rdec, arg_atfd, arg_cstr, arg_), + SARGS(clock_adjtime, rdec, arg_, arg_), + SARGS(syncfs, rdec, arg_fd), + SARGS(sendmmsg, rdec, arg_fd, arg_, arg_, arg_), + SARGS(setns, rdec, arg_fd, arg_), + SARGS(getcpu, rdec, arg_, arg_, arg_), + SARGS(process_vm_readv, rdec, arg_, arg_, arg_, arg_, arg_, arg_), + SARGS(process_vm_writev, rdec, arg_, arg_, arg_, arg_, arg_, arg_), + SARGS(kcmp, rdec, arg_, arg_, arg_, arg_, arg_), + SARGS(finit_module, rdec, arg_fd, arg_, arg_), +#ifdef SYS_sched_setattr + SARGS(sched_setattr, rdec, arg_, arg_, arg_), +#endif +#ifdef SYS_sched_getattr + SARGS(sched_getattr, rdec, arg_, arg_, arg_, arg_), +#endif +#ifdef SYS_renameat2 + SARGS(renameat2, rdec, arg_atfd, arg_cstr, arg_atfd, arg_cstr, arg_), +#endif +#ifdef SYS_seccomp + SARGS(seccomp, rdec, arg_, arg_, arg_), +#endif +#ifdef SYS_getrandom + SARGS(getrandom, rdec, arg_, arg_, arg_), +#endif +#ifdef SYS_memfd_create + SARGS(memfd_create, rdec, arg_cstr, arg_), +#endif +#ifdef SYS_kexec_file_load + SARGS(kexec_file_load, rdec, arg_, arg_, arg_, arg_, arg_), +#endif +#ifdef SYS_bpf + SARGS(bpf, rdec, arg_, arg_, arg_), +#endif +#ifdef SYS_execveat + SARGS(execveat, rdec, arg_atfd, arg_cstr, arg_, arg_, arg_), +#endif +#ifdef SYS_userfaultfd + SARGS(userfaultfd, rdec, arg_), +#endif +#ifdef SYS_membarrier + SARGS(membarrier, rdec, arg_, arg_), +#endif +#ifdef SYS_mlock2 + SARGS(mlock2, rdec, arg_, arg_, arg_), +#endif +#ifdef SYS_copy_file_range + SARGS(copy_file_range, rdec, arg_fd, arg_, arg_fd, arg_, arg_, arg_), +#endif +#ifdef SYS_preadv2 + SARGS(preadv2, rdec, arg_fd, arg_, arg_, arg_, arg_), +#endif +#ifdef SYS_pwritev2 + SARGS(pwritev2, rdec, arg_fd, arg_, arg_, arg_, arg_), +#endif +#ifdef SYS_pkey_mprotect + SARGS(pkey_mprotect, rdec, arg_, arg_, arg_, arg_), +#endif +#ifdef SYS_pkey_alloc + SARGS(pkey_alloc, rdec, arg_, arg_), +#endif +#ifdef SYS_pkey_free + SARGS(pkey_free, rdec, arg_), +#endif +}; +/* END CSTYLED */ + +#undef SARGS + +static struct syscall_format open_with_o_creat = {.name = "open", rdec, + {arg_cstr, arg_open_flags, arg_oct_mode}}; + +static struct syscall_format openat_with_o_creat = {.name = "openat", rdec, + {arg_atfd, arg_cstr, arg_open_flags, arg_oct_mode}}; + +static struct syscall_format unkown = {.name = NULL, rdec, + {arg_, arg_, arg_, arg_, arg_, arg_}}; + +const struct syscall_format * +get_syscall_format(const struct syscall_desc *desc) +{ + if (desc->nr < 0 || (size_t)desc->nr >= ARRAY_SIZE(formats)) + return &unkown; + + if (formats[desc->nr].name == NULL) + return &unkown; + + if (desc->nr == SYS_open && ((desc->args[1] & O_CREAT) == O_CREAT)) + return &open_with_o_creat; + + if (desc->nr == SYS_openat && ((desc->args[2] & O_CREAT) == O_CREAT)) + return &openat_with_o_creat; + + return formats + desc->nr; +} diff --git a/src/syscall_formats.h b/src/syscall_formats.h new file mode 100644 index 00000000..0a422422 --- /dev/null +++ b/src/syscall_formats.h @@ -0,0 +1,91 @@ +/* + * Copyright 2017, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef INTERCEPT_SYSCALL_FORMATS_H +#define INTERCEPT_SYSCALL_FORMATS_H + +#include "intercept.h" + +/* + * The formats of syscall arguments, as they should appear in logs. + * Note: the code is specific to the x86_64 ABI used on Linux, thus + * assumes the following integer sizes: + * int - 32bit + * long - 64bit + * intptr_t - 64bit + * These assumptions would only be wrong when the assembly code in the + * library would also be ported to some different ABI. + */ +enum arg_format { + arg_none = 0, /* no argument, used as a null terminator */ + arg_, /* general argument, not interpreted, print as hexadecimal */ + arg_dec, /* decimal number */ + arg_dec32, /* 32 bit decimal number */ + arg_oct_mode, /* mode_t, octal number ( open, chmod, etc.. ) */ + arg_hex, /* hexadecimal number, with zero padding e.g. pointers */ + arg_cstr, /* zero terminated string */ + arg_buf_in, /* input buffer, with a size in the next argument */ + arg_buf_out, /* output buffer, with a size in the result */ + arg_open_flags, /* only used for oflags in open, openat */ + arg_fd, /* fd argument - not the first argument of *at syscalls */ + arg_atfd, /* fd argument - the first argument of *at syscalls */ + arg_pointer, /* general pointer argument */ + arg_fcntl_args, /* 2nd (and 3rd) argument of fcntl */ + arg_clone_flags, /* 1st argument of clone */ + arg_seek_whence, /* 3rd argument of lseek */ + arg_2fds, /* array of 2 int fd numbers */ + arg_pipe2_flags, /* second argument of pipe2 */ + arg_access_mode /* second argument of access */ +}; + +/* + * The formats of syscall return values. + * Negative values greater than -4096 are always treated as error codes. + */ +enum return_type { + rpointer, + rhex, + rdec, + rmode, + rnoreturn /* syscall does not return, e.g. exit */ +}; + +struct syscall_format { + const char *name; + enum return_type return_type; + const enum arg_format args[7]; +}; + +const struct syscall_format * +get_syscall_format(const struct syscall_desc *desc); + +#endif diff --git a/test/libcintercept0.log.match b/test/libcintercept0.log.match index f400b7c0..a760f061 100644 --- a/test/libcintercept0.log.match +++ b/test/libcintercept0.log.match @@ -1,21 +1,21 @@ -$(S) $(XX) -- clone(CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID, 0x0, 0x0, $(XX), $(XX)) = ? -$(OPT)$(S) $(XX) -- clone(CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID, 0x0, 0x0, $(XX), $(XX)) = 0 -$(S) $(XX) -- clone(CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID, 0x0, 0x0, $(XX), $(XX)) = $(N) -$(OPT)$(S) $(XX) -- clone(CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID, 0x0, 0x0, $(XX), $(XX)) = 0 +$(S) $(XX) -- clone(CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID | 0x11, (null), (null), $(XX), $(XX)) = ? +$(OPT)$(S) $(XX) -- clone(CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID | 0x11, (null), (null), $(XX), $(XX)) = 0 +$(S) $(XX) -- clone(CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID | 0x11, (null), (null), $(XX), $(XX)) = $(N) +$(OPT)$(S) $(XX) -- clone(CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID | 0x11, (null), (null), $(XX), $(XX)) = 0 $(S) $(XX) -- wait4(-1, 0x0, 0x0, 0x0) = ? -$(OPT)$(S) $(XX) -- clone(CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID, 0x0, 0x0, $(XX), $(XX)) = 0 +$(OPT)$(S) $(XX) -- clone(CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID | 0x11, (null), (null), $(XX), $(XX)) = 0 $(OPT)$(S) $(XX) -- set_robust_list($(XX), $(N)) = ? $(OPT)$(S) $(XX) -- set_robust_list($(XX), $(N)) = $(N) $(S) $(XX) -- wait4(-1, 0x0, 0x0, 0x0) = $(N) -$(S) $(XX) -- open($(S), O_RDONLY, 0666) = ? -$(S) $(XX) -- open($(S), O_RDONLY, 0666) = $(N) +$(S) $(XX) -- open($(S), O_RDONLY) = ? +$(S) $(XX) -- open($(S), O_RDONLY) = $(N) $(S) $(XX) -- fstat($(N), $(XX)) = ? $(S) $(XX) -- fstat($(N), $(XX)) = 0 $(OPT)$(S) $(XX) -- mmap($(XX), $(N), $(N), $(N), $(N), $(XX)) = ? $(OPT)$(S) $(XX) -- mmap($(XX), $(N), $(N), $(N), $(N), $(XX)) = $(N) $(OPT)$(S) $(XX) -- mmap($(XX), $(N), $(N), $(N), $(N), $(XX)) = ? $(OPT)$(S) $(XX) -- mmap($(XX), $(N), $(N), $(N), $(N), $(XX)) = $(N) -$(S) $(XX) -- read($(N), "", $(N)) = ? +$(S) $(XX) -- read($(N), $(XX), $(N)) = ? $(S) $(XX) -- read($(N), "/*\n * Copyright 2016-2017, Intel Corporation\n *\n * Redistribution and use in source and binary forms, with or without\n...", $(N)) = $(N) $(S) $(XX) -- fstat(1, $(XX)) = ? $(S) $(XX) -- fstat(1, $(XX)) = 0 diff --git a/test/libcintercept0_child.log.match b/test/libcintercept0_child.log.match index ed6ce2e6..e4b3a1dd 100644 --- a/test/libcintercept0_child.log.match +++ b/test/libcintercept0_child.log.match @@ -1,12 +1,12 @@ -$(S) $(XX) -- open($(S), O_RDONLY, 0666) = ? -$(S) $(XX) -- open($(S), O_RDONLY, 0666) = $(N) +$(S) $(XX) -- open($(S), O_RDONLY) = ? +$(S) $(XX) -- open($(S), O_RDONLY) = $(N) $(S) $(XX) -- fstat($(N), $(XX)) = ? $(S) $(XX) -- fstat($(N), $(XX)) = 0 $(OPT)$(S) $(XX) -- mmap($(XX), $(N), $(N), $(N), $(N), $(XX)) = ? $(OPT)$(S) $(XX) -- mmap($(XX), $(N), $(N), $(N), $(N), $(XX)) = $(N) $(OPT)$(S) $(XX) -- mmap($(XX), $(N), $(N), $(N), $(N), $(XX)) = ? $(OPT)$(S) $(XX) -- mmap($(XX), $(N), $(N), $(N), $(N), $(XX)) = $(N) -$(S) $(XX) -- read($(N), "", $(N)) = ? +$(S) $(XX) -- read($(N), $(XX), $(N)) = ? $(S) $(XX) -- read($(N), "/*\n * Copyright 2016-2017, Intel Corporation\n *\n * Redistribution and use in source and binary forms, with or without\n...", $(N)) = $(N) $(S) $(XX) -- fstat(1, $(XX)) = ? $(S) $(XX) -- fstat(1, $(XX)) = 0 diff --git a/test/libcintercept1.log.match b/test/libcintercept1.log.match index 87c3ebfe..79d3f52e 100644 --- a/test/libcintercept1.log.match +++ b/test/libcintercept1.log.match @@ -1,6 +1,6 @@ $(S) $(XX) -- write(8765, "dummy_data\0", 11) = ? $(S) $(XX) -- write(8765, "dummy_data\0", 11) = 5 $(S) $(XX) -- write(8765, "thin", 4) = ? -$(S) $(XX) -- write(8765, "thin", 4) = -9 +$(S) $(XX) -- write(8765, "thin", 4) = -9 EBADF (Bad file number) $(S) $(XX) -- write(8765, "dummy_data\0", 11) = ? $(S) $(XX) -- write(8765, "dummy_data\0", 11) = 5