From 1bee5937bc51af45776c4ad9083f4a67afbaf109 Mon Sep 17 00:00:00 2001 From: Fredrik Orderud Date: Mon, 13 Apr 2020 15:50:32 +0200 Subject: Windows: Make QStandardPaths::writableLocation low-integrity aware Return %USERPROFILE%\AppData\LocalLow instead of %USERPROFILE%\AppData\Local when running in a low-integrity process. [ChangeLog][QtCore][QStandardPaths] When used in a low-integrity process on Windows, QStandardPaths::writableLocation returns respective low-integrity paths. Fixes: QTBUG-83453 Change-Id: Ie5e4625a34d08e4ef54be4ba45b2dae9e60feb63 Reviewed-by: Volker Hilsheimer --- src/corelib/io/qstandardpaths_win.cpp | 57 +++++++++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 2 deletions(-) (limited to 'src/corelib/io/qstandardpaths_win.cpp') diff --git a/src/corelib/io/qstandardpaths_win.cpp b/src/corelib/io/qstandardpaths_win.cpp index c2c3b2702b..5055f4020c 100644 --- a/src/corelib/io/qstandardpaths_win.cpp +++ b/src/corelib/io/qstandardpaths_win.cpp @@ -50,6 +50,7 @@ #include #include #include +#include #ifndef QT_NO_STANDARDPATHS @@ -92,9 +93,36 @@ static inline void appendTestMode(QString &path) path += QLatin1String("/qttest"); } +static bool isProcessLowIntegrity() { +#ifdef Q_CC_MINGW + // GetCurrentProcessToken was introduced in MinGW w64 in v7 + // Disable function until Qt CI is updated + return false; +#else + HANDLE process_token = GetCurrentProcessToken(); // non-leaking pseudo-handle + + QVarLengthArray token_info_buf(256); + auto* token_info = reinterpret_cast(token_info_buf.data()); + DWORD token_info_length = token_info_buf.size(); + if (!GetTokenInformation(process_token, TokenIntegrityLevel, token_info, token_info_length, &token_info_length)) { + // grow bufer and retry GetTokenInformation + token_info_buf.resize(token_info_length); + token_info = reinterpret_cast(token_info_buf.data()); + if (!GetTokenInformation(process_token, TokenIntegrityLevel, token_info, token_info_length, &token_info_length)) + return false; // assume "normal" process + } + + // The GetSidSubAuthorityCount return-code is undefined on failure, so + // there's no point in checking before dereferencing + DWORD integrity_level = *GetSidSubAuthority(token_info->Label.Sid, *GetSidSubAuthorityCount(token_info->Label.Sid) - 1); + return (integrity_level < SECURITY_MANDATORY_MEDIUM_RID); +#endif +} + // Map QStandardPaths::StandardLocation to KNOWNFOLDERID of SHGetKnownFolderPath() static GUID writableSpecialFolderId(QStandardPaths::StandardLocation type) { + // folders for medium & high integrity processes static const GUID folderIds[] = { FOLDERID_Desktop, // DesktopLocation FOLDERID_Documents, // DocumentsLocation @@ -114,9 +142,34 @@ static GUID writableSpecialFolderId(QStandardPaths::StandardLocation type) FOLDERID_RoamingAppData,// AppDataLocation ("Roaming" path) FOLDERID_LocalAppData, // AppConfigLocation ("Local" path) }; - Q_STATIC_ASSERT(sizeof(folderIds) / sizeof(folderIds[0]) == size_t(QStandardPaths::AppConfigLocation + 1)); - return size_t(type) < sizeof(folderIds) / sizeof(folderIds[0]) ? folderIds[type] : GUID(); + + // folders for low integrity processes + static const GUID folderIds_li[] = { + FOLDERID_Desktop, // DesktopLocation + FOLDERID_Documents, // DocumentsLocation + FOLDERID_Fonts, // FontsLocation + FOLDERID_Programs, // ApplicationsLocation + FOLDERID_Music, // MusicLocation + FOLDERID_Videos, // MoviesLocation + FOLDERID_Pictures, // PicturesLocation + GUID(), GUID(), // TempLocation/HomeLocation + FOLDERID_LocalAppDataLow,// AppLocalDataLocation ("Local" path), AppLocalDataLocation = DataLocation + GUID(), // CacheLocation + FOLDERID_LocalAppDataLow,// GenericDataLocation ("Local" path) + GUID(), // RuntimeLocation + FOLDERID_LocalAppDataLow,// ConfigLocation ("Local" path) + GUID(), GUID(), // DownloadLocation/GenericCacheLocation + FOLDERID_LocalAppDataLow,// GenericConfigLocation ("Local" path) + FOLDERID_RoamingAppData, // AppDataLocation ("Roaming" path) + FOLDERID_LocalAppDataLow,// AppConfigLocation ("Local" path) + }; + Q_STATIC_ASSERT(sizeof(folderIds_li) == sizeof(folderIds)); + + static bool low_integrity_process = isProcessLowIntegrity(); + if (size_t(type) < sizeof(folderIds) / sizeof(folderIds[0])) + return low_integrity_process ? folderIds_li[type] : folderIds[type]; + return GUID(); } // Convenience for SHGetKnownFolderPath(). -- cgit v1.2.3