mirror of https://github.com/sysown/proxysql
parent
6d60145a3d
commit
e10b2ff225
@ -0,0 +1,17 @@
|
||||
PROXYSQL_PATH=../..
|
||||
PROXYSQL_IDIR=$(PROXYSQL_PATH)/include
|
||||
|
||||
CC = afl-g++-fast
|
||||
CFLAGS = -Wall -fpermissive -pthread
|
||||
OBJS = c_tokenizer.o
|
||||
|
||||
all: afl_test
|
||||
|
||||
afl_test: $(OBJS)
|
||||
$(CC) $(CFLAGS) $(OBJS) -I$(PROXYSQL_IDIR) afl_mysql_query_digest.cpp -o afl_test
|
||||
|
||||
c_tokenizer.o: c_tokenizer.c c_tokenizer.h
|
||||
$(CC) $(CFLAGS) -c c_tokenizer.c
|
||||
|
||||
clean:
|
||||
rm -f *~ *.o afl_test
|
||||
@ -0,0 +1,51 @@
|
||||
## Description
|
||||
|
||||
This folder provides a AFL++ stability test for fuzzy testing 'mysql_query_digest_and_first_comment_2'
|
||||
implementation.
|
||||
|
||||
## Usage
|
||||
|
||||
For compiling test it's enough to run the following commands in ProxySQL main WORKSPACE folder:
|
||||
|
||||
```
|
||||
docker run -tid -v $(pwd):/src aflplusplus/aflplusplus
|
||||
docker exec -it $(CONTAINER_ID) /bin/bash
|
||||
cd /src/test/afl_digest_test/
|
||||
make
|
||||
```
|
||||
|
||||
Then for launching an individual instance of `afl-fuzz` it's enough to run:
|
||||
|
||||
```
|
||||
mkdir output
|
||||
afl-fuzz -M main-$HOSTNAME -i inputs/ -o output/ -- ./afl_test -d 1 -l 1 -n 1 -s 50 -g 0 -G 0
|
||||
```
|
||||
|
||||
Where the options that can be specified for the fuzzing test are:
|
||||
|
||||
```
|
||||
AFL fuzz testing for digest parsing
|
||||
|
||||
USAGE: afl_test [OPTIONS]
|
||||
|
||||
OPTIONS:
|
||||
|
||||
-d, --replace-digits ARG Query digest 'NoDigits'
|
||||
-G, --groups-grouping-limit ARG Query digest 'GroupsGroupingLimit'
|
||||
-g, --grouping-limit ARG Query digest 'GroupingLimit'
|
||||
-h, -help, --help, --usage Display usage instructions.
|
||||
-l, --lowercase ARG Query digest 'LowerCase'
|
||||
-n, --replace-null ARG Query digest 'ReplaceNULL'
|
||||
-s, --digest-size ARG Query digest 'MaxLength'
|
||||
|
||||
```
|
||||
|
||||
They can be optioned also by running `./afl_test -h`.
|
||||
|
||||
## Parallel testing
|
||||
|
||||
1\. For launching multiple instances of `afl-fuzz` the `launch_tests.sh` and `stop_tests.sh` scripts could be used.
|
||||
2\. For checking the overall progress of the parallel testing the following command can be used:
|
||||
```
|
||||
afl-whatsup -s output
|
||||
```
|
||||
@ -0,0 +1,180 @@
|
||||
#pragma GCC optimize("O0")
|
||||
#define QUERY_DIGEST_BUF 128
|
||||
|
||||
#include "c_tokenizer.h"
|
||||
#include "proxysql_utils.h"
|
||||
#include "ezOptionParser.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
__thread int mysql_thread___query_digests_max_query_length = 65000;
|
||||
__thread bool mysql_thread___query_digests_lowercase = false;
|
||||
__thread bool mysql_thread___query_digests_replace_null = true;
|
||||
__thread bool mysql_thread___query_digests_no_digits = false;
|
||||
__thread int mysql_thread___query_digests_grouping_limit = 3;
|
||||
__thread int mysql_thread___query_digests_groups_grouping_limit = 1;
|
||||
|
||||
using std::string;
|
||||
using option_err = std::pair<int, string>;
|
||||
|
||||
option_err check_and_set_option(ez::ezOptionParser& opts, string opt_id, int* config_option_val) {
|
||||
option_err err_res { EXIT_SUCCESS, "" };
|
||||
|
||||
if (opts.isSet(opt_id)) {
|
||||
string s_option_val {};
|
||||
char* str_end = NULL;
|
||||
|
||||
opts.get(opt_id.c_str())->getString(s_option_val);
|
||||
int option_val = std::strtoll(s_option_val.c_str(), &str_end, 10);
|
||||
|
||||
if (errno != ERANGE) {
|
||||
*config_option_val = option_val;
|
||||
} else {
|
||||
string t_invalid_value_msg { "Invalid '%s' supplied" };
|
||||
string invalid_value_msg {};
|
||||
string_format(t_invalid_value_msg, invalid_value_msg, opt_id.c_str());
|
||||
|
||||
string t_err_msg { "File %s, line %d, Error: %s" };
|
||||
string err_msg {};
|
||||
string_format(t_err_msg, err_msg, __FILE__, __LINE__, invalid_value_msg.c_str());
|
||||
|
||||
err_res = { EXIT_FAILURE, err_msg };
|
||||
}
|
||||
}
|
||||
|
||||
return err_res;
|
||||
}
|
||||
|
||||
void print_invalid_input_error(const option_err& err) {
|
||||
std::cout << "InvalidInputError: " << err.second << "\n";
|
||||
}
|
||||
|
||||
option_err parse_parameter_options(int argc, const char** argv) {
|
||||
option_err err_res { EXIT_SUCCESS, "" };
|
||||
|
||||
ez::ezOptionParser opts {};
|
||||
opts.overview = "AFL fuzz testing for digest parsing";
|
||||
opts.syntax = "afl_test [OPTIONS]";
|
||||
opts.footer = "\n\nHappy bug hunting :)";
|
||||
|
||||
opts.add(
|
||||
(const char *)"", 0, 0, 0, (const char *)"Display usage instructions.",
|
||||
(const char *)"-h", (const char *)"-help", (const char *)"--help", (const char *)"--usage"
|
||||
);
|
||||
opts.add(
|
||||
(const char *)"", 1, 1, 0, (const char *)"Query digest 'MaxLength'",
|
||||
(const char *)"-s", (const char *)"--digest-size"
|
||||
);
|
||||
opts.add(
|
||||
(const char *)"", 1, 1, 0, (const char *)"Query digest 'LowerCase'",
|
||||
(const char *)"-l", (const char *)"--lowercase"
|
||||
);
|
||||
opts.add(
|
||||
(const char *)"", 1, 1, 0, (const char *)"Query digest 'ReplaceNULL'",
|
||||
(const char *)"-n", (const char *)"--replace-null"
|
||||
);
|
||||
opts.add(
|
||||
(const char *)"", 1, 1, 0, (const char *)"Query digest 'NoDigits'",
|
||||
(const char *)"-d", (const char *)"--replace-digits"
|
||||
);
|
||||
opts.add(
|
||||
(const char *)"", 1, 1, 0, (const char *)"Query digest 'GroupingLimit'",
|
||||
(const char *)"-g", (const char *)"--grouping-limit"
|
||||
);
|
||||
opts.add(
|
||||
(const char *)"", 1, 1, 0, (const char *)"Query digest 'GroupsGroupingLimit'",
|
||||
(const char *)"-G", (const char *)"--groups-grouping-limit"
|
||||
);
|
||||
|
||||
// parse the arguments
|
||||
opts.parse(argc, argv);
|
||||
|
||||
// extract command line options
|
||||
if (opts.isSet("-h")) {
|
||||
std::string usage {};
|
||||
opts.getUsage(usage);
|
||||
std::cout << usage << std::endl;
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
int option_value = 0;
|
||||
|
||||
err_res = check_and_set_option(opts, "-s", &option_value);
|
||||
if (err_res.first != EXIT_SUCCESS) {
|
||||
return err_res;
|
||||
} else {
|
||||
mysql_thread___query_digests_max_query_length = option_value;
|
||||
}
|
||||
err_res = check_and_set_option(opts, "-l", &option_value);
|
||||
if (err_res.first != EXIT_SUCCESS) {
|
||||
return err_res;
|
||||
} else {
|
||||
mysql_thread___query_digests_lowercase = option_value;
|
||||
}
|
||||
err_res = check_and_set_option(opts, "-n", &option_value);
|
||||
if (err_res.first != EXIT_SUCCESS) {
|
||||
return err_res;
|
||||
} else {
|
||||
mysql_thread___query_digests_replace_null = option_value;
|
||||
}
|
||||
err_res = check_and_set_option(opts, "-d", &option_value);
|
||||
if (err_res.first != EXIT_SUCCESS) {
|
||||
return err_res;
|
||||
} else {
|
||||
mysql_thread___query_digests_no_digits = option_value;
|
||||
}
|
||||
err_res = check_and_set_option(opts, "-g", &option_value);
|
||||
if (err_res.first != EXIT_SUCCESS) {
|
||||
return err_res;
|
||||
} else {
|
||||
mysql_thread___query_digests_grouping_limit = option_value;
|
||||
}
|
||||
err_res = check_and_set_option(opts, "-G", &option_value);
|
||||
if (err_res.first != EXIT_SUCCESS) {
|
||||
return err_res;
|
||||
} else {
|
||||
mysql_thread___query_digests_groups_grouping_limit = option_value;
|
||||
}
|
||||
|
||||
return err_res;
|
||||
}
|
||||
|
||||
void process_digest_test(unsigned char* query, int len) {
|
||||
char buf[QUERY_DIGEST_BUF];
|
||||
char* first_comment = NULL;
|
||||
mysql_query_digest_and_first_comment_2(query, len, &first_comment, ((len < QUERY_DIGEST_BUF) ? buf : NULL));
|
||||
}
|
||||
|
||||
__AFL_FUZZ_INIT();
|
||||
|
||||
int main(int argc, const char** argv) {
|
||||
option_err opt_err = parse_parameter_options(argc, argv);
|
||||
if (opt_err.first != EXIT_SUCCESS) {
|
||||
std::cout << "InvalidSuppliedOption: " << opt_err.second << "\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
#ifdef __AFL_HAVE_MANUAL_CONTROL
|
||||
__AFL_INIT();
|
||||
#endif
|
||||
|
||||
unsigned char *buf = __AFL_FUZZ_TESTCASE_BUF;
|
||||
fflush(stdin);
|
||||
|
||||
while (__AFL_LOOP(10000)) {
|
||||
int len = __AFL_FUZZ_TESTCASE_LEN;
|
||||
process_digest_test(buf, len);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
../../lib/c_tokenizer.c
|
||||
@ -0,0 +1 @@
|
||||
../../include/c_tokenizer.h
|
||||
@ -0,0 +1 @@
|
||||
create table table_10_utf8_4 (\n`pk` int primary key,\n`col_bigint_undef_signed` bigint ,\n`col_bigint_undef_unsigned` bigint unsigned ,\n`col_bigint_key_signed` bigint ,\n`col_bigint_key_unsigned` bigint unsigned ,\n`col_float_undef_signed` float ,\n`col_float_undef_unsigned` float unsigned ,\n`col_float_key_signed` float ,\n`col_float_key_unsigned` float unsigned ,\n`col_double_undef_signed` double ,\n`col_double_undef_unsigned` double unsigned ,\n`col_double_key_signed` double ,\n`col_double_key_unsigned` double unsigned ,\n`col_decimal(40, 20)_undef_signed` decimal(40, 20) ,\n`col_decimal(40, 20)_undef_unsigned` decimal(40, 20) unsigned ,\n`col_decimal(40, 20)_key_signed` decimal(40, 20) ,\n`col_decimal(40, 20)_key_unsigned` decimal(40, 20) unsigned ,\n`col_char(20)_undef_signed` char(20) ,\n`col_char(20)_key_signed` char(20) ,\n`col_varchar(20)_undef_signed` varchar(20) ,\n`col_varchar(20)_key_signed` varchar(20) ,\n`col_enum_undef_signed` enum('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z') ,\n`col_enum_key_signed` enum('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z') ,\nkey (`col_bigint_key_signed`),\nkey (`col_bigint_key_unsigned`),\nkey (`col_float_key_signed`),\nkey (`col_float_key_unsigned`),\nkey (`col_double_key_signed`),\nkey (`col_double_key_unsigned`),\nkey (`col_decimal(40, 20)_key_signed`),\nkey (`col_decimal(40, 20)_key_unsigned`),\nkey (`col_char(20)_key_signed`),\nkey (`col_varchar(20)_key_signed`),\nkey (`col_enum_key_signed`)\n) character set utf8 \npartition by hash(pk)\npartitions 4
|
||||
File diff suppressed because one or more lines are too long
@ -0,0 +1 @@
|
||||
# WeirdFirstComment\nINSERT /* fst_comment */ INTO /*! random_comment */ db.table ( col1, col2,col3,col4, col5 ) VALUES ('val',1, 2,3,'foo'), ('val2',3,NULL,4,'foo2'), ('val2', 5,0x0239192,4,'foo2'), ('val2', 7,NULL,4,'foo2'), (1.1E+9, 2.9E-9, 0x23914993, 928.2939123), ('val2',3,NULL,4,'foo2'), ('val2',3*3.293192493419231,NULL,4+2,'foo2'), ('val2', "9212312",NULL,92.1293123,"foo2"), ON DUPLICATE KEY UPDATE col1 = VALUES(col2) -- final_comment \n
|
||||
@ -0,0 +1,7 @@
|
||||
screen -d -m afl-fuzz -M main-$HOSTNAME -i inputs/ -o output/ -- ./afl_test -d 1 -l 1 -n 1 -s 50 -g 0 -G 0
|
||||
|
||||
screen -d -m afl-fuzz -S variant-1 -i inputs/ -o output/ -- ./afl_test -d 1 -l 1 -n 1 -s 50 -g 1 -G 1
|
||||
screen -d -m afl-fuzz -S variant-2 -i inputs/ -o output/ -- ./afl_test -d 1 -l 1 -n 1 -s 100 -g 2 -G 2
|
||||
screen -d -m afl-fuzz -S variant-3 -i inputs/ -o output/ -- ./afl_test -d 1 -l 1 -n 1 -s 128 -g 3 -G 3
|
||||
screen -d -m afl-fuzz -S variant-4 -i inputs/ -o output/ -- ./afl_test -d 1 -l 1 -n 1 -s 300 -g 4 -G 4
|
||||
screen -d -m afl-fuzz -S variant-5 -i inputs/ -o output/ -- ./afl_test -d 1 -l 1 -n 1 -s 1000 -g 5 -G 5
|
||||
@ -0,0 +1 @@
|
||||
screen -ls | grep '(Detached)' | awk '{print $1}' | xargs -I % -t screen -X -S % quit
|
||||
Loading…
Reference in new issue