system_properties: Introduce native PropImitationHooks
Allows spoofing first API and security patch level in order to pass
SafetyNet CTS/Play Integrity on build fingerprints newer than 2018.
Inspired by https://github.com/chiteroman/PlayIntegrityFix
Change-Id: If4dd24abe84edcf5e98d27fb5f78ee99f266b4bd
diff --git a/libc/system_properties/Android.bp b/libc/system_properties/Android.bp
index af8bda9..106401c 100644
--- a/libc/system_properties/Android.bp
+++ b/libc/system_properties/Android.bp
@@ -17,6 +17,7 @@
"contexts_split.cpp",
"contexts_serialized.cpp",
"prop_area.cpp",
+ "prop_imitation_hooks.cpp",
"prop_info.cpp",
"system_properties.cpp",
],
diff --git a/libc/system_properties/include/system_properties/prop_imitation_hooks.h b/libc/system_properties/include/system_properties/prop_imitation_hooks.h
new file mode 100644
index 0000000..5d35ea0
--- /dev/null
+++ b/libc/system_properties/include/system_properties/prop_imitation_hooks.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2023 Paranoid Android
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#pragma once
+
+#include <async_safe/log.h>
+
+#define DEBUG false
+#define LOG_TAG "PropImitationHooks/Native"
+#define PIH_LOG(fmt, ...) if (DEBUG) \
+ async_safe_format_log(ANDROID_LOG_INFO, LOG_TAG, "%s: " fmt, __func__, ##__VA_ARGS__)
+
+class PropImitationHooks {
+ public:
+ PropImitationHooks() = default;
+ void OnFind(const char** name);
+};
diff --git a/libc/system_properties/prop_imitation_hooks.cpp b/libc/system_properties/prop_imitation_hooks.cpp
new file mode 100644
index 0000000..99b145e
--- /dev/null
+++ b/libc/system_properties/prop_imitation_hooks.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 Paranoid Android
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "system_properties/prop_imitation_hooks.h"
+
+#define GMS_UNSTABLE "com.google.android.gms.unstable"
+
+#define PROP_SECURITY_PATCH "ro.build.version.security_patch"
+#define PROP_PIH_SECURITY_PATCH "persist.sys.pihooks.security_patch"
+
+#define PROP_FIRST_API_LEVEL "ro.product.first_api_level"
+#define PROP_PIH_FIRST_API_LEVEL "persist.sys.pihooks.first_api_level"
+
+void PropImitationHooks::OnFind(const char** name) {
+ if (getprogname() == nullptr || strcmp(getprogname(), GMS_UNSTABLE) != 0) {
+ return;
+ }
+ PIH_LOG("name is %s", *name);
+ if (strcmp(*name, PROP_SECURITY_PATCH) == 0) {
+ *name = PROP_PIH_SECURITY_PATCH;
+ } else if (strcmp(*name, PROP_FIRST_API_LEVEL) == 0) {
+ *name = PROP_PIH_FIRST_API_LEVEL;
+ } else {
+ return;
+ }
+ PIH_LOG("name changed to %s", *name);
+}
diff --git a/libc/system_properties/system_properties.cpp b/libc/system_properties/system_properties.cpp
index 1cb15c3..ca8a688 100644
--- a/libc/system_properties/system_properties.cpp
+++ b/libc/system_properties/system_properties.cpp
@@ -46,6 +46,7 @@
#include "system_properties/context_node.h"
#include "system_properties/prop_area.h"
#include "system_properties/prop_info.h"
+#include "system_properties/prop_imitation_hooks.h"
#define SERIAL_DIRTY(serial) ((serial)&1)
#define SERIAL_VALUE_LEN(serial) ((serial) >> 24)
@@ -58,6 +59,8 @@
return S_ISDIR(info.st_mode);
}
+static PropImitationHooks pi_hooks;
+
bool SystemProperties::Init(const char* filename) {
// This is called from __libc_init_common, and should leave errno at 0 (http://b/37248982).
ErrnoRestorer errno_restorer;
@@ -127,6 +130,8 @@
return nullptr;
}
+ pi_hooks.OnFind(&name);
+
prop_area* pa = contexts_->GetPropAreaForName(name);
if (!pa) {
async_safe_format_log(ANDROID_LOG_WARN, "libc", "Access denied finding property \"%s\"", name);