Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ASan][Windows] Fix rip-relative instruction replacement #68432

Merged
merged 1 commit into from
Oct 9, 2023

Conversation

strega-nil
Copy link
Contributor

@strega-nil strega-nil commented Oct 6, 2023

The old code incorrectly checked what relative offsets were allowed.

The correct check is that the offset from the target to the instruction pointer should be within $[-2^{31}, 2^{31})$; however, the check that was originally written was that the offset was within $[0, 2^{31})$. Negative offsets are certainly allowable (as long as they fit in 32 bits), and this change fixes that.

@llvmbot
Copy link
Member

llvmbot commented Oct 6, 2023

@llvm/pr-subscribers-compiler-rt-sanitizer

Changes

The old code incorrectly checked what relative offsets were allowed.

The correct check is that the offset from the target to the instruction pointer should be within [-231, 231); however, the check that was originally written was that the offset was within [0, 2**31). Negative offsets are certainly allowable (as long as they fit in 32 bits), and this change fixes that.


Full diff: https://github.com/llvm/llvm-project/pull/68432.diff

1 Files Affected:

  • (modified) compiler-rt/lib/interception/interception_win.cpp (+11-5)
diff --git a/compiler-rt/lib/interception/interception_win.cpp b/compiler-rt/lib/interception/interception_win.cpp
index 23d26ea94b51a66..4f2a51e1adbc6e0 100644
--- a/compiler-rt/lib/interception/interception_win.cpp
+++ b/compiler-rt/lib/interception/interception_win.cpp
@@ -726,16 +726,22 @@ static bool CopyInstructions(uptr to, uptr from, size_t size) {
     size_t instruction_size = GetInstructionSize(from + cursor, &rel_offset);
     if (!instruction_size)
       return false;
-    _memcpy((void*)(to + cursor), (void*)(from + cursor),
+    _memcpy((void *)(to + cursor), (void *)(from + cursor),
             (size_t)instruction_size);
     if (rel_offset) {
-      uptr delta = to - from;
-      uptr relocated_offset = *(u32*)(to + cursor + rel_offset) - delta;
 #if SANITIZER_WINDOWS64
-      if (relocated_offset + 0x80000000U >= 0xFFFFFFFFU)
+      // we want to make sure that the new relative offset still fits in 32-bits
+      // this will be untrue if relocated_offset \notin [-2**31, 2**31)
+      s64 delta = to - from;
+      s64 relocated_offset = *(s32 *)(to + cursor + rel_offset) - delta;
+      if (-0x8000'0000ll > relocated_offset || relocated_offset > 0x7FFF'FFFFll)
         return false;
+#else
+      // on 32-bit, the relative offset will always be correct
+      s32 delta = to - from;
+      s32 relocated_offset = *(s32 *)(to + cursor + rel_offset) - delta;
 #endif
-      *(u32*)(to + cursor + rel_offset) = relocated_offset;
+      *(s32 *)(to + cursor + rel_offset) = relocated_offset;
     }
     cursor += instruction_size;
   }

@github-actions

This comment was marked as resolved.

The old code incorrectly checked what relative offsets were allowed.

The correct check is that the offset from the target to the instruction
pointer should be within $[-2^{31}, 2^{31})$; however, the check that was
originally written was that the offset was within $[0, 2^{31})$.
Negative offsets are certainly allowable (as long as they fit in 32 bits),
and this change fixes that.
@@ -726,16 +726,22 @@ static bool CopyInstructions(uptr to, uptr from, size_t size) {
size_t instruction_size = GetInstructionSize(from + cursor, &rel_offset);
if (!instruction_size)
return false;
_memcpy((void*)(to + cursor), (void*)(from + cursor),
_memcpy((void *)(to + cursor), (void *)(from + cursor),
Copy link
Collaborator

@vitalybuka vitalybuka Oct 9, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this clang-formated?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah.

uptr relocated_offset = *(u32*)(to + cursor + rel_offset) - delta;
#if SANITIZER_WINDOWS64
if (relocated_offset + 0x80000000U >= 0xFFFFFFFFU)
# if SANITIZER_WINDOWS64
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe if constexpr (SANITIZER_WINDOWS64) to compile it always

// we want to make sure that the new relative offset still fits in 32-bits
// this will be untrue if relocated_offset \notin [-2**31, 2**31)
s64 delta = to - from;
s64 relocated_offset = *(s32 *)(to + cursor + rel_offset) - delta;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess you can use same code if use s64/s32 -> sptr

@strega-nil strega-nil merged commit bc34a83 into llvm:main Oct 9, 2023
2 checks passed
@strega-nil strega-nil deleted the fix-relocation-math branch October 9, 2023 21:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants