Line data Source code
1 : #include "fd_gossip_private.h"
2 : #include <assert.h>
3 : #include <stdlib.h>
4 :
5 : int
6 : LLVMFuzzerInitialize( int * argc,
7 12 : char *** argv ) {
8 : /* Set up shell without signal handlers */
9 12 : putenv( "FD_LOG_BACKTRACE=0" );
10 12 : fd_boot( argc, argv );
11 12 : fd_log_level_stderr_set(4);
12 12 : atexit( fd_halt );
13 12 : return 0;
14 12 : }
15 :
16 : static int
17 : bounds_check_arr( ulong data_sz,
18 : ulong ele_off,
19 : ulong ele_sz,
20 0 : ulong ele_cnt ) {
21 0 : ulong ele_tot;
22 0 : if( FD_UNLIKELY( __builtin_umull_overflow( ele_sz, ele_cnt, &ele_tot ) ) )
23 0 : return 0;
24 0 : ulong ele_hi;
25 0 : if( FD_UNLIKELY( __builtin_uaddl_overflow( ele_off, ele_tot, &ele_hi ) ) )
26 0 : return 0;
27 0 : if( FD_UNLIKELY( ele_hi>data_sz ) )
28 0 : return 0;
29 0 : return 1;
30 0 : }
31 :
32 : static int
33 : bounds_check( ulong data_sz,
34 : ulong ele_off,
35 0 : ulong ele_sz ) {
36 0 : ulong ele_hi;
37 0 : if( FD_UNLIKELY( __builtin_uaddl_overflow( ele_off, ele_sz, &ele_hi ) ) )
38 0 : return 0;
39 0 : if( FD_UNLIKELY( ele_hi>data_sz ) )
40 0 : return 0;
41 0 : return 1;
42 0 : }
43 :
44 : static void
45 : check_view_snapshot_hashes( ulong size,
46 0 : fd_gossip_view_snapshot_hashes_t const * v ) {
47 0 : assert( bounds_check( size, v->full_off, 40UL ) );
48 0 : assert( bounds_check_arr( size, v->inc_off, 40UL, v->inc_len ) );
49 0 : }
50 :
51 : static void
52 : check_view_crds_value( uchar const * data,
53 : ulong size,
54 0 : fd_gossip_view_crds_value_t const * v ) {
55 0 : (void)data;
56 0 : assert( bounds_check( size, v->pubkey_off, sizeof(fd_pubkey_t) ) );
57 0 : assert( bounds_check_arr( size, v->value_off, 1UL, v->length ) );
58 0 : switch( v->tag ) {
59 0 : case FD_GOSSIP_VALUE_LEGACY_CONTACT_INFO:
60 0 : break;
61 0 : case FD_GOSSIP_VALUE_VOTE:
62 0 : assert( bounds_check_arr( size, v->vote->txn_off, 1UL, v->vote->txn_sz ) );
63 0 : break;
64 0 : case FD_GOSSIP_VALUE_LOWEST_SLOT:
65 0 : break;
66 0 : case FD_GOSSIP_VALUE_LEGACY_SNAPSHOT_HASHES:
67 0 : break;
68 0 : case FD_GOSSIP_VALUE_ACCOUNT_HASHES:
69 0 : break;
70 0 : case FD_GOSSIP_VALUE_EPOCH_SLOTS:
71 0 : break;
72 0 : case FD_GOSSIP_VALUE_LEGACY_VERSION:
73 0 : break;
74 0 : case FD_GOSSIP_VALUE_VERSION:
75 0 : break;
76 0 : case FD_GOSSIP_VALUE_NODE_INSTANCE:
77 0 : break;
78 0 : case FD_GOSSIP_VALUE_DUPLICATE_SHRED:
79 0 : assert( bounds_check_arr( size, v->duplicate_shred->chunk_off, 1UL, v->duplicate_shred->chunk_len ) );
80 0 : break;
81 0 : case FD_GOSSIP_VALUE_INC_SNAPSHOT_HASHES:
82 0 : check_view_snapshot_hashes( size, v->snapshot_hashes );
83 0 : break;
84 0 : case FD_GOSSIP_VALUE_CONTACT_INFO:
85 0 : break;
86 0 : case FD_GOSSIP_VALUE_RESTART_LAST_VOTED_FORK_SLOTS:
87 0 : break;
88 0 : case FD_GOSSIP_VALUE_RESTART_HEAVIEST_FORK:
89 0 : break;
90 0 : default:
91 0 : FD_LOG_CRIT(( "invalid CRDS value tag %u", v->tag ));
92 0 : }
93 0 : }
94 :
95 : int
96 : LLVMFuzzerTestOneInput( uchar const * data,
97 : ulong size ) {
98 : if( FD_UNLIKELY( size>1232UL ) ) return 0;
99 :
100 : fd_gossip_view_t view[1];
101 : if( !fd_gossip_msg_parse( view, data, size ) ) return 0;
102 : switch( view->tag ) {
103 : case FD_GOSSIP_MESSAGE_PULL_REQUEST:
104 : assert( bounds_check_arr( size, view->pull_request->bloom_keys_offset, sizeof(ulong), view->pull_request->bloom_keys_len ) );
105 : assert( bounds_check_arr( size, view->pull_request->bloom_bits_offset, sizeof(uchar), fd_ulong_align_up( view->pull_request->bloom_bits_cnt, 8UL )/8UL ) );
106 : break;
107 : case FD_GOSSIP_MESSAGE_PULL_RESPONSE:
108 : assert( bounds_check( size, view->pull_response->from_off, sizeof(fd_pubkey_t) ) );
109 : for( ulong i=0UL; i<(view->pull_response->crds_values_len); i++ ) {
110 : check_view_crds_value( data, size, &view->pull_response->crds_values[i] );
111 : }
112 : break;
113 : case FD_GOSSIP_MESSAGE_PUSH:
114 : assert( bounds_check( size, view->push->from_off, sizeof(fd_pubkey_t) ) );
115 : for( ulong i=0UL; i<(view->push->crds_values_len); i++ ) {
116 : check_view_crds_value( data, size, &view->push->crds_values[i] );
117 : }
118 : break;
119 : case FD_GOSSIP_MESSAGE_PRUNE:
120 : assert( bounds_check( size, view->prune->pubkey_off, sizeof(fd_pubkey_t) ) );
121 : assert( bounds_check_arr( size, view->prune->origins_off, sizeof(fd_pubkey_t), view->prune->origins_len ) );
122 : assert( bounds_check( size, view->prune->destination_off, sizeof(fd_pubkey_t) ) );
123 : assert( bounds_check( size, view->prune->signature_off, 64UL ) );
124 : break;
125 : case FD_GOSSIP_MESSAGE_PING:
126 : assert( bounds_check( size, view->ping_pong_off, sizeof(fd_gossip_view_ping_t) ) );
127 : break;
128 : case FD_GOSSIP_MESSAGE_PONG:
129 : assert( bounds_check( size, view->ping_pong_off, sizeof(fd_gossip_view_pong_t) ) );
130 : break;
131 : default:
132 : FD_LOG_CRIT(( "invalid gossip msg tag %u", view->tag ));
133 : }
134 :
135 : return 0;
136 : }
|