[tremulous] fix #806980 - fixed CVE-2010-5077
Jan Kaluža
jkaluza at fedoraproject.org
Tue Mar 27 09:14:36 UTC 2012
commit a4f420e0235dcd2bc44b413e3db7f94497643ad9
Author: Jan Kaluza <hanzz.k at gmail.com>
Date: Tue Mar 27 11:08:41 2012 +0200
fix #806980 - fixed CVE-2010-5077
tremulous-getstatus-dos.patch | 275 +++++++++++++++++++++++++++++++++++++++++
tremulous.spec | 7 +-
2 files changed, 281 insertions(+), 1 deletions(-)
---
diff --git a/tremulous-getstatus-dos.patch b/tremulous-getstatus-dos.patch
new file mode 100644
index 0000000..b3ba4d3
--- /dev/null
+++ b/tremulous-getstatus-dos.patch
@@ -0,0 +1,275 @@
+diff --git a/src/server/sv_main.c b/src/server/sv_main.c
+index 75e9dc7..d642c05 100644
+--- a/src/server/sv_main.c
++++ b/src/server/sv_main.c
+@@ -370,6 +370,182 @@ CONNECTIONLESS COMMANDS
+ ==============================================================================
+ */
+
++typedef struct leakyBucket_s leakyBucket_t;
++struct leakyBucket_s {
++ netadrtype_t type;
++
++ union {
++ byte _4[4];
++ byte _6[16];
++ } ipv;
++
++ int lastTime;
++ signed char burst;
++
++ long hash;
++
++ leakyBucket_t *prev, *next;
++};
++
++// This is deliberately quite large to make it more of an effort to DoS
++#define MAX_BUCKETS 16384
++#define MAX_HASHES 1024
++
++static leakyBucket_t buckets[ MAX_BUCKETS ];
++static leakyBucket_t *bucketHashes[ MAX_HASHES ];
++
++/*
++================
++SVC_HashForAddress
++================
++*/
++static long SVC_HashForAddress( netadr_t address ) {
++ byte *ip;
++ size_t size;
++ int i;
++ long hash = 0;
++
++ switch ( address.type ) {
++ case NA_IP: ip = address.ip; size = 4; break;
++ case NA_IP6: ip = address.ip6; size = 16; break;
++ default: break;
++ }
++
++ for ( i = 0; i < size; i++ ) {
++ hash += (long)( ip[ i ] ) * ( i + 119 );
++ }
++
++ hash = ( hash ^ ( hash >> 10 ) ^ ( hash >> 20 ) );
++ hash &= ( MAX_HASHES - 1 );
++
++ return hash;
++}
++
++/*
++================
++SVC_BucketForAddress
++
++Find or allocate a bucket for an address
++================
++*/
++static leakyBucket_t *SVC_BucketForAddress( netadr_t address, int burst, int period ) {
++ leakyBucket_t *bucket = NULL;
++ int i;
++ long hash = SVC_HashForAddress( address );
++ int now = Sys_Milliseconds();
++
++ for ( bucket = bucketHashes[ hash ]; bucket; bucket = bucket->next ) {
++ switch ( bucket->type ) {
++ case NA_IP:
++ if ( memcmp( bucket->ipv._4, address.ip, 4 ) == 0 ) {
++ return bucket;
++ }
++ break;
++
++ case NA_IP6:
++ if ( memcmp( bucket->ipv._6, address.ip6, 16 ) == 0 ) {
++ return bucket;
++ }
++ break;
++
++ default:
++ break;
++ }
++ }
++
++ for ( i = 0; i < MAX_BUCKETS; i++ ) {
++ int interval;
++
++ bucket = &buckets[ i ];
++ interval = now - bucket->lastTime;
++
++ // Reclaim expired buckets
++ if ( bucket->lastTime > 0 && interval > ( burst * period ) ) {
++ if ( bucket->prev != NULL ) {
++ bucket->prev->next = bucket->next;
++ } else {
++ bucketHashes[ bucket->hash ] = bucket->next;
++ }
++
++ if ( bucket->next != NULL ) {
++ bucket->next->prev = bucket->prev;
++ }
++
++ Com_Memset( bucket, 0, sizeof( leakyBucket_t ) );
++ }
++
++ if ( bucket->type == NA_BAD ) {
++ bucket->type = address.type;
++ switch ( address.type ) {
++ case NA_IP: Com_Memcpy( bucket->ipv._4, address.ip, 4 ); break;
++ case NA_IP6: Com_Memcpy( bucket->ipv._6, address.ip6, 16 ); break;
++ default: break;
++ }
++
++ bucket->lastTime = now;
++ bucket->burst = 0;
++ bucket->hash = hash;
++
++ // Add to the head of the relevant hash chain
++ bucket->next = bucketHashes[ hash ];
++ if ( bucketHashes[ hash ] != NULL ) {
++ bucketHashes[ hash ]->prev = bucket;
++ }
++
++ bucket->prev = NULL;
++ bucketHashes[ hash ] = bucket;
++
++ return bucket;
++ }
++ }
++
++ // Couldn't allocate a bucket for this address
++ return NULL;
++}
++
++/*
++================
++SVC_RateLimit
++================
++*/
++static qboolean SVC_RateLimit( leakyBucket_t *bucket, int burst, int period ) {
++ if ( bucket != NULL ) {
++ int now = Sys_Milliseconds();
++ int interval = now - bucket->lastTime;
++ int expired = interval / period;
++ int expiredRemainder = interval % period;
++
++ if ( expired > bucket->burst ) {
++ bucket->burst = 0;
++ bucket->lastTime = now;
++ } else {
++ bucket->burst -= expired;
++ bucket->lastTime = now - expiredRemainder;
++ }
++
++ if ( bucket->burst < burst ) {
++ bucket->burst++;
++
++ return qfalse;
++ }
++ }
++
++ return qtrue;
++}
++
++/*
++================
++SVC_RateLimitAddress
++
++Rate limit for a particular address
++================
++*/
++static qboolean SVC_RateLimitAddress( netadr_t from, int burst, int period ) {
++ leakyBucket_t *bucket = SVC_BucketForAddress( from, burst, period );
++
++ return SVC_RateLimit( bucket, burst, period );
++}
++
+ /*
+ ================
+ SVC_Status
+@@ -388,6 +564,21 @@ static void SVC_Status( netadr_t from ) {
+ int statusLength;
+ int playerLength;
+ char infostring[MAX_INFO_STRING];
++ static leakyBucket_t bucket;
++
++ // Prevent using getstatus as an amplifier
++ if ( SVC_RateLimitAddress( from, 10, 1000 ) ) {
++ Com_DPrintf( "SVC_Status: rate limit from %s exceeded, dropping request\n",
++ NET_AdrToString( from ) );
++ return;
++ }
++
++ // Allow getstatus to be DoSed relatively easily, but prevent
++ // excess outbound bandwidth usage when being flooded inbound
++ if ( SVC_RateLimit( &bucket, 10, 100 ) ) {
++ Com_DPrintf( "SVC_Status: rate limit exceeded, dropping request\n" );
++ return;
++ }
+
+ strcpy( infostring, Cvar_InfoString( CVAR_SERVERINFO ) );
+
+@@ -501,24 +692,30 @@ Redirect all printfs
+ */
+ static void SVC_RemoteCommand( netadr_t from, msg_t *msg ) {
+ qboolean valid;
+- unsigned int time;
+ char remaining[1024];
+ // TTimo - scaled down to accumulate, but not overflow anything network wise, print wise etc.
+ // (OOB messages are the bottleneck here)
+ #define SV_OUTPUTBUF_LENGTH (1024 - 16)
+ char sv_outputbuf[SV_OUTPUTBUF_LENGTH];
+- static unsigned int lasttime = 0;
+ char *cmd_aux;
+
+- // TTimo - https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=534
+- time = Com_Milliseconds();
+- if ( (unsigned)( time - lasttime ) < 500u ) {
++ // Prevent using rcon as an amplifier and make dictionary attacks impractical
++ if ( SVC_RateLimitAddress( from, 10, 1000 ) ) {
++ Com_DPrintf( "SVC_Status: rate limit from %s exceeded, dropping request\n",
++ NET_AdrToString( from ) );
+ return;
+ }
+- lasttime = time;
+
+ if ( !strlen( sv_rconPassword->string ) ||
+ strcmp (Cmd_Argv(1), sv_rconPassword->string) ) {
++ static leakyBucket_t bucket;
++
++ // Make DoS via rcon impractical
++ if ( SVC_RateLimit( &bucket, 10, 1000 ) ) {
++ Com_DPrintf( "SVC_Status: rate limit exceeded, dropping request\n" );
++ return;
++ }
++
+ valid = qfalse;
+ Com_Printf ("Bad rcon from %s: %s\n", NET_AdrToString (from), Cmd_ArgsFrom(2) );
+ } else {
+@@ -587,7 +784,7 @@ static void SV_ConnectionlessPacket( netadr_t from, msg_t *msg ) {
+ Com_DPrintf ("SV packet %s : %s\n", NET_AdrToString(from), c);
+
+ if (!Q_stricmp(c, "getstatus")) {
+- SVC_Status( from );
++ SVC_Status( from );
+ } else if (!Q_stricmp(c, "getinfo")) {
+ SVC_Info( from );
+ } else if (!Q_stricmp(c, "getchallenge")) {
+@@ -601,8 +798,8 @@ static void SV_ConnectionlessPacket( netadr_t from, msg_t *msg ) {
+ // server disconnect messages when their new server sees our final
+ // sequenced messages to the old client
+ } else {
+- Com_DPrintf ("bad connectionless packet from %s:\n%s\n"
+- , NET_AdrToString (from), s);
++ Com_DPrintf ("bad connectionless packet from %s:\n%s\n",
++ NET_AdrToString (from), s);
+ }
+ }
+
+@@ -610,7 +807,7 @@ static void SV_ConnectionlessPacket( netadr_t from, msg_t *msg ) {
+
+ /*
+ =================
+-SV_ReadPackets
++SV_PacketEvent
+ =================
+ */
+ void SV_PacketEvent( netadr_t from, msg_t *msg ) {
diff --git a/tremulous.spec b/tremulous.spec
index f1d237b..3425a24 100644
--- a/tremulous.spec
+++ b/tremulous.spec
@@ -1,6 +1,6 @@
Name: tremulous
Version: 1.2.0
-Release: 0.4.beta1%{?dist}
+Release: 0.5.beta1%{?dist}
Summary: First Person Shooter game based on the Quake 3 engine
Group: Amusements/Games
License: GPLv2+
@@ -13,6 +13,7 @@ Source0: tremulous-1.2.0.beta1.tar.gz
Source1: %{name}.desktop
Source2: %{name}.png
Patch0: tremulous-1.2.0-dll-overwrite.patch
+Patch1: tremulous-getstatus-dos.patch
BuildRequires: desktop-file-utils SDL-devel openal-soft-devel libvorbis-devel
BuildRequires: libjpeg-devel
BuildRequires: libcurl-devel
@@ -44,6 +45,7 @@ removing their ability to respawn by destroying their spawn structures.
%prep
%setup -q -n tremulous-1.2.beta1
%patch0 -p1 -b .dll-overwrite
+%patch1 -p1 -b .getstatus-dos
# Rip out the bundled libraries and use the
# system versions instead
@@ -98,6 +100,9 @@ fi
%{_datadir}/icons/hicolor/48x48/apps/%{name}.png
%changelog
+* Tue Mar 27 2012 Jan Kaluza <jkaluza at redhat.com> - 1.2.0-0.5.beta1
+- fix #806980 - fixed CVE-2010-5077
+
* Thu Feb 23 2012 Jan Kaluza <jkaluza at redhat.com> - 1.2.0-0.4.beta1
- fix #796362 - fixed CVE-2011-2764 and CVE-2011-3012
More information about the scm-commits
mailing list