Skip to content

spoof install source to Play Store for verified apps; add custom handling of stock OS packages; add cert digest and Play Store source stamp indicator to App info footer - #427

Open
muhomorr wants to merge 10 commits into
GrapheneOS:17from
muhomorr:17_08-12_base
Open

spoof install source to Play Store for verified apps; add custom handling of stock OS packages; add cert digest and Play Store source stamp indicator to App info footer#427
muhomorr wants to merge 10 commits into
GrapheneOS:17from
muhomorr:17_08-12_base

Conversation

@muhomorr

Copy link
Copy Markdown
Member

Adjust SystemJournalNotif to support PackageIdOwnershipChecks notifications which are added by the
next commit.
adevtool parses all stock OS APKs and builds an ApkParserConfig protobuf, which is included in the
OS at /product/etc/apk-parser-config.pb.

ApkParserConfig is checked at runtime by system_server for the following purposes:

- Ownership enforcement of system-wide stock OS package IDs: package names, permission
names, permission group names, content provider authorities. These IDs may be used
only if the signing certificate matches. Stock OS packages and native binaries don't always perform
these checks themselves, since on stock OS all of these IDs are already taken and can't be reused.
Therefore, it's not safe in the general case to include a subset of stock OS packages without these
checks.

- Blocking installation of a subset of stock OS packages.

- Isolation of specific stock OS packages from GmsCore and Play Store, or from all user-installed
apps.
Add missing checks for rare edge cases.
Comment on lines 41 to 43
@Composable
fun CopyableBody(body: String) {
fun CopyableBody(bodyCharSequence: CharSequence, showDropdownTitle: Boolean = true) {
var expanded by remember { mutableStateOf(false) }

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should avoid renaming upstream parameters to prevent possible compile errors for future upstream code that use named parameters

e.g. This is not included in an OS build but as an example: https://github.com/muhomorr/platform_frameworks_base/blob/17_08-12_base/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/CopyablePageProvider.kt#L49

Comment on lines +121 to +133
if (permission.isTree()) {
String prefix = name + '.';
for (String permName : ownershipMap.keySet()) {
if (!permName.startsWith(prefix)) {
continue;
}
String ownerPkgName = ownershipMap.get(permName);
String pkgName = pkg.getPackageName();
if (!ownerPkgName.equals(pkgName)) {
pkg.recordIdOwnershipViolation("permission-tree " + name + " conflicts with " + permName + " which is owned by " + ownerPkgName);
}
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefix conflicts are checked only when the incoming declaration is itself a permission tree

For example, system_ext/priv-app/GoogleServicesFramework/GoogleServicesFramework.apk provides a concrete example (although GSF isn't supposed to be used now anyway) by reserving this namespace in its manifest:

<permission-tree
    android:label="Google Services Permissions"
    android:name="com.google.android.googleapps.permission.GOOGLE_AUTH"/>

BriefPackageInfo combines that declaration with ordinary permissions, so the generated permission_owners map retains only the exact name and loses the fact that it is a tree.

While GSF is absent, another APK can therefore declare an ordinary permission under GSF"s com.google.android.googleapps.permission.GOOGLE_AUTH namespace such as com.google.android.googleapps.permission.GOOGLE_AUTH.UNREGISTERED_CHILD

This would have no exact map entry and there is no live tree to catch it. The same gap applies to any configured stock permission tree while its owner is absent

So trying to install a user app with

<permission
    android:name="com.google.android.googleapps.permission.GOOGLE_AUTH.ALL_SERVICES"
    android:protectionLevel="signature" />

would fail to install, since that's an existing permission in GSF

But trying to install a user app with

<permission
    android:name="com.google.android.googleapps.permission.GOOGLE_AUTH.UNREGISTERED_CHILD"
    android:protectionLevel="signature" />

would succeed

We should preserve tree ownership separately and reject ordinary permission declarations beneath reserved tree prefixes

@muhomorr muhomorr Aug 13, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This constraint isn't enforced even for preinstalled packages. Third-party apps can declare permission-trees and permissions that are within namespace of permission-trees of preinstalled apps.

Edit: missed that such permissions are ignored during package parsing.

@muhomorr muhomorr Aug 13, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing uses permission-trees in AOSP and on stock OS except GSF, which isn't used since Android 15. GSF is now an android:hasCode=false package, i.e. it can never add permissions at runtime.

Comment thread tools/aapt2/cmd/Dump.cpp
Comment on lines 416 to 417
for (xml::Element* manifest_child : manifest_el->GetChildElements()) {
if (manifest_child->name == "permission" || manifest_child->name == "permission-tree") {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

permission and permission-tree are combined here

Comment on lines +229 to +253
check(digest.size == 32)
lines.add(FormattingCommand.MonospaceTextStart)
lines.add(digest.copyOfRange(0, 16).toHexString(hexFormat))
lines.add(digest.copyOfRange(16, 32).toHexString(hexFormat))
lines.add(FormattingCommand.MonospaceTextEnd)
}
}
}

return buildAnnotatedString {
var start = -1
lines.forEachIndexed { idx, obj ->
when {
obj is String -> {
if (length != 0) {
append('\n')
}
append(obj)
}
obj == FormattingCommand.MonospaceTextStart -> {
start = length
}
obj == FormattingCommand.MonospaceTextEnd -> {
addStyle(SpanStyle(fontFamily = FontFamily.Monospace), start, length)
}

@inthewaves inthewaves Aug 12, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think something like this (wrapping the entire getFooterText in buildAnnotatedString) would be simpler / declarative and avoids FormattingCommand, MutableList<Any>:

  import androidx.compose.ui.text.withStyle

  private fun getFooterText(ctx: Context): AnnotatedString = buildAnnotatedString {
      fun appendLine(text: String) {
          if (length > 0) append('\n')
          append(text)
      }

      val pi = packageInfo

      appendLine(pi.packageName)
      pi.versionNameBidiWrapped?.let {
          appendLine(ctx.getString(R.string.version_text, it))
      }

      // ...

      val monospace = SpanStyle(fontFamily = FontFamily.Monospace)

      certs.forEach { cert ->
          appendLine(ctx.getString(R.string.app_info_apk_cert_digest))

          val digest = cert.sha256Digest
          check(digest.size == 32)

          append('\n')
          withStyle(monospace) {
              append(digest.copyOfRange(0, 16).toHexString(hexFormat))
              append('\n')
              append(digest.copyOfRange(16, 32).toHexString(hexFormat))
          }
      }
  }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

add support for automatically marking apps as installed from the Play Store if they have valid Play Store signing metadata

2 participants