summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Rettberg2017-10-30 21:39:56 +0100
committerSimon Rettberg2017-10-30 21:39:56 +0100
commit46c3e0e276e62b6be76e69b68de56432692efcf3 (patch)
tree194ab981ea90f1227cfb94509b9d17b25bb29354
parent[SERVER] Missed occurence of AF_INET(6) -> HOST_IP[46] (diff)
downloaddnbd3-46c3e0e276e62b6be76e69b68de56432692efcf3.tar.gz
dnbd3-46c3e0e276e62b6be76e69b68de56432692efcf3.tar.xz
dnbd3-46c3e0e276e62b6be76e69b68de56432692efcf3.zip
[SERVER] Add AFL support
AFL is an instrumenting fuzzer. It expects to pass input to the program to be tested via command line (file name) or via stdin. This adds support for reading messages that normally would arrive via network directly from stdin. In this mode, the server is pretty useless otherwise. http://lcamtuf.coredump.cx/afl/
-rw-r--r--CMakeLists.txt6
-rw-r--r--src/server/net.c37
-rw-r--r--src/server/rpc.c11
-rw-r--r--src/server/rpc.h1
-rw-r--r--src/server/server.c39
-rw-r--r--src/shared/log.c5
-rw-r--r--src/types.h6
7 files changed, 101 insertions, 4 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d738bd1..f2da9e5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -14,6 +14,8 @@ OPTION(BUILD_FUSE_CLIENT "Build dnbd3 fuse client" ON)
OPTION(BUILD_SERVER "Build dnbd3 server" ON)
OPTION(BUILD_STRESSTEST "Build dnbd3 stress testing tool" OFF)
+OPTION(SERVER_FOR_AFL "Build dnbd3-server for usage with afl-fuzz" OFF)
+
# Is there a non-retarded way to check if build type is debug or release?
# When specifying, it is case insensitive, so DeBuG would also enable debug builds,
# but in cmake, we can only do case sensitive matches... :/
@@ -140,6 +142,10 @@ ENDIF()
################################################################################
if(BUILD_SERVER)
+ IF(SERVER_FOR_AFL)
+ message(" ######################## Building server for AFL mode - will be useless otherwise!")
+ ADD_DEFINITIONS(-DAFL_MODE)
+ ENDIF()
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} ${JANSSON_INCLUDE_DIR})
FILE(GLOB SERVER_SRCS src/server/*.c src/shared/*.c src/server/picohttpparser/*.c)
ADD_EXECUTABLE(dnbd3-server ${SERVER_SRCS})
diff --git a/src/server/net.c b/src/server/net.c
index c7d34de..c11a78a 100644
--- a/src/server/net.c
+++ b/src/server/net.c
@@ -69,6 +69,9 @@ void net_updateGlobalSentStatsFromClient(dnbd3_client_t * const client)
static inline bool recv_request_header(int sock, dnbd3_request_t *request)
{
ssize_t ret, fails = 0;
+#ifdef AFL_MODE
+ sock = 0;
+#endif
// Read request header from socket
while ( ( ret = recv( sock, request, sizeof(*request), MSG_WAITALL ) ) != sizeof(*request) ) {
if ( errno == EINTR && ++fails < 10 ) continue;
@@ -93,6 +96,9 @@ static inline bool recv_request_header(int sock, dnbd3_request_t *request)
static inline bool recv_request_payload(int sock, uint32_t size, serialized_buffer_t *payload)
{
+#ifdef AFL_MODE
+ sock = 0;
+#endif
if ( size == 0 ) {
logadd( LOG_ERROR, "Called recv_request_payload() to receive 0 bytes" );
return false;
@@ -169,7 +175,11 @@ void* net_handleNewConnection(void *clientPtr)
// Await data from client. Since this is a fresh connection, we expect data right away
sock_setTimeout( client->sock, _clientTimeout );
do {
+#ifdef AFL_MODE
+ const int ret = (int)recv( 0, &request, sizeof(request), MSG_WAITALL );
+#else
const int ret = (int)recv( client->sock, &request, sizeof(request), MSG_WAITALL );
+#endif
// It's expected to be a real dnbd3 client
// Check request for validity. This implicitly dictates that all HTTP requests are more than 16 bytes...
if ( ret != (int)sizeof(request) ) {
@@ -408,7 +418,32 @@ void* net_handleNewConnection(void *clientPtr)
realBytes = image->realFilesize - offset;
}
while ( done < realBytes ) {
-#ifdef __linux__
+#ifdef AFL_MODE
+ char buf[1000];
+ size_t cnt = realBytes - done;
+ if ( cnt > 1000 ) {
+ cnt = 1000;
+ }
+ const ssize_t ret = pread( image_file, buf, cnt, offset );
+ if ( ret <= 0 ) {
+ const int err = errno;
+ if ( lock ) pthread_mutex_unlock( &client->sendMutex );
+ if ( ret == -1 ) {
+ if ( err != EPIPE && err != ECONNRESET && err != ESHUTDOWN
+ && err != EAGAIN && err != EWOULDBLOCK ) {
+ logadd( LOG_DEBUG1, "sendfile to %s failed (image to net. sent %d/%d, errno=%d)",
+ client->hostName, (int)done, (int)realBytes, err );
+ }
+ if ( err == EBADF || err == EFAULT || err == EINVAL || err == EIO ) {
+ logadd( LOG_INFO, "Disabling %s:%d", image->name, image->rid );
+ image->working = false;
+ }
+ }
+ goto exit_client_cleanup;
+ }
+ write( client->sock, buf, ret );
+ done += ret;
+#elif defined(__linux__)
const ssize_t ret = sendfile( client->sock, image_file, &foffset, realBytes - done );
if ( ret <= 0 ) {
const int err = errno;
diff --git a/src/server/rpc.c b/src/server/rpc.c
index f64e90a..97cca9e 100644
--- a/src/server/rpc.c
+++ b/src/server/rpc.c
@@ -133,7 +133,11 @@ void rpc_sendStatsJson(int sock, dnbd3_host_t* host, const void* data, const int
// Reaching here means partial request or parse error
if ( pret == -2 ) { // Partial, keep reading
prevLen = hoff;
+#ifdef AFL_MODE
+ ssize_t ret = recv( 0, headerBuf + hoff, sizeof(headerBuf) - hoff, 0 );
+#else
ssize_t ret = recv( sock, headerBuf + hoff, sizeof(headerBuf) - hoff, 0 );
+#endif
if ( ret == 0 ) return;
if ( ret == -1 ) {
if ( errno == EINTR ) continue;
@@ -260,6 +264,9 @@ static bool sendReply(int sock, const char *status, const char *ctype, const cha
if ( keepAlive == HTTP_CLOSE ) {
// Wait for flush
shutdown( sock, SHUT_WR );
+#ifdef AFL_MODE
+ sock = 0;
+#endif
while ( read( sock, buffer, sizeof buffer ) > 0 );
return false;
}
@@ -303,7 +310,11 @@ static int getacl(dnbd3_host_t *host)
if ( aclRules[i].bitMask != 0 && aclRules[i].host[aclRules[i].bytes] != ( host->addr[aclRules[i].bytes] & aclRules[i].bitMask ) ) continue;
return aclRules[i].permissions;
}
+#ifdef AFL_MODE
+ return 0x7fffff;
+#else
return 0;
+#endif
}
#define SETBIT(x) else if ( strcmp( argv[i], #x ) == 0 ) mask |= ACL_ ## x
diff --git a/src/server/rpc.h b/src/server/rpc.h
index 1d50e77..f337067 100644
--- a/src/server/rpc.h
+++ b/src/server/rpc.h
@@ -3,6 +3,7 @@
struct dnbd3_host_t;
+void rpc_init();
void rpc_sendStatsJson(int sock, struct dnbd3_host_t* host, const void *data, const int dataLen);
#endif
diff --git a/src/server/server.c b/src/server/server.c
index 5932b0b..5776765 100644
--- a/src/server/server.c
+++ b/src/server/server.c
@@ -28,6 +28,7 @@
#include "altservers.h"
#include "integrity.h"
#include "threadpool.h"
+#include "rpc.h"
#include "../version.h"
#include "../shared/sockhelper.h"
@@ -227,6 +228,40 @@ int main(int argc, char *argv[])
exit( EXIT_FAILURE );
}
+ timing_setBase();
+ timing_get( &startupTime );
+
+#ifdef AFL_MODE
+ // ###### AFL
+ //
+ image_serverStartup();
+ net_init();
+ uplink_globalsInit();
+ rpc_init();
+ if ( !image_loadAll( NULL ) || _shutdown ) {
+ fprintf( stderr, "Error loading images\n" );
+ exit( 3 );
+ }
+ {
+ struct sockaddr_storage client;
+ memset( &client, 0, sizeof client );
+ client.ss_family = AF_INET;
+ dnbd3_client_t *dnbd3_client = dnbd3_prepareClient( &client, 1 );
+ if ( dnbd3_client == NULL ) {
+ fprintf( stderr, "New client failed\n" );
+ exit( 1 );
+ }
+#ifdef __AFL_HAVE_MANUAL_CONTROL
+ __AFL_INIT();
+#endif
+ net_handleNewConnection( dnbd3_client );
+ exit( 0 );
+ }
+ //
+ // ###### AFL END
+#endif
+
+
// One-shots first:
if ( paramCreate != NULL ) {
@@ -236,12 +271,12 @@ int main(int argc, char *argv[])
// No one-shot detected, normal server operation
if ( demonize ) daemon( 1, 0 );
- timing_setBase();
image_serverStartup();
altservers_init();
integrity_init();
net_init();
uplink_globalsInit();
+ rpc_init();
logadd( LOG_INFO, "DNBD3 server starting.... Machine type: " ENDIAN_MODE );
if ( altservers_load() < 0 ) {
@@ -268,8 +303,6 @@ int main(int argc, char *argv[])
return 0;
}
- timing_get( &startupTime );
-
// Give other threads some time to start up before accepting connections
sleep( 1 );
diff --git a/src/shared/log.c b/src/shared/log.c
index 1022cec..62b104e 100644
--- a/src/shared/log.c
+++ b/src/shared/log.c
@@ -114,8 +114,13 @@ void logadd(const logmask_t mask, const char *fmt, ...)
pthread_mutex_unlock( &logLock );
}
if ( maskCon & mask ) {
+#ifdef AFL_MODE
+ fputs( buffer, stderr );
+ fflush( stderr );
+#else
fputs( buffer, stdout );
fflush( stdout );
+#endif
}
}
diff --git a/src/types.h b/src/types.h
index 313e907..fd7bd21 100644
--- a/src/types.h
+++ b/src/types.h
@@ -55,6 +55,12 @@
#include <netinet/in.h>
#endif
+#ifdef AFL_MODE
+#define send(a,b,c,d) write(a,b,c)
+#define recv(a,b,c,d) read(a,b,c)
+#endif
+
+
// ioctl
#define DNBD3_MAGIC 'd'
#define IOCTL_OPEN _IO(0xab, 1)