From f1a47b8fdfdf23ec4112b45b3e0eb210530a7db4 Mon Sep 17 00:00:00 2001 From: zhanghongyuan Date: Mon, 26 Oct 2026 23:32:57 +0800 Subject: [PATCH] fix: fix data loss and path bugs in drivercontrol module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Root cause: deleteLineOfFileWithItem never called QFile::open() before seek/read/write, but resize(0) still truncated the real file, wiping entire config files (data loss) 2. Fix: add open(QIODevice::ReadWrite | QIODevice::Text) guard before file operations; add seek(0) after resize(0) to reset cursor to start (resize does not move the file cursor); add stream.flush() before close() to ensure data is written to disk 3. Root cause: setModLoadedOnBoot used QFileInfo(dir).dir() which returns the parent directory, producing out-of-bounds paths that always fail the path guard, making boot-on-load feature unusable 4. Fix: use QDir(LOADONBOOT_PROBE_DIR).absoluteFilePath() for correct path construction 5. Root cause: rmFromBlackList libdir loop copy-pasted etcdir, so /usr/lib/modprobe.d files were never processed 6. Fix: change etcdir to libdir in the libdir traversal loop 7. Root cause: isPathWithinDirectory used canonicalFilePath() which returns empty for non-existent files, rejecting legitimate new config file paths created by addModBlackList/setModLoadedOnBoot 8. Fix: fall back to QDir::cleanPath(absoluteFilePath) when canonical path is empty, preserving path traversal protection Log: fix driver control config file data loss and boot-on-load failure Influence: 1. Test blacklist removal preserves non-matching lines in config files 2. Test setModLoadedOnBoot creates config in /etc/modules-load.d correctly 3. Test rmFromBlackList processes /usr/lib/modprobe.d directory files 4. Test addModBlackList accepts legitimate new file paths 5. Verify no path traversal regression in isPathWithinDirectory fix: 修复驱动管理模块配置文件数据丢失及路径错误 1. 根因:deleteLineOfFileWithItem 未调用 QFile::open() 即执行 seek/read/write,但 resize(0) 仍截断实际文件,导致整个配置 文件被清空(数据丢失) 2. 方案:在文件操作前增加 open(QIODevice::ReadWrite | QIODevice::Text) 保护;在 resize(0) 后增加 seek(0) 将游标重置到起始位置(resize 不移动文件游标);在 close() 前增加 stream.flush() 确保数据落盘 3. 根因:setModLoadedOnBoot 使用 QFileInfo(dir).dir() 返回父目录, 拼出越界路径导致边界检查恒失败,开机自启动功能不可用 4. 方案:改用 QDir(LOADONBOOT_PROBE_DIR).absoluteFilePath() 正确 构建路径 5. 根因:rmFromBlackList 的 libdir 循环复制粘贴误用 etcdir, /usr/lib/modprobe.d 下文件从未被处理 6. 方案:将 libdir 循环中的 etcdir 改为 libdir 7. 根因:isPathWithinDirectory 使用 canonicalFilePath() 对不存在 文件返回空串,拒绝 addModBlackList/setModLoadedOnBoot 创建的 合法新文件路径 8. 方案:canonical 路径为空时回退 QDir::cleanPath(absoluteFilePath), 保留路径穿越防护 Log: 修复驱动管理配置文件数据丢失及开机自启动失效 Influence: 1. 测试黑名单移除后配置文件正确保留非匹配行 2. 测试 setModLoadedOnBoot 正确在 /etc/modules-load.d 创建配置 3. 测试 rmFromBlackList 正确处理 /usr/lib/modprobe.d 目录文件 4. 测试 addModBlackList 接受合法新文件路径 5. 验证 isPathWithinDirectory 无路径穿越回归 --- .../deepin-devicecontrol/src/drivercontrol/modcore.cpp | 9 +++++++-- .../deepin-devicecontrol/src/securityutils.cpp | 2 ++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/deepin-devicemanager-server/deepin-devicecontrol/src/drivercontrol/modcore.cpp b/deepin-devicemanager-server/deepin-devicecontrol/src/drivercontrol/modcore.cpp index f482d5dfd..4b3fab125 100644 --- a/deepin-devicemanager-server/deepin-devicecontrol/src/drivercontrol/modcore.cpp +++ b/deepin-devicemanager-server/deepin-devicecontrol/src/drivercontrol/modcore.cpp @@ -464,6 +464,9 @@ void ModCore::deleteLineOfFileWithItem(const QString &filepath, const QString &i { QFile tmpfile(filepath); + if (!tmpfile.open(QIODevice::ReadWrite | QIODevice::Text)) + return; + //设置文件游标到起始位置 tmpfile.seek(0); QTextStream stream(&tmpfile); @@ -487,7 +490,9 @@ void ModCore::deleteLineOfFileWithItem(const QString &filepath, const QString &i #endif //清除原有内容 tmpfile.resize(0); + tmpfile.seek(0); stream << newcontent; + stream.flush(); tmpfile.close(); } @@ -688,7 +693,7 @@ void ModCore::rmFromBlackList(const QString &modName) } //遍历处理/usr/lib/modprobe.d目录下文件 foreach (QString strfile, libfiles) { - rmModFromBlackListFile(etcdir.absoluteFilePath(strfile), modName); + rmModFromBlackListFile(libdir.absoluteFilePath(strfile), modName); } } @@ -708,7 +713,7 @@ bool ModCore::setModLoadedOnBoot(const QString &modName) QFileInfo fileinfo(LOADONBOOT_PROBE_DIR); QString strfilename = QString(LOADONBOOT_FILENAME_TEMPLETE).arg(modName); - QString filepath = fileinfo.dir().absoluteFilePath(strfilename); + QString filepath = QDir(LOADONBOOT_PROBE_DIR).absoluteFilePath(strfilename); // 路径边界检查:确保最终路径在预期目录内 if (!isPathWithinDirectory(filepath, LOADONBOOT_PROBE_DIR)) { diff --git a/deepin-devicemanager-server/deepin-devicecontrol/src/securityutils.cpp b/deepin-devicemanager-server/deepin-devicecontrol/src/securityutils.cpp index bf39fd964..5658ea15f 100644 --- a/deepin-devicemanager-server/deepin-devicecontrol/src/securityutils.cpp +++ b/deepin-devicemanager-server/deepin-devicecontrol/src/securityutils.cpp @@ -30,6 +30,8 @@ bool isPathWithinDirectory(const QString &filePath, const QString &baseDir) QFileInfo fileInfo(filePath); QString canonicalPath = fileInfo.canonicalFilePath(); + if (canonicalPath.isEmpty()) + canonicalPath = QDir::cleanPath(fileInfo.absoluteFilePath()); if (canonicalPath.isEmpty()) return false;