Script Source

To support Safe Scene Script Execution, APIs that take as parameters a string or a CharStream representing a script, now take an additional parameter of type MAXScript::ScriptSource, which describes the scripts origin:

Callers of script execution APIs should specify a value of MAXScript::ScriptSource::Embedded if the script is embedded in the scene file, or if the script can be specified by a script and that script is running as an embedded script. An example of the former is a scripted particle flow operator where the script is embedded in the scene and is specifiable by the user. An example of the latter is the registering of a script to be run when a scene event occurs. The code that registers the script needs to persist the ScriptSource of the script currently being run via the following, and pass that to the evaluation method:

MAXScript_TLS* _tls = (MAXScript_TLS*)TlsGetValue(thread_locals_index); 
MAXScript::ScriptSource::ScriptSource scriptSource = _tls->scriptSource; 

The following APIs take a MAXScript::ScriptSource parameter

BOOL ExecuteMAXScriptScript(const MCHAR* s, MAXScript::ScriptSource scriptSource, BOOL quietErrors = FALSE, FPValue* fpv = NULL, BOOL logQuietErrors = TRUE); 
Value* ExecuteScript(CharStream* source, bool* res, MAXScript::ScriptSource scriptSource); 
virtual bool GUP::ExecuteStringScript(const MCHAR *string, MAXScript::ScriptSource scriptSource); 
Value* Parser::compile(CharStream* stream, MAXScript::ScriptSource scriptSource); 
Value* Parser::compile_factor(CharStream* stream, MAXScript::ScriptSource scriptSource); 
Value* Parser::compile_all(CharStream* stream, MAXScript::ScriptSource scriptSource); 
virtual MacroEntry* MacroDir::AddMacro(const MCHAR* category, const MCHAR* internalCategory, const MCHAR* name, const MCHAR* tooltip, const MCHAR* buttonText,                 const MCHAR* sourceText, MAXScript::ScriptSource scriptSource) = 0; 
virtual void Interface::CreatePreview(PreviewParams* pvp = nullptr, MSTR* filename = nullptr, MSTR* snippet = nullptr, MAXScript::ScriptSource scriptSource = MAXScript::ScriptSource::NotSpecified) = 0; 

Security exceptions

When an unsafe MAXScript command is blocked, an instance of class SecurityException is thrown, and it should be handled by the code that called the scripted command, as any other exceptions raised by the execution of the script.

3rd party plugin’s participation in Safe Scene Script Execution

3rd party plugins that expose their functionality to MAXScript are expected to ensure that they adhere to 3ds Max’s security settings. That is, if the implementation of 3rd party plugin’s MAXScript-exposed functionality allows the user to access operating system resources (such as the file system) and services (such as execute arbitrary commands), load into 3ds Max external code, create files with code that later 3ds Max will load and execute, access the internet to upload or download payloads, access email clients, etc, then the command is considered unsafe when called from a scene embedded script, and its implementation needs to follow the guidelines described below. Not following these guidelines can result in 3ds Max users falling victims of software security exploits.

There are two ways to expose functionality to MAXScript: by implementing a MAXScript primitive, or by using function publishing.

Implementing a MAXScript primitive

If the implementation of a MAXScript primitive matches the description given above of an unsafe command, it should call one of the overrides of the ValidateCanRunMAXScriptSystemCommand() function:

void ValidateCanRunMAXScriptSystemCommand(const MCHAR* command, Value** arg_list, int count); 
void ValidateCanRunMAXScriptSystemCommand(const MCHAR* command, const MCHAR* arguments); 

If execution of unsafe MAXScript commands embedded in scene files is not allowed, ValidateCanRunMAXScriptSystemCommand() will throw a security exception. The command name and list of arguments is reported by this function as a security message, logged as an error in Scripting Listener and the 3ds Max log file.

If the implementation of a MAXScript primitive calls Python scripts, they must call one of the following two functions:

void ValidateCanRunPythonScripts(const MCHAR* command, const MCHAR* arguments); 
void ValidateCanRunPythonScripts(const MCHAR* command, Value** arg_list, int count); 

If execution of Python scripts embedded in scene files is not allowed, ValidateCanRunPythonScripts() will throw a security exception. The command name and list of arguments is reported by this function as a security message, logged as an error in Scripting Listener and the 3ds Max log file.

Implementing a function published interface

If a function published method, property or action matches the description given above of unsafe code, it should specify one of the following flags in the publishing code: