Skip to content

Commit d1981f4

Browse files
committed
luzer: fix parse args from lua & added support for command line arguments for libfuzzer
Fixes #13
1 parent 0179547 commit d1981f4

File tree

3 files changed

+164
-36
lines changed

3 files changed

+164
-36
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1414
- Integration with libFuzzer's `FuzzedDataProvider`.
1515
- Examples with tests.
1616
- Documentation with usecases, API etc.
17+
- Added support for command line arguments for libfuzzer.
18+
- Added an environment variable to disable parsing of command line arguments for libphaser - `LUZER_NOT_USE_CLI_ARGS_FOR_LF`.

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ local function TestOneInput(buf)
5353
end
5454
end
5555

56-
luzer.Fuzz(TestOneInput)
56+
luzer.Fuzz(TestOneInput, nil, {})
5757
```
5858

5959
3. Start the fuzzer using the fuzz target

luzer/luzer.c

Lines changed: 161 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@
3131
#define CUSTOM_MUTATOR_LIB "libcustom_mutator.so.1"
3232
#define DEBUG_HOOK_FUNC "luzer_custom_hook"
3333

34+
#define ENV_NOT_USE_CLI_ARGS "LUZER_NOT_USE_CLI_ARGS_FOR_LF"
35+
36+
#define LUA_CORPUS_FLAG "-corpus"
37+
3438
static lua_State *LL;
3539

3640
static void
@@ -324,55 +328,177 @@ load_custom_mutator_lib(void) {
324328
return 0;
325329
}
326330

331+
/* Structure for convenient argument parsing. */
332+
struct args {
333+
char **argv;
334+
int argc;
335+
};
336+
337+
NO_SANITIZE static bool
338+
is_flag_in_args(struct args *f_args, const char *key) {
339+
if (!f_args || !f_args->argv || f_args->argc <= 0)
340+
return false;
341+
char search_flag[strlen(key) + 3];
342+
snprintf(search_flag, strlen(key) + 3, "-%s=", key);
343+
for (int i = 0; i <= f_args->argc; i++) {
344+
if (strncmp(f_args->argv[i], search_flag, strlen(search_flag)) == 0)
345+
return true;
346+
}
347+
return false;
348+
}
349+
327350
NO_SANITIZE static int
328-
luaL_fuzz(lua_State *L)
329-
{
330-
if (lua_istable(L, -1) == 0) {
331-
luaL_error(L, "opts is not a table");
351+
get_args_from_cli(lua_State *L, struct args *cli_args) {
352+
lua_getglobal(L, "arg");
353+
354+
cli_args->argv = malloc(1 * sizeof(char*));
355+
if (!cli_args->argv)
356+
luaL_error(L, "not enough memory");
357+
358+
lua_pushnil(L);
359+
360+
char* not_use_cli_args = getenv(ENV_NOT_USE_CLI_ARGS);
361+
cli_args->argc = 0;
362+
while (lua_next(L, -2) != 0) {
363+
const char *value = lua_tostring(L, -1);
364+
const int key = lua_tointeger(L, -2);
365+
lua_pop(L, 1);
366+
if (key < 0)
367+
continue;
368+
369+
const char *arg = strdup(value);
370+
if (!arg) {
371+
free(cli_args->argv);
372+
luaL_error(L, "not enough memory");
373+
}
374+
375+
if (key > 0 && (not_use_cli_args == NULL || !strcmp(not_use_cli_args, "0"))) {
376+
cli_args->argc++;
377+
char **argvp = realloc(cli_args->argv, sizeof(char*) * (cli_args->argc + 1));
378+
if (argvp == NULL) {
379+
free(cli_args->argv);
380+
luaL_error(L, "not enough memory");
381+
}
382+
cli_args->argv = argvp;
383+
cli_args->argv[cli_args->argc] = (char*)arg;
384+
} else {
385+
cli_args->argv[0] = (char*)arg;
386+
}
332387
}
388+
lua_pop(L, 1);
389+
return 0;
390+
}
391+
392+
NO_SANITIZE static int
393+
get_args_from_lua(lua_State *L, struct args *lua_args, struct args *cli_args) {
394+
if (lua_istable(L, -1) == 0)
395+
luaL_error(L, "opts is not a table");
396+
333397
lua_pushnil(L);
334398

335399
/* Processing a table with options. */
336-
int argc = 0;
337-
char **argv = malloc(1 * sizeof(char*));
338-
if (!argv)
339-
luaL_error(L, "not enough memory");
340-
const char *corpus_path = NULL;
341-
while (lua_next(L, -2) != 0) {
342-
char **argvp = realloc(argv, sizeof(char*) * (argc + 1));
343-
if (argvp == NULL) {
344-
free(argv);
345-
luaL_error(L, "not enough memory");
346-
}
400+
lua_args->argc = 0;
401+
while (lua_next(L, -2) != 0) {
347402
const char *key = lua_tostring(L, -2);
348403
const char *value = lua_tostring(L, -1);
349-
if (strcmp(key, "corpus") != 0) {
350-
size_t arg_len = strlen(key) + strlen(value) + 3;
351-
char *arg = calloc(arg_len, sizeof(char));
352-
if (!arg)
404+
lua_pop(L, 1);
405+
if (is_flag_in_args(cli_args, key))
406+
continue;
407+
408+
if (lua_args->argc > 0) {
409+
char **argvp = realloc(lua_args->argv, sizeof(char*) * (lua_args->argc + 1));
410+
if (argvp == NULL) {
411+
free(lua_args->argv);
353412
luaL_error(L, "not enough memory");
354-
snprintf(arg, arg_len, "-%s=%s", key, value);
355-
argvp[argc] = arg;
356-
argc++;
413+
}
414+
lua_args->argv = argvp;
357415
} else {
358-
corpus_path = strdup(value);
416+
lua_args->argv = malloc(1 * sizeof(char*));
417+
if (!lua_args->argv)
418+
luaL_error(L, "not enough memory");
359419
}
360-
lua_pop(L, 1);
361-
argv = argvp;
420+
size_t arg_len = strlen(key) + strlen(value) + 3;
421+
char *arg = calloc(arg_len, sizeof(char));
422+
if (!arg){
423+
free(lua_args->argv);
424+
luaL_error(L, "not enough memory");
425+
}
426+
snprintf(arg, arg_len, "-%s=%s", key, value);
427+
lua_args->argv[lua_args->argc] = arg;
428+
lua_args->argc++;
362429
}
363-
if (corpus_path) {
364-
argv[argc] = (char*)corpus_path;
365-
argc++;
430+
431+
lua_pop(L, 1);
432+
return 0;
433+
}
434+
435+
NO_SANITIZE static int
436+
merge_args(struct args *cli_args, struct args *lua_args, struct args *total_args) {
437+
total_args->argc = (cli_args->argc + lua_args->argc + 1);
438+
total_args->argv = malloc(sizeof(char*) * (total_args->argc + 1));
439+
if (!cli_args->argv)
440+
return -1;
441+
/* Program name on zero index. */
442+
total_args->argv[0] = cli_args->argv[0];
443+
444+
int cur_pos_arg = 1;
445+
char *corpus_path = NULL;
446+
for (int i = 0; i < lua_args->argc; i++) {
447+
if (strncmp(lua_args->argv[i], LUA_CORPUS_FLAG, strlen(LUA_CORPUS_FLAG)) == 0) {
448+
int corpus_path_len = strlen(lua_args->argv[i]) - strlen(LUA_CORPUS_FLAG);
449+
corpus_path = malloc(corpus_path_len * sizeof(char*));
450+
if (!corpus_path)
451+
return -1;
452+
memcpy(corpus_path, &lua_args->argv[i][strlen(LUA_CORPUS_FLAG) + 1], corpus_path_len);
453+
free(lua_args->argv[i]);
454+
} else {
455+
total_args->argv[cur_pos_arg] = lua_args->argv[i];
456+
cur_pos_arg++;
457+
}
366458
}
367-
if (argc == 0) {
368-
argv[argc] = "";
369-
argc++;
459+
for (int i = 1; i <= cli_args->argc; i++) {
460+
total_args->argv[cur_pos_arg] = cli_args->argv[i];
461+
cur_pos_arg++;
370462
}
371-
argv[argc] = NULL;
372-
lua_pop(L, 1);
463+
if (corpus_path) {
464+
total_args->argv[cur_pos_arg] = corpus_path;
465+
cur_pos_arg++;
466+
}
467+
total_args->argv[total_args->argc] = NULL;
468+
469+
if (lua_args->argv)
470+
free(lua_args->argv);
471+
472+
if (cli_args->argv)
473+
free(cli_args->argv);
474+
475+
return 0;
476+
}
477+
478+
479+
NO_SANITIZE static int
480+
luaL_fuzz(lua_State *L)
481+
{
482+
int result = -1;
483+
struct args cli_args = { .argv = NULL, .argc = 0 };
484+
struct args lua_args = { .argv = NULL, .argc = 0 };
485+
struct args total_args = { .argv = NULL, .argc = 0 };
486+
487+
result = get_args_from_cli(L, &cli_args);
488+
if (result < 0)
489+
luaL_error(L, "failed to parse arguments from console");
490+
491+
/* If flag in cli and lua is duplicated, then flag from lua is ignored. */
492+
result = get_args_from_lua(L, &lua_args, &cli_args);
493+
if (result < 0)
494+
luaL_error(L, "failed to parse arguments from lua");
495+
496+
result = merge_args(&cli_args, &lua_args, &total_args);
497+
if (result < 0)
498+
luaL_error(L, "failed to merge arguments");
373499

374500
#ifdef DEBUG
375-
char **p = argv;
501+
char **p = total_args.argv;
376502
while(*p++) {
377503
if (*p)
378504
DEBUG_PRINT("libFuzzer arg - '%s'\n", *p);
@@ -415,7 +541,7 @@ luaL_fuzz(lua_State *L)
415541
lua_pop(L, -1);
416542

417543
set_global_lua_state(L);
418-
int rc = LLVMFuzzerRunDriver(&argc, &argv, &TestOneInput);
544+
int rc = LLVMFuzzerRunDriver(&total_args.argc, &total_args.argv, &TestOneInput);
419545
luaL_cleanup(L);
420546

421547
lua_pushnumber(L, rc);

0 commit comments

Comments
 (0)