kNCurses/Debug.cpp

503 lines
23 KiB
C++

/**
* @author Christian Burger (christian@krikkel.de)
* @todo Switch over to <seccomp.h>? 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 <algorithm>
#include <cstring>
#include <filesystem>
#include <cstdio>
#include <syscall.h>
#include <sys/ptrace.h>
#include <sys/stat.h>
#include <fcntl.h>
#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<unsigned long long>(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<unsigned long long>(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<unsigned long long>(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 <sys/syscall.h>" }
/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
*/