feat(spoof): PatchLevelManager with PIF resolution
PatchLevelManager resolves the active security patch from PlayIntegrityFix via the same six-path override chain as Tricky-Addon's get_extra.sh (pif.json/pif.prop/custom.pif.*, later entries override earlier ones). Falls back to live ro.build.version.security_patch when no PIF source is present. updateTo() validates YYYY-MM-DD format, rejects dates below 2020-01-01 or more than one year older than today, then atomically stages security_patch.txt with explicit system/boot/vendor dates and resetprops ro.build.version.security_patch plus ro.vendor.build.security_patch. Cert tags 706/718/719 then encode consistent dates via AndroidDeviceUtils.parsePatchLevelValue (YYYYMM for OS, YYYYMMDD for VENDOR/BOOT per AOSP Tag.aidl). Wired from App.main after BootStateManager.apply().
This commit is contained in:
@@ -10,6 +10,7 @@ import java.security.Security
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider
|
||||
import org.matrix.TEESimulator.config.BootStateManager
|
||||
import org.matrix.TEESimulator.config.ConfigurationManager
|
||||
import org.matrix.TEESimulator.config.PatchLevelManager
|
||||
import org.matrix.TEESimulator.interception.keystore.AbstractKeystoreInterceptor
|
||||
import org.matrix.TEESimulator.interception.keystore.Keystore2Interceptor
|
||||
import org.matrix.TEESimulator.interception.keystore.KeystoreInterceptor
|
||||
@@ -46,6 +47,7 @@ object App {
|
||||
// Load the package configuration.
|
||||
ConfigurationManager.initialize()
|
||||
BootStateManager.apply()
|
||||
PatchLevelManager.initialize()
|
||||
// Set up the device's boot key and hash, which are crucial for attestation.
|
||||
AndroidDeviceUtils.setupBootKeyAndHash()
|
||||
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
package org.matrix.TEESimulator.config
|
||||
|
||||
import android.os.Build
|
||||
import android.os.SystemProperties
|
||||
import java.io.File
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.StandardCopyOption
|
||||
import java.time.LocalDate
|
||||
import org.json.JSONObject
|
||||
import org.matrix.TEESimulator.logging.SystemLogger
|
||||
import org.matrix.TEESimulator.util.AndroidDeviceUtils
|
||||
|
||||
object PatchLevelManager {
|
||||
private const val PATCH_FILE = "/data/adb/tricky_store/security_patch.txt"
|
||||
private const val STAGING_FILE = "/data/adb/tricky_store/security_patch.txt.next"
|
||||
private const val FLOOR_YYYYMMDD = 20200101
|
||||
private const val MAX_PAST_OFFSET = 10000
|
||||
|
||||
private val DATE_PATTERN = Regex("^\\d{4}-\\d{2}-\\d{2}$")
|
||||
private val PROP_PATTERN = Regex("^SECURITY_PATCH=(.+)$", RegexOption.MULTILINE)
|
||||
|
||||
private val PIF_SOURCES =
|
||||
listOf(
|
||||
"/data/adb/modules/playintegrityfix/pif.json",
|
||||
"/data/adb/pif.json",
|
||||
"/data/adb/modules/playintegrityfix/pif.prop",
|
||||
"/data/adb/pif.prop",
|
||||
"/data/adb/modules/playintegrityfix/custom.pif.json",
|
||||
"/data/adb/modules/playintegrityfix/custom.pif.prop",
|
||||
)
|
||||
|
||||
fun initialize() {
|
||||
val date =
|
||||
resolvePifPatch()
|
||||
?: SystemProperties.get(
|
||||
"ro.build.version.security_patch",
|
||||
Build.VERSION.SECURITY_PATCH,
|
||||
)
|
||||
SystemLogger.info("PatchLevelManager: resolved patch date = $date")
|
||||
updateTo(date)
|
||||
}
|
||||
|
||||
fun updateTo(date: String) {
|
||||
if (!DATE_PATTERN.matches(date)) {
|
||||
SystemLogger.warning("PatchLevelManager: invalid date format: $date")
|
||||
return
|
||||
}
|
||||
val dateInt = date.replace("-", "").toInt()
|
||||
if (dateInt < FLOOR_YYYYMMDD) {
|
||||
SystemLogger.warning("PatchLevelManager: $date below floor $FLOOR_YYYYMMDD")
|
||||
return
|
||||
}
|
||||
val today =
|
||||
LocalDate.now().let { it.year * 10000 + it.monthValue * 100 + it.dayOfMonth }
|
||||
if (today >= dateInt + MAX_PAST_OFFSET) {
|
||||
SystemLogger.warning(
|
||||
"PatchLevelManager: $date more than 1y older than today ($today)"
|
||||
)
|
||||
return
|
||||
}
|
||||
atomicWrite(date)
|
||||
AndroidDeviceUtils.setProperty("ro.build.version.security_patch", date)
|
||||
AndroidDeviceUtils.setProperty("ro.vendor.build.security_patch", date)
|
||||
SystemLogger.info("PatchLevelManager: applied patch date $date")
|
||||
}
|
||||
|
||||
private fun resolvePifPatch(): String? {
|
||||
val source = PIF_SOURCES.map(::File).lastOrNull { it.exists() } ?: return null
|
||||
return try {
|
||||
val text = source.readText()
|
||||
val parsed =
|
||||
if (source.name.endsWith(".json")) {
|
||||
JSONObject(text).optString("SECURITY_PATCH", "")
|
||||
} else {
|
||||
PROP_PATTERN.find(text)?.groupValues?.get(1)?.trim().orEmpty()
|
||||
}
|
||||
parsed.takeIf { it.isNotBlank() }
|
||||
} catch (e: Exception) {
|
||||
SystemLogger.warning(
|
||||
"PatchLevelManager: failed to parse ${source.path}: ${e.message}"
|
||||
)
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun atomicWrite(date: String) {
|
||||
val target = File(PATCH_FILE)
|
||||
val staging = File(STAGING_FILE)
|
||||
staging.writeText("system=$date\nboot=$date\nvendor=$date\n")
|
||||
Files.move(
|
||||
staging.toPath(),
|
||||
target.toPath(),
|
||||
StandardCopyOption.ATOMIC_MOVE,
|
||||
StandardCopyOption.REPLACE_EXISTING,
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user