Skip to content

Commit b877c49

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

File tree

3 files changed

+165
-36
lines changed

3 files changed

+165
-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: 162 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,178 @@ 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+
if (lua_getglobal(L, "arg") != LUA_TTABLE)
353+
return -1;
354+
355+
cli_args->argv = malloc(1 * sizeof(char*));
356+
if (!cli_args->argv)
357+
luaL_error(L, "not enough memory");
358+
359+
lua_pushnil(L);
360+
361+
char* not_use_cli_args = getenv(ENV_NOT_USE_CLI_ARGS);
362+
cli_args->argc = 0;
363+
while (lua_next(L, -2) != 0) {
364+
const char *value = lua_tostring(L, -1);
365+
const int key = lua_tointeger(L, -2);
366+
lua_pop(L, 1);
367+
if (key < 0)
368+
continue;
369+
370+
const char *arg = strdup(value);
371+
if (!arg) {
372+
free(cli_args->argv);
373+
luaL_error(L, "not enough memory");
374+
}
375+
376+
if (key > 0 && (not_use_cli_args == NULL || !strcmp(not_use_cli_args, "0"))) {
377+
cli_args->argc++;
378+
char **argvp = realloc(cli_args->argv, sizeof(char*) * (cli_args->argc + 1));
379+
if (argvp == NULL) {
380+
free(cli_args->argv);
381+
luaL_error(L, "not enough memory");
382+
}
383+
cli_args->argv = argvp;
384+
cli_args->argv[cli_args->argc] = (char*)arg;
385+
} else {
386+
cli_args->argv[0] = (char*)arg;
387+
}
332388
}
389+
lua_pop(L, 1);
390+
return 0;
391+
}
392+
393+
NO_SANITIZE static int
394+
get_args_from_lua(lua_State *L, struct args *lua_args, struct args *cli_args) {
395+
if (lua_istable(L, -1) == 0)
396+
luaL_error(L, "opts is not a table");
397+
333398
lua_pushnil(L);
334399

335400
/* 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-
}
401+
lua_args->argc = 0;
402+
while (lua_next(L, -2) != 0) {
347403
const char *key = lua_tostring(L, -2);
348404
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)
405+
lua_pop(L, 1);
406+
if (is_flag_in_args(cli_args, key))
407+
continue;
408+
409+
if (lua_args->argc > 0) {
410+
char **argvp = realloc(lua_args->argv, sizeof(char*) * (lua_args->argc + 1));
411+
if (argvp == NULL) {
412+
free(lua_args->argv);
353413
luaL_error(L, "not enough memory");
354-
snprintf(arg, arg_len, "-%s=%s", key, value);
355-
argvp[argc] = arg;
356-
argc++;
414+
}
415+
lua_args->argv = argvp;
357416
} else {
358-
corpus_path = strdup(value);
417+
lua_args->argv = malloc(1 * sizeof(char*));
418+
if (!lua_args->argv)
419+
luaL_error(L, "not enough memory");
359420
}
360-
lua_pop(L, 1);
361-
argv = argvp;
421+
size_t arg_len = strlen(key) + strlen(value) + 3;
422+
char *arg = calloc(arg_len, sizeof(char));
423+
if (!arg){
424+
free(lua_args->argv);
425+
luaL_error(L, "not enough memory");
426+
}
427+
snprintf(arg, arg_len, "-%s=%s", key, value);
428+
lua_args->argv[lua_args->argc] = arg;
429+
lua_args->argc++;
362430
}
363-
if (corpus_path) {
364-
argv[argc] = (char*)corpus_path;
365-
argc++;
431+
432+
lua_pop(L, 1);
433+
return 0;
434+
}
435+
436+
NO_SANITIZE static int
437+
merge_args(struct args *cli_args, struct args *lua_args, struct args *total_args) {
438+
total_args->argc = (cli_args->argc + lua_args->argc + 1);
439+
total_args->argv = malloc(sizeof(char*) * (total_args->argc + 1));
440+
if (!cli_args->argv)
441+
return -1;
442+
/* Program name on zero index. */
443+
total_args->argv[0] = cli_args->argv[0];
444+
445+
int cur_pos_arg = 1;
446+
char *corpus_path = NULL;
447+
for (int i = 0; i < lua_args->argc; i++) {
448+
if (strncmp(lua_args->argv[i], LUA_CORPUS_FLAG, strlen(LUA_CORPUS_FLAG)) == 0) {
449+
int corpus_path_len = strlen(lua_args->argv[i]) - strlen(LUA_CORPUS_FLAG);
450+
corpus_path = malloc(corpus_path_len * sizeof(char*));
451+
if (!corpus_path)
452+
return -1;
453+
memcpy(corpus_path, &lua_args->argv[i][strlen(LUA_CORPUS_FLAG) + 1], corpus_path_len);
454+
free(lua_args->argv[i]);
455+
} else {
456+
total_args->argv[cur_pos_arg] = lua_args->argv[i];
457+
cur_pos_arg++;
458+
}
366459
}
367-
if (argc == 0) {
368-
argv[argc] = "";
369-
argc++;
460+
for (int i = 1; i <= cli_args->argc; i++) {
461+
total_args->argv[cur_pos_arg] = cli_args->argv[i];
462+
cur_pos_arg++;
370463
}
371-
argv[argc] = NULL;
372-
lua_pop(L, 1);
464+
if (corpus_path) {
465+
total_args->argv[cur_pos_arg] = corpus_path;
466+
cur_pos_arg++;
467+
}
468+
total_args->argv[total_args->argc] = NULL;
469+
470+
if (lua_args->argv)
471+
free(lua_args->argv);
472+
473+
if (cli_args->argv)
474+
free(cli_args->argv);
475+
476+
return 0;
477+
}
478+
479+
480+
NO_SANITIZE static int
481+
luaL_fuzz(lua_State *L)
482+
{
483+
int result = -1;
484+
struct args cli_args = { .argv = NULL, .argc = 0 };
485+
struct args lua_args = { .argv = NULL, .argc = 0 };
486+
struct args total_args = { .argv = NULL, .argc = 0 };
487+
488+
result = get_args_from_cli(L, &cli_args);
489+
if (result < 0)
490+
luaL_error(L, "failed to parse arguments from console");
491+
492+
/* If flag in cli and lua is duplicated, then flag from lua is ignored. */
493+
result = get_args_from_lua(L, &lua_args, &cli_args);
494+
if (result < 0)
495+
luaL_error(L, "failed to parse arguments from lua");
496+
497+
result = merge_args(&cli_args, &lua_args, &total_args);
498+
if (result < 0)
499+
luaL_error(L, "failed to merge arguments");
373500

374501
#ifdef DEBUG
375-
char **p = argv;
502+
char **p = total_args.argv;
376503
while(*p++) {
377504
if (*p)
378505
DEBUG_PRINT("libFuzzer arg - '%s'\n", *p);
@@ -415,7 +542,7 @@ luaL_fuzz(lua_State *L)
415542
lua_pop(L, -1);
416543

417544
set_global_lua_state(L);
418-
int rc = LLVMFuzzerRunDriver(&argc, &argv, &TestOneInput);
545+
int rc = LLVMFuzzerRunDriver(&total_args.argc, &total_args.argv, &TestOneInput);
419546
luaL_cleanup(L);
420547

421548
lua_pushnumber(L, rc);

0 commit comments

Comments
 (0)