Skip to content

Commit

Permalink
Simplify launching and testing fuzzing tools (#366)
Browse files Browse the repository at this point in the history
* Use command-line arguments instead of pipes

stdin is a bit easier to use from the programming viewpoint, but it
complicates debugging crashes. It is simpler to pass the input file
as a command-line argument than to setup file redirection with lldb
or gdb.

Teach all tools to read input from the first command-line argument,
update AFL command-line to pass the input via arguments, and update
readme to prefer this form.

This gives us easier time with debugger:

    gdb --args build/afl/${tool} tools/afl/input/${tool}/*

and then we can just "run" in gdb's command line, instead of having
to setup redirection every time.

* Launch trap as a separate command

We should setup signal trap as a separate shell command for it to have
effect on the next one. The previous form works on macOS for some weird
reason but it does not work on Linux.

* Organize fuzzer output into subdirectories

Separate tool name in filesystem hierarchy makes it easier to iterate
over the findings for later reporting.

* Link statically against Themis

Dynamic linkage with non-system installation paths is a minefield.
For example, it works incorrectly on macOS if Themis is already
installed to /usr/local/lib (that's because of the "installation path"
thingy in dylibs). On Linux dynamic linkage requires LD_LIBRARY_PATH
to be correctly configured even when building the fuzzing tools.

Use static linkage instead. It turned out to be not that hard. We just
have to add libsoter.a explicitly as well as LDFLAGS from outer Themis
build to pull in the OpenSSL/LibreSSL/BoringSSL dependency.

* fixup! Use command-line arguments instead of pipes

* Human-readable error messages

It's not nice to humans just return exit codes. We should at least give
them a hint if the command-line is incorrect. Add some proper error
messages as well for cases when we can't read the input file, or some
Themis function breaks, or a really important test fails.
  • Loading branch information
ilammy committed Feb 6, 2019
1 parent 5fabd07 commit 069f07d
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 22 deletions.
5 changes: 4 additions & 1 deletion tools/afl/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,10 @@ in order to add a `${new_tool}` to fuzz test suite.

1. Create `src/${new_tool}.c` file.

It should be a simple C program which reads from standard input,
It should be a simple C program
which accepts a single command-line argument:
a path to the file with input data.
The tool reads the file,
exercises Themis in some way using the input data,
and exits cleanly if the test passes.

Expand Down
21 changes: 8 additions & 13 deletions tools/afl/fuzzy.mk
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,14 @@ FUZZ_PATH = tools/afl
FUZZ_BIN_PATH = $(BIN_PATH)/afl
FUZZ_SRC_PATH = $(FUZZ_PATH)/src
FUZZ_THEMIS_PATH = $(BIN_PATH)/afl-themis
FUZZ_THEMIS_LIB = $(FUZZ_THEMIS_PATH)/lib$(THEMIS_BIN).$(SHARED_EXT)
FUZZ_THEMIS_LIB = $(FUZZ_THEMIS_PATH)/lib$(THEMIS_BIN).a

FUZZ_TOOLS = $(addprefix $(FUZZ_BIN_PATH)/,$(notdir $(wildcard $(FUZZ_PATH)/input/*)))
FUZZ_OBJS = $(patsubst $(FUZZ_SRC_PATH)/%.c,$(FUZZ_BIN_PATH)/%.o,$(wildcard $(FUZZ_SRC_PATH)/*.c))
FUZZ_UTILS = $(filter-out $(addsuffix .o,$(FUZZ_TOOLS)),$(FUZZ_OBJS))

AFL_CFLAGS += $(CFLAGS) -I$(FUZZ_SRC_PATH)
AFL_LDFLAGS += -L$(FUZZ_THEMIS_PATH) -l$(THEMIS_BIN)

# Dynamic loader on Linux requires a bit of help to locate the libraries
ifdef IS_LINUX
AFL_LINKAGE = LD_LIBRARY_PATH="$(abspath $(FUZZ_THEMIS_PATH))"
endif
AFL_LDFLAGS += -L$(FUZZ_THEMIS_PATH) -l$(THEMIS_BIN) -l$(SOTER_BIN) $(LDFLAGS)

# We don't really track dependencies of $(FUZZ_THEMIS_LIB) here,
# so ask our make to rebuild it every time. The recursively called
Expand All @@ -46,7 +41,7 @@ endif

ifdef FUZZ_BIN
FUZZ_INPUT := $(FUZZ_PATH)/input/$(FUZZ_BIN)
FUZZ_OUTPUT := $(FUZZ_BIN_PATH)/output/$(FUZZ_BIN)_$(shell date +"%Y-%m-%d_%H-%M-%S")
FUZZ_OUTPUT := $(FUZZ_BIN_PATH)/output/$(FUZZ_BIN)/$(shell date +"%Y-%m-%d_%H-%M-%S")
endif

# american fuzzy lop is expected to be stopped via SIGINT (usually by pressing
Expand All @@ -56,8 +51,8 @@ fuzz: $(FUZZ_TOOLS)
ifdef FUZZ_BIN
@echo "fuzzing $(FUZZ_BIN)..."
@mkdir -p $(FUZZ_OUTPUT)
@trap 'echo "see $(FUZZ_OUTPUT) for results"' SIGINT && \
$(AFL_LINKAGE) $(AFL_FUZZ) -i $(FUZZ_INPUT) -o $(FUZZ_OUTPUT) $(FUZZ_BIN_PATH)/$(FUZZ_BIN)
@trap 'echo "see $(FUZZ_OUTPUT) for results"' SIGINT ; \
$(AFL_FUZZ) -i $(FUZZ_INPUT) -o $(FUZZ_OUTPUT) $(FUZZ_BIN_PATH)/$(FUZZ_BIN) @@
endif

$(FUZZ_BIN_PATH)/%.o: $(FUZZ_SRC_PATH)/%.c
Expand All @@ -66,11 +61,11 @@ $(FUZZ_BIN_PATH)/%.o: $(FUZZ_SRC_PATH)/%.c
@AFL_QUIET=1 $(AFL_CC) $(AFL_CFLAGS) -c -o $@ $<
@$(PRINT_OK)

$(FUZZ_BIN_PATH)/%: $(FUZZ_BIN_PATH)/%.o $(FUZZ_UTILS) | $(FUZZ_THEMIS_LIB)
$(FUZZ_BIN_PATH)/%: $(FUZZ_BIN_PATH)/%.o $(FUZZ_UTILS) $(FUZZ_THEMIS_LIB)
@mkdir -p $(@D)
@echo -n "link "
@AFL_QUIET=1 $(AFL_LINKAGE) $(AFL_CC) -o $@ $< $(FUZZ_UTILS) $(AFL_LDFLAGS)
@AFL_QUIET=1 $(AFL_CC) -o $@ $< $(FUZZ_UTILS) $(AFL_LDFLAGS)
@$(PRINT_OK)

$(FUZZ_THEMIS_LIB):
@AFL_QUIET=1 make themis_shared CC=$(AFL_CC) BUILD_PATH=$(FUZZ_THEMIS_PATH)
@AFL_QUIET=1 make themis_static CC=$(AFL_CC) BUILD_PATH=$(FUZZ_THEMIS_PATH)
31 changes: 27 additions & 4 deletions tools/afl/src/scell_seal_decrypt.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* limitations under the License.
*/

#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
Expand All @@ -23,38 +24,56 @@

#include "readline.h"

int main(void)
int main(int argc, char **argv)
{
themis_status_t err = THEMIS_SUCCESS;

/*
* Read test data.
*/

if (argc != 2)
{
fprintf(stderr, "usage:\n\t%s <input-file>\n", argv[0]);
return 1;
}

FILE* input = fopen(argv[1], "rb");
if (!input)
{
fprintf(stderr, "failed to open %s: %s\n", argv[1], strerror(errno));
return 1;
}

uint8_t *master_key_bytes = NULL;
size_t master_key_size = 0;

if (read_line_binary(stdin, &master_key_bytes, &master_key_size))
if (read_line_binary(input, &master_key_bytes, &master_key_size))
{
fprintf(stderr, "failed to read %s: %s\n", argv[1], strerror(errno));
return 1;
}

uint8_t *user_context_bytes = NULL;
size_t user_context_size = 0;

if (read_line_binary(stdin, &user_context_bytes, &user_context_size))
if (read_line_binary(input, &user_context_bytes, &user_context_size))
{
fprintf(stderr, "failed to read %s: %s\n", argv[1], strerror(errno));
return 1;
}

uint8_t *message_bytes = NULL;
size_t message_size = 0;

if (read_line_binary(stdin, &message_bytes, &message_size))
if (read_line_binary(input, &message_bytes, &message_size))
{
fprintf(stderr, "failed to read %s: %s\n", argv[1], strerror(errno));
return 1;
}

fclose(input);

/*
* Try decrypting it.
*/
Expand All @@ -70,12 +89,15 @@ int main(void)

if (err != THEMIS_BUFFER_TOO_SMALL)
{
fprintf(stderr, "failed to determine decrypted message size: %d\n", err);
return 2;
}

decrypted_bytes = malloc(decrypted_size);
if (!decrypted_bytes)
{
fprintf(stderr, "failed to allocate memory for decrypted message (%zu bytes)\n",
decrypted_size);
return 2;
}

Expand All @@ -87,6 +109,7 @@ int main(void)

if (err != THEMIS_SUCCESS)
{
fprintf(stderr, "failed to decrypt message: %d\n", err);
return 2;
}

Expand Down
38 changes: 34 additions & 4 deletions tools/afl/src/scell_seal_roundtrip.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* limitations under the License.
*/

#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
Expand All @@ -23,38 +24,56 @@

#include "readline.h"

int main(void)
int main(int argc, char **argv)
{
themis_status_t err = THEMIS_SUCCESS;

/*
* Read test data.
*/

if (argc != 2)
{
fprintf(stderr, "usage:\n\t%s <input-file>\n", argv[0]);
return 1;
}

FILE* input = fopen(argv[1], "rb");
if (!input)
{
fprintf(stderr, "failed to open %s: %s\n", argv[1], strerror(errno));
return 1;
}

uint8_t *master_key_bytes = NULL;
size_t master_key_size = 0;

if (read_line_binary(stdin, &master_key_bytes, &master_key_size))
if (read_line_binary(input, &master_key_bytes, &master_key_size))
{
fprintf(stderr, "failed to read %s: %s\n", argv[1], strerror(errno));
return 1;
}

uint8_t *user_context_bytes = NULL;
size_t user_context_size = 0;

if (read_line_binary(stdin, &user_context_bytes, &user_context_size))
if (read_line_binary(input, &user_context_bytes, &user_context_size))
{
fprintf(stderr, "failed to read %s: %s\n", argv[1], strerror(errno));
return 1;
}

uint8_t *message_bytes = NULL;
size_t message_size = 0;

if (read_line_binary(stdin, &message_bytes, &message_size))
if (read_line_binary(input, &message_bytes, &message_size))
{
fprintf(stderr, "failed to read %s: %s\n", argv[1], strerror(errno));
return 1;
}

fclose(input);

/*
* Try encrypting the message.
*/
Expand All @@ -70,12 +89,15 @@ int main(void)

if (err != THEMIS_BUFFER_TOO_SMALL)
{
fprintf(stderr, "failed to determine encrypted message size: %d\n", err);
return 2;
}

encrypted_bytes = malloc(encrypted_size);
if (!encrypted_bytes)
{
fprintf(stderr, "failed to allocate memory for encrypted message (%zu bytes)\n",
encrypted_size);
return 2;
}

Expand All @@ -87,6 +109,7 @@ int main(void)

if (err != THEMIS_SUCCESS)
{
fprintf(stderr, "failed to encrypt message: %d\n", err);
return 2;
}

Expand All @@ -105,12 +128,15 @@ int main(void)

if (err != THEMIS_BUFFER_TOO_SMALL)
{
fprintf(stderr, "failed to determine decrypted message size: %d\n", err);
return 3;
}

decrypted_bytes = malloc(decrypted_size);
if (!decrypted_bytes)
{
fprintf(stderr, "failed to allocate memory for decrypted message (%zu bytes)\n",
decrypted_size);
return 3;
}

Expand All @@ -122,6 +148,7 @@ int main(void)

if (err != THEMIS_SUCCESS)
{
fprintf(stderr, "failed to decrypt message: %d\n", err);
return 3;
}

Expand All @@ -131,10 +158,13 @@ int main(void)

if (decrypted_size != message_size)
{
fprintf(stderr, "message length does not match: actual %zu, expected %zu\n",
decrypted_size, message_size);
abort();
}
if (memcmp(message_bytes, decrypted_bytes, message_size) != 0)
{
fprintf(stderr, "message content does not match\n");
abort();
}

Expand Down

0 comments on commit 069f07d

Please sign in to comment.