From 4f8cfc8a4124202c71bd97c2aae357b32a02397b Mon Sep 17 00:00:00 2001 From: Tavi Date: Tue, 9 Apr 2024 13:41:25 -0400 Subject: [PATCH] you want it, you got it! now compile it yourself. Signed-off-by: Tavi --- .../android_frameworks_base/snet-16.patch | 511 ++++++++++++++++++ .../android_system_core/snet-16.patch | 59 ++ .../android_frameworks_base/snet-17.patch | 511 ++++++++++++++++++ .../android_system_core/snet-17.patch | 59 ++ .../android_frameworks_base/snet-18.patch | 511 ++++++++++++++++++ .../android_system_core/snet-18.patch | 59 ++ .../android_frameworks_base/snet-19.patch | 510 +++++++++++++++++ .../android_system_core/snet-19.patch | 85 +++ .../android_frameworks_base/snet-20.patch | 510 +++++++++++++++++ .../android_system_core/snet-20.patch | 85 +++ Scripts/Common/Functions.sh | 6 +- Scripts/LineageOS-16.0/Patch.sh | 2 + Scripts/LineageOS-17.1/Patch.sh | 2 + Scripts/LineageOS-18.1/Patch.sh | 2 + Scripts/LineageOS-19.1/Patch.sh | 2 + Scripts/LineageOS-20.0/Patch.sh | 2 + Scripts/init.sh | 7 + 17 files changed, 2921 insertions(+), 2 deletions(-) create mode 100644 Patches/LineageOS-16.0/android_frameworks_base/snet-16.patch create mode 100644 Patches/LineageOS-16.0/android_system_core/snet-16.patch create mode 100644 Patches/LineageOS-17.1/android_frameworks_base/snet-17.patch create mode 100644 Patches/LineageOS-17.1/android_system_core/snet-17.patch create mode 100644 Patches/LineageOS-18.1/android_frameworks_base/snet-18.patch create mode 100644 Patches/LineageOS-18.1/android_system_core/snet-18.patch create mode 100644 Patches/LineageOS-19.1/android_frameworks_base/snet-19.patch create mode 100644 Patches/LineageOS-19.1/android_system_core/snet-19.patch create mode 100644 Patches/LineageOS-20.0/android_frameworks_base/snet-20.patch create mode 100644 Patches/LineageOS-20.0/android_system_core/snet-20.patch diff --git a/Patches/LineageOS-16.0/android_frameworks_base/snet-16.patch b/Patches/LineageOS-16.0/android_frameworks_base/snet-16.patch new file mode 100644 index 00000000..7e52f0a4 --- /dev/null +++ b/Patches/LineageOS-16.0/android_frameworks_base/snet-16.patch @@ -0,0 +1,511 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Danny Lin +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 +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 +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 +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 +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 +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 +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 +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) { diff --git a/Patches/LineageOS-16.0/android_system_core/snet-16.patch b/Patches/LineageOS-16.0/android_system_core/snet-16.patch new file mode 100644 index 00000000..0268a975 --- /dev/null +++ b/Patches/LineageOS-16.0/android_system_core/snet-16.patch @@ -0,0 +1,59 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Danny Lin +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) { diff --git a/Patches/LineageOS-17.1/android_frameworks_base/snet-17.patch b/Patches/LineageOS-17.1/android_frameworks_base/snet-17.patch new file mode 100644 index 00000000..8187cacf --- /dev/null +++ b/Patches/LineageOS-17.1/android_frameworks_base/snet-17.patch @@ -0,0 +1,511 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Danny Lin +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 +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 +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 +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 +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 +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 +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 +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) { diff --git a/Patches/LineageOS-17.1/android_system_core/snet-17.patch b/Patches/LineageOS-17.1/android_system_core/snet-17.patch new file mode 100644 index 00000000..c21c55a5 --- /dev/null +++ b/Patches/LineageOS-17.1/android_system_core/snet-17.patch @@ -0,0 +1,59 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Danny Lin +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) { diff --git a/Patches/LineageOS-18.1/android_frameworks_base/snet-18.patch b/Patches/LineageOS-18.1/android_frameworks_base/snet-18.patch new file mode 100644 index 00000000..00c8b097 --- /dev/null +++ b/Patches/LineageOS-18.1/android_frameworks_base/snet-18.patch @@ -0,0 +1,511 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Danny Lin +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 +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 +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 +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 +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 +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 +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 +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) { diff --git a/Patches/LineageOS-18.1/android_system_core/snet-18.patch b/Patches/LineageOS-18.1/android_system_core/snet-18.patch new file mode 100644 index 00000000..a1150712 --- /dev/null +++ b/Patches/LineageOS-18.1/android_system_core/snet-18.patch @@ -0,0 +1,59 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Danny Lin +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(); diff --git a/Patches/LineageOS-19.1/android_frameworks_base/snet-19.patch b/Patches/LineageOS-19.1/android_frameworks_base/snet-19.patch new file mode 100644 index 00000000..0e45726c --- /dev/null +++ b/Patches/LineageOS-19.1/android_frameworks_base/snet-19.patch @@ -0,0 +1,510 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Danny Lin +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 +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 +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 +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 +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 +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 +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 +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) { diff --git a/Patches/LineageOS-19.1/android_system_core/snet-19.patch b/Patches/LineageOS-19.1/android_system_core/snet-19.patch new file mode 100644 index 00000000..cf32e7c9 --- /dev/null +++ b/Patches/LineageOS-19.1/android_system_core/snet-19.patch @@ -0,0 +1,85 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Danny Lin +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 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(); diff --git a/Patches/LineageOS-20.0/android_frameworks_base/snet-20.patch b/Patches/LineageOS-20.0/android_frameworks_base/snet-20.patch new file mode 100644 index 00000000..5015310a --- /dev/null +++ b/Patches/LineageOS-20.0/android_frameworks_base/snet-20.patch @@ -0,0 +1,510 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Danny Lin +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 +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 +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 +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 +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 +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 +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 +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) { diff --git a/Patches/LineageOS-20.0/android_system_core/snet-20.patch b/Patches/LineageOS-20.0/android_system_core/snet-20.patch new file mode 100644 index 00000000..4682ea4f --- /dev/null +++ b/Patches/LineageOS-20.0/android_system_core/snet-20.patch @@ -0,0 +1,85 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Danny Lin +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 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(); diff --git a/Scripts/Common/Functions.sh b/Scripts/Common/Functions.sh index d63d65f5..b33c7fbb 100644 --- a/Scripts/Common/Functions.sh +++ b/Scripts/Common/Functions.sh @@ -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; diff --git a/Scripts/LineageOS-16.0/Patch.sh b/Scripts/LineageOS-16.0/Patch.sh index 2591ac20..6d42a453 100644 --- a/Scripts/LineageOS-16.0/Patch.sh +++ b/Scripts/LineageOS-16.0/Patch.sh @@ -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 diff --git a/Scripts/LineageOS-17.1/Patch.sh b/Scripts/LineageOS-17.1/Patch.sh index e9a00802..35a826de 100644 --- a/Scripts/LineageOS-17.1/Patch.sh +++ b/Scripts/LineageOS-17.1/Patch.sh @@ -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 diff --git a/Scripts/LineageOS-18.1/Patch.sh b/Scripts/LineageOS-18.1/Patch.sh index 8a503e1d..311fac8e 100644 --- a/Scripts/LineageOS-18.1/Patch.sh +++ b/Scripts/LineageOS-18.1/Patch.sh @@ -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 diff --git a/Scripts/LineageOS-19.1/Patch.sh b/Scripts/LineageOS-19.1/Patch.sh index 9993e8b8..b300a075 100644 --- a/Scripts/LineageOS-19.1/Patch.sh +++ b/Scripts/LineageOS-19.1/Patch.sh @@ -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 diff --git a/Scripts/LineageOS-20.0/Patch.sh b/Scripts/LineageOS-20.0/Patch.sh index 41e0382c..d8699ffe 100644 --- a/Scripts/LineageOS-20.0/Patch.sh +++ b/Scripts/LineageOS-20.0/Patch.sh @@ -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 diff --git a/Scripts/init.sh b/Scripts/init.sh index 7329a646..1d06d163 100644 --- a/Scripts/init.sh +++ b/Scripts/init.sh @@ -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";