I have this code which takes bytes from stdin and then tries to unmarshal (basically deserialize) that data through the rubys c api rb_marshal_load function:
#include <ruby.h>
#include "ruby/re.h"
#define MAX_INPUT_SIZE 120
VALUE handle_error(VALUE obj1) {
return 0;
}
VALUE dangerous_func(VALUE x)
{
/* code that could raise an exception */
int thing;
printf("Calling the rb_marshal_load function: \n");
thing = rb_marshal_load(x);
return thing;
}
int main(int argc, char** argv) {
VALUE x;
VALUE result;
int state = 0;
char string[MAX_INPUT_SIZE];
ruby_setup();
ruby_init();
ruby_init_loadpath();
state = 0;
memset(string, 0, MAX_INPUT_SIZE);
read(0, string, MAX_INPUT_SIZE);
if (string[MAX_INPUT_SIZE-2]) {
return 0;
}
printf("Got this: %s\n", string);
x = rb_str_new_cstr(string);
result = rb_protect(dangerous_func, x, &state);
printf("result %d\n", state);
return 0;
}
I know that deserializing user defined input is dangerous, but I do not care about that in this context. I am trying to replicate this: https://medium.com/fuzzstation/breaking-rubys-unmarshal-with-afl-fuzz-6b5f72b581d5 with the C api instead of calling the ruby interpreter on a ruby script, because this way I think that it is a lot faster. This code works, but when I add the afl __AFL_LOOP() persistent loop to this code like so:
#include <ruby.h>
#include "ruby/re.h"
#define MAX_INPUT_SIZE 120
VALUE handle_error(VALUE obj1) {
return 0;
}
VALUE dangerous_func(VALUE x)
{
/* code that could raise an exception */
int thing;
printf("Calling the rb_marshal_load function: \n");
thing = rb_marshal_load(x);
printf("Regex return value: %d\n", thing);
return thing;
}
int main(int argc, char** argv) {
VALUE x;
VALUE result;
int state = 0;
char string[MAX_INPUT_SIZE];
ruby_setup();
ruby_init();
ruby_init_loadpath();
while (__AFL_LOOP(1000)) {
state = 0;
memset(string, 0, MAX_INPUT_SIZE);
read(0, string, MAX_INPUT_SIZE);
if (string[MAX_INPUT_SIZE-2]) {
return 0;
}
printf("Got this: %s\n", string);
x = rb_str_new_cstr(string);
result = rb_protect(dangerous_func, x, &state);
printf("result %d\n", state);
}
return 0;
}
I get an out-of-memory error after a bit of fuzzing with afl. I think that this is because the objects allocated by rb_marshal_load never get freed. I tried to do simply:
free(thing);
but that did not work.
How do I free the allocated object properly?
Thanks in advance for the help!