Creates a combined split-sepolicy file in merge_target_files.py.

This follows the same steps as OpenSplitPolicy() in
system/core/init/selinux.cpp on the device.

Bug: 178864050
Test: merge_target_files for R+S and S+S devices
Test: test_merge_target_files
Change-Id: Ia41a436bfda8e2cb65706122f0ff3805b99d16e1
This commit is contained in:
Daniel Norman 2021-02-22 15:15:24 -08:00
parent 5af98130b8
commit 48603ff158
4 changed files with 135 additions and 8 deletions

View File

@ -4136,6 +4136,7 @@ INTERNAL_OTATOOLS_MODULES := \
mkuserimg_mke2fs \
ota_from_target_files \
repack_bootimg \
secilc \
sefcontext_compile \
sgdisk \
shflags \

View File

@ -451,6 +451,7 @@ python_binary_host {
required: [
"checkvintf",
"host_init_verifier",
"secilc",
],
target: {
darwin: {

View File

@ -93,6 +93,7 @@ import shutil
import subprocess
import sys
import zipfile
from xml.etree import ElementTree
import add_img_to_target_files
import build_super_image
@ -658,6 +659,80 @@ def copy_file_contexts(framework_target_files_dir, vendor_target_files_dir,
os.path.join(output_target_files_dir, 'META', 'vendor_file_contexts.bin'))
def compile_split_sepolicy(product_out, partition_map, output_policy):
"""Uses secilc to compile a split sepolicy file.
Depends on various */etc/selinux/* and */etc/vintf/* files within partitions.
Args:
product_out: PRODUCT_OUT directory, containing partition directories.
partition_map: A map of partition name -> relative path within product_out.
output_policy: The name of the output policy created by secilc.
Returns:
A command list that can be executed to create the compiled sepolicy.
"""
def get_file(partition, path):
if partition not in partition_map:
logger.warning('Cannot load SEPolicy files for missing partition %s',
partition)
return None
return os.path.join(product_out, partition_map[partition], path)
# Load the kernel sepolicy version from the FCM. This is normally provided
# directly to selinux.cpp as a build flag, but is also available in this file.
fcm_file = get_file('system', 'etc/vintf/compatibility_matrix.device.xml')
if not fcm_file or not os.path.exists(fcm_file):
raise ExternalError('Missing required file for loading sepolicy: %s', fcm)
kernel_sepolicy_version = ElementTree.parse(fcm_file).getroot().find(
'sepolicy/kernel-sepolicy-version').text
# Load the vendor's plat sepolicy version. This is the version used for
# locating sepolicy mapping files.
vendor_plat_version_file = get_file('vendor',
'etc/selinux/plat_sepolicy_vers.txt')
if not vendor_plat_version_file or not os.path.exists(
vendor_plat_version_file):
raise ExternalError('Missing required sepolicy file %s',
vendor_plat_version_file)
with open(vendor_plat_version_file) as f:
vendor_plat_version = f.read().strip()
# Use the same flags and arguments as selinux.cpp OpenSplitPolicy().
cmd = ['secilc', '-m', '-M', 'true', '-G', '-N']
cmd.extend(['-c', kernel_sepolicy_version])
cmd.extend(['-o', output_policy])
cmd.extend(['-f', '/dev/null'])
required_policy_files = (
('system', 'etc/selinux/plat_sepolicy.cil'),
('system', 'etc/selinux/mapping/%s.cil' % vendor_plat_version),
('vendor', 'etc/selinux/vendor_sepolicy.cil'),
('vendor', 'etc/selinux/plat_pub_versioned.cil'),
)
for policy in (map(lambda partition_and_path: get_file(*partition_and_path),
required_policy_files)):
if not policy or not os.path.exists(policy):
raise ExternalError('Missing required sepolicy file %s', policy)
cmd.append(policy)
optional_policy_files = (
('system', 'etc/selinux/mapping/%s.compat.cil' % vendor_plat_version),
('system_ext', 'etc/selinux/system_ext_sepolicy.cil'),
('system_ext', 'etc/selinux/mapping/%s.cil' % vendor_plat_version),
('product', 'etc/selinux/product_sepolicy.cil'),
('product', 'etc/selinux/mapping/%s.cil' % vendor_plat_version),
('odm', 'etc/selinux/odm_sepolicy.cil'),
)
for policy in (map(lambda partition_and_path: get_file(*partition_and_path),
optional_policy_files)):
if policy and os.path.exists(policy):
cmd.append(policy)
return cmd
def process_special_cases(framework_target_files_temp_dir,
vendor_target_files_temp_dir,
output_target_files_temp_dir,
@ -977,17 +1052,28 @@ 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.
# host_init_verifier and secilc check only the following partitions:
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']
}
# Run host_init_verifier on the combined init rc files.
common.RunHostInitVerifier(
product_out=output_target_files_temp_dir,
partition_map=filtered_partitions)
# Check that the split sepolicy from the multiple builds can compile.
split_sepolicy_cmd = compile_split_sepolicy(
product_out=output_target_files_temp_dir,
partition_map=filtered_partitions,
output_policy=os.path.join(output_target_files_temp_dir,
'META/combined.policy'))
logger.info('Compiling split sepolicy: %s', ' '.join(split_sepolicy_cmd))
common.RunAndCheckOutput(split_sepolicy_cmd)
# TODO(b/178864050): Run tests on the combined.policy file.
generate_images(output_target_files_temp_dir, rebuild_recovery)
generate_super_empty_image(output_target_files_temp_dir, output_super_empty)

View File

@ -18,12 +18,11 @@ import os.path
import common
import test_utils
from merge_target_files import (validate_config_lists,
DEFAULT_FRAMEWORK_ITEM_LIST,
DEFAULT_VENDOR_ITEM_LIST,
DEFAULT_FRAMEWORK_MISC_INFO_KEYS, copy_items,
item_list_to_partition_set,
process_apex_keys_apk_certs_common)
from merge_target_files import (
validate_config_lists, DEFAULT_FRAMEWORK_ITEM_LIST,
DEFAULT_VENDOR_ITEM_LIST, DEFAULT_FRAMEWORK_MISC_INFO_KEYS, copy_items,
item_list_to_partition_set, process_apex_keys_apk_certs_common,
compile_split_sepolicy)
class MergeTargetFilesTest(test_utils.ReleaseToolsTestCase):
@ -235,3 +234,43 @@ class MergeTargetFilesTest(test_utils.ReleaseToolsTestCase):
]
partition_set = item_list_to_partition_set(item_list)
self.assertEqual(set(['product', 'system', 'system_ext']), partition_set)
def test_compile_split_sepolicy(self):
product_out_dir = common.MakeTempDir()
def write_temp_file(path, data=''):
full_path = os.path.join(product_out_dir, path)
if not os.path.exists(os.path.dirname(full_path)):
os.makedirs(os.path.dirname(full_path))
with open(full_path, 'w') as f:
f.write(data)
write_temp_file(
'system/etc/vintf/compatibility_matrix.device.xml', """
<compatibility-matrix>
<sepolicy>
<kernel-sepolicy-version>30</kernel-sepolicy-version>
</sepolicy>
</compatibility-matrix>""")
write_temp_file('vendor/etc/selinux/plat_sepolicy_vers.txt', '30.0')
write_temp_file('system/etc/selinux/plat_sepolicy.cil')
write_temp_file('system/etc/selinux/mapping/30.0.cil')
write_temp_file('product/etc/selinux/mapping/30.0.cil')
write_temp_file('vendor/etc/selinux/vendor_sepolicy.cil')
write_temp_file('vendor/etc/selinux/plat_pub_versioned.cil')
cmd = compile_split_sepolicy(product_out_dir, {
'system': 'system',
'product': 'product',
'vendor': 'vendor',
}, os.path.join(product_out_dir, 'policy'))
self.assertEqual(' '.join(cmd),
('secilc -m -M true -G -N -c 30 '
'-o {OTP}/policy -f /dev/null '
'{OTP}/system/etc/selinux/plat_sepolicy.cil '
'{OTP}/system/etc/selinux/mapping/30.0.cil '
'{OTP}/vendor/etc/selinux/vendor_sepolicy.cil '
'{OTP}/vendor/etc/selinux/plat_pub_versioned.cil '
'{OTP}/product/etc/selinux/mapping/30.0.cil').format(
OTP=product_out_dir))