tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 4492b391756a982d466fbdfcd328041861e9b314
parent e802acf1b449c6471c1c0cbf81703e671b6afd3e
Author: Greg Stoll <gstoll@mozilla.com>
Date:   Tue, 28 Oct 2025 15:19:16 +0000

Bug 1919213 part 2 - handle patching JS jump instruction r=yjuglaret,win-reviewers

We previously handled part of this in bug 1918478, but this was only
fixed in ESR. This handles the JS instructions that take single byte
and four byte offsets, and adds tests.

Differential Revision: https://phabricator.services.mozilla.com/D268652

Diffstat:
Mtoolkit/xre/dllservices/mozglue/interceptor/PatcherDetour.h | 32+++++++++++++++++++++++++++++++-
Mtoolkit/xre/dllservices/tests/AssemblyPayloads.h | 41+++++++++++++++++++++++++++++++++++++++++
Mtoolkit/xre/dllservices/tests/TestDllInterceptor.cpp | 2++
3 files changed, 74 insertions(+), 1 deletion(-)

diff --git a/toolkit/xre/dllservices/mozglue/interceptor/PatcherDetour.h b/toolkit/xre/dllservices/mozglue/interceptor/PatcherDetour.h @@ -664,7 +664,7 @@ class WindowsDllDetourPatcher final } # if defined(_M_X64) - enum class JumpType { Je, Jne, Jae, Jmp, Call }; + enum class JumpType { Je, Jne, Jae, Jmp, Call, Js }; static bool GenerateJump(Trampoline<MMPolicyT>& aTramp, uintptr_t aAbsTargetAddress, const JumpType aType) { @@ -695,6 +695,10 @@ class WindowsDllDetourPatcher final // JB RIP+14 aTramp.WriteByte(0x72); aTramp.WriteByte(14); + } else if (aType == JumpType::Js) { + // JNS RIP+14 + aTramp.WriteByte(0x79); + aTramp.WriteByte(14); } // Near jmp, absolute indirect, address given in r/m32 @@ -1176,6 +1180,15 @@ class WindowsDllDetourPatcher final jumpType)) { return; } + } else if (*origBytes == 0x88) { + // 0f 88 cd JS rel32 + ++origBytes; + --tramp; // overwrite the 0x0f we copied above + + if (!GenerateJump(tramp, origBytes.ReadDisp32AsAbsolute(), + JumpType::Js)) { + return; + } } else { MOZ_ASSERT_UNREACHABLE("Unrecognized opcode sequence"); return; @@ -1551,6 +1564,23 @@ class WindowsDllDetourPatcher final jumpType)) { return; } + } else if (*origBytes == 0x78) { + // 78 cb JS rel8 + int8_t offset = origBytes[1]; + if (offset < 0) { + // We don't support backwards relative jumps. If we want to in the + // future we should find a good way to test them. + MOZ_ASSERT_UNREACHABLE( + "Unrecognized opcode sequence - backwards relative jump"); + return; + } + + origBytes += 2; + + if (!GenerateJump(tramp, origBytes.OffsetToAbsolute(offset), + JumpType::Js)) { + return; + } } else if (*origBytes == 0xff) { uint8_t mod = origBytes[1] & kMaskMod; uint8_t reg = (origBytes[1] & kMaskReg) >> kRegFieldShift; diff --git a/toolkit/xre/dllservices/tests/AssemblyPayloads.h b/toolkit/xre/dllservices/tests/AssemblyPayloads.h @@ -78,6 +78,9 @@ __declspec(dllexport) MOZ_NAKED void NearJump() { "jae label3;" "je label3;" "jne label3;" + // This is past the 13 bytes that we patch (each instruction + // above is 6 bytes long)), so any instructions after + // this won't be patched. "label4:" "mov %0, %%rax;" @@ -92,6 +95,44 @@ __declspec(dllexport) MOZ_NAKED void NearJump() { : "i"(JumpDestination)); } +__declspec(dllexport) MOZ_NAKED void NearJump2() { + asm volatile( + "js label5;" + // Above instruction takes up 6 bytes of the 13 bytes + // that we patch. + + "label6:" + "mov %0, %%rax;" + "jmpq *%%rax;" + + // 0x100 bytes padding to generate js rel32 instead of js rel8 + PADDING_256_NOP + + "label5:" + "jmp label6;" + : + : "i"(JumpDestination)); +} + +__declspec(dllexport) MOZ_NAKED void JumpWith8BitOffset() { + asm volatile( + "jae label7;" + "je label7;" + "jne label7;" + "js label7;" + // Above instructions take up 8 bytes (each one is 2 bytes long) + // of the 13 bytes that we patch. + + "label8:" + "mov %0, %%rax;" + "jmpq *%%rax;" + + "label7:" + "jmp label8;" + : + : "i"(JumpDestination)); +} + __declspec(dllexport) MOZ_NAKED void OpcodeFF() { // Skip PUSH (FF /6) because clang prefers Opcode 50+rd // to translate PUSH r64 rather than Opcode FF. diff --git a/toolkit/xre/dllservices/tests/TestDllInterceptor.cpp b/toolkit/xre/dllservices/tests/TestDllInterceptor.cpp @@ -830,6 +830,8 @@ MOZ_GLOBINIT struct TestCase { // Passing NoStubAddressCheck as the following testcases return // a trampoline address instead of the original destination. TestCase("NearJump", NoStubAddressCheck), + TestCase("NearJump2", NoStubAddressCheck), + TestCase("JumpWith8BitOffset", NoStubAddressCheck), TestCase("OpcodeFF", NoStubAddressCheck), TestCase("IndirectCall", NoStubAddressCheck), TestCase("MovImm64", NoStubAddressCheck),