cicd: Check privapp-permissions by partition

This commit is contained in:
Paul Keith
2021-11-16 11:27:43 -06:00
parent 664187a854
commit 64fe7f9c11

View File

@@ -58,75 +58,93 @@ for perm in root.findall('permission'):
if len(levels_masked) == len(privileged_permission_mask): if len(levels_masked) == len(privileged_permission_mask):
privileged_permissions.add(name) privileged_permissions.add(name)
# List of partitions to check priv-app permissions on
partitions = ['product', 'system_ext']
# Definitions for privapp-permissions # Definitions for privapp-permissions
# Dictionary with structure: # Dictionary with structure:
# partition: permissions_dictionary
# Where permissions_dictionary has the structure:
# package_name : (set(allowed_permissions), set(requested_permissions)) # package_name : (set(allowed_permissions), set(requested_permissions))
privapp_permissions_dict = {} privapp_permissions_dict = {x: {} for x in partitions}
# Definitions for privapp-permission allowlists # Definitions for privapp-permission allowlists
GLOB_XML_STR = '../*/proprietary/*/etc/permissions/privapp-permissions*.xml' GLOB_XML_STR = '../*/proprietary/{}/etc/permissions/privapp-permissions*.xml'
# Parse allowlists to extract allowed privileged permissions # Parse allowlists to extract allowed privileged permissions
for allowlist in glob(GLOB_XML_STR): for partition in partitions:
# Get root of XML # Get pointer to permissions_dictionary for the partition
tree = ElementTree.parse(allowlist) perm_dict = privapp_permissions_dict[partition]
root = tree.getroot() # Loop over all the XMLs in the partition we want
# Loop through and find packages for allowlist in glob(GLOB_XML_STR.format(partition)):
for package in root.findall('privapp-permissions'): # Get root of XML
name = package.get('package') tree = ElementTree.parse(allowlist)
# Create empty entry if it's not in the dictionary root = tree.getroot()
if name not in privapp_permissions_dict: # Loop through and find packages
privapp_permissions_dict[name] = (set(), set()) for package in root.findall('privapp-permissions'):
# Get all permissions and add them to dictionary name = package.get('package')
for permission in package.findall('permission'): # Create empty entry if it's not in the dictionary
privapp_permissions_dict[name][0].add(permission.get('name')) if name not in perm_dict:
for permission in package.findall('deny-permission'): perm_dict[name] = (set(), set())
privapp_permissions_dict[name][0].add(permission.get('name')) # Get all permissions and add them to dictionary
for permission in package.findall('permission'):
perm_dict[name][0].add(permission.get('name'))
for permission in package.findall('deny-permission'):
perm_dict[name][0].add(permission.get('name'))
# Definitions for parsing APKs # Definitions for parsing APKs
GLOB_APK_STR = '../*/proprietary/*/priv-app/*/*.apk' GLOB_APK_STR = '../*/proprietary/{}/priv-app/*/*.apk'
AAPT_CMD = ['aapt', 'd', 'permissions'] AAPT_CMD = ['aapt', 'd', 'permissions']
# Extract requested privileged permissions from all priv-app APKs # Extract requested privileged permissions from all priv-app APKs
for apk in glob(GLOB_APK_STR): for partition in partitions:
# Run 'aapt d permissions' on APK # Get pointer to permissions_dictionary for the partition
aapt_output = subprocess.check_output(AAPT_CMD + [apk], perm_dict = privapp_permissions_dict[partition]
stderr=subprocess.STDOUT).decode(encoding='UTF-8') # Loop over all the APKs in the partition we want
lines = aapt_output.splitlines() for apk in glob(GLOB_APK_STR.format(partition)):
# Extract package name from the output # Run 'aapt d permissions' on APK
# Output looks like: aapt_output = subprocess.check_output(AAPT_CMD + [apk],
# package: my.package.name stderr=subprocess.STDOUT).decode(encoding='UTF-8')
package_name = parse('package: {}', lines[0])[0] lines = aapt_output.splitlines()
# Create empty entry if package is not in dict # Extract package name from the output
if package_name not in privapp_permissions_dict: # Output looks like:
privapp_permissions_dict[package_name] = (set(), set()) # package: my.package.name
# Extract 'uses-permission' lines from the rest of the output package_name = parse('package: {}', lines[0])[0]
# Relevant output looks like: # Create empty entry if package is not in dict
# uses-permission: name='permission' if package_name not in perm_dict:
for line in lines[1:]: perm_dict[package_name] = (set(), set())
# Extract permission name and add it to the dictionary if it's # Extract 'uses-permission' lines from the rest of the output
# one of the privileged permissions we extracted earlier # Relevant output looks like:
if perm_name := parse('uses-permission: name=\'{}\'', line): # uses-permission: name='permission'
if perm_name[0] in privileged_permissions: for line in lines[1:]:
privapp_permissions_dict[package_name][1].add(perm_name[0]) # Extract permission name and add it to the dictionary if it's
# one of the privileged permissions we extracted earlier
if perm_name := parse('uses-permission: name=\'{}\'', line):
if perm_name[0] in privileged_permissions:
perm_dict[package_name][1].add(perm_name[0])
# Keep track of exit code # Keep track of exit code
rc = 0 rc = 0
# Loop through all the packages and compare permission sets # Find all the missing permissions
for package in privapp_permissions_dict: for partition in partitions:
# Get the sets of permissions # Get pointer to permissions_dictionary for the partition
# Format is (allowed, requested) perm_dict = privapp_permissions_dict[partition]
perm_sets = privapp_permissions_dict[package] # Loop through all the packages and compare permission sets
# Compute the set difference requested - allowed for package in perm_dict:
# This gives us all the permissions requested that were not allowed # Get the sets of permissions
perm_diff = perm_sets[1] - perm_sets[0] # Format is (allowed, requested)
# If any permissions are left, set exit code to EPERM and print output perm_sets = perm_dict[package]
if len(perm_diff) > 0: # Compute the set difference requested - allowed
rc = errno.EPERM # This gives us all the permissions requested that were not allowed
sys.stderr.write(f"Package {package} is missing these permissions:\n") perm_diff = perm_sets[1] - perm_sets[0]
for perm in perm_diff: # If any permissions are left, set exit code to EPERM and print output
sys.stderr.write(f" - {perm}\n") if len(perm_diff) > 0:
rc = errno.EPERM
sys.stderr.write(
f"Package {package} on partition {partition} is missing these permissions:\n")
for perm in perm_diff:
sys.stderr.write(f" - {perm}\n")
# Exit program # Exit program
exit(rc) exit(rc)