[sanitizers][windows] Correctly override functions with backward jmps
authorMarkus Böck <markus.boeck02@gmail.com>
Mon, 12 Dec 2022 10:45:31 +0000 (11:45 +0100)
committerMarkus Böck <markus.boeck02@gmail.com>
Mon, 12 Dec 2022 10:45:43 +0000 (11:45 +0100)
commit78c033b541f00d12b7e1ba2a676b02e022c9beb1
treeaf82f49b58d0ce365928ace6ab15da7e59577634
parent46242d69fa6dc3916a66447a886ef2b7398ca11f
[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 https://github.com/llvm/llvm-project/issues/58846

Differential Revision: https://reviews.llvm.org/D137788
compiler-rt/lib/interception/interception_win.cpp
compiler-rt/lib/interception/tests/interception_win_test.cpp