diff --git a/Source/Core/Common/FileUtil.cpp b/Source/Core/Common/FileUtil.cpp index b7a2ace27e..246452b0bc 100644 --- a/Source/Core/Common/FileUtil.cpp +++ b/Source/Core/Common/FileUtil.cpp @@ -20,6 +20,9 @@ #include "Common/CommonFuncs.h" #include "Common/CommonPaths.h" #include "Common/CommonTypes.h" +#ifdef __APPLE__ +#include "Common/DynamicLibrary.h" +#endif #include "Common/FileUtil.h" #include "Common/IOFile.h" #include "Common/Logging/Log.h" @@ -66,6 +69,18 @@ namespace File static std::string s_android_sys_directory; #endif +#ifdef __APPLE__ +static Common::DynamicLibrary s_security_framework; + +using DolSecTranslocateIsTranslocatedURL = Boolean (*)(CFURLRef path, bool* isTranslocated, + CFErrorRef* __nullable error); +using DolSecTranslocateCreateOriginalPathForURL = CFURLRef +__nullable (*)(CFURLRef translocatedPath, CFErrorRef* __nullable error); + +static DolSecTranslocateIsTranslocatedURL s_is_translocated_url; +static DolSecTranslocateCreateOriginalPathForURL s_create_orig_path; +#endif + #ifdef _WIN32 FileInfo::FileInfo(const std::string& path) { @@ -776,16 +791,49 @@ std::string GetTempFilenameForAtomicWrite(std::string path) #if defined(__APPLE__) std::string GetBundleDirectory() { - CFURLRef BundleRef; - char AppBundlePath[MAXPATHLEN]; - // Get the main bundle for the app - BundleRef = CFBundleCopyBundleURL(CFBundleGetMainBundle()); - CFStringRef BundlePath = CFURLCopyFileSystemPath(BundleRef, kCFURLPOSIXPathStyle); - CFStringGetFileSystemRepresentation(BundlePath, AppBundlePath, sizeof(AppBundlePath)); - CFRelease(BundleRef); - CFRelease(BundlePath); + CFURLRef bundle_ref = CFBundleCopyBundleURL(CFBundleGetMainBundle()); - return AppBundlePath; + // Starting in macOS Sierra, apps downloaded from the Internet may be + // "translocated" to a read-only DMG and executed from there. This is + // done to prevent a scenario where an attacker can replace a trusted + // app's resources to load untrusted code. + // + // We should return Dolphin's actual location on the filesystem in + // this function, so bundle_ref will be untranslocated if necessary. + // + // More information: https://objective-see.com/blog/blog_0x15.html + if (__builtin_available(macOS 10.12, *)) + { + // The APIs to deal with translocated paths are private, so we have + // to dynamically load them from the Security framework. + // + // The headers can be found under "Security" on opensource.apple.com: + // Security/OSX/libsecurity_translocate/lib/SecTranslocate.h + if (!s_security_framework.IsOpen()) + { + s_security_framework.Open("/System/Library/Frameworks/Security.framework/Security"); + s_security_framework.GetSymbol("SecTranslocateIsTranslocatedURL", &s_is_translocated_url); + s_security_framework.GetSymbol("SecTranslocateCreateOriginalPathForURL", &s_create_orig_path); + } + + bool is_translocated = false; + s_is_translocated_url(bundle_ref, &is_translocated, nullptr); + + if (is_translocated) + { + CFURLRef untranslocated_ref = s_create_orig_path(bundle_ref, nullptr); + CFRelease(bundle_ref); + bundle_ref = untranslocated_ref; + } + } + + char app_bundle_path[MAXPATHLEN]; + CFStringRef bundle_path = CFURLCopyFileSystemPath(bundle_ref, kCFURLPOSIXPathStyle); + CFStringGetFileSystemRepresentation(bundle_path, app_bundle_path, sizeof(app_bundle_path)); + CFRelease(bundle_ref); + CFRelease(bundle_path); + + return app_bundle_path; } #endif diff --git a/Source/Core/UICommon/AutoUpdate.cpp b/Source/Core/UICommon/AutoUpdate.cpp index f5898f592b..c3363bcf23 100644 --- a/Source/Core/UICommon/AutoUpdate.cpp +++ b/Source/Core/UICommon/AutoUpdate.cpp @@ -227,7 +227,7 @@ void AutoUpdateChecker::TriggerUpdate(const AutoUpdateChecker::NewVersionInforma updater_flags["parent-pid"] = std::to_string(getpid()); #endif updater_flags["install-base-path"] = File::GetExeDirectory(); - updater_flags["log-file"] = File::GetExeDirectory() + DIR_SEP + UPDATER_LOG_FILE; + updater_flags["log-file"] = File::GetUserPath(D_LOGS_IDX) + UPDATER_LOG_FILE; if (restart_mode == RestartMode::RESTART_AFTER_UPDATE) updater_flags["binary-to-restart"] = File::GetExePath(); diff --git a/Source/Core/UpdaterCommon/UpdaterCommon.cpp b/Source/Core/UpdaterCommon/UpdaterCommon.cpp index f52755aeb5..ebd07e258c 100644 --- a/Source/Core/UpdaterCommon/UpdaterCommon.cpp +++ b/Source/Core/UpdaterCommon/UpdaterCommon.cpp @@ -37,8 +37,6 @@ const std::array UPDATE_PUB_KEY = { 0x2a, 0xb3, 0xd1, 0xdc, 0x6e, 0xf5, 0x07, 0xf6, 0xa0, 0x6c, 0x7c, 0x54, 0xdf, 0x54, 0xf4, 0x42, 0x80, 0xa6, 0x28, 0x8b, 0x6d, 0x70, 0x14, 0xb5, 0x4c, 0x34, 0x95, 0x20, 0x4d, 0xd4, 0xd3, 0x5d}; -const char UPDATE_TEMP_DIR[] = "TempUpdate"; - struct Manifest { using Filename = std::string; @@ -323,33 +321,6 @@ TodoList ComputeActionsToDo(Manifest this_manifest, Manifest next_manifest) return todo; } -std::optional FindOrCreateTempDir(const std::string& base_path) -{ - std::string temp_path = base_path + DIR_SEP + UPDATE_TEMP_DIR; - int counter = 0; - - File::DeleteDirRecursively(temp_path); - - do - { - if (File::CreateDir(temp_path)) - { - return temp_path; - } - else - { - fprintf(log_fp, "Couldn't create temp directory.\n"); - - // Try again with a counter appended to the path. - std::string suffix = UPDATE_TEMP_DIR + std::to_string(counter); - temp_path = base_path + DIR_SEP + suffix; - } - } while (counter++ < 10); - - fprintf(log_fp, "Could not find an appropriate temp directory name. Giving up.\n"); - return {}; -} - void CleanUpTempDir(const std::string& temp_dir, const TodoList& todo) { // This is best-effort cleanup, we ignore most errors. @@ -749,10 +720,12 @@ bool RunUpdater(std::vector args) TodoList todo = ComputeActionsToDo(this_manifest, next_manifest); todo.Log(); - std::optional maybe_temp_dir = FindOrCreateTempDir(opts.install_base_path); - if (!maybe_temp_dir) + std::string temp_dir = File::CreateTempDir(); + if (temp_dir.empty()) + { + FatalError("Could not create temporary directory. Aborting."); return false; - std::string temp_dir = std::move(*maybe_temp_dir); + } UI::SetDescription("Performing Update...");