Prevent players to reveal the map from GUI script

`Engine.SetViewedPlayer` and `Engine.SetPlayerID` could be used to
reveal the map from GUI scripts and the in game console.

This is prevented by querying the simulation whether this player is
allowed to call thous functions.

These two vulnerabilities were introduced with their respective
features:
20e7d2224a introduced SetPlayerID to allow controlling other players
	using the developer overlay.
a2f7d4d82a introduced SetViewedPlayer to allow observers to change the
	perspective.
This commit is contained in:
elexis 2024-12-11 01:22:56 +01:00 committed by phosit
parent 40d3ea33d8
commit 023527e56e
3 changed files with 55 additions and 11 deletions

View file

@ -74,6 +74,7 @@ CGame::CGame(bool replayLog):
// should be created outside only if needed.
m_GameView(CRenderer::IsInitialised() ? new CGameView(g_VideoMode.GetBackendDevice(), this) : nullptr),
m_GameStarted(false),
m_CheatsEnabled(false),
m_Paused(false),
m_SimRate(1.0f),
m_PlayerID(-1),
@ -221,6 +222,15 @@ void CGame::RegisterInit(const JS::HandleValue attribs, const std::string& saved
std::string mapType;
Script::GetProperty(rq, attribs, "mapType", mapType);
JS::RootedValue settings(rq.cx);
Script::GetProperty(rq, attribs, "settings", &settings);
if (Script::HasProperty(rq, attribs, "settings") &&
Script::HasProperty(rq, settings, "CheatsEnabled"))
{
Script::GetProperty(rq, settings, "CheatsEnabled", m_CheatsEnabled);
}
float speed;
if (Script::HasProperty(rq, attribs, "gameSpeed"))
{
@ -249,19 +259,14 @@ void CGame::RegisterInit(const JS::HandleValue attribs, const std::string& saved
{
// Load random map attributes
std::wstring scriptFile;
JS::RootedValue settings(rq.cx);
Script::GetProperty(rq, attribs, "script", scriptFile);
Script::GetProperty(rq, attribs, "settings", &settings);
m_World->RegisterInitRMS(scriptFile, scriptInterface.GetContext(), settings, m_PlayerID);
}
else
{
std::wstring mapFile;
JS::RootedValue settings(rq.cx);
Script::GetProperty(rq, attribs, "map", mapFile);
Script::GetProperty(rq, attribs, "settings", &settings);
m_World->RegisterInit(mapFile, scriptInterface.GetContext(), settings, m_PlayerID);
}
@ -379,6 +384,11 @@ void CGame::SetViewedPlayerID(player_id_t playerID)
m_ViewedPlayerID = playerID;
}
bool CGame::CheatsEnabled() const
{
return m_CheatsEnabled;
}
void CGame::StartGame(JS::MutableHandleValue attribs, const std::string& savedState)
{
if (m_ReplayLogger)
@ -475,3 +485,13 @@ bool CGame::IsGameFinished() const
return false;
}
bool CGame::PlayerFinished(player_id_t playerID) const
{
CmpPtr<ICmpPlayerManager> cmpPlayerManager(*m_Simulation2, SYSTEM_ENTITY);
if (!cmpPlayerManager)
return false;
CmpPtr<ICmpPlayer> cmpPlayer(*m_Simulation2, cmpPlayerManager->GetPlayerByID(playerID));
return cmpPlayer && cmpPlayer->GetState() != "active";
}

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2023 Wildfire Games.
/* Copyright (C) 2024 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -114,6 +114,8 @@ public:
int GetViewedPlayerID();
void SetViewedPlayerID(player_id_t playerID);
bool CheatsEnabled() const;
/**
* Check if the game is finished by testing if there's a winner.
* It is used to end a non visual autostarted game.
@ -122,6 +124,11 @@ public:
*/
bool IsGameFinished() const;
/**
* Check if the given player has been defeated or won the game.
*/
bool PlayerFinished(player_id_t playerID) const;
/**
* Retrieving player colors from scripts is slow, so this updates an
* internal cache of all players' colors.
@ -214,6 +221,8 @@ private:
int LoadInitialState(const std::string& savedState);
bool m_IsSavedGame; // true if loading a saved game; false for a new game
bool m_CheatsEnabled;
int LoadVisualReplayData();
OsPath m_ReplayPath;
bool m_IsVisualReplay;

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2023 Wildfire Games.
/* Copyright (C) 2024 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -67,20 +67,35 @@ int GetPlayerID()
return g_Game->GetPlayerID();
}
void SetPlayerID(int id)
void SetPlayerID(const ScriptRequest& rq, int id)
{
if (!g_Game)
return;
g_Game->SetPlayerID(id);
int currentID = g_Game->GetPlayerID();
if (currentID == id)
return;
if (g_Game->CheatsEnabled())
g_Game->SetPlayerID(id);
else
ScriptException::Raise(rq, "Changing player ID with cheats disabled is prohibited");
}
void SetViewedPlayer(int id)
void SetViewedPlayer(const ScriptRequest& rq, int id)
{
if (!g_Game)
return;
g_Game->SetViewedPlayerID(id);
int playerID = g_Game->GetPlayerID();
if (playerID == id)
return;
// Forbid active players to reveal the map by changing perspective, unless cheats are allowed.
if (playerID == -1 || g_Game->CheatsEnabled() || g_Game->PlayerFinished(playerID))
g_Game->SetViewedPlayerID(id);
else
ScriptException::Raise(rq, "Changing the perspective with cheats disabled is prohibited");
}
float GetSimRate()