mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-10-23 03:26:59 +09:00
* fix: resolve critical IPC security vulnerabilities - Validate IP/CIDR values from IPC before passing to Linux firewall - Replace shell interpolation with direct execve in firewall update functions - Block dangerous OpenVPN/WireGuard arguments in sanitizeArguments() - Add programId bounds check in IpcServerProcess::setProgram() - Add SO_PEERCRED peer authentication for IPC connections on Linux * fix: extend IPC security validation to macOS firewall * fix: suppress linux firewall errors and add missing 400.allowPIA anchor * fix: review changes * fix: review changes next * fix: remove UID check from IPC server * fix: IPC security review fixes * fix: address IPC review fixes
117 lines
3.0 KiB
C++
117 lines
3.0 KiB
C++
#ifndef IPC_H
|
|
#define IPC_H
|
|
|
|
#include <QObject>
|
|
#include <QString>
|
|
#include <QRegularExpression>
|
|
#include <QSet>
|
|
|
|
#include "../client/core/utils/utilities.h"
|
|
|
|
#define IPC_SERVICE_URL "local:AmneziaVpnIpcInterface"
|
|
|
|
namespace amnezia {
|
|
|
|
enum PermittedProcess {
|
|
Invalid,
|
|
OpenVPN,
|
|
Wireguard,
|
|
Tun2Socks,
|
|
CertUtil,
|
|
PermittedProcessCount
|
|
};
|
|
|
|
inline QString permittedProcessPath(PermittedProcess pid)
|
|
{
|
|
switch (pid) {
|
|
case PermittedProcess::OpenVPN:
|
|
return Utils::openVpnExecPath();
|
|
case PermittedProcess::Wireguard:
|
|
return Utils::wireguardExecPath();
|
|
case PermittedProcess::CertUtil:
|
|
return Utils::certUtilPath();
|
|
case PermittedProcess::Tun2Socks:
|
|
return Utils::tun2socksPath();
|
|
default:
|
|
return "";
|
|
}
|
|
}
|
|
|
|
|
|
inline QString getIpcServiceUrl() {
|
|
#ifdef Q_OS_WIN
|
|
return IPC_SERVICE_URL;
|
|
#else
|
|
return QString("/tmp/%1").arg(IPC_SERVICE_URL);
|
|
#endif
|
|
}
|
|
|
|
inline QString getIpcProcessUrl(int pid) {
|
|
#ifdef Q_OS_WIN
|
|
return QString("%1_%2").arg(IPC_SERVICE_URL).arg(pid);
|
|
#else
|
|
return QString("/tmp/%1_%2").arg(IPC_SERVICE_URL).arg(pid);
|
|
#endif
|
|
}
|
|
|
|
inline QStringList sanitizeArguments(PermittedProcess proc, const QStringList &args) {
|
|
using Validator = std::function<bool(const QString&)>;
|
|
QMap<QString, Validator> namedArgs;
|
|
QList<Validator> positionalArgs;
|
|
|
|
switch (proc) {
|
|
case OpenVPN: {
|
|
namedArgs["--config"] = [](const QString& v) { return !v.isEmpty(); };
|
|
namedArgs["--management"] = [](const QString& v) { return !v.isEmpty(); };
|
|
namedArgs["--management-client"] = nullptr;
|
|
positionalArgs.append([](const QString& v) {
|
|
bool ok;
|
|
int port = v.toInt(&ok);
|
|
return ok && port > 0 && port <= 65535;
|
|
});
|
|
break;
|
|
}
|
|
case Tun2Socks:
|
|
namedArgs["-device"] = [](const QString& v) { return v.startsWith("tun://"); };
|
|
namedArgs["-proxy"] = [](const QString& v) { return v.startsWith("socks5://"); };
|
|
break;
|
|
case CertUtil:
|
|
return args;
|
|
default:
|
|
return {};
|
|
}
|
|
|
|
QStringList sanitized;
|
|
|
|
for (int i = 0, pos = 0; i < args.size(); i++) {
|
|
const auto& key = args[i];
|
|
|
|
if (const auto found = namedArgs.find(key); found != namedArgs.end()) {
|
|
const auto validator = found.value();
|
|
|
|
if (validator) {
|
|
if (i + 1 < args.size()) {
|
|
const auto& value = args[i+1];
|
|
if (validator(value)) {
|
|
sanitized << key << value;
|
|
i++;
|
|
}
|
|
}
|
|
} else {
|
|
sanitized << key;
|
|
}
|
|
} else if (pos < positionalArgs.size()) {
|
|
if (const auto validator = positionalArgs[pos]; validator && validator(key)) {
|
|
sanitized << key;
|
|
pos++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return sanitized;
|
|
}
|
|
|
|
} // namespace amnezia
|
|
|
|
#endif // IPC_H
|