From 21c34f78e88bca9121da2322d229d203a267f8af Mon Sep 17 00:00:00 2001 From: Daniel Norman Date: Wed, 11 Nov 2020 17:25:50 -0800 Subject: [PATCH] Runs host_init_verifier on merged target files packages. This verifies the init rc files in the merged result. Bug: 163089173 Test: test_common.py Test: Run merge_target_files.py to merge two target-files packages where one has init_rc errors. Observe script failure. Test: Run merge_target_files.py on two good target-files packages, observe no failure. Change-Id: I86c8e5a2bc07c2c1896ac40afd32bc1d055447ee --- tools/releasetools/Android.bp | 1 + tools/releasetools/common.py | 53 ++++++++++++++++++++++++ tools/releasetools/merge_target_files.py | 22 +++++++--- tools/releasetools/test_common.py | 21 ++++++++++ 4 files changed, 91 insertions(+), 6 deletions(-) diff --git a/tools/releasetools/Android.bp b/tools/releasetools/Android.bp index 11fb584ca..cafc2bb1f 100644 --- a/tools/releasetools/Android.bp +++ b/tools/releasetools/Android.bp @@ -435,6 +435,7 @@ python_binary_host { ], required: [ "checkvintf", + "host_init_verifier", ], target: { darwin: { diff --git a/tools/releasetools/common.py b/tools/releasetools/common.py index 149deda24..bae0b20f2 100644 --- a/tools/releasetools/common.py +++ b/tools/releasetools/common.py @@ -1102,6 +1102,29 @@ def MergeDynamicPartitionInfoDicts(framework_dict, vendor_dict): return merged_dict +def PartitionMapFromTargetFiles(target_files_dir): + """Builds a map from partition -> path within an extracted target files directory.""" + # Keep possible_subdirs in sync with build/make/core/board_config.mk. + possible_subdirs = { + "system": ["SYSTEM"], + "vendor": ["VENDOR", "SYSTEM/vendor"], + "product": ["PRODUCT", "SYSTEM/product"], + "system_ext": ["SYSTEM_EXT", "SYSTEM/system_ext"], + "odm": ["ODM", "VENDOR/odm", "SYSTEM/vendor/odm"], + "vendor_dlkm": [ + "VENDOR_DLKM", "VENDOR/vendor_dlkm", "SYSTEM/vendor/vendor_dlkm" + ], + "odm_dlkm": ["ODM_DLKM", "VENDOR/odm_dlkm", "SYSTEM/vendor/odm_dlkm"], + } + partition_map = {} + for partition, subdirs in possible_subdirs.items(): + for subdir in subdirs: + if os.path.exists(os.path.join(target_files_dir, subdir)): + partition_map[partition] = subdir + break + return partition_map + + def SharedUidPartitionViolations(uid_dict, partition_groups): """Checks for APK sharedUserIds that cross partition group boundaries. @@ -1134,6 +1157,36 @@ def SharedUidPartitionViolations(uid_dict, partition_groups): return errors +def RunHostInitVerifier(product_out, partition_map): + """Runs host_init_verifier on the init rc files within partitions. + + host_init_verifier searches the etc/init path within each partition. + + Args: + product_out: PRODUCT_OUT directory, containing partition directories. + partition_map: A map of partition name -> relative path within product_out. + """ + allowed_partitions = ("system", "system_ext", "product", "vendor", "odm") + cmd = ["host_init_verifier"] + for partition, path in partition_map.items(): + if partition not in allowed_partitions: + raise ExternalError("Unable to call host_init_verifier for partition %s" % + partition) + cmd.extend(["--out_%s" % partition, os.path.join(product_out, path)]) + # Add --property-contexts if the file exists on the partition. + property_contexts = "%s_property_contexts" % ( + "plat" if partition == "system" else partition) + property_contexts_path = os.path.join(product_out, path, "etc", "selinux", + property_contexts) + if os.path.exists(property_contexts_path): + cmd.append("--property-contexts=%s" % property_contexts_path) + # Add the passwd file if the file exists on the partition. + passwd_path = os.path.join(product_out, path, "etc", "passwd") + if os.path.exists(passwd_path): + cmd.extend(["-p", passwd_path]) + return RunAndCheckOutput(cmd) + + def AppendAVBSigningArgs(cmd, partition): """Append signing arguments for avbtool.""" # e.g., "--key path/to/signing_key --algorithm SHA256_RSA4096" diff --git a/tools/releasetools/merge_target_files.py b/tools/releasetools/merge_target_files.py index b1b4a1651..9360d7bc8 100755 --- a/tools/releasetools/merge_target_files.py +++ b/tools/releasetools/merge_target_files.py @@ -951,18 +951,15 @@ def merge_target_files(temp_dir, framework_target_files, framework_item_list, if not check_target_files_vintf.CheckVintf(output_target_files_temp_dir): raise RuntimeError('Incompatible VINTF metadata') + partition_map = common.PartitionMapFromTargetFiles( + output_target_files_temp_dir) + # Generate and check for cross-partition violations of sharedUserId # values in APKs. This requires the input target-files packages to contain # *.apk files. shareduid_violation_modules = os.path.join( output_target_files_temp_dir, 'META', 'shareduid_violation_modules.json') with open(shareduid_violation_modules, 'w') as f: - framework_partitions = item_list_to_partition_set(framework_item_list) - vendor_partitions = item_list_to_partition_set(vendor_item_list) - - partition_map = {} - for partition in (framework_partitions.union(vendor_partitions)): - partition_map[partition.lower()] = partition.upper() violation = find_shareduid_violation.FindShareduidViolation( output_target_files_temp_dir, partition_map) @@ -970,6 +967,8 @@ def merge_target_files(temp_dir, framework_target_files, framework_item_list, f.write(violation) # Check for violations across the input builds' partition groups. + framework_partitions = item_list_to_partition_set(framework_item_list) + vendor_partitions = item_list_to_partition_set(vendor_item_list) shareduid_errors = common.SharedUidPartitionViolations( json.loads(violation), [framework_partitions, vendor_partitions]) if shareduid_errors: @@ -978,6 +977,17 @@ def merge_target_files(temp_dir, framework_target_files, framework_item_list, raise ValueError('sharedUserId APK error. See %s' % shareduid_violation_modules) + # Run host_init_verifier on the combined init rc files. + filtered_partitions = { + partition: path + for partition, path in partition_map.items() + # host_init_verifier checks only the following partitions: + if partition in ['system', 'system_ext', 'product', 'vendor', 'odm'] + } + common.RunHostInitVerifier( + product_out=output_target_files_temp_dir, + partition_map=filtered_partitions) + generate_images(output_target_files_temp_dir, rebuild_recovery) generate_super_empty_image(output_target_files_temp_dir, output_super_empty) diff --git a/tools/releasetools/test_common.py b/tools/releasetools/test_common.py index 0b368f9b6..ecd759c80 100644 --- a/tools/releasetools/test_common.py +++ b/tools/releasetools/test_common.py @@ -996,6 +996,27 @@ class CommonUtilsTest(test_utils.ReleaseToolsTestCase): }, sparse_image.file_map) + def test_PartitionMapFromTargetFiles(self): + target_files_dir = common.MakeTempDir() + os.makedirs(os.path.join(target_files_dir, 'SYSTEM')) + os.makedirs(os.path.join(target_files_dir, 'SYSTEM', 'vendor')) + os.makedirs(os.path.join(target_files_dir, 'PRODUCT')) + os.makedirs(os.path.join(target_files_dir, 'SYSTEM', 'product')) + os.makedirs(os.path.join(target_files_dir, 'SYSTEM', 'vendor', 'odm')) + os.makedirs(os.path.join(target_files_dir, 'VENDOR_DLKM')) + partition_map = common.PartitionMapFromTargetFiles(target_files_dir) + self.assertDictEqual( + partition_map, + { + 'system': 'SYSTEM', + 'vendor': 'SYSTEM/vendor', + # Prefer PRODUCT over SYSTEM/product + 'product': 'PRODUCT', + 'odm': 'SYSTEM/vendor/odm', + 'vendor_dlkm': 'VENDOR_DLKM', + # No system_ext or odm_dlkm + }) + def test_SharedUidPartitionViolations(self): uid_dict = { 'android.uid.phone': {