return true;
}
-bool LuaHelpers::RunScriptOnStack( Lua *L, CString &sError, int iArgs, int iReturnValues )
+bool LuaHelpers::RunScriptOnStack( Lua *L, CString &sError, int iArgs, int iReturnValues, bool bSandbox )
{
+ if( bSandbox )
+ {
+ lua_newtable( L );
+ lua_setfenv( L, -2 );
+ }
+
int ret = lua_pcall( L, iArgs, iReturnValues, 0 );
if( ret )
{
return true;
}
-bool LuaHelpers::RunScript( Lua *L, const CString &sScript, const CString &sName, CString &sError, int iReturnValues )
+bool LuaHelpers::RunScript( Lua *L, const CString &sScript, const CString &sName, CString &sError, int iReturnValues, bool bSandbox )
{
// load string
{
}
// evaluate
- return LuaHelpers::RunScriptOnStack( L, sError, 0, iReturnValues );
+ return LuaHelpers::RunScriptOnStack( L, sError, 0, iReturnValues, bSandbox );
}
-bool LuaHelpers::RunScript( Lua *L, const CString &sExpression, const CString &sName, int iReturnValues )
+bool LuaHelpers::RunScript( Lua *L, const CString &sExpression, const CString &sName, int iReturnValues, bool bSandbox )
{
CString sError;
- if( !LuaHelpers::RunScript( L, sExpression, sName.size()? sName:CString("in"), sError, iReturnValues ) )
+ if( !LuaHelpers::RunScript( L, sExpression, sName.size()? sName:CString("in"), sError, iReturnValues, bSandbox ) )
{
sError = ssprintf( "Lua runtime error parsing \"%s\": %s", sName.size()? sName.c_str():sExpression.c_str(), sError.c_str() );
Dialog::OK( sError, "LUA_ERROR" );
/* Run the function with arguments at the top of the stack, with the given
* number of arguments. The specified number of return values are left on
* the Lua stack. On error, nils are left on the stack, sError is set and
- * false is returned. */
- bool RunScriptOnStack( Lua *L, CString &sError, int iArgs = 0, int iReturnValues = 0 );
+ * false is returned. If bSandbox is true, the script is given a blank env
+ * to run in instead of the full Lua environment. */
+ bool RunScriptOnStack( Lua *L, CString &sError, int iArgs = 0, int iReturnValues = 0, bool bSandbox = false );
/* Run a script with the given name. Return values are left on the Lua stack.
* Returns false on error, with sError set. */
- bool RunScript( Lua *L, const CString &sScript, const CString &sName, CString &sError, int iReturnValues = 0 );
+ bool RunScript( Lua *L, const CString &sScript, const CString &sName, CString &sError, int iReturnValues = 0, bool bSandbox = false );
/* Convenience: run a script with one return value, displaying an error on failure.
* The return value is left on the Lua stack. */
- bool RunScript( Lua *L, const CString &sExpression, const CString &sName = "", int iReturnValues = 0 );
+ bool RunScript( Lua *L, const CString &sExpression, const CString &sName = "", int iReturnValues = 0, bool bSandbox = false );
bool RunScriptFile( const CString &sFile );
{
Lua *L = LUA->Get();
- if( !LuaHelpers::RunScript(L, m_sExpression, "expression", 1) )
+ if( !LuaHelpers::RunScript(L, m_sExpression, "expression", 1, m_bSandboxed) )
{
this->SetFromNil();
LUA->Release( L );
return sRet;
}
-void LuaData::LoadFromString( const CString &s )
+void LuaData::LoadFromString( const CString &s, bool bSandbox )
{
+ m_bSandboxed = bSandbox;
+
Lua *L = LUA->Get();
/* Restore the serialized data by evaluating it. */
CString sError;
- if( !LuaHelpers::RunScript( L, s, "serialization", sError, 1 ) )
+ if( !LuaHelpers::RunScript(L, s, "serialization", sError, 1, m_bSandboxed) )
{
/* Serialize() should never return an invalid script. Drop the failed
- * script into the log (it may be too big to pass to FAIL_M) and fail. */
+ * script into the log (it may be too big to pass to FAIL_M) and fail.
+ *
+ * Sandboxed scripts may fail due to attempting to escape the sandbox;
+ * log a warning, but don't fail in that case. */
LOG->Warn( "Unserialization of \"%s\" failed: %s", s.c_str(), sError.c_str() );
- FAIL_M( "Unserialization failed" );
+
+ if( !m_bSandboxed )
+ FAIL_M( "Unserialization failed" );
}
this->SetFromStack( L );
if( !m_bWasSet )
return;
- LoadFromString( m_sSerializedData );
+ LoadFromString( m_sSerializedData, m_bSandboxed );
m_sSerializedData.erase( m_sSerializedData.begin(), m_sSerializedData.end() );
}
class LuaExpression: public LuaReference
{
public:
- LuaExpression( const CString &sExpression = "" ) { if( sExpression != "" ) SetFromExpression( sExpression ); }
+ LuaExpression( const CString &sExpression = "", bool bSandbox = false )
+ {
+ m_bSandboxed = bSandbox;
+ if( sExpression != "" ) SetFromExpression( sExpression );
+ }
+
void SetFromExpression( const CString &sExpression );
- CString GetExpression() const { return m_sExpression; }
+ const CString& GetExpression() const { return m_sExpression; }
protected:
virtual void Register();
private:
CString m_sExpression;
+ bool m_bSandboxed;
};
/* Reference a trivially restorable Lua object (any object that Serialize can handle).
{
public:
virtual CString Serialize() const;
- virtual void LoadFromString( const CString &s );
+ virtual void LoadFromString( const CString &s, bool bSandbox = false );
protected:
virtual void BeforeReset();
CString m_sSerializedData;
bool m_bWasSet;
+ bool m_bSandboxed;
};
class LuaTable: public LuaData
pNode->GetChildValue( "TotalMines", m_iTotalMines );
pNode->GetChildValue( "TotalHands", m_iTotalHands );
- if( IsMachine() )
+ CString sData;
+ if( pNode->GetChildValue( "Data", sData ) )
{
- CString sData;
- if( pNode->GetChildValue( "Data", sData ) )
+ /* IMPORTANT: sandbox this call. We're taking arbitrary
+ * Lua from a source whose chain of trust has been broken. */
+ m_SavedLuaData.LoadFromString( sData, true );
+
+ if( m_SavedLuaData.GetLuaType() != LUA_TTABLE )
{
- m_SavedLuaData.LoadFromString( sData );
- if( m_SavedLuaData.GetLuaType() != LUA_TTABLE )
- {
- LOG->Warn( "Profile data did not evaluate to a table" );
- Lua *L = LUA->Get();
- lua_newtable( L );
- m_SavedLuaData.SetFromStack( L );
- LUA->Release( L );
- }
+ LOG->Warn( "Profile data did not evaluate to a table" );
+ Lua *L = LUA->Get();
+ lua_newtable( L );
+ m_SavedLuaData.SetFromStack( L );
+ LUA->Release( L );
}
}