moveToTrash/Unix: avoid TOCTOU in creating the unique file name

This is not a security issue because we still use QIODevice::NewOnly
(O_EXCL) and loop again. But because we do so, we don't need to check
for existence with QFile::exists() in the first place.

Pick-to: 6.6
Change-Id: I9d43e5b91eb142d6945cfffd1786c98a39781517
Reviewed-by: Ahmad Samir <a.samirh78@gmail.com>
This commit is contained in:
Thiago Macieira 2023-09-20 19:38:25 -07:00
parent 1c5575f194
commit de24134aa7

View File

@ -1338,14 +1338,9 @@ bool QFileSystemEngine::moveFileToTrash(const QFileSystemEntry &source,
*/ */
QString uniqueTrashedName = u'/' + sourcePath.fileName(); QString uniqueTrashedName = u'/' + sourcePath.fileName();
QString infoFileName; QString infoFileName;
int counter = 0;
QFile infoFile; QFile infoFile;
auto makeUniqueTrashedName = [sourcePath, &counter]() -> QString { auto openMode = QIODevice::NewOnly | QIODevice::WriteOnly | QIODevice::Text;
return QString::asprintf("/%ls-%04d", qUtf16Printable(sourcePath.fileName()), ++counter); for (int counter = 0; !infoFile.open(openMode); ++counter) {
};
do {
while (QFile::exists(trashDir.filePath(filesDir) + uniqueTrashedName))
uniqueTrashedName = makeUniqueTrashedName();
/* /*
"The $trash/info directory contains an "information file" for every file and directory "The $trash/info directory contains an "information file" for every file and directory
in $trash/files. This file MUST have exactly the same name as the file or directory in in $trash/files. This file MUST have exactly the same name as the file or directory in
@ -1358,12 +1353,12 @@ bool QFileSystemEngine::moveFileToTrash(const QFileSystemEntry &source,
filename, and then opening with O_EXCL. If that succeeds the creation was atomic filename, and then opening with O_EXCL. If that succeeds the creation was atomic
(at least on the same machine), if it fails you need to pick another filename." (at least on the same machine), if it fails you need to pick another filename."
*/ */
infoFileName = trashDir.filePath(infoDir) uniqueTrashedName = QString::asprintf("/%ls-%04d", qUtf16Printable(sourcePath.fileName()),
counter);
QString infoFileName = trashDir.filePath(infoDir)
+ uniqueTrashedName + ".trashinfo"_L1; + uniqueTrashedName + ".trashinfo"_L1;
infoFile.setFileName(infoFileName); infoFile.setFileName(infoFileName);
if (!infoFile.open(QIODevice::NewOnly | QIODevice::WriteOnly | QIODevice::Text)) }
uniqueTrashedName = makeUniqueTrashedName();
} while (!infoFile.isOpen());
QString pathForInfo = sourcePath.filePath(); QString pathForInfo = sourcePath.filePath();
const QStorageInfo storageInfo(pathForInfo); const QStorageInfo storageInfo(pathForInfo);