diff options
-rw-r--r-- | CMakeLists.txt | 6 | ||||
-rw-r--r-- | src/server/net.c | 37 | ||||
-rw-r--r-- | src/server/rpc.c | 11 | ||||
-rw-r--r-- | src/server/rpc.h | 1 | ||||
-rw-r--r-- | src/server/server.c | 39 | ||||
-rw-r--r-- | src/shared/log.c | 5 | ||||
-rw-r--r-- | src/types.h | 6 |
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) |