Hello community, here is the log from the commit of package kcrash for openSUSE:Factory checked in at 2019-02-14 14:24:24 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/kcrash (Old) and /work/SRC/openSUSE:Factory/.kcrash.new.28833 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "kcrash" Thu Feb 14 14:24:24 2019 rev:63 rq:674226 version:5.55.0 Changes: -------- --- /work/SRC/openSUSE:Factory/kcrash/kcrash.changes 2019-01-21 10:19:09.374147274 +0100 +++ /work/SRC/openSUSE:Factory/.kcrash.new.28833/kcrash.changes 2019-02-14 14:24:26.299900619 +0100 @@ -1,0 +2,12 @@ +Sun Feb 10 22:03:03 UTC 2019 - [email protected] + +- Update to 5.55.0 + * New feature release + * For more details please see: + * https://www.kde.org/announcements/kde-frameworks-5.55.0.php +- Changes since 5.54.0: + * Comment why changing the ptracer is required + * [KCrash] Establish socket to allow change of ptracer + * Fix out-of-bounds assert while running unittests with argv==nullptr. + +------------------------------------------------------------------- @@ -19,0 +32,5 @@ + +------------------------------------------------------------------- +Mon Nov 12 14:13:00 UTC 2018 - Jan Engelhardt <[email protected]> + +- Use noun phrase in summaries. Old: ---- kcrash-5.54.0.tar.xz New: ---- kcrash-5.55.0.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ kcrash.spec ++++++ --- /var/tmp/diff_new_pack.swQvpz/_old 2019-02-14 14:24:27.695899961 +0100 +++ /var/tmp/diff_new_pack.swQvpz/_new 2019-02-14 14:24:27.695899961 +0100 @@ -17,15 +17,15 @@ %define lname libKF5Crash5 -%define _tar_path 5.54 +%define _tar_path 5.55 # Full KF5 version (e.g. 5.33.0) %{!?_kf5_version: %global _kf5_version %{version}} # Last major and minor KF5 version (e.g. 5.33) %{!?_kf5_bugfix_version: %define _kf5_bugfix_version %(echo %{_kf5_version} | awk -F. '{print $1"."$2}')} Name: kcrash -Version: 5.54.0 +Version: 5.55.0 Release: 0 -Summary: Gracefull handling of application crashes +Summary: An application crash handler License: LGPL-2.1-or-later Group: System/GUI/KDE URL: https://www.kde.org @@ -47,7 +47,7 @@ KCrash provides support for intercepting and handling application crashes. %package -n %{lname} -Summary: Gracefull handling of application crashes +Summary: An application crash handler Group: System/GUI/KDE Recommends: drkonqi5 @@ -55,7 +55,7 @@ KCrash provides support for intercepting and handling application crashes. %package devel -Summary: Gracefull handling of application crashes: Build Environment +Summary: Build environment for the KCrash application crash handler Group: Development/Libraries/KDE Requires: %{lname} = %{version} Requires: extra-cmake-modules ++++++ kcrash-5.54.0.tar.xz -> kcrash-5.55.0.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kcrash-5.54.0/CMakeLists.txt new/kcrash-5.55.0/CMakeLists.txt --- old/kcrash-5.54.0/CMakeLists.txt 2019-01-04 22:41:32.000000000 +0100 +++ new/kcrash-5.55.0/CMakeLists.txt 2019-02-02 18:20:25.000000000 +0100 @@ -1,17 +1,17 @@ cmake_minimum_required(VERSION 3.5) -set(KF5_VERSION "5.54.0") # handled by release scripts -set(KF5_DEP_VERSION "5.54.0") # handled by release scripts +set(KF5_VERSION "5.55.0") # handled by release scripts +set(KF5_DEP_VERSION "5.55.0") # handled by release scripts project(KCrash VERSION ${KF5_VERSION}) include(FeatureSummary) -find_package(ECM 5.54.0 NO_MODULE) +find_package(ECM 5.55.0 NO_MODULE) set_package_properties(ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake Modules." URL "https://projects.kde.org/projects/kdesupport/extra-cmake-modules") feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND FATAL_ON_MISSING_REQUIRED_PACKAGES) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR}) -set(REQUIRED_QT_VERSION 5.9.0) +set(REQUIRED_QT_VERSION 5.10.0) find_package(Qt5 ${REQUIRED_QT_VERSION} CONFIG REQUIRED Core) include(KDEInstallDirs) include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kcrash-5.54.0/src/kcrash.cpp new/kcrash-5.55.0/src/kcrash.cpp --- old/kcrash-5.54.0/src/kcrash.cpp 2019-01-04 22:41:32.000000000 +0100 +++ new/kcrash-5.55.0/src/kcrash.cpp 2019-02-02 18:20:25.000000000 +0100 @@ -40,6 +40,7 @@ #include <qt_windows.h> #endif #ifdef Q_OS_LINUX +#include <sys/poll.h> #include <sys/prctl.h> #endif @@ -218,14 +219,16 @@ s_autoRestartCommand = qstrdup(QFile::encodeName(filePath).constData()); QStringList args = QCoreApplication::arguments(); - args[0] = filePath; // replace argv[0] with full path above - delete[] s_autoRestartCommandLine; - s_autoRestartArgc = args.count(); - s_autoRestartCommandLine = new char *[args.count() + 1]; - for (int i = 0; i < args.count(); ++i) { - s_autoRestartCommandLine[i] = qstrdup(QFile::encodeName(args.at(i)).constData()); + if (!args.isEmpty()) { // edge case: tst_QX11Info::startupId does QApplication app(argc, nullptr)... + args[0] = filePath; // replace argv[0] with full path above + delete[] s_autoRestartCommandLine; + s_autoRestartArgc = args.count(); + s_autoRestartCommandLine = new char *[args.count() + 1]; + for (int i = 0; i < args.count(); ++i) { + s_autoRestartCommandLine[i] = qstrdup(QFile::encodeName(args.at(i)).constData()); + } + s_autoRestartCommandLine[args.count()] = nullptr; } - s_autoRestartCommandLine[args.count()] = nullptr; } void KCrash::setDrKonqiEnabled(bool enabled) @@ -616,6 +619,11 @@ static int read_socket(int sock, char *buffer, int len); static int openSocket(); +#ifdef Q_OS_LINUX +static int openDrKonqiSocket(const QByteArray &socketpath); +static int pollDrKonqiSocket(pid_t pid, int sockfd); +#endif + void KCrash::startProcess(int argc, const char *argv[], bool waitAndExit) { bool startDirectly = true; @@ -644,24 +652,50 @@ if (pid > 0 && waitAndExit) { // Seems we made it.... - alarm(0); //stop the pending alarm that was set at the top of the defaultCrashHandler + alarm(0); // Stop the pending alarm that was set at the top of the defaultCrashHandler + bool running = true; // Wait forever until the started process exits. This code path is executed - // when launching drkonqi. Note that drkonqi will stop this process in the meantime. - if (directly) { - //if the process was started directly, use waitpid(), as it's a child... - while (waitpid(-1, nullptr, 0) != pid) {} - } else { + // when launching drkonqi. Note that DrKonqi will SIGSTOP this process in the meantime + // and only send SIGCONT when it is about to attach a debugger. #ifdef Q_OS_LINUX - // Declare the process that will be debugging the crashed KDE app (#245529) + // Declare the process that will be debugging the crashed KDE app (#245529). + // For now that will be DrKonqi, which may ask to transfer the ptrace scope to + // a debugger it is not an ancestor of (because it was started via kdeinit or + // KProcess::startDetached()) using a socket. #ifndef PR_SET_PTRACER # define PR_SET_PTRACER 0x59616d61 #endif - prctl(PR_SET_PTRACER, pid, 0, 0, 0); + prctl(PR_SET_PTRACER, pid, 0, 0, 0); + + // Create socket path to transfer ptrace scope and open connection + const QByteArray socketpath = QFile::encodeName( + QStringLiteral("%1/kcrash_%2").arg(QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation)) + .arg(getpid())); + int sockfd = openDrKonqiSocket(socketpath); + + if (sockfd >= 0) { + // Wait while DrKonqi is running and the socket connection exists + if (directly) { + // If the process was started directly, use waitpid(), as it's a child... + while ((running = waitpid(pid, nullptr, WNOHANG) != pid) && pollDrKonqiSocket(pid, sockfd) >= 0) {} + } else { + // ... else poll its status using kill() + while ((running = kill(pid, 0) >= 0) && pollDrKonqiSocket(pid, sockfd) >= 0) {} + } + close(sockfd); + unlink(socketpath.constData()); + } #endif - //...else poll its status using kill() - while (kill(pid, 0) >= 0) { - sleep(1); + if (running) { + if (directly) { + // If the process was started directly, use waitpid(), as it's a child... + while (waitpid(pid, nullptr, 0) != pid) {} + } else { + // ... else poll its status using kill() + while (kill(pid, 0) >= 0) { + sleep(1); + } } } if (!s_coreConfig->isProcess()) { @@ -832,4 +866,90 @@ return s; } +#ifdef Q_OS_LINUX + +static int openDrKonqiSocket(const QByteArray &socketpath) +{ + int sockfd = socket(PF_UNIX, SOCK_STREAM, 0); + if (sockfd < 0) { + perror("Warning: socket() for communication with DrKonqi failed"); + return -1; + } + + struct sockaddr_un drkonqi_server; + drkonqi_server.sun_family = AF_UNIX; + + if (socketpath.size() >= static_cast<int>(sizeof(drkonqi_server.sun_path))) { + fprintf(stderr, "Warning: socket path is too long\n"); + close(sockfd); + return -1; + } + strcpy(drkonqi_server.sun_path, socketpath.constData()); + + unlink(drkonqi_server.sun_path); // remove potential stale socket + if (bind(sockfd, (struct sockaddr *)&drkonqi_server, sizeof(drkonqi_server)) < 0) { + perror("Warning: bind() for communication with DrKonqi failed"); + close(sockfd); + unlink(drkonqi_server.sun_path); + return -1; + } + + listen(sockfd, 1); + + return sockfd; +} + +static int pollDrKonqiSocket(pid_t pid, int sockfd) +{ + struct pollfd fd; + fd.fd = sockfd; + fd.events = POLLIN; + int r; + do { + r = poll(&fd, 1, 1000); // wait for 1 second for a request by DrKonqi + } while (r == -1 && errno == EINTR); + // only continue if POLLIN event returned + if (r == 0) // timeout + return 0; + else if (r == -1 || !(fd.revents & POLLIN)) // some error + return -1; + + static struct sockaddr_un drkonqi_client; + static socklen_t cllength = sizeof(drkonqi_client); + int clsockfd; + do { + clsockfd = accept(sockfd, (struct sockaddr *)&drkonqi_client, &cllength); + } while (clsockfd == -1 && errno == EINTR); + if (clsockfd < 0) + return -1; + + // check whether the message is coming from DrKonqi + static struct ucred ucred; + static socklen_t credlen = sizeof(struct ucred); + if (getsockopt(clsockfd, SOL_SOCKET, SO_PEERCRED, &ucred, &credlen) < 0) + return -1; + + if (ucred.pid != pid) { + fprintf(stderr, "Warning: peer pid does not match DrKonqi pid\n"); + return -1; + } + + // read PID to change ptrace scope + static const int msize = 21; // most digits in a 64bit int (+sign +'\0') + char msg[msize]; + if (read_socket(clsockfd, msg, msize) == 0) { + int dpid = atoi(msg); + prctl(PR_SET_PTRACER, dpid, 0, 0, 0); + // confirm change to DrKonqi + if (write_socket(clsockfd, msg, msize) == 0) { + fprintf(stderr, "KCrash: ptrace access transferred to %s\n", msg); + } + } + close(clsockfd); + + return 1; +} + +#endif + #endif // Q_OS_UNIX
