Changeset 4869


Ignore:
Timestamp:
Jan 30, 2008, 3:39:41 PM (14 years ago)
Author:
charles
Message:

part 1 of the bencode exploit fix:

  • better error checking for int & string parsing
  • add automated unit tests
Location:
trunk/libtransmission
Files:
1 added
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/libtransmission/Makefile.am

    r4543 r4869  
    7474
    7575noinst_PROGRAMS = \
     76    bencode-test \
    7677    test-fastset \
    7778    test-peer-id
     
    8687    $(OPENSSL_LIBS) $(PTHREAD_LIBS) -lm
    8788
     89bencode_test_SOURCES = bencode-test.c
     90bencode_test_LDADD = $(TEST_LDADD)
    8891test_fastset_SOURCES = test-fastset.c
    8992test_fastset_LDADD = $(TEST_LDADD)
  • trunk/libtransmission/bencode.c

    r4404 r4869  
    2525#include <assert.h>
    2626#include <ctype.h> /* isdigit, isprint */
     27#include <errno.h>
    2728#include <stdarg.h>
    2829#include <stdio.h>
     
    5758***
    5859**/
     60
     61/**
     62 * The initial i and trailing e are beginning and ending delimiters.
     63 * You can have negative numbers such as i-3e. You cannot prefix the
     64 * number with a zero such as i04e. However, i0e is valid. 
     65 * Example: i3e represents the integer "3"
     66 * NOTE: The maximum number of bit of this integer is unspecified,
     67 * but to handle it as a signed 64bit integer is mandatory to handle
     68 * "large files" aka .torrent for more that 4Gbyte
     69 */
     70int
     71tr_bencParseInt( const uint8_t  * buf,
     72                 size_t           buflen,
     73                 const uint8_t ** setme_end,
     74                 int64_t        * setme_val )
     75{
     76    int err = TR_OK;
     77    char * endptr;
     78    const void * begin;
     79    const void * end;
     80    int64_t val;
     81
     82    if( !buflen )
     83        return TR_ERROR;
     84    if( *buf != 'i' )
     85        return TR_ERROR;
     86
     87    begin = buf + 1;
     88    end = memchr( begin, 'e', buflen-1 );
     89    if( end == NULL )
     90        return TR_ERROR;
     91
     92    errno = 0;
     93    val = strtoll( begin, &endptr, 10 );
     94    if( errno || ( endptr != end ) ) /* incomplete parse */
     95        err = TR_ERROR;
     96    else if( val && *(const char*)begin=='0' ) /* the spec forbids leading zeroes */
     97        err = TR_ERROR;
     98    else {
     99        *setme_end = end + 1;
     100        *setme_val = val;
     101    }
     102
     103    return err;
     104}
     105
     106
     107/**
     108 * Byte strings are encoded as follows:
     109 * <string length encoded in base ten ASCII>:<string data>
     110 * Note that there is no constant beginning delimiter, and no ending delimiter.
     111 * Example: 4:spam represents the string "spam"
     112 */
     113int
     114tr_bencParseStr( const uint8_t  * buf,
     115                 size_t           buflen,
     116                 const uint8_t ** setme_end,
     117                 uint8_t       ** setme_str,
     118                 size_t         * setme_strlen )
     119{
     120    size_t len;
     121    const void * end;
     122    char * endptr;
     123
     124    if( !buflen )
     125        return TR_ERROR;
     126
     127    if( !isdigit( *buf  ) )
     128        return TR_ERROR;
     129
     130    end = memchr( buf, ':', buflen );
     131    if( end == NULL )
     132        return TR_ERROR;
     133
     134    errno = 0;
     135    len = strtoul( (const char*)buf, &endptr, 10 );
     136    if( errno || endptr!=end )
     137        return TR_ERROR;
     138
     139    if( ( (const uint8_t*)end - buf ) + 1 + len > buflen )
     140        return TR_ERROR;
     141
     142    *setme_end = end + 1 + len;
     143    *setme_str = (uint8_t*) tr_strndup( end + 1, len );
     144    *setme_strlen = len;
     145    return TR_OK;
     146}
    59147
    60148/* setting to 1 to help expose bugs with tr_bencListAdd and tr_bencDictAdd */
  • trunk/libtransmission/bencode.h

    r4404 r4869  
    5454} benc_val_t;
    5555
     56
    5657#define tr_bencLoad(b,l,v,e) _tr_bencLoad((char*)(b),(l),(v),(char**)(e))
    5758int          _tr_bencLoad( char * buf, int len, benc_val_t * val,
     
    9091int64_t  tr_bencGetInt ( const benc_val_t * val );
    9192
     93
     94/**
     95***  Treat these as private -- they're only made public here
     96***  so that the unit tests can find them
     97**/
     98
     99int  tr_bencParseInt( const uint8_t  * buf,
     100                      size_t           buflen,
     101                      const uint8_t ** setme_end,
     102                      int64_t        * setme_val );
     103
     104int  tr_bencParseStr( const uint8_t  * buf,
     105                      size_t           buflen,
     106                      const uint8_t ** setme_end,
     107                      uint8_t       ** setme_str,
     108                      size_t         * setme_strlen );
     109
     110
     111
    92112#endif
Note: See TracChangeset for help on using the changeset viewer.