From 9d77520efa78ba52489b5a1136fb9717f554b747 Mon Sep 17 00:00:00 2001 From: Mateusz Moscicki Date: Thu, 22 Feb 2018 10:40:41 +0100 Subject: [PATCH 01/16] crash-manager: fix get cmd_path This commit fixes issue with report not being generated for processes started using a relative path (e.g.: ./test-app). In above case cmdline contained only './test-app' string and based on that it was impossible to determine the full path to a binary. Consequently, crash-manager assumed crashed program binary did not exist and did not generate the report. This commit changes the logic as follows: cinfo->cmd_name is read from /proc//cmdline cinfo->cmd_path is read from /proc//exe Change-Id: If1b7557b53417d2703a81644939692fee5c801ee --- src/crash-manager/crash-manager.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/src/crash-manager/crash-manager.c b/src/crash-manager/crash-manager.c index 580cb3c..4a5a44a 100644 --- a/src/crash-manager/crash-manager.c +++ b/src/crash-manager/crash-manager.c @@ -209,8 +209,9 @@ static int get_cmd_info(struct crash_info *cinfo) { int fd; int ret; - char *dup_cmd_path; + char cmdline[PATH_MAX]; char cmdline_path[PATH_MAX]; + char exe_link[PATH_MAX]; snprintf(cmdline_path, sizeof(cmdline_path), "/proc/%s/cmdline", cinfo->pid_info); @@ -220,21 +221,32 @@ static int get_cmd_info(struct crash_info *cinfo) return -1; } - ret = read(fd, cinfo->cmd_path, sizeof(cinfo->cmd_path) - 1); + ret = read(fd, cmdline, sizeof(cmdline) - 1); if (ret <= 0) { _E("Failed to read %s", cmdline_path); goto error; - } else if (access(cinfo->cmd_path, F_OK) == -1) { - _E("Invalid path %s", cinfo->cmd_path); - ret = -1; + } + + snprintf(cinfo->cmd_name, sizeof(cinfo->cmd_name), "%s", + basename(cmdline)); + + snprintf(exe_link, sizeof(exe_link), + "/proc/%s/exe", cinfo->pid_info); + + ret = readlink(exe_link, cinfo->cmd_path, + sizeof(cinfo->cmd_path) - 1); + if (ret <= 0) { + _E("Failed to read link %s", exe_link); goto error; } + cinfo->cmd_path[ret] = '\0'; - dup_cmd_path = strdup(cinfo->cmd_path); - snprintf(cinfo->cmd_name, sizeof(cinfo->cmd_name), - "%s", basename(dup_cmd_path)); - free(dup_cmd_path); + if (access(cinfo->cmd_path, F_OK) == -1) { + _E("Invalid path %s", cinfo->cmd_path); + ret = -1; + goto error; + } error: close(fd); -- 2.7.4 From 1d0d800b2129a1b2521ffc603fc247daffb18850 Mon Sep 17 00:00:00 2001 From: Mateusz Moscicki Date: Mon, 26 Feb 2018 13:22:47 +0100 Subject: [PATCH 02/16] crash-manager: don't store in zip archive files referred by symlinks minicoredump (will be introduced in next commit) has an option to save /proc// files in report. As /proc//fd/* contains symlinks, the created archive will contain the contents of these fds. This is undesirable as files might be quite big and contain private (sensitive) data. This commit adds -y option to zip, which will allow storing symlinks to actual files instead of their contents (as it was available originally under /proc//)" Change-Id: I0a7c9211eab1acd39da7db3930e967ddab5eceef --- src/crash-manager/crash-manager.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crash-manager/crash-manager.c b/src/crash-manager/crash-manager.c index 4a5a44a..28d9cd0 100644 --- a/src/crash-manager/crash-manager.c +++ b/src/crash-manager/crash-manager.c @@ -762,7 +762,7 @@ static void compress(void) return; } - ret = snprintf(command, sizeof(command), "cd %s && /bin/zip -r %s %s > /dev/null 2>&1", + ret = snprintf(command, sizeof(command), "cd %s && /bin/zip -y -r %s %s > /dev/null 2>&1", crash_info.temp_dir, zip_path, crash_info.name); if (ret < 0) { _E("Failed to snprintf for zip command"); -- 2.7.4 From 194eeea2ada4a02a00e5fc6517ac6f9fd1e327a8 Mon Sep 17 00:00:00 2001 From: Sunmin Lee Date: Thu, 28 Sep 2017 19:05:07 +0900 Subject: [PATCH 03/16] Fix potentially undefined behavior The documentation does not describe the behavior of the access() function for a NULL path argument, which can be returned by mkdtemp() Change-Id: I9c5c08eb424f5e9bdab248682b00e9cb895c7afa Signed-off-by: Sunmin Lee [ Cherry-picked from tizen_4.0 branch, extended commit message ] Signed-off-by: Mateusz Moscicki --- src/crash-manager/crash-manager.c | 4 ++-- src/dump_systemstate/dump_systemstate.c | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/crash-manager/crash-manager.c b/src/crash-manager/crash-manager.c index 28d9cd0..cc409d4 100644 --- a/src/crash-manager/crash-manager.c +++ b/src/crash-manager/crash-manager.c @@ -256,7 +256,7 @@ error: static int set_crash_info(int argc, char *argv[]) { int ret; - char *temp_dir_ret; + char *temp_dir_ret = NULL; time_t time_val; struct tm loc_tm; @@ -283,7 +283,7 @@ static int set_crash_info(int argc, char *argv[]) return -1; } temp_dir_ret = mkdtemp(crash_info.temp_dir); - if (access(temp_dir_ret, F_OK)) { + if (!temp_dir_ret || access(temp_dir_ret, F_OK)) { _E("Failed to mkdtemp for temp_dir"); return -1; } diff --git a/src/dump_systemstate/dump_systemstate.c b/src/dump_systemstate/dump_systemstate.c index 09467b1..0bf881e 100644 --- a/src/dump_systemstate/dump_systemstate.c +++ b/src/dump_systemstate/dump_systemstate.c @@ -106,8 +106,9 @@ int main(int argc, char *argv[]) case 'f': arg_file = optarg; break; - case '?': printf("\n"); + case '?': case 'h': + printf("\n"); usage(); ret = 0; goto exit; -- 2.7.4 From 804618f4143986122ae1280ab6ca8de78f160de8 Mon Sep 17 00:00:00 2001 From: Mateusz Moscicki Date: Fri, 11 May 2018 15:34:42 +0200 Subject: [PATCH 04/16] Set the default DBus policy for send and own to deny Change-Id: I49230b5c711cf7c4158f6de2fb448638035d750b --- src/log_dump/log_dump.conf | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/log_dump/log_dump.conf b/src/log_dump/log_dump.conf index 3d3e8e0..8674f46 100644 --- a/src/log_dump/log_dump.conf +++ b/src/log_dump/log_dump.conf @@ -21,11 +21,7 @@ - - + + -- 2.7.4 From 70c1372b5a85a64d5ea7c5bb20b99429213942be Mon Sep 17 00:00:00 2001 From: Mateusz Moscicki Date: Mon, 28 May 2018 12:46:32 +0200 Subject: [PATCH 05/16] crash-pipe: Fix write the coredump to the file splice len parameter is size_t type. On some architectures (eg. aarch64) splice returned EINVAL when the parameter len was ssize_t variable and was equal SSIZE_MAX Change-Id: Id84038662dcd2969a33af1e276a3b4500a780f29 --- src/crash-pipe/crash-pipe.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/crash-pipe/crash-pipe.c b/src/crash-pipe/crash-pipe.c index d04037b..0a8cb4d 100644 --- a/src/crash-pipe/crash-pipe.c +++ b/src/crash-pipe/crash-pipe.c @@ -32,6 +32,7 @@ #include #include #include +#include enum { OPT_HELP, @@ -74,7 +75,7 @@ static int copy_fd_splice(int in, int out) ssize_t s; _Bool copied_data = 0; - const ssize_t max_splice = SSIZE_MAX; + const size_t max_splice = SIZE_MAX; do { s = splice(in, NULL, out, NULL, max_splice, SPLICE_F_MOVE); -- 2.7.4 From e80ae266d95e2bba3d9d16a9e7815faf8804fffd Mon Sep 17 00:00:00 2001 From: Mateusz Moscicki Date: Fri, 20 Apr 2018 08:35:39 +0200 Subject: [PATCH 06/16] Stop setting the PR_SET_DUMPABLE flag for crash-manager processes prctl(PR_SET_DUMPABLE, 0) is not neccessary. Kernel runs the crash-manager and sets RLIMIT_CORE to 1 for the process. This is special value that prevents from running crash-manager recursively. Change-Id: I33df7c28c6ce939f2903d02af673734d473b649e --- src/crash-manager/crash-manager.c | 7 ++++++- src/crash-pipe/crash-pipe.c | 2 -- src/crash-stack/crash-stack.c | 2 -- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/crash-manager/crash-manager.c b/src/crash-manager/crash-manager.c index cc409d4..d1fe227 100644 --- a/src/crash-manager/crash-manager.c +++ b/src/crash-manager/crash-manager.c @@ -807,9 +807,14 @@ int main(int argc, char *argv[]) int debug_mode = access(DEBUGMODE_PATH, F_OK) == 0; #endif - prctl(PR_SET_DUMPABLE, 0); + /* + * prctl(PR_SET_DUMPABLE, 0) is not neccessary. Kernel runs the + * crash-manager and sets RLIMIT_CORE to 1 for the process. This is special + * value that prevents from running crash-manager recursively. + */ /* Get Configuration */ + get_config(); /* Create crash directories */ diff --git a/src/crash-pipe/crash-pipe.c b/src/crash-pipe/crash-pipe.c index 0a8cb4d..e6759c3 100644 --- a/src/crash-pipe/crash-pipe.c +++ b/src/crash-pipe/crash-pipe.c @@ -127,8 +127,6 @@ int main(int argc, char *argv[]) char *opt_save_core = NULL; int ret = 1; - prctl(PR_SET_DUMPABLE, 0); - argv0 = argv[0]; while ((c = getopt_long_only(argc, argv, "", opts, NULL)) != -1) { diff --git a/src/crash-stack/crash-stack.c b/src/crash-stack/crash-stack.c index add619b..73d6bd2 100644 --- a/src/crash-stack/crash-stack.c +++ b/src/crash-stack/crash-stack.c @@ -934,8 +934,6 @@ int main(int argc, char **argv) pid_t tid = 0; char bufferfile_path[20] = "/tmp/crash.XXXXXX"; - prctl(PR_SET_DUMPABLE, 0); - while ((c = getopt_long_only(argc, argv, "", opts, NULL)) != -1) { switch (c) { case OPT_PID: -- 2.7.4 From 6490e79cc9a0ae99f5bca5534f204343dcc733ce Mon Sep 17 00:00:00 2001 From: Mateusz Moscicki Date: Wed, 30 May 2018 13:31:21 +0200 Subject: [PATCH 07/16] Revert "crash-pipe: Fix write the coredump to the file" This reverts commit 70c1372b5a85a64d5ea7c5bb20b99429213942be. Change-Id: I553b4c6ef2e5aa9cdc80e4d58ecd318dc0a2d532 --- src/crash-pipe/crash-pipe.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/crash-pipe/crash-pipe.c b/src/crash-pipe/crash-pipe.c index e6759c3..1ba2f3a 100644 --- a/src/crash-pipe/crash-pipe.c +++ b/src/crash-pipe/crash-pipe.c @@ -32,7 +32,6 @@ #include #include #include -#include enum { OPT_HELP, @@ -75,7 +74,7 @@ static int copy_fd_splice(int in, int out) ssize_t s; _Bool copied_data = 0; - const size_t max_splice = SIZE_MAX; + const ssize_t max_splice = SSIZE_MAX; do { s = splice(in, NULL, out, NULL, max_splice, SPLICE_F_MOVE); -- 2.7.4 From 04d9badae6e14ed23b0421224e87ea609f2a9182 Mon Sep 17 00:00:00 2001 From: Mateusz Moscicki Date: Wed, 30 May 2018 13:33:20 +0200 Subject: [PATCH 08/16] crash-pipe: Fix write the coredump to the file splice returns EINVAL if (loff_t)(len + out.pos) is negative number. This was the case on aarch64 and x86_64. Change-Id: Ic52d08efce3fca555a83319c8161c3656b553cc1 --- src/crash-pipe/crash-pipe.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/crash-pipe/crash-pipe.c b/src/crash-pipe/crash-pipe.c index 1ba2f3a..53c0ac0 100644 --- a/src/crash-pipe/crash-pipe.c +++ b/src/crash-pipe/crash-pipe.c @@ -74,10 +74,14 @@ static int copy_fd_splice(int in, int out) ssize_t s; _Bool copied_data = 0; - const ssize_t max_splice = SSIZE_MAX; + ssize_t max_splice = SSIZE_MAX; do { s = splice(in, NULL, out, NULL, max_splice, SPLICE_F_MOVE); + // output file position + len must not exceed the loff_t type limit, + // that's why we reduce len in every iteration + max_splice -= s; + // We can try to fallback to simple copy only if first splice failed // (ie. we have not consumed any data yet) if (!copied_data && s > 0) -- 2.7.4 From 51cdc2c06af4fc4bcae017a61485a428529a1a02 Mon Sep 17 00:00:00 2001 From: Mateusz Moscicki Date: Wed, 16 May 2018 08:23:00 +0200 Subject: [PATCH 09/16] Add timeout to run_command_write_fd and replace popen by execvpe dump_systemstate runs many external commands. When one hungs, dump_systemstate will block the crash-worker. execvpe replaced popen because popen passes command to /bin/sh, and this can potentially allow to run the malicious command if attacker can modify the fragment of cmd, e.g: void read_file(char *filename) { ... sprintf(buff, "cat %s", filename); popen(buff, "r"); ... } main() { char filename[] = "/etc/passwd;rm -rf /"; read_file(filename); } Change-Id: Id7b37c058869c27d3c4d282d9d2dd30d5b9ec80c --- src/dump_systemstate/dump_systemstate.c | 41 ++++-- src/shared/util.c | 223 ++++++++++++++++++++++++++++++-- src/shared/util.h | 4 +- 3 files changed, 242 insertions(+), 26 deletions(-) diff --git a/src/dump_systemstate/dump_systemstate.c b/src/dump_systemstate/dump_systemstate.c index 0bf881e..1c5296e 100644 --- a/src/dump_systemstate/dump_systemstate.c +++ b/src/dump_systemstate/dump_systemstate.c @@ -37,6 +37,9 @@ #include "shared/log.h" #define FILE_PERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH) + +#define TIMEOUT_DEFAULT 60 + static struct dump_item { const char *title; const char *path; @@ -147,69 +150,83 @@ int main(int argc, char *argv[]) fprintf_fd(out_fd, "\n"); fprintf_fd(out_fd, "\n==== System disk space usage (/bin/df -h)\n"); - ret = run_command_write_fd("/bin/df -h", out_fd); + char *df_args[] = {"/bin/df", "-h", NULL}; + ret = run_command_write_fd_timeout(df_args[0], df_args, NULL, out_fd, NULL, 0, TIMEOUT_DEFAULT); if (ret < 0) goto exit_close; dpercent = get_disk_used_percent("/opt"); if (90 < dpercent) { fprintf_fd(out_fd, "\n==== System disk space usage detail - %d\% (/bin/du -ah /opt)\n", dpercent); - ret = run_command_write_fd("/usr/bin/du -ah /opt --exclude=/opt/usr", out_fd); + char *du_args[] = {"/bin/du", "-ah", "/opt", "--exclude=/opt/usr", NULL}; + ret = run_command_write_fd_timeout(du_args[0], du_args, NULL, out_fd, NULL, 0, TIMEOUT_DEFAULT); if (ret < 0) goto exit_close; } fprintf_fd(out_fd, "\n==== System timezone (ls -al /opt/etc/localtime)\n"); - ret = run_command_write_fd("ls -al /opt/etc/localtime", out_fd); + char *ls_args[] = {"/bin/ls", "-al", "/opt/etc/localtime", NULL}; + ret = run_command_write_fd_timeout(ls_args[0], ls_args, NULL, out_fd, NULL, 0, TIMEOUT_DEFAULT); if (ret < 0) goto exit_close; fprintf_fd(out_fd, "\n==== System summary (/usr/bin/top -bcH -n 1)\n"); - ret = run_command_write_fd("COLUMNS=200 /usr/bin/top -bcH -n 1", out_fd); + char *top_args[] = {"/bin/top", "-bcH", "-n", "1", NULL}; + char *top_env[] = {"COLUMNS=200", NULL}; + ret = run_command_write_fd_timeout(top_args[0], top_args, top_env, out_fd, NULL, 0, TIMEOUT_DEFAULT); if (ret < 0) goto exit_close; fprintf_fd(out_fd, "\n==== Current processes (/bin/ps auxfw)\n"); - ret = run_command_write_fd("/bin/ps auxfw", out_fd); + char *ps_args[] = {"/bin/ps", "auxfw", NULL}; + ret = run_command_write_fd_timeout(ps_args[0], ps_args, NULL, out_fd, NULL, 0, TIMEOUT_DEFAULT); if (ret < 0) goto exit_close; fprintf_fd(out_fd, "\n==== System memory statistics (/usr/bin/memps -v)\n"); - ret = run_command_write_fd("/usr/bin/memps -v", out_fd); + char *memps_args[] = {"/bin/memps", "-v", NULL}; + ret = run_command_write_fd_timeout(memps_args[0], memps_args, NULL, out_fd, NULL, 0, TIMEOUT_DEFAULT); if (ret < 0) goto exit_close; if (is_root) { fprintf_fd(out_fd, "\n==== System configuration (/usr/bin/vconftool get memory, db, file)\n"); - ret = run_command_write_fd("/usr/bin/vconftool get memory/ -r", out_fd); + char *get_mem_args[] = {"/bin/vconftool", "get", "memory/", "-r", NULL}; + ret = run_command_write_fd_timeout(get_mem_args[0], get_mem_args, NULL, out_fd, NULL, 0, TIMEOUT_DEFAULT); if (ret < 0) goto exit_close; - ret = run_command_write_fd("/usr/bin/vconftool get db/ -r", out_fd); + char *get_db_args[] = {"/bin/vconftool", "get", "db/", "-r", NULL}; + ret = run_command_write_fd_timeout(get_db_args[0], get_db_args, NULL, out_fd, NULL, 0, TIMEOUT_DEFAULT); if (ret < 0) goto exit_close; - ret = run_command_write_fd("/usr/bin/vconftool get file/ -r", out_fd); + char *get_file_args[] = {"/bin/vconftool", "get", "file/", "-r", NULL}; + ret = run_command_write_fd_timeout(get_file_args[0], get_file_args, NULL, out_fd, NULL, 0, TIMEOUT_DEFAULT); if (ret < 0) goto exit_close; } if (arg_dmesg && is_root) { fprintf_fd(out_fd, "\n==== Kernel messages (TZ=UTC /bin/dmesg -T)\n"); - ret = run_command_write_fd("TZ=UTC /bin/dmesg -T", out_fd); + char *dmesg_args[] = {"/bin/dmesg", "-T", NULL}; + char *dmesg_env[] = {"TZ=UTC", NULL}; + ret = run_command_write_fd_timeout(dmesg_args[0], dmesg_args, dmesg_env, out_fd, NULL, 0, TIMEOUT_DEFAULT); if (ret < 0) goto exit_close; } if (arg_dlog) { fprintf_fd(out_fd, "\n==== Log messages\n"); - ret = run_command_write_fd("/usr/bin/dlogutil -d -v threadtime -u 16384", out_fd); + char *dlogutil_args[] = {"/bin/dlogutil", "-d", "-v", "threadtime", "-u", "16384", NULL}; + ret = run_command_write_fd_timeout(dlogutil_args[0], dlogutil_args, NULL, out_fd, NULL, 0, TIMEOUT_DEFAULT); if (ret < 0) goto exit_close; } if (arg_journal) { fprintf_fd(out_fd, "\n==== Journal messages\n"); - ret = run_command_write_fd("/usr/bin/journalctl -b -n 1024", out_fd); + char *journalctl_args[] = {"/bin/journalctl", "-b", "-n", "1024", NULL}; + ret = run_command_write_fd_timeout(journalctl_args[0], journalctl_args, NULL, out_fd, NULL, 0, TIMEOUT_DEFAULT); if (ret < 0) goto exit_close; } diff --git a/src/shared/util.c b/src/shared/util.c index e18e943..8075f12 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -36,6 +37,9 @@ #include "util.h" #include "log.h" +#define READ_BUFF_SIZE 4096 +#define SELECT_TIMEOUT_US 100000 + int system_command_parallel(char *command) { int pid = 0; @@ -285,27 +289,220 @@ int dump_file_write_fd(char *src, int dfd) return 1; } -int run_command_write_fd(char *cmd, int dfd) +static int run_command(char *path, char *args[], char *env[], int fd[]) { - FILE *fp; - char buff[PIPE_BUF]; - int ret; + if (dup2(fd[1], STDOUT_FILENO) == -1) { + _E("dup2 error: %m"); + return -1; + } - if (!cmd) { - _E("Invalid argument\n"); + if (close(fd[1]) == -1) { + _E("close fd error: %m"); return -1; } - fp = popen(cmd, "r"); - if (fp == NULL) { - _E("Failed to popen\n"); + if (close(fd[0]) == -1) { + _E("close fd error: %m"); return -1; } - while (fgets(buff, PIPE_BUF, fp) != NULL) - write_fd(dfd, buff, strlen(buff)); - ret = pclose(fp); - return ret; + if (execvpe(path, args, env) == -1) { + _E("run command %s error: %m", path); + return -1; + } + return -1; +} + +static void wait_for_child(pid_t pid, int timeout) +{ + for (int i = 0; i < 10*timeout; i++) { + int status; + pid_t p = waitpid(pid, &status, WNOHANG); + if (p == pid) { + if (WIFSIGNALED(status)) { + _I("Killed by signal %d\n", WTERMSIG(status)); + break; + } else if (WIFEXITED(status)) { + if (WEXITSTATUS(status) > 0) + _I("Exit code %d\n", WEXITSTATUS(status)); + break; + } + } else if (p == -1) { + _E("waitpid error: %m"); + break; + } + usleep(100000); + } +} + +static int read_into_buff(int fd, char *buff, int size, int timeout_us, int *eof) +{ + struct timeval tout; + int sel_ret; + fd_set set; + + FD_ZERO(&set); + FD_SET(fd, &set); + + tout.tv_sec = timeout_us / 1000000; + tout.tv_usec = timeout_us % 1000000; + *eof = 0; + + int buff_pos = 0; + if ((sel_ret = select(fd+1, &set, NULL, NULL, &tout)) >= 0) { + if (sel_ret > 0) { + // we can do nonblocking read + int readed = read(fd, &buff[buff_pos], size); + + if (readed > 0) { + buff_pos += readed; + size -= readed; + } else if (readed == 0) { + // no more data to read + *eof = 1; + } else { + // error + _E("read data from the pipe error: %m"); + return -1; + } + } + } else + _E("select() error: %m"); + return buff_pos; +} + +// Usage: +// if buff is not NULL then 'size' bytes of the result is written the buffer, +// otherwise result is written to the dfd descriptor +int run_command_write_fd_timeout(char *path, char *args[], char *env[], int dfd, char *buff, int size, int timeout) +{ + char BUFF[READ_BUFF_SIZE]; + int fd[2]; + struct timeval start, end; + int write_to_fd = buff == NULL ? 1 : 0; + + if (!write_to_fd && size <= 0) { + _E("buffer size must be greather than zero"); + return -1; + } + + if (pipe(fd)) { + _E("pipe create error: %m"); + return -1; + } + + pid_t pid = fork(); + + if (pid == 0) { + return run_command(path, args, env, fd); + } else if (pid > 0) { + if (close(fd[1]) == -1) { + _E("close fd error: %m"); + return -1; + } + + if (gettimeofday(&start, NULL) == -1) { + _E("gettimeofday error: %m"); + return -1; + } + + int readed; + int eof = 0; + int outdated = 0; + int count = 0; + + int act_size; + char *act_buff; + + if (write_to_fd) { + act_size = READ_BUFF_SIZE; + act_buff = BUFF; + } else { + act_size = size; + act_buff = buff; + } + + while ((readed = read_into_buff(fd[0], act_buff, act_size, 1000000, &eof)) >= 0) { + if (readed > 0) { + // we have some data + if (count < (INT_MAX - readed)) + count += readed; + else + count = INT_MAX; + + if (write_to_fd) { + if (write_fd(dfd, act_buff, readed) == -1) { + _E("write data to pipe error: %m"); + break; + } + } else { + act_buff += readed; + act_size -= readed; + + if (act_size == 0) { + // buff is full, we can return + eof = 1; + } + } + } + + if (eof) + break; + + if (gettimeofday(&end, NULL) == -1) { + _E("gettimeofday error: %m"); + break; + } + + if ((end.tv_sec - start.tv_sec) > timeout) { + outdated = 1; + break; + } + + if (readed == 0) + usleep(100000); + } + + if (outdated) { + _E("command timeout: %s", path); + if (kill(pid, 0) == 0) { + // we can kill a child because we don't + // need it anymore + if (kill(pid, SIGTERM) == -1) + _E("kill child %d error: %m", pid); + } + } + + if (close(fd[0]) == -1) { + _E("close fd error: %m"); + return -1; + } + + // let's wait a second for a child + wait_for_child(pid, 1); + + return eof == 1 ? count : -1; + } else { + _E("fork() error: %m"); + return -1; + } + + return -1; +} + +int run_command_timeout(char *path, char *args[], char *env[], int timeout) +{ + int fd = open("/dev/null", O_WRONLY); + if (fd < 0) { + _E("open /dev/null error: %m"); + return -1; + } + + int res = run_command_write_fd_timeout(path, args, env, fd, NULL, 0, timeout); + + close(fd); + + return res; } static int remove_dir_internal(int fd) diff --git a/src/shared/util.h b/src/shared/util.h index 85416fa..eb34a6b 100644 --- a/src/shared/util.h +++ b/src/shared/util.h @@ -43,7 +43,9 @@ int move_file(char *src, char *dst); int dump_file_write_fd(char *src, int dfd); -int run_command_write_fd(char *cmd, int dfd); +int run_command_write_fd_timeout(char *path, char *args[], char *env[], int dfd, char *buff, int size, int timeout); + +int run_command_timeout(char *path, char *args[], char *env[], int timeout); int remove_dir(const char *path, int del_dir); -- 2.7.4 From b9071f6c3d2e15c04ccc720a018410da230a78cd Mon Sep 17 00:00:00 2001 From: Sunmin Lee Date: Mon, 18 Sep 2017 13:27:50 +0900 Subject: [PATCH 10/16] Fix vulnerabilities Change-Id: Ia7d8565ef86cfef9d8b61e2e11020b6f1b49ed1d Signed-off-by: Sunmin Lee --- src/crash-stack/crash-stack.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/crash-stack/crash-stack.c b/src/crash-stack/crash-stack.c index 73d6bd2..09de05c 100644 --- a/src/crash-stack/crash-stack.c +++ b/src/crash-stack/crash-stack.c @@ -646,7 +646,7 @@ static struct addr_node *get_addr_list_from_maps(int fd) /* parsing the maps to get executable code address */ while (fgets_fd(linebuf, BUF_SIZE, fd) != NULL) { memset(path, 0, PATH_MAX); - result = sscanf(linebuf, "%s %s %*s %*s %*s %s ", addr, perm, path); + result = sscanf(linebuf, "%34s %5s %*s %*s %*s %256s ", addr, perm, path); if (result < 0) continue; perm[PERM_LEN - 1] = 0; @@ -757,7 +757,7 @@ static void __crash_stack_print_meminfo(FILE* outputfile, pid_t pid) fprintf(errfile, "[crash-stack] cannot open /proc/meminfo\n"); } else { while (fgets_fd(linebuf, BUF_SIZE, fd) != NULL) { - sscanf(linebuf, "%s %s %*s", infoname, memsize); + sscanf(linebuf, "%16s %16s %*s", infoname, memsize); if (strcmp("MemTotal:", infoname) == 0) { fprintf(outputfile, "%s %8s KB\n", infoname, memsize); } else if (strcmp("MemFree:", infoname) == 0) { @@ -777,7 +777,7 @@ static void __crash_stack_print_meminfo(FILE* outputfile, pid_t pid) fprintf(errfile, "[crash-stack] cannot open %s\n", file_path); } else { while (fgets_fd(linebuf, BUF_SIZE, fd) != NULL) { - sscanf(linebuf, "%s %s %*s", infoname, memsize); + sscanf(linebuf, "%16s %16s %*s", infoname, memsize); if (strcmp("VmPeak:", infoname) == 0) { fprintf(outputfile, "%s %8s KB\n", infoname, memsize); -- 2.7.4 From 104b22b9ef844809cae97d420bcbe43e1c9ce6bd Mon Sep 17 00:00:00 2001 From: Mateusz Moscicki Date: Thu, 14 Jun 2018 12:37:56 +0200 Subject: [PATCH 11/16] Fix stack-buffer-overflow error Lenghts in sscanf format string refer to actually read bytes, without including space for null byte, E.g.: ... char buff[5+1]; sscanf(other_buff, "%5s", buff); ... Change-Id: I203e1bc04ba1e352029849e5bd29a7a6ca8a5763 --- src/crash-stack/crash-stack.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/crash-stack/crash-stack.c b/src/crash-stack/crash-stack.c index 09de05c..7581e08 100644 --- a/src/crash-stack/crash-stack.c +++ b/src/crash-stack/crash-stack.c @@ -58,6 +58,8 @@ #define STR_ANONY "[anony]" #define STR_ANONY_LEN 8 +#define STR_FS(length) "%"#length"s" + static FILE *outputfile = NULL; ///< global output stream static FILE *errfile = NULL; ///< global error stream static FILE *bufferfile = NULL; ///< buffer file for ordering @@ -646,7 +648,10 @@ static struct addr_node *get_addr_list_from_maps(int fd) /* parsing the maps to get executable code address */ while (fgets_fd(linebuf, BUF_SIZE, fd) != NULL) { memset(path, 0, PATH_MAX); - result = sscanf(linebuf, "%34s %5s %*s %*s %*s %256s ", addr, perm, path); + result = sscanf(linebuf, STR_FS(sizeof(addr)-1) + STR_FS(sizeof(perm)-1) + "%*s %*s %*s" + STR_FS(sizeof(path)-1), addr, perm, path); if (result < 0) continue; perm[PERM_LEN - 1] = 0; -- 2.7.4 From 2e07672c2aa7d393ba2937bd57171c2af8d90367 Mon Sep 17 00:00:00 2001 From: Mateusz Moscicki Date: Tue, 20 Mar 2018 08:43:10 +0100 Subject: [PATCH 12/16] Add *.so_info file to the report *.so_info file contains paths, rpm package info (name, version, release, architecture) and build IDs of mapped files that have a execute flag in /proc//maps. Change-Id: I087a8d25efeb1f51a5e25d95cce5c60a8f2a607b --- src/crash-manager/CMakeLists.txt | 1 + src/crash-manager/crash-manager.c | 18 +++ src/crash-manager/so-info.c | 280 ++++++++++++++++++++++++++++++++++++++ src/crash-manager/so-info.h | 24 ++++ 4 files changed, 323 insertions(+) create mode 100644 src/crash-manager/so-info.c create mode 100644 src/crash-manager/so-info.h diff --git a/src/crash-manager/CMakeLists.txt b/src/crash-manager/CMakeLists.txt index a474f33..db1c99b 100644 --- a/src/crash-manager/CMakeLists.txt +++ b/src/crash-manager/CMakeLists.txt @@ -8,6 +8,7 @@ ENDIF() INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/src) SET(CRASH_MANAGER_SRCS crash-manager.c + so-info.c ${CMAKE_SOURCE_DIR}/src/shared/util.c ) diff --git a/src/crash-manager/crash-manager.c b/src/crash-manager/crash-manager.c index d1fe227..8012e48 100644 --- a/src/crash-manager/crash-manager.c +++ b/src/crash-manager/crash-manager.c @@ -34,6 +34,7 @@ #include #include #include "crash-manager.h" +#include "so-info.h" #include "shared/log.h" #include "shared/util.h" @@ -460,6 +461,20 @@ static int dump_system_state(void) return system_command_parallel(command); } + +static void save_so_info() +{ + char maps_path[PATH_MAX]; + char so_info_path[PATH_MAX]; + snprintf(maps_path, sizeof(maps_path), "/proc/%s/maps", + crash_info.pid_info); + + snprintf(so_info_path, sizeof(so_info_path), + "%s/%s.%s", crash_info.pfx, crash_info.name, "so_info"); + + get_and_save_so_info(maps_path, so_info_path); +} + static void execute_crash_modules(int argc, char *argv[]) { @@ -833,6 +848,9 @@ int main(int argc, char *argv[]) /* Exec dump_systemstate */ dump_state_pid = dump_system_state(); + /* Save shared objects info (file names, bulid IDs, rpm package names) */ + save_so_info(); + /* Exec crash modules */ execute_crash_modules(argc, argv); diff --git a/src/crash-manager/so-info.c b/src/crash-manager/so-info.c new file mode 100644 index 0000000..b766e24 --- /dev/null +++ b/src/crash-manager/so-info.c @@ -0,0 +1,280 @@ +/* + * build-ids + * + * Copyright (c) 2018 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "shared/log.h" +#include "shared/util.h" + +#define BID_SNAME ".note.gnu.build-id" + +#define CMD_RPM "rpm -qf %s --qf '%%{NAME};%%{VERSION};%%{RELEASE};%%{ARCH}'" +#define CMD_RPM_LEN sizeof(CMD_RPM) + +#define RPM_INFO_MAXLEN PATH_MAX + + +static unsigned char *map_file(const char *filename, int64_t *size) +{ + struct stat file_stat; + int fd = open(filename, O_RDONLY); + + if (fd < 0) { + _E("Failed to open file %s: %m", filename); + return NULL; + } + + if (fstat(fd, &file_stat) < 0) { + _E("Failed to get file status %s: %m", filename); + close(fd); + return NULL; + } + + *size = file_stat.st_size; + void *mem = mmap(NULL, file_stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + close(fd); + + if (mem == MAP_FAILED) { + _E("Failed to map file %s into memory: %m", filename); + return NULL; + } + + return (unsigned char*)mem; +} + +#define DECLARE_BUILD_ID_SECTION_ADDRESS(bits) \ +static Elf##bits##_Off build_id_section_address##bits(const unsigned char *mapped_file, const int64_t size)\ +{\ + if (mapped_file <= 0)\ + return -1;\ +\ + Elf##bits##_Ehdr *elheader = (Elf##bits##_Ehdr*)mapped_file;\ + Elf##bits##_Shdr *sec = (Elf##bits##_Shdr*)(mapped_file + elheader->e_shoff);\ +\ + if (size < (intptr_t)sec + elheader->e_shstrndx*sizeof(Elf##bits##_Shdr) - (intptr_t)mapped_file)\ + return -2;\ +\ + char *names = (char *)(mapped_file + sec[elheader->e_shstrndx].sh_offset);\ +\ + for (int i = 0; i < elheader->e_shnum; i++) {\ + char *section_name = (char *)(&names[sec[i].sh_name]);\ + if (sec[i].sh_type == SHT_NOTE &&\ + strncmp(section_name, BID_SNAME, strlen(BID_SNAME)) == 0)\ + return sec[i].sh_offset;\ + } \ +\ + return -1;\ +} \ + +DECLARE_BUILD_ID_SECTION_ADDRESS(32) + +DECLARE_BUILD_ID_SECTION_ADDRESS(64) + +static Elf64_Off build_id_section_address(unsigned char *mapped_file, int64_t size) +{ + Elf64_Off offset; + + if (mapped_file[EI_CLASS] == ELFCLASS32) + offset = build_id_section_address32(mapped_file, size); + else if (mapped_file[EI_CLASS] == ELFCLASS64) + offset = build_id_section_address64(mapped_file, size); + else { + _E("Unrecognized ELF class"); + return 0; + } + + return offset; +} + +static char HEX_CHARS[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + +static int get_build_id_from(const unsigned char *mapped_file, const Elf64_Off section_offset, char **build_id) +{ + const unsigned char *p = mapped_file + section_offset + 0x10; + const unsigned int *len = (unsigned int *)(mapped_file + section_offset + 0x04); + const unsigned int dlen = (*len)*2; + + *build_id = (char *)malloc(dlen+1); + if (*build_id == NULL) { + _E("Failed to allocate memory: %m"); + return -1; + } + + for (int i = 0; i < dlen; p++) { + (*build_id)[i++] = HEX_CHARS[(*p / 16)]; + (*build_id)[i++] = HEX_CHARS[(*p % 16)]; + } + + (*build_id)[dlen] = '\0'; + return dlen; +} + +static int get_build_id(char *filename, char **build_id) +{ + int64_t size = 0; + int ret = 0; + unsigned char *mapped_file = map_file(filename, &size); + *build_id = NULL; + + if (mapped_file > 0) { + Elf64_Off offset = build_id_section_address(mapped_file, size); + if (offset > 0) + ret = get_build_id_from(mapped_file, offset, build_id); + else + ret = -1; + + munmap(mapped_file, size); + } else { + ret = -1; + } + return ret; +} + +static int get_perms(char *line, char *perms) +{ + char *first_space = strchr(line, ' '); + + if (first_space > 0) { + strncpy(perms, first_space+1, 4); + return 0; + } else + return -1; +} + +/* + * Return the pointer to start of the filename if the mapped region has execute + * permission ('x' in perms). Otherwise return NULL. + */ +static char *get_exe_filename(char *line) +{ + char perms[4]; + + if (get_perms(line, perms) == 0 && perms[2] == 'x') { + char *p = strstr(line, " /"); + if (p > 0) + return p+1; + } + return NULL; +} + +GSList* get_filepaths(char *map_path) +{ + char *line = NULL; + size_t len = 0; + GSList *file_list = NULL; + + FILE *f = fopen(map_path, "r"); + + if (f == NULL) { + _E("Failed to open maps file %s: %m", map_path); + return NULL; + } + + while (getline(&line, &len, f) != -1) { + char *exe_filename = get_exe_filename(line); + if (exe_filename == NULL) + continue; + + size_t n = strcspn(exe_filename, "\n"); + + if (n > 0 && n < PATH_MAX) { + char *file_name = (char *)malloc(n+1); + if (file_name == NULL) + continue; + + snprintf(file_name, n+1, "%s", exe_filename); + + file_list = g_slist_append(file_list, file_name); + } + } + + free(line); + fclose(f); + + return file_list; +} + +int get_rpm_info(char *filename, char *rpm_info) +{ + if (!filename) { + _E("Invalid filename"); + return -1; + } + + char *args[] = {"rpm", "-qf", filename, "--qf", "%{NAME};%{VERSION};%{RELEASE};%{ARCH}", NULL}; + + int readed; + if ((readed = run_command_write_fd_timeout("rpm", args, NULL, 0, rpm_info, RPM_INFO_MAXLEN, 60)) == -1) { + _E("Failed to get information about rpm installed packages"); + return -1; + } else { + rpm_info[readed] = 0; + } + + return 0; +} + +void get_and_save_so_info(char *map_path, char *out_path) +{ + GSList *file_list = get_filepaths(map_path); + + char rpm_info[RPM_INFO_MAXLEN+1]; + FILE *f = fopen(out_path, "w"); + + if (f == NULL) { + _E("Failed to open file for writing %s: %m", out_path); + } else { + char *build_id = NULL; + for (GSList *iterator = file_list; iterator; iterator = iterator->next) { + char *file_path = (char *)iterator->data; + + if (get_build_id(file_path, &build_id) <= 0 || build_id == NULL) + continue; + + int fret; + + if (get_rpm_info(file_path, rpm_info) != 0) + fret = fprintf(f, "%s %s\n", file_path, build_id); + else + fret = fprintf(f, "%s %s %s\n", file_path, build_id, rpm_info); + + free(build_id); + + if (fret < 0) { + _E("Failed to write to file %s", out_path); + break; + } + } + fclose(f); + } + + for (GSList *iterator = file_list; iterator; iterator = iterator->next) + free(iterator->data); + + g_slist_free(file_list); +} diff --git a/src/crash-manager/so-info.h b/src/crash-manager/so-info.h new file mode 100644 index 0000000..0b28770 --- /dev/null +++ b/src/crash-manager/so-info.h @@ -0,0 +1,24 @@ +/* + * build-ids + * + * Copyright (c) 2018 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __SO_INFO_H__ +#define __SO_INFO_H__ + +void get_and_save_so_info(char *map_filename, char *out_file); + +#endif -- 2.7.4 From 8cf07473062d7e7720b6cf3ff12d11bcaa859df3 Mon Sep 17 00:00:00 2001 From: Mateusz Moscicki Date: Thu, 22 Feb 2018 10:45:37 +0100 Subject: [PATCH 13/16] crash-manager: add minicoredumper minicoredumper strips unnecessary data from coredump and makes use of sparse file mechanism, to quickly save core files on disc. Change-Id: Ic8e968b5e7a011f9a06794876c372063e968a354 --- CMakeLists.txt | 5 +++- packaging/crash-worker.spec | 15 +++++++++++- src/crash-manager/CMakeLists.txt | 14 ++++++++++- src/crash-manager/crash-manager.c | 46 ++++++++++++++++++++++++++++++++---- src/crash-manager/crash-manager.h.in | 2 ++ 5 files changed, 75 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d55fc2b..f6e47cb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,10 @@ IF("${SYS_ASSERT}" STREQUAL "ON") ADD_SUBDIRECTORY(src/sys-assert) ENDIF("${SYS_ASSERT}" STREQUAL "ON") -ADD_SUBDIRECTORY(src/crash-pipe) +IF(TIZEN_ENABLE_COREDUMP STREQUAL on) + ADD_SUBDIRECTORY(src/crash-pipe) +ENDIF() + IF(TIZEN_FEATURE_PTRACE_CALLSTACK STREQUAL on) ADD_SUBDIRECTORY(src/crash-stack) ENDIF() diff --git a/packaging/crash-worker.spec b/packaging/crash-worker.spec index 0584e3e..d4743e3 100644 --- a/packaging/crash-worker.spec +++ b/packaging/crash-worker.spec @@ -3,6 +3,7 @@ %define _with_tests on %define TIZEN_FEATURE_PTRACE_CALLSTACK on +%define TIZEN_FEATURE_MINICOREDUMPER on %bcond_with doc %bcond_with sys_assert %bcond_with tests @@ -39,6 +40,10 @@ Requires(post): gzip Requires: zip Requires: libelf Requires: libdw + +%if "%{TIZEN_FEATURE_MINICOREDUMPER}" == "on" +Requires: /sbin/minicoredumper +%endif # If you need support for core dump files (see building below), # you should add this dependency # Requires: libebl @@ -85,7 +90,6 @@ cp %{SOURCE1001} . export CFLAGS+=" -Werror" export CFLAGS+=" -DTIZEN_ENGINEER_MODE" -export CFLAGS+=" -DTIZEN_ENABLE_COREDUMP" %ifarch %{arm} aarch64 %define ARCH arm @@ -110,7 +114,14 @@ export CFLAGS+=" -DTIZEN_ENABLE_COREDUMP" -DCRASH_PATH=%{crash_path} \ -DCRASH_TEMP=%{crash_temp} \ -DDEBUGMODE_PATH=%{debugmode_path} \ +%if "%{TIZEN_FEATURE_MINICOREDUMPER}" == "on" + -DTIZEN_ENABLE_MINICOREDUMP=on \ + -DMINICOREDUMPER_PATH=%{_sbindir}/minicoredumper \ + -DMINICOREDUMPER_CONF_DIR=%{_sysconfdir}/minicoredumper \ +%else + -DTIZEN_ENABLE_COREDUMP=on \ -DCRASH_PIPE_PATH=%{_libexecdir}/crash-pipe \ +%endif %if "%{TIZEN_FEATURE_PTRACE_CALLSTACK}" == "on" -DCRASH_STACK_PATH=%{_libexecdir}/crash-stack \ %endif @@ -188,7 +199,9 @@ sed -i "/${pattern}/D" %{_sysconfdir}/ld.so.preload %{_sysconfdir}/tmpfiles.d/sys-assert.conf %endif +%if "%{TIZEN_FEATURE_MINICOREDUMPER}" != "on" %{_libexecdir}/crash-pipe +%endif %if "%{TIZEN_FEATURE_PTRACE_CALLSTACK}" == "on" %{_libexecdir}/crash-stack %endif diff --git a/src/crash-manager/CMakeLists.txt b/src/crash-manager/CMakeLists.txt index db1c99b..d95e846 100644 --- a/src/crash-manager/CMakeLists.txt +++ b/src/crash-manager/CMakeLists.txt @@ -5,6 +5,14 @@ IF(TIZEN_FEATURE_PTRACE_CALLSTACK STREQUAL on) ADD_DEFINITIONS(-DTIZEN_FEATURE_PTRACE_CALLSTACK) ENDIF() +IF(TIZEN_ENABLE_COREDUMP STREQUAL on) + ADD_DEFINITIONS(-DTIZEN_ENABLE_COREDUMP) +ENDIF() + +IF(TIZEN_ENABLE_MINICOREDUMP STREQUAL on) + ADD_DEFINITIONS(-DTIZEN_ENABLE_MINICOREDUMP) +ENDIF() + INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/src) SET(CRASH_MANAGER_SRCS crash-manager.c @@ -26,7 +34,11 @@ ENDFOREACH(flag) SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIE") -IF("$ENV{CFLAGS}" MATCHES "-DTIZEN_ENABLE_COREDUMP") +IF(TIZEN_ENABLE_COREDUMP AND TIZEN_ENABLE_MINICOREDUMP) + message(FATAL_ERROR "You can not define TIZEN_ENABLE_COREDUMP and TIZEN_ENABLE_MINICOREDUMP at once.") +ENDIF() + +IF(TIZEN_ENABLE_COREDUMP OR TIZEN_ENABLE_MINICOREDUMP) OPTION(USE_COREDUMP_CONF "Use COREDUMP CONF" ON) ENDIF() diff --git a/src/crash-manager/crash-manager.c b/src/crash-manager/crash-manager.c index 8012e48..172327c 100644 --- a/src/crash-manager/crash-manager.c +++ b/src/crash-manager/crash-manager.c @@ -43,6 +43,7 @@ /* Parsing */ #define CRASH_CONF_FILE tzplatform_mkpath(TZ_SYS_ETC, "crash-manager.conf") +#define MINICOREDUMPER_CONF_FILE MINICOREDUMPER_CONF_DIR "/minicoredumper.cfg.json" #define KEY_MAX 255 #define CRASH_SECTION "CrashManager" @@ -62,6 +63,8 @@ #define CRASH_CHECK_DISK_PATH "/opt/usr" +#define MINICOREDUMPER_TIMEOUT 12*60 + enum { RET_EXCEED = 1, NUM_EXCEED, @@ -393,7 +396,7 @@ static int get_sysassert_cs(void) } #endif -#ifdef TIZEN_ENABLE_COREDUMP +#if defined(TIZEN_ENABLE_COREDUMP) || defined(TIZEN_ENABLE_MINICOREDUMP) static void launch_crash_popup(void) { GDBusConnection *conn; @@ -478,17 +481,21 @@ static void save_so_info() static void execute_crash_modules(int argc, char *argv[]) { -#if defined(TIZEN_ENABLE_COREDUMP) || defined(TIZEN_FEATURE_PTRACE_CALLSTACK) +#if defined(TIZEN_ENABLE_COREDUMP) || defined(TIZEN_ENABLE_MINICOREDUMP) || defined(TIZEN_FEATURE_PTRACE_CALLSTACK) int ret; char command[PATH_MAX]; #endif + _D("Execute crash module: "); #ifdef TIZEN_ENABLE_COREDUMP /* Execute crash-pipe */ ret = snprintf(command, sizeof(command), "%s --save-core %s", CRASH_PIPE_PATH, crash_info.core_path); + + _D(" %s", command); + if (ret < 0) { _E("Failed to snprintf for crash-pipe command"); return; @@ -496,6 +503,37 @@ static void execute_crash_modules(int argc, char *argv[]) system_command(command); #endif + +#ifdef TIZEN_ENABLE_MINICOREDUMP + char *coredump_name = NULL; + if (asprintf(&coredump_name, "%s.coredump", crash_info.name) == -1) + coredump_name = strdup("core"); + + /* Execute minicoredumper */ + char *args[] = { + MINICOREDUMPER_PATH, // minicoredumper filename path + crash_info.pid_info, // %p - pid + argv[2], // %u - UID + argv[3], // %g - GID + crash_info.sig_info, // %s - number of signal + argv[5], // %t - time of dump + "localhost", // %h - hostname + "core", // %e - exe name (need for result filename) + MINICOREDUMPER_CONF_FILE, // config file + "-d", + crash_info.pfx, // temp dir + "-o", + coredump_name, // coredump filename + NULL + }; + + _D(" %s", args[0]); + + run_command_timeout(args[0], args, NULL, MINICOREDUMPER_TIMEOUT); + + free(coredump_name); +#endif + #ifdef TIZEN_FEATURE_PTRACE_CALLSTACK # ifdef SYS_ASSERT @@ -818,7 +856,7 @@ int main(int argc, char *argv[]) { /* Execute dump_systemstate in parallel */ static int dump_state_pid; -#ifdef TIZEN_ENABLE_COREDUMP +#if defined(TIZEN_ENABLE_COREDUMP) || defined(TIZEN_ENABLE_MINICOREDUMP) int debug_mode = access(DEBUGMODE_PATH, F_OK) == 0; #endif @@ -862,7 +900,7 @@ int main(int argc, char *argv[]) compress(); else move_dump_dir(); -#ifdef TIZEN_ENABLE_COREDUMP +#if defined(TIZEN_ENABLE_COREDUMP) || defined(TIZEN_ENABLE_MINICOREDUMP) /* launch crash-popup only if the .debugmode file is exist*/ if (debug_mode) launch_crash_popup(); diff --git a/src/crash-manager/crash-manager.h.in b/src/crash-manager/crash-manager.h.in index 7a4089e..84c9775 100644 --- a/src/crash-manager/crash-manager.h.in +++ b/src/crash-manager/crash-manager.h.in @@ -27,6 +27,8 @@ #define CRASH_STACK_PATH "@CRASH_STACK_PATH@" #endif #define CRASH_PIPE_PATH "@CRASH_PIPE_PATH@" +#define MINICOREDUMPER_PATH "@MINICOREDUMPER_PATH@" +#define MINICOREDUMPER_CONF_DIR "@MINICOREDUMPER_CONF_DIR@" #define DEBUGMODE_PATH "@DEBUGMODE_PATH@" #endif -- 2.7.4 From 75f3f3ad7695bfa7b5706918f3142fccf82e09c0 Mon Sep 17 00:00:00 2001 From: Karol Lewandowski Date: Mon, 18 Jun 2018 15:06:06 +0200 Subject: [PATCH 14/16] Release crash-worker with minicoredumper Change-Id: Ie72ab3379f50174e1c76c79da5af56cb8aaed5ad --- packaging/crash-worker.spec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packaging/crash-worker.spec b/packaging/crash-worker.spec index d4743e3..e8b63c1 100644 --- a/packaging/crash-worker.spec +++ b/packaging/crash-worker.spec @@ -10,8 +10,8 @@ Name: crash-worker Summary: Crash-manager -Version: 1.0.1 -Release: 3 +Version: 1.1.0 +Release: 1 Group: Framework/system License: Apache-2.0 Source0: %{name}-%{version}.tar.gz -- 2.7.4 From bf66a65758ebb8dff0d70835aac071df8077d666 Mon Sep 17 00:00:00 2001 From: Karol Lewandowski Date: Mon, 18 Jun 2018 16:44:01 +0200 Subject: [PATCH 15/16] packaging: Fix minicoredumper path Change-Id: I5a57f9a3c0272ebed534aee7edd88d2c2f362b89 --- packaging/crash-worker.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/crash-worker.spec b/packaging/crash-worker.spec index e8b63c1..7177835 100644 --- a/packaging/crash-worker.spec +++ b/packaging/crash-worker.spec @@ -42,7 +42,7 @@ Requires: libelf Requires: libdw %if "%{TIZEN_FEATURE_MINICOREDUMPER}" == "on" -Requires: /sbin/minicoredumper +Requires: %{_sbindir}/minicoredumper %endif # If you need support for core dump files (see building below), # you should add this dependency -- 2.7.4 From 7ebf39774d36f40fe43860b894890d1c3a4194e6 Mon Sep 17 00:00:00 2001 From: Mateusz Moscicki Date: Fri, 29 Jun 2018 13:31:38 +0200 Subject: [PATCH 16/16] Fix reading /proc//maps file Macro is expanded by preprocessor, but sizeof() is evaluated at compile time. Change-Id: I4ca20ff703cf89fba2137ec3eb24550d1013fdff --- src/crash-stack/crash-stack.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/crash-stack/crash-stack.c b/src/crash-stack/crash-stack.c index 7581e08..3ddffd7 100644 --- a/src/crash-stack/crash-stack.c +++ b/src/crash-stack/crash-stack.c @@ -53,12 +53,13 @@ #define BUF_SIZE (BUFSIZ) #define HEXA 16 -#define PERM_LEN 5 -#define ADDR_LEN 16 +#define PERM_LEN 4 +#define ADDR_LEN 33 #define STR_ANONY "[anony]" #define STR_ANONY_LEN 8 -#define STR_FS(length) "%"#length"s" +#define STRING_FORMAT_SPECIFIER_WITH_MACRO(macro) "%"#macro"s" +#define STR_FS(macro) STRING_FORMAT_SPECIFIER_WITH_MACRO(macro) static FILE *outputfile = NULL; ///< global output stream static FILE *errfile = NULL; ///< global error stream @@ -93,7 +94,7 @@ const struct option opts[] = { struct addr_node { uintptr_t startaddr; uintptr_t endaddr; - char perm[PERM_LEN]; + char perm[PERM_LEN+1]; char *fpath; struct addr_node *next; }; @@ -637,9 +638,9 @@ static struct addr_node *get_addr_list_from_maps(int fd) int fpath_len, result; uintptr_t saddr; uintptr_t eaddr; - char perm[PERM_LEN]; - char path[PATH_MAX]; - char addr[ADDR_LEN * 2 + 2]; + char perm[PERM_LEN+1]; + char path[PATH_MAX+1]; + char addr[ADDR_LEN+1]; char linebuf[BUF_SIZE]; struct addr_node *head = NULL; struct addr_node *tail = NULL; @@ -647,14 +648,14 @@ static struct addr_node *get_addr_list_from_maps(int fd) /* parsing the maps to get executable code address */ while (fgets_fd(linebuf, BUF_SIZE, fd) != NULL) { - memset(path, 0, PATH_MAX); - result = sscanf(linebuf, STR_FS(sizeof(addr)-1) - STR_FS(sizeof(perm)-1) + memset(path, 0, PATH_MAX+1); + result = sscanf(linebuf, STR_FS(ADDR_LEN) + STR_FS(PERM_LEN) "%*s %*s %*s" - STR_FS(sizeof(path)-1), addr, perm, path); + STR_FS(PATH_MAX), addr, perm, path); if (result < 0) continue; - perm[PERM_LEN - 1] = 0; + perm[PERM_LEN] = 0; /* rwxp */ if ((perm[2] == 'x' && path[0] == '/') || (perm[1] == 'w' && path[0] != '/')) { @@ -672,7 +673,7 @@ static struct addr_node *get_addr_list_from_maps(int fd) fprintf(errfile, "error : mmap\n"); return NULL; } - memcpy(t_node->perm, perm, PERM_LEN); + memcpy(t_node->perm, perm, PERM_LEN+1); t_node->startaddr = saddr; t_node->endaddr = eaddr; t_node->fpath = NULL; -- 2.7.4