Merge pull request #8915 from OatmealDome/updater-temp-dir

macOS: Untranslocate the app bundle's path for the updater
This commit is contained in:
Léo Lam 2021-07-06 02:22:28 +02:00 committed by GitHub
commit 27c560fdfa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 63 additions and 42 deletions

View File

@ -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

View File

@ -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();

View File

@ -37,8 +37,6 @@ const std::array<u8, 32> 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<std::string> 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<std::string> args)
TodoList todo = ComputeActionsToDo(this_manifest, next_manifest);
todo.Log();
std::optional<std::string> 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...");