you want it, you got it!

now compile it yourself.

Signed-off-by: Tavi <tavi@divested.dev>
This commit is contained in:
Tavi 2024-04-09 13:41:25 -04:00
parent f5d06ea9aa
commit 4f8cfc8a41
No known key found for this signature in database
GPG Key ID: E599F62ECBAEAF2E
17 changed files with 2921 additions and 2 deletions

View File

@ -0,0 +1,511 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Danny Lin <danny@kdrag0n.dev>
Date: Mon, 11 Oct 2021 19:59:51 -0700
Subject: [PATCH 1/8] Alter model name to avoid SafetyNet HW attestation
enforcement
As of September 2, Google is enforcing SafetyNet's previously
opportunistic hardware-backed attestation based on device information.
Append a space to the device model name in order to avoid such
enforcement.
Also contains:
Spoof build fingerprint for Google Play Services
SafetyNet's CTS profile attestation checks whether Build.FINGERPRINT
matches that of the device's stock OS, which has passed CTS testing.
Spoof the fingerprint for Google Play Services to help pass SafetyNet.
We used to set the real system build fingerprint to the stock one, but
Android relies on each build having a unique fingerprint in order to
clear the correct caches and update persistent state for system changes.
On devices that no longer receive updates from the OEM, the build
fingerprint never changes and Android doesn't account for updates
correctly, which causes issues when updating without wiping data.
Only spoofing the fingerprint for Google Play Services fixes this issue.
Corresponding vendor commit:
"Only use stock build fingerprint for Google Play Services"
NB: This code is under the gmscompat package, but it does not depend on
any code from gmscompat.
Change-Id: I26a2498eb2e2163933303b03f6d516e5fb30fe51
* We don't need to spoof the fingerprint here since we do it globally, but we
use the Build field spoofing code it added for model
Change-Id: Ib7779e0aae40cab3730a56785e9231896917ab0a
---
core/java/android/app/Instrumentation.java | 4 ++
.../internal/gmscompat/AttestationHooks.java | 59 +++++++++++++++++++
2 files changed, 63 insertions(+)
create mode 100644 core/java/com/android/internal/gmscompat/AttestationHooks.java
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index d4385549da02..61e4176392f7 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -53,6 +53,8 @@ import android.view.Window;
import com.android.internal.content.ReferrerIntent;
+import com.android.internal.gmscompat.AttestationHooks;
+
import java.io.File;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -1119,6 +1121,7 @@ public class Instrumentation {
Application app = getFactory(context.getPackageName())
.instantiateApplication(cl, className);
app.attach(context);
+ AttestationHooks.initApplicationBeforeOnCreate(app);
return app;
}
@@ -1136,6 +1139,7 @@ public class Instrumentation {
ClassNotFoundException {
Application app = (Application)clazz.newInstance();
app.attach(context);
+ AttestationHooks.initApplicationBeforeOnCreate(app);
return app;
}
diff --git a/core/java/com/android/internal/gmscompat/AttestationHooks.java b/core/java/com/android/internal/gmscompat/AttestationHooks.java
new file mode 100644
index 000000000000..621156eb84b9
--- /dev/null
+++ b/core/java/com/android/internal/gmscompat/AttestationHooks.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.gmscompat;
+
+import android.app.Application;
+import android.os.Build;
+import android.os.SystemProperties;
+import android.util.Log;
+
+import java.lang.reflect.Field;
+
+/** @hide */
+public final class AttestationHooks {
+ private static final String TAG = "GmsCompat/Attestation";
+ private static final String PACKAGE_GMS = "com.google.android.gms";
+
+ private AttestationHooks() { }
+
+ private static void setBuildField(String key, String value) {
+ try {
+ // Unlock
+ Field field = Build.class.getDeclaredField(key);
+ field.setAccessible(true);
+
+ // Edit
+ field.set(null, value);
+
+ // Lock
+ field.setAccessible(false);
+ } catch (NoSuchFieldException | IllegalAccessException e) {
+ Log.e(TAG, "Failed to spoof Build." + key, e);
+ }
+ }
+
+ private static void spoofBuildGms() {
+ // Alter model name to avoid hardware attestation enforcement
+ setBuildField("MODEL", Build.MODEL + " ");
+ }
+
+ public static void initApplicationBeforeOnCreate(Application app) {
+ if (PACKAGE_GMS.equals(app.getPackageName())) {
+ spoofBuildGms();
+ }
+ }
+}
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Danny Lin <danny@kdrag0n.dev>
Date: Mon, 11 Oct 2021 20:00:44 -0700
Subject: [PATCH 2/8] keystore: Block key attestation for SafetyNet
SafetyNet (part of Google Play Services) opportunistically uses
hardware-backed key attestation via KeyStore as a strong integrity
check. This causes SafetyNet to fail on custom ROMs because the verified
boot key and bootloader unlock state can be detected from attestation
certificates.
As a workaround, we can take advantage of the fact that SafetyNet's
usage of key attestation is opportunistic (i.e. falls back to basic
integrity checks if it fails) and prevent it from getting the
attestation certificate chain from KeyStore. This is done by checking
the stack for DroidGuard, which is the codename for SafetyNet, and
pretending that the device doesn't support key attestation.
Key attestation has only been blocked for SafetyNet specifically, as
Google Play Services and other apps have many valid reasons to use it.
For example, it appears to be involved in Google's mobile security key
ferature.
Change-Id: I5146439d47f42dc6231cb45c4dab9f61540056f6
---
.../internal/gmscompat/AttestationHooks.java | 16 ++++++++++++++++
.../security/keystore/AndroidKeyStoreSpi.java | 4 ++++
2 files changed, 20 insertions(+)
diff --git a/core/java/com/android/internal/gmscompat/AttestationHooks.java b/core/java/com/android/internal/gmscompat/AttestationHooks.java
index 621156eb84b9..fe12dfe02a9f 100644
--- a/core/java/com/android/internal/gmscompat/AttestationHooks.java
+++ b/core/java/com/android/internal/gmscompat/AttestationHooks.java
@@ -22,12 +22,15 @@ import android.os.SystemProperties;
import android.util.Log;
import java.lang.reflect.Field;
+import java.util.Arrays;
/** @hide */
public final class AttestationHooks {
private static final String TAG = "GmsCompat/Attestation";
private static final String PACKAGE_GMS = "com.google.android.gms";
+ private static volatile boolean sIsGms = false;
+
private AttestationHooks() { }
private static void setBuildField(String key, String value) {
@@ -53,7 +56,20 @@ public final class AttestationHooks {
public static void initApplicationBeforeOnCreate(Application app) {
if (PACKAGE_GMS.equals(app.getPackageName())) {
+ sIsGms = true;
spoofBuildGms();
}
}
+
+ private static boolean isCallerSafetyNet() {
+ return Arrays.stream(Thread.currentThread().getStackTrace())
+ .anyMatch(elem -> elem.getClassName().contains("DroidGuard"));
+ }
+
+ public static void onEngineGetCertificateChain() {
+ // Check stack for SafetyNet
+ if (sIsGms && isCallerSafetyNet()) {
+ throw new UnsupportedOperationException();
+ }
+ }
}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
index 4c007cb70ba2..7dcd79197aa5 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
@@ -30,6 +30,8 @@ import android.security.keystore.SecureKeyImportUnavailableException;
import android.security.keystore.WrappedKeyEntry;
import android.util.Log;
+import com.android.internal.gmscompat.AttestationHooks;
+
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -104,6 +106,8 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi {
@Override
public Certificate[] engineGetCertificateChain(String alias) {
+ AttestationHooks.onEngineGetCertificateChain();
+
if (alias == null) {
throw new NullPointerException("alias == null");
}
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Anirudh Gupta <anirudhgupta109@aosip.dev>
Date: Wed, 4 Jan 2023 18:20:56 +0000
Subject: [PATCH 3/8] AttestationHooks: Set shipping level to 32 for devices
>=33
If ro.product.first_api_level is 33, it's forced to use HW attestation.
Setting it to 32 allows for software attestation and passing CTS.
Change-Id: Ie47fd00b009c93580ec8c950d223c60ed63a0d2f
---
.../internal/gmscompat/AttestationHooks.java | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/core/java/com/android/internal/gmscompat/AttestationHooks.java b/core/java/com/android/internal/gmscompat/AttestationHooks.java
index fe12dfe02a9f..f512adc3985b 100644
--- a/core/java/com/android/internal/gmscompat/AttestationHooks.java
+++ b/core/java/com/android/internal/gmscompat/AttestationHooks.java
@@ -49,9 +49,28 @@ public final class AttestationHooks {
}
}
+ private static void setVersionField(String key, Integer value) {
+ try {
+ // Unlock
+ Field field = Build.VERSION.class.getDeclaredField(key);
+ field.setAccessible(true);
+
+ // Edit
+ field.set(null, value);
+
+ // Lock
+ field.setAccessible(false);
+ } catch (NoSuchFieldException | IllegalAccessException e) {
+ Log.e(TAG, "Failed to spoof Build.VERSION." + key, e);
+ }
+ }
+
private static void spoofBuildGms() {
// Alter model name to avoid hardware attestation enforcement
setBuildField("MODEL", Build.MODEL + " ");
+ if (Build.VERSION.DEVICE_INITIAL_SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ setVersionField("DEVICE_INITIAL_SDK_INT", Build.VERSION_CODES.S_V2);
+ }
}
public static void initApplicationBeforeOnCreate(Application app) {
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Danny Lin <danny@kdrag0n.dev>
Date: Mon, 1 Nov 2021 20:06:48 -0700
Subject: [PATCH 4/8] Limit SafetyNet workarounds to unstable GMS process
The unstable process is where SafetyNet attestation actually runs, so
we only need to spoof the model in that process. Leaving other processes
fixes various issues caused by model detection and flag provisioning,
including screen-off Voice Match in Google Assistant, broken At a Glance
weather and settings on Android 12, and more.
Change-Id: Idcf663907a6c3d0408dbd45b1ac53c9eb4200df8
---
.../java/com/android/internal/gmscompat/AttestationHooks.java | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/core/java/com/android/internal/gmscompat/AttestationHooks.java b/core/java/com/android/internal/gmscompat/AttestationHooks.java
index f512adc3985b..c1021dd2eb22 100644
--- a/core/java/com/android/internal/gmscompat/AttestationHooks.java
+++ b/core/java/com/android/internal/gmscompat/AttestationHooks.java
@@ -28,6 +28,7 @@ import java.util.Arrays;
public final class AttestationHooks {
private static final String TAG = "GmsCompat/Attestation";
private static final String PACKAGE_GMS = "com.google.android.gms";
+ private static final String PROCESS_UNSTABLE = "com.google.android.gms.unstable";
private static volatile boolean sIsGms = false;
@@ -74,7 +75,8 @@ public final class AttestationHooks {
}
public static void initApplicationBeforeOnCreate(Application app) {
- if (PACKAGE_GMS.equals(app.getPackageName())) {
+ if (PACKAGE_GMS.equals(app.getPackageName()) &&
+ PROCESS_UNSTABLE.equals(Application.getProcessName())) {
sIsGms = true;
spoofBuildGms();
}
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Dyneteve <dyneteve@hentaios.com>
Date: Tue, 23 Aug 2022 18:57:05 +0200
Subject: [PATCH 5/8] gmscompat: Apply the SafetyNet workaround to Play Store
aswell
Play Store is used for the new Play Integrity API, extend the hack
to it aswell
Test: Device Integrity and Basic Integrity passes.
Change-Id: Id607cdff0b902f285a6c1b769c0a4ee4202842b1
---
.../android/internal/gmscompat/AttestationHooks.java | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/core/java/com/android/internal/gmscompat/AttestationHooks.java b/core/java/com/android/internal/gmscompat/AttestationHooks.java
index c1021dd2eb22..6a4aab000fe0 100644
--- a/core/java/com/android/internal/gmscompat/AttestationHooks.java
+++ b/core/java/com/android/internal/gmscompat/AttestationHooks.java
@@ -28,9 +28,11 @@ import java.util.Arrays;
public final class AttestationHooks {
private static final String TAG = "GmsCompat/Attestation";
private static final String PACKAGE_GMS = "com.google.android.gms";
+ private static final String PACKAGE_FINSKY = "com.android.vending";
private static final String PROCESS_UNSTABLE = "com.google.android.gms.unstable";
private static volatile boolean sIsGms = false;
+ private static volatile boolean sIsFinsky = false;
private AttestationHooks() { }
@@ -80,6 +82,11 @@ public final class AttestationHooks {
sIsGms = true;
spoofBuildGms();
}
+
+ if (PACKAGE_FINSKY.equals(app.getPackageName())) {
+ sIsFinsky = true;
+ spoofBuildGms();
+ }
}
private static boolean isCallerSafetyNet() {
@@ -92,5 +99,10 @@ public final class AttestationHooks {
if (sIsGms && isCallerSafetyNet()) {
throw new UnsupportedOperationException();
}
+
+ // Check stack for PlayIntegrity
+ if (sIsFinsky) {
+ throw new UnsupportedOperationException();
+ }
}
}
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Dyneteve <dyneteve@hentaios.com>
Date: Thu, 8 Sep 2022 14:39:52 +0200
Subject: [PATCH 6/8] gmscompat: Use Nexus 6P fingerprint for CTS/Integrity
Google seems to have patched the KM block to Play Store in record time,
but is still not enforced for anything under android N.
Since we moved to angler FP we don't need to spoof model to Play Store
anymore, however the KM block is still needed.
Test: Run Play Intregrity Attestation
Change-Id: Ic2401a6e40ddfc4318a1d0faa87e42eb118ac3d1
---
.../java/com/android/internal/gmscompat/AttestationHooks.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/core/java/com/android/internal/gmscompat/AttestationHooks.java b/core/java/com/android/internal/gmscompat/AttestationHooks.java
index 6a4aab000fe0..6bd12a1c1e03 100644
--- a/core/java/com/android/internal/gmscompat/AttestationHooks.java
+++ b/core/java/com/android/internal/gmscompat/AttestationHooks.java
@@ -69,7 +69,8 @@ public final class AttestationHooks {
}
private static void spoofBuildGms() {
- // Alter model name to avoid hardware attestation enforcement
+ // Alter model name and fingerprint to avoid hardware attestation enforcement
+ setBuildField("FINGERPRINT", "google/angler/angler:6.0/MDB08L/2343525:user/release-keys");
setBuildField("MODEL", Build.MODEL + " ");
if (Build.VERSION.DEVICE_INITIAL_SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
setVersionField("DEVICE_INITIAL_SDK_INT", Build.VERSION_CODES.S_V2);
@@ -85,7 +86,6 @@ public final class AttestationHooks {
if (PACKAGE_FINSKY.equals(app.getPackageName())) {
sIsFinsky = true;
- spoofBuildGms();
}
}
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Dyneteve <dyneteve@hentaios.com>
Date: Wed, 8 Feb 2023 15:21:01 +0000
Subject: [PATCH 7/8] gmscompat: Make CTS/Play Integrity pass again
The logic behind CTS and Play Integrity has been updated today it now
checks the product and model names against the fingerprint and if
they do not match the CTS profile will fail.
Also while we are at it use a newer FP from Pixel XL and add logging
for key attestation blocking for debugging.
Test: Boot, check for CTS and Play Integrity
Change-Id: I089d5ef935bba40338e10c795ea7d181103ffd15
---
.../internal/gmscompat/AttestationHooks.java | 22 ++++++++-----------
1 file changed, 9 insertions(+), 13 deletions(-)
diff --git a/core/java/com/android/internal/gmscompat/AttestationHooks.java b/core/java/com/android/internal/gmscompat/AttestationHooks.java
index 6bd12a1c1e03..b10cb04cb4f3 100644
--- a/core/java/com/android/internal/gmscompat/AttestationHooks.java
+++ b/core/java/com/android/internal/gmscompat/AttestationHooks.java
@@ -70,11 +70,11 @@ public final class AttestationHooks {
private static void spoofBuildGms() {
// Alter model name and fingerprint to avoid hardware attestation enforcement
- setBuildField("FINGERPRINT", "google/angler/angler:6.0/MDB08L/2343525:user/release-keys");
- setBuildField("MODEL", Build.MODEL + " ");
- if (Build.VERSION.DEVICE_INITIAL_SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
- setVersionField("DEVICE_INITIAL_SDK_INT", Build.VERSION_CODES.S_V2);
- }
+ setBuildField("FINGERPRINT", "google/marlin/marlin:7.1.2/NJH47F/4146041:user/release-keys");
+ setBuildField("PRODUCT", "marlin");
+ setBuildField("DEVICE", "marlin");
+ setBuildField("MODEL", "Pixel XL");
+ setVersionField("DEVICE_INITIAL_SDK_INT", Build.VERSION_CODES.N_MR1);
}
public static void initApplicationBeforeOnCreate(Application app) {
@@ -90,18 +90,14 @@ public final class AttestationHooks {
}
private static boolean isCallerSafetyNet() {
- return Arrays.stream(Thread.currentThread().getStackTrace())
+ return sIsGms && Arrays.stream(Thread.currentThread().getStackTrace())
.anyMatch(elem -> elem.getClassName().contains("DroidGuard"));
}
public static void onEngineGetCertificateChain() {
- // Check stack for SafetyNet
- if (sIsGms && isCallerSafetyNet()) {
- throw new UnsupportedOperationException();
- }
-
- // Check stack for PlayIntegrity
- if (sIsFinsky) {
+ // Check stack for SafetyNet or Play Integrity
+ if (isCallerSafetyNet() || sIsFinsky) {
+ Log.i(TAG, "Blocked key attestation sIsGms=" + sIsGms + " sIsFinsky=" + sIsFinsky);
throw new UnsupportedOperationException();
}
}
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Davide Garberi <dade.garberi@gmail.com>
Date: Wed, 8 Nov 2023 21:36:02 +0100
Subject: [PATCH 8/8] gmscompat: Use new info
Change-Id: I3cb0c55d28249b73ecc53be83bed030304c782d9
---
.../android/internal/gmscompat/AttestationHooks.java | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/core/java/com/android/internal/gmscompat/AttestationHooks.java b/core/java/com/android/internal/gmscompat/AttestationHooks.java
index b10cb04cb4f3..04a536d8073d 100644
--- a/core/java/com/android/internal/gmscompat/AttestationHooks.java
+++ b/core/java/com/android/internal/gmscompat/AttestationHooks.java
@@ -70,11 +70,11 @@ public final class AttestationHooks {
private static void spoofBuildGms() {
// Alter model name and fingerprint to avoid hardware attestation enforcement
- setBuildField("FINGERPRINT", "google/marlin/marlin:7.1.2/NJH47F/4146041:user/release-keys");
- setBuildField("PRODUCT", "marlin");
- setBuildField("DEVICE", "marlin");
- setBuildField("MODEL", "Pixel XL");
- setVersionField("DEVICE_INITIAL_SDK_INT", Build.VERSION_CODES.N_MR1);
+ setBuildField("DEVICE", "bullhead");
+ setBuildField("FINGERPRINT", "google/bullhead/bullhead:8.0.0/OPR6.170623.013/4283548:user/release-keys");
+ setBuildField("MODEL", "Nexus 5X");
+ setBuildField("PRODUCT", "bullhead");
+ setVersionField("DEVICE_INITIAL_SDK_INT", Build.VERSION_CODES.N);
}
public static void initApplicationBeforeOnCreate(Application app) {

View File

@ -0,0 +1,59 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Danny Lin <danny@kdrag0n.dev>
Date: Wed, 7 Oct 2020 00:24:54 -0700
Subject: [PATCH] init: Set properties to make SafetyNet pass
Google's SafetyNet integrity checks will check the values of these
properties when performing basic attestation. Setting fake values helps
us pass basic SafetyNet with no Magisk Hide or kernel patches necessary.
Note that these properties need to be set very early, before parsing the
kernel command-line, as they are read-only properties that the bootloader
sets using androidboot kernel arguments. The bootloader's real values
cause SafetyNet to fail with an unlocked bootloader and/or custom
software because the verified boot chain is broken in that case.
Change-Id: I66d23fd91d82906b00d5eb020668f01ae83ec31f
- Also don't set these in recovery
Change-Id: I57f6d48acddb29748778053edf354d7bd8994bd7
---
init/property_service.cpp | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/init/property_service.cpp b/init/property_service.cpp
index f47c93596..6c404de62 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -101,6 +101,15 @@ struct PropertyAuditData {
const char* name;
};
+static void SetSafetyNetProps() {
+ InitPropertySet("ro.boot.flash.locked", "1");
+ InitPropertySet("ro.boot.verifiedbootstate", "green");
+ InitPropertySet("ro.boot.veritymode", "enforcing");
+ InitPropertySet("ro.boot.vbmeta.device_state", "locked");
+ InitPropertySet("ro.boot.warranty_bit", "0");
+ InitPropertySet("ro.warranty_bit", "0");
+}
+
void property_init() {
mkdir("/dev/__properties__", S_IRWXU | S_IXGRP | S_IXOTH);
CreateSerializedPropertyInfo();
@@ -110,6 +119,14 @@ void property_init() {
if (!property_info_area.LoadDefaultPath()) {
LOG(FATAL) << "Failed to load serialized property info file";
}
+
+ // Report a valid verified boot chain to make Google SafetyNet integrity
+ // checks pass. This needs to be done before parsing the kernel cmdline as
+ // these properties are read-only and will be set to invalid values with
+ // androidboot cmdline arguments.
+ if (!IsRecoveryMode()) {
+ SetSafetyNetProps();
+ }
}
static bool CheckMacPerms(const std::string& name, const char* target_context,
const char* source_context, const ucred& cr) {

View File

@ -0,0 +1,511 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Danny Lin <danny@kdrag0n.dev>
Date: Mon, 11 Oct 2021 19:59:51 -0700
Subject: [PATCH 1/8] Alter model name to avoid SafetyNet HW attestation
enforcement
As of September 2, Google is enforcing SafetyNet's previously
opportunistic hardware-backed attestation based on device information.
Append a space to the device model name in order to avoid such
enforcement.
Also contains:
Spoof build fingerprint for Google Play Services
SafetyNet's CTS profile attestation checks whether Build.FINGERPRINT
matches that of the device's stock OS, which has passed CTS testing.
Spoof the fingerprint for Google Play Services to help pass SafetyNet.
We used to set the real system build fingerprint to the stock one, but
Android relies on each build having a unique fingerprint in order to
clear the correct caches and update persistent state for system changes.
On devices that no longer receive updates from the OEM, the build
fingerprint never changes and Android doesn't account for updates
correctly, which causes issues when updating without wiping data.
Only spoofing the fingerprint for Google Play Services fixes this issue.
Corresponding vendor commit:
"Only use stock build fingerprint for Google Play Services"
NB: This code is under the gmscompat package, but it does not depend on
any code from gmscompat.
Change-Id: I26a2498eb2e2163933303b03f6d516e5fb30fe51
* We don't need to spoof the fingerprint here since we do it globally, but we
use the Build field spoofing code it added for model
Change-Id: Ib7779e0aae40cab3730a56785e9231896917ab0a
---
core/java/android/app/Instrumentation.java | 4 ++
.../internal/gmscompat/AttestationHooks.java | 59 +++++++++++++++++++
2 files changed, 63 insertions(+)
create mode 100644 core/java/com/android/internal/gmscompat/AttestationHooks.java
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 9720e9f47f83..e19f3fc4db85 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -57,6 +57,8 @@ import android.view.WindowManagerGlobal;
import com.android.internal.content.ReferrerIntent;
+import com.android.internal.gmscompat.AttestationHooks;
+
import java.io.File;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -1154,6 +1156,7 @@ public class Instrumentation {
Application app = getFactory(context.getPackageName())
.instantiateApplication(cl, className);
app.attach(context);
+ AttestationHooks.initApplicationBeforeOnCreate(app);
return app;
}
@@ -1171,6 +1174,7 @@ public class Instrumentation {
ClassNotFoundException {
Application app = (Application)clazz.newInstance();
app.attach(context);
+ AttestationHooks.initApplicationBeforeOnCreate(app);
return app;
}
diff --git a/core/java/com/android/internal/gmscompat/AttestationHooks.java b/core/java/com/android/internal/gmscompat/AttestationHooks.java
new file mode 100644
index 000000000000..621156eb84b9
--- /dev/null
+++ b/core/java/com/android/internal/gmscompat/AttestationHooks.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.gmscompat;
+
+import android.app.Application;
+import android.os.Build;
+import android.os.SystemProperties;
+import android.util.Log;
+
+import java.lang.reflect.Field;
+
+/** @hide */
+public final class AttestationHooks {
+ private static final String TAG = "GmsCompat/Attestation";
+ private static final String PACKAGE_GMS = "com.google.android.gms";
+
+ private AttestationHooks() { }
+
+ private static void setBuildField(String key, String value) {
+ try {
+ // Unlock
+ Field field = Build.class.getDeclaredField(key);
+ field.setAccessible(true);
+
+ // Edit
+ field.set(null, value);
+
+ // Lock
+ field.setAccessible(false);
+ } catch (NoSuchFieldException | IllegalAccessException e) {
+ Log.e(TAG, "Failed to spoof Build." + key, e);
+ }
+ }
+
+ private static void spoofBuildGms() {
+ // Alter model name to avoid hardware attestation enforcement
+ setBuildField("MODEL", Build.MODEL + " ");
+ }
+
+ public static void initApplicationBeforeOnCreate(Application app) {
+ if (PACKAGE_GMS.equals(app.getPackageName())) {
+ spoofBuildGms();
+ }
+ }
+}
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Danny Lin <danny@kdrag0n.dev>
Date: Mon, 11 Oct 2021 20:00:44 -0700
Subject: [PATCH 2/8] keystore: Block key attestation for SafetyNet
SafetyNet (part of Google Play Services) opportunistically uses
hardware-backed key attestation via KeyStore as a strong integrity
check. This causes SafetyNet to fail on custom ROMs because the verified
boot key and bootloader unlock state can be detected from attestation
certificates.
As a workaround, we can take advantage of the fact that SafetyNet's
usage of key attestation is opportunistic (i.e. falls back to basic
integrity checks if it fails) and prevent it from getting the
attestation certificate chain from KeyStore. This is done by checking
the stack for DroidGuard, which is the codename for SafetyNet, and
pretending that the device doesn't support key attestation.
Key attestation has only been blocked for SafetyNet specifically, as
Google Play Services and other apps have many valid reasons to use it.
For example, it appears to be involved in Google's mobile security key
ferature.
Change-Id: I5146439d47f42dc6231cb45c4dab9f61540056f6
---
.../internal/gmscompat/AttestationHooks.java | 16 ++++++++++++++++
.../security/keystore/AndroidKeyStoreSpi.java | 4 ++++
2 files changed, 20 insertions(+)
diff --git a/core/java/com/android/internal/gmscompat/AttestationHooks.java b/core/java/com/android/internal/gmscompat/AttestationHooks.java
index 621156eb84b9..fe12dfe02a9f 100644
--- a/core/java/com/android/internal/gmscompat/AttestationHooks.java
+++ b/core/java/com/android/internal/gmscompat/AttestationHooks.java
@@ -22,12 +22,15 @@ import android.os.SystemProperties;
import android.util.Log;
import java.lang.reflect.Field;
+import java.util.Arrays;
/** @hide */
public final class AttestationHooks {
private static final String TAG = "GmsCompat/Attestation";
private static final String PACKAGE_GMS = "com.google.android.gms";
+ private static volatile boolean sIsGms = false;
+
private AttestationHooks() { }
private static void setBuildField(String key, String value) {
@@ -53,7 +56,20 @@ public final class AttestationHooks {
public static void initApplicationBeforeOnCreate(Application app) {
if (PACKAGE_GMS.equals(app.getPackageName())) {
+ sIsGms = true;
spoofBuildGms();
}
}
+
+ private static boolean isCallerSafetyNet() {
+ return Arrays.stream(Thread.currentThread().getStackTrace())
+ .anyMatch(elem -> elem.getClassName().contains("DroidGuard"));
+ }
+
+ public static void onEngineGetCertificateChain() {
+ // Check stack for SafetyNet
+ if (sIsGms && isCallerSafetyNet()) {
+ throw new UnsupportedOperationException();
+ }
+ }
}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
index 51c42520ccc9..b77ddc711492 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
@@ -30,6 +30,8 @@ import android.security.keystore.SecureKeyImportUnavailableException;
import android.security.keystore.WrappedKeyEntry;
import android.util.Log;
+import com.android.internal.gmscompat.AttestationHooks;
+
import libcore.util.EmptyArray;
import java.io.ByteArrayInputStream;
@@ -113,6 +115,8 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi {
@Override
public Certificate[] engineGetCertificateChain(String alias) {
+ AttestationHooks.onEngineGetCertificateChain();
+
if (alias == null) {
throw new NullPointerException("alias == null");
}
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Anirudh Gupta <anirudhgupta109@aosip.dev>
Date: Wed, 4 Jan 2023 18:20:56 +0000
Subject: [PATCH 3/8] AttestationHooks: Set shipping level to 32 for devices
>=33
If ro.product.first_api_level is 33, it's forced to use HW attestation.
Setting it to 32 allows for software attestation and passing CTS.
Change-Id: Ie47fd00b009c93580ec8c950d223c60ed63a0d2f
---
.../internal/gmscompat/AttestationHooks.java | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/core/java/com/android/internal/gmscompat/AttestationHooks.java b/core/java/com/android/internal/gmscompat/AttestationHooks.java
index fe12dfe02a9f..f512adc3985b 100644
--- a/core/java/com/android/internal/gmscompat/AttestationHooks.java
+++ b/core/java/com/android/internal/gmscompat/AttestationHooks.java
@@ -49,9 +49,28 @@ public final class AttestationHooks {
}
}
+ private static void setVersionField(String key, Integer value) {
+ try {
+ // Unlock
+ Field field = Build.VERSION.class.getDeclaredField(key);
+ field.setAccessible(true);
+
+ // Edit
+ field.set(null, value);
+
+ // Lock
+ field.setAccessible(false);
+ } catch (NoSuchFieldException | IllegalAccessException e) {
+ Log.e(TAG, "Failed to spoof Build.VERSION." + key, e);
+ }
+ }
+
private static void spoofBuildGms() {
// Alter model name to avoid hardware attestation enforcement
setBuildField("MODEL", Build.MODEL + " ");
+ if (Build.VERSION.DEVICE_INITIAL_SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ setVersionField("DEVICE_INITIAL_SDK_INT", Build.VERSION_CODES.S_V2);
+ }
}
public static void initApplicationBeforeOnCreate(Application app) {
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Danny Lin <danny@kdrag0n.dev>
Date: Mon, 1 Nov 2021 20:06:48 -0700
Subject: [PATCH 4/8] Limit SafetyNet workarounds to unstable GMS process
The unstable process is where SafetyNet attestation actually runs, so
we only need to spoof the model in that process. Leaving other processes
fixes various issues caused by model detection and flag provisioning,
including screen-off Voice Match in Google Assistant, broken At a Glance
weather and settings on Android 12, and more.
Change-Id: Idcf663907a6c3d0408dbd45b1ac53c9eb4200df8
---
.../java/com/android/internal/gmscompat/AttestationHooks.java | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/core/java/com/android/internal/gmscompat/AttestationHooks.java b/core/java/com/android/internal/gmscompat/AttestationHooks.java
index f512adc3985b..c1021dd2eb22 100644
--- a/core/java/com/android/internal/gmscompat/AttestationHooks.java
+++ b/core/java/com/android/internal/gmscompat/AttestationHooks.java
@@ -28,6 +28,7 @@ import java.util.Arrays;
public final class AttestationHooks {
private static final String TAG = "GmsCompat/Attestation";
private static final String PACKAGE_GMS = "com.google.android.gms";
+ private static final String PROCESS_UNSTABLE = "com.google.android.gms.unstable";
private static volatile boolean sIsGms = false;
@@ -74,7 +75,8 @@ public final class AttestationHooks {
}
public static void initApplicationBeforeOnCreate(Application app) {
- if (PACKAGE_GMS.equals(app.getPackageName())) {
+ if (PACKAGE_GMS.equals(app.getPackageName()) &&
+ PROCESS_UNSTABLE.equals(Application.getProcessName())) {
sIsGms = true;
spoofBuildGms();
}
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Dyneteve <dyneteve@hentaios.com>
Date: Tue, 23 Aug 2022 18:57:05 +0200
Subject: [PATCH 5/8] gmscompat: Apply the SafetyNet workaround to Play Store
aswell
Play Store is used for the new Play Integrity API, extend the hack
to it aswell
Test: Device Integrity and Basic Integrity passes.
Change-Id: Id607cdff0b902f285a6c1b769c0a4ee4202842b1
---
.../android/internal/gmscompat/AttestationHooks.java | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/core/java/com/android/internal/gmscompat/AttestationHooks.java b/core/java/com/android/internal/gmscompat/AttestationHooks.java
index c1021dd2eb22..6a4aab000fe0 100644
--- a/core/java/com/android/internal/gmscompat/AttestationHooks.java
+++ b/core/java/com/android/internal/gmscompat/AttestationHooks.java
@@ -28,9 +28,11 @@ import java.util.Arrays;
public final class AttestationHooks {
private static final String TAG = "GmsCompat/Attestation";
private static final String PACKAGE_GMS = "com.google.android.gms";
+ private static final String PACKAGE_FINSKY = "com.android.vending";
private static final String PROCESS_UNSTABLE = "com.google.android.gms.unstable";
private static volatile boolean sIsGms = false;
+ private static volatile boolean sIsFinsky = false;
private AttestationHooks() { }
@@ -80,6 +82,11 @@ public final class AttestationHooks {
sIsGms = true;
spoofBuildGms();
}
+
+ if (PACKAGE_FINSKY.equals(app.getPackageName())) {
+ sIsFinsky = true;
+ spoofBuildGms();
+ }
}
private static boolean isCallerSafetyNet() {
@@ -92,5 +99,10 @@ public final class AttestationHooks {
if (sIsGms && isCallerSafetyNet()) {
throw new UnsupportedOperationException();
}
+
+ // Check stack for PlayIntegrity
+ if (sIsFinsky) {
+ throw new UnsupportedOperationException();
+ }
}
}
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Dyneteve <dyneteve@hentaios.com>
Date: Thu, 8 Sep 2022 14:39:52 +0200
Subject: [PATCH 6/8] gmscompat: Use Nexus 6P fingerprint for CTS/Integrity
Google seems to have patched the KM block to Play Store in record time,
but is still not enforced for anything under android N.
Since we moved to angler FP we don't need to spoof model to Play Store
anymore, however the KM block is still needed.
Test: Run Play Intregrity Attestation
Change-Id: Ic2401a6e40ddfc4318a1d0faa87e42eb118ac3d1
---
.../java/com/android/internal/gmscompat/AttestationHooks.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/core/java/com/android/internal/gmscompat/AttestationHooks.java b/core/java/com/android/internal/gmscompat/AttestationHooks.java
index 6a4aab000fe0..6bd12a1c1e03 100644
--- a/core/java/com/android/internal/gmscompat/AttestationHooks.java
+++ b/core/java/com/android/internal/gmscompat/AttestationHooks.java
@@ -69,7 +69,8 @@ public final class AttestationHooks {
}
private static void spoofBuildGms() {
- // Alter model name to avoid hardware attestation enforcement
+ // Alter model name and fingerprint to avoid hardware attestation enforcement
+ setBuildField("FINGERPRINT", "google/angler/angler:6.0/MDB08L/2343525:user/release-keys");
setBuildField("MODEL", Build.MODEL + " ");
if (Build.VERSION.DEVICE_INITIAL_SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
setVersionField("DEVICE_INITIAL_SDK_INT", Build.VERSION_CODES.S_V2);
@@ -85,7 +86,6 @@ public final class AttestationHooks {
if (PACKAGE_FINSKY.equals(app.getPackageName())) {
sIsFinsky = true;
- spoofBuildGms();
}
}
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Dyneteve <dyneteve@hentaios.com>
Date: Wed, 8 Feb 2023 15:21:01 +0000
Subject: [PATCH 7/8] gmscompat: Make CTS/Play Integrity pass again
The logic behind CTS and Play Integrity has been updated today it now
checks the product and model names against the fingerprint and if
they do not match the CTS profile will fail.
Also while we are at it use a newer FP from Pixel XL and add logging
for key attestation blocking for debugging.
Test: Boot, check for CTS and Play Integrity
Change-Id: I089d5ef935bba40338e10c795ea7d181103ffd15
---
.../internal/gmscompat/AttestationHooks.java | 22 ++++++++-----------
1 file changed, 9 insertions(+), 13 deletions(-)
diff --git a/core/java/com/android/internal/gmscompat/AttestationHooks.java b/core/java/com/android/internal/gmscompat/AttestationHooks.java
index 6bd12a1c1e03..b10cb04cb4f3 100644
--- a/core/java/com/android/internal/gmscompat/AttestationHooks.java
+++ b/core/java/com/android/internal/gmscompat/AttestationHooks.java
@@ -70,11 +70,11 @@ public final class AttestationHooks {
private static void spoofBuildGms() {
// Alter model name and fingerprint to avoid hardware attestation enforcement
- setBuildField("FINGERPRINT", "google/angler/angler:6.0/MDB08L/2343525:user/release-keys");
- setBuildField("MODEL", Build.MODEL + " ");
- if (Build.VERSION.DEVICE_INITIAL_SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
- setVersionField("DEVICE_INITIAL_SDK_INT", Build.VERSION_CODES.S_V2);
- }
+ setBuildField("FINGERPRINT", "google/marlin/marlin:7.1.2/NJH47F/4146041:user/release-keys");
+ setBuildField("PRODUCT", "marlin");
+ setBuildField("DEVICE", "marlin");
+ setBuildField("MODEL", "Pixel XL");
+ setVersionField("DEVICE_INITIAL_SDK_INT", Build.VERSION_CODES.N_MR1);
}
public static void initApplicationBeforeOnCreate(Application app) {
@@ -90,18 +90,14 @@ public final class AttestationHooks {
}
private static boolean isCallerSafetyNet() {
- return Arrays.stream(Thread.currentThread().getStackTrace())
+ return sIsGms && Arrays.stream(Thread.currentThread().getStackTrace())
.anyMatch(elem -> elem.getClassName().contains("DroidGuard"));
}
public static void onEngineGetCertificateChain() {
- // Check stack for SafetyNet
- if (sIsGms && isCallerSafetyNet()) {
- throw new UnsupportedOperationException();
- }
-
- // Check stack for PlayIntegrity
- if (sIsFinsky) {
+ // Check stack for SafetyNet or Play Integrity
+ if (isCallerSafetyNet() || sIsFinsky) {
+ Log.i(TAG, "Blocked key attestation sIsGms=" + sIsGms + " sIsFinsky=" + sIsFinsky);
throw new UnsupportedOperationException();
}
}
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Davide Garberi <dade.garberi@gmail.com>
Date: Wed, 8 Nov 2023 21:36:02 +0100
Subject: [PATCH 8/8] gmscompat: Use new info
Change-Id: I3cb0c55d28249b73ecc53be83bed030304c782d9
---
.../android/internal/gmscompat/AttestationHooks.java | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/core/java/com/android/internal/gmscompat/AttestationHooks.java b/core/java/com/android/internal/gmscompat/AttestationHooks.java
index b10cb04cb4f3..04a536d8073d 100644
--- a/core/java/com/android/internal/gmscompat/AttestationHooks.java
+++ b/core/java/com/android/internal/gmscompat/AttestationHooks.java
@@ -70,11 +70,11 @@ public final class AttestationHooks {
private static void spoofBuildGms() {
// Alter model name and fingerprint to avoid hardware attestation enforcement
- setBuildField("FINGERPRINT", "google/marlin/marlin:7.1.2/NJH47F/4146041:user/release-keys");
- setBuildField("PRODUCT", "marlin");
- setBuildField("DEVICE", "marlin");
- setBuildField("MODEL", "Pixel XL");
- setVersionField("DEVICE_INITIAL_SDK_INT", Build.VERSION_CODES.N_MR1);
+ setBuildField("DEVICE", "bullhead");
+ setBuildField("FINGERPRINT", "google/bullhead/bullhead:8.0.0/OPR6.170623.013/4283548:user/release-keys");
+ setBuildField("MODEL", "Nexus 5X");
+ setBuildField("PRODUCT", "bullhead");
+ setVersionField("DEVICE_INITIAL_SDK_INT", Build.VERSION_CODES.N);
}
public static void initApplicationBeforeOnCreate(Application app) {

View File

@ -0,0 +1,59 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Danny Lin <danny@kdrag0n.dev>
Date: Wed, 7 Oct 2020 00:24:54 -0700
Subject: [PATCH] init: Set properties to make SafetyNet pass
Google's SafetyNet integrity checks will check the values of these
properties when performing basic attestation. Setting fake values helps
us pass basic SafetyNet with no Magisk Hide or kernel patches necessary.
Note that these properties need to be set very early, before parsing the
kernel command-line, as they are read-only properties that the bootloader
sets using androidboot kernel arguments. The bootloader's real values
cause SafetyNet to fail with an unlocked bootloader and/or custom
software because the verified boot chain is broken in that case.
Change-Id: I66d23fd91d82906b00d5eb020668f01ae83ec31f
- Also don't set these in recovery
Change-Id: I57f6d48acddb29748778053edf354d7bd8994bd7
---
init/property_service.cpp | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 65e9cda1c..7be56d0db 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -117,6 +117,15 @@ static int PropertyAuditCallback(void* data, security_class_t /*cls*/, char* buf
return 0;
}
+static void SetSafetyNetProps() {
+ InitPropertySet("ro.boot.flash.locked", "1");
+ InitPropertySet("ro.boot.verifiedbootstate", "green");
+ InitPropertySet("ro.boot.veritymode", "enforcing");
+ InitPropertySet("ro.boot.vbmeta.device_state", "locked");
+ InitPropertySet("ro.boot.warranty_bit", "0");
+ InitPropertySet("ro.warranty_bit", "0");
+}
+
void property_init() {
selinux_callback cb;
cb.func_audit = PropertyAuditCallback;
@@ -130,6 +139,14 @@ void property_init() {
if (!property_info_area.LoadDefaultPath()) {
LOG(FATAL) << "Failed to load serialized property info file";
}
+
+ // Report a valid verified boot chain to make Google SafetyNet integrity
+ // checks pass. This needs to be done before parsing the kernel cmdline as
+ // these properties are read-only and will be set to invalid values with
+ // androidboot cmdline arguments.
+ if (!IsRecoveryMode()) {
+ SetSafetyNetProps();
+ }
}
bool CanReadProperty(const std::string& source_context, const std::string& name) {

View File

@ -0,0 +1,511 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Danny Lin <danny@kdrag0n.dev>
Date: Mon, 11 Oct 2021 19:59:51 -0700
Subject: [PATCH 1/8] Alter model name to avoid SafetyNet HW attestation
enforcement
As of September 2, Google is enforcing SafetyNet's previously
opportunistic hardware-backed attestation based on device information.
Append a space to the device model name in order to avoid such
enforcement.
Also contains:
Spoof build fingerprint for Google Play Services
SafetyNet's CTS profile attestation checks whether Build.FINGERPRINT
matches that of the device's stock OS, which has passed CTS testing.
Spoof the fingerprint for Google Play Services to help pass SafetyNet.
We used to set the real system build fingerprint to the stock one, but
Android relies on each build having a unique fingerprint in order to
clear the correct caches and update persistent state for system changes.
On devices that no longer receive updates from the OEM, the build
fingerprint never changes and Android doesn't account for updates
correctly, which causes issues when updating without wiping data.
Only spoofing the fingerprint for Google Play Services fixes this issue.
Corresponding vendor commit:
"Only use stock build fingerprint for Google Play Services"
NB: This code is under the gmscompat package, but it does not depend on
any code from gmscompat.
Change-Id: I26a2498eb2e2163933303b03f6d516e5fb30fe51
* We don't need to spoof the fingerprint here since we do it globally, but we
use the Build field spoofing code it added for model
Change-Id: Ib7779e0aae40cab3730a56785e9231896917ab0a
---
core/java/android/app/Instrumentation.java | 4 ++
.../internal/gmscompat/AttestationHooks.java | 59 +++++++++++++++++++
2 files changed, 63 insertions(+)
create mode 100644 core/java/com/android/internal/gmscompat/AttestationHooks.java
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 721525d9af9d..09dcad811d4d 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -57,6 +57,8 @@ import android.view.WindowManagerGlobal;
import com.android.internal.content.ReferrerIntent;
+import com.android.internal.gmscompat.AttestationHooks;
+
import java.io.File;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -1157,6 +1159,7 @@ public class Instrumentation {
Application app = getFactory(context.getPackageName())
.instantiateApplication(cl, className);
app.attach(context);
+ AttestationHooks.initApplicationBeforeOnCreate(app);
return app;
}
@@ -1174,6 +1177,7 @@ public class Instrumentation {
ClassNotFoundException {
Application app = (Application)clazz.newInstance();
app.attach(context);
+ AttestationHooks.initApplicationBeforeOnCreate(app);
return app;
}
diff --git a/core/java/com/android/internal/gmscompat/AttestationHooks.java b/core/java/com/android/internal/gmscompat/AttestationHooks.java
new file mode 100644
index 000000000000..621156eb84b9
--- /dev/null
+++ b/core/java/com/android/internal/gmscompat/AttestationHooks.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.gmscompat;
+
+import android.app.Application;
+import android.os.Build;
+import android.os.SystemProperties;
+import android.util.Log;
+
+import java.lang.reflect.Field;
+
+/** @hide */
+public final class AttestationHooks {
+ private static final String TAG = "GmsCompat/Attestation";
+ private static final String PACKAGE_GMS = "com.google.android.gms";
+
+ private AttestationHooks() { }
+
+ private static void setBuildField(String key, String value) {
+ try {
+ // Unlock
+ Field field = Build.class.getDeclaredField(key);
+ field.setAccessible(true);
+
+ // Edit
+ field.set(null, value);
+
+ // Lock
+ field.setAccessible(false);
+ } catch (NoSuchFieldException | IllegalAccessException e) {
+ Log.e(TAG, "Failed to spoof Build." + key, e);
+ }
+ }
+
+ private static void spoofBuildGms() {
+ // Alter model name to avoid hardware attestation enforcement
+ setBuildField("MODEL", Build.MODEL + " ");
+ }
+
+ public static void initApplicationBeforeOnCreate(Application app) {
+ if (PACKAGE_GMS.equals(app.getPackageName())) {
+ spoofBuildGms();
+ }
+ }
+}
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Danny Lin <danny@kdrag0n.dev>
Date: Mon, 11 Oct 2021 20:00:44 -0700
Subject: [PATCH 2/8] keystore: Block key attestation for SafetyNet
SafetyNet (part of Google Play Services) opportunistically uses
hardware-backed key attestation via KeyStore as a strong integrity
check. This causes SafetyNet to fail on custom ROMs because the verified
boot key and bootloader unlock state can be detected from attestation
certificates.
As a workaround, we can take advantage of the fact that SafetyNet's
usage of key attestation is opportunistic (i.e. falls back to basic
integrity checks if it fails) and prevent it from getting the
attestation certificate chain from KeyStore. This is done by checking
the stack for DroidGuard, which is the codename for SafetyNet, and
pretending that the device doesn't support key attestation.
Key attestation has only been blocked for SafetyNet specifically, as
Google Play Services and other apps have many valid reasons to use it.
For example, it appears to be involved in Google's mobile security key
ferature.
Change-Id: I5146439d47f42dc6231cb45c4dab9f61540056f6
---
.../internal/gmscompat/AttestationHooks.java | 16 ++++++++++++++++
.../security/keystore/AndroidKeyStoreSpi.java | 4 ++++
2 files changed, 20 insertions(+)
diff --git a/core/java/com/android/internal/gmscompat/AttestationHooks.java b/core/java/com/android/internal/gmscompat/AttestationHooks.java
index 621156eb84b9..fe12dfe02a9f 100644
--- a/core/java/com/android/internal/gmscompat/AttestationHooks.java
+++ b/core/java/com/android/internal/gmscompat/AttestationHooks.java
@@ -22,12 +22,15 @@ import android.os.SystemProperties;
import android.util.Log;
import java.lang.reflect.Field;
+import java.util.Arrays;
/** @hide */
public final class AttestationHooks {
private static final String TAG = "GmsCompat/Attestation";
private static final String PACKAGE_GMS = "com.google.android.gms";
+ private static volatile boolean sIsGms = false;
+
private AttestationHooks() { }
private static void setBuildField(String key, String value) {
@@ -53,7 +56,20 @@ public final class AttestationHooks {
public static void initApplicationBeforeOnCreate(Application app) {
if (PACKAGE_GMS.equals(app.getPackageName())) {
+ sIsGms = true;
spoofBuildGms();
}
}
+
+ private static boolean isCallerSafetyNet() {
+ return Arrays.stream(Thread.currentThread().getStackTrace())
+ .anyMatch(elem -> elem.getClassName().contains("DroidGuard"));
+ }
+
+ public static void onEngineGetCertificateChain() {
+ // Check stack for SafetyNet
+ if (sIsGms && isCallerSafetyNet()) {
+ throw new UnsupportedOperationException();
+ }
+ }
}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
index 51c42520ccc9..b77ddc711492 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
@@ -30,6 +30,8 @@ import android.security.keystore.SecureKeyImportUnavailableException;
import android.security.keystore.WrappedKeyEntry;
import android.util.Log;
+import com.android.internal.gmscompat.AttestationHooks;
+
import libcore.util.EmptyArray;
import java.io.ByteArrayInputStream;
@@ -113,6 +115,8 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi {
@Override
public Certificate[] engineGetCertificateChain(String alias) {
+ AttestationHooks.onEngineGetCertificateChain();
+
if (alias == null) {
throw new NullPointerException("alias == null");
}
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Anirudh Gupta <anirudhgupta109@aosip.dev>
Date: Wed, 4 Jan 2023 18:20:56 +0000
Subject: [PATCH 3/8] AttestationHooks: Set shipping level to 32 for devices
>=33
If ro.product.first_api_level is 33, it's forced to use HW attestation.
Setting it to 32 allows for software attestation and passing CTS.
Change-Id: Ie47fd00b009c93580ec8c950d223c60ed63a0d2f
---
.../internal/gmscompat/AttestationHooks.java | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/core/java/com/android/internal/gmscompat/AttestationHooks.java b/core/java/com/android/internal/gmscompat/AttestationHooks.java
index fe12dfe02a9f..f512adc3985b 100644
--- a/core/java/com/android/internal/gmscompat/AttestationHooks.java
+++ b/core/java/com/android/internal/gmscompat/AttestationHooks.java
@@ -49,9 +49,28 @@ public final class AttestationHooks {
}
}
+ private static void setVersionField(String key, Integer value) {
+ try {
+ // Unlock
+ Field field = Build.VERSION.class.getDeclaredField(key);
+ field.setAccessible(true);
+
+ // Edit
+ field.set(null, value);
+
+ // Lock
+ field.setAccessible(false);
+ } catch (NoSuchFieldException | IllegalAccessException e) {
+ Log.e(TAG, "Failed to spoof Build.VERSION." + key, e);
+ }
+ }
+
private static void spoofBuildGms() {
// Alter model name to avoid hardware attestation enforcement
setBuildField("MODEL", Build.MODEL + " ");
+ if (Build.VERSION.DEVICE_INITIAL_SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ setVersionField("DEVICE_INITIAL_SDK_INT", Build.VERSION_CODES.S_V2);
+ }
}
public static void initApplicationBeforeOnCreate(Application app) {
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Danny Lin <danny@kdrag0n.dev>
Date: Mon, 1 Nov 2021 20:06:48 -0700
Subject: [PATCH 4/8] Limit SafetyNet workarounds to unstable GMS process
The unstable process is where SafetyNet attestation actually runs, so
we only need to spoof the model in that process. Leaving other processes
fixes various issues caused by model detection and flag provisioning,
including screen-off Voice Match in Google Assistant, broken At a Glance
weather and settings on Android 12, and more.
Change-Id: Idcf663907a6c3d0408dbd45b1ac53c9eb4200df8
---
.../java/com/android/internal/gmscompat/AttestationHooks.java | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/core/java/com/android/internal/gmscompat/AttestationHooks.java b/core/java/com/android/internal/gmscompat/AttestationHooks.java
index f512adc3985b..c1021dd2eb22 100644
--- a/core/java/com/android/internal/gmscompat/AttestationHooks.java
+++ b/core/java/com/android/internal/gmscompat/AttestationHooks.java
@@ -28,6 +28,7 @@ import java.util.Arrays;
public final class AttestationHooks {
private static final String TAG = "GmsCompat/Attestation";
private static final String PACKAGE_GMS = "com.google.android.gms";
+ private static final String PROCESS_UNSTABLE = "com.google.android.gms.unstable";
private static volatile boolean sIsGms = false;
@@ -74,7 +75,8 @@ public final class AttestationHooks {
}
public static void initApplicationBeforeOnCreate(Application app) {
- if (PACKAGE_GMS.equals(app.getPackageName())) {
+ if (PACKAGE_GMS.equals(app.getPackageName()) &&
+ PROCESS_UNSTABLE.equals(Application.getProcessName())) {
sIsGms = true;
spoofBuildGms();
}
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Dyneteve <dyneteve@hentaios.com>
Date: Tue, 23 Aug 2022 18:57:05 +0200
Subject: [PATCH 5/8] gmscompat: Apply the SafetyNet workaround to Play Store
aswell
Play Store is used for the new Play Integrity API, extend the hack
to it aswell
Test: Device Integrity and Basic Integrity passes.
Change-Id: Id607cdff0b902f285a6c1b769c0a4ee4202842b1
---
.../android/internal/gmscompat/AttestationHooks.java | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/core/java/com/android/internal/gmscompat/AttestationHooks.java b/core/java/com/android/internal/gmscompat/AttestationHooks.java
index c1021dd2eb22..6a4aab000fe0 100644
--- a/core/java/com/android/internal/gmscompat/AttestationHooks.java
+++ b/core/java/com/android/internal/gmscompat/AttestationHooks.java
@@ -28,9 +28,11 @@ import java.util.Arrays;
public final class AttestationHooks {
private static final String TAG = "GmsCompat/Attestation";
private static final String PACKAGE_GMS = "com.google.android.gms";
+ private static final String PACKAGE_FINSKY = "com.android.vending";
private static final String PROCESS_UNSTABLE = "com.google.android.gms.unstable";
private static volatile boolean sIsGms = false;
+ private static volatile boolean sIsFinsky = false;
private AttestationHooks() { }
@@ -80,6 +82,11 @@ public final class AttestationHooks {
sIsGms = true;
spoofBuildGms();
}
+
+ if (PACKAGE_FINSKY.equals(app.getPackageName())) {
+ sIsFinsky = true;
+ spoofBuildGms();
+ }
}
private static boolean isCallerSafetyNet() {
@@ -92,5 +99,10 @@ public final class AttestationHooks {
if (sIsGms && isCallerSafetyNet()) {
throw new UnsupportedOperationException();
}
+
+ // Check stack for PlayIntegrity
+ if (sIsFinsky) {
+ throw new UnsupportedOperationException();
+ }
}
}
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Dyneteve <dyneteve@hentaios.com>
Date: Thu, 8 Sep 2022 14:39:52 +0200
Subject: [PATCH 6/8] gmscompat: Use Nexus 6P fingerprint for CTS/Integrity
Google seems to have patched the KM block to Play Store in record time,
but is still not enforced for anything under android N.
Since we moved to angler FP we don't need to spoof model to Play Store
anymore, however the KM block is still needed.
Test: Run Play Intregrity Attestation
Change-Id: Ic2401a6e40ddfc4318a1d0faa87e42eb118ac3d1
---
.../java/com/android/internal/gmscompat/AttestationHooks.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/core/java/com/android/internal/gmscompat/AttestationHooks.java b/core/java/com/android/internal/gmscompat/AttestationHooks.java
index 6a4aab000fe0..6bd12a1c1e03 100644
--- a/core/java/com/android/internal/gmscompat/AttestationHooks.java
+++ b/core/java/com/android/internal/gmscompat/AttestationHooks.java
@@ -69,7 +69,8 @@ public final class AttestationHooks {
}
private static void spoofBuildGms() {
- // Alter model name to avoid hardware attestation enforcement
+ // Alter model name and fingerprint to avoid hardware attestation enforcement
+ setBuildField("FINGERPRINT", "google/angler/angler:6.0/MDB08L/2343525:user/release-keys");
setBuildField("MODEL", Build.MODEL + " ");
if (Build.VERSION.DEVICE_INITIAL_SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
setVersionField("DEVICE_INITIAL_SDK_INT", Build.VERSION_CODES.S_V2);
@@ -85,7 +86,6 @@ public final class AttestationHooks {
if (PACKAGE_FINSKY.equals(app.getPackageName())) {
sIsFinsky = true;
- spoofBuildGms();
}
}
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Dyneteve <dyneteve@hentaios.com>
Date: Wed, 8 Feb 2023 15:21:01 +0000
Subject: [PATCH 7/8] gmscompat: Make CTS/Play Integrity pass again
The logic behind CTS and Play Integrity has been updated today it now
checks the product and model names against the fingerprint and if
they do not match the CTS profile will fail.
Also while we are at it use a newer FP from Pixel XL and add logging
for key attestation blocking for debugging.
Test: Boot, check for CTS and Play Integrity
Change-Id: I089d5ef935bba40338e10c795ea7d181103ffd15
---
.../internal/gmscompat/AttestationHooks.java | 22 ++++++++-----------
1 file changed, 9 insertions(+), 13 deletions(-)
diff --git a/core/java/com/android/internal/gmscompat/AttestationHooks.java b/core/java/com/android/internal/gmscompat/AttestationHooks.java
index 6bd12a1c1e03..b10cb04cb4f3 100644
--- a/core/java/com/android/internal/gmscompat/AttestationHooks.java
+++ b/core/java/com/android/internal/gmscompat/AttestationHooks.java
@@ -70,11 +70,11 @@ public final class AttestationHooks {
private static void spoofBuildGms() {
// Alter model name and fingerprint to avoid hardware attestation enforcement
- setBuildField("FINGERPRINT", "google/angler/angler:6.0/MDB08L/2343525:user/release-keys");
- setBuildField("MODEL", Build.MODEL + " ");
- if (Build.VERSION.DEVICE_INITIAL_SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
- setVersionField("DEVICE_INITIAL_SDK_INT", Build.VERSION_CODES.S_V2);
- }
+ setBuildField("FINGERPRINT", "google/marlin/marlin:7.1.2/NJH47F/4146041:user/release-keys");
+ setBuildField("PRODUCT", "marlin");
+ setBuildField("DEVICE", "marlin");
+ setBuildField("MODEL", "Pixel XL");
+ setVersionField("DEVICE_INITIAL_SDK_INT", Build.VERSION_CODES.N_MR1);
}
public static void initApplicationBeforeOnCreate(Application app) {
@@ -90,18 +90,14 @@ public final class AttestationHooks {
}
private static boolean isCallerSafetyNet() {
- return Arrays.stream(Thread.currentThread().getStackTrace())
+ return sIsGms && Arrays.stream(Thread.currentThread().getStackTrace())
.anyMatch(elem -> elem.getClassName().contains("DroidGuard"));
}
public static void onEngineGetCertificateChain() {
- // Check stack for SafetyNet
- if (sIsGms && isCallerSafetyNet()) {
- throw new UnsupportedOperationException();
- }
-
- // Check stack for PlayIntegrity
- if (sIsFinsky) {
+ // Check stack for SafetyNet or Play Integrity
+ if (isCallerSafetyNet() || sIsFinsky) {
+ Log.i(TAG, "Blocked key attestation sIsGms=" + sIsGms + " sIsFinsky=" + sIsFinsky);
throw new UnsupportedOperationException();
}
}
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Davide Garberi <dade.garberi@gmail.com>
Date: Wed, 8 Nov 2023 21:36:02 +0100
Subject: [PATCH 8/8] gmscompat: Use new info
Change-Id: I3cb0c55d28249b73ecc53be83bed030304c782d9
---
.../android/internal/gmscompat/AttestationHooks.java | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/core/java/com/android/internal/gmscompat/AttestationHooks.java b/core/java/com/android/internal/gmscompat/AttestationHooks.java
index b10cb04cb4f3..04a536d8073d 100644
--- a/core/java/com/android/internal/gmscompat/AttestationHooks.java
+++ b/core/java/com/android/internal/gmscompat/AttestationHooks.java
@@ -70,11 +70,11 @@ public final class AttestationHooks {
private static void spoofBuildGms() {
// Alter model name and fingerprint to avoid hardware attestation enforcement
- setBuildField("FINGERPRINT", "google/marlin/marlin:7.1.2/NJH47F/4146041:user/release-keys");
- setBuildField("PRODUCT", "marlin");
- setBuildField("DEVICE", "marlin");
- setBuildField("MODEL", "Pixel XL");
- setVersionField("DEVICE_INITIAL_SDK_INT", Build.VERSION_CODES.N_MR1);
+ setBuildField("DEVICE", "bullhead");
+ setBuildField("FINGERPRINT", "google/bullhead/bullhead:8.0.0/OPR6.170623.013/4283548:user/release-keys");
+ setBuildField("MODEL", "Nexus 5X");
+ setBuildField("PRODUCT", "bullhead");
+ setVersionField("DEVICE_INITIAL_SDK_INT", Build.VERSION_CODES.N);
}
public static void initApplicationBeforeOnCreate(Application app) {

View File

@ -0,0 +1,59 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Danny Lin <danny@kdrag0n.dev>
Date: Wed, 7 Oct 2020 00:24:54 -0700
Subject: [PATCH] init: Set properties to make SafetyNet pass
Google's SafetyNet integrity checks will check the values of these
properties when performing basic attestation. Setting fake values helps
us pass basic SafetyNet with no Magisk Hide or kernel patches necessary.
Note that these properties need to be set very early, before parsing the
kernel command-line, as they are read-only properties that the bootloader
sets using androidboot kernel arguments. The bootloader's real values
cause SafetyNet to fail with an unlocked bootloader and/or custom
software because the verified boot chain is broken in that case.
Change-Id: I66d23fd91d82906b00d5eb020668f01ae83ec31f
- Also don't set these in recovery
Change-Id: I57f6d48acddb29748778053edf354d7bd8994bd7
---
init/property_service.cpp | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 42dd5afcb..a2c7c2db6 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -1064,6 +1064,15 @@ static void ProcessKernelCmdline() {
}
}
+static void SetSafetyNetProps() {
+ InitPropertySet("ro.boot.flash.locked", "1");
+ InitPropertySet("ro.boot.verifiedbootstate", "green");
+ InitPropertySet("ro.boot.veritymode", "enforcing");
+ InitPropertySet("ro.boot.vbmeta.device_state", "locked");
+ InitPropertySet("ro.boot.warranty_bit", "0");
+ InitPropertySet("ro.warranty_bit", "0");
+}
+
void PropertyInit() {
selinux_callback cb;
cb.func_audit = PropertyAuditCallback;
@@ -1078,6 +1087,14 @@ void PropertyInit() {
LOG(FATAL) << "Failed to load serialized property info file";
}
+ // Report a valid verified boot chain to make Google SafetyNet integrity
+ // checks pass. This needs to be done before parsing the kernel cmdline as
+ // these properties are read-only and will be set to invalid values with
+ // androidboot cmdline arguments.
+ if (!IsRecoveryMode()) {
+ SetSafetyNetProps();
+ }
+
// If arguments are passed both on the command line and in DT,
// properties set in DT always have priority over the command-line ones.
ProcessKernelDt();

View File

@ -0,0 +1,510 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Danny Lin <danny@kdrag0n.dev>
Date: Mon, 11 Oct 2021 19:59:51 -0700
Subject: [PATCH 1/8] Alter model name to avoid SafetyNet HW attestation
enforcement
As of September 2, Google is enforcing SafetyNet's previously
opportunistic hardware-backed attestation based on device information.
Append a space to the device model name in order to avoid such
enforcement.
Also contains:
Spoof build fingerprint for Google Play Services
SafetyNet's CTS profile attestation checks whether Build.FINGERPRINT
matches that of the device's stock OS, which has passed CTS testing.
Spoof the fingerprint for Google Play Services to help pass SafetyNet.
We used to set the real system build fingerprint to the stock one, but
Android relies on each build having a unique fingerprint in order to
clear the correct caches and update persistent state for system changes.
On devices that no longer receive updates from the OEM, the build
fingerprint never changes and Android doesn't account for updates
correctly, which causes issues when updating without wiping data.
Only spoofing the fingerprint for Google Play Services fixes this issue.
Corresponding vendor commit:
"Only use stock build fingerprint for Google Play Services"
NB: This code is under the gmscompat package, but it does not depend on
any code from gmscompat.
Change-Id: I26a2498eb2e2163933303b03f6d516e5fb30fe51
* We don't need to spoof the fingerprint here since we do it globally, but we
use the Build field spoofing code it added for model
Change-Id: Ib7779e0aae40cab3730a56785e9231896917ab0a
---
core/java/android/app/Instrumentation.java | 4 ++
.../internal/gmscompat/AttestationHooks.java | 59 +++++++++++++++++++
2 files changed, 63 insertions(+)
create mode 100644 core/java/com/android/internal/gmscompat/AttestationHooks.java
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index fd6fa57b9e8d..05d840dca223 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -57,6 +57,8 @@ import android.view.WindowManagerGlobal;
import com.android.internal.content.ReferrerIntent;
+import com.android.internal.gmscompat.AttestationHooks;
+
import java.io.File;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -1188,6 +1190,7 @@ public class Instrumentation {
Application app = getFactory(context.getPackageName())
.instantiateApplication(cl, className);
app.attach(context);
+ AttestationHooks.initApplicationBeforeOnCreate(app);
return app;
}
@@ -1205,6 +1208,7 @@ public class Instrumentation {
ClassNotFoundException {
Application app = (Application)clazz.newInstance();
app.attach(context);
+ AttestationHooks.initApplicationBeforeOnCreate(app);
return app;
}
diff --git a/core/java/com/android/internal/gmscompat/AttestationHooks.java b/core/java/com/android/internal/gmscompat/AttestationHooks.java
new file mode 100644
index 000000000000..621156eb84b9
--- /dev/null
+++ b/core/java/com/android/internal/gmscompat/AttestationHooks.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.gmscompat;
+
+import android.app.Application;
+import android.os.Build;
+import android.os.SystemProperties;
+import android.util.Log;
+
+import java.lang.reflect.Field;
+
+/** @hide */
+public final class AttestationHooks {
+ private static final String TAG = "GmsCompat/Attestation";
+ private static final String PACKAGE_GMS = "com.google.android.gms";
+
+ private AttestationHooks() { }
+
+ private static void setBuildField(String key, String value) {
+ try {
+ // Unlock
+ Field field = Build.class.getDeclaredField(key);
+ field.setAccessible(true);
+
+ // Edit
+ field.set(null, value);
+
+ // Lock
+ field.setAccessible(false);
+ } catch (NoSuchFieldException | IllegalAccessException e) {
+ Log.e(TAG, "Failed to spoof Build." + key, e);
+ }
+ }
+
+ private static void spoofBuildGms() {
+ // Alter model name to avoid hardware attestation enforcement
+ setBuildField("MODEL", Build.MODEL + " ");
+ }
+
+ public static void initApplicationBeforeOnCreate(Application app) {
+ if (PACKAGE_GMS.equals(app.getPackageName())) {
+ spoofBuildGms();
+ }
+ }
+}
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Danny Lin <danny@kdrag0n.dev>
Date: Mon, 11 Oct 2021 20:00:44 -0700
Subject: [PATCH 2/8] keystore: Block key attestation for SafetyNet
SafetyNet (part of Google Play Services) opportunistically uses
hardware-backed key attestation via KeyStore as a strong integrity
check. This causes SafetyNet to fail on custom ROMs because the verified
boot key and bootloader unlock state can be detected from attestation
certificates.
As a workaround, we can take advantage of the fact that SafetyNet's
usage of key attestation is opportunistic (i.e. falls back to basic
integrity checks if it fails) and prevent it from getting the
attestation certificate chain from KeyStore. This is done by checking
the stack for DroidGuard, which is the codename for SafetyNet, and
pretending that the device doesn't support key attestation.
Key attestation has only been blocked for SafetyNet specifically, as
Google Play Services and other apps have many valid reasons to use it.
For example, it appears to be involved in Google's mobile security key
ferature.
Change-Id: I5146439d47f42dc6231cb45c4dab9f61540056f6
---
.../internal/gmscompat/AttestationHooks.java | 16 ++++++++++++++++
.../security/keystore2/AndroidKeyStoreSpi.java | 3 +++
2 files changed, 19 insertions(+)
diff --git a/core/java/com/android/internal/gmscompat/AttestationHooks.java b/core/java/com/android/internal/gmscompat/AttestationHooks.java
index 621156eb84b9..fe12dfe02a9f 100644
--- a/core/java/com/android/internal/gmscompat/AttestationHooks.java
+++ b/core/java/com/android/internal/gmscompat/AttestationHooks.java
@@ -22,12 +22,15 @@ import android.os.SystemProperties;
import android.util.Log;
import java.lang.reflect.Field;
+import java.util.Arrays;
/** @hide */
public final class AttestationHooks {
private static final String TAG = "GmsCompat/Attestation";
private static final String PACKAGE_GMS = "com.google.android.gms";
+ private static volatile boolean sIsGms = false;
+
private AttestationHooks() { }
private static void setBuildField(String key, String value) {
@@ -53,7 +56,20 @@ public final class AttestationHooks {
public static void initApplicationBeforeOnCreate(Application app) {
if (PACKAGE_GMS.equals(app.getPackageName())) {
+ sIsGms = true;
spoofBuildGms();
}
}
+
+ private static boolean isCallerSafetyNet() {
+ return Arrays.stream(Thread.currentThread().getStackTrace())
+ .anyMatch(elem -> elem.getClassName().contains("DroidGuard"));
+ }
+
+ public static void onEngineGetCertificateChain() {
+ // Check stack for SafetyNet
+ if (sIsGms && isCallerSafetyNet()) {
+ throw new UnsupportedOperationException();
+ }
+ }
}
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
index 33411e1ec5b9..133a4094d434 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
@@ -42,6 +42,7 @@ import android.system.keystore2.ResponseCode;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.gmscompat.AttestationHooks;
import java.io.ByteArrayInputStream;
import java.io.IOException;
@@ -164,6 +165,8 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi {
@Override
public Certificate[] engineGetCertificateChain(String alias) {
+ AttestationHooks.onEngineGetCertificateChain();
+
KeyEntryResponse response = getKeyMetadata(alias);
if (response == null || response.metadata.certificate == null) {
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Anirudh Gupta <anirudhgupta109@aosip.dev>
Date: Wed, 4 Jan 2023 18:20:56 +0000
Subject: [PATCH 3/8] AttestationHooks: Set shipping level to 32 for devices
>=33
If ro.product.first_api_level is 33, it's forced to use HW attestation.
Setting it to 32 allows for software attestation and passing CTS.
Change-Id: Ie47fd00b009c93580ec8c950d223c60ed63a0d2f
---
.../internal/gmscompat/AttestationHooks.java | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/core/java/com/android/internal/gmscompat/AttestationHooks.java b/core/java/com/android/internal/gmscompat/AttestationHooks.java
index fe12dfe02a9f..f512adc3985b 100644
--- a/core/java/com/android/internal/gmscompat/AttestationHooks.java
+++ b/core/java/com/android/internal/gmscompat/AttestationHooks.java
@@ -49,9 +49,28 @@ public final class AttestationHooks {
}
}
+ private static void setVersionField(String key, Integer value) {
+ try {
+ // Unlock
+ Field field = Build.VERSION.class.getDeclaredField(key);
+ field.setAccessible(true);
+
+ // Edit
+ field.set(null, value);
+
+ // Lock
+ field.setAccessible(false);
+ } catch (NoSuchFieldException | IllegalAccessException e) {
+ Log.e(TAG, "Failed to spoof Build.VERSION." + key, e);
+ }
+ }
+
private static void spoofBuildGms() {
// Alter model name to avoid hardware attestation enforcement
setBuildField("MODEL", Build.MODEL + " ");
+ if (Build.VERSION.DEVICE_INITIAL_SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ setVersionField("DEVICE_INITIAL_SDK_INT", Build.VERSION_CODES.S_V2);
+ }
}
public static void initApplicationBeforeOnCreate(Application app) {
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Danny Lin <danny@kdrag0n.dev>
Date: Mon, 1 Nov 2021 20:06:48 -0700
Subject: [PATCH 4/8] Limit SafetyNet workarounds to unstable GMS process
The unstable process is where SafetyNet attestation actually runs, so
we only need to spoof the model in that process. Leaving other processes
fixes various issues caused by model detection and flag provisioning,
including screen-off Voice Match in Google Assistant, broken At a Glance
weather and settings on Android 12, and more.
Change-Id: Idcf663907a6c3d0408dbd45b1ac53c9eb4200df8
---
.../java/com/android/internal/gmscompat/AttestationHooks.java | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/core/java/com/android/internal/gmscompat/AttestationHooks.java b/core/java/com/android/internal/gmscompat/AttestationHooks.java
index f512adc3985b..c1021dd2eb22 100644
--- a/core/java/com/android/internal/gmscompat/AttestationHooks.java
+++ b/core/java/com/android/internal/gmscompat/AttestationHooks.java
@@ -28,6 +28,7 @@ import java.util.Arrays;
public final class AttestationHooks {
private static final String TAG = "GmsCompat/Attestation";
private static final String PACKAGE_GMS = "com.google.android.gms";
+ private static final String PROCESS_UNSTABLE = "com.google.android.gms.unstable";
private static volatile boolean sIsGms = false;
@@ -74,7 +75,8 @@ public final class AttestationHooks {
}
public static void initApplicationBeforeOnCreate(Application app) {
- if (PACKAGE_GMS.equals(app.getPackageName())) {
+ if (PACKAGE_GMS.equals(app.getPackageName()) &&
+ PROCESS_UNSTABLE.equals(Application.getProcessName())) {
sIsGms = true;
spoofBuildGms();
}
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Dyneteve <dyneteve@hentaios.com>
Date: Tue, 23 Aug 2022 18:57:05 +0200
Subject: [PATCH 5/8] gmscompat: Apply the SafetyNet workaround to Play Store
aswell
Play Store is used for the new Play Integrity API, extend the hack
to it aswell
Test: Device Integrity and Basic Integrity passes.
Change-Id: Id607cdff0b902f285a6c1b769c0a4ee4202842b1
---
.../android/internal/gmscompat/AttestationHooks.java | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/core/java/com/android/internal/gmscompat/AttestationHooks.java b/core/java/com/android/internal/gmscompat/AttestationHooks.java
index c1021dd2eb22..6a4aab000fe0 100644
--- a/core/java/com/android/internal/gmscompat/AttestationHooks.java
+++ b/core/java/com/android/internal/gmscompat/AttestationHooks.java
@@ -28,9 +28,11 @@ import java.util.Arrays;
public final class AttestationHooks {
private static final String TAG = "GmsCompat/Attestation";
private static final String PACKAGE_GMS = "com.google.android.gms";
+ private static final String PACKAGE_FINSKY = "com.android.vending";
private static final String PROCESS_UNSTABLE = "com.google.android.gms.unstable";
private static volatile boolean sIsGms = false;
+ private static volatile boolean sIsFinsky = false;
private AttestationHooks() { }
@@ -80,6 +82,11 @@ public final class AttestationHooks {
sIsGms = true;
spoofBuildGms();
}
+
+ if (PACKAGE_FINSKY.equals(app.getPackageName())) {
+ sIsFinsky = true;
+ spoofBuildGms();
+ }
}
private static boolean isCallerSafetyNet() {
@@ -92,5 +99,10 @@ public final class AttestationHooks {
if (sIsGms && isCallerSafetyNet()) {
throw new UnsupportedOperationException();
}
+
+ // Check stack for PlayIntegrity
+ if (sIsFinsky) {
+ throw new UnsupportedOperationException();
+ }
}
}
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Dyneteve <dyneteve@hentaios.com>
Date: Thu, 8 Sep 2022 14:39:52 +0200
Subject: [PATCH 6/8] gmscompat: Use Nexus 6P fingerprint for CTS/Integrity
Google seems to have patched the KM block to Play Store in record time,
but is still not enforced for anything under android N.
Since we moved to angler FP we don't need to spoof model to Play Store
anymore, however the KM block is still needed.
Test: Run Play Intregrity Attestation
Change-Id: Ic2401a6e40ddfc4318a1d0faa87e42eb118ac3d1
---
.../java/com/android/internal/gmscompat/AttestationHooks.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/core/java/com/android/internal/gmscompat/AttestationHooks.java b/core/java/com/android/internal/gmscompat/AttestationHooks.java
index 6a4aab000fe0..6bd12a1c1e03 100644
--- a/core/java/com/android/internal/gmscompat/AttestationHooks.java
+++ b/core/java/com/android/internal/gmscompat/AttestationHooks.java
@@ -69,7 +69,8 @@ public final class AttestationHooks {
}
private static void spoofBuildGms() {
- // Alter model name to avoid hardware attestation enforcement
+ // Alter model name and fingerprint to avoid hardware attestation enforcement
+ setBuildField("FINGERPRINT", "google/angler/angler:6.0/MDB08L/2343525:user/release-keys");
setBuildField("MODEL", Build.MODEL + " ");
if (Build.VERSION.DEVICE_INITIAL_SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
setVersionField("DEVICE_INITIAL_SDK_INT", Build.VERSION_CODES.S_V2);
@@ -85,7 +86,6 @@ public final class AttestationHooks {
if (PACKAGE_FINSKY.equals(app.getPackageName())) {
sIsFinsky = true;
- spoofBuildGms();
}
}
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Dyneteve <dyneteve@hentaios.com>
Date: Wed, 8 Feb 2023 15:21:01 +0000
Subject: [PATCH 7/8] gmscompat: Make CTS/Play Integrity pass again
The logic behind CTS and Play Integrity has been updated today it now
checks the product and model names against the fingerprint and if
they do not match the CTS profile will fail.
Also while we are at it use a newer FP from Pixel XL and add logging
for key attestation blocking for debugging.
Test: Boot, check for CTS and Play Integrity
Change-Id: I089d5ef935bba40338e10c795ea7d181103ffd15
---
.../internal/gmscompat/AttestationHooks.java | 22 ++++++++-----------
1 file changed, 9 insertions(+), 13 deletions(-)
diff --git a/core/java/com/android/internal/gmscompat/AttestationHooks.java b/core/java/com/android/internal/gmscompat/AttestationHooks.java
index 6bd12a1c1e03..b10cb04cb4f3 100644
--- a/core/java/com/android/internal/gmscompat/AttestationHooks.java
+++ b/core/java/com/android/internal/gmscompat/AttestationHooks.java
@@ -70,11 +70,11 @@ public final class AttestationHooks {
private static void spoofBuildGms() {
// Alter model name and fingerprint to avoid hardware attestation enforcement
- setBuildField("FINGERPRINT", "google/angler/angler:6.0/MDB08L/2343525:user/release-keys");
- setBuildField("MODEL", Build.MODEL + " ");
- if (Build.VERSION.DEVICE_INITIAL_SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
- setVersionField("DEVICE_INITIAL_SDK_INT", Build.VERSION_CODES.S_V2);
- }
+ setBuildField("FINGERPRINT", "google/marlin/marlin:7.1.2/NJH47F/4146041:user/release-keys");
+ setBuildField("PRODUCT", "marlin");
+ setBuildField("DEVICE", "marlin");
+ setBuildField("MODEL", "Pixel XL");
+ setVersionField("DEVICE_INITIAL_SDK_INT", Build.VERSION_CODES.N_MR1);
}
public static void initApplicationBeforeOnCreate(Application app) {
@@ -90,18 +90,14 @@ public final class AttestationHooks {
}
private static boolean isCallerSafetyNet() {
- return Arrays.stream(Thread.currentThread().getStackTrace())
+ return sIsGms && Arrays.stream(Thread.currentThread().getStackTrace())
.anyMatch(elem -> elem.getClassName().contains("DroidGuard"));
}
public static void onEngineGetCertificateChain() {
- // Check stack for SafetyNet
- if (sIsGms && isCallerSafetyNet()) {
- throw new UnsupportedOperationException();
- }
-
- // Check stack for PlayIntegrity
- if (sIsFinsky) {
+ // Check stack for SafetyNet or Play Integrity
+ if (isCallerSafetyNet() || sIsFinsky) {
+ Log.i(TAG, "Blocked key attestation sIsGms=" + sIsGms + " sIsFinsky=" + sIsFinsky);
throw new UnsupportedOperationException();
}
}
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Davide Garberi <dade.garberi@gmail.com>
Date: Wed, 8 Nov 2023 21:36:02 +0100
Subject: [PATCH 8/8] gmscompat: Use new info
Change-Id: I3cb0c55d28249b73ecc53be83bed030304c782d9
---
.../android/internal/gmscompat/AttestationHooks.java | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/core/java/com/android/internal/gmscompat/AttestationHooks.java b/core/java/com/android/internal/gmscompat/AttestationHooks.java
index b10cb04cb4f3..04a536d8073d 100644
--- a/core/java/com/android/internal/gmscompat/AttestationHooks.java
+++ b/core/java/com/android/internal/gmscompat/AttestationHooks.java
@@ -70,11 +70,11 @@ public final class AttestationHooks {
private static void spoofBuildGms() {
// Alter model name and fingerprint to avoid hardware attestation enforcement
- setBuildField("FINGERPRINT", "google/marlin/marlin:7.1.2/NJH47F/4146041:user/release-keys");
- setBuildField("PRODUCT", "marlin");
- setBuildField("DEVICE", "marlin");
- setBuildField("MODEL", "Pixel XL");
- setVersionField("DEVICE_INITIAL_SDK_INT", Build.VERSION_CODES.N_MR1);
+ setBuildField("DEVICE", "bullhead");
+ setBuildField("FINGERPRINT", "google/bullhead/bullhead:8.0.0/OPR6.170623.013/4283548:user/release-keys");
+ setBuildField("MODEL", "Nexus 5X");
+ setBuildField("PRODUCT", "bullhead");
+ setVersionField("DEVICE_INITIAL_SDK_INT", Build.VERSION_CODES.N);
}
public static void initApplicationBeforeOnCreate(Application app) {

View File

@ -0,0 +1,85 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Danny Lin <danny@kdrag0n.dev>
Date: Wed, 7 Oct 2020 00:24:54 -0700
Subject: [PATCH] init: Set properties to make SafetyNet pass
Google's SafetyNet integrity checks will check the values of these
properties when performing basic attestation. Setting fake values helps
us pass basic SafetyNet with no Magisk Hide or kernel patches necessary.
Note that these properties need to be set very early, before parsing the
kernel command-line, as they are read-only properties that the bootloader
sets using androidboot kernel arguments. The bootloader's real values
cause SafetyNet to fail with an unlocked bootloader and/or custom
software because the verified boot chain is broken in that case.
Change-Id: I66d23fd91d82906b00d5eb020668f01ae83ec31f
fastboot: Revert to Android 11 method of checking lock status
Now that we're setting system-wide properties for SafetyNet, which
includes ro.boot.verifiedbootstate=green, fastbootd always detects the
bootloader as being locked. Revert to the Android 11 method of reading
directly from the kernel cmdline to work arround the issue.
- Also don't set these in recovery
Change-Id: I57f6d48acddb29748778053edf354d7bd8994bd7
---
fastboot/device/utility.cpp | 7 ++++++-
init/property_service.cpp | 17 +++++++++++++++++
2 files changed, 23 insertions(+), 1 deletion(-)
diff --git a/fastboot/device/utility.cpp b/fastboot/device/utility.cpp
index b8b3119ac..f9267e0eb 100644
--- a/fastboot/device/utility.cpp
+++ b/fastboot/device/utility.cpp
@@ -204,7 +204,12 @@ std::vector<std::string> ListPartitions(FastbootDevice* device) {
}
bool GetDeviceLockStatus() {
- return android::base::GetProperty("ro.boot.verifiedbootstate", "") == "green";
+ std::string cmdline;
+ // Return lock status true if unable to read kernel command line.
+ if (!android::base::ReadFileToString("/proc/cmdline", &cmdline)) {
+ return true;
+ }
+ return cmdline.find("androidboot.verifiedbootstate=orange") == std::string::npos;
}
bool UpdateAllPartitionMetadata(FastbootDevice* device, const std::string& super_name,
diff --git a/init/property_service.cpp b/init/property_service.cpp
index d429fc762..c73a2fa5d 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -1251,6 +1251,15 @@ static void ProcessBootconfig() {
});
}
+static void SetSafetyNetProps() {
+ InitPropertySet("ro.boot.flash.locked", "1");
+ InitPropertySet("ro.boot.verifiedbootstate", "green");
+ InitPropertySet("ro.boot.veritymode", "enforcing");
+ InitPropertySet("ro.boot.vbmeta.device_state", "locked");
+ InitPropertySet("ro.boot.warranty_bit", "0");
+ InitPropertySet("ro.warranty_bit", "0");
+}
+
void PropertyInit() {
selinux_callback cb;
cb.func_audit = PropertyAuditCallback;
@@ -1265,6 +1274,14 @@ void PropertyInit() {
LOG(FATAL) << "Failed to load serialized property info file";
}
+ // Report a valid verified boot chain to make Google SafetyNet integrity
+ // checks pass. This needs to be done before parsing the kernel cmdline as
+ // these properties are read-only and will be set to invalid values with
+ // androidboot cmdline arguments.
+ if (!IsRecoveryMode()) {
+ SetSafetyNetProps();
+ }
+
// If arguments are passed both on the command line and in DT,
// properties set in DT always have priority over the command-line ones.
ProcessKernelDt();

View File

@ -0,0 +1,510 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Danny Lin <danny@kdrag0n.dev>
Date: Mon, 11 Oct 2021 19:59:51 -0700
Subject: [PATCH 1/8] Alter model name to avoid SafetyNet HW attestation
enforcement
As of September 2, Google is enforcing SafetyNet's previously
opportunistic hardware-backed attestation based on device information.
Append a space to the device model name in order to avoid such
enforcement.
Also contains:
Spoof build fingerprint for Google Play Services
SafetyNet's CTS profile attestation checks whether Build.FINGERPRINT
matches that of the device's stock OS, which has passed CTS testing.
Spoof the fingerprint for Google Play Services to help pass SafetyNet.
We used to set the real system build fingerprint to the stock one, but
Android relies on each build having a unique fingerprint in order to
clear the correct caches and update persistent state for system changes.
On devices that no longer receive updates from the OEM, the build
fingerprint never changes and Android doesn't account for updates
correctly, which causes issues when updating without wiping data.
Only spoofing the fingerprint for Google Play Services fixes this issue.
Corresponding vendor commit:
"Only use stock build fingerprint for Google Play Services"
NB: This code is under the gmscompat package, but it does not depend on
any code from gmscompat.
Change-Id: I26a2498eb2e2163933303b03f6d516e5fb30fe51
* We don't need to spoof the fingerprint here since we do it globally, but we
use the Build field spoofing code it added for model
Change-Id: Ib7779e0aae40cab3730a56785e9231896917ab0a
---
core/java/android/app/Instrumentation.java | 4 ++
.../internal/gmscompat/AttestationHooks.java | 59 +++++++++++++++++++
2 files changed, 63 insertions(+)
create mode 100644 core/java/com/android/internal/gmscompat/AttestationHooks.java
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 556058b567f9..44449588bbab 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -57,6 +57,8 @@ import android.view.WindowManagerGlobal;
import com.android.internal.content.ReferrerIntent;
+import com.android.internal.gmscompat.AttestationHooks;
+
import java.io.File;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -1242,6 +1244,7 @@ public class Instrumentation {
Application app = getFactory(context.getPackageName())
.instantiateApplication(cl, className);
app.attach(context);
+ AttestationHooks.initApplicationBeforeOnCreate(app);
return app;
}
@@ -1259,6 +1262,7 @@ public class Instrumentation {
ClassNotFoundException {
Application app = (Application)clazz.newInstance();
app.attach(context);
+ AttestationHooks.initApplicationBeforeOnCreate(app);
return app;
}
diff --git a/core/java/com/android/internal/gmscompat/AttestationHooks.java b/core/java/com/android/internal/gmscompat/AttestationHooks.java
new file mode 100644
index 000000000000..621156eb84b9
--- /dev/null
+++ b/core/java/com/android/internal/gmscompat/AttestationHooks.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.gmscompat;
+
+import android.app.Application;
+import android.os.Build;
+import android.os.SystemProperties;
+import android.util.Log;
+
+import java.lang.reflect.Field;
+
+/** @hide */
+public final class AttestationHooks {
+ private static final String TAG = "GmsCompat/Attestation";
+ private static final String PACKAGE_GMS = "com.google.android.gms";
+
+ private AttestationHooks() { }
+
+ private static void setBuildField(String key, String value) {
+ try {
+ // Unlock
+ Field field = Build.class.getDeclaredField(key);
+ field.setAccessible(true);
+
+ // Edit
+ field.set(null, value);
+
+ // Lock
+ field.setAccessible(false);
+ } catch (NoSuchFieldException | IllegalAccessException e) {
+ Log.e(TAG, "Failed to spoof Build." + key, e);
+ }
+ }
+
+ private static void spoofBuildGms() {
+ // Alter model name to avoid hardware attestation enforcement
+ setBuildField("MODEL", Build.MODEL + " ");
+ }
+
+ public static void initApplicationBeforeOnCreate(Application app) {
+ if (PACKAGE_GMS.equals(app.getPackageName())) {
+ spoofBuildGms();
+ }
+ }
+}
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Danny Lin <danny@kdrag0n.dev>
Date: Mon, 11 Oct 2021 20:00:44 -0700
Subject: [PATCH 2/8] keystore: Block key attestation for SafetyNet
SafetyNet (part of Google Play Services) opportunistically uses
hardware-backed key attestation via KeyStore as a strong integrity
check. This causes SafetyNet to fail on custom ROMs because the verified
boot key and bootloader unlock state can be detected from attestation
certificates.
As a workaround, we can take advantage of the fact that SafetyNet's
usage of key attestation is opportunistic (i.e. falls back to basic
integrity checks if it fails) and prevent it from getting the
attestation certificate chain from KeyStore. This is done by checking
the stack for DroidGuard, which is the codename for SafetyNet, and
pretending that the device doesn't support key attestation.
Key attestation has only been blocked for SafetyNet specifically, as
Google Play Services and other apps have many valid reasons to use it.
For example, it appears to be involved in Google's mobile security key
ferature.
Change-Id: I5146439d47f42dc6231cb45c4dab9f61540056f6
---
.../internal/gmscompat/AttestationHooks.java | 16 ++++++++++++++++
.../security/keystore2/AndroidKeyStoreSpi.java | 3 +++
2 files changed, 19 insertions(+)
diff --git a/core/java/com/android/internal/gmscompat/AttestationHooks.java b/core/java/com/android/internal/gmscompat/AttestationHooks.java
index 621156eb84b9..fe12dfe02a9f 100644
--- a/core/java/com/android/internal/gmscompat/AttestationHooks.java
+++ b/core/java/com/android/internal/gmscompat/AttestationHooks.java
@@ -22,12 +22,15 @@ import android.os.SystemProperties;
import android.util.Log;
import java.lang.reflect.Field;
+import java.util.Arrays;
/** @hide */
public final class AttestationHooks {
private static final String TAG = "GmsCompat/Attestation";
private static final String PACKAGE_GMS = "com.google.android.gms";
+ private static volatile boolean sIsGms = false;
+
private AttestationHooks() { }
private static void setBuildField(String key, String value) {
@@ -53,7 +56,20 @@ public final class AttestationHooks {
public static void initApplicationBeforeOnCreate(Application app) {
if (PACKAGE_GMS.equals(app.getPackageName())) {
+ sIsGms = true;
spoofBuildGms();
}
}
+
+ private static boolean isCallerSafetyNet() {
+ return Arrays.stream(Thread.currentThread().getStackTrace())
+ .anyMatch(elem -> elem.getClassName().contains("DroidGuard"));
+ }
+
+ public static void onEngineGetCertificateChain() {
+ // Check stack for SafetyNet
+ if (sIsGms && isCallerSafetyNet()) {
+ throw new UnsupportedOperationException();
+ }
+ }
}
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
index 33411e1ec5b9..133a4094d434 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
@@ -42,6 +42,7 @@ import android.system.keystore2.ResponseCode;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.gmscompat.AttestationHooks;
import java.io.ByteArrayInputStream;
import java.io.IOException;
@@ -164,6 +165,8 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi {
@Override
public Certificate[] engineGetCertificateChain(String alias) {
+ AttestationHooks.onEngineGetCertificateChain();
+
KeyEntryResponse response = getKeyMetadata(alias);
if (response == null || response.metadata.certificate == null) {
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Anirudh Gupta <anirudhgupta109@aosip.dev>
Date: Wed, 4 Jan 2023 18:20:56 +0000
Subject: [PATCH 3/8] AttestationHooks: Set shipping level to 32 for devices
>=33
If ro.product.first_api_level is 33, it's forced to use HW attestation.
Setting it to 32 allows for software attestation and passing CTS.
Change-Id: Ie47fd00b009c93580ec8c950d223c60ed63a0d2f
---
.../internal/gmscompat/AttestationHooks.java | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/core/java/com/android/internal/gmscompat/AttestationHooks.java b/core/java/com/android/internal/gmscompat/AttestationHooks.java
index fe12dfe02a9f..f512adc3985b 100644
--- a/core/java/com/android/internal/gmscompat/AttestationHooks.java
+++ b/core/java/com/android/internal/gmscompat/AttestationHooks.java
@@ -49,9 +49,28 @@ public final class AttestationHooks {
}
}
+ private static void setVersionField(String key, Integer value) {
+ try {
+ // Unlock
+ Field field = Build.VERSION.class.getDeclaredField(key);
+ field.setAccessible(true);
+
+ // Edit
+ field.set(null, value);
+
+ // Lock
+ field.setAccessible(false);
+ } catch (NoSuchFieldException | IllegalAccessException e) {
+ Log.e(TAG, "Failed to spoof Build.VERSION." + key, e);
+ }
+ }
+
private static void spoofBuildGms() {
// Alter model name to avoid hardware attestation enforcement
setBuildField("MODEL", Build.MODEL + " ");
+ if (Build.VERSION.DEVICE_INITIAL_SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ setVersionField("DEVICE_INITIAL_SDK_INT", Build.VERSION_CODES.S_V2);
+ }
}
public static void initApplicationBeforeOnCreate(Application app) {
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Danny Lin <danny@kdrag0n.dev>
Date: Mon, 1 Nov 2021 20:06:48 -0700
Subject: [PATCH 4/8] Limit SafetyNet workarounds to unstable GMS process
The unstable process is where SafetyNet attestation actually runs, so
we only need to spoof the model in that process. Leaving other processes
fixes various issues caused by model detection and flag provisioning,
including screen-off Voice Match in Google Assistant, broken At a Glance
weather and settings on Android 12, and more.
Change-Id: Idcf663907a6c3d0408dbd45b1ac53c9eb4200df8
---
.../java/com/android/internal/gmscompat/AttestationHooks.java | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/core/java/com/android/internal/gmscompat/AttestationHooks.java b/core/java/com/android/internal/gmscompat/AttestationHooks.java
index f512adc3985b..c1021dd2eb22 100644
--- a/core/java/com/android/internal/gmscompat/AttestationHooks.java
+++ b/core/java/com/android/internal/gmscompat/AttestationHooks.java
@@ -28,6 +28,7 @@ import java.util.Arrays;
public final class AttestationHooks {
private static final String TAG = "GmsCompat/Attestation";
private static final String PACKAGE_GMS = "com.google.android.gms";
+ private static final String PROCESS_UNSTABLE = "com.google.android.gms.unstable";
private static volatile boolean sIsGms = false;
@@ -74,7 +75,8 @@ public final class AttestationHooks {
}
public static void initApplicationBeforeOnCreate(Application app) {
- if (PACKAGE_GMS.equals(app.getPackageName())) {
+ if (PACKAGE_GMS.equals(app.getPackageName()) &&
+ PROCESS_UNSTABLE.equals(Application.getProcessName())) {
sIsGms = true;
spoofBuildGms();
}
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Dyneteve <dyneteve@hentaios.com>
Date: Tue, 23 Aug 2022 18:57:05 +0200
Subject: [PATCH 5/8] gmscompat: Apply the SafetyNet workaround to Play Store
aswell
Play Store is used for the new Play Integrity API, extend the hack
to it aswell
Test: Device Integrity and Basic Integrity passes.
Change-Id: Id607cdff0b902f285a6c1b769c0a4ee4202842b1
---
.../android/internal/gmscompat/AttestationHooks.java | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/core/java/com/android/internal/gmscompat/AttestationHooks.java b/core/java/com/android/internal/gmscompat/AttestationHooks.java
index c1021dd2eb22..6a4aab000fe0 100644
--- a/core/java/com/android/internal/gmscompat/AttestationHooks.java
+++ b/core/java/com/android/internal/gmscompat/AttestationHooks.java
@@ -28,9 +28,11 @@ import java.util.Arrays;
public final class AttestationHooks {
private static final String TAG = "GmsCompat/Attestation";
private static final String PACKAGE_GMS = "com.google.android.gms";
+ private static final String PACKAGE_FINSKY = "com.android.vending";
private static final String PROCESS_UNSTABLE = "com.google.android.gms.unstable";
private static volatile boolean sIsGms = false;
+ private static volatile boolean sIsFinsky = false;
private AttestationHooks() { }
@@ -80,6 +82,11 @@ public final class AttestationHooks {
sIsGms = true;
spoofBuildGms();
}
+
+ if (PACKAGE_FINSKY.equals(app.getPackageName())) {
+ sIsFinsky = true;
+ spoofBuildGms();
+ }
}
private static boolean isCallerSafetyNet() {
@@ -92,5 +99,10 @@ public final class AttestationHooks {
if (sIsGms && isCallerSafetyNet()) {
throw new UnsupportedOperationException();
}
+
+ // Check stack for PlayIntegrity
+ if (sIsFinsky) {
+ throw new UnsupportedOperationException();
+ }
}
}
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Dyneteve <dyneteve@hentaios.com>
Date: Thu, 8 Sep 2022 14:39:52 +0200
Subject: [PATCH 6/8] gmscompat: Use Nexus 6P fingerprint for CTS/Integrity
Google seems to have patched the KM block to Play Store in record time,
but is still not enforced for anything under android N.
Since we moved to angler FP we don't need to spoof model to Play Store
anymore, however the KM block is still needed.
Test: Run Play Intregrity Attestation
Change-Id: Ic2401a6e40ddfc4318a1d0faa87e42eb118ac3d1
---
.../java/com/android/internal/gmscompat/AttestationHooks.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/core/java/com/android/internal/gmscompat/AttestationHooks.java b/core/java/com/android/internal/gmscompat/AttestationHooks.java
index 6a4aab000fe0..6bd12a1c1e03 100644
--- a/core/java/com/android/internal/gmscompat/AttestationHooks.java
+++ b/core/java/com/android/internal/gmscompat/AttestationHooks.java
@@ -69,7 +69,8 @@ public final class AttestationHooks {
}
private static void spoofBuildGms() {
- // Alter model name to avoid hardware attestation enforcement
+ // Alter model name and fingerprint to avoid hardware attestation enforcement
+ setBuildField("FINGERPRINT", "google/angler/angler:6.0/MDB08L/2343525:user/release-keys");
setBuildField("MODEL", Build.MODEL + " ");
if (Build.VERSION.DEVICE_INITIAL_SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
setVersionField("DEVICE_INITIAL_SDK_INT", Build.VERSION_CODES.S_V2);
@@ -85,7 +86,6 @@ public final class AttestationHooks {
if (PACKAGE_FINSKY.equals(app.getPackageName())) {
sIsFinsky = true;
- spoofBuildGms();
}
}
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Dyneteve <dyneteve@hentaios.com>
Date: Wed, 8 Feb 2023 15:21:01 +0000
Subject: [PATCH 7/8] gmscompat: Make CTS/Play Integrity pass again
The logic behind CTS and Play Integrity has been updated today it now
checks the product and model names against the fingerprint and if
they do not match the CTS profile will fail.
Also while we are at it use a newer FP from Pixel XL and add logging
for key attestation blocking for debugging.
Test: Boot, check for CTS and Play Integrity
Change-Id: I089d5ef935bba40338e10c795ea7d181103ffd15
---
.../internal/gmscompat/AttestationHooks.java | 22 ++++++++-----------
1 file changed, 9 insertions(+), 13 deletions(-)
diff --git a/core/java/com/android/internal/gmscompat/AttestationHooks.java b/core/java/com/android/internal/gmscompat/AttestationHooks.java
index 6bd12a1c1e03..b10cb04cb4f3 100644
--- a/core/java/com/android/internal/gmscompat/AttestationHooks.java
+++ b/core/java/com/android/internal/gmscompat/AttestationHooks.java
@@ -70,11 +70,11 @@ public final class AttestationHooks {
private static void spoofBuildGms() {
// Alter model name and fingerprint to avoid hardware attestation enforcement
- setBuildField("FINGERPRINT", "google/angler/angler:6.0/MDB08L/2343525:user/release-keys");
- setBuildField("MODEL", Build.MODEL + " ");
- if (Build.VERSION.DEVICE_INITIAL_SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
- setVersionField("DEVICE_INITIAL_SDK_INT", Build.VERSION_CODES.S_V2);
- }
+ setBuildField("FINGERPRINT", "google/marlin/marlin:7.1.2/NJH47F/4146041:user/release-keys");
+ setBuildField("PRODUCT", "marlin");
+ setBuildField("DEVICE", "marlin");
+ setBuildField("MODEL", "Pixel XL");
+ setVersionField("DEVICE_INITIAL_SDK_INT", Build.VERSION_CODES.N_MR1);
}
public static void initApplicationBeforeOnCreate(Application app) {
@@ -90,18 +90,14 @@ public final class AttestationHooks {
}
private static boolean isCallerSafetyNet() {
- return Arrays.stream(Thread.currentThread().getStackTrace())
+ return sIsGms && Arrays.stream(Thread.currentThread().getStackTrace())
.anyMatch(elem -> elem.getClassName().contains("DroidGuard"));
}
public static void onEngineGetCertificateChain() {
- // Check stack for SafetyNet
- if (sIsGms && isCallerSafetyNet()) {
- throw new UnsupportedOperationException();
- }
-
- // Check stack for PlayIntegrity
- if (sIsFinsky) {
+ // Check stack for SafetyNet or Play Integrity
+ if (isCallerSafetyNet() || sIsFinsky) {
+ Log.i(TAG, "Blocked key attestation sIsGms=" + sIsGms + " sIsFinsky=" + sIsFinsky);
throw new UnsupportedOperationException();
}
}
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Davide Garberi <dade.garberi@gmail.com>
Date: Wed, 8 Nov 2023 21:36:02 +0100
Subject: [PATCH 8/8] gmscompat: Use new info
Change-Id: I3cb0c55d28249b73ecc53be83bed030304c782d9
---
.../android/internal/gmscompat/AttestationHooks.java | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/core/java/com/android/internal/gmscompat/AttestationHooks.java b/core/java/com/android/internal/gmscompat/AttestationHooks.java
index b10cb04cb4f3..04a536d8073d 100644
--- a/core/java/com/android/internal/gmscompat/AttestationHooks.java
+++ b/core/java/com/android/internal/gmscompat/AttestationHooks.java
@@ -70,11 +70,11 @@ public final class AttestationHooks {
private static void spoofBuildGms() {
// Alter model name and fingerprint to avoid hardware attestation enforcement
- setBuildField("FINGERPRINT", "google/marlin/marlin:7.1.2/NJH47F/4146041:user/release-keys");
- setBuildField("PRODUCT", "marlin");
- setBuildField("DEVICE", "marlin");
- setBuildField("MODEL", "Pixel XL");
- setVersionField("DEVICE_INITIAL_SDK_INT", Build.VERSION_CODES.N_MR1);
+ setBuildField("DEVICE", "bullhead");
+ setBuildField("FINGERPRINT", "google/bullhead/bullhead:8.0.0/OPR6.170623.013/4283548:user/release-keys");
+ setBuildField("MODEL", "Nexus 5X");
+ setBuildField("PRODUCT", "bullhead");
+ setVersionField("DEVICE_INITIAL_SDK_INT", Build.VERSION_CODES.N);
}
public static void initApplicationBeforeOnCreate(Application app) {

View File

@ -0,0 +1,85 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Danny Lin <danny@kdrag0n.dev>
Date: Wed, 7 Oct 2020 00:24:54 -0700
Subject: [PATCH] init: Set properties to make SafetyNet pass
Google's SafetyNet integrity checks will check the values of these
properties when performing basic attestation. Setting fake values helps
us pass basic SafetyNet with no Magisk Hide or kernel patches necessary.
Note that these properties need to be set very early, before parsing the
kernel command-line, as they are read-only properties that the bootloader
sets using androidboot kernel arguments. The bootloader's real values
cause SafetyNet to fail with an unlocked bootloader and/or custom
software because the verified boot chain is broken in that case.
Change-Id: I66d23fd91d82906b00d5eb020668f01ae83ec31f
fastboot: Revert to Android 11 method of checking lock status
Now that we're setting system-wide properties for SafetyNet, which
includes ro.boot.verifiedbootstate=green, fastbootd always detects the
bootloader as being locked. Revert to the Android 11 method of reading
directly from the kernel cmdline to work arround the issue.
- Also don't set these in recovery
Change-Id: I57f6d48acddb29748778053edf354d7bd8994bd7
---
fastboot/device/utility.cpp | 7 ++++++-
init/property_service.cpp | 17 +++++++++++++++++
2 files changed, 23 insertions(+), 1 deletion(-)
diff --git a/fastboot/device/utility.cpp b/fastboot/device/utility.cpp
index 2d9b71213..a14eea376 100644
--- a/fastboot/device/utility.cpp
+++ b/fastboot/device/utility.cpp
@@ -196,7 +196,12 @@ std::vector<std::string> ListPartitions(FastbootDevice* device) {
}
bool GetDeviceLockStatus() {
- return android::base::GetProperty("ro.boot.verifiedbootstate", "") == "green";
+ std::string cmdline;
+ // Return lock status true if unable to read kernel command line.
+ if (!android::base::ReadFileToString("/proc/cmdline", &cmdline)) {
+ return true;
+ }
+ return cmdline.find("androidboot.verifiedbootstate=orange") == std::string::npos;
}
bool UpdateAllPartitionMetadata(FastbootDevice* device, const std::string& super_name,
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 7fd64b389..06709cb7c 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -1286,6 +1286,15 @@ static void ProcessBootconfig() {
});
}
+static void SetSafetyNetProps() {
+ InitPropertySet("ro.boot.flash.locked", "1");
+ InitPropertySet("ro.boot.verifiedbootstate", "green");
+ InitPropertySet("ro.boot.veritymode", "enforcing");
+ InitPropertySet("ro.boot.vbmeta.device_state", "locked");
+ InitPropertySet("ro.boot.warranty_bit", "0");
+ InitPropertySet("ro.warranty_bit", "0");
+}
+
void PropertyInit() {
selinux_callback cb;
cb.func_audit = PropertyAuditCallback;
@@ -1300,6 +1309,14 @@ void PropertyInit() {
LOG(FATAL) << "Failed to load serialized property info file";
}
+ // Report a valid verified boot chain to make Google SafetyNet integrity
+ // checks pass. This needs to be done before parsing the kernel cmdline as
+ // these properties are read-only and will be set to invalid values with
+ // androidboot cmdline arguments.
+ if (!IsRecoveryMode()) {
+ SetSafetyNetProps();
+ }
+
// If arguments are passed both on the command line and in DT,
// properties set in DT always have priority over the command-line ones.
ProcessKernelDt();

View File

@ -929,8 +929,10 @@ export -f changeDefaultDNS;
editKernelLocalversion() {
local defconfigPath=$(getDefconfig)
sed -i 's/CONFIG_LOCALVERSION=".*"/CONFIG_LOCALVERSION="'"$1"'"/' $defconfigPath &>/dev/null || true;
sed -zi '/CONFIG_LOCALVERSION="'"$1"'"/!s/$/\nCONFIG_LOCALVERSION="'"$1"'"/' $defconfigPath &>/dev/null;
local replacement=$1;
if [ "$DOS_SNET" = true ]; then local replacement="-oink"; fi;
sed -i 's/CONFIG_LOCALVERSION=".*"/CONFIG_LOCALVERSION="'"$replacement"'"/' $defconfigPath &>/dev/null || true;
sed -zi '/CONFIG_LOCALVERSION="'"$replacement"'"/!s/$/\nCONFIG_LOCALVERSION="'"$replacement"'"/' $defconfigPath &>/dev/null;
}
export -f editKernelLocalversion;

View File

@ -196,6 +196,7 @@ applyPatch "$DOS_PATCHES/android_frameworks_base/0013-Sensors_Permission.patch";
if [ "$DOS_GRAPHENE_CONSTIFY" = true ]; then applyPatch "$DOS_PATCHES/android_frameworks_base/0014-constify_JNINativeMethod.patch"; fi; #Constify JNINativeMethod tables (GrapheneOS)
#if [ "$DOS_MICROG_SUPPORT" = true ]; then applyPatch "$DOS_PATCHES/android_frameworks_base/0021-Unprivileged_microG_Handling.patch"; fi; #Unprivileged microG handling (heavily based off of a CalyxOS patch)
applyPatch "$DOS_PATCHES_COMMON/android_frameworks_base/0008-No_Crash_GSF.patch"; #Don't crash apps that depend on missing Gservices provider (GrapheneOS)
if [ "$DOS_SNET" = true ]; then applyPatch "$DOS_PATCHES/android_frameworks_base/snet-16.patch"; fi;
sed -i 's/DEFAULT_MAX_FILES = 1000;/DEFAULT_MAX_FILES = 0;/' services/core/java/com/android/server/DropBoxManagerService.java; #Disable DropBox internal logging service
sed -i 's/DEFAULT_MAX_FILES_LOWRAM = 300;/DEFAULT_MAX_FILES_LOWRAM = 0;/' services/core/java/com/android/server/DropBoxManagerService.java;
sed -i 's/(notif.needNotify)/(true)/' location/java/com/android/internal/location/GpsNetInitiatedHandler.java; #Notify the user if their location is requested via SUPL
@ -381,6 +382,7 @@ applyPatch "$DOS_PATCHES/android_system_core/0001-Harden.patch"; #Harden mounts
if [ "$DOS_GRAPHENE_MALLOC" = true ]; then applyPatch "$DOS_PATCHES/android_system_core/0002-HM-Increase_vm_mmc.patch"; fi; #(GrapheneOS)
if [ "$DOS_GRAPHENE_BIONIC" = true ]; then applyPatch "$DOS_PATCHES/android_system_core/0003-Zero_Sensitive_Info.patch"; fi; #Zero sensitive information with explicit_bzero (GrapheneOS)
#applyPatch "$DOS_PATCHES/android_system_core/0004-ptrace_scope.patch"; #Add a property for controlling ptrace_scope (GrapheneOS)
if [ "$DOS_SNET_EXTRA" = true ]; then applyPatch "$DOS_PATCHES/android_system_core/snet-16.patch"; fi;
fi;
if enterAndClear "system/extras"; then

View File

@ -219,6 +219,7 @@ if [ "$DOS_MICROG_SUPPORT" = true ]; then applyPatch "$DOS_PATCHES/android_frame
applyPatch "$DOS_PATCHES_COMMON/android_frameworks_base/0006-Do-not-throw-in-setAppOnInterfaceLocked.patch"; #Fix random reboots on broken kernels when an app has data restricted XXX: ugly (DivestOS)
applyPatch "$DOS_PATCHES_COMMON/android_frameworks_base/0007-ABI_Warning.patch"; #Warn when running activity from 32 bit app on ARM64 devices. (AOSP)
applyPatch "$DOS_PATCHES_COMMON/android_frameworks_base/0008-No_Crash_GSF.patch"; #Don't crash apps that depend on missing Gservices provider (GrapheneOS)
if [ "$DOS_SNET" = true ]; then applyPatch "$DOS_PATCHES/android_frameworks_base/snet-17.patch"; fi;
sed -i 's/DEFAULT_MAX_FILES = 1000;/DEFAULT_MAX_FILES = 0;/' services/core/java/com/android/server/DropBoxManagerService.java; #Disable DropBox internal logging service
sed -i 's/DEFAULT_MAX_FILES_LOWRAM = 300;/DEFAULT_MAX_FILES_LOWRAM = 0;/' services/core/java/com/android/server/DropBoxManagerService.java;
sed -i 's/(notif.needNotify)/(true)/' location/java/com/android/internal/location/GpsNetInitiatedHandler.java; #Notify the user if their location is requested via SUPL
@ -430,6 +431,7 @@ applyPatch "$DOS_PATCHES/android_system_core/0001-Harden.patch"; #Harden mounts
if [ "$DOS_GRAPHENE_MALLOC" = true ]; then applyPatch "$DOS_PATCHES/android_system_core/0002-HM-Increase_vm_mmc.patch"; fi; #(GrapheneOS)
if [ "$DOS_GRAPHENE_BIONIC" = true ]; then applyPatch "$DOS_PATCHES/android_system_core/0003-Zero_Sensitive_Info.patch"; fi; #Zero sensitive information with explicit_bzero (GrapheneOS)
applyPatch "$DOS_PATCHES/android_system_core/0004-ptrace_scope.patch"; #Add a property for controlling ptrace_scope (GrapheneOS)
if [ "$DOS_SNET_EXTRA" = true ]; then applyPatch "$DOS_PATCHES/android_system_core/snet-17.patch"; fi;
fi;
if enterAndClear "system/extras"; then

View File

@ -174,6 +174,7 @@ applyPatch "$DOS_PATCHES/android_frameworks_base/0025-tile_restrictions.patch";
applyPatch "$DOS_PATCHES_COMMON/android_frameworks_base/0006-Do-not-throw-in-setAppOnInterfaceLocked.patch"; #Fix random reboots on broken kernels when an app has data restricted XXX: ugly (DivestOS)
applyPatch "$DOS_PATCHES_COMMON/android_frameworks_base/0007-ABI_Warning.patch"; #Warn when running activity from 32 bit app on ARM64 devices. (AOSP)
applyPatch "$DOS_PATCHES_COMMON/android_frameworks_base/0008-No_Crash_GSF.patch"; #Don't crash apps that depend on missing Gservices provider (GrapheneOS)
if [ "$DOS_SNET" = true ]; then applyPatch "$DOS_PATCHES/android_frameworks_base/snet-18.patch"; fi;
hardenLocationConf services/core/java/com/android/server/location/gps_debug.conf; #Harden the default GPS config
sed -i 's/DEFAULT_USE_COMPACTION = false;/DEFAULT_USE_COMPACTION = true;/' services/core/java/com/android/server/am/CachedAppOptimizer.java; #Enable app compaction by default (GrapheneOS)
sed -i 's/DEFAULT_USE_FREEZER = false;/DEFAULT_USE_FREEZER = true;/' services/core/java/com/android/server/am/CachedAppOptimizer.java; #Enable app freezer by default (GrapheneOS)
@ -401,6 +402,7 @@ applyPatch "$DOS_PATCHES/android_system_core/0001-Harden.patch"; #Harden mounts
applyPatch "$DOS_PATCHES/android_system_core/0002-ptrace_scope.patch"; #Add a property for controlling ptrace_scope (GrapheneOS)
if [ "$DOS_GRAPHENE_MALLOC" = true ]; then applyPatch "$DOS_PATCHES/android_system_core/0003-HM-Increase_vm_mmc.patch"; fi; #(GrapheneOS)
if [ "$DOS_GRAPHENE_BIONIC" = true ]; then applyPatch "$DOS_PATCHES/android_system_core/0004-Zero_Sensitive_Info.patch"; fi; #Zero sensitive information with explicit_bzero (GrapheneOS)
if [ "$DOS_SNET_EXTRA" = true ]; then applyPatch "$DOS_PATCHES/android_system_core/snet-18.patch"; fi;
fi;
if enterAndClear "system/extras"; then

View File

@ -182,6 +182,7 @@ applyPatch "$DOS_PATCHES/android_frameworks_base/0032-tile_restrictions.patch";
applyPatch "$DOS_PATCHES/android_frameworks_base/0033-minimal_screenshot_exif.patch"; #Put bare minimum metadata in screenshots (CalyxOS)
applyPatch "$DOS_PATCHES_COMMON/android_frameworks_base/0007-ABI_Warning.patch"; #Warn when running activity from 32 bit app on ARM64 devices. (AOSP)
applyPatch "$DOS_PATCHES_COMMON/android_frameworks_base/0008-No_Crash_GSF.patch"; #Don't crash apps that depend on missing Gservices provider (GrapheneOS)
if [ "$DOS_SNET" = true ]; then applyPatch "$DOS_PATCHES/android_frameworks_base/snet-19.patch"; fi;
hardenLocationConf services/core/java/com/android/server/location/gnss/gps_debug.conf; #Harden the default GPS config
sed -i 's/DEFAULT_USE_COMPACTION = false;/DEFAULT_USE_COMPACTION = true;/' services/core/java/com/android/server/am/CachedAppOptimizer.java; #Enable app compaction by default (GrapheneOS)
sed -i 's/DEFAULT_MAX_FILES = 1000;/DEFAULT_MAX_FILES = 0;/' services/core/java/com/android/server/DropBoxManagerService.java; #Disable DropBox internal logging service
@ -403,6 +404,7 @@ git revert --no-edit 07adb89d0f8c966c88869d1abffc57da0e707568; #insanity
applyPatch "$DOS_PATCHES/android_system_core/0001-Harden.patch"; #Harden mounts with nodev/noexec/nosuid + misc sysctl changes (GrapheneOS)
applyPatch "$DOS_PATCHES/android_system_core/0002-ptrace_scope.patch"; #Add a property for controlling ptrace_scope (GrapheneOS)
if [ "$DOS_GRAPHENE_MALLOC" = true ]; then applyPatch "$DOS_PATCHES/android_system_core/0003-HM-Increase_vm_mmc.patch"; fi; #(GrapheneOS)
if [ "$DOS_SNET_EXTRA" = true ]; then applyPatch "$DOS_PATCHES/android_system_core/snet-19.patch"; fi;
fi;
if enterAndClear "system/extras"; then

View File

@ -197,6 +197,7 @@ applyPatch "$DOS_PATCHES/android_frameworks_base/0039-package_hooks.patch"; #Add
applyPatch "$DOS_PATCHES/android_frameworks_base/0040-euicc-restrictions.patch"; #Integrate Google's EuiccSupportPixel package (GrapheneOS)
applyPatch "$DOS_PATCHES/android_frameworks_base/0041-tile_restrictions.patch"; #SystemUI: Require unlocking to use sensitive QS tiles (GrapheneOS)
applyPatch "$DOS_PATCHES/android_frameworks_base/0042-minimal_screenshot_exif.patch"; #Put bare minimum metadata in screenshots (CalyxOS)
if [ "$DOS_SNET" = true ]; then applyPatch "$DOS_PATCHES/android_frameworks_base/snet-20.patch"; fi;
applyPatch "$DOS_PATCHES_COMMON/android_frameworks_base/0008-No_Crash_GSF.patch"; #Don't crash apps that depend on missing Gservices provider (GrapheneOS)
hardenLocationConf services/core/java/com/android/server/location/gnss/gps_debug.conf; #Harden the default GPS config
sed -i 's/DEFAULT_USE_COMPACTION = false;/DEFAULT_USE_COMPACTION = true;/' services/core/java/com/android/server/am/CachedAppOptimizer.java; #Enable app compaction by default (GrapheneOS)
@ -418,6 +419,7 @@ git revert --no-edit 942dd2ac9eed11d0ff31fb734de46c2da24b4b9b; #unknown impact
applyPatch "$DOS_PATCHES/android_system_core/0001-Harden.patch"; #Harden mounts with nodev/noexec/nosuid + misc sysctl changes (GrapheneOS)
applyPatch "$DOS_PATCHES/android_system_core/0002-ptrace_scope.patch"; #Add a property for controlling ptrace_scope (GrapheneOS)
if [ "$DOS_GRAPHENE_MALLOC" = true ]; then applyPatch "$DOS_PATCHES/android_system_core/0003-HM-Increase_vm_mmc.patch"; fi; #(GrapheneOS)
if [ "$DOS_SNET_EXTRA" = true ]; then applyPatch "$DOS_PATCHES/android_system_core/snet-20.patch"; fi;
fi;
if enterAndClear "system/extras"; then

View File

@ -67,6 +67,8 @@ export DOS_GRAPHENE_EXEC=true; #Enables use of GrapheneOS' exec spawning feature
export DOS_HOSTS_BLOCKING=true; #Set false to prevent inclusion of a HOSTS file
export DOS_HOSTS_BLOCKING_LIST="https://divested.dev/hosts-wildcards"; #Must be in the format "127.0.0.1 bad.domain.tld"
export DOS_MICROG_SUPPORT=true; #Opt-in unprivileged microG support on 17.1+18.1+19.1+20.0
export DOS_SNET=false; #Selectively spoof select build properties
export DOS_SNET_EXTRA=false; #Globally spoof select bootloader properties
export DOS_SENSORS_PERM=false; #Set true to provide a per-app sensors permission for 14.1/15.1 #XXX: can break things like camera
export DOS_STRONG_ENCRYPTION_ENABLED=false; #Set true to enable AES 256-bit FDE encryption on 14.1+15.1 #XXX: THIS WILL **DESTROY** EXISTING INSTALLS!
export DOS_USE_KSM=false; #Set true to use KSM for increased memory efficiency at the cost of easier side-channel attacks and increased CPU usage #XXX: testing only
@ -145,6 +147,11 @@ if [ ! -d "$DOS_BUILD_BASE" ]; then
return 1;
fi;
if [ "$DOS_MICROG_SUPPORT" = false ]; then
export DOS_SNET=false;
export DOS_SNET_EXTRA=false;
fi;
export DOS_TMP_DIR="/tmp/dos_tmp";
mkdir -p "$DOS_TMP_DIR";
export DOS_HOSTS_FILE="$DOS_TMP_DIR/hosts";