diff options
| -rw-r--r-- | core/java/com/android/server/SystemConfig.java | 33 | ||||
| -rw-r--r-- | services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java | 117 |
2 files changed, 139 insertions, 11 deletions
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java index 39f17e510a1c..fb0b7fdd6ce3 100644 --- a/core/java/com/android/server/SystemConfig.java +++ b/core/java/com/android/server/SystemConfig.java @@ -663,6 +663,7 @@ public class SystemConfig { readPermissions(parser, Environment.buildPath(f, "etc", "permissions"), apexPermissionFlag); } + pruneVendorApexPrivappAllowlists(); } @VisibleForTesting @@ -1175,7 +1176,8 @@ public class SystemConfig { readPrivAppPermissions(parser, mSystemExtPrivAppPermissions, mSystemExtPrivAppDenyPermissions); } else if (apex) { - readApexPrivAppPermissions(parser, permFile); + readApexPrivAppPermissions(parser, permFile, + Environment.getApexDirectory().toPath()); } else { readPrivAppPermissions(parser, mPrivAppPermissions, mPrivAppDenyPermissions); @@ -1525,6 +1527,21 @@ public class SystemConfig { } } + /** + * Prunes out any privileged permission allowlists bundled in vendor apexes. + */ + @VisibleForTesting + public void pruneVendorApexPrivappAllowlists() { + for (String moduleName: mAllowedVendorApexes.keySet()) { + if (mApexPrivAppPermissions.containsKey(moduleName) + || mApexPrivAppDenyPermissions.containsKey(moduleName)) { + Slog.w(TAG, moduleName + " is a vendor apex, ignore its priv-app allowlist"); + mApexPrivAppPermissions.remove(moduleName); + mApexPrivAppDenyPermissions.remove(moduleName); + } + } + } + private void readInstallInUserType(XmlPullParser parser, Map<String, Set<String>> doInstallMap, Map<String, Set<String>> nonInstallMap) @@ -1735,8 +1752,7 @@ public class SystemConfig { /** * Returns the module name for a file in the apex module's partition. */ - private String getApexModuleNameFromFilePath(Path path) { - final Path apexDirectoryPath = Environment.getApexDirectory().toPath(); + private String getApexModuleNameFromFilePath(Path path, Path apexDirectoryPath) { if (!path.startsWith(apexDirectoryPath)) { throw new IllegalArgumentException("File " + path + " is not part of an APEX."); } @@ -1748,9 +1764,14 @@ public class SystemConfig { return path.getName(apexDirectoryPath.getNameCount()).toString(); } - private void readApexPrivAppPermissions(XmlPullParser parser, File permFile) - throws IOException, XmlPullParserException { - final String moduleName = getApexModuleNameFromFilePath(permFile.toPath()); + /** + * Reads the contents of the privileged permission allowlist stored inside an APEX. + */ + @VisibleForTesting + public void readApexPrivAppPermissions(XmlPullParser parser, File permFile, + Path apexDirectoryPath) throws IOException, XmlPullParserException { + final String moduleName = + getApexModuleNameFromFilePath(permFile.toPath(), apexDirectoryPath); final ArrayMap<String, ArraySet<String>> privAppPermissions; if (mApexPrivAppPermissions.containsKey(moduleName)) { privAppPermissions = mApexPrivAppPermissions.get(moduleName); diff --git a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java index eeaf781dd307..bfdffc0e6567 100644 --- a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java +++ b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java @@ -39,9 +39,11 @@ import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.junit.runner.RunWith; import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; import java.io.BufferedWriter; import java.io.File; +import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.util.Arrays; @@ -137,13 +139,14 @@ public class SystemConfigTest { new ArraySet<>(Arrays.asList("GUEST", "PROFILE"))); final File folder1 = createTempSubfolder("folder1"); - createTempFile(folder1, "permFile1.xml", contents1); + createTempFile(folder1, "permissionFile1.xml", contents1); final File folder2 = createTempSubfolder("folder2"); - createTempFile(folder2, "permFile2.xml", contents2); + createTempFile(folder2, "permissionFile2.xml", contents2); - // Also, make a third file, but with the name folder1/permFile2.xml, to prove no conflicts. - createTempFile(folder1, "permFile2.xml", contents3); + // Also, make a third file, but with the name folder1/permissionFile2.xml, to prove no + // conflicts. + createTempFile(folder1, "permissionFile2.xml", contents3); readPermissions(folder1, /* No permission needed anyway */ 0); readPermissions(folder2, /* No permission needed anyway */ 0); @@ -333,6 +336,91 @@ public class SystemConfigTest { assertThat(mSysConfig.getAllowedVendorApexes()).isEmpty(); } + @Test + public void readApexPrivAppPermissions_addAllPermissions() + throws Exception { + final String contents = + "<privapp-permissions package=\"com.android.apk_in_apex\">" + + "<permission name=\"android.permission.FOO\"/>" + + "<deny-permission name=\"android.permission.BAR\"/>" + + "</privapp-permissions>"; + File apexDir = createTempSubfolder("apex"); + File permissionFile = createTempFile( + createTempSubfolder("apex/com.android.my_module/etc/permissions"), + "permissions.xml", contents); + XmlPullParser parser = readXmlUntilStartTag(permissionFile); + + mSysConfig.readApexPrivAppPermissions(parser, permissionFile, apexDir.toPath()); + + assertThat(mSysConfig.getApexPrivAppPermissions("com.android.my_module", + "com.android.apk_in_apex")) + .containsExactly("android.permission.FOO"); + assertThat(mSysConfig.getApexPrivAppDenyPermissions("com.android.my_module", + "com.android.apk_in_apex")) + .containsExactly("android.permission.BAR"); + } + + @Test + public void pruneVendorApexPrivappAllowlists_removeVendor() + throws Exception { + File apexDir = createTempSubfolder("apex"); + + // Read non-vendor apex permission allowlists + final String allowlistNonVendorContents = + "<privapp-permissions package=\"com.android.apk_in_non_vendor_apex\">" + + "<permission name=\"android.permission.FOO\"/>" + + "<deny-permission name=\"android.permission.BAR\"/>" + + "</privapp-permissions>"; + File nonVendorPermDir = + createTempSubfolder("apex/com.android.non_vendor/etc/permissions"); + File nonVendorPermissionFile = + createTempFile(nonVendorPermDir, "permissions.xml", allowlistNonVendorContents); + XmlPullParser nonVendorParser = readXmlUntilStartTag(nonVendorPermissionFile); + mSysConfig.readApexPrivAppPermissions(nonVendorParser, nonVendorPermissionFile, + apexDir.toPath()); + + // Read vendor apex permission allowlists + final String allowlistVendorContents = + "<privapp-permissions package=\"com.android.apk_in_vendor_apex\">" + + "<permission name=\"android.permission.BAZ\"/>" + + "<deny-permission name=\"android.permission.BAT\"/>" + + "</privapp-permissions>"; + File vendorPermissionFile = + createTempFile(createTempSubfolder("apex/com.android.vendor/etc/permissions"), + "permissions.xml", allowlistNonVendorContents); + XmlPullParser vendorParser = readXmlUntilStartTag(vendorPermissionFile); + mSysConfig.readApexPrivAppPermissions(vendorParser, vendorPermissionFile, + apexDir.toPath()); + + // Read allowed vendor apex list + final String allowedVendorContents = + "<config>\n" + + " <allowed-vendor-apex package=\"com.android.vendor\" " + + "installerPackage=\"com.installer\" />\n" + + "</config>"; + final File allowedVendorFolder = createTempSubfolder("folder"); + createTempFile(allowedVendorFolder, "vendor-apex-allowlist.xml", allowedVendorContents); + readPermissions(allowedVendorFolder, /* Grant all permission flags */ ~0); + + // Finally, prune non-vendor allowlists. + // There is no guarantee in which order the above reads will be done, however pruning + // will always happen last. + mSysConfig.pruneVendorApexPrivappAllowlists(); + + assertThat(mSysConfig.getApexPrivAppPermissions("com.android.non_vendor", + "com.android.apk_in_non_vendor_apex")) + .containsExactly("android.permission.FOO"); + assertThat(mSysConfig.getApexPrivAppDenyPermissions("com.android.non_vendor", + "com.android.apk_in_non_vendor_apex")) + .containsExactly("android.permission.BAR"); + assertThat(mSysConfig.getApexPrivAppPermissions("com.android.vendor", + "com.android.apk_in_vendor_apex")) + .isNull(); + assertThat(mSysConfig.getApexPrivAppDenyPermissions("com.android.vendor", + "com.android.apk_in_vendor_apex")) + .isNull(); + } + /** * Tests that readPermissions works correctly for a library with on-bootclasspath-before * and on-bootclasspath-since. @@ -492,6 +580,25 @@ public class SystemConfigTest { } /** + * Create an {@link XmlPullParser} for {@param permissionFile} and begin parsing it until + * reaching the root tag. + */ + private XmlPullParser readXmlUntilStartTag(File permissionFile) + throws IOException, XmlPullParserException { + FileReader permReader = new FileReader(permissionFile); + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(permReader); + int type; + do { + type = parser.next(); + } while (type != parser.START_TAG && type != parser.END_DOCUMENT); + if (type != parser.START_TAG) { + throw new XmlPullParserException("No start tag found"); + } + return parser; + } + + /** * Creates folderName/fileName in the mTemporaryFolder and fills it with the contents. * * @param folderName subdirectory of mTemporaryFolder to put the file, creating if needed @@ -500,7 +607,7 @@ public class SystemConfigTest { private File createTempSubfolder(String folderName) throws IOException { File folder = new File(mTemporaryFolder.getRoot(), folderName); - folder.mkdir(); + folder.mkdirs(); return folder; } |