From de24134aa7795a05ba271a751bf76792f9a3ff98 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 20 Sep 2023 19:38:25 -0700 Subject: [PATCH] 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 --- src/corelib/io/qfilesystemengine_unix.cpp | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/corelib/io/qfilesystemengine_unix.cpp b/src/corelib/io/qfilesystemengine_unix.cpp index 950939597a9..582d48ef8d9 100644 --- a/src/corelib/io/qfilesystemengine_unix.cpp +++ b/src/corelib/io/qfilesystemengine_unix.cpp @@ -1338,14 +1338,9 @@ bool QFileSystemEngine::moveFileToTrash(const QFileSystemEntry &source, */ QString uniqueTrashedName = u'/' + sourcePath.fileName(); QString infoFileName; - int counter = 0; QFile infoFile; - auto makeUniqueTrashedName = [sourcePath, &counter]() -> QString { - return QString::asprintf("/%ls-%04d", qUtf16Printable(sourcePath.fileName()), ++counter); - }; - do { - while (QFile::exists(trashDir.filePath(filesDir) + uniqueTrashedName)) - uniqueTrashedName = makeUniqueTrashedName(); + auto openMode = QIODevice::NewOnly | QIODevice::WriteOnly | QIODevice::Text; + for (int counter = 0; !infoFile.open(openMode); ++counter) { /* "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 @@ -1358,12 +1353,12 @@ bool QFileSystemEngine::moveFileToTrash(const QFileSystemEntry &source, 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." */ - infoFileName = trashDir.filePath(infoDir) + uniqueTrashedName = QString::asprintf("/%ls-%04d", qUtf16Printable(sourcePath.fileName()), + counter); + QString infoFileName = trashDir.filePath(infoDir) + uniqueTrashedName + ".trashinfo"_L1; infoFile.setFileName(infoFileName); - if (!infoFile.open(QIODevice::NewOnly | QIODevice::WriteOnly | QIODevice::Text)) - uniqueTrashedName = makeUniqueTrashedName(); - } while (!infoFile.isOpen()); + } QString pathForInfo = sourcePath.filePath(); const QStorageInfo storageInfo(pathForInfo);