From 4466db8a9fedeba2406444c03c044754186d70a6 Mon Sep 17 00:00:00 2001 From: Mateusz Moscicki Date: Tue, 28 May 2019 14:16:31 +0200 Subject: [PATCH 01/16] Fix SVACE warnings Change-Id: I8c1c88cb34637b9c6a341d59134e9bb1c9f1cfea --- src/crash-manager/dbus_notify.c | 2 +- src/crash-stack/crash-stack.c | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/crash-manager/dbus_notify.c b/src/crash-manager/dbus_notify.c index 32448a2..68728a6 100644 --- a/src/crash-manager/dbus_notify.c +++ b/src/crash-manager/dbus_notify.c @@ -192,6 +192,7 @@ static GVariant* build_message_data(const struct NotifyParams *notify_params) static bool send_notify(GDBusConnection *conn, const struct NotifyParams *notify_params) { int result = false; + GError *error = NULL; GVariant *data = build_message_data(notify_params); if (data == NULL) { @@ -199,7 +200,6 @@ static bool send_notify(GDBusConnection *conn, const struct NotifyParams *notify goto out; } - GError *error = NULL; g_dbus_connection_emit_signal(conn, NULL, CRASH_PATH_CRASH, diff --git a/src/crash-stack/crash-stack.c b/src/crash-stack/crash-stack.c index 00e2f3f..fc97c0c 100644 --- a/src/crash-stack/crash-stack.c +++ b/src/crash-stack/crash-stack.c @@ -389,6 +389,10 @@ static struct addr_node *get_addr_list_from_maps(int fd) if ((perm[2] == 'x' && path[0] == '/') || (perm[1] == 'w' && path[0] != '/')) { char* addr2 = strchr(addr, '-'); + if (addr2 == NULL) { + _E("Not found '-' in addr: %s", addr); + continue; + } *(addr2++) = '\0'; /* add addr node to list */ saddr = strtoul(addr, NULL, HEXA); -- 2.7.4 From e0d15c2602b30cc050c387e77faf8501b69432cd Mon Sep 17 00:00:00 2001 From: Mateusz Moscicki Date: Wed, 22 May 2019 12:37:09 +0200 Subject: [PATCH 02/16] Remove logging to error output Change-Id: I7abce9958153729ed7ae91d582970211ad0e004f --- src/crash-stack/crash-stack.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/crash-stack/crash-stack.c b/src/crash-stack/crash-stack.c index fc97c0c..c0f9604 100644 --- a/src/crash-stack/crash-stack.c +++ b/src/crash-stack/crash-stack.c @@ -67,7 +67,6 @@ #define STRWW_FS(macro) STRINGWW_FORMAT_SPECIFIER_WITH_MACRO(macro) static FILE *outputfile = NULL; ///< global output stream -static FILE *errfile = NULL; ///< global error stream static FILE *bufferfile = NULL; ///< buffer file for ordering /** @@ -78,7 +77,6 @@ enum { OPT_TID, OPT_SIGNUM, OPT_OUTPUTFILE, - OPT_ERRFILE, OPT_PRSTATUS_FD }; @@ -90,7 +88,6 @@ const struct option opts[] = { { "tid", required_argument, 0, OPT_TID }, { "sig", required_argument, 0, OPT_SIGNUM }, { "output", required_argument, 0, OPT_OUTPUTFILE }, - { "erroutput", required_argument, 0, OPT_ERRFILE }, { "prstatus_fd", required_argument, 0, OPT_PRSTATUS_FD }, { 0, 0, 0, 0 } }; @@ -615,10 +612,6 @@ int main(int argc, char **argv) case OPT_OUTPUTFILE: outputfile = fopen(optarg, "w"); break; - case OPT_ERRFILE: - errfile = fopen(optarg, "w"); - _W("--erroutput is deprecated"); - break; case OPT_PRSTATUS_FD: prstatus_fd = strtol(optarg, &p, 10); if (*p != 0) @@ -627,11 +620,10 @@ int main(int argc, char **argv) } } - if (NULL == errfile) errfile = stderr; if (NULL == outputfile) outputfile = stdout; if (tid == 0) { - fprintf(errfile, "TID not provided\n"); + _E("TID not provided"); return errno; } -- 2.7.4 From dce1790207fe32b7d87a7a4ac6c571cfaba4246b Mon Sep 17 00:00:00 2001 From: Karol Lewandowski Date: Tue, 18 Jun 2019 15:45:10 +0200 Subject: [PATCH 03/16] system-tests: Fix incorrect variable usage Change-Id: Ifafc9ff3c62f760b96188c4a51471a219e66cee0 --- tests/system/utils/minicore-utils.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/system/utils/minicore-utils.sh b/tests/system/utils/minicore-utils.sh index a677541..94fa8bf 100644 --- a/tests/system/utils/minicore-utils.sh +++ b/tests/system/utils/minicore-utils.sh @@ -45,7 +45,7 @@ function check_file_not_exists { function check_zip_contains { zipfile=${1} pattern="$2" - if ! unzip -qql "$logfile" | grep -E "$pattern"; then + if ! unzip -qql "$zipfile" | grep -E "$pattern"; then exit_with_code "FAIL: zip file ${zipfile} does not contain ${pattern}" ${FAIL_CODE} fi } -- 2.7.4 From 8e2e40cc8470d0d829ad14df5cb35e5fdda76e02 Mon Sep 17 00:00:00 2001 From: Karol Lewandowski Date: Tue, 18 Jun 2019 12:57:48 +0200 Subject: [PATCH 04/16] crash-manager: Add ExtraScript to config ExtraScript will be called for report types >= FULL. This will allow attaching arbitrary data to crash report. Script is called with report's temporary directory as first and only argument, ie. exec("$ExtraScript", "/path/to/report/temp/dir", PID) Change-Id: Icc38b92daae7a39b13063b2c45bffc1b863e72d6 --- packaging/crash-worker_system-tests.spec | 1 + src/crash-manager/crash-manager.c | 27 +++++++++++-- src/crash-manager/crash-manager.conf | 5 +++ src/shared/config.c | 5 +++ src/shared/config.h | 1 + tests/system/CMakeLists.txt | 1 + tests/system/extra_script/extra_script.sh.template | 46 ++++++++++++++++++++++ 7 files changed, 83 insertions(+), 3 deletions(-) create mode 100644 tests/system/extra_script/extra_script.sh.template diff --git a/packaging/crash-worker_system-tests.spec b/packaging/crash-worker_system-tests.spec index 03dcd48..396c7e8 100644 --- a/packaging/crash-worker_system-tests.spec +++ b/packaging/crash-worker_system-tests.spec @@ -72,6 +72,7 @@ cd tests/system %{_libdir}/crash-worker_system-tests/without_core/without_core.sh %{_libdir}/crash-worker_system-tests/crash_root_path/crash_root_path.sh %{_libdir}/crash-worker_system-tests/dump_systemstate_extras/dump_systemstate_extras.sh +%{_libdir}/crash-worker_system-tests/extra_script/extra_script.sh %{_libdir}/crash-worker_system-tests/utils/btee %{_libdir}/crash-worker_system-tests/utils/kenny %{_libdir}/crash-worker_system-tests/utils/minicore-utils.sh diff --git a/src/crash-manager/crash-manager.c b/src/crash-manager/crash-manager.c index 64f538e..f505834 100644 --- a/src/crash-manager/crash-manager.c +++ b/src/crash-manager/crash-manager.c @@ -659,6 +659,22 @@ end: #define SNPRINTF_OR_EXIT_W(name, format, member) if (snprintf(name##_str, sizeof(name##_str), format, cinfo->member) < 0) goto out; #define SNPRINTF_OR_EXIT(name, format) SNPRINTF_OR_EXIT_W(name, format, name##_info) +static bool extra_script(const struct crash_info *cinfo, pid_t *pid) +{ + if (!config.extra_script) + return false; + + char pid_str[11]; + SNPRINTF_OR_EXIT(pid, "%d") + + char *av[] = { config.extra_script, cinfo->pfx, pid_str, NULL }; + spawn_param_s param = { .fn = spawn_setstdout, .u.int_val = STDERR_FILENO }; + return spawn(av, NULL, ¶m, pid, NULL); + +out: + return false; +} + static void launch_dbus_notify(struct crash_info *cinfo) { assert(cinfo); @@ -1198,8 +1214,8 @@ int main(int argc, char *argv[]) { struct crash_info cinfo = {.prstatus_fd = -1}; - /* Execute dump_systemstate in parallel */ - static pid_t dump_state_pid; + /* Execute processes in parallel */ + static pid_t dump_state_pid = 0, extra_script_pid = 0; int debug_mode = access(DEBUGMODE_PATH, F_OK) == 0; int res = 0; @@ -1248,6 +1264,9 @@ int main(int argc, char *argv[]) _E("Failed to get system state report"); goto exit; } + + if (config.extra_script && !extra_script(&cinfo, &extra_script_pid)) + _W("Failed to call extra script from config"); } /* Exec crash modules */ @@ -1261,8 +1280,10 @@ int main(int argc, char *argv[]) /* Save shared objects info (file names, bulid IDs, rpm package names) */ save_so_info(&cinfo); - /* Wait dump_system_state */ + /* Wait misc. pids */ wait_for_pid(dump_state_pid, NULL); + if (extra_script_pid > 0) + wait_for_pid(extra_script_pid, NULL); /* Tar compression */ if (config.allow_zip) diff --git a/src/crash-manager/crash-manager.conf b/src/crash-manager/crash-manager.conf index 82f5b91..c485527 100644 --- a/src/crash-manager/crash-manager.conf +++ b/src/crash-manager/crash-manager.conf @@ -14,3 +14,8 @@ AllowZip=yes # Dump coredump - 1 to enable (default), 0 to disable # This option applies to ReportType=FULL only! # DumpCore=1 + +# Extra script to run whose output will be attached to generated report +# Script will be called with two arguments, in pseudo-code: +# sh -c "$ExtraScript /path/to/report/temp/directory PID" +# ExtraScript=/path/to/script diff --git a/src/shared/config.c b/src/shared/config.c index 617a151..2bd7c7c 100644 --- a/src/shared/config.c +++ b/src/shared/config.c @@ -68,6 +68,11 @@ bool config_init(config_t *c, const char *const path) if (!c->crash_root_path) goto out; + /* strdup() can technically fail, but we don't mind. It is better to + * create a report without the extra script than to abort completely. */ + char *extrascript = GET(string, "ExtraScript", NULL); + c->extra_script = extrascript ? strdup(extrascript) : NULL; + char *reptype = GET(string, "ReportType", (char *)report_type_strmap[REP_TYPE_FULL]); c->report_type = report_type_from_str(reptype); if (!report_type_to_str(c->report_type)) diff --git a/src/shared/config.h b/src/shared/config.h index 7105341..5c3ea1f 100644 --- a/src/shared/config.h +++ b/src/shared/config.h @@ -46,6 +46,7 @@ typedef struct config { int dump_core; enum ReportType report_type; char *crash_root_path; + char *extra_script; } config_t; diff --git a/tests/system/CMakeLists.txt b/tests/system/CMakeLists.txt index 07a676b..da31257 100644 --- a/tests/system/CMakeLists.txt +++ b/tests/system/CMakeLists.txt @@ -37,6 +37,7 @@ configure_test("log_dump_normal") configure_test("log_dump_crash_root_path") configure_test("dump_systemstate_extras") configure_test("livedumper") +configure_test("extra_script") get_property(TESTS_LIST GLOBAL PROPERTY TMP_TESTS_LIST) diff --git a/tests/system/extra_script/extra_script.sh.template b/tests/system/extra_script/extra_script.sh.template new file mode 100644 index 0000000..1c8fe5e --- /dev/null +++ b/tests/system/extra_script/extra_script.sh.template @@ -0,0 +1,46 @@ +#!/bin/bash + +# Custom report path test + +if [ -z "${CRASH_WORKER_SYSTEM_TESTS}" ]; then + CRASH_WORKER_SYSTEM_TESTS="@CRASH_SYSTEM_TESTS_PATH@" +fi + +. ${CRASH_WORKER_SYSTEM_TESTS}/utils/minicore-utils.sh + +CRASH_MANAGER_CONF=/etc/crash-manager.conf + +S=$(mktemp /tmp/extra.XXXXXX) +cat >$S < \$1/cookie +EOF + +chmod 755 $S + +mount -o rw,remount / +mount -o exec,remount /tmp +backup_file ${CRASH_MANAGER_CONF} +cat ${CRASH_MANAGER_CONF}.backup | sed "s|#[ ]\+ExtraScript=.*|ExtraScript=${S}|" > ${CRASH_MANAGER_CONF} + +clean_crash_dump + +{ + ${CRASH_WORKER_SYSTEM_TESTS}/utils/kenny & + sleep 1 + kill -6 $! +} 1> /dev/null 2>&1 + +sleep 2 + +restore_file ${CRASH_MANAGER_CONF} + +wait_for_app crash-manager + +dumpfile="$(echo $CRASH_DUMP_PATH/kenny_*.zip)" +check_file_exists "$dumpfile" +check_zip_contains "$dumpfile" '.*log$' +check_zip_contains "$dumpfile" '.*info$' +check_zip_contains "$dumpfile" '.*cookie$' + +exit_with_code "SUCCESS" ${SUCCESS_CODE} -- 2.7.4 From 532d850fd44f136bfdd7e730194053d1ae5ac6c8 Mon Sep 17 00:00:00 2001 From: Karol Lewandowski Date: Tue, 18 Jun 2019 16:01:08 +0200 Subject: [PATCH 05/16] system-tests: packaging: Sort files Change-Id: Ic61351ecef500221afe2876582a2ae034f905761 --- packaging/crash-worker_system-tests.spec | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/packaging/crash-worker_system-tests.spec b/packaging/crash-worker_system-tests.spec index 396c7e8..1c37a32 100644 --- a/packaging/crash-worker_system-tests.spec +++ b/packaging/crash-worker_system-tests.spec @@ -57,26 +57,26 @@ cd tests/system %{_libdir}/crash-worker_system-tests/check_minicore_mem/cp.sh %{_libdir}/crash-worker_system-tests/cmp_backtraces/cmp_backtraces.sh %{_libdir}/crash-worker_system-tests/cmp_backtraces/cp.sh +%{_libdir}/crash-worker_system-tests/crash_root_path/crash_root_path.sh %{_libdir}/crash-worker_system-tests/critical_process/critical_process.sh -%{_libdir}/crash-worker_system-tests/time_test/time_test.sh -%{_libdir}/crash-worker_system-tests/time_test/cp.sh -%{_libdir}/crash-worker_system-tests/wait_for_opt_usr/wait_for_opt_usr.sh +%{_libdir}/crash-worker_system-tests/dump_systemstate_extras/dump_systemstate_extras.sh +%{_libdir}/crash-worker_system-tests/extra_script/extra_script.sh %{_libdir}/crash-worker_system-tests/info_file/info_file.sh +%{_libdir}/crash-worker_system-tests/log_dump_crash_root_path/log_dump_crash_root_path.sh %{_libdir}/crash-worker_system-tests/log_dump_normal/log_dump_normal.sh %{_libdir}/crash-worker_system-tests/log_dump_short/log_dump_short.sh -%{_libdir}/crash-worker_system-tests/log_dump_crash_root_path/log_dump_crash_root_path.sh %{_libdir}/crash-worker_system-tests/log_file/log_file.sh -%{_libdir}/crash-worker_system-tests/so_info_file/so_info_file.sh %{_libdir}/crash-worker_system-tests/report_basic/report_basic.sh %{_libdir}/crash-worker_system-tests/report_type_info/report_type_info.sh -%{_libdir}/crash-worker_system-tests/without_core/without_core.sh -%{_libdir}/crash-worker_system-tests/crash_root_path/crash_root_path.sh -%{_libdir}/crash-worker_system-tests/dump_systemstate_extras/dump_systemstate_extras.sh -%{_libdir}/crash-worker_system-tests/extra_script/extra_script.sh +%{_libdir}/crash-worker_system-tests/run.sh +%{_libdir}/crash-worker_system-tests/so_info_file/so_info_file.sh +%{_libdir}/crash-worker_system-tests/time_test/cp.sh +%{_libdir}/crash-worker_system-tests/time_test/time_test.sh %{_libdir}/crash-worker_system-tests/utils/btee %{_libdir}/crash-worker_system-tests/utils/kenny %{_libdir}/crash-worker_system-tests/utils/minicore-utils.sh -%{_libdir}/crash-worker_system-tests/run.sh +%{_libdir}/crash-worker_system-tests/wait_for_opt_usr/wait_for_opt_usr.sh +%{_libdir}/crash-worker_system-tests/without_core/without_core.sh %if %{with livedumper} %{_libdir}/crash-worker_system-tests/livedumper/livedumper.sh %endif -- 2.7.4 From b10e3bb4ef1d722e00c0a53d5ea3150ac95a860c Mon Sep 17 00:00:00 2001 From: Karol Lewandowski Date: Tue, 18 Jun 2019 16:01:39 +0200 Subject: [PATCH 06/16] Release 5.5.14 This release brings: - ExtraScript= crash-worker's option, allowing to call arbitrary script which can add files to report - assorted fixes Change-Id: I2828135b2bef5118453c4e3356dfc4f96bc59755 --- packaging/crash-worker.spec | 2 +- packaging/crash-worker_system-tests.spec | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packaging/crash-worker.spec b/packaging/crash-worker.spec index dfa19b8..253d84c 100644 --- a/packaging/crash-worker.spec +++ b/packaging/crash-worker.spec @@ -14,7 +14,7 @@ Name: crash-worker Summary: Crash-manager -Version: 5.5.13 +Version: 5.5.14 Release: 1 Group: Framework/system License: Apache-2.0 and BSD diff --git a/packaging/crash-worker_system-tests.spec b/packaging/crash-worker_system-tests.spec index 1c37a32..039a594 100644 --- a/packaging/crash-worker_system-tests.spec +++ b/packaging/crash-worker_system-tests.spec @@ -8,7 +8,7 @@ Name: crash-worker_system-tests Summary: Package with binaries and scripts for crash-worker system tests -Version: 5.5.13 +Version: 5.5.14 Release: 1 Group: Framework/system License: Apache-2.0 and BSD -- 2.7.4 From 0a91e5e2e78c273ea24e77ef203da8ea8bca09bd Mon Sep 17 00:00:00 2001 From: INSUN PYO Date: Wed, 26 Jun 2019 09:23:41 +0900 Subject: [PATCH 07/16] Change the config value of the "RemainAfterExit=" ("true" -> "yes") Change-Id: I8456f7ebfbbf1679092ff2a9e92745574e482766 --- tests/system/critical_process/critical_process.sh.template | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/system/critical_process/critical_process.sh.template b/tests/system/critical_process/critical_process.sh.template index f609fbe..63568b4 100755 --- a/tests/system/critical_process/critical_process.sh.template +++ b/tests/system/critical_process/critical_process.sh.template @@ -36,7 +36,7 @@ Description=Test service [Service] Type=oneshot ExecStart=/bin/sleep 1 -RemainAfterExit=true +RemainAfterExit=yes ExecStop=/bin/sh -c 'kill -6 \$\$\$\$' [Install] -- 2.7.4 From b8135197ab96bcdb6f3fd8bb0ec999a0da870c24 Mon Sep 17 00:00:00 2001 From: Mateusz Moscicki Date: Wed, 26 Jun 2019 10:49:48 +0200 Subject: [PATCH 08/16] Add ability to dump minicore Change-Id: I9056c6e630e11a9990933832906302e45905dea2 --- LICENSE.BSD | 20 +++ packaging/crash-worker.spec | 2 +- src/livedumper/CMakeLists.txt | 1 + src/livedumper/core.hpp | 317 ++++++++++++++++++++++++++++++++++++++++-- src/livedumper/helpers.hpp | 17 +++ src/livedumper/livedumper.hpp | 32 ++++- src/livedumper/log.hpp | 6 +- src/livedumper/main.cpp | 27 +++- src/livedumper/maps.hpp | 11 +- src/livedumper/note.hpp | 4 + src/livedumper/prochandle.hpp | 108 ++++++++++++++ src/livedumper/program.hpp | 3 +- 12 files changed, 523 insertions(+), 25 deletions(-) create mode 100644 LICENSE.BSD create mode 100644 src/livedumper/prochandle.hpp diff --git a/LICENSE.BSD b/LICENSE.BSD new file mode 100644 index 0000000..5bfb5a0 --- /dev/null +++ b/LICENSE.BSD @@ -0,0 +1,20 @@ +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/packaging/crash-worker.spec b/packaging/crash-worker.spec index 253d84c..5951257 100644 --- a/packaging/crash-worker.spec +++ b/packaging/crash-worker.spec @@ -192,7 +192,7 @@ sed -i "/${pattern}/D" %{_sysconfdir}/ld.so.preload %endif %files -%license LICENSE +%license LICENSE LICENSE.BSD %manifest crash-worker.manifest %defattr(-,system_fw,system_fw,-) %dir %{crash_root_path} diff --git a/src/livedumper/CMakeLists.txt b/src/livedumper/CMakeLists.txt index 27faf24..ea20fc6 100644 --- a/src/livedumper/CMakeLists.txt +++ b/src/livedumper/CMakeLists.txt @@ -18,6 +18,7 @@ endif(DLOG) set(LIVEDUMPER_SRCS main.cpp ${LOGGER_FILE}) add_executable(${LIVEDUMPER_BIN} ${LIVEDUMPER_SRCS}) +target_link_libraries(${LIVEDUMPER_BIN} -lelf -lthread_db) if("${LOGGER}" STREQUAL "dlog") include(FindPkgConfig) diff --git a/src/livedumper/core.hpp b/src/livedumper/core.hpp index d9abfe9..193577c 100644 --- a/src/livedumper/core.hpp +++ b/src/livedumper/core.hpp @@ -5,7 +5,7 @@ * 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 + * 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, @@ -24,31 +24,40 @@ #include "program.hpp" #include +#include #include #include +#include #include +extern "C" { +#include +} + #include #include +#include #include #include #include +static constexpr size_t PAGESIZE = 0x1000; template class Core { private: - static constexpr size_t PAGESIZE = 0x1000; ProgramTableEntryBase *m_note_header; std::vector>> m_phdrt; + std::vector> m_symdata; size_t current_data_address; std::vector > m_notes; typename T::Ehdr m_ehdr; public: Core() : m_note_header(new ProgramTableEntryNote()), - current_data_address(sizeof(m_ehdr)) { - m_phdrt.push_back(std::unique_ptr>(m_note_header)); + current_data_address(sizeof(m_ehdr)), + m_ehdr() { + m_phdrt.push_back(std::unique_ptr>(m_note_header)); } void FillELFHeader() { @@ -84,6 +93,7 @@ class Core { entry->header.p_filesz = record->end - record->start; entry->header.p_memsz = record->end - record->start; entry->header.p_align = PAGESIZE; + entry->important = record->important; m_phdrt.push_back(std::unique_ptr>(entry)); } @@ -146,19 +156,17 @@ class Core { } } - void SaveLoadable(const std::string &mem_path, std::ofstream &core_file) { - int fd = open(mem_path.c_str(), O_RDONLY); - if (fd == -1) - throw std::system_error(errno, std::system_category(), "failed to open mem file " + mem_path); - + void SaveLoadable(int mem_fd, std::ofstream &core_file, bool minicore) { for (const auto &record : m_phdrt) { if (record->header.p_type != PT_LOAD) continue; - if (lseek64(fd, record->header.p_vaddr, SEEK_SET) == -1) + if (lseek64(mem_fd, record->header.p_vaddr, SEEK_SET) == -1) logger.log_error("lseek64 error: %s", std::system_category().default_error_condition(errno).message()); - CopyData(fd, core_file, record->header.p_filesz); + if (!minicore || static_cast*>(record.get())->important) + CopyData(mem_fd, core_file, record->header.p_filesz); + else + core_file.seekp(record->header.p_filesz, std::ios_base::cur); } - close(fd); } void AddNote(Note *note) { @@ -194,6 +202,287 @@ class Core { for (const auto &record : records) ImportMapRecord(record); } -}; -#endif // CORE_HPP__ + typename T::uint AUXVval(const typename T::auxv_t *auxv, typename T::Addr type) { + for (int i = 0; auxv[i].a_type != AT_NULL; i++) { + if (auxv[i].a_type == type) + return auxv[i].a_un.a_val; + } + return 0; + } + + void ReadFromFile(std::ifstream &input, unsigned long address, void *data, size_t len) { + input.seekg(address, std::ios_base::beg); + input.read(static_cast(data), len); + } + + void ReadFromFile(const int fd, unsigned long address, void *data, size_t len) { + lseek64(fd, address, SEEK_SET); + if (read(fd, data, len) == -1) + throw std::system_error(errno, std::system_category(), "failed to read at " + std::to_string(address)); + } + + void DumpData(int fd, std::ofstream &output, typename T::Addr iaddress, typename T::Addr oaddress, size_t len, const std::string &desc) { + lseek64(fd, iaddress, SEEK_SET); + output.seekp(oaddress, std::ios_base::beg); + logger.log_info("dumping %s: 0x%x-0x%x to 0x%x (%d bytes)", desc.c_str(), iaddress, iaddress+len, oaddress, len); + CopyData(fd, output, len); + } + + void DumpData(int fd, std::ofstream &output, typename T::Addr iaddress, size_t len, const std::string &desc) { + typename T::Addr out_addr = MemAddr2FileAddr(iaddress); + if (out_addr) + DumpData(fd, output, iaddress, out_addr, len, desc); + else + logger.log_error("No address for 0x%x", iaddress); + } + + ProgramTableEntryLoad* FindRecordForMemAddress(typename T::Addr address) { + for (auto &record : m_phdrt) { + if (record->header.p_type != PT_LOAD) + continue; + + ProgramTableEntryLoad* entry = static_cast*>(record.get()); + if (address >= entry->header.p_vaddr && address < entry->header.p_vaddr + entry->header.p_memsz) { + return entry; + } + } + return nullptr; + } + + typename T::Addr MemAddr2FileAddr(typename T::Addr address) { + ProgramTableEntryLoad *record = FindRecordForMemAddress(address); + + if (record == nullptr) + return 0; + + return record->header.p_offset + (address - record->header.p_vaddr); + } + + SymData* AllocSymData(const std::string &lib, unsigned long start, typename T::Word type) { + elf_version(EV_CURRENT); + auto sym_data = new SymData(); + Elf_Scn *scn = nullptr; + + sym_data->start = start; + sym_data->fd = open(lib.c_str(), O_RDONLY); + + if (sym_data->fd < 0) { + delete sym_data; + return nullptr; + } + + sym_data->elf = elf_begin(sym_data->fd, ELF_C_READ, nullptr); + + while (1) { + GElf_Shdr *shdr; + scn = elf_nextscn(sym_data->elf, scn); + + if (!scn) { + elf_end(sym_data->elf); + close(sym_data->fd); + delete sym_data; + logger.log_info("no sym data for %s", lib.c_str()); + return nullptr; + } + + shdr = gelf_getshdr(scn, &sym_data->shdr); + if (shdr && sym_data->shdr.sh_type == type) + break; + } + + sym_data->data = elf_getdata(scn, nullptr); + sym_data->count = sym_data->shdr.sh_size / sym_data->shdr.sh_entsize; + + return sym_data; + } + + void SaveSymData(const std::string &lib, unsigned long start) { + SymData* sym_data; + + for (auto type: {SHT_SYMTAB, SHT_DYNSYM}) { + sym_data = AllocSymData(lib, start, type); + if (!sym_data) + continue; + + m_symdata.push_back(std::unique_ptr(sym_data)); + } + } + + static int FindPthreadsCb(const td_thrhandle_t *th, void *cb_data) { + td_thrinfo_t thinfo; + td_thr_get_info(th, &thinfo); + return TD_OK; + } + + void SavePthreadList(int mem_fd, std::ofstream &core_file, int pid) { + struct ps_prochandle ph = { + .core_obj = this, + .bit32 = (std::is_same::value), + .mem_fd = mem_fd, + .core_file = core_file, + .pid = pid + }; + + td_thragent_t *ta; + td_err_e err; + + err = td_ta_new(&ph, &ta); + if (err == TD_OK) { + err = td_ta_thr_iter(ta, FindPthreadsCb, nullptr, TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY, + TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS); + td_ta_delete(ta); + } + + if (err == TD_NOLIBTHREAD) { + logger.log_info("target does not appear to be multi-threaded"); + } else if (err != TD_OK) { + logger.log_info("WARNING: libthread_db not found, using fallback"); + // TODO: fallback + } + } + + bool SymAddress(const char *sym_name, unsigned long *addr) { + for (const auto &sd : m_symdata) { + for (int i = 0; i < sd->count; i++) { + GElf_Sym sym; + GElf_Sym *s; + + s = gelf_getsym(sd->data, i, &sym); + if (!s) + continue; + + const char *st = elf_strptr(sd->elf, sd->shdr.sh_link, s->st_name); + + if (strcmp(st, sym_name) != 0) + continue; + + *addr = sd->start + s->st_value; + return true; + } + } + return false; + } + + void SaveAUXVData(const std::string &exe_path, int mem_fd, std::ofstream &core_file) { + unsigned long debug_ptr = 0; + NoteCoreAUXV *auxv_note = nullptr; + + for (auto ¬e : m_notes) { + if (note->type == PT_PHDR) { + auxv_note = static_cast(note.get()); + break; + } + } + if (!auxv_note) + return; + + auto *auxv_data = reinterpret_cast(auxv_note->auxv().data()); + + auto phnum = AUXVval(auxv_data, AT_PHNUM); + auto phdr = AUXVval(auxv_data, AT_PHDR); + + if (phdr == 0) { + logger.log_info("PHDR not found for %s", exe_path); + return; + } + + typename T::Addr relocation = 0, dyn_addr = 0; + + size_t i; + + for (i = 0; i < phnum; i++) { + auto addr = phdr + (sizeof(typename T::Phdr) * i) + offsetof(typename T::Phdr, p_type); + uint32_t val; + ReadFromFile(mem_fd, addr, &val, sizeof(val)); + + if (val == PT_NULL) { + break; + } else if (val == PT_PHDR) { + addr = phdr + (sizeof(typename T::Phdr) * i) + offsetof(typename T::Phdr, p_vaddr); + ReadFromFile(mem_fd, addr, &relocation, sizeof(relocation)); + if (relocation > phdr) { + logger.log_error("relocation is greather than phdr"); + return; + } + relocation = phdr - relocation; + } else if (val == PT_DYNAMIC) { + addr = phdr + (sizeof(typename T::Phdr) * i) + offsetof(typename T::Phdr, p_vaddr); + ReadFromFile(mem_fd, addr, &dyn_addr, sizeof(dyn_addr)); + } + } + + DumpData(mem_fd, core_file, phdr, sizeof(typename T::Phdr)*i, "phdr"); + + SaveSymData(exe_path, relocation); + + dyn_addr += relocation; + + + for (i = 0; ; i++) { + unsigned long addr = dyn_addr + (sizeof(typename T::Dyn)*i) + offsetof(typename T::Dyn, d_tag); + uint32_t val; + ReadFromFile(mem_fd, addr, &val, sizeof(val)); + if (val == DT_NULL) + break; + if (val == DT_DEBUG) { + addr = dyn_addr + sizeof(typename T::Dyn)*i + offsetof(typename T::Dyn, d_un.d_ptr); + ReadFromFile(mem_fd, addr, &debug_ptr, sizeof(debug_ptr)); + } + } + if (!debug_ptr) { + logger.log_error("debug_ptr not found"); + return; + } + DumpData(mem_fd, core_file, dyn_addr, sizeof(typename T::Dyn)*i, "auxv dyns"); + DumpData(mem_fd, core_file, debug_ptr, sizeof(struct r_debug), "auxv r_debug"); + + unsigned long ptr = debug_ptr; + ReadFromFile(mem_fd, ptr + offsetof(struct r_debug, r_map), &ptr, sizeof(ptr)); + + while (ptr) { + unsigned long addr = 0; + DumpData(mem_fd, core_file, ptr, sizeof(struct link_map), "auxv link_map"); + + ReadFromFile(mem_fd, ptr + offsetof(struct link_map, l_name), &addr, sizeof(addr)); + + char buff[PAGESIZE]; + ReadFromFile(mem_fd, addr, buff, sizeof(buff)); + + if (buff[0] != 0) { + DumpData(mem_fd, core_file, addr, strlen(buff) + 1, "l_name"); + ReadFromFile(mem_fd, ptr+offsetof(struct link_map, l_addr), &addr, sizeof(addr)); + SaveSymData(buff, addr); + } + + ReadFromFile(mem_fd, ptr + offsetof(struct link_map, l_next), &ptr, sizeof(ptr)); + } + } + + unsigned long GetStackPointer(int task_nr, std::map ®isters) { + unsigned long result; +#if defined(__x86_64__) + result = registers[task_nr].rsp; +#elif defined(__i386__) + result = registers[task_nr].esp; +#elif defined(__arm__) + result = registers[task_nr].uregs[13]; +#elif defined(__aarch64__) + result = registers[task_nr].sp; +#else +#error Unsupported architecture +#endif + return result; + } + + void SaveStacks(int mem_fd, std::ofstream &core_file, std::vector tasks, std::map registers) { + for (auto task_nr : tasks) { + unsigned long sp = GetStackPointer(task_nr, registers); + auto *entry = FindRecordForMemAddress(sp); + size_t len = entry->header.p_vaddr + entry->header.p_memsz - sp; + auto out_addr = MemAddr2FileAddr(sp); + DumpData(mem_fd, core_file, sp, out_addr, len, "stack nr " + std::to_string(task_nr)); + } + } +}; +#endif // CORE_HPP__ diff --git a/src/livedumper/helpers.hpp b/src/livedumper/helpers.hpp index 60dcb0b..135e56a 100644 --- a/src/livedumper/helpers.hpp +++ b/src/livedumper/helpers.hpp @@ -61,12 +61,24 @@ struct ProgramTableHeader64 { uint64_t p_memsz; uint64_t p_align; }; + +struct SymData { + unsigned long start; + Elf *elf; + Elf64_Shdr shdr; + Elf_Data *data; + int fd; + int count; + struct SymData *next; +}; + #pragma pack(pop) struct Elf32 { typedef Elf32_Ehdr Ehdr; typedef Elf32_Phdr Phdr; typedef Elf32_Addr Addr; + typedef Elf32_Shdr Shdr; typedef Elf32_Off Off; typedef Elf32_Section Section; typedef Elf32_Versym Versym; @@ -77,6 +89,8 @@ struct Elf32 { typedef Elf32_Xword Xword; typedef ProgramTableHeader32 ProgramTableHeader; typedef Notefile32 Notefile; + typedef Elf32_auxv_t auxv_t; + typedef Elf32_Dyn Dyn; typedef uint32_t uint; static const char ELFCLASS = ELFCLASS32; }; @@ -85,6 +99,7 @@ struct Elf64 { typedef Elf64_Ehdr Ehdr; typedef Elf64_Phdr Phdr; typedef Elf64_Addr Addr; + typedef Elf64_Shdr Shdr; typedef Elf64_Off Off; typedef Elf64_Section Section; typedef Elf64_Versym Versym; @@ -95,6 +110,8 @@ struct Elf64 { typedef Elf64_Xword Xword; typedef ProgramTableHeader64 ProgramTableHeader; typedef Notefile64 Notefile; + typedef Elf64_auxv_t auxv_t; + typedef Elf64_Dyn Dyn; typedef uint64_t uint; static const char ELFCLASS = ELFCLASS64; }; diff --git a/src/livedumper/livedumper.hpp b/src/livedumper/livedumper.hpp index 5b97066..6e0869a 100644 --- a/src/livedumper/livedumper.hpp +++ b/src/livedumper/livedumper.hpp @@ -20,6 +20,7 @@ #include "core.hpp" #include "helpers.hpp" +#include "prochandle.hpp" #include "log.hpp" #include "maps.hpp" @@ -35,12 +36,14 @@ #include #include #include +#include template class LiveDumper { private: pid_t m_pid; std::vector m_tpids; + std::map m_registers; Core m_core; std::ofstream m_core_file; int prstatus_fd = -1; @@ -162,12 +165,15 @@ class LiveDumper { if (prstatus_fd >= 0) SaveRegsToPrStatusFd(registers); + m_registers[m_pid] = registers; m_core.AddPRSTATUSNote(registers, m_pid); for (const auto &pid : m_tpids) { if (pid == m_pid) continue; GetRegs(®isters, pid); + + m_registers[pid] = registers; m_core.AddPRSTATUSNote(registers, pid); } @@ -176,7 +182,21 @@ class LiveDumper { m_core.AddAUXVNote(auxv); } - bool DumpCore(const std::string &path) { + void MarkImportantRegions(const std::vector> &records) { + } + + std::string GetExePath(const pid_t pid) { + char BUFF[PATH_MAX]; + std::string exe_path = std::string("/proc/" + std::to_string(pid) + "/exe"); + ssize_t path_len; + if ((path_len = readlink(exe_path.c_str(), BUFF, sizeof(BUFF))) == -1) { + std::cout << "GetExePath error from" << exe_path << std::endl; + throw std::system_error(errno, std::system_category(), "GetExePath() for " + exe_path + " failed"); + } + return std::string(BUFF, path_len); + } + + bool DumpCore(const std::string &path, bool minicore) { bool result = true; try { @@ -188,12 +208,20 @@ class LiveDumper { const std::vector> records = ReadMaps(); AddNotes(records); + MarkImportantRegions(records); m_core.ImportMapRecords(records); m_core.SaveELFHeader(m_core_file); m_core.SaveProgramHeadersTable(m_core_file); m_core.SaveNotes(m_core_file); std::string mem_path = std::string("/proc/" + std::to_string(m_pid) + "/mem"); - m_core.SaveLoadable(mem_path, m_core_file); + int mem_fd = open(mem_path.c_str(), O_RDONLY); + m_core.SaveLoadable(mem_fd, m_core_file, minicore); + if (minicore) { + m_core.SaveAUXVData(GetExePath(m_pid), mem_fd, m_core_file); + m_core.SavePthreadList(mem_fd, m_core_file, m_pid); + m_core.SaveStacks(mem_fd, m_core_file, m_tpids, m_registers); + } + close(mem_fd); } catch (std::system_error &e) { logger.log_error("DumpCore: %s", e.what()); result = false; diff --git a/src/livedumper/log.hpp b/src/livedumper/log.hpp index f051dd1..311179d 100644 --- a/src/livedumper/log.hpp +++ b/src/livedumper/log.hpp @@ -29,9 +29,9 @@ class Logger { void log(const LogMsgType type, const char *fmt...); }; -#define log_info(fmt, args...) log(LogMsgType::INFO, fmt, args) -#define log_warning(fmt, args...) log(LogMsgType::WARNING, fmt, args) -#define log_error(fmt, args...) log(LogMsgType::ERROR, fmt, args) +#define log_info(fmt, args...) log(LogMsgType::INFO, fmt, ##args) +#define log_warning(fmt, args...) log(LogMsgType::WARNING, fmt, ##args) +#define log_error(fmt, args...) log(LogMsgType::ERROR, fmt, ##args) extern Logger logger; diff --git a/src/livedumper/main.cpp b/src/livedumper/main.cpp index 3a4430c..f8d5a7e 100644 --- a/src/livedumper/main.cpp +++ b/src/livedumper/main.cpp @@ -16,10 +16,16 @@ */ #include "livedumper.hpp" +#include "log.hpp" #include #include +#include +#include +#include +#include + #if defined(__arm__) || defined(__i386__) #define ELF_TYPE Elf32 #elif defined(__x86_64__) || defined(__aarch64__) @@ -31,7 +37,8 @@ void help(const char *app_name) { << " " << app_name << " [-f file_name] [-P fd] " << std::endl << std::endl << " -f output path" << std::endl - << " -P descriptor nr" << std::endl; + << " -P descriptor nr" << std::endl + << " -m save minicore" << std::endl; } int main(int argc, char *argv[]) { @@ -39,8 +46,9 @@ int main(int argc, char *argv[]) { int prstatus_fd = -1; std::string output_file; + bool minicore = false; - while ((opt = getopt(argc, argv, "hP:f:")) != -1) { + while ((opt = getopt(argc, argv, "hP:f:m")) != -1) { switch (opt) { case 'P': prstatus_fd = atoi(optarg); @@ -51,6 +59,9 @@ int main(int argc, char *argv[]) { case 'f': output_file = optarg; break; + case 'm': + minicore = true; + break; default: help(argv[0]); exit(EXIT_FAILURE); @@ -72,5 +83,15 @@ int main(int argc, char *argv[]) { if (prstatus_fd > 0) dumper.setPrstatusFd(prstatus_fd); - return dumper.DumpCore(output_file) ? EXIT_SUCCESS : EXIT_FAILURE; + try { + return dumper.DumpCore(output_file, minicore) ? EXIT_SUCCESS : EXIT_FAILURE; + } catch (std::exception &e) { + logger.log_error("%s", e.what()); + std::cout << e.what() << std::endl; + return EXIT_FAILURE; + } catch (...) { + logger.log_error("unspecified error"); + std::cout << "unspecified error" << std::endl; + return EXIT_FAILURE; + } } diff --git a/src/livedumper/maps.hpp b/src/livedumper/maps.hpp index 84a0555..ac90cb5 100644 --- a/src/livedumper/maps.hpp +++ b/src/livedumper/maps.hpp @@ -49,6 +49,7 @@ struct MapRecord { uintptr_t offset; Permissions perms; std::string path; + bool important; bool IsLoadable() const { // we need only readable records @@ -81,6 +82,13 @@ class Maps { return m_map_records; } + bool DoWeNeedThisRecord(const std::shared_ptr record) { + return (record->path == "[vsyscall]" || + record->path == "[vdso]" || + record->path == "[vectors]" || + record->path == "[stack]"); + } + void Parse() { const std::string& maps_file_name = "/proc/" + std::to_string(m_pid) + "/maps"; @@ -92,7 +100,8 @@ class Maps { while (std::getline(maps_file, line)) { std::shared_ptr record = ParseLine(line); - if (record->IsLoadable()) + record->important = DoWeNeedThisRecord(record); + if ((record->perms & Permissions::Read) == Permissions::Read) m_map_records.push_back(record); } } diff --git a/src/livedumper/note.hpp b/src/livedumper/note.hpp index 6977c08..9cc8f92 100644 --- a/src/livedumper/note.hpp +++ b/src/livedumper/note.hpp @@ -175,5 +175,9 @@ class NoteCoreAUXV : public Note { void SaveDataTo(std::ofstream &core_file) const { core_file.write(m_auxv.data(), m_auxv.size()); } + + const std::vector& auxv() const { + return m_auxv; + } }; #endif // NOTE_HPP__ diff --git a/src/livedumper/prochandle.hpp b/src/livedumper/prochandle.hpp new file mode 100644 index 0000000..01a0257 --- /dev/null +++ b/src/livedumper/prochandle.hpp @@ -0,0 +1,108 @@ +#ifndef PROCHANDLE_HPP__ +#define PROCHANDLE_HPP__ + +#include "helpers.hpp" +#include "core.hpp" + +#include + +typedef enum +{ + PS_OK, + PS_ERR, + PS_BADPID, + PS_BADLID, + PS_BADADDR, + PS_NOSYM, + PS_NOFREGS +} ps_err_e; + +struct ps_prochandle { + void *core_obj; + bool bit32; + const int mem_fd; + std::ofstream &core_file; + const pid_t pid; + + unsigned long int MemAddr2FileAddr(unsigned long int addr) { + if (bit32) + return static_cast*>(core_obj)->MemAddr2FileAddr(addr); + else + return static_cast*>(core_obj)->MemAddr2FileAddr(addr); + } + + void DumpData(int fd, std::ofstream &output, unsigned long iaddress, unsigned long oaddress, size_t len, const std::string &desc) { + if (bit32) + static_cast*>(core_obj)->DumpData(fd, output, iaddress, oaddress, len, desc); + else + static_cast*>(core_obj)->DumpData(fd, output, iaddress, oaddress, len, desc); + } + + bool SymAddress(const char *sym_name, unsigned long *addr) { + if (bit32) + return static_cast*>(core_obj)->SymAddress(sym_name, addr); + else + return static_cast*>(core_obj)->SymAddress(sym_name, addr); + } + + void ReadFromFile(std::ifstream &input, unsigned long address, void *data, size_t len) { + if (bit32) + static_cast*>(core_obj)->ReadFromFile(input, address, data, len); + else + static_cast*>(core_obj)->ReadFromFile(input, address, data, len); + } + + void ReadFromFile(const int fd, unsigned long address, void *data, size_t len) { + if (bit32) + static_cast*>(core_obj)->ReadFromFile(fd, address, data, len); + else + static_cast*>(core_obj)->ReadFromFile(fd, address, data, len); + } +}; + +extern "C" { + ps_err_e ps_pdread(struct ps_prochandle *ph, psaddr_t addr, void *buf, size_t size) { + ph->ReadFromFile(ph->mem_fd, reinterpret_cast(addr), buf, size); + + auto out_addr = ph->MemAddr2FileAddr(reinterpret_cast(addr)); + ph->DumpData(ph->mem_fd, ph->core_file, reinterpret_cast(addr), out_addr, size, "pthread data"); + + return PS_OK; + } + + ps_err_e ps_pdwrite(struct ps_prochandle *ph, psaddr_t addr, const void *buf, size_t size) { + return PS_OK; + } + + ps_err_e ps_lgetregs(struct ps_prochandle *ph, lwpid_t lwpid, prgregset_t prgregset) { + return PS_OK; + } + + ps_err_e ps_lgetfpregs(struct ps_prochandle *ph, lwpid_t lwpid, prfpregset_t *prfpregset) { + return PS_OK; + } + + ps_err_e ps_lsetregs(struct ps_prochandle *ph, lwpid_t lwpid, const prgregset_t prgregset) { + return PS_OK; + } + + ps_err_e ps_lsetfpregs(struct ps_prochandle *ph, lwpid_t lwpid, const prfpregset_t *prfpregset) { + return PS_OK; + } + + pid_t ps_getpid(struct ps_prochandle *ph) { + return ph->pid; + } + + ps_err_e ps_pglobal_lookup(struct ps_prochandle *ph, const char *object_name, + const char *sym_name, psaddr_t *sym_addr) { + unsigned long addr; + + if (!ph->SymAddress(sym_name, &addr)) + return PS_NOSYM; + + *sym_addr = (psaddr_t)addr; + return PS_OK; + } +} +#endif // PROCHANDLE_HPP__ diff --git a/src/livedumper/program.hpp b/src/livedumper/program.hpp index 1c5b450..855e7e4 100644 --- a/src/livedumper/program.hpp +++ b/src/livedumper/program.hpp @@ -45,7 +45,8 @@ class ProgramTableEntryNote : public ProgramTableEntryBase { template class ProgramTableEntryLoad : public ProgramTableEntryBase { public: - ProgramTableEntryLoad() : ProgramTableEntryBase(PT_LOAD) { + bool important; + ProgramTableEntryLoad() : ProgramTableEntryBase(PT_LOAD), important(false) { this->header.p_flags = PF_R; } }; -- 2.7.4 From e9a6645bc0fe40b12c44115fbf2f630f8026b603 Mon Sep 17 00:00:00 2001 From: Mateusz Moscicki Date: Fri, 5 Jul 2019 16:07:35 +0200 Subject: [PATCH 09/16] Release 5.5.15 - livedumper is able to create mini coredumps (-m option) Change-Id: I0a2bc0e42757e3fe9378cca8b671448804abdcca --- packaging/crash-worker.spec | 2 +- packaging/crash-worker_system-tests.spec | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packaging/crash-worker.spec b/packaging/crash-worker.spec index 5951257..4635a5b 100644 --- a/packaging/crash-worker.spec +++ b/packaging/crash-worker.spec @@ -14,7 +14,7 @@ Name: crash-worker Summary: Crash-manager -Version: 5.5.14 +Version: 5.5.15 Release: 1 Group: Framework/system License: Apache-2.0 and BSD diff --git a/packaging/crash-worker_system-tests.spec b/packaging/crash-worker_system-tests.spec index 039a594..c80d9ac 100644 --- a/packaging/crash-worker_system-tests.spec +++ b/packaging/crash-worker_system-tests.spec @@ -8,7 +8,7 @@ Name: crash-worker_system-tests Summary: Package with binaries and scripts for crash-worker system tests -Version: 5.5.14 +Version: 5.5.15 Release: 1 Group: Framework/system License: Apache-2.0 and BSD -- 2.7.4 From b1f8fe54f2b1760f5def6bb3ba24f8b0678c9e77 Mon Sep 17 00:00:00 2001 From: Michal Bloch Date: Mon, 8 Jul 2019 16:49:34 +0200 Subject: [PATCH 10/16] Fix a bunch of minor issues found by Coverity. Change-Id: I6dc3f56f1d590a6a49800d28ba78d3185555a837 Signed-off-by: Michal Bloch --- src/livedumper/core.hpp | 4 ++++ src/livedumper/livedumper.hpp | 18 +++++++++++++----- src/livedumper/program.hpp | 1 + src/shared/spawn.c | 3 +++ 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/livedumper/core.hpp b/src/livedumper/core.hpp index 193577c..2f52efd 100644 --- a/src/livedumper/core.hpp +++ b/src/livedumper/core.hpp @@ -136,6 +136,10 @@ class Core { len = size; ssize_t cur_pos = lseek64(input, 0, SEEK_CUR); + if (cur_pos < 0) { + logger.log_error("lseek error: %s", std::system_category().default_error_condition(errno).message()); + return; + } ssize_t bytes_read; if ((bytes_read = read(input, buff, len)) == -1) { diff --git a/src/livedumper/livedumper.hpp b/src/livedumper/livedumper.hpp index 6e0869a..01a2225 100644 --- a/src/livedumper/livedumper.hpp +++ b/src/livedumper/livedumper.hpp @@ -47,9 +47,15 @@ class LiveDumper { Core m_core; std::ofstream m_core_file; int prstatus_fd = -1; + std::pair map_buff; public: - explicit LiveDumper(const pid_t pid) : m_pid(pid) {} + explicit LiveDumper(const pid_t pid) : m_pid(pid), map_buff(MAP_FAILED, 0) {} + + ~ LiveDumper () { + if (map_buff.first != MAP_FAILED) + munmap(map_buff.first, map_buff.second); + } void CollectTpids() { m_tpids.clear(); @@ -148,14 +154,16 @@ class LiveDumper { memcpy(&prstatus.pr_reg, ®isters, sizeof(prstatus.pr_reg)); prstatus.pr_pid = m_pid; - auto buff = reinterpret_cast(mmap(nullptr, sizeof(prstatus), + map_buff.first = mmap(nullptr, sizeof(prstatus), PROT_READ | PROT_WRITE, MAP_SHARED, prstatus_fd, - 0)); - if (buff == MAP_FAILED) + 0); + if (map_buff.first == MAP_FAILED) return; - memcpy(buff, &prstatus, sizeof(prstatus)); + map_buff.second = sizeof prstatus; + + memcpy(static_cast (map_buff.first), &prstatus, sizeof(prstatus)); } void AddNotes(const std::vector> &records) { diff --git a/src/livedumper/program.hpp b/src/livedumper/program.hpp index 855e7e4..f2eca7d 100644 --- a/src/livedumper/program.hpp +++ b/src/livedumper/program.hpp @@ -30,6 +30,7 @@ class ProgramTableEntryBase { memset(&header, 0, sizeof(header)); header.p_type = p_type; } + virtual ~ProgramTableEntryBase () {} }; template diff --git a/src/shared/spawn.c b/src/shared/spawn.c index baca45d..392a053 100644 --- a/src/shared/spawn.c +++ b/src/shared/spawn.c @@ -51,6 +51,9 @@ int spawn_setstderr(spawn_param_s *param) int spawn_nullstdfds(spawn_param_s *param) { int fd = open("/dev/null", O_RDWR); + if (fd < 0) + return -1; + int ret = dup2(fd, STDIN_FILENO) < 0 || dup2(fd, STDOUT_FILENO) < 0 || dup2(fd, STDERR_FILENO) < 0 ? -1 : 0; if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO) close(fd); -- 2.7.4 From c7c918c7c0e0bdf383e6fcdfe4f1facf195d74e5 Mon Sep 17 00:00:00 2001 From: Mateusz Moscicki Date: Tue, 9 Jul 2019 15:54:55 +0200 Subject: [PATCH 11/16] Release 5.5.16 - Fix Coverity issues Change-Id: Ic94d6570135a93575b793447c1fc5ea365c6a5f3 --- packaging/crash-worker.spec | 2 +- packaging/crash-worker_system-tests.spec | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packaging/crash-worker.spec b/packaging/crash-worker.spec index 4635a5b..f68f0b6 100644 --- a/packaging/crash-worker.spec +++ b/packaging/crash-worker.spec @@ -14,7 +14,7 @@ Name: crash-worker Summary: Crash-manager -Version: 5.5.15 +Version: 5.5.16 Release: 1 Group: Framework/system License: Apache-2.0 and BSD diff --git a/packaging/crash-worker_system-tests.spec b/packaging/crash-worker_system-tests.spec index c80d9ac..92f3faa 100644 --- a/packaging/crash-worker_system-tests.spec +++ b/packaging/crash-worker_system-tests.spec @@ -8,7 +8,7 @@ Name: crash-worker_system-tests Summary: Package with binaries and scripts for crash-worker system tests -Version: 5.5.15 +Version: 5.5.16 Release: 1 Group: Framework/system License: Apache-2.0 and BSD -- 2.7.4 From 5a4d1c937810a5017db5f47d73cc29f0f4f3520f Mon Sep 17 00:00:00 2001 From: Mateusz Moscicki Date: Mon, 15 Jul 2019 11:09:11 +0200 Subject: [PATCH 12/16] Fix format specifier Change-Id: I5378d23401594aae9adf42ce595d6fad43c847ce --- src/livedumper/core.hpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/livedumper/core.hpp b/src/livedumper/core.hpp index 2f52efd..aebd3a4 100644 --- a/src/livedumper/core.hpp +++ b/src/livedumper/core.hpp @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -128,16 +129,16 @@ class Core { } void CopyData(int input, std::ofstream &output, size_t size) { - size_t len = PAGESIZE; + off64_t len = PAGESIZE; char buff[PAGESIZE]; while (size > 0) { if (size < len) len = size; - ssize_t cur_pos = lseek64(input, 0, SEEK_CUR); - if (cur_pos < 0) { - logger.log_error("lseek error: %s", std::system_category().default_error_condition(errno).message()); + off64_t cur_pos = lseek64(input, 0, SEEK_CUR); + if (cur_pos == -1) { + logger.log_error("lseek error: %s", std::system_category().default_error_condition(errno).message().c_str()); return; } @@ -145,7 +146,7 @@ class Core { if ((bytes_read = read(input, buff, len)) == -1) { // tell() returns 128bits value so I cast this to 64bit to be able to print it logger.log_error("read error at 0x%llx: %s\n", static_cast(output.tellp()), - std::system_category().default_error_condition(errno).message()); + std::system_category().default_error_condition(errno).message().c_str()); lseek64(input, cur_pos + len, SEEK_SET); output.seekp(len, std::ios_base::cur); size -= len; @@ -165,7 +166,7 @@ class Core { if (record->header.p_type != PT_LOAD) continue; if (lseek64(mem_fd, record->header.p_vaddr, SEEK_SET) == -1) - logger.log_error("lseek64 error: %s", std::system_category().default_error_condition(errno).message()); + logger.log_error("lseek64 error: %s", std::system_category().default_error_condition(errno).message().c_str()); if (!minicore || static_cast*>(record.get())->important) CopyData(mem_fd, core_file, record->header.p_filesz); else @@ -229,7 +230,11 @@ class Core { void DumpData(int fd, std::ofstream &output, typename T::Addr iaddress, typename T::Addr oaddress, size_t len, const std::string &desc) { lseek64(fd, iaddress, SEEK_SET); output.seekp(oaddress, std::ios_base::beg); - logger.log_info("dumping %s: 0x%x-0x%x to 0x%x (%d bytes)", desc.c_str(), iaddress, iaddress+len, oaddress, len); + constexpr const char * format = std::is_same::value ? + "dumping %s: 0x%" PRIx64 "-0x%" PRIx64 " to 0x%" PRIx64 " (%zu bytes)" : + "dumping %s: 0x%" PRIx32 "-0x%" PRIx32 " to 0x%" PRIx32 " (%zu bytes)"; + + logger.log_info(format, desc.c_str(), iaddress, iaddress+len, oaddress, len); CopyData(fd, output, len); } -- 2.7.4 From 34c62042fc362f40e42090b5db1c138ad883c251 Mon Sep 17 00:00:00 2001 From: Mateusz Moscicki Date: Mon, 15 Jul 2019 14:46:50 +0200 Subject: [PATCH 13/16] Skip test if livedumper doesn't exist Change-Id: Ibe22df39b4c8e572c29efec0f338cae0bef1bc9f --- tests/system/livedumper/livedumper.sh.template | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/system/livedumper/livedumper.sh.template b/tests/system/livedumper/livedumper.sh.template index 54d438b..51c9be1 100644 --- a/tests/system/livedumper/livedumper.sh.template +++ b/tests/system/livedumper/livedumper.sh.template @@ -8,6 +8,10 @@ fi . ${CRASH_WORKER_SYSTEM_TESTS}/utils/minicore-utils.sh +if [ ! -x /usr/bin/livedumper ]; then + exit_with_code "SKIP" ${SKIP_CODE} +fi + mount -o rw,remount / clean_crash_dump -- 2.7.4 From 9c54cfca4e88fae209cde90c299168273aeeb65e Mon Sep 17 00:00:00 2001 From: Mateusz Moscicki Date: Mon, 15 Jul 2019 15:11:54 +0200 Subject: [PATCH 14/16] crash-manager executes livedumper with -m option Change-Id: If36b60500d18fe43065a4b9322446e9309e18564 --- src/crash-manager/crash-manager.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/crash-manager/crash-manager.c b/src/crash-manager/crash-manager.c index f505834..bf55763 100644 --- a/src/crash-manager/crash-manager.c +++ b/src/crash-manager/crash-manager.c @@ -785,6 +785,7 @@ static bool execute_livedumper(const struct crash_info *cinfo, int *exit_code) /* Execute livedumper */ char *args[] = { LIVEDUMPER_BIN_PATH, // livedumper filename path + "-m", // minilivecoredump "-P", prstatus_fd_str, "-f", coredump_path, pid_str, // %p - pid -- 2.7.4 From 363700b9166a71339b10e2251fff3352b2524f8a Mon Sep 17 00:00:00 2001 From: Mateusz Moscicki Date: Mon, 15 Jul 2019 15:15:19 +0200 Subject: [PATCH 15/16] Release 5.5.17 - Fix format specifier in livedumper - crash-manager executes livedumper with -m option Change-Id: I1031fce26edd993612d1d0190fb31775488ff29e --- packaging/crash-worker.spec | 2 +- packaging/crash-worker_system-tests.spec | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packaging/crash-worker.spec b/packaging/crash-worker.spec index f68f0b6..304659d 100644 --- a/packaging/crash-worker.spec +++ b/packaging/crash-worker.spec @@ -14,7 +14,7 @@ Name: crash-worker Summary: Crash-manager -Version: 5.5.16 +Version: 5.5.17 Release: 1 Group: Framework/system License: Apache-2.0 and BSD diff --git a/packaging/crash-worker_system-tests.spec b/packaging/crash-worker_system-tests.spec index 92f3faa..b082f56 100644 --- a/packaging/crash-worker_system-tests.spec +++ b/packaging/crash-worker_system-tests.spec @@ -8,7 +8,7 @@ Name: crash-worker_system-tests Summary: Package with binaries and scripts for crash-worker system tests -Version: 5.5.16 +Version: 5.5.17 Release: 1 Group: Framework/system License: Apache-2.0 and BSD -- 2.7.4 From 7d7c99931e4cf5f1f8e525795c12a509c897872c Mon Sep 17 00:00:00 2001 From: Karol Lewandowski Date: Tue, 16 Jul 2019 13:46:29 +0200 Subject: [PATCH 16/16] Build all programs as PIE - needed for ASLR to work Change-Id: If965bb4ef9008bf280d211feeebe1a5a95de7252 --- src/crash-manager/CMakeLists.txt | 4 ++-- src/livedumper/CMakeLists.txt | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/crash-manager/CMakeLists.txt b/src/crash-manager/CMakeLists.txt index 6a20570..198a92c 100644 --- a/src/crash-manager/CMakeLists.txt +++ b/src/crash-manager/CMakeLists.txt @@ -35,12 +35,12 @@ TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${crash-manager_pkgs_LDFLAGS} -pie -lrt) set(CRASH_POPUP crash-popup-launch) ADD_EXECUTABLE(${CRASH_POPUP} ${CRASH_POPUP}.c) -TARGET_LINK_LIBRARIES(${CRASH_POPUP} ${helper_pkgs_LDFLAGS}) +TARGET_LINK_LIBRARIES(${CRASH_POPUP} ${helper_pkgs_LDFLAGS} -pie) install(TARGETS ${CRASH_POPUP} DESTINATION libexec) SET(CRASH_NOTIFY crash-notify-send) ADD_EXECUTABLE(${CRASH_NOTIFY} dbus_notify.c) -TARGET_LINK_LIBRARIES(${CRASH_NOTIFY} ${helper_pkgs_LDFLAGS}) +TARGET_LINK_LIBRARIES(${CRASH_NOTIFY} ${helper_pkgs_LDFLAGS} -pie) install(TARGETS ${CRASH_NOTIFY} DESTINATION libexec) INSTALL(TARGETS ${PROJECT_NAME} DESTINATION bin diff --git a/src/livedumper/CMakeLists.txt b/src/livedumper/CMakeLists.txt index ea20fc6..efdf65a 100644 --- a/src/livedumper/CMakeLists.txt +++ b/src/livedumper/CMakeLists.txt @@ -18,7 +18,8 @@ endif(DLOG) set(LIVEDUMPER_SRCS main.cpp ${LOGGER_FILE}) add_executable(${LIVEDUMPER_BIN} ${LIVEDUMPER_SRCS}) -target_link_libraries(${LIVEDUMPER_BIN} -lelf -lthread_db) +set_property(TARGET ${LIVEDUMPER_BIN} APPEND_STRING PROPERTY COMPILE_FLAGS "-fPIE ") +target_link_libraries(${LIVEDUMPER_BIN} -lelf -lthread_db -pie) if("${LOGGER}" STREQUAL "dlog") include(FindPkgConfig) -- 2.7.4