summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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)