From f66914c06f09ecd5231b962440bbdac86c131fd1 Mon Sep 17 00:00:00 2001 From: wangrong Date: Thu, 2 Jul 2026 10:13:24 +0800 Subject: [PATCH] fix(security): replace shell exec with direct subprocess invocation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Eliminate /bin/bash -c pipe commands across utils, xfs, luks, partedcore, watcher and DeviceStorage. Use QProcess with explicit argument lists and pipe stdin for passwords (LUKS) and interactive input (fdisk), avoiding shell injection and credential leakage via ps. 移除 utils、xfs、luks、partedcore、watcher 及 DeviceStorage 中通过 /bin/bash -c 执行管道命令的方式,改为使用 QProcess 显式参数列表, 并通过 stdin 传入密码(LUKS)及交互输入(fdisk), 避免 shell 注入及凭据经 ps 泄漏。 Log: 重构命令执行方式,使用直接子进程调用替代 shell 管道 PMS: BUG-368007 Influence: 消除 shell 注入与命令行凭据泄漏风险,提升磁盘管理服务安全性;同时减少对 awk/grep 等外部 shell 工具的依赖。 --- basestruct/utils.cpp | 35 ++++++++-- basestruct/utils.h | 8 ++- service/diskoperation/DeviceStorage.cpp | 18 +++-- service/diskoperation/filesystems/xfs.cpp | 13 ++-- .../luksoperator/luksoperator.cpp | 69 ++++++------------- service/diskoperation/partedcore.cpp | 14 ++-- service/watcher.cpp | 41 ++++++----- service/watcher.h | 4 +- 8 files changed, 107 insertions(+), 95 deletions(-) diff --git a/basestruct/utils.cpp b/basestruct/utils.cpp index 0f398967..fdb8ca60 100644 --- a/basestruct/utils.cpp +++ b/basestruct/utils.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2022 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-only @@ -86,12 +86,37 @@ int Utils::executCmd(const QString &strCmd, QString &outPut, QString &error) return exitcode; } -int Utils::executWithPipeCmd(const QString &strCmd, QString &outPut, QString &error) +int Utils::executWithInputOutputCmd(const QString &strCmd, const QStringList &strArg, const QString *inPut, QString &outPut, QString &error) { - QStringList argList; - argList << "-c" << strCmd; + qDebug() << "Entering Utils::executWithInputOutputCmd with command:" << strCmd << strArg; + QProcess proc; + int exitCode; + + proc.start(strCmd, strArg); + + // 统一等待启动完成:无论是否需要写入 stdin,都检测 FailedToStart + // (程序不存在等场景),避免后续 readAll 取到空输出且 exitCode 为 0 的"假成功" + if (!proc.waitForStarted(-1)) { + error = proc.errorString(); + return -1; + } + + if (inPut) { + proc.write(inPut->toLocal8Bit()); + proc.closeWriteChannel(); + } + + proc.waitForFinished(-1); + outPut = proc.readAllStandardOutput().data(); + // 优先取子进程 stderr(含 cryptsetup/xfs_db 等的真实失败原因); + // 为空时回退到 QProcess 自身错误(如启动失败 execvp: ...) + QString stdErr = proc.readAllStandardError(); + error = stdErr.isEmpty() ? proc.errorString() : stdErr; + exitCode = proc.exitCode(); + proc.close(); - return executeCmdWithArtList("/bin/bash", argList, outPut, error); + qDebug() << "Utils::executWithInputOutputCmd exitCode: " << exitCode; + return exitCode; } int Utils::executWithErrorCmd(const QString &strCmd, const QStringList &strArg, QString &outPut, QString &outPutError, QString &error) diff --git a/basestruct/utils.h b/basestruct/utils.h index 47113f60..28f3c85b 100644 --- a/basestruct/utils.h +++ b/basestruct/utils.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2022 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-only @@ -55,13 +55,15 @@ class Utils static int executCmd(const QString &strCmd); /** - * @brief 执行外部命令,使用 /bin/bash -c 执行管道命令 + * @brief 执行外部命令,并提供输入输出 * @param strCmd:命令 + * @param strArg:参数 + * @param inPut:命令输入 * @param outPut:命令输出 * @param error:错误信息 * @return 非0失败 */ - static int executWithPipeCmd(const QString &strCmd, QString &outPut, QString &error); + static int executWithInputOutputCmd(const QString &strCmd, const QStringList &strArg, const QString *inPut, QString &outPut, QString &error); /** * @brief 执行外部命令 diff --git a/service/diskoperation/DeviceStorage.cpp b/service/diskoperation/DeviceStorage.cpp index 6fe1896a..cb3fd798 100755 --- a/service/diskoperation/DeviceStorage.cpp +++ b/service/diskoperation/DeviceStorage.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2022 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-only @@ -504,14 +504,18 @@ void DeviceStorage::getDiskInfoModel(const QString &devicePath, QString &model) } } - cmd = "udevadm info " + devicePath + " | grep ID_MODEL="; - proc.start("bash", QStringList() << "-c" << cmd); + proc.start("udevadm", QStringList() << "info" << devicePath); proc.waitForFinished(-1); outPut = proc.readAllStandardOutput(); - if (!outPut.isEmpty()) { - auto idModel = outPut.split("=", QString::SkipEmptyParts); - if (idModel.count() > 1) - model = idModel.at(1).trimmed(); + QString key = "ID_MODEL="; + int start = outPut.indexOf(key); + if (start != -1) { + start += key.length(); // 移动到等号后面 + int end = outPut.indexOf('\n', start); // 找到行尾 + if (end == -1) + end = outPut.length(); // 如果是最后一行 + + model = outPut.mid(start, end - start).trimmed(); if (!model.isEmpty()) return; } diff --git a/service/diskoperation/filesystems/xfs.cpp b/service/diskoperation/filesystems/xfs.cpp index 77416cb5..a368815b 100644 --- a/service/diskoperation/filesystems/xfs.cpp +++ b/service/diskoperation/filesystems/xfs.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2022 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-only @@ -47,12 +47,13 @@ FS XFS::getFilesystemSupport() void XFS::setUsedSectors(Partition &partition) { - QString output, error, strmatch, strcmd; + QString output, error; m_blocksSize = m_numOfFreeOrUsedBlocks = m_totalNumOfBlock = -1; - strcmd = QString("xfs_db -r -c 'sb 0' -c 'print blocksize' -c 'print dblocks'" - " -c 'print fdblocks' %1") - .arg(partition.getPath()); - if (Utils::executWithPipeCmd(strcmd, output, error) == 0) { + QStringList args; + args << "-r" << "-c" << "sb 0" << "-c" << "print blocksize" + << "-c" << "print dblocks" << "-c" << "print fdblocks" + << partition.getPath(); + if (Utils::executWithInputOutputCmd("xfs_db", args, nullptr, output, error) == 0) { auto strList = output.split("\n"); foreach (auto &item, strList) { auto value = item.split("=", QString::SkipEmptyParts); diff --git a/service/diskoperation/luksoperator/luksoperator.cpp b/service/diskoperation/luksoperator/luksoperator.cpp index fe071417..03cb382f 100644 --- a/service/diskoperation/luksoperator/luksoperator.cpp +++ b/service/diskoperation/luksoperator/luksoperator.cpp @@ -1,5 +1,4 @@ -// Copyright (C) 2022 ~ 2022 Deepin Technology Co., Ltd. -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2022 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-only @@ -476,20 +475,13 @@ bool LUKSOperator::isLUKS(QString devPath) bool LUKSOperator::format(const LUKS_INFO &luks) { - QProcess proc; - QStringList options; - options << "-c" << QString("echo -n '%1' | cryptsetup --cipher %2 --key-size 256 --hash sha256 luksFormat --label=%3 %4 -q") - .arg(luks.m_decryptStr) - .arg(Utils::getCipherStr(luks.m_crypt)) - .arg(luks.m_fileSystemLabel) - .arg(luks.m_devicePath); - proc.start("/bin/bash", options); - proc.waitForFinished(-1); - proc.waitForReadyRead(); - QString outPut = proc.readAllStandardOutput(); - QString error = proc.errorString(); - proc.close(); - bool success = (proc.exitCode() == 0); + QString outPut, error; + QStringList args; + args << "--cipher" << Utils::getCipherStr(luks.m_crypt) + << "--key-size" << "256" << "--hash" << "sha256" + << "luksFormat" << QString("--label=%1").arg(luks.m_fileSystemLabel) + << luks.m_devicePath << "-q"; + bool success = (Utils::executWithInputOutputCmd("cryptsetup", args, &luks.m_decryptStr, outPut, error) == 0); if (!success) { qCritical() << Q_FUNC_INFO << "output:" << outPut << "\terror:" << error; } @@ -498,32 +490,18 @@ bool LUKSOperator::format(const LUKS_INFO &luks) bool LUKSOperator::open(const LUKS_INFO &luks) { - QProcess proc; - QStringList options; - options << "-c" << QString("echo -n '%1' | cryptsetup open %2 %3 -q") - .arg(luks.m_decryptStr) - .arg(luks.m_devicePath) - .arg(luks.m_mapper.m_dmName); - proc.start("/bin/bash", options); - proc.waitForFinished(-1); - proc.waitForReadyRead();// - proc.close(); - return proc.exitCode() == 0; + QString outPut, error; + QStringList args; + args << "open" << luks.m_devicePath << luks.m_mapper.m_dmName << "-q"; + return (Utils::executWithInputOutputCmd("cryptsetup", args, &luks.m_decryptStr, outPut, error) == 0); } bool LUKSOperator::testKey(const LUKS_INFO &luks) { - QProcess proc; - QStringList options; - options << "-c" << QString("echo -n '%1' | cryptsetup open --test-passphrase %2 %3 -q") - .arg(luks.m_decryptStr) - .arg(luks.m_devicePath) - .arg(luks.m_mapper.m_dmName); - proc.start("/bin/bash", options); - proc.waitForFinished(-1); - proc.waitForReadyRead();// - proc.close(); - return proc.exitCode() == 0; + QString outPut, error; + QStringList args; + args << "open" << "--test-passphrase" << luks.m_devicePath << luks.m_mapper.m_dmName << "-q"; + return (Utils::executWithInputOutputCmd("cryptsetup", args, &luks.m_decryptStr, outPut, error) == 0); } bool LUKSOperator::close(const LUKS_INFO &luks) @@ -597,17 +575,10 @@ bool LUKSOperator::addKeyFile(const LUKS_INFO &luks) } //添加key - QProcess proc; - QStringList options; - options << "-c" << QString("echo -n '%1' | cryptsetup luksAddKey %2 %3 -q") - .arg(luks.m_decryptStr) - .arg(luks.m_devicePath) - .arg(filePath); - proc.start("/bin/bash", options); - proc.waitForFinished(); - proc.waitForReadyRead();// - proc.close(); - return proc.exitCode() == 0; + QString outPut, error; + QStringList args; + args << "luksAddKey" << luks.m_devicePath << filePath << "-q"; + return (Utils::executWithInputOutputCmd("cryptsetup", args, &luks.m_decryptStr, outPut, error) == 0); } bool LUKSOperator::deleteKeyFile(const LUKS_INFO &luks) diff --git a/service/diskoperation/partedcore.cpp b/service/diskoperation/partedcore.cpp index 41274d36..87be2789 100644 --- a/service/diskoperation/partedcore.cpp +++ b/service/diskoperation/partedcore.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2022 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-only @@ -432,8 +432,10 @@ bool PartedCore::detectionPartitionTableError(const QString &devicePath) bool needRewrite = gptIsExpanded(devicePath); if (needRewrite) { QString outPutFix, errorFix; - QString cmdFix = QString("echo w | fdisk %1").arg(devicePath); - Utils::executWithPipeCmd(cmdFix, outPutFix, errorFix); + QStringList args; + args << devicePath; + QString inPut("w\n"); + Utils::executWithInputOutputCmd("fdisk", args, &inPut, outPutFix, errorFix); qDebug() << __FUNCTION__ << "createPartition Partition Table Rewrite Done"; return false; } @@ -3335,8 +3337,10 @@ void PartedCore::reWritePartition(const QString &devicePath) bool needRewrite = gptIsExpanded(devicePath); if (needRewrite) { QString outPutFix, errorFix; - QString cmdFix = QString("echo w | fdisk %1").arg(devicePath); - Utils::executWithPipeCmd(cmdFix, outPutFix, errorFix); + QStringList args; + args << devicePath; + QString inPut("w\n"); + Utils::executWithInputOutputCmd("fdisk", args, &inPut, outPutFix, errorFix); qDebug() << __FUNCTION__ << "createPartition Partition Table Rewrite Done"; return; } diff --git a/service/watcher.cpp b/service/watcher.cpp index d66519aa..969decb5 100644 --- a/service/watcher.cpp +++ b/service/watcher.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2022 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-only @@ -11,24 +11,36 @@ #include #include #include +#include #include namespace DiskManager { /** - * @brief 执行外部命令 - * @param strCmd:外部命令字符串 - * @param outPut:命令控制台输出 - * @param error:错误信息 - * @return exitcode:退出码 + * @brief 检测前端进程 deepin-diskmanager 是否在运行 + * + * 仅启动 ps 一个子进程并在代码内完成过滤,避免使用 shell 解释器,也不再串联 awk/grep 子进程。 + * 等价于管道 `ps -eo cmd | grep -w deepin-diskmanager$`。 + * */ -void Watcher::executCmd(const QString &strCmd, QString &outPut, QString &error) +bool Watcher::isFrontEndRunning(QString &error) { QProcess proc; - proc.start("bash", QStringList() << "-c" << strCmd); + proc.start("ps", QStringList() << "-eo" << "cmd"); proc.waitForFinished(-1); - outPut = proc.readAllStandardOutput(); + error = proc.readAllStandardError(); + + static const QRegularExpression rxMatch("(?:^|[^\\w])deepin-diskmanager$"); + const QStringList lines = QString::fromLocal8Bit(proc.readAllStandardOutput()).split('\n'); + for (const QString &line : lines) { + const QString exe = line.trimmed().section(' ', 0, 0, QString::SectionSkipEmpty); + if (rxMatch.match(exe).hasMatch()) { + return true; + } + } + + return false; } void Watcher::exit() @@ -41,18 +53,12 @@ void Watcher::exit() void Watcher::run() { bool isrun = false; - QString cmd, outPut, error; - //先判断后台服务进程是否存在,如果存在可能是强制退出导致,应先退出后台程序再重新启动磁盘管理器 - cmd = QString("ps -eo pid,cmd |awk '{print $2}' |grep -w deepin-diskmanager$"); + QString error; while (!stoped) { QThread::msleep(500); //0.5 second - executCmd(cmd, outPut, error); - int ret = 0; - ret = outPut.length(); - if (ret) { + if (isFrontEndRunning(error)) { //这里表示前端在运行当中 - // qDebug() << "Set to true!!!!!"; isrun = true; } else { //这里表示,前端启动过,但是现在已经关闭了 @@ -61,7 +67,6 @@ void Watcher::run() _exit(0); } } - // qDebug() << "Sleep !!! == " << ret << " " << outPut << " " << outPut.length() << " "<< error; } } diff --git a/service/watcher.h b/service/watcher.h index ca9bbd2c..26c65bcb 100644 --- a/service/watcher.h +++ b/service/watcher.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2022 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-only @@ -24,7 +24,7 @@ class Watcher :public QThread */ void run(); - void executCmd(const QString &strCmd, QString &outPut, QString &error); + bool isFrontEndRunning(QString &error); public Q_SLOTS: void exit();