Add a skeleton sepolicy compat generator

sepolicy_generate_compat will be used to generate compat files for ToT,
based on the mapping file from aosp_arm64-userdebug target of {ver}
source tree. For now, it only supports downloading a mapping file
system/etc/selinux/mapping/{ver}.cil from the Android build server.

Bug: 214336258
Test: sepolicy_generate_compat --branch sc-v2-dev --version 32.0
Change-Id: I48043c71a6866aa385ecd67462f7678561cc5a38
This commit is contained in:
Inseob Kim 2022-01-17 16:37:51 +09:00
parent 9de6ad61ff
commit 29e357e898
2 changed files with 143 additions and 0 deletions

View file

@ -63,3 +63,8 @@ python_binary_host {
name: "insertkeys",
srcs: ["insertkeys.py"],
}
python_binary_host {
name: "sepolicy_generate_compat",
srcs: ["sepolicy_generate_compat.py"],
}

View file

@ -0,0 +1,138 @@
#!/usr/bin/env python3
# Copyright 2022 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import argparse
import glob
import logging
import os
import shutil
import subprocess
import tempfile
import zipfile
"""This tool generates a mapping file for {ver} core sepolicy."""
def check_run(cmd):
logging.debug('Running cmd: %s' % cmd)
subprocess.run(cmd, check=True)
def check_output(cmd):
logging.debug('Running cmd: %s' % cmd)
return subprocess.run(cmd, check=True, stdout=subprocess.PIPE)
def fetch_artifact(branch, build, pattern, destination='.'):
"""Fetches build artifacts from Android Build server.
Args:
branch: string, branch to pull build artifacts from
build: string, build ID or "latest"
pattern: string, pattern of build artifact file name
destination: string, destination to pull build artifact to
"""
fetch_artifact_path = '/google/data/ro/projects/android/fetch_artifact'
cmd = [
fetch_artifact_path, '--branch', branch, '--target',
'aosp_arm64-userdebug'
]
if build == 'latest':
cmd.append('--latest')
else:
cmd.extend(['--bid', build])
cmd.extend([pattern, destination])
check_run(cmd)
def extract_mapping_file_from_img(img_path, ver, destination='.'):
""" Extracts system/etc/selinux/mapping/{ver}.cil from system.img file.
Args:
img_path: string, path to system.img file
ver: string, version of designated mapping file
destination: string, destination to pull the mapping file to
"""
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:
logging.debug('Extracting %s.cil to %s' % (ver, destination))
f.write(check_output(cmd).stdout)
def download_mapping_file(branch, build, ver, destination='.'):
""" Downloads system/etc/selinux/mapping/{ver}.cil from Android Build server.
Args:
branch: string, branch to pull build artifacts from (e.g. "sc-v2-dev")
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
"""
temp_dir = tempfile.mkdtemp()
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)
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 get_args():
parser = argparse.ArgumentParser()
parser.add_argument(
'--branch',
required=True,
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',
required=True,
help='Version of designated mapping file. e.g. "32.0"')
parser.add_argument(
'-v',
'--verbose',
action='count',
default=0,
help='Increase output verbosity, e.g. "-v", "-vv".')
return parser.parse_args()
def main():
args = get_args()
verbosity = min(args.verbose, 2)
logging.basicConfig(
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)
if __name__ == '__main__':
main()