fix: unescape exec before pass this arg to wordexp

Signed-off-by: ComixHe <heyuming@deepin.org>
This commit is contained in:
ComixHe 2023-10-19 14:18:44 +08:00 committed by Comix
parent 5597ba5c44
commit f796535233
5 changed files with 98 additions and 27 deletions

View File

@ -9,6 +9,7 @@
#include "propertiesForwarder.h" #include "propertiesForwarder.h"
#include "dbus/instanceadaptor.h" #include "dbus/instanceadaptor.h"
#include "launchoptions.h" #include "launchoptions.h"
#include "desktopentry.h"
#include <QUuid> #include <QUuid>
#include <QStringList> #include <QStringList>
#include <QList> #include <QList>
@ -197,7 +198,8 @@ QDBusObjectPath ApplicationService::Launch(const QString &action, const QStringL
sendErrorReply(QDBusError::Failed, msg); sendErrorReply(QDBusError::Failed, msg);
return {}; return {};
} }
execStr = toString(Actions.value());
execStr = Actions.value().toString();
if (execStr.isEmpty()) { if (execStr.isEmpty()) {
QString msg{"maybe entry actions's format is invalid, abort launch."}; QString msg{"maybe entry actions's format is invalid, abort launch."};
qWarning() << msg; qWarning() << msg;
@ -733,13 +735,21 @@ void ApplicationService::resetEntry(DesktopEntry *newEntry) noexcept
emit scaleFactorChanged(); emit scaleFactorChanged();
} }
LaunchTask ApplicationService::unescapeExec(const QString &str, const QStringList &fields) QStringList ApplicationService::unescapeExecArgs(const QString &str) noexcept
{ {
LaunchTask task; auto unescapedStr = unescape(str, true);
auto deleter = [](wordexp_t *word) { wordfree(word); }; if (unescapedStr.isEmpty()) {
qWarning() << "unescape Exec failed.";
return {};
}
auto deleter = [](wordexp_t *word) {
wordfree(word);
delete word;
};
std::unique_ptr<wordexp_t, decltype(deleter)> words{new (std::nothrow) wordexp_t{0, nullptr, 0}, deleter}; std::unique_ptr<wordexp_t, decltype(deleter)> words{new (std::nothrow) wordexp_t{0, nullptr, 0}, deleter};
if (auto ret = wordexp(str.toLocal8Bit().constData(), words.get(), WRDE_SHOWERR); ret != 0) { if (auto ret = wordexp(unescapedStr.toLocal8Bit(), words.get(), WRDE_SHOWERR); ret != 0) {
if (ret != 0) { if (ret != 0) {
QString errMessage; QString errMessage;
switch (ret) { switch (ret) {
@ -771,6 +781,14 @@ LaunchTask ApplicationService::unescapeExec(const QString &str, const QStringLis
for (int i = 0; i < words->we_wordc; ++i) { for (int i = 0; i < words->we_wordc; ++i) {
execList.emplace_back(words->we_wordv[i]); execList.emplace_back(words->we_wordv[i]);
} }
return execList;
}
LaunchTask ApplicationService::unescapeExec(const QString &str, const QStringList &fields) noexcept
{
LaunchTask task;
auto execList = unescapeExecArgs(str);
task.LaunchBin = execList.first(); task.LaunchBin = execList.first();
QRegularExpression re{"%[fFuUickdDnNvm]"}; QRegularExpression re{"%[fFuUickdDnNvm]"};

View File

@ -5,25 +5,25 @@
#ifndef APPLICATIONSERVICE_H #ifndef APPLICATIONSERVICE_H
#define APPLICATIONSERVICE_H #define APPLICATIONSERVICE_H
#include <QObject> #include "applicationmanager1service.h"
#include <QDBusObjectPath>
#include <QMap>
#include <QString>
#include <QDBusUnixFileDescriptor>
#include <QSharedPointer>
#include <QUuid>
#include <QTextStream>
#include <QDBusContext>
#include <QFile>
#include <memory>
#include <utility>
#include "applicationmanagerstorage.h" #include "applicationmanagerstorage.h"
#include "dbus/applicationmanager1service.h" #include "dbus/applicationmanager1service.h"
#include "dbus/instanceservice.h" #include "dbus/instanceservice.h"
#include "global.h"
#include "desktopentry.h"
#include "dbus/jobmanager1service.h" #include "dbus/jobmanager1service.h"
#include "applicationmanager1service.h" #include "desktopentry.h"
#include "global.h"
#include <QDBusContext>
#include <QDBusObjectPath>
#include <QDBusUnixFileDescriptor>
#include <QFile>
#include <QMap>
#include <QObject>
#include <QSharedPointer>
#include <QString>
#include <QTextStream>
#include <QUuid>
#include <memory>
#include <utility>
QString getDeepinWineScaleFactor(const QString &appId) noexcept; QString getDeepinWineScaleFactor(const QString &appId) noexcept;
double getScaleFactor() noexcept; double getScaleFactor() noexcept;
@ -70,8 +70,8 @@ public:
[[nodiscard]] bool terminal() const noexcept; [[nodiscard]] bool terminal() const noexcept;
// FIXME: // FIXME:
// This property should implement with fuse guarded $XDG_CONFIG_HOME/autostart/. // This property should implement with fuse guarded
// Current implementation has some problems, // $XDG_CONFIG_HOME/autostart/. Current implementation has some problems,
Q_PROPERTY(bool AutoStart READ isAutoStart WRITE setAutoStart NOTIFY autostartChanged) Q_PROPERTY(bool AutoStart READ isAutoStart WRITE setAutoStart NOTIFY autostartChanged)
[[nodiscard]] bool isAutoStart() const noexcept; [[nodiscard]] bool isAutoStart() const noexcept;
void setAutoStart(bool autostart) noexcept; void setAutoStart(bool autostart) noexcept;
@ -119,6 +119,9 @@ public:
void resetEntry(DesktopEntry *newEntry) noexcept; void resetEntry(DesktopEntry *newEntry) noexcept;
void detachAllInstance() noexcept; void detachAllInstance() noexcept;
[[nodiscard]] LaunchTask unescapeExec(const QString &str, const QStringList &fields) noexcept;
[[nodiscard]] static QStringList unescapeExecArgs(const QString &str) noexcept;
private Q_SLOTS: private Q_SLOTS:
void onGlobalScaleFactorChanged() noexcept; void onGlobalScaleFactorChanged() noexcept;
@ -165,7 +168,6 @@ private:
DesktopFile m_desktopSource; DesktopFile m_desktopSource;
QSharedPointer<DesktopEntry> m_entry{nullptr}; QSharedPointer<DesktopEntry> m_entry{nullptr};
QMap<QDBusObjectPath, QSharedPointer<InstanceService>> m_Instances; QMap<QDBusObjectPath, QSharedPointer<InstanceService>> m_Instances;
[[nodiscard]] LaunchTask unescapeExec(const QString &str, const QStringList &fields);
[[nodiscard]] QVariant findEntryValue(const QString &group, [[nodiscard]] QVariant findEntryValue(const QString &group,
const QString &valueKey, const QString &valueKey,
EntryValueType type, EntryValueType type,

View File

@ -236,7 +236,7 @@ std::optional<DesktopEntry::Value> DesktopEntry::value(const QString &groupKey,
return *it; return *it;
} }
QString unescape(const QString &str) noexcept QString unescape(const QString &str, bool shellMode) noexcept
{ {
QString unescapedStr; QString unescapedStr;
for (qsizetype i = 0; i < str.size(); ++i) { for (qsizetype i = 0; i < str.size(); ++i) {
@ -270,10 +270,13 @@ QString unescape(const QString &str) noexcept
unescapedStr.append(';'); unescapedStr.append(';');
++i; ++i;
break; break;
case 's': case 's': {
if (shellMode) { // for wordexp
unescapedStr.append('\\');
}
unescapedStr.append(' '); unescapedStr.append(' ');
++i; ++i;
break; } break;
} }
} }
@ -296,6 +299,7 @@ QString toString(const DesktopEntry::Value &value) noexcept
} }
auto unescapedStr = unescape(str); auto unescapedStr = unescape(str);
if (hasNonAsciiAndControlCharacters(unescapedStr)) { if (hasNonAsciiAndControlCharacters(unescapedStr)) {
return {}; return {};
} }

View File

@ -137,7 +137,7 @@ bool operator==(const DesktopFile &lhs, const DesktopFile &rhs);
bool operator!=(const DesktopFile &lhs, const DesktopFile &rhs); bool operator!=(const DesktopFile &lhs, const DesktopFile &rhs);
QString unescape(const QString &str) noexcept; QString unescape(const QString &str, bool shellMode = false) noexcept;
QString toLocaleString(const QStringMap &localeMap, const QLocale &locale) noexcept; QString toLocaleString(const QStringMap &localeMap, const QLocale &locale) noexcept;

47
tests/ut_escapeexec.cpp Normal file
View File

@ -0,0 +1,47 @@
// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later
#include "dbus/applicationservice.h"
#include <gtest/gtest.h>
#include <QString>
TEST(UnescapeExec, blankSpace)
{
QList<std::pair<QString, QList<QString>>> testCases{
{
R"(/usr/bin/hello\sworld --arg1=val1 -h --str="rrr ggg bbb")",
{
"/usr/bin/hello world",
"--arg1=val1",
"-h",
"--str=rrr ggg bbb",
},
},
{
R"("/usr/bin/hello world" a b -- "c d")",
{
"/usr/bin/hello world",
"a",
"b",
"--",
"c d",
},
},
{
R"("/usr/bin/hello\t\nworld" a b -- c d)",
{
"/usr/bin/hello\t\nworld",
"a",
"b",
"--",
"c",
"d",
},
},
};
for (auto &testCase : testCases) {
EXPECT_EQ(ApplicationService::unescapeExecArgs(testCase.first), testCase.second);
}
}