Implement x86 anal.jmp.retpoline switch tables (spectre/meltdown) ##anal (#16391)

This commit is contained in:
radare 2020-04-01 16:49:39 +02:00 committed by GitHub
parent dc790f5250
commit eaa46ca936
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 76 additions and 2 deletions

View File

@ -360,6 +360,43 @@ static void fcn_takeover_block_recursive(RAnalFunction *fcn, RAnalBlock *start_b
r_anal_block_recurse (start_block, fcn_takeover_block_recursive_cb, fcn);
}
static const char *retpoline_reg(RAnal *anal, ut64 addr) {
RFlagItem *flag = anal->flag_get (anal->flb.f, addr);
if (flag) {
const char *token = "x86_indirect_thunk_";
const char *thunk = strstr (flag->name, token);
if (thunk) {
return thunk + strlen (token);
}
}
#if 0
// TODO: implement following code analysis check for stripped binaries:
// 1) op(addr).type == CALL
// 2) call_dest = op(addr).addr
// 3) op(call_dest).type == STORE
// 4) op(call_dest + op(call_dest).size).type == RET
[0x00000a65]> pid 6
0x00000a65 sym.__x86_indirect_thunk_rax:
0x00000a65 .------- e807000000 call 0xa71
0x00000a6a | f390 pause
0x00000a6c | 0faee8 lfence
0x00000a6f | ebf9 jmp 0xa6a
0x00000a71 `----> 48890424 mov qword [rsp], rax
0x00000a75 c3 ret
#endif
return NULL;
}
static void analyze_retpoline(RAnal *anal, RAnalOp *op) {
if (anal->opt.retpoline) {
const char *rr = retpoline_reg (anal, op->jump);
if (rr) {
op->type = R_ANAL_OP_TYPE_RJMP;
op->reg = rr;
}
}
}
static int fcn_recurse(RAnal *anal, RAnalFunction *fcn, ut64 addr, ut64 len, int depth) {
const int continue_after_jump = anal->opt.afterjmp;
const int addrbytes = anal->iob.io ? anal->iob.io->addrbytes : 1;
@ -677,6 +714,7 @@ repeat:
// swapped parameters wtf
r_anal_xrefs_set (anal, op.addr, op.ptr, R_ANAL_REF_TYPE_DATA);
}
analyze_retpoline (anal, &op);
switch (op.type & R_ANAL_OP_TYPE_MASK) {
case R_ANAL_OP_TYPE_CMOV:
case R_ANAL_OP_TYPE_MOV:

View File

@ -212,6 +212,12 @@ static bool cb_debug_hitinfo(void *user, void *data) {
return true;
}
static bool cb_anal_jmpretpoline(void *user, void *data) {
RCore *core = (RCore*) user;
RConfigNode *node = (RConfigNode*) data;
core->anal->opt.retpoline = node->i_value;
return true;
}
static bool cb_anal_jmptailcall(void *user, void *data) {
RCore *core = (RCore*) user;
RConfigNode *node = (RConfigNode*) data;
@ -2869,6 +2875,7 @@ R_API int r_core_config_init(RCore *core) {
"anal.fcn", "anal.bb",
NULL);
SETI ("anal.timeout", 0, "Stop analyzing after a couple of seconds");
SETCB ("anal.jmp.retpoline", "true", &cb_anal_jmpretpoline, "Analyze retpolines, may be slower if not needed");
SETICB ("anal.jmp.tailcall", 0, &cb_anal_jmptailcall, "Consume a branch as a call if delta is big");
SETCB ("anal.armthumb", "false", &cb_analarmthumb, "aae computes arm/thumb changes (lot of false positives ahead)");

View File

@ -1696,7 +1696,7 @@ static int __runMain(RMainCallback cb, const char *arg) {
char *a = r_str_trim_dup (arg);
int argc = 0;
char **args = r_str_argv (a, &argc);
int res = cb (argc, args);
int res = cb (argc, (const char **)args);
free (args);
free (a);
return res;

View File

@ -1607,7 +1607,7 @@ static int cmd_open(void *data, const char *input) {
char *uri = r_str_newf ("malloc://%d", len);
ut8 *data = calloc (len, 1);
r_io_read_at (core->io, core->offset, data, len);
if (file = r_core_file_open (core, uri, R_PERM_RWX, 0)) {
if ((file = r_core_file_open (core, uri, R_PERM_RWX, 0))) {
fd = file->fd;
core->num->value = fd;
r_core_bin_load (core, uri, 0);

View File

@ -581,6 +581,7 @@ typedef struct r_anal_options_t {
bool endsize; // chop function size which is known to be buggy but goodie too
bool delay;
int tailcall;
bool retpoline;
} RAnalOptions;
typedef enum {

View File

@ -3410,3 +3410,31 @@ e asm.bits=64
ar=
EOF
RUN
NAME=x86_64 retpoline jmptbl
FILE=../bins/elf/retpoline
EXPECT=<<EOF
3:
2:
1:
0:
4:
EOF
CMDS=<<EOF
s 0x780
af
pdr~- case[2]
EOF
RUN
NAME=x86_64 retpoline disabled jmptbl
FILE=../bins/elf/retpoline
EXPECT=<<EOF
EOF
CMDS=<<EOF
e anal.jmp.retpoline = false
s 0x780
af
pdr~- case[2]
EOF
RUN