/** * @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(size_t index = 0; index < length / sizeof(long); ++index) { long datum = ptrace(PTRACE_PEEKDATA, shellPid, ((char *) data) + index * sizeof(long)); if(length == (size_t) -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 == (unsigned long long) -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 == (unsigned long long) -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 == (unsigned long long) -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 */