aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZeex <zeex@rocketmail.com>2020-11-01 12:10:19 +0600
committerZeex <zeex@rocketmail.com>2020-11-01 12:10:38 +0600
commit499827d15b12aa90de7cb5ba1a2bc6db0fcbec0f (patch)
treec6b24030593960bbd726ee285ef968b778566177
parent0a393c55d587f21c1690d2e64d5635b67dee0c56 (diff)
downloadsubhook-499827d15b12aa90de7cb5ba1a2bc6db0fcbec0f.zip
subhook-499827d15b12aa90de7cb5ba1a2bc6db0fcbec0f.tar.gz
subhook-499827d15b12aa90de7cb5ba1a2bc6db0fcbec0f.tar.bz2
Detect overflows when relocating 32-bit jumps inside trampoline on x64
-rw-r--r--subhook_x86.c31
1 files changed, 22 insertions, 9 deletions
diff --git a/subhook_x86.c b/subhook_x86.c
index 1948386..b4d3a38 100644
--- a/subhook_x86.c
+++ b/subhook_x86.c
@@ -63,6 +63,9 @@
#define JMP64_MOV_SIB 0x24 /* write to [rsp] */
#define JMP64_MOV_OFFSET 0x04
+#define CHECK_INT32_OVERFLOW(x) \
+ ((int64_t)(x) < INT32_MIN || ((int64_t)(x)) > INT32_MAX)
+
#pragma pack(push, 1)
struct subhook_jmp32 {
@@ -336,7 +339,7 @@ static int subhook_make_jmp32(void *src, void *dst) {
#endif
#ifdef SUBHOOK_X86_64
- if (distance < INT32_MIN || distance > INT32_MAX) {
+ if (CHECK_INT32_OVERFLOW(distance)) {
return -EOVERFLOW;
}
#endif
@@ -412,17 +415,27 @@ static int subhook_make_trampoline(void *trampoline,
(void *)(src_addr + orig_size),
insn_len);
- /* If the operand is a relative address, such as found in calls or
- * jumps, it needs to be relocated because the original code and the
- * trampoline reside at different locations in memory.
+ /* If the operand is a relative address, such as found in calls or jumps,
+ * it needs to be relocated because the original code and the trampoline
+ * reside at different locations in memory.
*/
if (reloc_op_offset > 0) {
- /* Calculate how far our trampoline is from the source and change
- * the address accordingly.
+ /* Calculate how far our trampoline is from the source and change the
+ * address accordingly.
*/
- int32_t offset = (int32_t)(trampoline_addr - src_addr);
+ intptr_t offset = trampoline_addr - src_addr;
+#ifdef SUBHOOK_X86_64
+ if (CHECK_INT32_OVERFLOW(offset)) {
+ /*
+ * Oops! It looks like the two locations are too far away from each
+ * other! This is not going to work...
+ */
+ *trampoline_len = 0;
+ return -EOVERFLOW;
+ }
+#endif
int32_t *op = (int32_t *)(trampoline_addr + orig_size + reloc_op_offset);
- *op -= offset;
+ *op -= (int32_t)offset;
}
orig_size += insn_len;
@@ -480,7 +493,7 @@ SUBHOOK_EXPORT subhook_t SUBHOOK_API subhook_new(void *src,
hook->jmp_size,
&hook->trampoline_len,
hook->flags);
- if (result != 0) {
+ if (result != 0 && result != -EOVERFLOW) {
goto error_exit;
}