[macOS export] Detect embedded helper executables using MachO header.
This commit is contained in:
parent
dd926b9132
commit
bae27340c9
|
@ -903,7 +903,7 @@ Error EditorExportPlatformMacOS::_notarize(const Ref<EditorExportPreset> &p_pres
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error EditorExportPlatformMacOS::_code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path, bool p_warn) {
|
Error EditorExportPlatformMacOS::_code_sign(const Ref<EditorExportPreset> &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");
|
int codesign_tool = p_preset->get("codesign/codesign");
|
||||||
switch (codesign_tool) {
|
switch (codesign_tool) {
|
||||||
case 1: { // built-in ad-hoc
|
case 1: { // built-in ad-hoc
|
||||||
|
@ -947,6 +947,12 @@ Error EditorExportPlatformMacOS::_code_sign(const Ref<EditorExportPreset> &p_pre
|
||||||
args.push_back("--code-signature-flags");
|
args.push_back("--code-signature-flags");
|
||||||
args.push_back("runtime");
|
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("-v"); /* provide some more feedback */
|
||||||
|
|
||||||
args.push_back(p_path);
|
args.push_back(p_path);
|
||||||
|
@ -1006,6 +1012,12 @@ Error EditorExportPlatformMacOS::_code_sign(const Ref<EditorExportPreset> &p_pre
|
||||||
args.push_back(p_preset->get("codesign/identity"));
|
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("-v"); /* provide some more feedback */
|
||||||
args.push_back("-f");
|
args.push_back("-f");
|
||||||
|
|
||||||
|
@ -1037,7 +1049,7 @@ Error EditorExportPlatformMacOS::_code_sign(const Ref<EditorExportPreset> &p_pre
|
||||||
}
|
}
|
||||||
|
|
||||||
Error EditorExportPlatformMacOS::_code_sign_directory(const Ref<EditorExportPreset> &p_preset, const String &p_path,
|
Error EditorExportPlatformMacOS::_code_sign_directory(const Ref<EditorExportPreset> &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<String> extensions_to_sign;
|
static Vector<String> extensions_to_sign;
|
||||||
|
|
||||||
if (extensions_to_sign.is_empty()) {
|
if (extensions_to_sign.is_empty()) {
|
||||||
|
@ -1064,7 +1076,8 @@ Error EditorExportPlatformMacOS::_code_sign_directory(const Ref<EditorExportPres
|
||||||
}
|
}
|
||||||
|
|
||||||
if (extensions_to_sign.find(current_file.get_extension()) > -1) {
|
if (extensions_to_sign.find(current_file.get_extension()) > -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) {
|
if (code_sign_error != OK) {
|
||||||
return code_sign_error;
|
return code_sign_error;
|
||||||
}
|
}
|
||||||
|
@ -1073,7 +1086,7 @@ Error EditorExportPlatformMacOS::_code_sign_directory(const Ref<EditorExportPres
|
||||||
FileAccess::set_unix_permissions(current_file_path, 0755);
|
FileAccess::set_unix_permissions(current_file_path, 0755);
|
||||||
}
|
}
|
||||||
} else if (dir_access->current_is_dir()) {
|
} else if (dir_access->current_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) {
|
if (code_sign_error != OK) {
|
||||||
return code_sign_error;
|
return code_sign_error;
|
||||||
}
|
}
|
||||||
|
@ -1091,6 +1104,7 @@ Error EditorExportPlatformMacOS::_code_sign_directory(const Ref<EditorExportPres
|
||||||
Error EditorExportPlatformMacOS::_copy_and_sign_files(Ref<DirAccess> &dir_access, const String &p_src_path,
|
Error EditorExportPlatformMacOS::_copy_and_sign_files(Ref<DirAccess> &dir_access, const String &p_src_path,
|
||||||
const String &p_in_app_path, bool p_sign_enabled,
|
const String &p_in_app_path, bool p_sign_enabled,
|
||||||
const Ref<EditorExportPreset> &p_preset, const String &p_ent_path,
|
const Ref<EditorExportPreset> &p_preset, const String &p_ent_path,
|
||||||
|
const String &p_helper_ent_path,
|
||||||
bool p_should_error_on_non_code_sign) {
|
bool p_should_error_on_non_code_sign) {
|
||||||
static Vector<String> extensions_to_sign;
|
static Vector<String> extensions_to_sign;
|
||||||
|
|
||||||
|
@ -1180,10 +1194,11 @@ Error EditorExportPlatformMacOS::_copy_and_sign_files(Ref<DirAccess> &dir_access
|
||||||
if (err == OK && p_sign_enabled) {
|
if (err == OK && p_sign_enabled) {
|
||||||
if (dir_access->dir_exists(p_src_path) && p_src_path.get_extension().is_empty()) {
|
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.
|
// 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 {
|
} else {
|
||||||
if (extensions_to_sign.find(p_in_app_path.get_extension()) > -1) {
|
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)) {
|
if (dir_access->file_exists(p_in_app_path) && is_executable(p_in_app_path)) {
|
||||||
// chmod with 0755 if the file is executable.
|
// chmod with 0755 if the file is executable.
|
||||||
|
@ -1197,13 +1212,13 @@ Error EditorExportPlatformMacOS::_copy_and_sign_files(Ref<DirAccess> &dir_access
|
||||||
Error EditorExportPlatformMacOS::_export_macos_plugins_for(Ref<EditorExportPlugin> p_editor_export_plugin,
|
Error EditorExportPlatformMacOS::_export_macos_plugins_for(Ref<EditorExportPlugin> p_editor_export_plugin,
|
||||||
const String &p_app_path_name, Ref<DirAccess> &dir_access,
|
const String &p_app_path_name, Ref<DirAccess> &dir_access,
|
||||||
bool p_sign_enabled, const Ref<EditorExportPreset> &p_preset,
|
bool p_sign_enabled, const Ref<EditorExportPreset> &p_preset,
|
||||||
const String &p_ent_path) {
|
const String &p_ent_path, const String &p_helper_ent_path) {
|
||||||
Error error{ OK };
|
Error error{ OK };
|
||||||
const Vector<String> &macos_plugins{ p_editor_export_plugin->get_macos_plugin_files() };
|
const Vector<String> &macos_plugins{ p_editor_export_plugin->get_macos_plugin_files() };
|
||||||
for (int i = 0; i < macos_plugins.size(); ++i) {
|
for (int i = 0; i < macos_plugins.size(); ++i) {
|
||||||
String src_path{ ProjectSettings::get_singleton()->globalize_path(macos_plugins[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() };
|
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) {
|
if (error != OK) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1780,8 +1795,9 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
|
||||||
add_message(EXPORT_MESSAGE_ERROR, TTR("Code Signing"), TTR("'rcodesign' doesn't support signing applications with embedded dynamic libraries."));
|
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 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())) {
|
if (sign_enabled && (ent_path.is_empty())) {
|
||||||
ent_path = EditorPaths::get_singleton()->get_cache_dir().path_join(pkg_name + ".entitlements");
|
ent_path = EditorPaths::get_singleton()->get_cache_dir().path_join(pkg_name + ".entitlements");
|
||||||
|
|
||||||
|
@ -1933,7 +1949,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
|
||||||
err = ERR_CANT_CREATE;
|
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);
|
ent_f = FileAccess::open(hlp_ent_path, FileAccess::WRITE);
|
||||||
if (ent_f.is_valid()) {
|
if (ent_f.is_valid()) {
|
||||||
ent_f->store_line("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
ent_f->store_line("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
||||||
|
@ -1959,7 +1975,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
|
||||||
String hlp_path = helpers[i];
|
String hlp_path = helpers[i];
|
||||||
err = da->copy(hlp_path, tmp_app_path_name + "/Contents/Helpers/" + hlp_path.get_file());
|
err = da->copy(hlp_path, tmp_app_path_name + "/Contents/Helpers/" + hlp_path.get_file());
|
||||||
if (err == OK && sign_enabled) {
|
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);
|
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<EditorExportPreset> &p
|
||||||
String src_path = ProjectSettings::get_singleton()->globalize_path(shared_objects[i].path);
|
String src_path = ProjectSettings::get_singleton()->globalize_path(shared_objects[i].path);
|
||||||
if (shared_objects[i].target.is_empty()) {
|
if (shared_objects[i].target.is_empty()) {
|
||||||
String path_in_app = tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file();
|
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 {
|
} else {
|
||||||
String path_in_app = tmp_app_path_name.path_join(shared_objects[i].target);
|
String path_in_app = tmp_app_path_name.path_join(shared_objects[i].target);
|
||||||
tmp_app_dir->make_dir_recursive(path_in_app);
|
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) {
|
if (err != OK) {
|
||||||
break;
|
break;
|
||||||
|
@ -1984,7 +2000,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
|
||||||
|
|
||||||
Vector<Ref<EditorExportPlugin>> export_plugins{ EditorExport::get_singleton()->get_export_plugins() };
|
Vector<Ref<EditorExportPlugin>> export_plugins{ EditorExport::get_singleton()->get_export_plugins() };
|
||||||
for (int i = 0; i < export_plugins.size(); ++i) {
|
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) {
|
if (err != OK) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2004,7 +2020,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
|
||||||
if (ep.step(TTR("Code signing bundle"), 2)) {
|
if (ep.step(TTR("Code signing bundle"), 2)) {
|
||||||
return ERR_SKIP;
|
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;
|
String noto_path = p_path;
|
||||||
|
@ -2022,7 +2038,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
|
||||||
if (ep.step(TTR("Code signing DMG"), 3)) {
|
if (ep.step(TTR("Code signing DMG"), 3)) {
|
||||||
return ERR_SKIP;
|
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") {
|
} else if (export_format == "pkg") {
|
||||||
// Create a Installer.
|
// Create a Installer.
|
||||||
|
|
|
@ -89,14 +89,14 @@ class EditorExportPlatformMacOS : public EditorExportPlatform {
|
||||||
void _make_icon(const Ref<EditorExportPreset> &p_preset, const Ref<Image> &p_icon, Vector<uint8_t> &p_data);
|
void _make_icon(const Ref<EditorExportPreset> &p_preset, const Ref<Image> &p_icon, Vector<uint8_t> &p_data);
|
||||||
|
|
||||||
Error _notarize(const Ref<EditorExportPreset> &p_preset, const String &p_path);
|
Error _notarize(const Ref<EditorExportPreset> &p_preset, const String &p_path);
|
||||||
Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path, bool p_warn = true);
|
Error _code_sign(const Ref<EditorExportPreset> &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<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path, bool p_should_error_on_non_code = true);
|
Error _code_sign_directory(const Ref<EditorExportPreset> &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<DirAccess> &dir_access, const String &p_src_path, const String &p_in_app_path,
|
Error _copy_and_sign_files(Ref<DirAccess> &dir_access, const String &p_src_path, const String &p_in_app_path,
|
||||||
bool p_sign_enabled, const Ref<EditorExportPreset> &p_preset, const String &p_ent_path,
|
bool p_sign_enabled, const Ref<EditorExportPreset> &p_preset, const String &p_ent_path, const String &p_helper_ent_path,
|
||||||
bool p_should_error_on_non_code_sign);
|
bool p_should_error_on_non_code_sign);
|
||||||
Error _export_macos_plugins_for(Ref<EditorExportPlugin> p_editor_export_plugin, const String &p_app_path_name,
|
Error _export_macos_plugins_for(Ref<EditorExportPlugin> p_editor_export_plugin, const String &p_app_path_name,
|
||||||
Ref<DirAccess> &dir_access, bool p_sign_enabled, const Ref<EditorExportPreset> &p_preset,
|
Ref<DirAccess> &dir_access, bool p_sign_enabled, const Ref<EditorExportPreset> &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_dmg(const String &p_dmg_path, const String &p_pkg_name, const String &p_app_path_name);
|
||||||
Error _create_pkg(const Ref<EditorExportPreset> &p_preset, const String &p_pkg_path, const String &p_app_path_name);
|
Error _create_pkg(const Ref<EditorExportPreset> &p_preset, const String &p_pkg_path, const String &p_app_path_name);
|
||||||
Error _export_debug_script(const Ref<EditorExportPreset> &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path);
|
Error _export_debug_script(const Ref<EditorExportPreset> &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path);
|
||||||
|
|
|
@ -105,6 +105,26 @@ bool MachO::is_macho(const String &p_path) {
|
||||||
return (magic == 0xcefaedfe || magic == 0xfeedface || magic == 0xcffaedfe || magic == 0xfeedfacf);
|
return (magic == 0xcefaedfe || magic == 0xfeedface || magic == 0xcffaedfe || magic == 0xfeedfacf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t MachO::get_filetype(const String &p_path) {
|
||||||
|
Ref<FileAccess> 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) {
|
bool MachO::open_file(const String &p_path) {
|
||||||
fa = FileAccess::open(p_path, FileAccess::READ_WRITE);
|
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));
|
ERR_FAIL_COND_V_MSG(fa.is_null(), false, vformat("MachO: Can't open file: \"%s\".", p_path));
|
||||||
|
|
|
@ -181,6 +181,7 @@ class MachO : public RefCounted {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static bool is_macho(const String &p_path);
|
static bool is_macho(const String &p_path);
|
||||||
|
static uint32_t get_filetype(const String &p_path);
|
||||||
|
|
||||||
bool open_file(const String &p_path);
|
bool open_file(const String &p_path);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue