compat_generator: find new types and removed types
To generate compat files, we need: - base plat sepolicy - old plat sepolicy - base plat pub sepolicy - mapping file from the device - latest compat files Generator now triggers the build system itself to get necessary base files, and then uses the artifacts to extract new types and removed types. For the next step, the new/removed types will be mapped to old types, based on the latest compat files. Bug: 214336258 Test: sepolicy_generate_compat --branch sc-v2-dev --target-version \ 32.0 --latest-version 31.0 -vvvv --build latest Change-Id: I1f228233c1e3638e78bc0630ae51e48667a12ef5
This commit is contained in:
parent
4ec796aa2f
commit
cbc95ea5e2
3 changed files with 146 additions and 29 deletions
|
@ -25,34 +25,46 @@ cc_library_host_shared {
|
|||
},
|
||||
}
|
||||
|
||||
python_library_host {
|
||||
name: "mini_cil_parser",
|
||||
srcs: ["mini_parser.py"],
|
||||
}
|
||||
|
||||
python_library_host {
|
||||
name: "pysepolwrap",
|
||||
srcs: [
|
||||
"fc_sort.py",
|
||||
"policy.py",
|
||||
],
|
||||
}
|
||||
|
||||
python_binary_host {
|
||||
name: "treble_sepolicy_tests",
|
||||
srcs: [
|
||||
"fc_sort.py",
|
||||
"mini_parser.py",
|
||||
"policy.py",
|
||||
"treble_sepolicy_tests.py",
|
||||
],
|
||||
libs: [
|
||||
"mini_cil_parser",
|
||||
"pysepolwrap",
|
||||
],
|
||||
data: [":libsepolwrap"],
|
||||
}
|
||||
|
||||
python_binary_host {
|
||||
name: "sepolicy_tests",
|
||||
srcs: [
|
||||
"fc_sort.py",
|
||||
"policy.py",
|
||||
"sepolicy_tests.py",
|
||||
],
|
||||
libs: ["pysepolwrap"],
|
||||
data: [":libsepolwrap"],
|
||||
}
|
||||
|
||||
python_binary_host {
|
||||
name: "searchpolicy",
|
||||
srcs: [
|
||||
"fc_sort.py",
|
||||
"policy.py",
|
||||
"searchpolicy.py",
|
||||
],
|
||||
libs: ["pysepolwrap"],
|
||||
required: ["libsepolwrap"],
|
||||
}
|
||||
|
||||
|
@ -60,8 +72,8 @@ python_binary_host {
|
|||
name: "combine_maps",
|
||||
srcs: [
|
||||
"combine_maps.py",
|
||||
"mini_parser.py",
|
||||
],
|
||||
libs: ["mini_cil_parser"],
|
||||
}
|
||||
|
||||
python_binary_host {
|
||||
|
|
|
@ -67,4 +67,6 @@ python_binary_host {
|
|||
python_binary_host {
|
||||
name: "sepolicy_generate_compat",
|
||||
srcs: ["sepolicy_generate_compat.py"],
|
||||
libs: ["mini_cil_parser", "pysepolwrap"],
|
||||
data: [":libsepolwrap"],
|
||||
}
|
||||
|
|
|
@ -15,19 +15,27 @@
|
|||
# limitations under the License.
|
||||
|
||||
import argparse
|
||||
import distutils.ccompiler
|
||||
import glob
|
||||
import logging
|
||||
import mini_parser
|
||||
import os
|
||||
import policy
|
||||
import shutil
|
||||
import subprocess
|
||||
import tempfile
|
||||
import zipfile
|
||||
"""This tool generates a mapping file for {ver} core sepolicy."""
|
||||
|
||||
temp_dir = ''
|
||||
|
||||
def check_run(cmd):
|
||||
logging.debug('Running cmd: %s' % cmd)
|
||||
subprocess.run(cmd, check=True)
|
||||
|
||||
def check_run(cmd, cwd=None):
|
||||
if cwd:
|
||||
logging.debug('Running cmd at %s: %s' % (cwd, cmd))
|
||||
else:
|
||||
logging.debug('Running cmd: %s' % cmd)
|
||||
subprocess.run(cmd, cwd=cwd, check=True)
|
||||
|
||||
|
||||
def check_output(cmd):
|
||||
|
@ -35,6 +43,15 @@ def check_output(cmd):
|
|||
return subprocess.run(cmd, check=True, stdout=subprocess.PIPE)
|
||||
|
||||
|
||||
def get_android_build_top():
|
||||
ANDROID_BUILD_TOP = os.getenv('ANDROID_BUILD_TOP')
|
||||
if not ANDROID_BUILD_TOP:
|
||||
sys.exit(
|
||||
'Error: Missing ANDROID_BUILD_TOP env variable. Please run '
|
||||
'\'. build/envsetup.sh; lunch <build target>\'. Exiting script.')
|
||||
return ANDROID_BUILD_TOP
|
||||
|
||||
|
||||
def fetch_artifact(branch, build, pattern, destination='.'):
|
||||
"""Fetches build artifacts from Android Build server.
|
||||
|
||||
|
@ -64,15 +81,20 @@ def extract_mapping_file_from_img(img_path, ver, destination='.'):
|
|||
img_path: string, path to system.img file
|
||||
ver: string, version of designated mapping file
|
||||
destination: string, destination to pull the mapping file to
|
||||
|
||||
Returns:
|
||||
string, path to extracted mapping file
|
||||
"""
|
||||
|
||||
cmd = [
|
||||
'debugfs', '-R',
|
||||
'cat system/etc/selinux/mapping/%s.cil' % ver, img_path
|
||||
]
|
||||
with open(os.path.join(destination, '%s.cil' % ver), 'wb') as f:
|
||||
path = os.path.join(destination, '%s.cil' % ver)
|
||||
with open(path, 'wb') as f:
|
||||
logging.debug('Extracting %s.cil to %s' % (ver, destination))
|
||||
f.write(check_output(cmd).stdout)
|
||||
return path
|
||||
|
||||
|
||||
def download_mapping_file(branch, build, ver, destination='.'):
|
||||
|
@ -83,24 +105,55 @@ def download_mapping_file(branch, build, ver, destination='.'):
|
|||
build: string, build ID or "latest"
|
||||
ver: string, version of designated mapping file (e.g. "32.0")
|
||||
destination: string, destination to pull build artifact to
|
||||
|
||||
Returns:
|
||||
string, path to extracted mapping file
|
||||
"""
|
||||
temp_dir = tempfile.mkdtemp()
|
||||
logging.info('Downloading %s mapping file from branch %s build %s...' %
|
||||
(ver, branch, build))
|
||||
artifact_pattern = 'aosp_arm64-img-*.zip'
|
||||
fetch_artifact(branch, build, artifact_pattern, temp_dir)
|
||||
|
||||
try:
|
||||
artifact_pattern = 'aosp_arm64-img-*.zip'
|
||||
fetch_artifact(branch, build, artifact_pattern, temp_dir)
|
||||
# glob must succeed
|
||||
zip_path = glob.glob(os.path.join(temp_dir, artifact_pattern))[0]
|
||||
with zipfile.ZipFile(zip_path) as zip_file:
|
||||
logging.debug('Extracting system.img to %s' % temp_dir)
|
||||
zip_file.extract('system.img', temp_dir)
|
||||
|
||||
# glob must succeed
|
||||
zip_path = glob.glob(os.path.join(temp_dir, artifact_pattern))[0]
|
||||
with zipfile.ZipFile(zip_path) as zip_file:
|
||||
logging.debug('Extracting system.img to %s' % temp_dir)
|
||||
zip_file.extract('system.img', temp_dir)
|
||||
system_img_path = os.path.join(temp_dir, 'system.img')
|
||||
return extract_mapping_file_from_img(system_img_path, ver, destination)
|
||||
|
||||
system_img_path = os.path.join(temp_dir, 'system.img')
|
||||
extract_mapping_file_from_img(system_img_path, ver, destination)
|
||||
finally:
|
||||
logging.info('Deleting temporary dir: {}'.format(temp_dir))
|
||||
shutil.rmtree(temp_dir)
|
||||
|
||||
def build_base_files(target_version):
|
||||
""" Builds needed base policy files from the source code.
|
||||
|
||||
Args:
|
||||
target_version: string, target version to gerenate the mapping file
|
||||
|
||||
Returns:
|
||||
(string, string, string), paths to base policy, old policy, and pub policy
|
||||
cil
|
||||
"""
|
||||
logging.info('building base sepolicy files')
|
||||
build_top = get_android_build_top()
|
||||
|
||||
cmd = [
|
||||
'build/soong/soong_ui.bash',
|
||||
'--make-mode',
|
||||
'dist',
|
||||
'base-sepolicy-files-for-mapping',
|
||||
'TARGET_PRODUCT=aosp_arm64',
|
||||
'TARGET_BUILD_VARIANT=userdebug',
|
||||
]
|
||||
check_run(cmd, cwd=build_top)
|
||||
|
||||
dist_dir = os.path.join(build_top, 'out', 'dist')
|
||||
base_policy_path = os.path.join(dist_dir, 'base_plat_sepolicy')
|
||||
old_policy_path = os.path.join(dist_dir,
|
||||
'%s_plat_sepolicy' % target_version)
|
||||
pub_policy_cil_path = os.path.join(dist_dir, 'base_plat_pub_policy.cil')
|
||||
|
||||
return base_policy_path, old_policy_path, pub_policy_cil_path
|
||||
|
||||
|
||||
def get_args():
|
||||
|
@ -111,9 +164,13 @@ def get_args():
|
|||
help='Branch to pull build from. e.g. "sc-v2-dev"')
|
||||
parser.add_argument('--build', required=True, help='Build ID, or "latest"')
|
||||
parser.add_argument(
|
||||
'--version',
|
||||
'--target-version',
|
||||
required=True,
|
||||
help='Version of designated mapping file. e.g. "32.0"')
|
||||
help='Target version of designated mapping file. e.g. "32.0"')
|
||||
parser.add_argument(
|
||||
'--latest-version',
|
||||
required=True,
|
||||
help='Latest version for mapping of newer types. e.g. "31.0"')
|
||||
parser.add_argument(
|
||||
'-v',
|
||||
'--verbose',
|
||||
|
@ -131,7 +188,53 @@ def main():
|
|||
format='%(levelname)-8s [%(filename)s:%(lineno)d] %(message)s',
|
||||
level=(logging.WARNING, logging.INFO, logging.DEBUG)[verbosity])
|
||||
|
||||
download_mapping_file(args.branch, args.build, args.version)
|
||||
global temp_dir
|
||||
temp_dir = tempfile.mkdtemp()
|
||||
|
||||
try:
|
||||
libpath = os.path.join(
|
||||
os.path.dirname(os.path.realpath(__file__)), 'libsepolwrap' +
|
||||
distutils.ccompiler.new_compiler().shared_lib_extension)
|
||||
if not os.path.exists(libpath):
|
||||
sys.exit(
|
||||
'Error: libsepolwrap does not exist. Is this binary corrupted?\n'
|
||||
)
|
||||
|
||||
build_top = get_android_build_top()
|
||||
sepolicy_path = os.path.join(build_top, 'system', 'sepolicy')
|
||||
target_compat_path = os.path.join(sepolicy_path, 'private', 'compat',
|
||||
args.target_version)
|
||||
|
||||
# Step 1. Download system/etc/selinux/mapping/{ver}.cil, and remove types/typeattributes
|
||||
mapping_file = download_mapping_file(args.branch, args.build,
|
||||
args.target_version)
|
||||
mapping_file_cil = mini_parser.MiniCilParser(mapping_file)
|
||||
mapping_file_cil.types = set()
|
||||
mapping_file_cil.typeattributes = set()
|
||||
|
||||
# Step 2. Build base policy files and parse latest mapping files
|
||||
base_policy_path, old_policy_path, pub_policy_cil_path = build_base_files(
|
||||
args.target_version)
|
||||
base_policy = policy.Policy(base_policy_path, None, libpath)
|
||||
old_policy = policy.Policy(old_policy_path, None, libpath)
|
||||
pub_policy_cil = mini_parser.MiniCilParser(pub_policy_cil_path)
|
||||
|
||||
all_types = base_policy.GetAllTypes(False)
|
||||
old_all_types = old_policy.GetAllTypes(False)
|
||||
pub_types = pub_policy_cil.types
|
||||
|
||||
# Step 3. Find new types and removed types
|
||||
new_types = pub_types & (all_types - old_all_types)
|
||||
removed_types = (mapping_file_cil.pubtypes - mapping_file_cil.types) & (
|
||||
old_all_types - all_types)
|
||||
|
||||
logging.info('new types: %s' % new_types)
|
||||
logging.info('removed types: %s' % removed_types)
|
||||
|
||||
# TODO: Step 4. Map new types and removed types appropriately
|
||||
finally:
|
||||
logging.info('Deleting temporary dir: {}'.format(temp_dir))
|
||||
shutil.rmtree(temp_dir)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
Loading…
Reference in a new issue