don't crash in makemeta when trying to build a torrent from files you don't have read access to. (wereHamster)

This commit is contained in:
Charles Kerr 2008-03-02 19:42:45 +00:00
parent fb81f0adf5
commit d712545433
4 changed files with 88 additions and 17 deletions

View File

@ -95,15 +95,24 @@ tr_bencParseInt( const uint8_t * buf,
begin = buf + 1;
end = memchr( begin, 'e', (bufend-buf)-1 );
if( end == NULL )
if( end == NULL ) {
fprintf( stderr, "%s:%d\n", __FILE__, __LINE__ );
return TR_ERROR;
}
errno = 0;
val = strtoll( begin, &endptr, 10 );
if( errno || ( endptr != end ) ) /* incomplete parse */
if( errno || ( endptr != end ) ) { /* incomplete parse */
fprintf( stderr, "Unable to parse int [%*.*s]\n", (int)(end-begin), (int)(end-begin), (const char*)begin );
if( errno )
fprintf( stderr, "errno is %d (%s)\n", errno, strerror(errno) );
fprintf( stderr, "%s:%d\n", __FILE__, __LINE__ );
err = TR_ERROR;
else if( val && *(const char*)begin=='0' ) /* no leading zeroes! */
}
else if( val && *(const char*)begin=='0' ) { /* no leading zeroes! */
fprintf( stderr, "%s:%d\n", __FILE__, __LINE__ );
err = TR_ERROR;
}
else {
*setme_end = end + 1;
*setme_val = val;
@ -137,16 +146,22 @@ tr_bencParseStr( const uint8_t * buf,
return TR_ERROR;
end = memchr( buf, ':', bufend-buf );
if( end == NULL )
if( end == NULL ) {
fprintf( stderr, "%s:%d\n", __FILE__, __LINE__ );
return TR_ERROR;
}
errno = 0;
len = strtoul( (const char*)buf, &endptr, 10 );
if( errno || endptr!=end )
if( errno || endptr!=end ) {
fprintf( stderr, "%s:%d\n", __FILE__, __LINE__ );
return TR_ERROR;
}
if( (const uint8_t*)end + 1 + len > bufend )
if( (const uint8_t*)end + 1 + len > bufend ) {
fprintf( stderr, "%s:%d\n", __FILE__, __LINE__ );
return TR_ERROR;
}
*setme_end = end + 1 + len;
*setme_str = (uint8_t*) tr_strndup( end + 1, len );
@ -317,14 +332,16 @@ tr_bencParse( const void * buf_in,
int
tr_bencLoad( const void * buf_in,
int buflen,
tr_benc * setme_benc,
tr_benc * setme_benc,
char ** setme_end )
{
const uint8_t * buf = buf_in;
const uint8_t * end;
const int ret = tr_bencParse( buf, buf+buflen, setme_benc, &end );
fprintf( stderr, "tried to parse len %d\n", buflen );
if( !ret && setme_end )
*setme_end = (char*) end;
fprintf( stderr, "tr_bencLoad returning %d\n", ret );
return ret;
}

View File

@ -204,6 +204,12 @@ getHashInfo ( tr_metainfo_builder * b )
b->pieceIndex = 0;
totalRemain = b->totalSize;
fp = fopen( b->files[fileIndex].filename, "rb" );
if( !fp ) {
tr_err( "Unable to open \"%s\": %s", b->files[fileIndex].filename, tr_strerror( errno ) );
tr_free( ret );
b->failed = 1;
return NULL;
}
while ( totalRemain )
{
uint8_t *bufptr = buf;
@ -227,6 +233,12 @@ getHashInfo ( tr_metainfo_builder * b )
fp = NULL;
if( ++fileIndex < b->fileCount ) {
fp = fopen( b->files[fileIndex].filename, "rb" );
if( !fp ) {
tr_err( "Unable to open \"%s\": %s", b->files[fileIndex].filename, tr_strerror( errno ) );
tr_free( ret );
b->failed = 1;
return NULL;
}
}
}
}
@ -345,9 +357,10 @@ makeInfoDict ( tr_benc * dict,
val = tr_bencDictAdd( dict, "piece length" );
tr_bencInitInt( val, builder->pieceSize );
pch = getHashInfo( builder );
val = tr_bencDictAdd( dict, "pieces" );
tr_bencInitStr( val, pch, SHA_DIGEST_LENGTH * builder->pieceCount, 0 );
if( ( pch = getHashInfo( builder ) ) ) {
val = tr_bencDictAdd( dict, "pieces" );
tr_bencInitStr( val, pch, SHA_DIGEST_LENGTH * builder->pieceCount, 0 );
}
val = tr_bencDictAdd( dict, "private" );
tr_bencInitInt( val, builder->isPrivate ? 1 : 0 );
@ -385,7 +398,7 @@ static void tr_realMakeMetaInfo ( tr_metainfo_builder * builder )
makeInfoDict( val, builder );
/* save the file */
if ( !builder->abortFlag ) {
if ( !builder->failed && !builder->abortFlag ) {
size_t nmemb;
char * pch = tr_bencSave( &top, &n );
FILE * fp = fopen( builder->outputFile, "wb+" );

View File

@ -54,8 +54,9 @@ tr_httpParseUrl( const char * url_in, int len,
int success;
success = parseURL( url, host, &port, &path );
if( success ) {
if( !success )
tr_err( "Can't parse URL \"%s\"", url );
else {
*setme_host = tr_strdup( host );
*setme_port = port;
*setme_path = tr_strdup( path );
@ -176,6 +177,7 @@ tr_metainfoParse( tr_info * inf, const tr_benc * meta_in, const char * tag )
tr_benc * meta = (tr_benc *) meta_in;
char buf[4096];
fprintf( stderr, "%s:%d\n", __FILE__, __LINE__ );
/* info_hash: urlencoded 20-byte SHA1 hash of the value of the info key
* from the Metainfo file. Note that the value will be a bencoded
* dictionary, given the definition of the info key above. */
@ -185,70 +187,89 @@ tr_metainfoParse( tr_info * inf, const tr_benc * meta_in, const char * tag )
char * str = tr_bencSave( beInfo, &len );
tr_sha1( inf->hash, str, len, NULL );
tr_free( str );
fprintf( stderr, "%s:%d\n", __FILE__, __LINE__ );
}
else
{
tr_err( "info dictionary not found!" );
fprintf( stderr, "%s:%d\n", __FILE__, __LINE__ );
return TR_EINVALID;
}
fprintf( stderr, "%s:%d\n", __FILE__, __LINE__ );
tr_sha1_to_hex( inf->hashString, inf->hash );
savedname( inf->torrent, sizeof( inf->torrent ), inf->hashString, tag );
fprintf( stderr, "%s:%d\n", __FILE__, __LINE__ );
/* comment */
memset( buf, '\0', sizeof( buf ) );
val = tr_bencDictFindFirst( meta, "comment.utf-8", "comment", NULL );
if( val && val->type == TYPE_STR )
strlcat_utf8( buf, val->val.s.s, sizeof( buf ), 0 );
fprintf( stderr, "%s:%d\n", __FILE__, __LINE__ );
tr_free( inf->comment );
inf->comment = tr_strdup( buf );
fprintf( stderr, "%s:%d\n", __FILE__, __LINE__ );
/* creator */
memset( buf, '\0', sizeof( buf ) );
val = tr_bencDictFindFirst( meta, "created by.utf-8", "created by", NULL );
if( val && val->type == TYPE_STR )
strlcat_utf8( buf, val->val.s.s, sizeof( buf ), 0 );
fprintf( stderr, "%s:%d\n", __FILE__, __LINE__ );
tr_free( inf->creator );
inf->creator = tr_strdup( buf );
/* Date created */
inf->dateCreated = 0;
val = tr_bencDictFind( meta, "creation date" );
fprintf( stderr, "%s:%d\n", __FILE__, __LINE__ );
if( NULL != val && TYPE_INT == val->type )
{
fprintf( stderr, "%s:%d\n", __FILE__, __LINE__ );
inf->dateCreated = val->val.i;
}
/* Private torrent */
val = tr_bencDictFind( beInfo, "private" );
val2 = tr_bencDictFind( meta, "private" );
fprintf( stderr, "%s:%d\n", __FILE__, __LINE__ );
if( ( NULL != val && ( TYPE_INT != val->type || 0 != val->val.i ) ) ||
( NULL != val2 && ( TYPE_INT != val2->type || 0 != val2->val.i ) ) )
{
fprintf( stderr, "%s:%d\n", __FILE__, __LINE__ );
inf->isPrivate = 1;
}
/* Piece length */
val = tr_bencDictFind( beInfo, "piece length" );
fprintf( stderr, "%s:%d\n", __FILE__, __LINE__ );
if( NULL == val || TYPE_INT != val->type )
{
fprintf( stderr, "%s:%d\n", __FILE__, __LINE__ );
tr_err( "%s \"piece length\" entry", ( val ? "Invalid" : "Missing" ) );
goto fail;
}
fprintf( stderr, "%s:%d\n", __FILE__, __LINE__ );
inf->pieceSize = val->val.i;
/* Hashes */
val = tr_bencDictFind( beInfo, "pieces" );
fprintf( stderr, "%s:%d\n", __FILE__, __LINE__ );
if( NULL == val || TYPE_STR != val->type )
{
fprintf( stderr, "%s:%d\n", __FILE__, __LINE__ );
tr_err( "%s \"pieces\" entry", ( val ? "Invalid" : "Missing" ) );
goto fail;
}
fprintf( stderr, "%s:%d\n", __FILE__, __LINE__ );
if( val->val.s.i % SHA_DIGEST_LENGTH )
{
fprintf( stderr, "%s:%d\n", __FILE__, __LINE__ );
tr_err( "Invalid \"piece\" string (size is %d)", val->val.s.i );
goto fail;
}
fprintf( stderr, "%s:%d\n", __FILE__, __LINE__ );
inf->pieceCount = val->val.s.i / SHA_DIGEST_LENGTH;
inf->pieces = calloc ( inf->pieceCount, sizeof(tr_piece) );
@ -260,43 +281,56 @@ tr_metainfoParse( tr_info * inf, const tr_benc * meta_in, const char * tag )
/* get file or top directory name */
val = tr_bencDictFindFirst( beInfo, "name.utf-8", "name", NULL );
fprintf( stderr, "%s:%d\n", __FILE__, __LINE__ );
if( parseFiles( inf, tr_bencDictFindFirst( beInfo,
"name.utf-8", "name", NULL ),
tr_bencDictFind( beInfo, "files" ),
tr_bencDictFind( beInfo, "length" ) ) )
{
fprintf( stderr, "%s:%d\n", __FILE__, __LINE__ );
goto fail;
}
fprintf( stderr, "%s:%d\n", __FILE__, __LINE__ );
if( !inf->fileCount )
{
fprintf( stderr, "%s:%d\n", __FILE__, __LINE__ );
tr_err( "Torrent has no files." );
goto fail;
}
fprintf( stderr, "%s:%d\n", __FILE__, __LINE__ );
if( !inf->totalSize )
{
fprintf( stderr, "%s:%d\n", __FILE__, __LINE__ );
tr_err( "Torrent is zero bytes long." );
goto fail;
}
fprintf( stderr, "%s:%d\n", __FILE__, __LINE__ );
/* TODO add more tests so we don't crash on weird files */
fprintf( stderr, "%s:%d\n", __FILE__, __LINE__ );
if( (uint64_t) inf->pieceCount !=
( inf->totalSize + inf->pieceSize - 1 ) / inf->pieceSize )
{
fprintf( stderr, "%s:%d\n", __FILE__, __LINE__ );
tr_err( "Size of hashes and files don't match" );
goto fail;
}
fprintf( stderr, "%s:%d\n", __FILE__, __LINE__ );
/* get announce or announce-list */
if( getannounce( inf, meta ) )
{
fprintf( stderr, "%s:%d\n", __FILE__, __LINE__ );
goto fail;
}
fprintf( stderr, "%s:%d\n", __FILE__, __LINE__ );
return TR_OK;
fprintf( stderr, "%s:%d\n", __FILE__, __LINE__ );
fail:
tr_metainfoFree( inf );
return TR_EINVALID;
@ -499,10 +533,8 @@ static int getannounce( tr_info * inf, tr_benc * meta )
++pch;
if( tr_httpParseUrl( pch, -1, &address, &port, &announce ) )
{
tr_err( "Invalid announce URL (%s)", val->val.s.s );
return TR_EINVALID;
}
sublist = calloc( 1, sizeof( sublist[0] ) );
sublist[0].address = address;
sublist[0].port = port;

View File

@ -418,20 +418,25 @@ tr_torrentParse( const tr_handle * handle,
setmeInfo = &tmp;
memset( setmeInfo, 0, sizeof( tr_info ) );
if( !err && tr_ctorGetMetainfo( ctor, &metainfo ) )
if( !err && tr_ctorGetMetainfo( ctor, &metainfo ) ) {
fprintf( stderr, "%s:%d can't get metainfo\n", __FILE__, __LINE__ );
return TR_EINVALID;
}
err = tr_metainfoParse( setmeInfo, metainfo, handle->tag );
fprintf( stderr, "%s:%d err %d\n", __FILE__, __LINE__, err );
doFree = !err && ( setmeInfo == &tmp );
if( !err && hashExists( handle, setmeInfo->hash ) ) {
err = TR_EDUPLICATE;
fprintf( stderr, "%s:%d err %d\n", __FILE__, __LINE__, err );
doFree = 1;
}
if( doFree )
tr_metainfoFree( setmeInfo );
fprintf( stderr, "%s:%d err %d\n", __FILE__, __LINE__, err );
return err;
}
@ -445,14 +450,18 @@ tr_torrentNew( tr_handle * handle,
tr_torrent * tor = NULL;
err = tr_torrentParse( handle, ctor, &tmpInfo );
fprintf( stderr, "%s:%d, err %d\n", __FILE__, __LINE__, err );
if( !err ) {
tor = tr_new0( tr_torrent, 1 );
tor->info = tmpInfo;
torrentRealInit( handle, tor, ctor );
fprintf( stderr, "%s:%d, tor %p\n", __FILE__, __LINE__, tor );
} else if( setmeError ) {
fprintf( stderr, "err is %d\n", err );
*setmeError = err;
}
fprintf( stderr, "returning torrent %p\n", tor );
return tor;
}