Skip to content

Commit

Permalink
Merge branch 'patched' into fix-counters
Browse files Browse the repository at this point in the history
  • Loading branch information
azanegin authored Dec 30, 2023
2 parents 8c83666 + a42b72e commit e58c5a1
Show file tree
Hide file tree
Showing 8 changed files with 247 additions and 56 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Integration with libFuzzer's `FuzzedDataProvider`.
- Examples with tests.
- Documentation with usecases, API etc.
- Support for command line arguments for libfuzzer.
- Environment variable to disable parsing of command line arguments for libfuzzer - `LUZER_NOT_USE_CLI_ARGS_FOR_LF`.
- Two ways to approximate amount of counters for interpreted code.

### Fixed
- Interfering coverage instrumentation of fuzzer internals (#11)
- Interpreted code counter never handed to libfuzzer. (#12)
- Bad lifetime and initization of struct sigaction.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ local function TestOneInput(buf)
end
end

luzer.Fuzz(TestOneInput)
luzer.Fuzz(TestOneInput, nil, {})
```

3. Start the fuzzer using the fuzz target
Expand Down
3 changes: 2 additions & 1 deletion luzer/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ set(LUZER_SOURCES luzer.c
fuzzed_data_provider.cc
tracer.c
counters.c
io.cc
luzer_args.c
io.cc
${CMAKE_CURRENT_BINARY_DIR}/version.c)

add_library(${CMAKE_PROJECT_NAME} SHARED ${LUZER_SOURCES})
Expand Down
54 changes: 4 additions & 50 deletions luzer/luzer.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "macros.h"
#include "tracer.h"
#include "version.h"
#include "luzer_args.h"
#include "luzer.h"

#define GLOBAL_BYTECODE_TO_COUNTERS_SCALE 4
Expand Down Expand Up @@ -447,57 +448,10 @@ lua_ctrs_alloc_notify_lf(lua_State *L)
NO_SANITIZE static int
luaL_fuzz(lua_State *L)
{
if (lua_istable(L, -1) == 0) {
luaL_error(L, "opts is not a table");
}
lua_pushnil(L);
char **argv = NULL;
int argc = 0;

/* Processing a table with options. */
int argc = 0;
char **argv = malloc(1 * sizeof(char*));
if (!argv)
luaL_error(L, "not enough memory");
const char *corpus_path = NULL;
while (lua_next(L, -2) != 0) {
char **argvp = realloc(argv, sizeof(char*) * (argc + 1));
if (argvp == NULL) {
free(argv);
luaL_error(L, "not enough memory");
}
const char *key = lua_tostring(L, -2);
const char *value = lua_tostring(L, -1);
if (strcmp(key, "corpus") != 0) {
size_t arg_len = strlen(key) + strlen(value) + 3;
char *arg = calloc(arg_len, sizeof(char));
if (!arg)
luaL_error(L, "not enough memory");
snprintf(arg, arg_len, "-%s=%s", key, value);
argvp[argc] = arg;
argc++;
} else {
corpus_path = strdup(value);
}
lua_pop(L, 1);
argv = argvp;
}
if (corpus_path) {
argv[argc] = (char*)corpus_path;
argc++;
}
if (argc == 0) {
argv[argc] = "";
argc++;
}
argv[argc] = NULL;
lua_pop(L, 1);

#ifdef DEBUG
char **p = argv;
while(*p++) {
if (*p)
DEBUG_PRINT("libFuzzer arg - '%s'\n", *p);
}
#endif /* DEBUG */
get_fuzz_args(L, &argv, &argc);

/* Processing a function with custom mutator. */
if (!lua_isnil(L, -1) && (lua_isfunction(L, -1) == 1)) {
Expand Down
6 changes: 3 additions & 3 deletions luzer/luzer.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#ifndef LUZER_MACROS_H_
#define LUZER_MACROS_H_
#ifndef LUZER_H_
#define LUZER_H_

#ifdef __cplusplus
extern "C" {
Expand All @@ -10,4 +10,4 @@ int luaL_mutate(lua_State *L);
} /* extern "C" */
#endif

#endif // LUZER_MACROS_H_
#endif // LUZER_H_
212 changes: 212 additions & 0 deletions luzer/luzer_args.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
/*
* SPDX-License-Identifier: ISC
*
* Copyright 2022-2023, Sergey Bronnikov
*/

#include <lauxlib.h>
#include <stdlib.h>
#include <string.h>

#include "luzer_args.h"
#include "macros.h"

#define ENV_NOT_USE_CLI_ARGS "LUZER_NOT_USE_CLI_ARGS_FOR_LF"

#define LUA_CORPUS_FLAG "-corpus"

/* Structure for convenient argument parsing. */
struct Luzer_args {
char **argv;
int argc;
};

NO_SANITIZE static bool
is_flag_in_args(struct Luzer_args *f_args, const char *key) {
if (!f_args || !f_args->argv || f_args->argc <= 0)
return false;
char search_flag[strlen(key) + 3];
snprintf(search_flag, strlen(key) + 3, "-%s=", key);
for (int i = 0; i <= f_args->argc; i++) {
if (strncmp(f_args->argv[i], search_flag, strlen(search_flag)) == 0)
return true;
}
return false;
}

NO_SANITIZE static int
get_args_from_cli(lua_State *L, struct Luzer_args *cli_args) {
lua_getglobal(L, "arg");

cli_args->argv = malloc(1 * sizeof(char*));
if (!cli_args->argv)
return -1;

lua_pushnil(L);

char* not_use_cli_args = getenv(ENV_NOT_USE_CLI_ARGS);
cli_args->argc = 0;
while (lua_next(L, -2) != 0) {
const char *value = lua_tostring(L, -1);
const int key = lua_tointeger(L, -2);
lua_pop(L, 1);
if (key < 0)
continue;

const char *arg = strdup(value);
if (!arg)
return -1;

if (key > 0 && (not_use_cli_args == NULL || !strncmp(not_use_cli_args, "0", 1))) {
cli_args->argc++;
char **argvp = realloc(cli_args->argv, sizeof(char*) * (cli_args->argc + 1));
if (argvp == NULL)
return -1;
cli_args->argv = argvp;
cli_args->argv[cli_args->argc] = (char*)arg;
} else {
cli_args->argv[0] = (char*)arg;
}
}
lua_pop(L, 1);
return 0;
}

NO_SANITIZE static int
get_args_from_table(lua_State *L, struct Luzer_args *table_args, struct Luzer_args *cli_args) {
if (lua_istable(L, -1) == 0)
return -2;

lua_pushnil(L);

/* Processing a table with options. */
table_args->argc = 0;
while (lua_next(L, -2) != 0) {
const char *key = lua_tostring(L, -2);
const char *value = lua_tostring(L, -1);
lua_pop(L, 1);
if (is_flag_in_args(cli_args, key))
continue;

if (table_args->argc > 0) {
char **argvp = realloc(table_args->argv, sizeof(char*) * (table_args->argc + 1));
if (argvp == NULL)
return -1;
table_args->argv = argvp;
} else {
table_args->argv = malloc(1 * sizeof(char*));
if (!table_args->argv)
return -1;
}
size_t arg_len = strlen(key) + strlen(value) + 3;
char *arg = calloc(arg_len, sizeof(char));
if (!arg)
return -1;
snprintf(arg, arg_len, "-%s=%s", key, value);
table_args->argv[table_args->argc] = arg;
table_args->argc++;
}
lua_pop(L, 1);
return 0;
}

NO_SANITIZE static int
merge_args(struct Luzer_args *cli_args, struct Luzer_args *table_args, struct Luzer_args *total_args) {
total_args->argc = (cli_args->argc + table_args->argc + 1);
total_args->argv = malloc(sizeof(char*) * (total_args->argc + 1));
if (!cli_args->argv)
return -1;

/* Program name on zero index. */
total_args->argv[0] = cli_args->argv[0];

int cur_pos_arg = 1;
char *corpus_path = NULL;
for (int i = 0; i < table_args->argc; i++) {
if (strncmp(table_args->argv[i], LUA_CORPUS_FLAG, strlen(LUA_CORPUS_FLAG)) == 0) {
int corpus_path_len = strlen(table_args->argv[i]) - strlen(LUA_CORPUS_FLAG);
corpus_path = malloc(corpus_path_len * sizeof(char*));
if (!corpus_path)
return -1;
memcpy(corpus_path, &table_args->argv[i][strlen(LUA_CORPUS_FLAG) + 1], corpus_path_len);
free(table_args->argv[i]);
table_args->argv[i] = NULL;
} else {
total_args->argv[cur_pos_arg] = table_args->argv[i];
cur_pos_arg++;
}
}
for (int i = 1; i <= cli_args->argc; i++) {
total_args->argv[cur_pos_arg] = cli_args->argv[i];
cur_pos_arg++;
}
if (corpus_path) {
total_args->argv[cur_pos_arg] = corpus_path;
cur_pos_arg++;
}
total_args->argv[total_args->argc] = NULL;

if (table_args->argv)
free(table_args->argv);

if (cli_args->argv)
free(cli_args->argv);

return 0;
}

NO_SANITIZE static void
free_args(struct Luzer_args args) {
if (!args.argv)
return;
for (int i = 0; i < args.argc; i++) {
if (args.argv[i])
free(args.argv[i]);
}
free(args.argv);
}

NO_SANITIZE int
get_fuzz_args(lua_State *L, char ***argv, int *argc) {
struct Luzer_args total_args = { .argv = NULL, .argc = 0};
struct Luzer_args cli_args = { .argv = NULL, .argc = 0 };
struct Luzer_args table_args = { .argv = NULL, .argc = 0 };

int result = -1;
result = get_args_from_cli(L, &cli_args);
if (result != 0) {
free_args(cli_args);
luaL_error(L, "failed parsing fuzz args. not enough memory");
}

/* If flag in cli and lua is duplicated, then flag from lua is ignored. */
result = get_args_from_table(L, &table_args, &cli_args);
if (result != 0) {
free_args(table_args);
free_args(cli_args);
if (result == -2)
luaL_error(L, "failed parsing fuzz args. last argument is not a table");
luaL_error(L, "failed parsing fuzz args. not enough memory");
}

result = merge_args(&cli_args, &table_args, &total_args);
if (result != 0) {
free_args(table_args);
free_args(cli_args);
free_args(total_args);
luaL_error(L, "failed parsing fuzz args. not enough memory");
}

*argv = total_args.argv;
*argc = total_args.argc;

#ifdef DEBUG
char **p = *argv;
while(*p++) {
if (*p)
DEBUG_PRINT("libFuzzer arg - '%s'\n", *p);
}
#endif /* DEBUG */

return 0;
}
7 changes: 7 additions & 0 deletions luzer/luzer_args.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#ifndef LUZER_ARGS_H_
#define LUZER_ARGS_H_

int get_fuzz_args(lua_State *L, char ***argv, int *argc);

#endif // LUZER_ARGS_H_

16 changes: 15 additions & 1 deletion luzer/macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,20 @@
#define NO_SANITIZE_MEMORY
#endif // __has_attribute

#define NO_SANITIZE NO_SANITIZE_ADDRESS NO_SANITIZE_MEMORY
// https://clang.llvm.org/docs/SanitizerCoverage.html#disabling-instrumentation-with-attribute-no-sanitize-coverage
#ifdef __has_feature

#if __has_feature(coverage_sanitizer)
#define NO_SANITIZE_COVERAGE __attribute__((no_sanitize("coverage")))
#else // __has_feature(coverage_sanitizer)
#warning "compiler does not provide 'coverage_sanitizer' feature"
#define NO_SANITIZE_COVERAGE
#endif // __has_feature(coverage_sanitizer)

#else // __has_feature
#warning "compiler does not provide __has_feature, can't check for sanitization"
#endif // __has_feature

#define NO_SANITIZE NO_SANITIZE_ADDRESS NO_SANITIZE_MEMORY NO_SANITIZE_COVERAGE

#endif // LUZER_MACROS_H_

0 comments on commit e58c5a1

Please sign in to comment.