From bae27340c9f033740bd699aab110f555864352f6 Mon Sep 17 00:00:00 2001 From: bruvzg <7645683+bruvzg@users.noreply.github.com> Date: Tue, 9 Apr 2024 13:19:24 +0300 Subject: [PATCH] [macOS export] Detect embedded helper executables using MachO header. --- platform/macos/export/export_plugin.cpp | 48 ++++++++++++++++--------- platform/macos/export/export_plugin.h | 8 ++--- platform/macos/export/macho.cpp | 20 +++++++++++ platform/macos/export/macho.h | 1 + 4 files changed, 57 insertions(+), 20 deletions(-) diff --git a/platform/macos/export/export_plugin.cpp b/platform/macos/export/export_plugin.cpp index 05ae4a74c9c..9f4dd934887 100644 --- a/platform/macos/export/export_plugin.cpp +++ b/platform/macos/export/export_plugin.cpp @@ -903,7 +903,7 @@ Error EditorExportPlatformMacOS::_notarize(const Ref &p_pres return OK; } -Error EditorExportPlatformMacOS::_code_sign(const Ref &p_preset, const String &p_path, const String &p_ent_path, bool p_warn) { +Error EditorExportPlatformMacOS::_code_sign(const Ref &p_preset, const String &p_path, const String &p_ent_path, bool p_warn, bool p_set_id) { int codesign_tool = p_preset->get("codesign/codesign"); switch (codesign_tool) { case 1: { // built-in ad-hoc @@ -947,6 +947,12 @@ Error EditorExportPlatformMacOS::_code_sign(const Ref &p_pre args.push_back("--code-signature-flags"); args.push_back("runtime"); + if (p_set_id) { + String app_id = p_preset->get("application/bundle_identifier"); + args.push_back("--binary-identifier"); + args.push_back(app_id); + } + args.push_back("-v"); /* provide some more feedback */ args.push_back(p_path); @@ -1006,6 +1012,12 @@ Error EditorExportPlatformMacOS::_code_sign(const Ref &p_pre args.push_back(p_preset->get("codesign/identity")); } + if (p_set_id) { + String app_id = p_preset->get("application/bundle_identifier"); + args.push_back("-i"); + args.push_back(app_id); + } + args.push_back("-v"); /* provide some more feedback */ args.push_back("-f"); @@ -1037,7 +1049,7 @@ Error EditorExportPlatformMacOS::_code_sign(const Ref &p_pre } Error EditorExportPlatformMacOS::_code_sign_directory(const Ref &p_preset, const String &p_path, - const String &p_ent_path, bool p_should_error_on_non_code) { + const String &p_ent_path, const String &p_helper_ent_path, bool p_should_error_on_non_code) { static Vector extensions_to_sign; if (extensions_to_sign.is_empty()) { @@ -1064,7 +1076,8 @@ Error EditorExportPlatformMacOS::_code_sign_directory(const Ref -1) { - Error code_sign_error{ _code_sign(p_preset, current_file_path, p_ent_path, false) }; + int ftype = MachO::get_filetype(current_file_path); + Error code_sign_error{ _code_sign(p_preset, current_file_path, (ftype == 2 || ftype == 5) ? p_helper_ent_path : p_ent_path, false, (ftype == 2 || ftype == 5)) }; if (code_sign_error != OK) { return code_sign_error; } @@ -1073,7 +1086,7 @@ Error EditorExportPlatformMacOS::_code_sign_directory(const Refcurrent_is_dir()) { - Error code_sign_error{ _code_sign_directory(p_preset, current_file_path, p_ent_path, p_should_error_on_non_code) }; + Error code_sign_error{ _code_sign_directory(p_preset, current_file_path, p_ent_path, p_helper_ent_path, p_should_error_on_non_code) }; if (code_sign_error != OK) { return code_sign_error; } @@ -1091,6 +1104,7 @@ Error EditorExportPlatformMacOS::_code_sign_directory(const Ref &dir_access, const String &p_src_path, const String &p_in_app_path, bool p_sign_enabled, const Ref &p_preset, const String &p_ent_path, + const String &p_helper_ent_path, bool p_should_error_on_non_code_sign) { static Vector extensions_to_sign; @@ -1180,10 +1194,11 @@ Error EditorExportPlatformMacOS::_copy_and_sign_files(Ref &dir_access if (err == OK && p_sign_enabled) { if (dir_access->dir_exists(p_src_path) && p_src_path.get_extension().is_empty()) { // If it is a directory, find and sign all dynamic libraries. - err = _code_sign_directory(p_preset, p_in_app_path, p_ent_path, p_should_error_on_non_code_sign); + err = _code_sign_directory(p_preset, p_in_app_path, p_ent_path, p_helper_ent_path, p_should_error_on_non_code_sign); } else { if (extensions_to_sign.find(p_in_app_path.get_extension()) > -1) { - err = _code_sign(p_preset, p_in_app_path, p_ent_path, false); + int ftype = MachO::get_filetype(p_in_app_path); + err = _code_sign(p_preset, p_in_app_path, (ftype == 2 || ftype == 5) ? p_helper_ent_path : p_ent_path, false, (ftype == 2 || ftype == 5)); } if (dir_access->file_exists(p_in_app_path) && is_executable(p_in_app_path)) { // chmod with 0755 if the file is executable. @@ -1197,13 +1212,13 @@ Error EditorExportPlatformMacOS::_copy_and_sign_files(Ref &dir_access Error EditorExportPlatformMacOS::_export_macos_plugins_for(Ref p_editor_export_plugin, const String &p_app_path_name, Ref &dir_access, bool p_sign_enabled, const Ref &p_preset, - const String &p_ent_path) { + const String &p_ent_path, const String &p_helper_ent_path) { Error error{ OK }; const Vector &macos_plugins{ p_editor_export_plugin->get_macos_plugin_files() }; for (int i = 0; i < macos_plugins.size(); ++i) { String src_path{ ProjectSettings::get_singleton()->globalize_path(macos_plugins[i]) }; String path_in_app{ p_app_path_name + "/Contents/PlugIns/" + src_path.get_file() }; - error = _copy_and_sign_files(dir_access, src_path, path_in_app, p_sign_enabled, p_preset, p_ent_path, false); + error = _copy_and_sign_files(dir_access, src_path, path_in_app, p_sign_enabled, p_preset, p_ent_path, p_helper_ent_path, false); if (error != OK) { break; } @@ -1780,8 +1795,9 @@ Error EditorExportPlatformMacOS::export_project(const Ref &p add_message(EXPORT_MESSAGE_ERROR, TTR("Code Signing"), TTR("'rcodesign' doesn't support signing applications with embedded dynamic libraries.")); } + bool sandbox = p_preset->get("codesign/entitlements/app_sandbox/enabled"); String ent_path = p_preset->get("codesign/entitlements/custom_file"); - String hlp_ent_path = EditorPaths::get_singleton()->get_cache_dir().path_join(pkg_name + "_helper.entitlements"); + String hlp_ent_path = sandbox ? EditorPaths::get_singleton()->get_cache_dir().path_join(pkg_name + "_helper.entitlements") : ent_path; if (sign_enabled && (ent_path.is_empty())) { ent_path = EditorPaths::get_singleton()->get_cache_dir().path_join(pkg_name + ".entitlements"); @@ -1933,7 +1949,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref &p err = ERR_CANT_CREATE; } - if ((err == OK) && helpers.size() > 0) { + if ((err == OK) && sandbox && (helpers.size() > 0 || shared_objects.size() > 0)) { ent_f = FileAccess::open(hlp_ent_path, FileAccess::WRITE); if (ent_f.is_valid()) { ent_f->store_line(""); @@ -1959,7 +1975,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref &p String hlp_path = helpers[i]; err = da->copy(hlp_path, tmp_app_path_name + "/Contents/Helpers/" + hlp_path.get_file()); if (err == OK && sign_enabled) { - err = _code_sign(p_preset, tmp_app_path_name + "/Contents/Helpers/" + hlp_path.get_file(), hlp_ent_path, false); + err = _code_sign(p_preset, tmp_app_path_name + "/Contents/Helpers/" + hlp_path.get_file(), hlp_ent_path, false, true); } FileAccess::set_unix_permissions(tmp_app_path_name + "/Contents/Helpers/" + hlp_path.get_file(), 0755); } @@ -1971,11 +1987,11 @@ Error EditorExportPlatformMacOS::export_project(const Ref &p String src_path = ProjectSettings::get_singleton()->globalize_path(shared_objects[i].path); if (shared_objects[i].target.is_empty()) { String path_in_app = tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file(); - err = _copy_and_sign_files(da, src_path, path_in_app, sign_enabled, p_preset, ent_path, true); + err = _copy_and_sign_files(da, src_path, path_in_app, sign_enabled, p_preset, ent_path, hlp_ent_path, true); } else { String path_in_app = tmp_app_path_name.path_join(shared_objects[i].target); tmp_app_dir->make_dir_recursive(path_in_app); - err = _copy_and_sign_files(da, src_path, path_in_app.path_join(src_path.get_file()), sign_enabled, p_preset, ent_path, false); + err = _copy_and_sign_files(da, src_path, path_in_app.path_join(src_path.get_file()), sign_enabled, p_preset, ent_path, hlp_ent_path, false); } if (err != OK) { break; @@ -1984,7 +2000,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref &p Vector> export_plugins{ EditorExport::get_singleton()->get_export_plugins() }; for (int i = 0; i < export_plugins.size(); ++i) { - err = _export_macos_plugins_for(export_plugins[i], tmp_app_path_name, da, sign_enabled, p_preset, ent_path); + err = _export_macos_plugins_for(export_plugins[i], tmp_app_path_name, da, sign_enabled, p_preset, ent_path, hlp_ent_path); if (err != OK) { break; } @@ -2004,7 +2020,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref &p if (ep.step(TTR("Code signing bundle"), 2)) { return ERR_SKIP; } - err = _code_sign(p_preset, tmp_app_path_name, ent_path); + err = _code_sign(p_preset, tmp_app_path_name, ent_path, true, false); } String noto_path = p_path; @@ -2022,7 +2038,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref &p if (ep.step(TTR("Code signing DMG"), 3)) { return ERR_SKIP; } - err = _code_sign(p_preset, p_path, ent_path, false); + err = _code_sign(p_preset, p_path, ent_path, false, false); } } else if (export_format == "pkg") { // Create a Installer. diff --git a/platform/macos/export/export_plugin.h b/platform/macos/export/export_plugin.h index 0764b63e8ce..2d615abedee 100644 --- a/platform/macos/export/export_plugin.h +++ b/platform/macos/export/export_plugin.h @@ -89,14 +89,14 @@ class EditorExportPlatformMacOS : public EditorExportPlatform { void _make_icon(const Ref &p_preset, const Ref &p_icon, Vector &p_data); Error _notarize(const Ref &p_preset, const String &p_path); - Error _code_sign(const Ref &p_preset, const String &p_path, const String &p_ent_path, bool p_warn = true); - Error _code_sign_directory(const Ref &p_preset, const String &p_path, const String &p_ent_path, bool p_should_error_on_non_code = true); + Error _code_sign(const Ref &p_preset, const String &p_path, const String &p_ent_path, bool p_warn = true, bool p_set_id = false); + Error _code_sign_directory(const Ref &p_preset, const String &p_path, const String &p_ent_path, const String &p_helper_ent_path, bool p_should_error_on_non_code = true); Error _copy_and_sign_files(Ref &dir_access, const String &p_src_path, const String &p_in_app_path, - bool p_sign_enabled, const Ref &p_preset, const String &p_ent_path, + bool p_sign_enabled, const Ref &p_preset, const String &p_ent_path, const String &p_helper_ent_path, bool p_should_error_on_non_code_sign); Error _export_macos_plugins_for(Ref p_editor_export_plugin, const String &p_app_path_name, Ref &dir_access, bool p_sign_enabled, const Ref &p_preset, - const String &p_ent_path); + const String &p_ent_path, const String &p_helper_ent_path); Error _create_dmg(const String &p_dmg_path, const String &p_pkg_name, const String &p_app_path_name); Error _create_pkg(const Ref &p_preset, const String &p_pkg_path, const String &p_app_path_name); Error _export_debug_script(const Ref &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path); diff --git a/platform/macos/export/macho.cpp b/platform/macos/export/macho.cpp index c7556c1964e..a829774a88e 100644 --- a/platform/macos/export/macho.cpp +++ b/platform/macos/export/macho.cpp @@ -105,6 +105,26 @@ bool MachO::is_macho(const String &p_path) { return (magic == 0xcefaedfe || magic == 0xfeedface || magic == 0xcffaedfe || magic == 0xfeedfacf); } +uint32_t MachO::get_filetype(const String &p_path) { + Ref fa = FileAccess::open(p_path, FileAccess::READ); + ERR_FAIL_COND_V_MSG(fa.is_null(), 0, vformat("MachO: Can't open file: \"%s\".", p_path)); + uint32_t magic = fa->get_32(); + MachHeader mach_header; + + // Read MachO header. + if (magic == 0xcefaedfe || magic == 0xfeedface) { + // Thin 32-bit binary. + fa->get_buffer((uint8_t *)&mach_header, sizeof(MachHeader)); + } else if (magic == 0xcffaedfe || magic == 0xfeedfacf) { + // Thin 64-bit binary. + fa->get_buffer((uint8_t *)&mach_header, sizeof(MachHeader)); + fa->get_32(); // Skip extra reserved field. + } else { + ERR_FAIL_V_MSG(0, vformat("MachO: File is not a valid MachO binary: \"%s\".", p_path)); + } + return mach_header.filetype; +} + bool MachO::open_file(const String &p_path) { fa = FileAccess::open(p_path, FileAccess::READ_WRITE); ERR_FAIL_COND_V_MSG(fa.is_null(), false, vformat("MachO: Can't open file: \"%s\".", p_path)); diff --git a/platform/macos/export/macho.h b/platform/macos/export/macho.h index 37975f08205..a84de7de60b 100644 --- a/platform/macos/export/macho.h +++ b/platform/macos/export/macho.h @@ -181,6 +181,7 @@ class MachO : public RefCounted { public: static bool is_macho(const String &p_path); + static uint32_t get_filetype(const String &p_path); bool open_file(const String &p_path);