-
-
Notifications
You must be signed in to change notification settings - Fork 3k
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
Fix OOB in the Gameboy instruction decoder ##anal #17088
Conversation
The only thing that sucks at the moment is that you didn't fill it with, at least, the output of ASAN I provided. When in 3 months from now someone will look at this PR, they will have no idea why this change was done. There are reasons why there is this template to file. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a description of what this is even for.
libr/anal/p/anal_gb.c
Outdated
@@ -714,7 +714,10 @@ static bool gb_custom_daa (RAnalEsil *esil) { | |||
static int gb_anop(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *data, int len, RAnalOpMask mask) { | |||
int ilen = gbOpLength (gb_op[data[0]].type); | |||
if (ilen > len) { | |||
ilen = 0; | |||
op->addr = addr; | |||
op->type = R_ANAL_OP_TYPE_UNK; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i would say that if the instruction trying to be disassembled is bigger than the provided buffer the type should be INV (as for invalid) and about op->size. i would keep the original opsize, and just return 0 or -1. because this way the user knows how many bytes must be provided to get the disasm of that instruction.
also i think op->addr is filled by the caller of this callback. so no need to set it in here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pìng
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry for the delay, my laptop broke and i had to wait for spare parts to repair
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"also i think op->addr is filled by the caller of this callback. so no need to set it in here." - why do you pass addr to plugin->op then, if you already pass op to it?
Can you provide a test for this bug? any reproducer? stuff like this must be properly defined in the documentation and stated in the unit test for the RAsm api. because invalid,unaligned,truncated are valid events in r2 disasm but it's probably not clear enough how to handle this without reading other plugin's code |
ping @condret |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can add a test like this:
$ rasm2 -a gb -d 30
invalid
$ r2 -qc 'pad 30@a:gb' -
invalid
But i think there was a reproducer somewhere, anyway
libr/anal/p/anal_gb.c
Outdated
op->addr = addr; | ||
op->type = R_ANAL_OP_TYPE_UNK; | ||
op->size = 0; | ||
return 0; | ||
} else if (mask & R_ANAL_OP_MASK_DISASM) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
don't else after return
libr/anal/p/anal_gb.c
Outdated
@@ -714,7 +714,10 @@ static bool gb_custom_daa (RAnalEsil *esil) { | |||
static int gb_anop(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *data, int len, RAnalOpMask mask) { | |||
int ilen = gbOpLength (gb_op[data[0]].type); | |||
if (ilen > len) { | |||
ilen = 0; | |||
op->addr = addr; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think this field is set by the caller, so you dont need to define it here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure about that. Also if that is the case, why do we pass addr to plugin->op anyway?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good question, we can probably get rid of this argument too
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But i think it is better to focus on rarch refactoring to do that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so far this plugin has set the addr on it's own, and I believe that other plugins do that as well. so not sure if removing that line would be good
ilen = 0; | ||
op->addr = addr; | ||
op->type = R_ANAL_OP_TYPE_UNK; | ||
op->size = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you may set op->size = ilen; this way the caller knows the size of the instruction that was not possible to disassebmle because of lack of data provided
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
well, I can do that, but that requires the caller to check the return value and the value in op. ... Maybe one should consider making plugin->op return a bool instead of length?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah seems like an option here. Enforcing opsize only in one place and return bool to specify success or not. The reason can be found in the ranalop struct if needed. But that should be done in another pr. Kinda big change i guess
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, so for now, I'd like to keep this as it is
@thestr4ng3r I don't see what is so hard to understand about "fix oob heap access". |
It's unclear from the diff where the oob comes from without a reproducer. |
Ok, I will change that and also check other plugins and open issues for them |
here some copypasta showing the problem.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, that clears it up for me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
<!-- Filling this template sucks -->
Your checklist for this pull request
Detailed description
...
Test plan
...
Closing issues
...