mirror of
https://github.com/ioquake/ioq3.git
synced 2025-02-22 11:31:26 +00:00
security fix: prevent command injection via callvote
This commit is contained in:
parent
cde5fcfb9b
commit
f5aae78481
4 changed files with 29 additions and 3 deletions
|
@ -1213,6 +1213,7 @@ Cmd_CallVote_f
|
||||||
==================
|
==================
|
||||||
*/
|
*/
|
||||||
void Cmd_CallVote_f( gentity_t *ent ) {
|
void Cmd_CallVote_f( gentity_t *ent ) {
|
||||||
|
char* c;
|
||||||
int i;
|
int i;
|
||||||
char arg1[MAX_STRING_TOKENS];
|
char arg1[MAX_STRING_TOKENS];
|
||||||
char arg2[MAX_STRING_TOKENS];
|
char arg2[MAX_STRING_TOKENS];
|
||||||
|
@ -1239,9 +1240,16 @@ void Cmd_CallVote_f( gentity_t *ent ) {
|
||||||
trap_Argv( 1, arg1, sizeof( arg1 ) );
|
trap_Argv( 1, arg1, sizeof( arg1 ) );
|
||||||
trap_Argv( 2, arg2, sizeof( arg2 ) );
|
trap_Argv( 2, arg2, sizeof( arg2 ) );
|
||||||
|
|
||||||
if( strchr( arg1, ';' ) || strchr( arg2, ';' ) ) {
|
// check for command separators in arg2
|
||||||
trap_SendServerCommand( ent-g_entities, "print \"Invalid vote string.\n\"" );
|
for( c = arg2; *c; ++c) {
|
||||||
return;
|
switch(*c) {
|
||||||
|
case '\n':
|
||||||
|
case '\r':
|
||||||
|
case ';':
|
||||||
|
trap_SendServerCommand( ent-g_entities, "print \"Invalid vote string.\n\"" );
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !Q_stricmp( arg1, "map_restart" ) ) {
|
if ( !Q_stricmp( arg1, "map_restart" ) ) {
|
||||||
|
|
|
@ -433,6 +433,22 @@ char *Cmd_Cmd(void)
|
||||||
return cmd_cmd;
|
return cmd_cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Replace command separators with space to prevent interpretation
|
||||||
|
This is a hack to protect buggy qvms
|
||||||
|
https://bugzilla.icculus.org/show_bug.cgi?id=3593
|
||||||
|
*/
|
||||||
|
void Cmd_Args_Sanitize( void ) {
|
||||||
|
int i;
|
||||||
|
for ( i = 1 ; i < cmd_argc ; i++ ) {
|
||||||
|
char* c = cmd_argv[i];
|
||||||
|
while ((c = strpbrk(c, "\n\r;"))) {
|
||||||
|
*c = ' ';
|
||||||
|
++c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
============
|
============
|
||||||
Cmd_TokenizeString
|
Cmd_TokenizeString
|
||||||
|
|
|
@ -434,6 +434,7 @@ char *Cmd_Args (void);
|
||||||
char *Cmd_ArgsFrom( int arg );
|
char *Cmd_ArgsFrom( int arg );
|
||||||
void Cmd_ArgsBuffer( char *buffer, int bufferLength );
|
void Cmd_ArgsBuffer( char *buffer, int bufferLength );
|
||||||
char *Cmd_Cmd (void);
|
char *Cmd_Cmd (void);
|
||||||
|
void Cmd_Args_Sanitize( void );
|
||||||
// The functions that execute commands get their parameters with these
|
// The functions that execute commands get their parameters with these
|
||||||
// functions. Cmd_Argv () will return an empty string, not a NULL
|
// functions. Cmd_Argv () will return an empty string, not a NULL
|
||||||
// if arg > argc, so string operations are allways safe.
|
// if arg > argc, so string operations are allways safe.
|
||||||
|
|
|
@ -1500,6 +1500,7 @@ void SV_ExecuteClientCommand( client_t *cl, const char *s, qboolean clientOK ) {
|
||||||
if (clientOK) {
|
if (clientOK) {
|
||||||
// pass unknown strings to the game
|
// pass unknown strings to the game
|
||||||
if (!u->name && sv.state == SS_GAME) {
|
if (!u->name && sv.state == SS_GAME) {
|
||||||
|
Cmd_Args_Sanitize();
|
||||||
VM_Call( gvm, GAME_CLIENT_COMMAND, cl - svs.clients );
|
VM_Call( gvm, GAME_CLIENT_COMMAND, cl - svs.clients );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue