source: trunk/libtransmission/bencode-test.c @ 4876

Last change on this file since 4876 was 4876, checked in by charles, 14 years ago

#667: remote crash exploit in bencode parser

File size: 6.5 KB
Line 
1#include <stdio.h>
2#include "transmission.h"
3#include "bencode.h"
4#include "utils.h" /* tr_free */
5
6#define VERBOSE 0
7
8int test = 0;
9
10#define check(A) { \
11    ++test; \
12    if (A) { \
13        if( VERBOSE ) \
14            fprintf( stderr, "PASS test #%d (%s, %d)\n", test, __FILE__, __LINE__ ); \
15    } else { \
16        if( VERBOSE ) \
17            fprintf( stderr, "FAIL test #%d (%s, %d)\n", test, __FILE__, __LINE__ ); \
18        return test; \
19    } \
20}
21
22static int
23testInt( void )
24{
25    uint8_t buf[128];
26    int64_t val;
27    int err;
28    const uint8_t * end;
29
30    /* good int string */
31    snprintf( (char*)buf, sizeof( buf ), "i64e" );
32    err = tr_bencParseInt( buf, buf+4, &end, &val );
33    check( err == 0 );
34    check( val == 64 );
35    check( end == buf + 4 );
36
37    /* missing 'e' */
38    end = NULL;
39    val = 888;
40    err = tr_bencParseInt( buf, buf+3, &end, &val );
41    check( err == TR_ERROR ); 
42    check( val == 888 );
43    check( end == NULL );
44
45    /* empty buffer */
46    err = tr_bencParseInt( buf, buf+0, &end, &val );
47    check( err == TR_ERROR ); 
48    check( val == 888 );
49    check( end == NULL );
50
51    /* bad number */
52    snprintf( (char*)buf, sizeof( buf ), "i6z4e" );
53    err = tr_bencParseInt( buf, buf+5, &end, &val );
54    check( err == TR_ERROR );
55    check( val == 888 );
56    check( end == NULL );
57
58    /* negative number */
59    snprintf( (char*)buf, sizeof( buf ), "i-3e" );
60    err = tr_bencParseInt( buf, buf+4, &end, &val );
61    check( err == TR_OK );
62    check( val == -3 );
63    check( end == buf + 4 );
64
65    /* zero */
66    snprintf( (char*)buf, sizeof( buf ), "i0e" );
67    err = tr_bencParseInt( buf, buf+4, &end, &val );
68    check( err == TR_OK );
69    check( val == 0 );
70    check( end == buf + 3 );
71
72    /* no leading zeroes allowed */
73    val = 0;
74    end = NULL;
75    snprintf( (char*)buf, sizeof( buf ), "i04e" );
76    err = tr_bencParseInt( buf, buf+4, &end, &val );
77    check( err == TR_ERROR );
78    check( val == 0 );
79    check( end == NULL );
80
81    return 0;
82}
83
84static int
85testStr( void )
86{
87    uint8_t buf[128];
88    int err;
89    const uint8_t * end;
90    uint8_t * str;
91    size_t len;
92
93    /* good string */
94    snprintf( (char*)buf, sizeof( buf ), "4:boat" );
95    err = tr_bencParseStr( buf, buf+6, &end, &str, &len );
96    check( err == TR_OK );
97    check( !strcmp( (char*)str, "boat" ) );
98    check( len == 4 );
99    check( end == buf + 6 );
100    tr_free( str );
101    str = NULL;
102    end = NULL;
103    len = 0;
104
105    /* string goes past end of buffer */
106    err = tr_bencParseStr( buf, buf+5, &end, &str, &len );
107    check( err == TR_ERROR );
108    check( str == NULL );
109    check( end == NULL );
110    check( !len );
111
112    /* empty string */
113    snprintf( (char*)buf, sizeof( buf ), "0:" );
114    err = tr_bencParseStr( buf, buf+2, &end, &str, &len );
115    check( err == TR_OK );
116    check( !*str );
117    check( !len );
118    check( end == buf + 2 );
119    tr_free( str );
120    str = NULL;
121    end = NULL;
122    len = 0;
123
124    /* short string */
125    snprintf( (char*)buf, sizeof( buf ), "3:boat" );
126    err = tr_bencParseStr( buf, buf+6, &end, &str, &len );
127    check( err == TR_OK );
128    check( !strcmp( (char*)str, "boa" ) );
129    check( len == 3 );
130    check( end == buf + 5 );
131    tr_free( str );
132    str = NULL;
133    end = NULL;
134    len = 0;
135
136    return 0;
137}
138
139static int
140testParse( void )
141{
142    benc_val_t val;
143    benc_val_t * child;
144    benc_val_t * child2;
145    uint8_t buf[512];
146    const uint8_t * end;
147    int err;
148    int len;
149    char * saved;
150
151    snprintf( (char*)buf, sizeof( buf ), "i64e" );
152    err = tr_bencParse( buf, buf + sizeof( buf ), &val, &end );
153    check( !err );
154    check( tr_bencIsInt( &val ) );
155    check( tr_bencGetInt( &val ) == 64 );
156    check( end == buf + 4 );
157    tr_bencFree( &val );
158
159    snprintf( (char*)buf, sizeof( buf ), "li64ei32ei16ee" );
160    err = tr_bencParse( buf, buf + sizeof( buf ), &val, &end );
161    check( !err );
162    check( tr_bencIsList( &val ) );
163    check( end == buf + strlen( (char*)buf ) );
164    check( val.val.l.count == 3 );
165    check( tr_bencGetInt( &val.val.l.vals[0] ) == 64 );
166    check( tr_bencGetInt( &val.val.l.vals[1] ) == 32 );
167    check( tr_bencGetInt( &val.val.l.vals[2] ) == 16 );
168    saved = tr_bencSave( &val, &len );
169    check( !strcmp( saved, (char*)buf ) );
170    tr_free( saved );
171    tr_bencFree( &val );
172
173    end = NULL;
174    snprintf( (char*)buf, sizeof( buf ), "lllee" );
175    err = tr_bencParse( buf, buf + strlen( (char*)buf ), &val , &end );
176    check( err );
177    check( end == NULL );
178
179    end = NULL;
180    snprintf( (char*)buf, sizeof( buf ), "le" );
181    err = tr_bencParse( buf, buf + sizeof( buf ), &val , &end );
182    check( !err );
183    check( end == buf + 2 );
184    saved = tr_bencSave( &val, &len );
185    check( !strcmp( saved, "le" ) );
186    tr_free( saved );
187    tr_bencFree( &val );
188
189    end = NULL;
190    snprintf( (char*)buf, sizeof( buf ), "llleee" );
191    err = tr_bencParse( buf, buf + sizeof( buf ), &val , &end );
192    check( !err );
193    check( end == buf + 6 );
194    saved = tr_bencSave( &val, &len );
195    check( !strcmp( saved, "llleee" ) );
196    tr_free( saved );
197    tr_bencFree( &val );
198
199    /* nested containers
200     * parse an unsorted dict
201     * save as a sorted dict */
202    end = NULL;
203    snprintf( (char*)buf, sizeof( buf ), "lld1:bi32e1:ai64eeee" );
204    err = tr_bencParse( buf, buf + sizeof( buf ), &val, &end );
205    check( !err );
206    check( end == buf + strlen( (const char*)buf ) );
207    check( tr_bencIsList( &val ) );
208    check(( child = tr_bencListGetNthChild( &val, 0 )));
209    check( tr_bencIsList( child ) );
210    check(( child2 = tr_bencListGetNthChild( child, 0 )));
211    check( tr_bencIsDict( child2 ) );
212    saved = tr_bencSave( &val, &len );
213    check( !strcmp( saved, "lld1:ai64e1:bi32eeee" ) );
214    tr_free( saved );
215    tr_bencFree( &val );
216
217    return 0;
218}
219
220static int
221testStackSmash( void )
222{
223    int i;
224    int len;
225    int depth;
226    int err;
227    uint8_t * in;
228    const uint8_t * end;
229    benc_val_t val;
230    char * saved;
231
232    depth = 1000000;
233    in = tr_new( uint8_t, depth*2 + 1 );
234    for( i=0; i<depth; ++i ) {
235        in[i] = 'l';
236        in[depth+i] = 'e';
237    }
238    in[depth*2] = '\0';
239    err = tr_bencParse( in, in+(depth*2), &val, &end );
240    check( !err );
241    check( tr_bencIsList( &val ) );
242    check( end == in+(depth*2) );
243    saved = tr_bencSave( &val, &len );
244    check( !strcmp( saved, (char*)in ) );
245    tr_free( in );
246    tr_free( saved );
247    tr_bencFree( &val );
248
249    return 0;
250}
251
252
253int
254main( void )
255{
256    int i;
257
258    if(( i = testInt( )))
259        return i;
260
261    if(( i = testStr( )))
262        return i;
263
264    if(( i = testParse( )))
265        return i;
266
267    if(( i = testStackSmash( )))
268        return i;
269
270    return 0;
271}
Note: See TracBrowser for help on using the repository browser.