mirror of
https://github.com/transmission/transmission.git
synced 2026-05-08 09:39:08 +01:00
harden the bitfield handling to handle corrupt messages from peers. This is in response to Ryoujin's crash report in the forums (http://forum.transmissionbt.com/viewtopic.php?p=20414#20414)
This commit is contained in:
@@ -1311,10 +1311,12 @@ readBtMessage( tr_peermsgs * msgs, struct evbuffer * inbuf, size_t inlen )
|
||||
case BT_HAVE:
|
||||
tr_peerIoReadUint32( msgs->io, inbuf, &ui32 );
|
||||
dbgmsg( msgs, "got Have: %u", ui32 );
|
||||
tr_bitfieldAdd( msgs->info->have, ui32 );
|
||||
if( tr_bitfieldAdd( msgs->info->have, ui32 ) )
|
||||
fireError( msgs, TR_ERROR_PEER_MESSAGE );
|
||||
/* If this is a fast-allowed piece for this peer, mark it as normal now */
|
||||
if( msgs->clientAllowedPieces != NULL && tr_bitfieldHas( msgs->clientAllowedPieces, ui32 ) )
|
||||
tr_bitfieldRem( msgs->clientAllowedPieces, ui32 );
|
||||
if( tr_bitfieldRem( msgs->clientAllowedPieces, ui32 ) )
|
||||
fireError( msgs, TR_ERROR_PEER_MESSAGE );
|
||||
updatePeerProgress( msgs );
|
||||
tr_rcTransferred( msgs->torrent->swarmspeed, msgs->torrent->info.pieceSize );
|
||||
break;
|
||||
@@ -1365,7 +1367,8 @@ readBtMessage( tr_peermsgs * msgs, struct evbuffer * inbuf, size_t inlen )
|
||||
dbgmsg( msgs, "Got a BT_SUGGEST" );
|
||||
tr_peerIoReadUint32( msgs->io, inbuf, &ui32 );
|
||||
if( tr_cpPieceIsComplete( msgs->torrent->completion, ui32 ) )
|
||||
tr_bitfieldAdd( msgs->clientSuggestedPieces, ui32 );
|
||||
if( tr_bitfieldAdd( msgs->clientSuggestedPieces, ui32 ) )
|
||||
fireError( msgs, TR_ERROR_PEER_MESSAGE );
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1397,7 +1400,8 @@ readBtMessage( tr_peermsgs * msgs, struct evbuffer * inbuf, size_t inlen )
|
||||
case BT_ALLOWED_FAST: {
|
||||
dbgmsg( msgs, "Got a BT_ALLOWED_FAST" );
|
||||
tr_peerIoReadUint32( msgs->io, inbuf, &ui32 );
|
||||
tr_bitfieldAdd( msgs->clientAllowedPieces, ui32 );
|
||||
if( tr_bitfieldAdd( msgs->clientAllowedPieces, ui32 ) )
|
||||
fireError( msgs, TR_ERROR_PEER_MESSAGE );
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -716,7 +716,10 @@ typedef enum tr_errno
|
||||
|
||||
/* tracker errors */
|
||||
TR_ERROR_TC_ERROR = -300,
|
||||
TR_ERROR_TC_WARNING
|
||||
TR_ERROR_TC_WARNING,
|
||||
|
||||
/* peer errors */
|
||||
TR_ERROR_PEER_MESSAGE = -400
|
||||
}
|
||||
tr_errno;
|
||||
|
||||
|
||||
+43
-12
@@ -541,6 +541,14 @@ tr_errorString( int code )
|
||||
case TR_ERROR_IO_OTHER:
|
||||
return "Generic I/O error";
|
||||
|
||||
case TR_ERROR_TC_ERROR:
|
||||
return "Tracker error";
|
||||
case TR_ERROR_TC_WARNING:
|
||||
return "Tracker warning";
|
||||
|
||||
case TR_ERROR_PEER_MESSAGE:
|
||||
return "Peer sent a bad message";
|
||||
|
||||
default:
|
||||
return "Unknown error";
|
||||
}
|
||||
@@ -673,49 +681,72 @@ int
|
||||
tr_bitfieldHas( const tr_bitfield * bitfield, size_t nth )
|
||||
{
|
||||
static const uint8_t ands[8] = { 128, 64, 32, 16, 8, 4, 2, 1 };
|
||||
return bitfield!=NULL && (bitfield->bits[nth>>3u] & ands[nth&7u] );
|
||||
const size_t i = nth >> 3u;
|
||||
return ( bitfield != NULL )
|
||||
&& ( bitfield->bits != NULL )
|
||||
&& ( i < bitfield->len )
|
||||
&& ( ( bitfield->bits[i] & ands[nth&7u] ) != 0 );
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
tr_bitfieldAdd( tr_bitfield * bitfield, size_t nth )
|
||||
{
|
||||
static const uint8_t ands[8] = { 128, 64, 32, 16, 8, 4, 2, 1 };
|
||||
bitfield->bits[nth>>3u] |= ands[nth&7u];
|
||||
const size_t i = nth >> 3u;
|
||||
|
||||
assert( bitfield != NULL );
|
||||
assert( bitfield->bits != NULL );
|
||||
|
||||
if( i >= bitfield->len )
|
||||
return -1;
|
||||
|
||||
bitfield->bits[i] |= ands[nth&7u];
|
||||
assert( tr_bitfieldHas( bitfield, nth ) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
tr_bitfieldAddRange( tr_bitfield * bitfield,
|
||||
size_t begin,
|
||||
size_t end )
|
||||
{
|
||||
/* TODO: there are faster ways to do this */
|
||||
int err = 0;
|
||||
size_t i;
|
||||
for( i=begin; i<end; ++i )
|
||||
tr_bitfieldAdd( bitfield, i );
|
||||
if(( err = tr_bitfieldAdd( bitfield, i )))
|
||||
break;
|
||||
return err;
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
tr_bitfieldRem( tr_bitfield * bitfield,
|
||||
size_t nth )
|
||||
{
|
||||
static const uint8_t rems[8] = { 127, 191, 223, 239, 247, 251, 253, 254 };
|
||||
const size_t i = nth >> 3u;
|
||||
|
||||
if( bitfield != NULL )
|
||||
bitfield->bits[nth>>3u] &= rems[nth&7u];
|
||||
assert( bitfield != NULL );
|
||||
assert( bitfield->bits != NULL );
|
||||
|
||||
if( i >= bitfield->len )
|
||||
return -1;
|
||||
|
||||
bitfield->bits[i] &= rems[nth&7u];
|
||||
assert( !tr_bitfieldHas( bitfield, nth ) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
tr_bitfieldRemRange ( tr_bitfield * b,
|
||||
size_t begin,
|
||||
size_t end )
|
||||
{
|
||||
/* TODO: there are faster ways to do this */
|
||||
int err = 0;
|
||||
size_t i;
|
||||
for( i=begin; i<end; ++i )
|
||||
tr_bitfieldRem( b, i );
|
||||
if(( err = tr_bitfieldRem( b, i )))
|
||||
break;
|
||||
return err;
|
||||
}
|
||||
|
||||
tr_bitfield*
|
||||
|
||||
@@ -158,10 +158,10 @@ tr_bitfield* tr_bitfieldDup( const tr_bitfield* );
|
||||
void tr_bitfieldFree( tr_bitfield*);
|
||||
|
||||
void tr_bitfieldClear( tr_bitfield* );
|
||||
void tr_bitfieldAdd( tr_bitfield*, size_t bit );
|
||||
void tr_bitfieldRem( tr_bitfield*, size_t bit );
|
||||
void tr_bitfieldAddRange( tr_bitfield *, size_t begin, size_t end );
|
||||
void tr_bitfieldRemRange ( tr_bitfield*, size_t begin, size_t end );
|
||||
int tr_bitfieldAdd( tr_bitfield*, size_t bit );
|
||||
int tr_bitfieldRem( tr_bitfield*, size_t bit );
|
||||
int tr_bitfieldAddRange( tr_bitfield *, size_t begin, size_t end );
|
||||
int tr_bitfieldRemRange ( tr_bitfield*, size_t begin, size_t end );
|
||||
|
||||
int tr_bitfieldHas( const tr_bitfield*, size_t bit );
|
||||
int tr_bitfieldIsEmpty( const tr_bitfield* );
|
||||
|
||||
Reference in New Issue
Block a user