Skip to content

Commit

Permalink
http: add request parser fuzzer
Browse files Browse the repository at this point in the history
  • Loading branch information
riptl authored and ripatel-fd committed Dec 1, 2023
1 parent 5fdba9e commit 36a36fa
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 0 deletions.
4 changes: 4 additions & 0 deletions corpus/fuzz_picohttpparser/request_simple
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
GET /hoge HTTP/1.1
Host: example.com
Cookie:

2 changes: 2 additions & 0 deletions src/ballet/http/Local.mk
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@ src/ballet/http/fd_picohttpparser.c: src/ballet/http/picohttpparser.c src/ballet
$(RM) src/ballet/http/picohttpparsertemp.c

$(OBJDIR)/obj/ballet/http/fd_picohttpparser.o: src/ballet/http/fd_picohttpparser.c

$(call fuzz-test,fuzz_picohttpparser,fuzz_picohttpparser,fd_ballet fd_util)
100 changes: 100 additions & 0 deletions src/ballet/http/fuzz_picohttpparser.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#if !FD_HAS_HOSTED
#error "This target requires FD_HAS_HOSTED"
#endif

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include "../../util/fd_util.h"
#include "picohttpparser.h"

int
LLVMFuzzerInitialize( int * argc,
char *** argv ) {
/* Set up shell without signal handlers */
putenv( "FD_LOG_BACKTRACE=0" );
fd_boot( argc, argv );
atexit( fd_halt );

/* Disable parsing error logging */
fd_log_level_stderr_set(4);
return 0;
}

#define HEADER_CAP (32UL)

int
LLVMFuzzerTestOneInput( uchar const * data,
ulong size ) {

/* parse request in one go */

do {
char const * method;
ulong method_len;
char const * path;
ulong path_len;
int minor_version;
struct phr_header headers[ HEADER_CAP ];
ulong header_cnt = HEADER_CAP;

int res = phr_parse_request(
(char const *)data, size,
&method, &method_len,
&path, &path_len,
&minor_version,
headers, &header_cnt, 0UL );

if( res==0 ) {
assert( method_len < size );
assert( path_len < size );
assert( header_cnt <= HEADER_CAP );
for( ulong i=0UL; i<header_cnt; i++ ) {
assert( headers[i].name_len < size );
assert( headers[i].value_len < size );
}
}
} while(0);

/* parse request byte by byte */

do {
char const * method;
ulong method_len;
char const * path;
ulong path_len;
int minor_version;
struct phr_header headers[ HEADER_CAP ];
ulong header_cnt = HEADER_CAP;
int ok = 0;

for( ulong cursor=0UL; cursor<size; cursor++ ) {
int res = phr_parse_request(
(char const *)data + cursor, 1UL,
&method, &method_len,
&path, &path_len,
&minor_version,
headers, &header_cnt, 0UL );
if( res>0 ) {
ok = 1;
break;
}
if( res==-1 ) break;
assert( res==-2 );
}

if( ok ) {
assert( method_len < size );
assert( path_len < size );
assert( header_cnt <= HEADER_CAP );
for( ulong i=0UL; i<header_cnt; i++ ) {
assert( headers[i].name_len < size );
assert( headers[i].value_len < size );
}
}
} while(0);

return 0;
}

0 comments on commit 36a36fa

Please sign in to comment.