-
Notifications
You must be signed in to change notification settings - Fork 255
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement new perf elevated privilege system
Instead of using a script that changes system configuration temporarily, just run perf as root. To properly synchronize with a launched app (that itself should not run as root), launch the app in a separate, initially stopped process, and use the control fifo feature of perf to properly synchronize with it. The control fifos are also needed to be able to stop sudo-perf, as one does not have permission to SIGINT it anymore.
- Loading branch information
1 parent
5a6280b
commit ab73817
Showing
14 changed files
with
483 additions
and
203 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
/* | ||
SPDX-FileCopyrightText: Zeno Endemann <zeno.endemann@kdab.com> | ||
SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com | ||
SPDX-License-Identifier: GPL-2.0-or-later | ||
*/ | ||
|
||
#include <cstring> | ||
|
||
#include "initiallystoppedprocess.h" | ||
|
||
#include <QDebug> | ||
#include <QFile> | ||
#include <QLoggingCategory> | ||
#include <QSocketNotifier> | ||
#include <QStandardPaths> | ||
|
||
#include <fcntl.h> | ||
#include <signal.h> | ||
#include <sys/stat.h> | ||
#include <sys/types.h> | ||
#include <sys/wait.h> | ||
#include <vector> | ||
|
||
namespace { | ||
Q_LOGGING_CATEGORY(initiallystoppedprocess, "hotspot.initiallystoppedprocess") | ||
|
||
void sendSignal(pid_t pid, int signal) | ||
{ | ||
if (kill(pid, signal) != 0) { | ||
qCCritical(initiallystoppedprocess) | ||
<< "Failed to send signal" << signal << "to" << pid << ":" << std::strerror(errno); | ||
} | ||
} | ||
} | ||
|
||
InitiallyStoppedProcess::~InitiallyStoppedProcess() | ||
{ | ||
kill(); | ||
} | ||
|
||
bool InitiallyStoppedProcess::createProcessAndStop(const QString& exePath, const QStringList& exeOptions, | ||
const QString& workingDirectory) | ||
{ | ||
kill(); | ||
|
||
// convert arguments and working dir into what the C API needs | ||
const auto wd = workingDirectory.toLocal8Bit(); | ||
|
||
std::vector<QByteArray> argsQBA; | ||
std::vector<char*> argsRaw; | ||
auto addArg = [&](const QString& arg) { | ||
argsQBA.emplace_back(arg.toLocal8Bit()); | ||
argsRaw.emplace_back(argsQBA.back().data()); | ||
}; | ||
|
||
argsQBA.reserve(exeOptions.size() + 1); | ||
argsRaw.reserve(exeOptions.size() + 2); | ||
|
||
addArg(exePath); | ||
for (const auto& opt : exeOptions) | ||
addArg(opt); | ||
|
||
argsRaw.emplace_back(nullptr); | ||
|
||
// fork | ||
m_pid = fork(); | ||
|
||
if (m_pid == 0) { // inside child process | ||
// change working dir | ||
if (!wd.isEmpty() && chdir(wd.data()) != 0) { | ||
qCCritical(initiallystoppedprocess) | ||
<< "Failed to change working directory to:" << wd.data() << std::strerror(errno); | ||
} | ||
|
||
// stop self | ||
if (raise(SIGSTOP) != 0) { | ||
qCCritical(initiallystoppedprocess) << "Failed to raise SIGSTOP:" << std::strerror(errno); | ||
} | ||
|
||
// exec | ||
execvp(argsRaw[0], argsRaw.data()); | ||
qCCritical(initiallystoppedprocess) << "Failed to exec" << argsRaw[0] << std::strerror(errno); | ||
} else if (m_pid < 0) { | ||
qCCritical(initiallystoppedprocess) << "Failed to fork:" << std::strerror(errno); | ||
return false; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
bool InitiallyStoppedProcess::continueStoppedProcess() | ||
{ | ||
if (m_pid <= 0) | ||
return false; | ||
|
||
// wait for child to be stopped | ||
|
||
int wstatus; | ||
if (waitpid(m_pid, &wstatus, WUNTRACED) == -1) { | ||
qCWarning(initiallystoppedprocess()) << "Failed to wait on process:" << std::strerror(errno); | ||
} | ||
|
||
if (!WIFSTOPPED(wstatus)) { | ||
m_pid = -1; | ||
return false; | ||
} | ||
|
||
// continue | ||
|
||
sendSignal(m_pid, SIGCONT); | ||
return true; | ||
} | ||
|
||
void InitiallyStoppedProcess::terminate() | ||
{ | ||
if (m_pid > 0) { | ||
sendSignal(m_pid, SIGTERM); | ||
} | ||
} | ||
|
||
void InitiallyStoppedProcess::kill() | ||
{ | ||
if (m_pid > 0) { | ||
sendSignal(m_pid, SIGILL); | ||
if (waitpid(m_pid, nullptr, 0) == -1) { | ||
qCWarning(initiallystoppedprocess()) << "failed to wait on pid:" << m_pid << std::strerror(errno); | ||
} | ||
m_pid = -1; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
/* | ||
SPDX-FileCopyrightText: Zeno Endemann <zeno.endemann@kdab.com> | ||
SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com | ||
SPDX-License-Identifier: GPL-2.0-or-later | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include <QString> | ||
#include <QStringList> | ||
#include <QtGlobal> | ||
|
||
#include <unistd.h> | ||
|
||
class InitiallyStoppedProcess | ||
{ | ||
Q_DISABLE_COPY(InitiallyStoppedProcess) | ||
public: | ||
InitiallyStoppedProcess() = default; | ||
~InitiallyStoppedProcess(); | ||
|
||
/// @return the PID of the child process, or -1 if no process was started yet | ||
pid_t processPID() const | ||
{ | ||
return m_pid; | ||
} | ||
|
||
/// this function stops any existing child process and then creates a new child process | ||
/// and changes into @p workingDirectory. The process will be stopped immediately. | ||
/// After receiving SIGCONT it will run @p exePath with @p exeOptions | ||
/// @sa continueStoppedProcess | ||
bool createProcessAndStop(const QString& exePath, const QStringList& exeOptions, const QString& workingDirectory); | ||
|
||
/// wait for child process to be stopped and then continues its execution | ||
/// @sa createProcessAndStop | ||
bool continueStoppedProcess(); | ||
|
||
/// send SIGTERM to the child process | ||
void terminate(); | ||
|
||
/// send SIGKILL to the child process | ||
void kill(); | ||
|
||
private: | ||
pid_t m_pid = -1; | ||
}; |
Oops, something went wrong.