summaryrefslogtreecommitdiffstats
path: root/src/corelib
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib')
-rw-r--r--src/corelib/io/qstandardpaths_unix.cpp162
1 files changed, 120 insertions, 42 deletions
diff --git a/src/corelib/io/qstandardpaths_unix.cpp b/src/corelib/io/qstandardpaths_unix.cpp
index 748ce67dac..d71a28432d 100644
--- a/src/corelib/io/qstandardpaths_unix.cpp
+++ b/src/corelib/io/qstandardpaths_unix.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2020 The Qt Company Ltd.
+** Copyright (C) 2020 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -71,6 +72,111 @@ static void appendOrganizationAndApp(QString &path)
#endif
}
+static bool checkXdgRuntimeDir(const QString &xdgRuntimeDir)
+{
+ auto describeMetaData = [](const QFileSystemMetaData &metaData) -> QByteArray {
+ if (!metaData.exists())
+ return "a broken symlink";
+
+ QByteArray description;
+ if (metaData.isLink())
+ description = "a symbolic link to ";
+
+ if (metaData.isFile())
+ description += "a regular file";
+ else if (metaData.isDirectory())
+ description += "a directory";
+ else if (metaData.isSequential())
+ description += "a character device, socket or FIFO";
+ else
+ description += "a block device";
+
+ // convert QFileSystemMetaData permissions back to Unix
+ mode_t perms = 0;
+ if (metaData.permissions() & QFile::ReadOwner)
+ perms |= S_IRUSR;
+ if (metaData.permissions() & QFile::WriteOwner)
+ perms |= S_IWUSR;
+ if (metaData.permissions() & QFile::ExeOwner)
+ perms |= S_IXUSR;
+ if (metaData.permissions() & QFile::ReadGroup)
+ perms |= S_IRGRP;
+ if (metaData.permissions() & QFile::WriteGroup)
+ perms |= S_IWGRP;
+ if (metaData.permissions() & QFile::ExeGroup)
+ perms |= S_IXGRP;
+ if (metaData.permissions() & QFile::ReadOther)
+ perms |= S_IROTH;
+ if (metaData.permissions() & QFile::WriteOther)
+ perms |= S_IWOTH;
+ if (metaData.permissions() & QFile::ExeOther)
+ perms |= S_IXOTH;
+ description += " permissions 0" + QByteArray::number(perms, 8);
+
+ return description
+ + " owned by UID " + QByteArray::number(metaData.userId())
+ + " GID " + QByteArray::number(metaData.groupId());
+ };
+
+ // http://standards.freedesktop.org/basedir-spec/latest/
+ const uint myUid = uint(geteuid());
+ const QFile::Permissions wantedPerms = QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner;
+ const QFileSystemMetaData::MetaDataFlags statFlags = QFileSystemMetaData::PosixStatFlags
+ | QFileSystemMetaData::LinkType;
+ QFileSystemMetaData metaData;
+ QFileSystemEntry entry(xdgRuntimeDir);
+
+ // Check that the xdgRuntimeDir is a directory by attempting to create it.
+ // A stat() before mkdir() that concluded it doesn't exist is a meaningless
+ // result: we'd race against someone else attempting to create it.
+ // ### QFileSystemEngine::createDirectory cannot take the extra mode argument.
+ if (QT_MKDIR(entry.nativeFilePath(), 0700) == 0)
+ return true;
+ if (errno != EEXIST) {
+ qErrnoWarning("QStandardPaths: error creating runtime directory '%ls'",
+ qUtf16Printable(xdgRuntimeDir));
+ return false;
+ }
+
+ // We use LinkType to force an lstat(), but fillMetaData() still returns error
+ // on broken symlinks.
+ if (!QFileSystemEngine::fillMetaData(entry, metaData, statFlags) && !metaData.isLink()) {
+ qErrnoWarning("QStandardPaths: error obtaining permissions of runtime directory '%ls'",
+ qUtf16Printable(xdgRuntimeDir));
+ return false;
+ }
+
+ // Checks:
+ // - is a directory
+ // - is not a symlink (even is pointing to a directory)
+ if (metaData.isLink() || !metaData.isDirectory()) {
+ qWarning("QStandardPaths: runtime directory '%ls' is not a directory, but %s",
+ qUtf16Printable(xdgRuntimeDir), describeMetaData(metaData).constData());
+ return false;
+ }
+
+ // - "The directory MUST be owned by the user"
+ if (metaData.userId() != myUid) {
+ qWarning("QStandardPaths: runtime directory '%ls' is not owned by UID %d, but %s",
+ qUtf16Printable(xdgRuntimeDir), myUid, describeMetaData(metaData).constData());
+ return false;
+ }
+
+ // "and he MUST be the only one having read and write access to it. Its Unix access mode MUST be 0700."
+ if (metaData.permissions() != wantedPerms) {
+ // attempt to correct:
+ QSystemError error;
+ if (!QFileSystemEngine::setPermissions(entry, wantedPerms, error)) {
+ qErrnoWarning("QStandardPaths: could not set correct permissions on runtime directory "
+ "'%ls', which is %s", qUtf16Printable(xdgRuntimeDir),
+ describeMetaData(metaData).constData());
+ return false;
+ }
+ }
+
+ return true;
+}
+
QString QStandardPaths::writableLocation(StandardLocation type)
{
switch (type) {
@@ -120,52 +226,24 @@ QString QStandardPaths::writableLocation(StandardLocation type)
}
case RuntimeLocation:
{
- const uint myUid = uint(geteuid());
- // http://standards.freedesktop.org/basedir-spec/latest/
- QFileInfo fileInfo;
QString xdgRuntimeDir = QFile::decodeName(qgetenv("XDG_RUNTIME_DIR"));
- if (xdgRuntimeDir.isEmpty()) {
+ bool fromEnv = !xdgRuntimeDir.isEmpty();
+ if (xdgRuntimeDir.isEmpty() || !checkXdgRuntimeDir(xdgRuntimeDir)) {
+ // environment variable not set or is set to something unsuitable
+ const uint myUid = uint(geteuid());
const QString userName = QFileSystemEngine::resolveUserName(myUid);
xdgRuntimeDir = QDir::tempPath() + QLatin1String("/runtime-") + userName;
- fileInfo.setFile(xdgRuntimeDir);
- if (!fileInfo.isDir()) {
- if (!QDir().mkdir(xdgRuntimeDir)) {
- qWarning("QStandardPaths: error creating runtime directory %s: %s", qPrintable(xdgRuntimeDir), qPrintable(qt_error_string(errno)));
- return QString();
- }
- }
- qWarning("QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '%s'", qPrintable(xdgRuntimeDir));
- } else {
- fileInfo.setFile(xdgRuntimeDir);
- if (!fileInfo.exists()) {
- qWarning("QStandardPaths: XDG_RUNTIME_DIR points to non-existing path '%s', "
- "please create it with 0700 permissions.", qPrintable(xdgRuntimeDir));
- return QString();
- }
- if (!fileInfo.isDir()) {
- qWarning("QStandardPaths: XDG_RUNTIME_DIR points to '%s' which is not a directory",
- qPrintable(xdgRuntimeDir));
- return QString();
- }
- }
- // "The directory MUST be owned by the user"
- if (fileInfo.ownerId() != myUid) {
- qWarning("QStandardPaths: wrong ownership on runtime directory %s, %d instead of %d", qPrintable(xdgRuntimeDir),
- fileInfo.ownerId(), myUid);
- return QString();
- }
- // "and he MUST be the only one having read and write access to it. Its Unix access mode MUST be 0700."
- // since the current user is the owner, set both xxxUser and xxxOwner
- const QFile::Permissions wantedPerms = QFile::ReadUser | QFile::WriteUser | QFile::ExeUser
- | QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner;
- if (fileInfo.permissions() != wantedPerms) {
- QFile file(xdgRuntimeDir);
- if (!file.setPermissions(wantedPerms)) {
- qWarning("QStandardPaths: could not set correct permissions on runtime directory %s: %s",
- qPrintable(xdgRuntimeDir), qPrintable(file.errorString()));
- return QString();
+
+ if (!fromEnv) {
+#ifndef Q_OS_WASM
+ qWarning("QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '%ls'", qUtf16Printable(xdgRuntimeDir));
+#endif
}
+
+ if (!checkXdgRuntimeDir(xdgRuntimeDir))
+ xdgRuntimeDir.clear();
}
+
return xdgRuntimeDir;
}
default: