-
Notifications
You must be signed in to change notification settings - Fork 21
First shot at gum_stalker_prefetch support #10
Conversation
Thanks to @WorksButNotTested for adding this feature to Frida
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.
w00t! 🚀
static void prefetch_log(const GumEvent* event, GumCpuContext* cpu_context, gpointer user_data) { | ||
switch (event->type) { | ||
case GUM_COMPILE: { | ||
const GumCompileEvent* compile = &event->compile; |
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 could consider doing this in the transformer to avoid the need for a separate event sink. This may help performance.
gpointer key, value; | ||
g_hash_table_iter_init(&iter, table); | ||
while (g_hash_table_iter_next(&iter, &key, &value)) { | ||
int status = write(fd, &key, sizeof(key)); |
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 consider using a shared memory IPC like AFL already uses for the coverage bitmap. This way, you should not need any syscalls and hence any world switches after the initial setup.
|
||
static void prefetch_read(int fd, GHashTable *table) { | ||
gpointer block_address; | ||
while (read(fd, &block_address, sizeof(block_address)) == sizeof(block_address)) { |
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.
If you prefer the pipes, you could consider reading a buffer full of address in one go to reduce the number of syscalls. This could be further reduced if prefetching is only triggered every 'n' forks. Whilst slower during the initial run-up, this will be quicker later on when there are few new paths being discovered.
|
||
// This is written into by "prefetch_log". | ||
// | ||
prefetch_compiled = g_hash_table_new(NULL, NULL); |
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 went with a single hash table as follows:
- The parent creates a hash table of prefetched blocks during init.
- The child inherits a COPY of this on fork.
- The child checks the hash table before writing a block to the IPC
- The child then adds the block to its copy of the hash table to avoid any duplicates being sent.
- The parent reads blocks from the IPC and updates its copy of the hash table as it goes.
- The hash table is then inherited by the next child.
@@ -58,6 +127,8 @@ int main(int argc, char* argv[]) { | |||
|
|||
gum_stalker_unfollow_me(stalker); | |||
|
|||
prefetch_write(compile_pipes[STDOUT_FILENO], prefetch_compiled); |
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 could consider omitting the garbage collection step as you are about to bin the child anyway. You might get some performance gain.
@@ -1,6 +1,6 @@ | |||
/* | |||
Copyright 2013 Google LLC All rights reserved. | |||
Copyright 2020 Keegan S. <keegan@sdf.org> | |||
Copyright 2020 Keegan Saunders <keegan@undefinedbehaviour.org> |
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.
Looks good to me. Does it help performance any? I've had a few thoughts below on how you might squeeze a little bit more performance out of it.
Closing in favour of #15 |
Thanks to @WorksButNotTested for adding this feature to Frida
Closes #2