Skip to content

Commit

Permalink
Add jmp macroinst and basic mod checks
Browse files Browse the repository at this point in the history
  • Loading branch information
zyedidia committed Jan 7, 2025
1 parent de5bc8a commit 1cfa181
Show file tree
Hide file tree
Showing 5 changed files with 178 additions and 34 deletions.
78 changes: 44 additions & 34 deletions lfi-verify/amd64/macroinst.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,67 +4,78 @@ struct MacroInst {
};

static struct MacroInst macroinst_jmp(Verifier* v, uint8_t* buf, size_t size) {
FdInstr i_and, i_jmp;
// andl $0xffffffe0, %eX
// orq %r14, %rX
// jmpq *%rX

FdInstr i_and, i_or, i_jmp;
if (fd_decode(&buf[0], size, 64, 0, &i_and) < 0)
return (struct MacroInst){-1, 0};
if (fd_decode(&buf[i_and.size], size - i_and.size, 64, 0, &i_jmp) < 0)
if (fd_decode(&buf[i_and.size], size - i_and.size, 64, 0, &i_or) < 0)
return (struct MacroInst){-1, 0};
if (fd_decode(&buf[i_and.size + i_or.size], size - i_and.size - i_or.size, 64, 0, &i_jmp) < 0)
return (struct MacroInst){-1, 0};
// andq $0xffffffffffffffe0, %rXX

if (FD_TYPE(&i_and) != FDI_AND ||
FD_OP_TYPE(&i_and, 0) != FD_OT_REG ||
FD_OP_SIZE(&i_and, 0) != 4 ||
FD_OP_TYPE(&i_and, 1) != FD_OT_IMM ||
FD_OP_IMM(&i_and, 1) != 0xffffffffffffffe0)
return (struct MacroInst){-1, 0};

// jmpq *%rXX
if (FD_TYPE(&i_or) != FDI_OR ||
FD_OP_TYPE(&i_or, 0) != FD_OT_REG ||
FD_OP_TYPE(&i_or, 1) != FD_OT_REG ||
FD_OP_SIZE(&i_or, 0) != 8 ||
FD_OP_SIZE(&i_or, 1) != 8 ||
FD_OP_REG(&i_or, 1) != FD_REG_R14 ||
FD_OP_REG(&i_or, 0) != FD_OP_REG(&i_and, 0))
return (struct MacroInst){-1, 0};

if (FD_TYPE(&i_jmp) != FDI_JMP ||
FD_OP_TYPE(&i_jmp, 0) != FD_OT_REG ||
FD_OP_REG(&i_jmp, 0) != FD_OP_REG(&i_and, 0))
return (struct MacroInst){-1, 0};

return (struct MacroInst){i_and.size + i_jmp.size, 2};
return (struct MacroInst){i_and.size + i_or.size + i_jmp.size, 3};
}

static struct MacroInst macroinst_call(Verifier* v, uint8_t* buf, size_t size) {
FdInstr i_and, i_call;
// andl $0xffffffe0, %eX
// orq %r14, %rX
// nop*
// callq *%rX

FdInstr i_and, i_or, i_jmp;
if (fd_decode(&buf[0], size, 64, 0, &i_and) < 0)
return (struct MacroInst){-1, 0};
if (fd_decode(&buf[i_and.size], size - i_and.size, 64, 0, &i_call) < 0)
if (fd_decode(&buf[i_and.size], size - i_and.size, 64, 0, &i_or) < 0)
return (struct MacroInst){-1, 0};
if (fd_decode(&buf[i_and.size + i_or.size], size - i_and.size - i_or.size, 64, 0, &i_jmp) < 0)
return (struct MacroInst){-1, 0};
// andq $0xffffffffffffffe0, %rXX

if (FD_TYPE(&i_and) != FDI_AND ||
FD_OP_TYPE(&i_and, 0) != FD_OT_REG ||
FD_OP_SIZE(&i_and, 0) != 4 ||
FD_OP_TYPE(&i_and, 1) != FD_OT_IMM ||
FD_OP_IMM(&i_and, 1) != 0xffffffffffffffe0)
return (struct MacroInst){-1, 0};

// callq *%rXX
if (FD_TYPE(&i_call) != FDI_CALL ||
FD_OP_TYPE(&i_call, 0) != FD_OT_REG ||
FD_OP_REG(&i_call, 0) != FD_OP_REG(&i_and, 0))
if (FD_TYPE(&i_or) != FDI_OR ||
FD_OP_TYPE(&i_or, 0) != FD_OT_REG ||
FD_OP_TYPE(&i_or, 1) != FD_OT_REG ||
FD_OP_SIZE(&i_or, 0) != 8 ||
FD_OP_SIZE(&i_or, 1) != 8 ||
FD_OP_REG(&i_or, 1) != FD_REG_R14 ||
FD_OP_REG(&i_or, 0) != FD_OP_REG(&i_and, 0))
return (struct MacroInst){-1, 0};

return (struct MacroInst){i_and.size + i_call.size, 2};
}

static struct MacroInst macroinst_shxd(Verifier* v, uint8_t* buf, size_t size) {
return (struct MacroInst){-1, 0};
}

static struct MacroInst macroinst_bsx(Verifier* v, uint8_t* buf, size_t size) {
FdInstr i_test, i_jz, i_bsx;
if (fd_decode(&buf[0], size, 64, 0, &i_test) < 0)
return (struct MacroInst){-1, 0};
if (fd_decode(&buf[i_test.size], size - i_test.size, 64, 0, &i_jz) < 0)
return (struct MacroInst){-1, 0};
if (fd_decode(&buf[i_test.size + i_jz.size], size - i_test.size - i_jz.size, 64, 0, &i_bsx) < 0)
if (FD_TYPE(&i_jmp) != FDI_JMP ||
FD_OP_TYPE(&i_jmp, 0) != FD_OT_REG ||
FD_OP_REG(&i_jmp, 0) != FD_OP_REG(&i_and, 0))
return (struct MacroInst){-1, 0};

// test %rXX, %rXX
// jz .SKIP
// bsx
// .SKIP:
return (struct MacroInst){-1, 0};
return (struct MacroInst){i_and.size + i_or.size + i_jmp.size, 3};
}

static struct MacroInst macroinst_modsp(Verifier* v, uint8_t* buf, size_t size) {
Expand All @@ -77,6 +88,8 @@ static struct MacroInst macroinst_modsp(Verifier* v, uint8_t* buf, size_t size)
if (fd_decode(&buf[i_mov.size], size - i_mov.size, 64, 0, &i_or) < 0)
return (struct MacroInst){-1, 0};

printf("%d\n", FD_TYPE(&i_mov));

// allow addl, subl, or movl
if (FD_TYPE(&i_mov) != FDI_MOV &&
FD_TYPE(&i_mov) != FDI_ADD &&
Expand Down Expand Up @@ -104,9 +117,6 @@ typedef struct MacroInst (*MacroFn)(Verifier*, uint8_t*, size_t);

static MacroFn mfns[] = {
macroinst_jmp,
macroinst_call,
macroinst_shxd,
macroinst_bsx,
macroinst_modsp,
};

Expand Down
65 changes: 65 additions & 0 deletions lfi-verify/amd64/macroinst_decl.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
static struct MacroInst macroinst_jmp(Verifier* v, uint8_t* buf, size_t size) {
// andq $0xffffffffffffffe0, %rXX
// jmpq *%rXX

FdInstr i_and, i_jmp;
if (fd_decode(&buf[0], size, 64, 0, &i_and) < 0)
return (struct MacroInst){-1, 0};
if (fd_decode(&buf[i_and.size], size - i_and.size, 64, 0, &i_jmp) < 0)
return (struct MacroInst){-1, 0};
if (FD_TYPE(&i_and) != FDI_AND ||
FD_OP_TYPE(&i_and, 0) != FD_OT_REG ||
FD_OP_TYPE(&i_and, 1) != FD_OT_IMM ||
FD_OP_IMM(&i_and, 1) != 0xffffffffffffffe0)
return (struct MacroInst){-1, 0};

if (FD_TYPE(&i_jmp) != FDI_JMP ||
FD_OP_TYPE(&i_jmp, 0) != FD_OT_REG ||
FD_OP_REG(&i_jmp, 0) != FD_OP_REG(&i_and, 0))
return (struct MacroInst){-1, 0};

return (struct MacroInst){i_and.size + i_jmp.size, 2};
}

static struct MacroInst macroinst_call(Verifier* v, uint8_t* buf, size_t size) {
// andq $0xffffffffffffffe0, %rXX
// callq *%rXX

FdInstr i_and, i_call;
if (fd_decode(&buf[0], size, 64, 0, &i_and) < 0)
return (struct MacroInst){-1, 0};
if (fd_decode(&buf[i_and.size], size - i_and.size, 64, 0, &i_call) < 0)
return (struct MacroInst){-1, 0};
if (FD_TYPE(&i_and) != FDI_AND ||
FD_OP_TYPE(&i_and, 0) != FD_OT_REG ||
FD_OP_TYPE(&i_and, 1) != FD_OT_IMM ||
FD_OP_IMM(&i_and, 1) != 0xffffffffffffffe0)
return (struct MacroInst){-1, 0};

if (FD_TYPE(&i_call) != FDI_CALL ||
FD_OP_TYPE(&i_call, 0) != FD_OT_REG ||
FD_OP_REG(&i_call, 0) != FD_OP_REG(&i_and, 0))
return (struct MacroInst){-1, 0};

return (struct MacroInst){i_and.size + i_call.size, 2};
}

static struct MacroInst macroinst_shxd(Verifier* v, uint8_t* buf, size_t size) {
return (struct MacroInst){-1, 0};
}

static struct MacroInst macroinst_bsx(Verifier* v, uint8_t* buf, size_t size) {
FdInstr i_test, i_jz, i_bsx;
if (fd_decode(&buf[0], size, 64, 0, &i_test) < 0)
return (struct MacroInst){-1, 0};
if (fd_decode(&buf[i_test.size], size - i_test.size, 64, 0, &i_jz) < 0)
return (struct MacroInst){-1, 0};
if (fd_decode(&buf[i_test.size + i_jz.size], size - i_test.size - i_jz.size, 64, 0, &i_bsx) < 0)
return (struct MacroInst){-1, 0};

// test %rXX, %rXX
// jz .SKIP
// bsx
// .SKIP:
return (struct MacroInst){-1, 0};
}
28 changes: 28 additions & 0 deletions lfi-verify/amd64/verify.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ static void verr(Verifier* v, FdInstr* inst, const char* msg) {
verrmin(v, "%x: %s: %s", v->addr, fmtbuf, msg);
}

static bool reserved(FdReg reg) {
return reg == FD_REG_R14 || reg == FD_REG_SP;
}

static bool branchinfo(Verifier* v, FdInstr* instr, int64_t* target, bool* indirect, bool* cond) {
*target = 0;
*indirect = false;
Expand Down Expand Up @@ -153,6 +157,29 @@ static void chkmem(Verifier* v, FdInstr* instr) {
}
}

static int nmod(FdInstr* instr) {
switch (FD_TYPE(instr)) {
case FDI_CMP:
return 0;
case FDI_XCHG:
return 2;
default:
return 1;
}
}

static void chkmod(Verifier* v, FdInstr* instr) {
if (FD_TYPE(instr) == FDI_NOP)
return;

int n = nmod(instr);
assert(n <= 4);
for (size_t i = 0; i < n; i++) {
if (FD_OP_TYPE(instr, i) == FD_OT_REG && reserved(FD_OP_REG(instr, i)))
verr(v, instr, "modification of reserved register");
}
}

static void chkbranch(Verifier* v, FdInstr* instr, size_t bundlesize) {
int64_t target;
bool indirect, cond;
Expand Down Expand Up @@ -188,6 +215,7 @@ static size_t vchkbundle(Verifier* v, uint8_t* buf, size_t size, size_t bundlesi

chkbranch(v, &instr, bundlesize);
chkmem(v, &instr);
chkmod(v, &instr);
}

if (count + mi.size > bundlesize) {
Expand Down
29 changes: 29 additions & 0 deletions lfi-verify/test/amd64/fail.s
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,32 @@ mov (%rsp, %rax), %rax
mov (%rax), %rax
---
mov (%esp), %rax
---
jmp *%rax
---
andl $0xffffffff, %eax
orq %r14, %rax
jmp *%rax
---
andq $0xffffffffffffffe0, %rax
orq %r14, %rax
jmp *%rax
---
andl $0xffffffe0, %eax
jmp *%rax
---
andl $0xffffffe0, %eax
orl %r14d, %eax
jmp *%rax
---
mov %rax, %r14
---
mov $0, %r14
---
mov %rax, %rsp
---
mov $0, %rsp
---
add $12, %rsp
---
xchg %r14, %rax
12 changes: 12 additions & 0 deletions lfi-verify/test/amd64/pass.s
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,15 @@ leaq 8(%rax), %rax
mov 12(%rsp), %rax
---
mov 12(%rip), %rax
---
andl $0xffffffe0, %eax
orq %r14, %rax
jmp *%rax
---
movl %eax, %esp
orq %r14, %rsp
---
add $12, %esp
orq %r14, %rsp
---
cmp %rsp, %rsp

0 comments on commit 1cfa181

Please sign in to comment.