LCOV - code coverage report
Current view: top level - ballet/http - fuzz_picohttpparser.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 36 179 20.1 %
Date: 2025-01-08 12:08:44 Functions: 3 6 50.0 %

          Line data    Source code
       1             : #if !FD_HAS_HOSTED
       2             : #error "This target requires FD_HAS_HOSTED"
       3             : #endif
       4             : 
       5             : #include <assert.h>
       6             : #include <stdio.h>
       7             : #include <stdlib.h>
       8             : #include <unistd.h>
       9             : 
      10             : #include "../../util/fd_util.h"
      11             : #include "../../util/sanitize/fd_fuzz.h"
      12             : #include "picohttpparser.h"
      13             : 
      14             : int
      15             : LLVMFuzzerInitialize( int  *   argc,
      16          18 :                       char *** argv ) {
      17             :   /* Set up shell without signal handlers */
      18          18 :   putenv( "FD_LOG_BACKTRACE=0" );
      19          18 :   fd_boot( argc, argv );
      20          18 :   atexit( fd_halt );
      21             : 
      22             :   /* Disable parsing error logging */
      23          18 :   fd_log_level_stderr_set(4);
      24          18 :   return 0;
      25          18 : }
      26             : 
      27           0 : #define HEADER_CAP (32UL)
      28             : 
      29           0 : void fuzz_request(uchar const * data, ulong size) {
      30           0 :   if (size >= sizeof(size_t)) {
      31           0 :     size -= sizeof(size_t);
      32           0 :     size_t last_len = *(size_t *)data;
      33           0 :     if (last_len > 0) {
      34           0 :       if (size == 0) {
      35           0 :         last_len = 0;
      36           0 :       } else {
      37           0 :         last_len %= size;
      38           0 :       }
      39           0 :     }
      40           0 :     data += sizeof(size_t);
      41             : 
      42           0 :     do {
      43           0 :       char const *      method;
      44           0 :       ulong             method_len;
      45           0 :       char const *      path;
      46           0 :       ulong             path_len;
      47           0 :       int               minor_version;
      48           0 :       struct phr_header headers[ HEADER_CAP ];
      49           0 :       ulong             header_cnt = HEADER_CAP;
      50             : 
      51           0 :       int res = phr_parse_request(
      52           0 :           (char const *)data, size,
      53           0 :           &method, &method_len,
      54           0 :           &path, &path_len,
      55           0 :           &minor_version,
      56           0 :           headers, &header_cnt, last_len );
      57             : 
      58           0 :       if( res==0 ) {
      59           0 :         FD_FUZZ_MUST_BE_COVERED;
      60           0 :         assert( method_len < size );
      61           0 :         assert( path_len   < size );
      62           0 :         assert( header_cnt <= HEADER_CAP );
      63           0 :         for( ulong i=0UL; i<header_cnt; i++ ) {
      64           0 :           assert( headers[i].name_len  < size );
      65           0 :           assert( headers[i].value_len < size );
      66           0 :         }
      67           0 :       } else if ( res > 0 ) {
      68           0 :         assert( (ulong) res <= size) ;
      69           0 :       } else {
      70           0 :         FD_FUZZ_MUST_BE_COVERED;
      71           0 :       }
      72           0 :     } while(0);
      73             : 
      74             :     /* parse request byte by byte */
      75             : 
      76           0 :     do {
      77           0 :       char const *      method;
      78           0 :       ulong             method_len;
      79           0 :       char const *      path;
      80           0 :       ulong             path_len;
      81           0 :       int               minor_version;
      82           0 :       struct phr_header headers[ HEADER_CAP ];
      83           0 :       ulong             header_cnt = HEADER_CAP;
      84           0 :       int               ok = 0;
      85             : 
      86           0 :       for( ulong cursor=0UL; cursor<size; cursor++ ) {
      87           0 :         FD_FUZZ_MUST_BE_COVERED;
      88           0 :         int res = phr_parse_request(
      89           0 :             (char const *)data + cursor, 1UL,
      90           0 :             &method, &method_len,
      91           0 :             &path, &path_len,
      92           0 :             &minor_version,
      93           0 :             headers, &header_cnt, 0 );
      94           0 :         if( res>0 ) {
      95           0 :           ok = 1;
      96           0 :           break;
      97           0 :         }
      98           0 :         if( res==-1 ) break;
      99           0 :         assert( res==-2 );
     100           0 :       }
     101             : 
     102           0 :       if( ok ) {
     103           0 :         FD_FUZZ_MUST_BE_COVERED;
     104           0 :         assert( method_len < size );
     105           0 :         assert( path_len   < size );
     106           0 :         assert( header_cnt <= HEADER_CAP );
     107           0 :         for( ulong i=0UL; i<header_cnt; i++ ) {
     108           0 :           assert( headers[i].name_len  < size );
     109           0 :           assert( headers[i].value_len < size );
     110           0 :         }
     111           0 :       } else {
     112           0 :         FD_FUZZ_MUST_BE_COVERED;
     113           0 :       }
     114           0 :     } while(0);
     115           0 :   }
     116           0 : }
     117             : 
     118           0 : void fuzz_response(uchar const * data, ulong size) {
     119           0 :   if (size >= sizeof(size_t)) {
     120           0 :     size -= sizeof(size_t);
     121           0 :     size_t last_len = *(size_t *)data;
     122           0 :     if (last_len > 0) {
     123           0 :       if (size == 0) {
     124           0 :         last_len = 0;
     125           0 :       } else {
     126           0 :         last_len %= size;
     127           0 :       }
     128           0 :     }
     129           0 :     data += sizeof(size_t);
     130             : 
     131           0 :     do {
     132           0 :       int minor_version;
     133           0 :       int status;
     134           0 :       const char * message;
     135           0 :       ulong message_len;
     136           0 :       struct phr_header headers[ HEADER_CAP ];
     137           0 :       ulong num_headers = HEADER_CAP;
     138             : 
     139           0 :       int res = phr_parse_response(
     140           0 :           (char const *)data, size,
     141           0 :           &minor_version, &status, &message, &message_len,
     142           0 :           headers, &num_headers, last_len );
     143           0 :       if ( res > 0 ) {
     144           0 :         assert( (ulong) res <= size) ;
     145           0 :       }
     146           0 :     } while(0);
     147           0 :   }
     148           0 : }
     149             : 
     150           0 : void fuzz_headers(uchar const * data, ulong size) {
     151           0 :   if (size >= sizeof(size_t)) {
     152           0 :     size -= sizeof(size_t);
     153           0 :     size_t last_len = *(size_t *)data;
     154           0 :     if (last_len > 0) {
     155           0 :       if (size == 0) {
     156           0 :         last_len = 0;
     157           0 :       } else {
     158           0 :         last_len %= size;
     159           0 :       }
     160           0 :     }
     161           0 :     data += sizeof(size_t);
     162             : 
     163           0 :     do {
     164           0 :       struct phr_header headers[ HEADER_CAP ];
     165           0 :       ulong num_headers = HEADER_CAP;
     166             : 
     167           0 :       int res = phr_parse_headers(
     168           0 :           (char const *)data, size,
     169           0 :           headers, &num_headers, last_len );
     170           0 :       if ( res > 0 ) {
     171           0 :         assert( (ulong) res <= size) ;
     172           0 :       }
     173           0 :     } while(0);
     174           0 :   }
     175           0 : }
     176             : 
     177           3 : void fuzz_phr_decode_chunked(uchar const * data, ulong size) {
     178           3 :   if (size >= 2) {
     179           3 :     struct phr_chunked_decoder decoder;
     180           3 :     memset(&decoder, 0, sizeof(struct phr_chunked_decoder));
     181           3 :     decoder._state = (char) (data[0] % 6);
     182           3 :     decoder.consume_trailer = (char) data[1];
     183             : 
     184           3 :     size_t buf_sz = size - 2;
     185           3 :     if (buf_sz > 0) {
     186           3 :       char *buf = malloc(buf_sz);
     187           3 :       memcpy(buf, data + 2, buf_sz);
     188             : 
     189           3 :       do {
     190           3 :         phr_decode_chunked(&decoder, buf, &buf_sz);
     191           3 :       } while(0);
     192             : 
     193           3 :       free(buf);
     194           3 :     }
     195           3 :   }
     196           3 : }
     197             : 
     198             : int
     199             : LLVMFuzzerTestOneInput( uchar const * data,
     200           3 :                         ulong         size ) {
     201             : 
     202             :   /* parse request in one go */
     203             : 
     204           3 :   if (size >= 1) {
     205           3 :     uchar action = data[0] % 4;
     206           3 :     switch(action) {
     207           0 :       case 0:
     208           0 :         fuzz_request(data + 1, size - 1);
     209           0 :         break;
     210           0 :       case 1:
     211           0 :         fuzz_response(data + 1, size - 1);
     212           0 :         break;
     213           0 :       case 2:
     214           0 :         fuzz_headers(data + 1, size - 1);
     215           0 :         break;
     216           3 :       case 3:
     217           3 :         fuzz_phr_decode_chunked(data + 1, size - 1);
     218           3 :         break;
     219           3 :     }
     220           3 :   }
     221             : 
     222             :   
     223             : 
     224           3 :   FD_FUZZ_MUST_BE_COVERED;
     225           3 :   return 0;
     226           3 : }

Generated by: LCOV version 1.14