From 64fe7f9c11b659be1d9106edb732d32568acdb08 Mon Sep 17 00:00:00 2001 From: Paul Keith Date: Tue, 16 Nov 2021 11:27:43 -0600 Subject: [PATCH] cicd: Check privapp-permissions by partition --- cicd/verify-permissions.py | 124 +++++++++++++++++++++---------------- 1 file changed, 71 insertions(+), 53 deletions(-) diff --git a/cicd/verify-permissions.py b/cicd/verify-permissions.py index 437866d..cd145b8 100755 --- a/cicd/verify-permissions.py +++ b/cicd/verify-permissions.py @@ -58,75 +58,93 @@ for perm in root.findall('permission'): if len(levels_masked) == len(privileged_permission_mask): privileged_permissions.add(name) +# List of partitions to check priv-app permissions on +partitions = ['product', 'system_ext'] + # Definitions for privapp-permissions # Dictionary with structure: +# partition: permissions_dictionary +# Where permissions_dictionary has the structure: # package_name : (set(allowed_permissions), set(requested_permissions)) -privapp_permissions_dict = {} +privapp_permissions_dict = {x: {} for x in partitions} # 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 -for allowlist in glob(GLOB_XML_STR): - # Get root of XML - tree = ElementTree.parse(allowlist) - root = tree.getroot() - # Loop through and find packages - for package in root.findall('privapp-permissions'): - name = package.get('package') - # Create empty entry if it's not in the dictionary - if name not in privapp_permissions_dict: - privapp_permissions_dict[name] = (set(), set()) - # Get all permissions and add them to dictionary - for permission in package.findall('permission'): - privapp_permissions_dict[name][0].add(permission.get('name')) - for permission in package.findall('deny-permission'): - privapp_permissions_dict[name][0].add(permission.get('name')) +for partition in partitions: + # Get pointer to permissions_dictionary for the partition + perm_dict = privapp_permissions_dict[partition] + # Loop over all the XMLs in the partition we want + for allowlist in glob(GLOB_XML_STR.format(partition)): + # Get root of XML + tree = ElementTree.parse(allowlist) + root = tree.getroot() + # Loop through and find packages + for package in root.findall('privapp-permissions'): + name = package.get('package') + # Create empty entry if it's not in the dictionary + if name not in perm_dict: + perm_dict[name] = (set(), set()) + # 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 -GLOB_APK_STR = '../*/proprietary/*/priv-app/*/*.apk' +GLOB_APK_STR = '../*/proprietary/{}/priv-app/*/*.apk' AAPT_CMD = ['aapt', 'd', 'permissions'] # Extract requested privileged permissions from all priv-app APKs -for apk in glob(GLOB_APK_STR): - # Run 'aapt d permissions' on APK - aapt_output = subprocess.check_output(AAPT_CMD + [apk], - stderr=subprocess.STDOUT).decode(encoding='UTF-8') - lines = aapt_output.splitlines() - # Extract package name from the output - # Output looks like: - # package: my.package.name - package_name = parse('package: {}', lines[0])[0] - # Create empty entry if package is not in dict - if package_name not in privapp_permissions_dict: - privapp_permissions_dict[package_name] = (set(), set()) - # Extract 'uses-permission' lines from the rest of the output - # Relevant output looks like: - # uses-permission: name='permission' - for line in lines[1:]: - # 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: - privapp_permissions_dict[package_name][1].add(perm_name[0]) +for partition in partitions: + # Get pointer to permissions_dictionary for the partition + perm_dict = privapp_permissions_dict[partition] + # Loop over all the APKs in the partition we want + for apk in glob(GLOB_APK_STR.format(partition)): + # Run 'aapt d permissions' on APK + aapt_output = subprocess.check_output(AAPT_CMD + [apk], + stderr=subprocess.STDOUT).decode(encoding='UTF-8') + lines = aapt_output.splitlines() + # Extract package name from the output + # Output looks like: + # package: my.package.name + package_name = parse('package: {}', lines[0])[0] + # Create empty entry if package is not in dict + if package_name not in perm_dict: + perm_dict[package_name] = (set(), set()) + # Extract 'uses-permission' lines from the rest of the output + # Relevant output looks like: + # uses-permission: name='permission' + for line in lines[1:]: + # 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 rc = 0 -# Loop through all the packages and compare permission sets -for package in privapp_permissions_dict: - # Get the sets of permissions - # Format is (allowed, requested) - perm_sets = privapp_permissions_dict[package] - # Compute the set difference requested - allowed - # This gives us all the permissions requested that were not allowed - perm_diff = perm_sets[1] - perm_sets[0] - # If any permissions are left, set exit code to EPERM and print output - if len(perm_diff) > 0: - rc = errno.EPERM - sys.stderr.write(f"Package {package} is missing these permissions:\n") - for perm in perm_diff: - sys.stderr.write(f" - {perm}\n") +# Find all the missing permissions +for partition in partitions: + # Get pointer to permissions_dictionary for the partition + perm_dict = privapp_permissions_dict[partition] + # Loop through all the packages and compare permission sets + for package in perm_dict: + # Get the sets of permissions + # Format is (allowed, requested) + perm_sets = perm_dict[package] + # Compute the set difference requested - allowed + # This gives us all the permissions requested that were not allowed + perm_diff = perm_sets[1] - perm_sets[0] + # If any permissions are left, set exit code to EPERM and print output + 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(rc)