There's an infinite loop in Cmd_FollowCycle_f (g_cmds.c) that can easily be used to attack an unpatched server.
To reproduce the infinite loop:
- Join a server (Preferrably FFA?) where there are no in-game players (Spectators are fine)
- /team follow1
- Click to cycle through clients
Replace it with this version, also containing
this fix
Code:
void Cmd_FollowCycle_f( gentity_t *ent, int dir ) {
int clientnum;
int original;
qboolean looped = qfalse;
// if they are playing a tournement game, count as a loss
if ( (g_gametype.integer == GT_DUEL || g_gametype.integer == GT_POWERDUEL)
&& ent->client->sess.sessionTeam == TEAM_FREE ) {\
//WTF???
ent->client->sess.losses++;
}
// first set them to spectator
if ( ent->client->sess.spectatorState == SPECTATOR_NOT ) {
SetTeam( ent, "spectator" );
}
if ( dir != 1 && dir != -1 ) {
G_Error( "Cmd_FollowCycle_f: bad dir %i", dir );
}
clientnum = ent->client->sess.spectatorClient;
original = clientnum;
do {
clientnum += dir;
if ( clientnum >= level.maxclients )
{
//Raz: Avoid /team follow1 crash
if ( looped )
{
clientnum = original;
break;
}
else
{
clientnum = 0;
looped = qtrue;
}
}
if ( clientnum < 0 ) {
if ( looped )
{
clientnum = original;
break;
}
else
{
clientnum = level.maxclients - 1;
looped = qtrue;
}
}
// can only follow connected clients
if ( level.clients[ clientnum ].pers.connected != CON_CONNECTED ) {
continue;
}
// can't follow another spectator
if ( level.clients[ clientnum ].sess.sessionTeam == TEAM_SPECTATOR ) {
continue;
}
//ensiform's fix
// can't follow another spectator
if ( level.clients[ clientnum ].tempSpectate >= level.time ) {
return;
}
// this is good, we can use it
ent->client->sess.spectatorClient = clientnum;
ent->client->sess.spectatorState = SPECTATOR_FOLLOW;
return;
} while ( clientnum != original );
// leave it where it was
}
I'm sure the loop could be written more elegantly, but this will suffice.