From ac28ee357e8e1ccb20e74d721eec3064d6d3f7a6 Mon Sep 17 00:00:00 2001 From: Andrew Branson Date: Fri, 7 Mar 2025 17:12:11 +0100 Subject: [PATCH] Adapt patches to Android 13 - Adds a sysprop to enable spoofing. - ComputerEngine moved to its own class - SigningInfo support - Add signatures and signinginfo when requested in flags. - Allow any package to declare itself forceQueryable if spoofing is enabled, so MicroG doesn't need to be built into the image. --- 33/android_frameworks_base.patch | 222 +++++++++++++++++++++++++++++++ 1 file changed, 222 insertions(+) create mode 100644 33/android_frameworks_base.patch diff --git a/33/android_frameworks_base.patch b/33/android_frameworks_base.patch new file mode 100644 index 0000000..96e8102 --- /dev/null +++ b/33/android_frameworks_base.patch @@ -0,0 +1,222 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Andrew Branson +Date: Tue, 14 Jan 2025 17:21:01 +0100 +Subject: [PATCH 1/1] Add support for app signature spoofing + +This is needed by microG GmsCore to pretend to be the official Google +Play Services package, because client apps check the package signature +to make sure it matches Google's official certificate. + +This was forward-ported from the Android 10 patch by gudenau: +https://github.com/microg/android_packages_apps_GmsCore/pull/957 + +Changes made for Android 11: + - Updated PackageInfo calls + - Added new permission to public API surface, needed for + PermissionController which is now an updatable APEX on 11 + - Added a dummy permission group to allow users to manage the + permission through the PermissionController UI + (by Vachounet ) + - Updated location provider comment for conciseness + +Changes made for Android 12 (Danny Lin ): + - Moved mayFakeSignature into lock-free Computer subclass + - Always get permissions for packages that request signature spoofing + (otherwise permissions are usually ommitted and thus the permission + check doesn't work properly) + - Optimize mayFakeSignature check order to improve performance + +Changes made for Android 13: + - Add 'persist.package.replacement.enabled' sysprop to enable spoofing + - ComputerEngine subclass is now an independent class. + - Include new SigningInfo additions from LineageOS. + - Signatures, SigningInfo and permissions should only be present if + requested in flags. Copy signature array properly between the two fields. + - Allow all packages to declare themselves as forceQueryable if spoofing + is enabled. + +Change-Id: Ied7d6ce0b83a2d2345c3abba0429998d86494a88 +--- + core/api/current.txt | 2 + + core/res/AndroidManifest.xml | 15 ++++++ + core/res/res/values/strings.xml | 12 +++++ + .../com/android/server/pm/AppsFilterImpl.java | 2 + + .../com/android/server/pm/ComputerEngine.java | 53 +++++++++++++++++++ + 5 files changed, 84 insertions(+) + +diff --git a/core/api/current.txt b/core/api/current.txt +--- a/core/api/current.txt ++++ b/core/api/current.txt +@@ -87,6 +87,7 @@ package android { + field public static final String DUMP = "android.permission.DUMP"; + field public static final String EXPAND_STATUS_BAR = "android.permission.EXPAND_STATUS_BAR"; + field public static final String FACTORY_TEST = "android.permission.FACTORY_TEST"; ++ field public static final String FAKE_PACKAGE_SIGNATURE = "android.permission.FAKE_PACKAGE_SIGNATURE"; + field public static final String FOREGROUND_SERVICE = "android.permission.FOREGROUND_SERVICE"; + field public static final String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS"; + field public static final String GET_ACCOUNTS_PRIVILEGED = "android.permission.GET_ACCOUNTS_PRIVILEGED"; +@@ -222,6 +223,7 @@ package android { + field public static final String CALL_LOG = "android.permission-group.CALL_LOG"; + field public static final String CAMERA = "android.permission-group.CAMERA"; + field public static final String CONTACTS = "android.permission-group.CONTACTS"; ++ field public static final String FAKE_PACKAGE = "android.permission-group.FAKE_PACKAGE"; + field public static final String LOCATION = "android.permission-group.LOCATION"; + field public static final String MICROPHONE = "android.permission-group.MICROPHONE"; + field public static final String NEARBY_DEVICES = "android.permission-group.NEARBY_DEVICES"; +diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml +--- a/core/res/AndroidManifest.xml ++++ b/core/res/AndroidManifest.xml +@@ -3538,6 +3538,21 @@ + android:description="@string/permdesc_getPackageSize" + android:protectionLevel="normal" /> + ++ ++ ++ ++ ++ ++ + +diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml +--- a/core/res/res/values/strings.xml ++++ b/core/res/res/values/strings.xml +@@ -974,6 +974,18 @@ + + + ++ ++ Spoof package signature ++ ++ Allows the app to pretend to be a different app. Malicious applications might be able to use this to access private application data. Legitimate uses include an emulator pretending to be what it emulates. Grant this permission with caution only! ++ ++ Spoof package signature ++ ++ allow to spoof package signature ++ ++ Allow ++ <b>%1$s</b> to spoof package signature? ++ + + disable or modify status bar + +diff --git a/services/core/java/com/android/server/pm/AppsFilterImpl.java b/services/core/java/com/android/server/pm/AppsFilterImpl.java +--- a/services/core/java/com/android/server/pm/AppsFilterImpl.java ++++ b/services/core/java/com/android/server/pm/AppsFilterImpl.java +@@ -27,6 +27,7 @@ import static com.android.server.pm.AppsFilterUtils.canQueryViaComponents; + import static com.android.server.pm.AppsFilterUtils.canQueryViaPackage; + import static com.android.server.pm.AppsFilterUtils.canQueryViaUsesLibrary; + import static com.android.server.pm.AppsFilterUtils.requestsQueryAllPackages; ++import static com.android.server.pm.ComputerEngine.isSpoofingEnabled; + + import android.annotation.NonNull; + import android.annotation.Nullable; +@@ -522,6 +523,7 @@ public final class AppsFilterImpl extends AppsFilterLocked implements Watchable, + newIsForceQueryable = mForceQueryable.contains(newPkgSetting.getAppId()) + /* shared user that is already force queryable */ + || newPkgSetting.isForceQueryableOverride() /* adb override */ ++ || (newPkg.isForceQueryable() && isSpoofingEnabled()) + || (newPkgSetting.isSystem() && (mSystemAppsQueryable + || newPkg.isForceQueryable() + || ArrayUtils.contains(mForceQueryableByDevicePackageNames, +diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java +--- a/services/core/java/com/android/server/pm/ComputerEngine.java ++++ b/services/core/java/com/android/server/pm/ComputerEngine.java +@@ -29,6 +29,8 @@ import static android.content.pm.PackageManager.CERT_INPUT_SHA256; + import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; + import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED; + import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED; ++import static android.content.pm.PackageManager.GET_SIGNATURES; ++import static android.content.pm.PackageManager.GET_SIGNING_CERTIFICATES; + import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER; + import static android.content.pm.PackageManager.MATCH_ALL; + import static android.content.pm.PackageManager.MATCH_ANY_USER; +@@ -99,6 +101,7 @@ import android.os.IBinder; + import android.os.ParcelableException; + import android.os.PatternMatcher; + import android.os.Process; ++import android.os.SystemProperties; + import android.os.Trace; + import android.os.UserHandle; + import android.os.UserManager; +@@ -160,6 +163,7 @@ import java.io.FileOutputStream; + import java.io.IOException; + import java.io.PrintWriter; + import java.nio.charset.StandardCharsets; ++import java.security.cert.CertificateException; + import java.util.ArrayList; + import java.util.Collection; + import java.util.Collections; +@@ -1600,6 +1604,49 @@ public class ComputerEngine implements Computer { + return result; + } + ++ public static boolean isSpoofingEnabled() { ++ return SystemProperties.getBoolean("persist.package.replacement.enabled", false); ++ } ++ ++ private boolean requestsFakeSignature(AndroidPackage p) { ++ return p.getMetaData() != null && ++ p.getMetaData().getString("fake-signature") != null && ++ isSpoofingEnabled(); ++ } ++ ++ private PackageInfo mayFakeSignature(AndroidPackage p, PackageInfo pi, ++ @PackageManager.PackageInfoFlagsBits long flags, Set permissions) { ++ try { ++ if (p.getMetaData() != null && ++ ((flags & (GET_SIGNATURES | GET_SIGNING_CERTIFICATES)) != 0) && ++ p.getTargetSdkVersion() > Build.VERSION_CODES.LOLLIPOP_MR1) { ++ String sig = p.getMetaData().getString("fake-signature"); ++ if (sig != null && ++ permissions.contains("android.permission.FAKE_PACKAGE_SIGNATURE")) { ++ Signature[] sigs = new Signature[] {new Signature(sig)}; ++ if ((flags & GET_SIGNING_CERTIFICATES) != 0) { ++ try { ++ pi.signingInfo = new SigningInfo( ++ new SigningDetails(sigs, ++ SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3, ++ SigningDetails.toSigningKeys(sigs), null)); ++ } catch (CertificateException ex) { ++ Slog.e(TAG, "Caught an exception when creating signing keys: ", ex); ++ } ++ } ++ if ((flags & GET_SIGNATURES) != 0) { ++ pi.signatures = new Signature[sigs.length]; ++ System.arraycopy(sigs, 0, pi.signatures, 0, sigs.length); ++ } ++ } ++ } ++ } catch (Throwable t) { ++ // We should never die because of any failures, this is system code! ++ Log.w(TAG, "PackageManagerService.FAKE_PACKAGE_SIGNATURE", t); ++ } ++ return pi; ++ } ++ + public final PackageInfo generatePackageInfo(PackageStateInternal ps, + @PackageManager.PackageInfoFlagsBits long flags, int userId) { + if (!mUserManager.exists(userId)) return null; +@@ -1641,6 +1688,12 @@ public class ComputerEngine implements Computer { + return null; + } + ++ if (requestsFakeSignature(p)) { ++ packageInfo = mayFakeSignature(p, packageInfo, flags, ++ permissions.isEmpty() ? ++ mPermissionManager.getGrantedPermissions(ps.getPackageName(), userId) : permissions); ++ } ++ + packageInfo.packageName = packageInfo.applicationInfo.packageName = + resolveExternalPackageName(p); +