You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
dp4-uos/example/service/qtdbushook.cpp

276 lines
11 KiB

// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later
#include "qtdbushook.h"
#include "policy.h"
#include "serviceqtdbus.h"
#include <QDBusConnectionInterface>
#include <QDBusMessage>
#include <QDebug>
#include <QFile>
#include <QLoggingCategory>
#include <QTimer>
#ifdef Q_DBUS_EXPORT
extern Q_DBUS_EXPORT void qDBusAddSpyHook(void (*)(const QDBusMessage &));
extern Q_DBUS_EXPORT void qDBusAddFilterHook(int (*)(const QString &, const QDBusMessage &));
#else
extern QDBUS_EXPORT void qDBusAddSpyHook(void (*)(const QDBusMessage &));
extern QDBUS_EXPORT void qDBusAddFilterHook(int (*)(const QString &, const QDBusMessage &));
#endif
#ifdef Q_DBUS_HOOK_FILTER
# define HOOK_RESULT_TYPE int
# define HOOK_RESULT_SUCCESS 0
# define HOOK_RESULT_FAILED -1
#else
# define HOOK_RESULT_TYPE void
# define HOOK_RESULT_SUCCESS
# define HOOK_RESULT_FAILED
#endif
Q_LOGGING_CATEGORY(dsm_hook_qt, "[QDBusHook]")
QString getCMD(ServiceBase *obj, QString dbusService)
{
ServiceQtDBus *srv = qobject_cast<ServiceQtDBus *>(obj);
if (!srv) {
return "";
}
const unsigned int &pid = srv->qDbusConnection().interface()->servicePid(dbusService).value();
qCDebug(dsm_hook_qt) << "--pid:" << pid;
QFile procCmd("/proc/" + QString::number(pid) + "/cmdline");
QString cmd;
if (procCmd.open(QIODevice::ReadOnly)) {
QList<QByteArray> cmds = procCmd.readAll().split('\0');
cmd = QString(cmds.first());
qCDebug(dsm_hook_qt) << "--cmd:" << cmd;
}
return cmd;
}
// if it is not a local message, hook exec at main thread
void QTDBusSpyHook(const QDBusMessage &msg)
{
qCInfo(dsm_hook_qt) << "--msg=" << msg;
// qInfo() << "--Handler ThreadID:" << QThread::currentThreadId();
ServiceBase *serviceObj = nullptr;
bool isSubPath;
QString realPath; // 子PATH可能没有配置,使用父PATH的配置
bool findRet = QTDbusHook::instance()->getServiceObject("",
msg.path(),
&serviceObj,
isSubPath,
realPath);
if (!findRet) {
qCWarning(dsm_hook_qt) << "--can not find hook object: " << msg.path();
return;
}
if (!serviceObj->isRegister()) {
qCInfo(dsm_hook_qt) << "--to register dbus object: " << msg.path();
serviceObj->registerService();
}
if (!serviceObj->policy->isResident() && !serviceObj->isLockTimer()) {
qCInfo(dsm_hook_qt) << QString("--service: %1 will unregister in %2 minutes!")
.arg(serviceObj->policy->name)
.arg(serviceObj->policy->idleTime);
QTimer::singleShot(0, serviceObj, SLOT(restartTimer()));
}
if (msg.member() == "Introspect" && msg.interface() == "org.freedesktop.DBus.Introspectable") {
if (serviceObj->policy->checkPathHide(realPath)) {
qCDebug(dsm_hook_qt) << "--call Introspect" << msg.path() << " ,is hided!";
QList<QVariant> arguments;
arguments << "";
QDBusMessage reply = msg.createReply(arguments);
ServiceQtDBus *srv = qobject_cast<ServiceQtDBus *>(serviceObj);
if (srv) {
srv->qDbusConnection().send(reply);
}
// ((ServiceQtDBus*)serviceObj)->qDbusConnection().send(reply);
}
} else if (msg.member() == "Set" && msg.interface() == "org.freedesktop.DBus.Properties") {
const QList<QVariant> &args = msg.arguments();
if (args.size() >= 2) {
if (!serviceObj->policy->checkPropertyPermission(getCMD(serviceObj, msg.service()),
realPath,
args.at(0).toString(),
args.at(1).toString())) {
QDBusMessage reply = msg.createErrorReply("com.deepin.service.Permission.Deny",
"The call is deny");
ServiceQtDBus *srv = qobject_cast<ServiceQtDBus *>(serviceObj);
if (srv) {
srv->qDbusConnection().send(reply);
return;
}
}
}
} else if (msg.interface() != "org.freedesktop.DBus.Properties"
&& msg.interface() != "org.freedesktop.DBus.Introspectable"
&& msg.interface() != "org.freedesktop.DBus.Peer") {
if (!serviceObj->policy->checkMethodPermission(getCMD(serviceObj, msg.service()),
realPath,
msg.interface(),
msg.member())) {
QDBusMessage reply =
msg.createErrorReply("com.deepin.service.Permission.Deny", "The call is deny2");
ServiceQtDBus *srv = qobject_cast<ServiceQtDBus *>(serviceObj);
if (srv) {
// srv->qDbusConnection().send(reply);
// QDBusConnection::sessionBus().send(reply);
QDBusConnection::connectToBus(QDBusConnection::SessionBus,
QString("org.dsdsf.dsfsdf"))
.send(reply);
return;
}
}
}
return;
}
// if it is not a local message, hook exec at main thread
int QTDBusHook(const QString &baseService, const QDBusMessage &msg)
{
qCInfo(dsm_hook_qt) << "--baseService=" << baseService;
qCInfo(dsm_hook_qt) << "--msg=" << msg;
// qInfo() << "--Handler ThreadID:" << QThread::currentThreadId();
ServiceBase *serviceObj = nullptr;
bool isSubPath;
QString realPath; // 子PATH可能没有配置,使用父PATH的配置
bool findRet = QTDbusHook::instance()->getServiceObject("",
msg.path(),
&serviceObj,
isSubPath,
realPath);
if (!findRet) {
qCWarning(dsm_hook_qt) << "--can not find hook object:" << msg.path();
return 0;
}
if (!serviceObj->isRegister()) {
qCInfo(dsm_hook_qt) << "--to register dbus object: " << msg.path();
serviceObj->registerService();
}
if (!serviceObj->policy->isResident() && !serviceObj->isLockTimer()) {
qCInfo(dsm_hook_qt) << QString("--service: %1 will unregister in 10 minutes!")
.arg(serviceObj->policy->name);
QTimer::singleShot(0, serviceObj, SLOT(restartTimer()));
}
if (msg.member() == "Introspect" && msg.interface() == "org.freedesktop.DBus.Introspectable") {
if (serviceObj->policy->checkPathHide(realPath)) {
qCDebug(dsm_hook_qt) << "--call Introspect" << msg.path() << " ,is hided!";
QList<QVariant> arguments;
arguments << "";
QDBusMessage reply = msg.createReply(arguments);
ServiceQtDBus *srv = qobject_cast<ServiceQtDBus *>(serviceObj);
if (srv) {
srv->qDbusConnection().send(reply);
}
// ((ServiceQtDBus*)serviceObj)->qDbusConnection().send(reply);
}
} else if (msg.member() == "Set" && msg.interface() == "org.freedesktop.DBus.Properties") {
const QList<QVariant> &args = msg.arguments();
if (args.size() >= 2) {
if (!serviceObj->policy->checkPropertyPermission(getCMD(serviceObj, msg.service()),
realPath,
args.at(0).toString(),
args.at(1).toString())) {
QDBusMessage reply = msg.createErrorReply("com.deepin.service.Permission.Deny",
"The call is deny");
ServiceQtDBus *srv = qobject_cast<ServiceQtDBus *>(serviceObj);
if (srv) {
srv->qDbusConnection().send(reply);
return -1;
}
}
}
} else if (msg.interface() != "org.freedesktop.DBus.Properties"
&& msg.interface() != "org.freedesktop.DBus.Introspectable"
&& msg.interface() != "org.freedesktop.DBus.Peer") {
if (!serviceObj->policy->checkMethodPermission(getCMD(serviceObj, msg.service()),
realPath,
msg.interface(),
msg.member())) {
QDBusMessage reply =
msg.createErrorReply("com.deepin.service.Permission.Deny", "The call is deny2");
ServiceQtDBus *srv = qobject_cast<ServiceQtDBus *>(serviceObj);
if (srv) {
srv->qDbusConnection().send(reply);
return -1;
}
}
}
return 0;
// test TODO
// if (msg.member() == "Register") {
// Policy ppp;
// ppp.Test();
// QList<QVariant> arguments;
// arguments << true << "sdvvv";
// QDBusMessage reply =
// msg.createErrorReply("com.deepin.services.Nooooooo", "The method
// call 'Register()' is not supported");
// QDBusConnection::connectToBus(QDBusConnection::SessionBus,
// "org.deepin.services.demo2").send(reply);
// }
}
Q_GLOBAL_STATIC(QTDbusHook, qtDBusHook)
QTDbusHook::QTDbusHook()
{
qCDebug(dsm_hook_qt) << "qt hook register.";
#ifdef Q_DBUS_HOOK_FILTER
qDBusAddFilterHook(QTDBusHook);
#else
qDBusAddSpyHook(QTDBusSpyHook);
#endif
}
QTDbusHook *QTDbusHook::instance()
{
return qtDBusHook;
}
bool QTDbusHook::getServiceObject(
QString name, QString path, ServiceBase **service, bool &isSubPath, QString &realPath)
{
Q_UNUSED(name) // TODO:QtDBus Hook 无法获取到name
ServiceObjectMap::iterator iterService = m_serviceMap.find(path);
if (iterService != m_serviceMap.end()) {
*service = iterService.value();
isSubPath = true;
realPath = iterService.key();
return true;
}
for (auto iter = m_serviceMap.begin(); iter != m_serviceMap.end(); ++iter) {
if (path.startsWith(iter.key()) && iter.value()->policy->allowSubPath(iter.key())) {
*service = iter.value();
isSubPath = false;
realPath = iter.key();
return true;
}
}
return false;
}
bool QTDbusHook::setServiceObject(ServiceBase *obj)
{
QStringList paths = obj->policy->paths();
for (auto path : paths) {
ServiceObjectMap::iterator iterService = m_serviceMap.find(path);
if (iterService != m_serviceMap.end()) {
qCWarning(dsm_hook_qt) << "set service path failed, the object is existed: " << path;
continue;
}
m_serviceMap[path] = obj;
}
return true;
}