Skip to content

Instantly share code, notes, and snippets.

@jcmvbkbc
Last active June 17, 2022 00:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jcmvbkbc/88bd49600290ee5114418056a4806113 to your computer and use it in GitHub Desktop.
Save jcmvbkbc/88bd49600290ee5114418056a4806113 to your computer and use it in GitHub Desktop.
division-by-0-fixer
#define _GNU_SOURCE
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <signal.h>
#if defined(__x86_64__) || defined(__i386__)
static int fixup_div0(siginfo_t *si, ucontext_t *uc)
{
const uint8_t *insnbuf = si->si_addr;
int d8 = 0;
int sib = 0;
int i = 0;
//fprintf(stderr, "%s: si_addr = %p\n", __func__, si->si_addr);
for (;;) {
/* check for the prefix */
switch (insnbuf[i]) {
case 0xf0: /* LOCK */
case 0xf2: /* REPNZ */
case 0xf3: /* REP */
case 0x2e: /* CS */
case 0x36: /* SS */
case 0x3e: /* DS */
case 0x26: /* ES */
case 0x64: /* FS */
case 0x65: /* GS */
case 0x66: /* operand size */
case 0x67: /* address size */
++i;
continue;
default:
#ifdef __x86_64__
/* REX prefixes */
if ((insnbuf[i] & 0xf0) == 0x40) {
++i;
continue;
}
#endif
break;
}
break;
}
switch (insnbuf[i]) {
case 0xf6: /* IDIV r/m8 */
d8 = 1;
/* fallthrough */
case 0xf7: /* IDIV */
++i;
/* Reg/opcode field in ModR/M byte */
if ((insnbuf[i] & 0x30) == 0x30)
break;
/* fallthrough */
default:
/* unknown opcode */
return 0;
}
/* ModR/M analysis */
switch (insnbuf[i] & 0xc7) {
case 0x04:
case 0x44:
case 0x84:
sib = 1;
break;
}
if ((insnbuf[i] & 0xc7) == 0x05) {
/* disp32 */
i += 4;
} else if ((insnbuf[i] & 0xc0) == 0x40) {
/* disp8 */
++i;
} else if ((insnbuf[i] & 0xc0) == 0x80) {
/* disp32 */
i += 4;
}
i += 1 + sib;
//fprintf(stderr, "insn length = %d\n", i);
#ifdef __x86_64__
#define IP REG_RIP
#define AX REG_RAX
#define DX REG_RDX
#endif
#ifdef __i386__
#define IP REG_EIP
#define AX REG_EAX
#define DX REG_EDX
#endif
uc->uc_mcontext.gregs[IP] += i;
uc->uc_mcontext.gregs[AX] = 0xbadc0de;
if (!d8)
uc->uc_mcontext.gregs[DX] = 0;
return 1;
}
#endif
#if defined(__xtensa__)
#if defined(__XTENSA_EL__)
#define OP_MASK 0x00ff000f
#define OP_QUOU 0x00c20000
#define OP_QUOS 0x00d20000
#define OP_REMU 0x00e20000
#define OP_REMS 0x00f20000
#define R_MASK 0x0000f000
#define R_SHIFT 12
#elif defined(__XTENSA_EB__)
#define OP_MASK 0xf000ff00
#define OP_QUOU 0x00002c00
#define OP_QUOS 0x00002d00
#define OP_REMU 0x00002e00
#define OP_REMS 0x00002f00
#define R_MASK 0x000f0000
#define R_SHIFT 16
#else
#error Unsupported endianness
#endif
static int fixup_div0(siginfo_t *si, ucontext_t *uc)
{
uint32_t opcode = 0;
memcpy(&opcode, si->si_addr, 3);
switch (opcode & OP_MASK) {
case OP_QUOU:
case OP_QUOS:
case OP_REMU:
case OP_REMS:
break;
default:
return 0;
}
uc->uc_mcontext.sc_pc += 3;
uc->uc_mcontext.sc_a[(opcode & R_MASK) >> R_SHIFT] = 0xbadc0de;
return 1;
}
#endif
void fpe_handler(int s, siginfo_t *si, void *c)
{
if (!fixup_div0(si, c))
abort();
}
int8_t s8(int8_t a, int8_t b)
{
return a / b;
}
int32_t s32(int32_t a, int32_t b)
{
return a / b;
}
int64_t s64(int64_t a, int64_t b)
{
return a / b;
}
uint8_t u8(uint8_t a, uint8_t b)
{
return a / b;
}
uint32_t u32(uint32_t a, uint32_t b)
{
return a / b;
}
uint64_t u64(uint64_t a, uint64_t b)
{
return a / b;
}
int main()
{
int a = 0;
int b = 0;
long c = -1;
struct sigaction old_action;
struct sigaction new_action = {
.sa_sigaction = fpe_handler,
.sa_flags = SA_SIGINFO,
};
sigaction(SIGFPE, &new_action, &old_action);
c = s8(a, b);
printf("c = %lx\n", c);
c = s32(a, b);
printf("c = %lx\n", c);
c = s64(a, b);
printf("c = %lx\n", c);
c = u8(a, b);
printf("c = %lx\n", c);
c = u32(a, b);
printf("c = %lx\n", c);
c = u64(a, b);
printf("c = %lx\n", c);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment