Make ExternalCommandHelper::getNonce() reentrant.

Store previously generated values of nonce, and remove them from
the container when they are used.

BUG: 396312
This commit is contained in:
Andrius Štikonas 2018-07-21 11:03:25 +01:00
parent c50e04c9d1
commit 938ec7fa8b
4 changed files with 46 additions and 25 deletions

View File

@ -142,8 +142,8 @@ bool ExternalCommand::start(int timeout)
bool rval = false;
if (iface.isValid()) {
QByteArray request;
request.setNum(getNonce(iface));
const quint64 nonce = getNonce(iface);
request.setNum(nonce);
request.append(cmd.toUtf8());
for (const auto &argument : qAsConst(d->m_Args))
request.append(argument.toUtf8());
@ -154,6 +154,7 @@ bool ExternalCommand::start(int timeout)
QDBusPendingCall pcall = iface.asyncCall(QStringLiteral("start"),
privateKey->signMessage(hash, QCA::EMSA3_Raw),
nonce,
cmd,
args(),
d->m_Input,
@ -203,7 +204,8 @@ bool ExternalCommand::copyBlocks(CopySource& source, CopyTarget& target)
if (iface.isValid()) {
QByteArray request;
request.setNum(getNonce(iface));
const quint64 nonce = getNonce(iface);
request.setNum(nonce);
request.append(source.path().toUtf8());
request.append(QByteArray::number(source.firstByte()));
request.append(QByteArray::number(source.length()));
@ -214,8 +216,9 @@ bool ExternalCommand::copyBlocks(CopySource& source, CopyTarget& target)
QByteArray hash = QCryptographicHash::hash(request, QCryptographicHash::Sha512);
// Use asynchronous DBus calls, so that we can process reports and progress
QDBusPendingCall pcall= iface.asyncCall(QStringLiteral("copyblocks"),
QDBusPendingCall pcall = iface.asyncCall(QStringLiteral("copyblocks"),
privateKey->signMessage(hash, QCA::EMSA3_Raw),
nonce,
source.path(), source.firstByte(), source.length(),
target.path(), target.firstByte(), blockSize);
@ -410,16 +413,17 @@ void ExternalCommand::stopHelper()
QDBusInterface iface(QStringLiteral("org.kde.kpmcore.helperinterface"), QStringLiteral("/Helper"), QStringLiteral("org.kde.kpmcore.externalcommand"), QDBusConnection::systemBus());
if (iface.isValid()) {
QByteArray request;
request.setNum(getNonce(iface));
const quint64 nonce = getNonce(iface);
request.setNum(nonce);
QByteArray hash = QCryptographicHash::hash(request, QCryptographicHash::Sha512);
iface.call(QStringLiteral("exit"), privateKey->signMessage(hash, QCA::EMSA3_Raw));
iface.call(QStringLiteral("exit"), privateKey->signMessage(hash, QCA::EMSA3_Raw), nonce);
}
delete privateKey;
delete init;
}
unsigned long long ExternalCommand::getNonce(QDBusInterface& iface)
quint64 ExternalCommand::getNonce(QDBusInterface& iface)
{
QDBusPendingCall pcall = iface.asyncCall(QStringLiteral("getNonce"));
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pcall);

View File

@ -130,13 +130,13 @@ private:
void onFinished(int exitCode, QProcess::ExitStatus exitStatus);
void onReadOutput();
static unsigned long long getNonce(QDBusInterface& iface);
static quint64 getNonce(QDBusInterface& iface);
private:
std::unique_ptr<ExternalCommandPrivate> d;
// KAuth stuff
static unsigned long long m_Nonce;
// KAuth
static quint64 m_Nonce;
static KAuth::ExecuteJob *m_job;
static QCA::Initializer *init;
static QCA::PrivateKey *privateKey;

View File

@ -61,7 +61,6 @@ ActionReply ExternalCommandHelper::init(const QVariantMap& args)
}
m_publicKey = QCA::PublicKey::fromDER(args[QStringLiteral("pubkey")].toByteArray());
m_Nonce = m_Generator.generate();
HelperSupport::progressStep(QVariantMap());
auto timeout = [this] () {
@ -93,10 +92,11 @@ ActionReply ExternalCommandHelper::init(const QVariantMap& args)
/** Generates cryptographic nonce
* @return nonce
*/
unsigned long long ExternalCommandHelper::getNonce()
quint64 ExternalCommandHelper::getNonce()
{
m_Nonce = m_Generator.generate();
return m_Nonce;
quint64 nonce = m_Generator.generate();
m_Nonces.insert(nonce);
return nonce;
}
/** Reads the given number of bytes from the sourceDevice into the given buffer.
@ -156,11 +156,16 @@ bool ExternalCommandHelper::writeData(const QString &targetDevice, const QByteAr
return true;
}
bool ExternalCommandHelper::copyblocks(const QByteArray& signature, const QString& sourceDevice, const qint64 sourceFirstByte, const qint64 sourceLength, const QString& targetDevice, const qint64 targetFirstByte, const qint64 blockSize)
bool ExternalCommandHelper::copyblocks(const QByteArray& signature, const quint64 nonce, const QString& sourceDevice, const qint64 sourceFirstByte, const qint64 sourceLength, const QString& targetDevice, const qint64 targetFirstByte, const qint64 blockSize)
{
if (m_Nonces.find(nonce) != m_Nonces.end())
m_Nonces.erase( nonce );
else
return false;
QByteArray request;
request.setNum(m_Nonce);
request.setNum(nonce);
request.append(sourceDevice.toUtf8());
request.append(QByteArray::number(sourceFirstByte));
request.append(QByteArray::number(sourceLength));
@ -253,14 +258,21 @@ bool ExternalCommandHelper::copyblocks(const QByteArray& signature, const QStrin
return rval;
}
QVariantMap ExternalCommandHelper::start(const QByteArray& signature, const QString& command, const QStringList& arguments, const QByteArray& input, const int processChannelMode)
QVariantMap ExternalCommandHelper::start(const QByteArray& signature, const quint64 nonce, const QString& command, const QStringList& arguments, const QByteArray& input, const int processChannelMode)
{
QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
QVariantMap reply;
reply[QStringLiteral("success")] = true;
if (m_Nonces.find(nonce) != m_Nonces.end())
m_Nonces.erase( nonce );
else {
reply[QStringLiteral("success")] = false;
return reply;
}
QByteArray request;
request.setNum(m_Nonce);
request.setNum(nonce);
request.append(command.toUtf8());
for (const auto &argument : arguments)
request.append(argument.toUtf8());
@ -288,10 +300,13 @@ QVariantMap ExternalCommandHelper::start(const QByteArray& signature, const QStr
return reply;
}
void ExternalCommandHelper::exit(const QByteArray& signature)
void ExternalCommandHelper::exit(const QByteArray& signature, const quint64 nonce)
{
QByteArray request;
request.setNum(m_Nonce);
if (m_Nonces.find(nonce) == m_Nonces.end())
return;
request.setNum(nonce);
QByteArray hash = QCryptographicHash::hash(request, QCryptographicHash::Sha512);
if (!m_publicKey.verifyMessage(hash, signature, QCA::EMSA3_Raw)) {
qCritical() << xi18n("Invalid cryptographic signature");

View File

@ -18,6 +18,8 @@
#ifndef KPMCORE_EXTERNALCOMMANDHELPER_H
#define KPMCORE_EXTERNALCOMMANDHELPER_H
#include <unordered_set>
#include <KAuth>
#include <QEventLoop>
@ -44,10 +46,10 @@ public:
public Q_SLOTS:
ActionReply init(const QVariantMap& args);
Q_SCRIPTABLE unsigned long long getNonce();
Q_SCRIPTABLE QVariantMap start(const QByteArray& signature, const QString& command, const QStringList& arguments, const QByteArray& input, const int processChannelMode);
Q_SCRIPTABLE bool copyblocks(const QByteArray& signature, const QString& sourceDevice, const qint64 sourceFirstByte, const qint64 sourceLength, const QString& targetDevice, const qint64 targetFirstByte, const qint64 blockSize);
Q_SCRIPTABLE void exit(const QByteArray& signature);
Q_SCRIPTABLE quint64 getNonce();
Q_SCRIPTABLE QVariantMap start(const QByteArray& signature, const quint64 nonce, const QString& command, const QStringList& arguments, const QByteArray& input, const int processChannelMode);
Q_SCRIPTABLE bool copyblocks(const QByteArray& signature, const quint64 nonce, const QString& sourceDevice, const qint64 sourceFirstByte, const qint64 sourceLength, const QString& targetDevice, const qint64 targetFirstByte, const qint64 blockSize);
Q_SCRIPTABLE void exit(const QByteArray& signature, const quint64 nonce);
private:
void onReadOutput();
@ -56,7 +58,7 @@ private:
QCA::Initializer initializer;
QCA::PublicKey m_publicKey;
QRandomGenerator64 m_Generator;
unsigned long long m_Nonce;
std::unordered_set<quint64> m_Nonces;
QString m_command;
QString m_sourceDevice;
QProcess m_cmd;