diff --git a/app/src/main/java/com/droiddeck/launcher/runtime/ElfSeccompPatch.kt b/app/src/main/java/com/droiddeck/launcher/runtime/ElfSeccompPatch.kt index 22595b952..817cbc975 100644 --- a/app/src/main/java/com/droiddeck/launcher/runtime/ElfSeccompPatch.kt +++ b/app/src/main/java/com/droiddeck/launcher/runtime/ElfSeccompPatch.kt @@ -47,11 +47,15 @@ object ElfSeccompPatch { var next = pos + 4 val limit = minOf(end, pos + 4 + WINDOW * 4) while (next < limit) { - if (buffer.getInt(next) == SVC) { + val insn = buffer.getInt(next) + if (insn == SVC) { buffer.putInt(next, replacement) patched++ break } + // A site patched before, or x8 set again: an svc after it is another call's + // (a second run found clone3's thread exit there and turned it into -ENOSYS) + if (insn == MOV_X0_ENOSYS || (insn and 0x1f) == 8) break next += 4 } } diff --git a/app/src/test/java/com/droiddeck/launcher/runtime/ElfSeccompPatchTest.kt b/app/src/test/java/com/droiddeck/launcher/runtime/ElfSeccompPatchTest.kt index ec751d739..386017d15 100644 --- a/app/src/test/java/com/droiddeck/launcher/runtime/ElfSeccompPatchTest.kt +++ b/app/src/test/java/com/droiddeck/launcher/runtime/ElfSeccompPatchTest.kt @@ -32,6 +32,18 @@ class ElfSeccompPatchTest { assertEquals(0, ElfSeccompPatch.patch(data)) } + @Test + fun aSecondRunLeavesTheNextCallAlone() { + val svc = 0xd4000001.toInt() + val exit = 0xd2800ba8.toInt() + for (blocked in listOf(0xd2803668.toInt(), 0xd2800c68.toInt())) { + val data = elfWith(blocked, svc, 0xaa1303e0.toInt(), exit, svc) + assertEquals(1, ElfSeccompPatch.patch(data)) + assertEquals(0, ElfSeccompPatch.patch(data)) + assertEquals(svc, ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN).getInt(0x110)) + } + } + @Test fun otherSystemCallsAreLeftAlone() { val svc = 0xd4000001.toInt()