From 0669d0761223c254d815cc16f95fe2eee3cd8fda Mon Sep 17 00:00:00 2001 From: Chris Bracken Date: Thu, 5 Sep 2024 16:12:42 -0700 Subject: [PATCH] iOS,macOS: add unsigned_binaries.txt (flutter/engine#54977) There are three categories of binaries produced as part of the framework artifacts: * Those that use APIs that require entitlements and must be code-signed; e.g. gen_snapshot * Those that do not use APIs that require entitlements and must be code-signed; e.g. Flutter.framework dylib. * Those that do not need to be code-signed; e.g. Flutter.dSYM symbols. Until now, our signing infrastructure has assumed that all mach-o binaries in the artifacts we produce require a signature. dSYM files are not required to be codesigned, although the xcframework containing them are, and as such they cannot be removed or tampered with. The framework code-signing tests in `dev/bots/suite_runners/run_verify_binaries_codesigned_tests.dart` are only run on post-submit on release branches, and thus, this issue was not uncovered until the first release after all the dSYM work landed. Those tests were updated in https://github.com/flutter/flutter/pull/154591. This updates the framework and artifact archive generation code to also explicitly exclude those files from signing. Issue: https://github.com/flutter/flutter/issues/154571 Related: https://github.com/flutter/flutter/issues/116493 Related: https://github.com/flutter/flutter/issues/153532 [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style --- .../flutter/sky/tools/create_ios_framework.py | 20 +++++++++---- .../sky/tools/create_macos_framework.py | 22 ++++++++++---- engine/src/flutter/sky/tools/sky_utils.py | 29 ++++++++++++++----- 3 files changed, 52 insertions(+), 19 deletions(-) diff --git a/engine/src/flutter/sky/tools/create_ios_framework.py b/engine/src/flutter/sky/tools/create_ios_framework.py index 2e91c07de6..2f90d9816b 100644 --- a/engine/src/flutter/sky/tools/create_ios_framework.py +++ b/engine/src/flutter/sky/tools/create_ios_framework.py @@ -168,24 +168,31 @@ def zip_archive(dst, args): # the framework's `verifyCodeSignedTestRunner`. # # See: https://github.com/flutter/flutter/blob/62382c7b83a16b3f48dc06c19a47f6b8667005a5/dev/bots/suite_runners/run_verify_binaries_codesigned_tests.dart#L82-L130 + + # Binaries that must be codesigned and require entitlements for particular APIs. with_entitlements = ['gen_snapshot_arm64'] with_entitlements_file = os.path.join(dst, 'entitlements.txt') sky_utils.write_codesign_config(with_entitlements_file, with_entitlements) + # Binaries that must be codesigned and DO NOT require entitlements. without_entitlements = [ 'Flutter.xcframework/ios-arm64/Flutter.framework/Flutter', 'Flutter.xcframework/ios-arm64_x86_64-simulator/Flutter.framework/Flutter', 'extension_safe/Flutter.xcframework/ios-arm64/Flutter.framework/Flutter', 'extension_safe/Flutter.xcframework/ios-arm64_x86_64-simulator/Flutter.framework/Flutter', ] + without_entitlements_file = os.path.join(dst, 'without_entitlements.txt') + sky_utils.write_codesign_config(without_entitlements_file, without_entitlements) + + # Binaries that will not be codesigned. + unsigned_binaries = [] if args.dsym: - without_entitlements.extend([ + unsigned_binaries.extend([ 'Flutter.xcframework/ios-arm64/dSYMs/Flutter.framework.dSYM/Contents/Resources/DWARF/Flutter', 'extension_safe/Flutter.xcframework/ios-arm64/dSYMs/Flutter.framework.dSYM/Contents/Resources/DWARF/Flutter', ]) - - without_entitlements_file = os.path.join(dst, 'without_entitlements.txt') - sky_utils.write_codesign_config(without_entitlements_file, without_entitlements) + unsigned_binaries_file = os.path.join(dst, 'unsigned_binaries.txt') + sky_utils.write_codesign_config(unsigned_binaries_file, unsigned_binaries) # pylint: enable=line-too-long zip_contents = [ @@ -193,9 +200,12 @@ def zip_archive(dst, args): 'Flutter.xcframework', 'entitlements.txt', 'without_entitlements.txt', + 'unsigned_binaries.txt', 'extension_safe/Flutter.xcframework', ] - sky_utils.assert_valid_codesign_config(dst, zip_contents, with_entitlements, without_entitlements) + sky_utils.assert_valid_codesign_config( + dst, zip_contents, with_entitlements, without_entitlements, unsigned_binaries + ) sky_utils.create_zip(dst, 'artifacts.zip', zip_contents) diff --git a/engine/src/flutter/sky/tools/create_macos_framework.py b/engine/src/flutter/sky/tools/create_macos_framework.py index 16f415d697..0d58b68f55 100755 --- a/engine/src/flutter/sky/tools/create_macos_framework.py +++ b/engine/src/flutter/sky/tools/create_macos_framework.py @@ -121,28 +121,38 @@ def zip_xcframework_archive(dst, args): # the framework's `verifyCodeSignedTestRunner`. # # See: https://github.com/flutter/flutter/blob/62382c7b83a16b3f48dc06c19a47f6b8667005a5/dev/bots/suite_runners/run_verify_binaries_codesigned_tests.dart#L82-L130 + + # Binaries that must be codesigned and require entitlements for particular APIs. with_entitlements = [] with_entitlements_file = os.path.join(dst, 'entitlements.txt') sky_utils.write_codesign_config(with_entitlements_file, with_entitlements) + # Binaries that must be codesigned and DO NOT require entitlements. without_entitlements = [ 'FlutterMacOS.xcframework/macos-arm64_x86_64/FlutterMacOS.framework/Versions/A/FlutterMacOS', ] - if args.dsym: - without_entitlements.extend([ - 'FlutterMacOS.xcframework/macos-arm64_x86_64/dSYMs/FlutterMacOS.framework.dSYM/Contents/Resources/DWARF/FlutterMacOS', - ]) - without_entitlements_file = os.path.join(dst, 'without_entitlements.txt') sky_utils.write_codesign_config(without_entitlements_file, without_entitlements) + + # Binaries that will not be codesigned. + unsigned_binaries = [] + if args.dsym: + unsigned_binaries.extend([ + 'FlutterMacOS.xcframework/macos-arm64_x86_64/dSYMs/FlutterMacOS.framework.dSYM/Contents/Resources/DWARF/FlutterMacOS', + ]) + unsigned_binaries_file = os.path.join(dst, 'unsigned_binaries.txt') + sky_utils.write_codesign_config(unsigned_binaries_file, unsigned_binaries) # pylint: enable=line-too-long zip_contents = [ 'FlutterMacOS.xcframework', 'entitlements.txt', 'without_entitlements.txt', + 'unsigned_binaries.txt', ] - sky_utils.assert_valid_codesign_config(dst, zip_contents, with_entitlements, without_entitlements) + sky_utils.assert_valid_codesign_config( + dst, zip_contents, with_entitlements, without_entitlements, unsigned_binaries + ) sky_utils.create_zip(dst, 'framework.zip', zip_contents) diff --git a/engine/src/flutter/sky/tools/sky_utils.py b/engine/src/flutter/sky/tools/sky_utils.py index a00131d9b2..72ca3647d0 100644 --- a/engine/src/flutter/sky/tools/sky_utils.py +++ b/engine/src/flutter/sky/tools/sky_utils.py @@ -25,7 +25,9 @@ def assert_file(path, what): sys.exit(os.EX_NOINPUT) -def assert_valid_codesign_config(framework_dir, zip_contents, entitlements, without_entitlements): +def assert_valid_codesign_config( + framework_dir, zip_contents, entitlements, without_entitlements, unsigned_binaries +): """Exits with exit code 1 if the codesign configuration contents are incorrect. All Mach-O binaries found within zip_contents exactly must be listed in either entitlements or without_entitlements.""" @@ -37,7 +39,11 @@ def assert_valid_codesign_config(framework_dir, zip_contents, entitlements, with log_error('ERROR: duplicate value(s) found in without_entitlements.txt') sys.exit(os.EX_DATAERR) - if _contains_duplicates(entitlements + without_entitlements): + if _contains_duplicates(unsigned_binaries): + log_error('ERROR: duplicate value(s) found in unsigned_binaries.txt') + sys.exit(os.EX_DATAERR) + + if _contains_duplicates(entitlements + without_entitlements + unsigned_binaries): log_error('ERROR: value(s) found in both entitlements and without_entitlements.txt') sys.exit(os.EX_DATAERR) @@ -52,12 +58,13 @@ def assert_valid_codesign_config(framework_dir, zip_contents, entitlements, with if _is_macho_binary(file): binaries.add(os.path.relpath(file, framework_dir)) - # Verify that all Mach-O binaries are listed in either entitlements or without_entitlements. - listed_binaries = set(entitlements + without_entitlements) + # Verify that all Mach-O binaries are listed in either entitlements, + # without_entitlements, or unsigned_binaries. + listed_binaries = set(entitlements + without_entitlements + unsigned_binaries) if listed_binaries != binaries: log_error( - 'ERROR: binaries listed in entitlements.txt and without_entitlements.txt do not ' - 'match the set of binaries in the files to be zipped' + 'ERROR: binaries listed in entitlements.txt, without_entitlements.txt, and' + 'unsigned_binaries.txt do not match the set of binaries in the files to be zipped' ) log_error('Binaries found in files to be zipped:') for file in sorted(binaries): @@ -65,13 +72,19 @@ def assert_valid_codesign_config(framework_dir, zip_contents, entitlements, with not_listed = sorted(binaries - listed_binaries) if not_listed: - log_error('Binaries NOT LISTED in entitlements.txt/without_entitlements.txt:') + log_error( + 'Binaries NOT LISTED in entitlements.txt, without_entitlements.txt, ' + 'unsigned_binaries.txt:' + ) for file in not_listed: log_error(' ' + file) not_found = sorted(listed_binaries - binaries) if not_found: - log_error('Binaries listed in entitlements.txt/without_entitlements.txt but NOT FOUND:') + log_error( + 'Binaries listed in entitlements.txt, without_entitlements.txt, ' + 'unsigned_binaries.txt but NOT FOUND:' + ) for file in not_found: log_error(' ' + file) sys.exit(os.EX_NOINPUT)