From 4e55ba4e77f2838eafd14b05f7db122d6b81fb18 Mon Sep 17 00:00:00 2001 From: Enginex0 Date: Tue, 19 May 2026 05:09:39 +0100 Subject: [PATCH] fix(spoof): preserve [pkg] sections in atomicWrite atomicWrite previously overwrote the entire security_patch.txt with only the three global lines, destroying the per-package [pkg] overrides supported by ConfigurationManager. Read the existing file, strip only global system/boot/vendor/all key assignments, prepend the refreshed global block, and append everything else (comments, blanks, all [pkg] sections) verbatim. --- .../TEESimulator/config/PatchLevelManager.kt | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/matrix/TEESimulator/config/PatchLevelManager.kt b/app/src/main/java/org/matrix/TEESimulator/config/PatchLevelManager.kt index f036f6d..85e9f0c 100644 --- a/app/src/main/java/org/matrix/TEESimulator/config/PatchLevelManager.kt +++ b/app/src/main/java/org/matrix/TEESimulator/config/PatchLevelManager.kt @@ -19,6 +19,8 @@ object PatchLevelManager { private val DATE_PATTERN = Regex("^\\d{4}-\\d{2}-\\d{2}$") private val PROP_PATTERN = Regex("^SECURITY_PATCH=(.+)$", RegexOption.MULTILINE) + private val SECTION_HEADER = Regex("^\\[[a-zA-Z0-9_.-]+]$") + private val GLOBAL_KEYS = setOf("system", "boot", "vendor", "all") private val PIF_SOURCES = listOf( @@ -107,7 +109,7 @@ object PatchLevelManager { private fun atomicWrite(date: String) { val target = File(PATCH_FILE) val staging = File(STAGING_FILE) - staging.writeText("system=$date\nboot=$date\nvendor=$date\n") + staging.writeText(mergedContents(target, date)) Files.move( staging.toPath(), target.toPath(), @@ -115,4 +117,36 @@ object PatchLevelManager { StandardCopyOption.REPLACE_EXISTING, ) } + + private fun mergedContents(target: File, date: String): String { + val globalBlock = "system=$date\nboot=$date\nvendor=$date\n" + if (!target.exists()) return globalBlock + val tail = + runCatching { stripGlobalAssignments(target.readLines()) }.getOrNull() + ?: return globalBlock + if (tail.isEmpty()) return globalBlock + return globalBlock + tail.joinToString("\n", prefix = "\n", postfix = "\n") + } + + private fun stripGlobalAssignments(lines: List): List { + val kept = mutableListOf() + var inGlobal = true + for (line in lines) { + val trimmed = line.trim() + if (SECTION_HEADER.matches(trimmed)) { + inGlobal = false + kept += line + continue + } + if (inGlobal && isGlobalKeyAssignment(trimmed)) continue + kept += line + } + return kept + } + + private fun isGlobalKeyAssignment(trimmed: String): Boolean { + if (trimmed.isEmpty() || trimmed.startsWith("#")) return false + val key = trimmed.substringBefore("=").trim().lowercase() + return key in GLOBAL_KEYS + } }