Skip to content

Commit 78c033b

Browse files
committed
[sanitizers][windows] Correctly override functions with backward jmps
To reproduce: Download and run the latest Firefox ASAN build (https://firefox-ci-tc.services.mozilla.com/api/index/v1/task/gecko.v2.mozilla-central.latest.firefox.win64-asan-opt/artifacts/public/build/target.zip) on Windows 11 (version 10.0.22621 Build 22621); it will crash on launch. Note that this doesn't seem to crash on another Windows 11 VM I've tried, so I'm not sure how reproducible it is across machines, but it reproduces on my machine every time. The problem seems to be that when overriding the memset function in OverrideFunctionWithRedirectJump(), the relative_offset is stored as a uptr. Per the Intel x64 instruction set reference (https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf - warning: large PDF), on page 646 the jmp instruction (specifically the near jump flavors that start with E9, which are the ones the OverrideFunctionWithRedirectJump() considers) treats the offset as a signed displacement. This causes an incorrect value to be stored for REAL(memset) which points to uninitialized memory, and a crash the next time that gets called. The fix is to simply treat that offset as signed. I have also added a test case. Fixes llvm#58846 Differential Revision: https://reviews.llvm.org/D137788
1 parent 46242d6 commit 78c033b

File tree

2 files changed

+30
-8
lines changed

2 files changed

+30
-8
lines changed

compiler-rt/lib/interception/interception_win.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -738,7 +738,7 @@ bool OverrideFunctionWithRedirectJump(
738738
return false;
739739

740740
if (orig_old_func) {
741-
uptr relative_offset = *(u32*)(old_func + 1);
741+
sptr relative_offset = *(s32 *)(old_func + 1);
742742
uptr absolute_target = old_func + relative_offset + kJumpInstructionLength;
743743
*orig_old_func = absolute_target;
744744
}

compiler-rt/lib/interception/tests/interception_win_test.cpp

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,16 @@ const u8 kIdentityCodeWithJump[] = {
8585
0xC3, // ret
8686
};
8787

88-
#else
88+
const u8 kIdentityCodeWithJumpBackwards[] = {
89+
0x89, 0xC8, // mov eax, ecx
90+
0xC3, // ret
91+
0xE9, 0xF8, 0xFF, 0xFF,
92+
0xFF, // jmp - 8
93+
0xCC, 0xCC, 0xCC, 0xCC,
94+
};
95+
const u8 kIdentityCodeWithJumpBackwardsOffset = 3;
96+
97+
# else
8998

9099
const u8 kIdentityCodeWithPrologue[] = {
91100
0x55, // push ebp
@@ -134,7 +143,16 @@ const u8 kIdentityCodeWithJump[] = {
134143
0xC3, // ret
135144
};
136145

137-
#endif
146+
const u8 kIdentityCodeWithJumpBackwards[] = {
147+
0x8B, 0x44, 0x24, 0x04, // mov eax,dword ptr [esp + 4]
148+
0xC3, // ret
149+
0xE9, 0xF6, 0xFF, 0xFF,
150+
0xFF, // jmp - 10
151+
0xCC, 0xCC, 0xCC, 0xCC,
152+
};
153+
const u8 kIdentityCodeWithJumpBackwardsOffset = 5;
154+
155+
# endif
138156

139157
const u8 kPatchableCode1[] = {
140158
0xB8, 0x4B, 0x00, 0x00, 0x00, // mov eax,4B
@@ -366,13 +384,14 @@ TEST(Interception, InternalGetProcAddress) {
366384
EXPECT_NE(DbgPrint_adddress, isdigit_address);
367385
}
368386

369-
template<class T>
387+
template <class T>
370388
static void TestIdentityFunctionPatching(
371-
const T &code,
372-
TestOverrideFunction override,
373-
FunctionPrefixKind prefix_kind = FunctionPrefixNone) {
389+
const T &code, TestOverrideFunction override,
390+
FunctionPrefixKind prefix_kind = FunctionPrefixNone,
391+
int function_start_offset = 0) {
374392
uptr identity_address;
375393
LoadActiveCode(code, &identity_address, prefix_kind);
394+
identity_address += function_start_offset;
376395
IdentityFunction identity = (IdentityFunction)identity_address;
377396

378397
// Validate behavior before dynamic patching.
@@ -410,7 +429,7 @@ static void TestIdentityFunctionPatching(
410429
TestOnlyReleaseTrampolineRegions();
411430
}
412431

413-
#if !SANITIZER_WINDOWS64
432+
# if !SANITIZER_WINDOWS64
414433
TEST(Interception, OverrideFunctionWithDetour) {
415434
TestOverrideFunction override = OverrideFunctionWithDetour;
416435
FunctionPrefixKind prefix = FunctionPrefixDetour;
@@ -424,6 +443,9 @@ TEST(Interception, OverrideFunctionWithDetour) {
424443
TEST(Interception, OverrideFunctionWithRedirectJump) {
425444
TestOverrideFunction override = OverrideFunctionWithRedirectJump;
426445
TestIdentityFunctionPatching(kIdentityCodeWithJump, override);
446+
TestIdentityFunctionPatching(kIdentityCodeWithJumpBackwards, override,
447+
FunctionPrefixNone,
448+
kIdentityCodeWithJumpBackwardsOffset);
427449
}
428450

429451
TEST(Interception, OverrideFunctionWithHotPatch) {

0 commit comments

Comments
 (0)