Skip to content

Fix parsing arg#14

Closed
forzafedor wants to merge 1 commit intoligurio:masterfrom
forzafedor:fix-parsing-arg
Closed

Fix parsing arg#14
forzafedor wants to merge 1 commit intoligurio:masterfrom
forzafedor:fix-parsing-arg

Conversation

@forzafedor
Copy link
Copy Markdown

@forzafedor forzafedor commented Dec 19, 2023

I changed the flag formatting algorithm for libfuzzer

2 problems were solved:

  • Now all flags are processed correctly and the libfuzzer receives the file name as a zero argument. (libfuzzer receives flag from first index link).
  • Now no error with free() function when script finishes work (there was an error in the algorithm of argument parsing).

Now flags (and corpus directories) for libfuzzer can be added from console.
For example:

lua example_basic.lua -max_total_time=60 -only_ascii=1
lua example_basic.lua ./corpus/

But now for luzer.Fuzz() function as third arguments need use global table arg.
If you need to add flags from a Lua script, you can use the construction:

local args = {
    "-only_ascii=1",
}

for i = 1, #args do
    arg[#arg + 1] = args[i]
end

luzer.Fuzz(TestOneInput, nil, arg)

Perhaps there is a better and easier way :)

@forzafedor
Copy link
Copy Markdown
Author

Don't look at the merge yet, I'll change it

@forzafedor forzafedor marked this pull request as draft December 20, 2023 15:34
Copy link
Copy Markdown
Owner

@ligurio ligurio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the patch!

I left a number of comments, please take a look.
Also, please squash commits to a single one, update commit description (it is better to say that we change arg format, not algorithm, and add a long commit description). Add Fixes #13 at the end of commit message`. Changelog entry is also required.

@@ -32,7 +32,7 @@ local function TestOneInput(buf)
parser.parse(decoder.decode(buf))
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW docs/api.md should be updated too.
At least this:

  • args is a table with arguments: the process arguments to pass to the
    fuzzer. Field corpus specifies a path to a directory with seed corpus, see a
    list with other options in the [libFuzzer documentation][libfuzzer-options-url].

Copy link
Copy Markdown
Author

@forzafedor forzafedor Dec 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not relevant

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please describe passing arguments via command-line in documentation.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

documentation is still missed

README.md Outdated
end

luzer.Fuzz(TestOneInput)
luzer.Fuzz(TestOneInput, nil, arg)
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

arg is added, but in a step 3 it is unused (no options are passed to a script).

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed it

@forzafedor
Copy link
Copy Markdown
Author

Thanks for the review!
I've changed the argument parsing process and added support for command line arguments.
The code from Lua's has not changed

@forzafedor forzafedor marked this pull request as ready for review December 27, 2023 13:03
Copy link
Copy Markdown
Owner

@ligurio ligurio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for update!
I like your idea to keep a Lua table with options and merge it with CLI arguments.
Please see the comments inline.

end

luzer.Fuzz(TestOneInput)
luzer.Fuzz(TestOneInput, nil, {})
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What for this change?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (lua_istable(L, -1) == 0) {

At the moment, it is checked that the last argument is a table and if not, fuzzing ends with an error. Therefore, it is necessary to explicitly specify arguments 2 and 3.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not clear why support of CLI arguments makes custom mutator and table with options mandatory for Fuzz function.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is that the code currently shown in the readme will not work at all. The fuzzing process will start only if all 3 arguments are passed to the function input. In this PR, the process of parsing input arguments has been changed, I decided to fix this too.

luzer/luzer.c Outdated
#define CUSTOM_MUTATOR_LIB "libcustom_mutator.so.1"
#define DEBUG_HOOK_FUNC "luzer_custom_hook"

#define ENV_NOT_USE_CLI_ARGS "LUZER_NOT_USE_CLI_ARGS_FOR_LF"
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to changelog, option allows discarding arguments specified in command line.
What is the point? Just don't pass these options, and that's all. Or I didn't get your usecase.
From my point of view, it is more sense to introduce an option that will allow ignoring libfuzzer options specified in Lua.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is necessary so that if we fuzz functionality that works with command line arguments, there may be problems if the flags are the same.
For example:

local function TestOneInput(buf)
    local fdp = luzer.FuzzedDataProvider(buf)
    local str = fdp:consume_string(4)

    local b = {}
    str:gsub(".", function(c) table.insert(b, c) end)
    if (b[1] == "o" and #arg > 0 and arg[1] == "-help=1") then assert(nil) end
end

if we need to set the "-help=1" flag, then without this environment variable, the fuzzer will simply launch its help and fuzzing will not even start, but with the variable set, this crash will be found.

luzer/luzer.c Outdated
Comment on lines +493 to +494
if (result < 0)
luaL_error(L, "failed to parse arguments from lua");
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to implementation get_args_from_lua never returns non-zero exit code. It is a Lua C function and we raise lua_error inside it.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed it

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add descriptions for luaL_get_args_from_cli and luaL_get_args_from_table with possible return codes.

luzer/luzer.c Outdated
Comment on lines +497 to +498
if (result < 0)
luaL_error(L, "failed to merge arguments");
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Message "failed to merge arguments" says nothing to user. It is not clear what a problem is happened and what is "merging arguments" at all. Probably it is better to return an error code for each type of error and use this code here. Currently, we return non-zero code in merge_args in case of lack of memory.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed it

luzer/luzer.c Outdated
Comment on lines +488 to +489
if (result < 0)
luaL_error(L, "failed to parse arguments from console");
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same comment as for get_args_from_lua

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed it

@forzafedor
Copy link
Copy Markdown
Author

Corrected the PR according to your comments

Comment on lines +28 to +29
char search_flag[strlen(key) + 3];
snprintf(search_flag, strlen(key) + 3, "-%s=", key);
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please define a var for strlen(key) + 3 and use it in array definition and for snprintf.

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)
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

strlen(search_flag) is known, replace with variable (see a previous comment)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why ignored? You calculate string length three times!

image

if (!arg)
return -1;

if (key > 0 && (not_use_cli_args == NULL || !strncmp(not_use_cli_args, "0", 1))) {
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getenv(3):

The getenv() function returns a pointer to the value in the environment, or NULL if there is no match.

so comparing not_use_cli_args with NULL is enough

Do not use console arguments when LUZER_NOT_USE_CLI_ARGS_FOR_LF is set (even when equal to 0) and use console arguments when LUZER_NOT_USE_CLI_ARGS_FOR_LF is not set.

@forzafedor
Copy link
Copy Markdown
Author

@ligurio Wait for your response.

@ligurio
Copy link
Copy Markdown
Owner

ligurio commented Jan 9, 2024

@ligurio Wait for your response.

Sure, I'll take a look.

Copy link
Copy Markdown
Owner

@ligurio ligurio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for fixes!
The patch looks good, need some polishing. Please resolve comments that I left.

end

luzer.Fuzz(TestOneInput)
luzer.Fuzz(TestOneInput, nil, {})
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not clear why support of CLI arguments makes custom mutator and table with options mandatory for Fuzz function.

@forzafedor forzafedor force-pushed the fix-parsing-arg branch 5 times, most recently from d10c7b5 to 746ace8 Compare January 21, 2024 20:17
@forzafedor
Copy link
Copy Markdown
Author

@ligurio Thanks for the review. I fixed everything

Copy link
Copy Markdown
Owner

@ligurio ligurio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for fixes! We are close to finish, but need a little more work.
Please take a look on comments.

@@ -0,0 +1,284 @@
/*
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

Please fix indentation in a whole patch.

@@ -32,7 +32,7 @@ local function TestOneInput(buf)
parser.parse(decoder.decode(buf))
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

documentation is still missed

const int key = lua_tointeger(L, -2);
lua_pop(L, 1);

if (key < 0) {
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add comment here with explanation

luzer/luzer.c Outdated
Comment on lines +493 to +494
if (result < 0)
luaL_error(L, "failed to parse arguments from lua");
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add descriptions for luaL_get_args_from_cli and luaL_get_args_from_table with possible return codes.

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

#define ENV_NOT_USE_CLI_ARGS "LUZER_NOT_USE_CLI_ARGS"
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rename ENV_NOT_USE_CLI_ARGS to IGNORE_CLI_ARGS and the same for env variable name: LUZER_NOT_USE_CLI_ARGS -> LUZER_IGNORE_CLI_ARGS.

#define FLAG_SCANF_FORMAT_KEY "-%[^=]"
#define FLAG_PATTERN_KEY "-%s="
#define FLAG_PATTERN_KEY_VALUE "-%s=%s"
#define FLAG_PATTERN_OVERHEAD 2
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Used only once in a line below, I would drop it.

NO_SANITIZE static bool
is_flag_in_args(luzer_args *f_args, const char *key) {
if (!f_args || !f_args->argv || f_args->argc <= 1) {
return false;
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why functions below returns int and here you are using bool?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean to change return type to int? With return 0/1?

total_args->argv[0] = cli_args->argv[0];

char *corpus_path = NULL;
for (int i = 0; i < table_args->argc; i++) {
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably it is better to put table_args->argv[i] to a separate variable (for example cur_arg) at the beginning of loop iteration. This change will reduce length of lines a bit. Currently, it is difficult to read lines in a loop body.

luzer_args table_args = { .argv = NULL, .argc = 0 };

int result = -1;
result = luaL_get_args_from_cli(L, &cli_args);
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not a self-explained variable name. I propose to rename to something like retcode, rc or something else.

@ligurio
Copy link
Copy Markdown
Owner

ligurio commented Mar 19, 2025

Superseded by #21.

@ligurio ligurio closed this Mar 19, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants