diff --git a/wasm-fuzzer/.env b/wasm-fuzzer/.env index 3b2e31fb..348177cd 100644 --- a/wasm-fuzzer/.env +++ b/wasm-fuzzer/.env @@ -1,8 +1,11 @@ # Whether we are using AFL with Swam or just using dummy data DUMMY_TESTING_AFL=False -# (Not being used yet..) Error, Warn, Info, Debug -LOG_LEVEL=Error +# Enum: ERROR, WARNING, INFO, DEBUG +LOG_LEVEL=INFO + +# Set True if AFL should always continue where it left off (and not delete old findings). Useful if AFL/SWAM may crash and auto-restart. +REUSE_DATA_AFL=True # Path to the parent directory of our local .wasm/.wat executable LOCAL_WASM=/tmp/fuzzer-wat_files diff --git a/wasm-fuzzer/fuzzing-client-afl/entrypoint_afl.sh b/wasm-fuzzer/fuzzing-client-afl/entrypoint_afl.sh index f5445ac4..450ca947 100644 --- a/wasm-fuzzer/fuzzing-client-afl/entrypoint_afl.sh +++ b/wasm-fuzzer/fuzzing-client-afl/entrypoint_afl.sh @@ -9,18 +9,31 @@ PREPARED_INPUT_PATH="$DOCKER_AFL_INPUT/prepared_input.dat" REQUIRED_BYTES=$(./getFileSize.out $PREPARED_INPUT_PATH) # Parallel fuzzing: https://github.com/mirrorer/afl/blob/master/docs/parallel_fuzzing.txt -if [[ ! -z "$MASTER_AFL_NODE" ]] -then +if [[ ! -z "$MASTER_AFL_NODE" ]]; then DOCKER_CONTAINER_ID=$( readFileToVector(const std::string &filename) { std::ifstream source; @@ -26,24 +20,24 @@ void log_file(char *filename) std::vector vector = readFileToVector(filename); for (int i = 0; i < vector.size(); ++i) { - LOG(vector[i]); + log_default(vector[i], DEBUG); } } uint8_t *getShm() { std::string shmStr = parseEnvVariables((char *)"__AFL_SHM_ID"); - LOG("shmStr: " + shmStr); + log_default("shmStr: " + shmStr, INFO); key_t key = std::stoi(shmStr); uint8_t *trace_bits = (uint8_t *)shmat(key, 0, 0); if (trace_bits == (uint8_t *)-1) { - LOG("Failed to access shared memory"); + log_default("Failed to access shared memory", ERROR); exit(1); } - LOG("Shared memory attached."); + log_default("Shared memory attached.", INFO); return trace_bits; } @@ -69,7 +63,8 @@ void pass_data_to_afl(int sizeReadBuffer, char *readBuffer, uint8_t *trace_bits) void main_fuzz( char *fuzzed_input_path, uint8_t *trace_bits, - int requiredBytes) + int requiredBytes, + pid_t aflPID) { std::string DUMMY_TESTING_AFL = parseEnvVariables((char *)"DUMMY_TESTING_AFL"); @@ -79,17 +74,36 @@ void main_fuzz( exit(0); } - // TODO: Replace sendBuffer by char sendBuffer[requiredBytes]; readBinaryToBuffer(sendBuffer, sizeof(sendBuffer), (std::string)fuzzed_input_path); - // std::reverse(sendBuffer, &sendBuffer[sizeof(sendBuffer)]); // Reverse order of tempBuffer char readBuffer[AFL_SHM_SIZE + 1]; // + 1 for exit code std::string SWAM_SOCKET_HOST = parseEnvVariables((char *)"SWAM_SOCKET_HOST"); std::string SWAM_SOCKET_PORT = parseEnvVariables((char *)"SWAM_SOCKET_PORT"); - runClient(sizeof(sendBuffer), sendBuffer, sizeof(readBuffer), readBuffer, &SWAM_SOCKET_HOST[0], std::stoi(SWAM_SOCKET_PORT)); + int num_tries = 0; + while (true) + { + try + { + runClient(sizeof(sendBuffer), sendBuffer, sizeof(readBuffer), readBuffer, &SWAM_SOCKET_HOST[0], std::stoi(SWAM_SOCKET_PORT)); + break; + } + catch (...) + { + num_tries += 1; + if (num_tries > 1) + { + // Failing twice probably means SWAM server is down. Therefore, kill + // AFL before AFL kills us due to timeout. Would run here endlessly + // otherwise. + kill(aflPID, 6); + log_default("Killed AFL because server not responding.", WARNING); + exit(1); + } + } + } pass_data_to_afl(sizeof(readBuffer), readBuffer, trace_bits); @@ -109,6 +123,19 @@ void fork_server(char *fuzzed_input_path, uint8_t *trace_bits, int requiredBytes hard-coded by AFL and thereby accessible here. */ + // Just for logging: + pid_t aflPID = getppid(); + char aflPIDChar[6]; + sprintf(aflPIDChar, "%d", aflPID); + std::string aflPIDString = aflPIDChar; + log_default("AFL's PID: " + aflPIDString, INFO); + + pid_t forkServerPID = getpid(); + char forkServerPIDChar[6]; + sprintf(forkServerPIDChar, "%d", forkServerPID); + std::string forkServerPIDString = forkServerPIDChar; + log_default("Forkserver's PID: " + forkServerPIDString, INFO); + int status = 0; // Starting the 'Fork server handshake' @@ -116,7 +143,7 @@ void fork_server(char *fuzzed_input_path, uint8_t *trace_bits, int requiredBytes // Phone home and tell AFL that we're OK if (write(199, &status, 4) != 4) { - LOG("Write failed"); + log_default("Write failed", ERROR); close(199); exit(1); } @@ -125,11 +152,12 @@ void fork_server(char *fuzzed_input_path, uint8_t *trace_bits, int requiredBytes // and is creating forks of itself is called the "fork server". while (true) { + // Wait for AFL by reading from the pipe. // This will block until AFL sends us something. Abort if read fails. if (read(198, &status, 4) != 4) { - LOG("Read failed"); + log_default("Read failed", ERROR); close(198); close(199); exit(1); @@ -143,7 +171,7 @@ void fork_server(char *fuzzed_input_path, uint8_t *trace_bits, int requiredBytes int pid = fork(); if (pid < 0) { - LOG("Fork failed"); + log_default("Fork failed", ERROR); close(198); close(199); exit(1); @@ -153,7 +181,7 @@ void fork_server(char *fuzzed_input_path, uint8_t *trace_bits, int requiredBytes // This is the child process close(198); close(199); - main_fuzz(fuzzed_input_path, trace_bits, requiredBytes); + main_fuzz(fuzzed_input_path, trace_bits, requiredBytes, aflPID); exit(0); } @@ -171,7 +199,7 @@ void fork_server(char *fuzzed_input_path, uint8_t *trace_bits, int requiredBytes // Waiting for child if (waitpid(pid, &status, 0) <= 0) // Technically only fails at -1; 0 means still running { - LOG("waitpid() failed."); + log_default("waitpid() failed.", ERROR); close(198); close(199); exit(1); @@ -186,14 +214,14 @@ void fork_server(char *fuzzed_input_path, uint8_t *trace_bits, int requiredBytes else if (WIFSIGNALED(status)) // Process was stopped/terminated by signal; { // TODO: Find out why this branch gets triggered - LOG("Signal status: " + std::to_string(status)); - LOG("WTERMSIG(status): " + std::to_string(WTERMSIG(status))); - LOG("WSTOPSIG(status): " + std::to_string(WSTOPSIG(status))); + log_default("Signal status: " + std::to_string(status), ERROR); + log_default("WTERMSIG(status): " + std::to_string(WTERMSIG(status)), ERROR); + log_default("WSTOPSIG(status): " + std::to_string(WSTOPSIG(status)), ERROR); write(199, &status, 4); } else { - LOG("Weird status: " + std::to_string(status)); + log_default("Weird status: " + std::to_string(status), ERROR); close(198); close(199); exit(1); @@ -205,13 +233,12 @@ void log_args(int argc, char *argv[]) { for (int i = 0; i < argc; ++i) { - LOG("argv[" + std::to_string(i) + "]: " + std::string(argv[i])); + log_default("argv[" + std::to_string(i) + "]: " + std::string(argv[i]), INFO); } } int main(int argc, char *argv[]) { - // TODO: Remove everything related to requiredBytes; not necessary anymore log_args(argc, argv); char *fuzzed_input_path = argv[1]; diff --git a/wasm-fuzzer/fuzzing-client-afl/interface.h b/wasm-fuzzer/fuzzing-client-afl/interface.h index 58a1b63a..2ca6d74a 100644 --- a/wasm-fuzzer/fuzzing-client-afl/interface.h +++ b/wasm-fuzzer/fuzzing-client-afl/interface.h @@ -14,5 +14,6 @@ #include #include #include +#include #endif \ No newline at end of file diff --git a/wasm-fuzzer/fuzzing-client-afl/prepare_wasm_input.cpp b/wasm-fuzzer/fuzzing-client-afl/prepare_wasm_input.cpp index dcb9e863..5ba2889a 100644 --- a/wasm-fuzzer/fuzzing-client-afl/prepare_wasm_input.cpp +++ b/wasm-fuzzer/fuzzing-client-afl/prepare_wasm_input.cpp @@ -84,7 +84,6 @@ void printResult(std::string filepath) printf("Total bytes written: %i\n", fileSize); char buffer[fileSize]; readBinaryToBuffer(buffer, fileSize, filepath); - // std::reverse(buffer, &buffer[sizeof(buffer)]); printBuffer(sizeof(buffer), buffer); printf("-----------------\n"); diff --git a/wasm-fuzzer/fuzzing-client-afl/run_client.cpp b/wasm-fuzzer/fuzzing-client-afl/run_client.cpp index ce83c57d..a7f51311 100644 --- a/wasm-fuzzer/fuzzing-client-afl/run_client.cpp +++ b/wasm-fuzzer/fuzzing-client-afl/run_client.cpp @@ -5,15 +5,14 @@ // data sent by the client properly int main(int argc, char *argv[]) { - std::string inputFile = (std::string) argv[1]; + std::string inputFile = (std::string)argv[1]; char readBuffer[AFL_SHM_SIZE + 1]; // + 1 for exit code int fileSize = (int)getFileSize(inputFile); char sendBuffer[fileSize]; readBinaryToBuffer(sendBuffer, fileSize, inputFile); - // std::reverse(sendBuffer, &sendBuffer[sizeof(sendBuffer)]); // Reverse order of sendBuffer - runClient(sizeof(sendBuffer), sendBuffer, sizeof(readBuffer), readBuffer, "localhost", 9999); + runClient(sizeof(sendBuffer), sendBuffer, sizeof(readBuffer), readBuffer, (char *)"localhost", 9999); exit(0); }; diff --git a/wasm-fuzzer/fuzzing-client-afl/run_test.sh b/wasm-fuzzer/fuzzing-client-afl/run_test.sh index 3a504b62..8aea665f 100755 --- a/wasm-fuzzer/fuzzing-client-afl/run_test.sh +++ b/wasm-fuzzer/fuzzing-client-afl/run_test.sh @@ -1,5 +1,7 @@ #!/bin/bash +# TODO: Since now all logging is to a file (using env var DOCKER_LOGS), this script cannot be run locally anymore. Fix this. + # For testing the integration of prepare_wasm_input.cpp and socket_client.cpp. # Run server in Swam first (example with fibo.wat): diff --git a/wasm-fuzzer/fuzzing-client-afl/socket_client.cpp b/wasm-fuzzer/fuzzing-client-afl/socket_client.cpp index acc3f30c..8d4456e4 100644 --- a/wasm-fuzzer/fuzzing-client-afl/socket_client.cpp +++ b/wasm-fuzzer/fuzzing-client-afl/socket_client.cpp @@ -2,10 +2,10 @@ // Most code based on: https://www.bogotobogo.com/cplusplus/sockets_server_client.php -void error(const char *msg) +void errorAndThrow(const char *msg) { - // fprintf("Socket: %s\n", msg); - perror(msg); + std::string msgStr = msg; + log_default(msgStr, ERROR); throw std::runtime_error(msg); } @@ -24,15 +24,15 @@ int connectToServer(char *socket_hostname, int socket_port) sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) - error("Error opening socket"); + errorAndThrow("Error opening socket"); server = gethostbyname(socket_hostname); if (server == NULL) { - // fprintf(stderr, "Error, no such host\n"); - perror("Error, no such host"); - exit(1); + errorAndThrow("Error, no such host"); + // log_default("Error, no such host", ERROR); + // exit(1); } bzero((char *)&serv_addr, sizeof(serv_addr)); // Maybe use memset @@ -46,7 +46,7 @@ int connectToServer(char *socket_hostname, int socket_port) serv_addr.sin_port = htons(socket_port); if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) - error("Error connecting"); + errorAndThrow("Error connecting"); return sockfd; } @@ -55,7 +55,7 @@ void clientWrite(int sockfd, char *sendBuffer, int sizeBuffer) { int n = write(sockfd, sendBuffer, sizeBuffer); if (n < 0) - error("Error writing to socket"); + errorAndThrow("Error writing to socket"); } void clientRead(int sockfd, char *readBuffer, int sizeBuffer) @@ -68,12 +68,43 @@ void clientRead(int sockfd, char *readBuffer, int sizeBuffer) // is in a loop. int nNew = read(sockfd, readBuffer + n, sizeBuffer - n); if (nNew < 0) - error("Error reading from socket"); + errorAndThrow("Error reading from socket"); n = n + nNew; } } -// TODO: Use MessagePack object instead of sendBuffer & readBuffer +void wait_for_server(char *socket_hostname, int socket_port, int wait_milli, int timeout_milli) +{ + log_default("Waiting for Swam server...", INFO); + + auto t_start = std::chrono::high_resolution_clock::now(); + int duration_milli; + + int sockfd; + while (true) + { + try + { + sockfd = connectToServer(socket_hostname, socket_port); + close(sockfd); + break; + } + catch (const std::runtime_error& error) + { + auto t_end = std::chrono::high_resolution_clock::now(); + duration_milli = std::chrono::duration(t_end-t_start).count(); + if (duration_milli > timeout_milli) { + log_default("Timeout reached in wait_for_server", ERROR); + throw error; + } + log_default("Trying to connect again in 4 seconds...", INFO); + usleep(wait_milli); + std::this_thread::sleep_for(std::chrono::milliseconds(wait_milli)); + } + } + log_default("Can connect to Swam!", INFO); +} + void runClient( int sizeSendBuffer, char *sendBuffer, diff --git a/wasm-fuzzer/fuzzing-client-afl/socket_client.h b/wasm-fuzzer/fuzzing-client-afl/socket_client.h index f99c2521..3cac6e77 100644 --- a/wasm-fuzzer/fuzzing-client-afl/socket_client.h +++ b/wasm-fuzzer/fuzzing-client-afl/socket_client.h @@ -14,11 +14,16 @@ #include #include #include +#include +#include +#include +#include void error(const char *); int connectToServer(char *, int); -void clientWrite(int, char*, int); -void clientRead(int, char*, int); -void runClient(int, char*, int, char*, char *, int); +void clientWrite(int, char *, int); +void clientRead(int, char *, int); +void wait_for_server(char *, int, int = 4000, int = 40000); +void runClient(int, char *, int, char *, char *, int); #endif diff --git a/wasm-fuzzer/fuzzing-client-afl/utils.cpp b/wasm-fuzzer/fuzzing-client-afl/utils.cpp index 77c286f5..ccd03456 100644 --- a/wasm-fuzzer/fuzzing-client-afl/utils.cpp +++ b/wasm-fuzzer/fuzzing-client-afl/utils.cpp @@ -6,13 +6,61 @@ #include #include #include -#include +#include -void log(std::string filename, std::string some_string) +LogEnum getLogLevel() +{ + std::string DEFAULT_LOG_LEVEL = parseEnvVariables((char *)"LOG_LEVEL"); + if (DEFAULT_LOG_LEVEL == "DEBUG") + return DEBUG; + if (DEFAULT_LOG_LEVEL == "INFO") + return INFO; + if (DEFAULT_LOG_LEVEL == "WARNING") + return WARNING; + return ERROR; +} + +LogEnum DEFAULT_LOG_LEVEL_ENUM = getLogLevel(); +std::string DOCKER_LOGS_DIR = parseEnvVariables((char *)"DOCKER_LOGS"); + +void log_default(std::string someString, LogEnum log_level) +{ + std::string actualLog; + if ((int)log_level > (int)DEFAULT_LOG_LEVEL_ENUM) + return; + + switch (log_level) + { + case ERROR: + { + std::string errorString = std::strerror(errno); + actualLog = "ERROR --- " + someString + " * errno: * " + errorString; + break; + } + case WARNING: + { + actualLog = "WARNING --- " + someString; + break; + } + case INFO: + { + actualLog = "INFO --- " + someString; + break; + } + case DEBUG: + { + actualLog = "DEBUG --- " + someString; + break; + } + } + log(DOCKER_LOGS_DIR + "/afl.log", actualLog); +} + +void log(std::string filename, std::string someString) { std::ofstream logfile; logfile.open(filename, std::ios_base::app); - logfile << some_string + "\n"; + logfile << someString + "\n"; logfile.close(); } @@ -81,7 +129,8 @@ std::vector split(const std::string &s, char delimiter) return tokens; } -void clearFile(std::string pathName){ +void clearFile(std::string pathName) +{ std::ofstream wf(pathName, std::ios::out | std::ios::binary); if (!wf) { diff --git a/wasm-fuzzer/fuzzing-client-afl/utils.h b/wasm-fuzzer/fuzzing-client-afl/utils.h index 34a41f31..8b3b2971 100644 --- a/wasm-fuzzer/fuzzing-client-afl/utils.h +++ b/wasm-fuzzer/fuzzing-client-afl/utils.h @@ -7,7 +7,18 @@ #include #include #include +#include +#include +enum LogEnum +{ + ERROR, + WARNING, + INFO, + DEBUG +}; + +void log_default(std::string, LogEnum); void log(std::string, std::string); void printBuffer(int, char *); void logBuffer(std::string, int, char *); diff --git a/wasm-fuzzer/fuzzing-client-afl/wait_for_server.cpp b/wasm-fuzzer/fuzzing-client-afl/wait_for_server.cpp index 30d7c14c..88e8c7a6 100644 --- a/wasm-fuzzer/fuzzing-client-afl/wait_for_server.cpp +++ b/wasm-fuzzer/fuzzing-client-afl/wait_for_server.cpp @@ -1,28 +1,15 @@ #include "utils.h" #include "socket_client.h" #include -#include #include - int main(int argc, char *argv[]) { - setbuf(stdout, NULL); // For some reason stdout gets buffered until exit otherwise std::string SWAM_SOCKET_HOST = parseEnvVariables((char *)"SWAM_SOCKET_HOST"); std::string SWAM_SOCKET_PORT = parseEnvVariables((char *)"SWAM_SOCKET_PORT"); - printf("Waiting for Swam server...\n"); - int sockfd; - while (true) { - try { - sockfd = connectToServer(&SWAM_SOCKET_HOST[0], std::stoi(SWAM_SOCKET_PORT)); - close(sockfd); - break; - } catch (...) { - printf("Trying to connect again in 4 seconds...\n"); - std::this_thread::sleep_for(std::chrono::milliseconds(4000)); - } - } - printf("Can connect to Swam!\n"); + // TODO: Check if uncaught exception leads to exit code != 0 + wait_for_server(&SWAM_SOCKET_HOST[0], std::stoi(SWAM_SOCKET_PORT)); + exit(0); } diff --git a/wasm-fuzzer/fuzzing-server-swam b/wasm-fuzzer/fuzzing-server-swam index 028a7b8d..e0728af8 160000 --- a/wasm-fuzzer/fuzzing-server-swam +++ b/wasm-fuzzer/fuzzing-server-swam @@ -1 +1 @@ -Subproject commit 028a7b8dac86b1936e692ae0b3c19431bf2ee387 +Subproject commit e0728af81800d47dd9124de7942fc4b79caeaa7c diff --git a/wasm-fuzzer/supervisord.conf b/wasm-fuzzer/supervisord.conf index cbaf9839..5a364a24 100644 --- a/wasm-fuzzer/supervisord.conf +++ b/wasm-fuzzer/supervisord.conf @@ -2,7 +2,7 @@ nodaemon=true user=root -[program:mill_server] +[program:swam_server] command=%(ENV_DOCKER_SWAM_SRC)s/entrypoint_mill_server.sh stdout_logfile=/dev/stdout stderr_logfile=/dev/stderr