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 : }
|