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 <volker.hilsheimer@qt.io>
bb10
Fredrik Orderud 2020-04-13 15:50:32 +02:00 committed by Volker Hilsheimer
parent c7e8ee4e62
commit 1bee5937bc
1 changed files with 55 additions and 2 deletions

View File

@ -50,6 +50,7 @@
#include <qt_windows.h>
#include <shlobj.h>
#include <intshcut.h>
#include <qvarlengtharray.h>
#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<char,256> token_info_buf(256);
auto* token_info = reinterpret_cast<TOKEN_MANDATORY_LABEL*>(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_MANDATORY_LABEL*>(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().