LCOV - code coverage report
Current view: top level - discof/restore/utils - fuzz_snapshot_parser.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 197 0.0 %
Date: 2025-10-13 04:42:14 Functions: 0 5 0.0 %

          Line data    Source code
       1             : #include "fd_ssparse.h"
       2             : 
       3             : #include "../../../util/fd_util.h"
       4             : #include "../../../util/archive/fd_tar.h"
       5             : #include "../../../util/sanitize/fd_fuzz.h"
       6             : 
       7             : #include <assert.h>
       8             : #include <stdlib.h>
       9             : 
      10           0 : #define MAX_ACC_VEC_CNT (64UL)
      11             : 
      12             : static void * parser_mem;
      13             : 
      14             : int
      15             : LLVMFuzzerInitialize( int  *   argc,
      16             :                       char *** argv ) {
      17             :   /* Set up shell without signal handlers */
      18             :   putenv( "FD_LOG_BACKTRACE=0" );
      19             :   fd_boot( argc, argv );
      20             :   atexit( fd_halt );
      21             :   fd_log_level_core_set   ( 4 );
      22             :   fd_log_level_logfile_set( 4 );
      23             : 
      24             :   parser_mem = aligned_alloc( fd_ssparse_align(), fd_ssparse_footprint( 1024UL ) );
      25             :   assert( parser_mem );
      26             : 
      27             :   return 0;
      28             : }
      29             : 
      30             : static void
      31             : make_tar_hdr( uchar *      data,
      32             :               char const * name,
      33             :               ulong        name_sz,
      34           0 :               ulong        file_sz ) {
      35           0 :   fd_tar_meta_t * tar = (fd_tar_meta_t *)data;
      36           0 :   LLVMFuzzerMutate( data, sizeof(fd_tar_meta_t), sizeof(fd_tar_meta_t) );
      37           0 :   fd_memcpy( tar->magic, FD_TAR_MAGIC, 6UL );
      38           0 :   fd_memcpy( tar->name, name, name_sz );
      39           0 :   fd_tar_meta_set_size( tar, file_sz );
      40           0 :   tar->typeflag = FD_TAR_TYPE_REGULAR;
      41           0 : }
      42             : 
      43             : static ulong
      44             : add_snapshot_chunk( uchar *      data,
      45             :                     ulong *      offset,
      46             :                     ulong *      avail,
      47             :                     char const * name,
      48             :                     ulong        name_sz,
      49           0 :                     ulong        file_sz ) {
      50             :   /* tar header for manifest */
      51           0 :   if( FD_UNLIKELY( *avail<sizeof(fd_tar_meta_t)+file_sz ) ) return LLVMFuzzerMutate( data + *offset, *avail, *avail );
      52             : 
      53           0 :   make_tar_hdr( data + *offset, name, name_sz, file_sz );
      54           0 :   *offset = *offset + sizeof(fd_tar_meta_t);
      55           0 :   *avail  = *avail - sizeof(fd_tar_meta_t);
      56             : 
      57           0 :   LLVMFuzzerMutate( data + *offset, file_sz, file_sz );
      58           0 :   *offset = *offset + file_sz;
      59           0 :   *avail  = *avail - file_sz;
      60             : 
      61             :   /* skip padding */
      62           0 :   ulong padding = fd_ulong_align_up( *offset, 512UL ) - *offset;
      63           0 :   if( FD_UNLIKELY( *avail<padding ) ) return LLVMFuzzerMutate( data + *offset, *avail, *avail );
      64           0 :   LLVMFuzzerMutate( data+*offset, padding, padding );
      65           0 :   *offset = *offset + padding;
      66           0 :   *avail  = *avail - padding;
      67             : 
      68           0 :   return 0;
      69           0 : }
      70             : 
      71             : static ulong
      72             : make_version( uchar *    data,
      73             :               fd_rng_t * rng,
      74             :               ulong *    offset,
      75           0 :               ulong *    avail ) {
      76             :   /* make a version tar header */
      77           0 :   ulong file_sz = 5UL;
      78           0 :   uint wrong_version_size = fd_rng_uint_roll( rng, 2U );
      79           0 :   if( FD_UNLIKELY( wrong_version_size ) ) file_sz = 5UL + fd_rng_ulong_roll( rng, 5UL );
      80             : 
      81           0 :   if( *avail<sizeof(fd_tar_meta_t)+file_sz ) return LLVMFuzzerMutate( data+*offset, *avail, *avail );
      82           0 :   make_tar_hdr( data+*offset, "version", 8UL, file_sz );
      83           0 :   *offset += sizeof(fd_tar_meta_t);
      84           0 :   *avail  -= sizeof(fd_tar_meta_t);
      85             : 
      86           0 :   uint random_version = fd_rng_uint_roll( rng, 2U );
      87             : 
      88           0 :   if( FD_LIKELY( random_version ) ) {
      89           0 :     LLVMFuzzerMutate( data+*offset, file_sz,  file_sz );
      90           0 :   } else {
      91             :     /* write version */
      92           0 :     fd_memcpy( data+*offset, "1.2.0", 5UL );
      93           0 :     *offset += file_sz;
      94           0 :     *avail  -= file_sz;
      95           0 :   }
      96             : 
      97             :   /* skip padding */
      98           0 :   ulong padding = fd_ulong_align_up( *offset, 512UL ) - *offset;
      99           0 :   if( FD_UNLIKELY( *avail<padding ) ) return LLVMFuzzerMutate( data+*offset, *avail, *avail );
     100           0 :   LLVMFuzzerMutate( data+*offset, padding, padding );
     101           0 :   *offset = *offset + padding;
     102           0 :   *avail  = *avail - padding;
     103           0 :   return 0;
     104           0 : }
     105             : 
     106             : static ulong
     107             : add_garbage( uchar * data,
     108             :              ulong * offset,
     109             :              ulong * avail,
     110           0 :              ulong   file_sz ) {
     111           0 :   ulong byte_to_mutate = fd_ulong_min( sizeof(fd_tar_meta_t)+file_sz, *avail );
     112           0 :   LLVMFuzzerMutate( data+*offset, byte_to_mutate, byte_to_mutate );
     113           0 :   *offset = *offset + byte_to_mutate;
     114           0 :   *avail  = *avail - byte_to_mutate;
     115             : 
     116             :   /* skip padding */
     117           0 :   ulong padding = fd_ulong_align_up( *offset, 512UL ) - *offset;
     118           0 :   if( FD_UNLIKELY( *avail<padding ) ) return LLVMFuzzerMutate( data + *offset, *avail, *avail );
     119           0 :   LLVMFuzzerMutate( data+*offset, padding, padding );
     120           0 :   *offset = *offset + padding;
     121           0 :   *avail  = *avail - padding;
     122             : 
     123           0 :   return 0;
     124           0 : }
     125             : 
     126           0 : #define NUM_SNAPSHOT_CHUNK_TYPES (6U)
     127             : 
     128           0 : #define VERSION           (0U)
     129           0 : #define STATUS_CACHE      (1U)
     130           0 : #define MANIFEST          (2U)
     131           0 : #define ACCOUNT           (3U)
     132           0 : #define STRUCTURED_RANDOM (4U)
     133           0 : #define GARBAGE           (5U)
     134             : 
     135             : ulong
     136             : LLVMFuzzerCustomMutator( uchar * data,
     137             :                          ulong   size,
     138             :                          ulong   max_size,
     139           0 :                          uint    seed ) {
     140           0 :   (void)size;
     141           0 :   fd_rng_t rng[1];
     142           0 :   FD_TEST( fd_rng_join( fd_rng_new( rng, seed, 0UL ) ) );
     143           0 :   ulong offset = 0UL;
     144           0 :   ulong avail  = max_size;
     145             : 
     146             :   /* create append vec mapping at front of input */
     147           0 :   ulong slots[ MAX_ACC_VEC_CNT ];
     148           0 :   ulong ids[ MAX_ACC_VEC_CNT ];
     149           0 :   ulong file_szs[ MAX_ACC_VEC_CNT ];
     150           0 :   ulong acc_vec_cnt = fd_rng_ulong_roll( rng, MAX_ACC_VEC_CNT );
     151           0 :   for( ulong i=0UL; i<acc_vec_cnt; i++ ) {
     152           0 :     file_szs[ i ] = fd_rng_ulong_roll( rng, 65536UL );
     153           0 :     slots[ i ]    = i;
     154           0 :     ids[ i ]      = i;
     155           0 :   }
     156             : 
     157           0 :   if( FD_UNLIKELY( avail<8UL+24UL*acc_vec_cnt ) ) return LLVMFuzzerMutate( data, avail, avail );
     158           0 :   *(ulong *)data = acc_vec_cnt;
     159           0 :   offset += 8UL;
     160           0 :   avail  -= 8UL;
     161             : 
     162           0 :   for( ulong i=0UL; i<acc_vec_cnt; i++ ) {
     163           0 :     *(ulong *)(data+offset)      = slots[ i ];
     164           0 :     *(ulong *)(data+offset+8UL)  = ids[ i ];
     165           0 :     *(ulong *)(data+offset+16UL) = file_szs[ i ];
     166           0 :     offset += 24UL;
     167           0 :     avail  -= 24UL;
     168           0 :   }
     169             : 
     170             :   /* pad to 512 bytes */
     171           0 :   ulong padding = fd_ulong_align_up( offset, 512UL ) - offset;
     172           0 :   if( FD_UNLIKELY( avail<padding ) ) return LLVMFuzzerMutate( data+offset, avail, avail );
     173           0 :   offset += padding;
     174           0 :   avail  -= padding;
     175             : 
     176           0 :   if( FD_UNLIKELY( avail<sizeof(fd_tar_meta_t) ) ) return LLVMFuzzerMutate( data, avail, avail );
     177             : 
     178           0 :   uint random_snapshot_chunks = fd_rng_uint_roll( rng, 2U );
     179             : 
     180           0 :   if( FD_LIKELY( random_snapshot_chunks ) ) {
     181           0 :     avail -= sizeof(fd_tar_meta_t)*2UL; /* reserve space for final zero tar frame and a valid tar frame */
     182             : 
     183           0 :     for(;;) {
     184           0 :       uint snapshot_chunk_type = fd_rng_uint_roll( rng, NUM_SNAPSHOT_CHUNK_TYPES );
     185             : 
     186           0 :       switch( snapshot_chunk_type ) {
     187           0 :         case VERSION: {
     188           0 :           ulong done = make_version( data, rng, &offset, &avail );
     189           0 :           if( FD_UNLIKELY( done ) ) goto end;
     190           0 :           break;
     191           0 :         }
     192           0 :         case MANIFEST: {
     193             :           /* tar header for manifest */
     194           0 :           ulong done = add_snapshot_chunk( data, &offset, &avail, "snapshots/123", 14UL, fd_rng_ulong_roll( rng, 16384UL ) );
     195           0 :           if( FD_UNLIKELY( done ) ) goto end;
     196           0 :           break;
     197           0 :         }
     198           0 :         case STATUS_CACHE: {
     199           0 :           ulong done = add_snapshot_chunk( data, &offset, &avail, "snapshots/status_cache", 23UL, fd_rng_ulong_roll( rng, 16384UL ) );
     200           0 :           if( FD_UNLIKELY( done ) ) goto end;
     201           0 :           break;
     202           0 :         }
     203           0 :         case ACCOUNT: {
     204             :           /* Add some account vecs */
     205           0 :           for( ulong i=0UL; i<acc_vec_cnt; i++ ) {
     206           0 :             if( FD_UNLIKELY( avail<sizeof(fd_tar_meta_t)+file_szs[ i ] ) ) return LLVMFuzzerMutate( data+offset, avail, avail );
     207             : 
     208           0 :             char name[ 100UL ];
     209           0 :             ulong name_sz;
     210           0 :             FD_TEST( fd_cstr_printf_check( name, 256UL, &name_sz, "accounts/%lu.%lu", slots[ i ], ids[ i ] ) );
     211           0 :             uint wrong_file_sz = fd_rng_uint_roll( rng, 2U );
     212           0 :             ulong file_sz = file_szs[ i ];
     213           0 :             if( FD_UNLIKELY( wrong_file_sz ) ) file_sz += fd_rng_ulong_roll( rng, 4096UL );
     214           0 :             ulong done = add_snapshot_chunk( data, &offset, &avail, name, name_sz, file_sz );
     215           0 :             if( FD_UNLIKELY( done ) ) goto end;
     216           0 :           }
     217           0 :           break;
     218           0 :         }
     219           0 :         case STRUCTURED_RANDOM: {
     220           0 :           char name[ 100UL ];
     221           0 :           LLVMFuzzerMutate( (uchar *)name, 99UL, 99UL );
     222           0 :           name[99UL ] = '\0';
     223           0 :           ulong done = add_snapshot_chunk( data, &offset, &avail, name, sizeof(name), fd_rng_ulong_roll( rng, 4096UL ) );
     224           0 :           if( FD_UNLIKELY( done ) ) goto end;
     225           0 :           break;
     226           0 :         }
     227           0 :         case GARBAGE: {
     228           0 :           ulong done = add_garbage( data, &offset, &avail, fd_rng_ulong_roll( rng, 4096UL ) );
     229           0 :           if( FD_UNLIKELY( done ) ) goto end;
     230           0 :           break;
     231           0 :         }
     232           0 :         default:
     233           0 :           FD_LOG_ERR(( "unknown snapshot chunk type %u", snapshot_chunk_type ));
     234           0 :           break;
     235           0 :       }
     236           0 :     }
     237           0 :   } else {
     238             :     /* make a version tar header */
     239           0 :     ulong done = make_version( data, rng, &offset, &avail );
     240           0 :     if( FD_UNLIKELY( done ) ) goto end;
     241             : 
     242             :     /* status cache */
     243           0 :     ulong file_sz = fd_rng_ulong_roll( rng, 4096UL );
     244           0 :     done = add_snapshot_chunk( data, &offset, &avail, "snapshots/status_cache", 23UL, file_sz );
     245           0 :     if( FD_UNLIKELY( done ) ) goto end;
     246             : 
     247             :     /* manifest */
     248           0 :     file_sz = fd_rng_ulong_roll( rng, 16384UL );
     249           0 :     done = add_snapshot_chunk( data, &offset, &avail, "snapshots/123", 14UL, file_sz );
     250           0 :     if( FD_UNLIKELY( done ) ) goto end;
     251             : 
     252             :     /* Add some account vecs */
     253           0 :     for( ulong i=0UL; i<acc_vec_cnt; i++ ) {
     254           0 :       if( FD_UNLIKELY( avail<sizeof(fd_tar_meta_t)+file_szs[ i ] ) ) return LLVMFuzzerMutate( data+offset, avail, avail );
     255             : 
     256           0 :       char name[ 100UL ];
     257           0 :       ulong name_sz;
     258           0 :       FD_TEST( fd_cstr_printf_check( name, 256UL, &name_sz, "accounts/%lu.%lu", slots[ i ], ids[ i ] ) );
     259           0 :       uint wrong_file_sz = fd_rng_uint_roll( rng, 2U );
     260           0 :       ulong file_sz = file_szs[ i ];
     261           0 :       if( FD_UNLIKELY( wrong_file_sz ) ) file_sz += fd_rng_ulong_roll( rng, 4096UL );
     262           0 :       ulong done = add_snapshot_chunk( data, &offset, &avail, name, name_sz, file_sz );
     263           0 :       if( FD_UNLIKELY( done ) ) goto end;
     264           0 :     }
     265             : 
     266           0 :     uint include_garbage = fd_rng_uint_roll( rng, 2U );
     267           0 :     if( FD_LIKELY( include_garbage ) ) {
     268           0 :       add_garbage( data, &offset, &avail, fd_rng_ulong_roll( rng, 4096UL ) );
     269           0 :     }
     270           0 :   }
     271             : 
     272           0 : end:
     273           0 :   if( FD_LIKELY( random_snapshot_chunks ) ) avail += sizeof(fd_tar_meta_t)*2UL;
     274             :   /* zero tar frame */
     275           0 :   padding = 512UL;
     276           0 :   if( FD_UNLIKELY( avail<padding ) ) return LLVMFuzzerMutate( data+offset, avail, avail );
     277           0 :   fd_memset( data+offset, 0, padding );
     278           0 :   offset += padding;
     279           0 :   avail  -= padding;
     280             : 
     281           0 :   uint random_valid_tar_hdr = fd_rng_uint_roll( rng, 2U );
     282           0 :   if( FD_LIKELY( random_valid_tar_hdr ) ) {
     283           0 :     if( FD_UNLIKELY( avail<sizeof(fd_tar_meta_t) ) ) return LLVMFuzzerMutate( data+offset, avail, avail );
     284           0 :     make_tar_hdr( data+offset, "version", 8UL, 5UL );
     285           0 :     offset += sizeof(fd_tar_meta_t);
     286           0 :     avail  -= sizeof(fd_tar_meta_t);
     287           0 :   } else {
     288             :     /* zero tar frame */
     289           0 :     padding = 512UL;
     290           0 :     if( FD_UNLIKELY( avail<padding ) ) return LLVMFuzzerMutate( data+offset, avail, avail );
     291           0 :     fd_memset( data+offset, 0, padding );
     292           0 :     offset += padding;
     293           0 :     avail  -= padding;
     294           0 :   }
     295             : 
     296             : 
     297           0 :   return offset;
     298           0 : }
     299             : 
     300             : int
     301             : LLVMFuzzerTestOneInput( uchar const * const data,
     302             :                         ulong         const size ) {
     303             :   fd_ssparse_t * parser = fd_ssparse_new( parser_mem, 1024UL, 42UL );
     304             :   assert( parser );
     305             : 
     306             :   fd_ssparse_reset( parser );
     307             : 
     308             :   if( FD_UNLIKELY( size<sizeof(ulong) ) ) return -1;
     309             :   ulong acc_vec_cnt = *(ulong *)data;
     310             :   if( FD_UNLIKELY( acc_vec_cnt>MAX_ACC_VEC_CNT ) ) return -1;
     311             : 
     312             :   ulong offset_to_padding = 8UL + 24UL*acc_vec_cnt;
     313             :   if( FD_UNLIKELY( size<offset_to_padding ) ) return -1;
     314             : 
     315             :   ulong slots[ MAX_ACC_VEC_CNT ];
     316             :   ulong ids[ MAX_ACC_VEC_CNT ];
     317             :   ulong file_szs[ MAX_ACC_VEC_CNT ];
     318             :   for( ulong i=0UL; i<acc_vec_cnt; i++ ) {
     319             :     slots[ i ]    = *(ulong *)(data+8UL+24UL*i);
     320             :     ids[ i ]      = *(ulong *)(data+8UL+24UL*i+8UL);
     321             :     file_szs[ i ] = *(ulong *)(data+8UL+24UL*i+16UL);
     322             :   }
     323             : 
     324             :   if( FD_UNLIKELY( fd_ssparse_populate_acc_vec_map( parser, slots, ids, file_szs, acc_vec_cnt ) ) ) return -1;
     325             : 
     326             :   ulong offset_to_input = fd_ulong_align_up( offset_to_padding, 512UL );
     327             :   if( FD_UNLIKELY( size<offset_to_input ) ) return -1;
     328             : 
     329             :   /* FIXME split input in the future */
     330             :   fd_ssparse_advance_result_t result[1];
     331             :   uchar const * data_ptr = data + offset_to_input;
     332             :   ulong         data_sz  = size - offset_to_input;
     333             :   for (;;) {
     334             :     int res = fd_ssparse_advance( parser, data_ptr, data_sz, result );
     335             :     if( res==FD_SSPARSE_ADVANCE_DONE || res==FD_SSPARSE_ADVANCE_ERROR ) break;
     336             :     data_ptr += result->bytes_consumed;
     337             :     data_sz  -= result->bytes_consumed;
     338             :   }
     339             :   return 0;
     340             : }

Generated by: LCOV version 1.14