From 0dee566e98f5ff4f224e596de1c04de4f9685df4 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 29 Jun 2017 11:16:04 -0700 Subject: QFileSystemEngine: verify that the file name isn't empty Making system calls with empty file names is not a good idea. When you run qmake $srcdir, you see this in strace: stat("", 0x7ffed229e250) = -1 ENOENT (No such file or directory) (twice) I've also inlined the isEmpty() function for better code generation. Some functions take QSystemError and some don't. That needs to be corrected at some point, possibly with something like std::expected. Change-Id: I1eba2b016de74620bfc8fffd14ccbfa162f93631 Reviewed-by: Simon Hausmann --- src/corelib/io/qfilesystemengine_unix.cpp | 39 +++++++++++++++++++++++++++++-- src/corelib/io/qfilesystementry.cpp | 5 ---- src/corelib/io/qfilesystementry_p.h | 5 +++- 3 files changed, 41 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/corelib/io/qfilesystemengine_unix.cpp b/src/corelib/io/qfilesystemengine_unix.cpp index 3bb20a2e00..d74c126bef 100644 --- a/src/corelib/io/qfilesystemengine_unix.cpp +++ b/src/corelib/io/qfilesystemengine_unix.cpp @@ -95,6 +95,13 @@ static int statx(int dirfd, const char *pathname, int flag, unsigned mask, struc QT_BEGIN_NAMESPACE +#define emptyFileEntryWarning() emptyFileEntryWarning_(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC) +static void emptyFileEntryWarning_(const char *file, int line, const char *function) +{ + QMessageLogger(file, line, function).warning("Empty filename passed to function"); + errno = EINVAL; +} + #if defined(Q_OS_DARWIN) static inline bool hasResourcePropertyFlag(const QFileSystemMetaData &data, const QFileSystemEntry &entry, @@ -602,6 +609,9 @@ void QFileSystemMetaData::fillFromDirEnt(const QT_DIRENT &entry) //static QFileSystemEntry QFileSystemEngine::getLinkTarget(const QFileSystemEntry &link, QFileSystemMetaData &data) { + if (Q_UNLIKELY(link.isEmpty())) + return emptyFileEntryWarning(), link; + QByteArray s = qt_readlink(link.nativeFilePath().constData()); if (s.length() > 0) { QString ret; @@ -666,7 +676,9 @@ QFileSystemEntry QFileSystemEngine::getLinkTarget(const QFileSystemEntry &link, //static QFileSystemEntry QFileSystemEngine::canonicalName(const QFileSystemEntry &entry, QFileSystemMetaData &data) { - if (entry.isEmpty() || entry.isRoot()) + if (Q_UNLIKELY(entry.isEmpty())) + return emptyFileEntryWarning(), entry; + if (entry.isRoot()) return entry; #if !defined(Q_OS_MAC) && !defined(Q_OS_QNX) && !defined(Q_OS_ANDROID) && !defined(Q_OS_HAIKU) && _POSIX_VERSION < 200809L @@ -733,6 +745,8 @@ QFileSystemEntry QFileSystemEngine::canonicalName(const QFileSystemEntry &entry, //static QFileSystemEntry QFileSystemEngine::absoluteName(const QFileSystemEntry &entry) { + if (Q_UNLIKELY(entry.isEmpty())) + return emptyFileEntryWarning(), entry; if (entry.isAbsolute() && entry.isClean()) return entry; @@ -766,6 +780,9 @@ QFileSystemEntry QFileSystemEngine::absoluteName(const QFileSystemEntry &entry) //static QByteArray QFileSystemEngine::id(const QFileSystemEntry &entry) { + if (Q_UNLIKELY(entry.isEmpty())) + return emptyFileEntryWarning(), QByteArray(); + QT_STATBUF statResult; if (QT_STAT(entry.nativeFilePath().constData(), &statResult)) { if (errno != ENOENT) @@ -873,6 +890,9 @@ QString QFileSystemEngine::bundleName(const QFileSystemEntry &entry) bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemMetaData &data, QFileSystemMetaData::MetaDataFlags what) { + if (Q_UNLIKELY(entry.isEmpty())) + return emptyFileEntryWarning(), false; + #if defined(Q_OS_DARWIN) if (what & QFileSystemMetaData::BundleType) { if (!data.hasFlags(QFileSystemMetaData::DirectoryType)) @@ -1083,6 +1103,8 @@ static bool createDirectoryWithParents(const QByteArray &nativeName, bool should bool QFileSystemEngine::createDirectory(const QFileSystemEntry &entry, bool createParents) { QString dirName = entry.filePath(); + if (Q_UNLIKELY(dirName.isEmpty())) + return emptyFileEntryWarning(), false; // Darwin doesn't support trailing /'s, so remove for everyone while (dirName.size() > 1 && dirName.endsWith(QLatin1Char('/'))) @@ -1101,6 +1123,9 @@ bool QFileSystemEngine::createDirectory(const QFileSystemEntry &entry, bool crea //static bool QFileSystemEngine::removeDirectory(const QFileSystemEntry &entry, bool removeEmptyParents) { + if (Q_UNLIKELY(entry.isEmpty())) + return emptyFileEntryWarning(), false; + if (removeEmptyParents) { QString dirName = QDir::cleanPath(entry.filePath()); for (int oldslash = 0, slash=dirName.length(); slash > 0; oldslash = slash) { @@ -1124,6 +1149,8 @@ bool QFileSystemEngine::removeDirectory(const QFileSystemEntry &entry, bool remo //static bool QFileSystemEngine::createLink(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error) { + if (Q_UNLIKELY(source.isEmpty() || target.isEmpty())) + return emptyFileEntryWarning(), false; if (::symlink(source.nativeFilePath().constData(), target.nativeFilePath().constData()) == 0) return true; error = QSystemError(errno, QSystemError::StandardLibraryError); @@ -1158,6 +1185,8 @@ bool QFileSystemEngine::renameFile(const QFileSystemEntry &source, const QFileSy { QFileSystemEntry::NativePath srcPath = source.nativeFilePath(); QFileSystemEntry::NativePath tgtPath = target.nativeFilePath(); + if (Q_UNLIKELY(srcPath.isEmpty() || tgtPath.isEmpty())) + return emptyFileEntryWarning(), false; #if defined(RENAME_NOREPLACE) && (QT_CONFIG(renameat2) || defined(SYS_renameat2)) if (renameat2(AT_FDCWD, srcPath, AT_FDCWD, tgtPath, RENAME_NOREPLACE) == 0) @@ -1227,6 +1256,8 @@ bool QFileSystemEngine::renameFile(const QFileSystemEntry &source, const QFileSy //static bool QFileSystemEngine::renameOverwriteFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error) { + if (Q_UNLIKELY(source.isEmpty() || target.isEmpty())) + return emptyFileEntryWarning(), false; if (::rename(source.nativeFilePath().constData(), target.nativeFilePath().constData()) == 0) return true; error = QSystemError(errno, QSystemError::StandardLibraryError); @@ -1236,6 +1267,8 @@ bool QFileSystemEngine::renameOverwriteFile(const QFileSystemEntry &source, cons //static bool QFileSystemEngine::removeFile(const QFileSystemEntry &entry, QSystemError &error) { + if (Q_UNLIKELY(entry.isEmpty())) + return emptyFileEntryWarning(), false; if (unlink(entry.nativeFilePath().constData()) == 0) return true; error = QSystemError(errno, QSystemError::StandardLibraryError); @@ -1270,8 +1303,10 @@ static mode_t toMode_t(QFile::Permissions permissions) //static bool QFileSystemEngine::setPermissions(const QFileSystemEntry &entry, QFile::Permissions permissions, QSystemError &error, QFileSystemMetaData *data) { - mode_t mode = toMode_t(permissions); + if (Q_UNLIKELY(entry.isEmpty())) + return emptyFileEntryWarning(), false; + mode_t mode = toMode_t(permissions); bool success = ::chmod(entry.nativeFilePath().constData(), mode) == 0; if (success && data) { data->entryFlags &= ~QFileSystemMetaData::Permissions; diff --git a/src/corelib/io/qfilesystementry.cpp b/src/corelib/io/qfilesystementry.cpp index cbff17d0f1..3ff90bd0a3 100644 --- a/src/corelib/io/qfilesystementry.cpp +++ b/src/corelib/io/qfilesystementry.cpp @@ -331,11 +331,6 @@ bool QFileSystemEntry::isRoot() const return isRootPath(m_filePath); } -bool QFileSystemEntry::isEmpty() const -{ - return m_filePath.isEmpty() && m_nativeFilePath.isEmpty(); -} - // private methods void QFileSystemEntry::findLastSeparator() const diff --git a/src/corelib/io/qfilesystementry_p.h b/src/corelib/io/qfilesystementry_p.h index 700696d09e..251eca553a 100644 --- a/src/corelib/io/qfilesystementry_p.h +++ b/src/corelib/io/qfilesystementry_p.h @@ -98,7 +98,10 @@ public: #endif bool isRoot() const; - bool isEmpty() const; + bool isEmpty() const + { + return m_filePath.isEmpty() && m_nativeFilePath.isEmpty(); + } void clear() { *this = QFileSystemEntry(); -- cgit v1.2.3