/** * @author Christian Burger (christian@krikkel.de) * @todo Switch over to ? For resolving system call numbers? * Maybe keep the current solution as a fallback? * @todo catch `out of range` exception from stoi() * * Contains mapping of system calls numbers to names from original dev system: * "Linux 5.13.0-28-generic #31~20.04.1-Ubuntu SMP \ * Wed Jan 19 14:08:10 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux" * See comment at the end for the actual command to gather mapping information. */ #ifndef NDEBUG #include "Debug.hpp" #include #include #include #include #include #include #include #include #define BUFFER_SIZE 128 namespace krikkel { using std::string; using std::fstream; using std::filesystem::is_directory; using std::endl; using std::time; using std::localtime; using std::strftime; using std::min; Debug::Debug() { string directory = "."; if(is_directory("sandbox")) directory = "./sandbox"; logFile = fstream(directory + "/debug.log", fstream::out | fstream::app);//| fstream::trunc); logFile << endl << endl << endl << endl << "New instance of class Debug." << endl; logFile << getUname(); logFile.flush(); } string Debug::getUname() { string result = ""; char buffer[BUFFER_SIZE]; FILE *unameProcess = popen("uname -srvmpio", "r"); if(unameProcess && fgets(buffer, BUFFER_SIZE, unameProcess)) result = buffer; pclose(unameProcess); return result; } string Debug::getTimestamp() { time_t now = time(NULL); tm *localNow = localtime(&now); static char formattedLocalNow[32]; strftime(formattedLocalNow, 32, "%c", localNow); return formattedLocalNow; } void Debug::log(string message, string fileName, int lineNo, string functionName) { string output = ""; size_t position = message.find("sysCall("); if(position != string::npos) { size_t end = message.find_first_not_of("0123456789", position + 8); unsigned long long systemCallNumber = std::stoi(message.substr(position + 8, end - position - 8)); string systemCallName = strlen(syscalls[systemCallNumber]) != 0 ? syscalls[systemCallNumber] : "unknown_system_call"; if(systemCallNumber < MAX_NUMBER_OF_SYSCALLS) output = message.replace(position, end - position + 1, systemCallName + "("); } if(output == "") output = message; logFile << getTimestamp() << ": " << output << " (in " << fileName.substr(fileName.rfind('/') + 1) << ":" << lineNo << " in " << functionName << "())" << endl; logFile.flush(); } std::string Debug::peekData(pid_t shellPid, void *data, size_t length) { std::string result; for(int index = 0; index < length / sizeof(long); ++index) { long datum = ptrace(PTRACE_PEEKDATA, shellPid, ((char *) data) + index * sizeof(long)); if(length == -1) { size_t datumLength = strnlen((char *) &datum, sizeof(long)); result += string((char *) &datum, datumLength); if(datumLength < sizeof(long)) break; } else result += string((char *) &datum, sizeof(long)); } return result; } std::string Debug::formatToAddress(unsigned long long address) { char addressString[17]; snprintf(addressString, 17, "%016llx", address); return string("0x") + addressString; } void Debug::logPtraceSysCall(pid_t shellPid, uint16_t sysCallId, bool returnedFromSysCall, unsigned long long result, unsigned long long firstArgument, unsigned long long secondArgument, unsigned long long thirdArgument, unsigned long long fourthArgument, std::string fileName, int lineNo, std::string functionName) { const static uint8_t maxStringLength = 32; string message = "syscall: "; string sysCallName; if(sysCallId < MAX_NUMBER_OF_SYSCALLS) sysCallName = syscalls[sysCallId]; if(sysCallName.empty()) sysCallName = "syscall" + std::to_string(sysCallId); switch(sysCallId) { case SYS_read: if(returnedFromSysCall) message += (result == -1 ? "-1" : std::to_string((size_t) result)) + " = "; message += sysCallName + "(" + std::to_string((int) firstArgument) + ", \"" + (returnedFromSysCall ? __debug_make_bytes_printable(peekData(shellPid, (char *) secondArgument, (size_t) min(thirdArgument, maxStringLength))) : "") + (maxStringLength < thirdArgument || returnedFromSysCall == true ? "[…]" : "") + "\"" + ", " + std::to_string((size_t) thirdArgument) + ")"; break; case SYS_write: if(returnedFromSysCall) message += (result == -1 ? "-1" : std::to_string((size_t) result)) + " = "; message += sysCallName + "(" + std::to_string((int) firstArgument) + ", \"" + __debug_make_bytes_printable(peekData(shellPid, (char *) secondArgument, (size_t) min(thirdArgument, maxStringLength))) + (maxStringLength < thirdArgument || returnedFromSysCall == true ? "[…]" : "") + "\"" + ", " + std::to_string((size_t) thirdArgument) + ")"; break; case SYS_close: if(returnedFromSysCall) message += std::to_string((int) result) + " = "; message += sysCallName + "(" + std::to_string((int) firstArgument) + ")"; break; case SYS_stat: if(returnedFromSysCall) message += std::to_string((int) result) + " = "; message += sysCallName + "(\"" + peekData(shellPid, (char *) firstArgument, -1) + "\"" + ", " + formatToAddress(secondArgument) + ")"; break; case SYS_fstat: if(returnedFromSysCall) message += std::to_string((int) result) + " = "; message += sysCallName + "(" + std::to_string((int) firstArgument) + ", " + formatToAddress(secondArgument) + ")"; break; case SYS_openat: if(returnedFromSysCall) message += std::to_string((int) result) + " = "; message += sysCallName + "(" + ((int) firstArgument == AT_FDCWD ? string("AT_FDCWD") : std::to_string((int) firstArgument)) + ", \"" + __debug_make_bytes_printable(peekData(shellPid, (char *) secondArgument, -1)) + "\"" + ", " + std::to_string((int) thirdArgument) + ")"; break; case SYS_rt_sigprocmask: if(returnedFromSysCall) message += std::to_string((int) result) + " = "; message += sysCallName + "(" + std::to_string((int) firstArgument) + ", " + formatToAddress(secondArgument) + ", " + formatToAddress(thirdArgument) + ", " + std::to_string((size_t) fourthArgument) + ")"; break; case SYS_access: if(returnedFromSysCall) message += std::to_string((int) result) + " = "; message += sysCallName + "(" + peekData(shellPid, (char *) firstArgument, -1) + ", " + std::to_string((int) secondArgument) + ")"; break; case SYS_dup2: if(returnedFromSysCall) message += std::to_string((int) result) + " = "; message += sysCallName + "(" + std::to_string((int) firstArgument) + ", " + std::to_string((int) secondArgument) + ")"; break; case SYS_fcntl: if(returnedFromSysCall) message += std::to_string((int) result) + " = "; message += sysCallName + "(" + std::to_string((int) firstArgument) + ", " + (secondArgument == 0 ? string("F_DUP_FD") : std::to_string((int) secondArgument)) + ", …" + ")"; break; /* case SYS_fstat: struct stat statbuf; message += "(" + std::to_string(firstArgument) + ", \"" + __debug_make_bytes_printable(peekData(shellPid, (char *) secondArgument, (size_t) min(thirdArgument, maxStringLength))) + (maxStringLength < thirdArgument ? "[…]" : "") + "\"" + ", " + std::to_string((size_t) thirdArgument) + ")"; break; */ default: if(returnedFromSysCall) message += (result == -1 ? "-1" : std::to_string(result)) + " = "; message += sysCallName + "(" + formatToAddress(firstArgument) + ", " + formatToAddress(secondArgument) + ", " + formatToAddress(thirdArgument) + ", " + formatToAddress(fourthArgument) + ")"; } // source: https://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/ log(message, fileName, lineNo, functionName); } Debug *Debug::getInstance() { static Debug *debug = new Debug(); return debug; } const char *Debug::syscalls[MAX_NUMBER_OF_SYSCALLS] = {[0] = "read",[1] = "write", [2] = "open",[3] = "close", [4] = "stat",[5] = "fstat", [6] = "lstat",[7] = "poll", [8] = "lseek",[9] = "mmap", [10] = "mprotect",[11] = "munmap", [12] = "brk",[13] = "rt_sigaction", [14] = "rt_sigprocmask",[15] = "rt_sigreturn", [16] = "ioctl",[17] = "pread64", [18] = "pwrite64",[19] = "readv", [20] = "writev",[21] = "access", [22] = "pipe",[23] = "select", [24] = "sched_yield",[25] = "mremap", [26] = "msync",[27] = "mincore", [28] = "madvise",[29] = "shmget", [30] = "shmat",[31] = "shmctl", [32] = "dup",[33] = "dup2", [34] = "pause",[35] = "nanosleep", [36] = "getitimer",[37] = "alarm", [38] = "setitimer",[39] = "getpid", [40] = "sendfile",[41] = "socket", [42] = "connect",[43] = "accept", [44] = "sendto",[45] = "recvfrom", [46] = "sendmsg",[47] = "recvmsg", [48] = "shutdown",[49] = "bind", [50] = "listen",[51] = "getsockname", [52] = "getpeername",[53] = "socketpair", [54] = "setsockopt",[55] = "getsockopt", [56] = "clone",[57] = "fork", [58] = "vfork",[59] = "execve", [60] = "exit",[61] = "wait4", [62] = "kill",[63] = "uname", [64] = "semget",[65] = "semop", [66] = "semctl",[67] = "shmdt", [68] = "msgget",[69] = "msgsnd", [70] = "msgrcv",[71] = "msgctl", [72] = "fcntl",[73] = "flock", [74] = "fsync",[75] = "fdatasync", [76] = "truncate",[77] = "ftruncate", [78] = "getdents",[79] = "getcwd", [80] = "chdir",[81] = "fchdir", [82] = "rename",[83] = "mkdir", [84] = "rmdir",[85] = "creat", [86] = "link",[87] = "unlink", [88] = "symlink",[89] = "readlink", [90] = "chmod",[91] = "fchmod", [92] = "chown",[93] = "fchown", [94] = "lchown",[95] = "umask", [96] = "gettimeofday",[97] = "getrlimit", [98] = "getrusage",[99] = "sysinfo", [100] = "times",[101] = "ptrace", [102] = "getuid",[103] = "syslog", [104] = "getgid",[105] = "setuid", [106] = "setgid",[107] = "geteuid", [108] = "getegid",[109] = "setpgid", [110] = "getppid",[111] = "getpgrp", [112] = "setsid",[113] = "setreuid", [114] = "setregid",[115] = "getgroups", [116] = "setgroups",[117] = "setresuid", [118] = "getresuid",[119] = "setresgid", [120] = "getresgid",[121] = "getpgid", [122] = "setfsuid",[123] = "setfsgid", [124] = "getsid",[125] = "capget", [126] = "capset",[127] = "rt_sigpending", [128] = "rt_sigtimedwait",[129] = "rt_sigqueueinfo", [130] = "rt_sigsuspend",[131] = "sigaltstack", [132] = "utime",[133] = "mknod", [134] = "uselib",[135] = "personality", [136] = "ustat",[137] = "statfs", [138] = "fstatfs",[139] = "sysfs", [140] = "getpriority",[141] = "setpriority", [142] = "sched_setparam",[143] = "sched_getparam", [144] = "sched_setscheduler",[145] = "sched_getscheduler", [146] = "sched_get_priority_max",[147] = "sched_get_priority_min", [148] = "sched_rr_get_interval",[149] = "mlock", [150] = "munlock",[151] = "mlockall", [152] = "munlockall",[153] = "vhangup", [154] = "modify_ldt",[155] = "pivot_root", [156] = "",[157] = "prctl", [158] = "arch_prctl",[159] = "adjtimex", [160] = "setrlimit",[161] = "chroot", [162] = "sync",[163] = "acct", [164] = "settimeofday",[165] = "mount", [166] = "",[167] = "swapon", [168] = "swapoff",[169] = "reboot", [170] = "sethostname",[171] = "setdomainname", [172] = "iopl",[173] = "ioperm", [174] = "",[175] = "init_module", [176] = "delete_module",[177] = "", [178] = "",[179] = "quotactl", [180] = "",[181] = "", [182] = "",[183] = "", [184] = "",[185] = "", [186] = "gettid",[187] = "readahead", [188] = "setxattr",[189] = "lsetxattr", [190] = "fsetxattr",[191] = "getxattr", [192] = "lgetxattr",[193] = "fgetxattr", [194] = "listxattr",[195] = "llistxattr", [196] = "flistxattr",[197] = "removexattr", [198] = "lremovexattr",[199] = "fremovexattr", [200] = "tkill",[201] = "time", [202] = "futex",[203] = "sched_setaffinity", [204] = "sched_getaffinity",[205] = "set_thread_area", [206] = "io_setup",[207] = "io_destroy", [208] = "io_getevents",[209] = "io_submit", [210] = "io_cancel",[211] = "get_thread_area", [212] = "",[213] = "epoll_create", [214] = "",[215] = "", [216] = "remap_file_pages",[217] = "getdents64", [218] = "set_tid_address",[219] = "restart_syscall", [220] = "semtimedop",[221] = "fadvise64", [222] = "timer_create",[223] = "timer_settime", [224] = "timer_gettime",[225] = "timer_getoverrun", [226] = "timer_delete",[227] = "clock_settime", [228] = "clock_gettime",[229] = "clock_getres", [230] = "clock_nanosleep",[231] = "exit_group", [232] = "epoll_wait",[233] = "epoll_ctl", [234] = "tgkill",[235] = "utimes", [236] = "",[237] = "mbind", [238] = "set_mempolicy",[239] = "get_mempolicy", [240] = "mq_open",[241] = "mq_unlink", [242] = "mq_timedsend",[243] = "mq_timedreceive", [244] = "mq_notify",[245] = "mq_getsetattr", [246] = "kexec_load",[247] = "waitid", [248] = "add_key",[249] = "request_key", [250] = "keyctl",[251] = "ioprio_set", [252] = "ioprio_get",[253] = "inotify_init", [254] = "inotify_add_watch",[255] = "inotify_rm_watch", [256] = "migrate_pages",[257] = "openat", [258] = "mkdirat",[259] = "mknodat", [260] = "fchownat",[261] = "futimesat", [262] = "newfstatat",[263] = "unlinkat", [264] = "renameat",[265] = "linkat", [266] = "symlinkat",[267] = "readlinkat", [268] = "fchmodat",[269] = "faccessat", [270] = "pselect6",[271] = "ppoll", [272] = "unshare",[273] = "set_robust_list", [274] = "get_robust_list",[275] = "splice", [276] = "tee",[277] = "sync_file_range", [278] = "vmsplice",[279] = "move_pages", [280] = "utimensat",[281] = "epoll_pwait", [282] = "signalfd",[283] = "timerfd_create", [284] = "eventfd",[285] = "fallocate", [286] = "timerfd_settime",[287] = "timerfd_gettime", [288] = "accept4",[289] = "signalfd4", [290] = "eventfd2",[291] = "epoll_create1", [292] = "dup3",[293] = "pipe2", [294] = "inotify_init1",[295] = "preadv", [296] = "pwritev",[297] = "rt_tgsigqueueinfo", [298] = "perf_event_open",[299] = "recvmmsg", [300] = "fanotify_init",[301] = "fanotify_mark", [302] = "prlimit64",[303] = "name_to_handle_at", [304] = "open_by_handle_at",[305] = "clock_adjtime", [306] = "syncfs",[307] = "sendmmsg", [308] = "setns",[309] = "getcpu", [310] = "process_vm_readv",[311] = "process_vm_writev", [312] = "kcmp",[313] = "finit_module", [314] = "sched_setattr",[315] = "sched_getattr", [316] = "renameat2",[317] = "seccomp", [318] = "getrandom",[319] = "memfd_create", [320] = "kexec_file_load",[321] = "bpf", [322] = "execveat",[323] = "userfaultfd", [324] = "membarrier",[325] = "mlock2", [326] = "copy_file_range",[327] = "preadv2", [328] = "pwritev2",[329] = "pkey_mprotect", [330] = "pkey_alloc",[331] = "pkey_free", [332] = "statx",[333] = "io_pgetevents", [334] = "rseq",[335] = "", [336] = "",[337] = "", [338] = "",[339] = "", [340] = "",[341] = "", [342] = "",[343] = "", [344] = "",[345] = "", [346] = "",[347] = "", [348] = "",[349] = "", [350] = "",[351] = "", [352] = "",[353] = "", [354] = "",[355] = "", [356] = "",[357] = "", [358] = "",[359] = "", [360] = "",[361] = "", [362] = "",[363] = "", [364] = "",[365] = "", [366] = "",[367] = "", [368] = "",[369] = "", [370] = "",[371] = "", [372] = "",[373] = "", [374] = "",[375] = "", [376] = "",[377] = "", [378] = "",[379] = "", [380] = "",[381] = "", [382] = "",[383] = "", [384] = "",[385] = "", [386] = "",[387] = "", [388] = "",[389] = "", [390] = "",[391] = "", [392] = "",[393] = "", [394] = "",[395] = "", [396] = "",[397] = "", [398] = "",[399] = "", [400] = "",[401] = "", [402] = "",[403] = "", [404] = "",[405] = "", [406] = "",[407] = "", [408] = "",[409] = "", [410] = "",[411] = "", [412] = "",[413] = "", [414] = "",[415] = "", [416] = "",[417] = "", [418] = "",[419] = "", [420] = "",[421] = "", [422] = "",[423] = "", [424] = "pidfd_send_signal",[425] = "io_uring_setup", [426] = "io_uring_enter",[427] = "io_uring_register", [428] = "open_tree",[429] = "move_mount", [430] = "fsopen",[431] = "fsconfig", [432] = "fsmount",[433] = "fspick", [434] = "pidfd_open",[435] = "clone3" }; } #endif /* Following command in part thx to: https://unix.stackexchange.com/questions/445507/syscall-number-%E2%86%92-name-mapping-at-runtime Command to create mapping of system call number to system call name: #!/bin/bash awk 'BEGIN { print "#include " } /p_syscall_meta/ { syscall = substr($NF, 19); printf "[SYS_%s] = \"%s\", \n", syscall, syscall }' /proc/kallsyms \ | gcc -E -P - \ | sort -V \ | grep "\[[0-9]" \ | awk 'BEGIN {expectedIndex = 0;} { actualIndex = $1; gsub(/[\[\]]/, "", actualIndex); if (actualIndex != expectedIndex) for (; expectedIndex < actualIndex; expectedIndex++) print "[" expectedIndex "] = \"\","; print $0; expectedIndex++ }' \ | tr -d "\n" \ | sed -e "s/^/const char *syscalls[1024] = {/; s/,$/ };/" \ | sed -e 's/,/,\n /2;P;D' \ | cat - <(echo) # new line at the end */