Secure Execution and Tainting
The User Interface API's for WoW 2.0 have been updated to prevent scripted automation of decision making using the same code security model that protects the movement functions in prior releases. This means that several more of the API functions have been protected against execution from insecure code.
A number of common WoW UI coding practices (most notably hooking) can easily cause problems in this model, preventing players from casting spells or performing actions, so I hope to explain how the security model works for developers in order for you to avoid these problems, as well as introducing some new Blizzard features to make existing ideas work under the new constraints.
Secure execution and "Tainting"
When WoW starts executing lua code, the execution starts off 'secure', and able to run protected functions. Execution remains secure until it encounters 'taint' - which is an indicator that a function or object came from an untrusted (AddOn or /script) source. The basic idea is that execution becomes 'tainted' as soon as it reads tainted data or executes tainted code, and any data written by a tainted execution is itself tainted. Protected functions refuse to operate when called from an execution path that is not secure.
When the UI first loads, all code and data from Blizzard signed FrameXML and AddOns (plus their saved variables) is secure, and all code and data from user provided AddOns (plus their saved variables) is tainted.
What can be tainted?
All lua values and references can be tainted - local variables, global variables, table keys, table values:
- When new values are created (e.g. local x = 2) then they inherit the current taint of their execution path.
- When code accesses secure values, the resulting value will be tainted by the current execution path (but the original value remains clean).
- When code accesses tainted values, the resulting value will remain tainted and the execution path is also tainted.
- When code sets global values, the resulting value has the taint of the execution path.
Function closures can also be tainted, executing a function closure applies its taint to the current environment.
Hooking and the hooksecurefunc function
The taint model is the reason that 'hooking' as it is commonly done today can easily break lots of UI functionality, trying to hook a function that is used by secure code causes a tainted function to be called in the middle of an otherwise secure execution path, this then taints the execution path so that nothing following the hook can use secure functions - don't be too dismayed however, we've been given a tool to get around this.
The new hooksecurefunc API function allows AddOn code to 'post hook' a secure global function, that is run another function after the original one has been run. So for example you could track calls to CastSpellByName using hooksecurefunc("CastSpellByName", mySpellCastTracker). The API replaces the original global function with its own secure hook function that calls the original function, saves its return values away, and then calls your hook function with the same arguments as the original function (any return values from your hook function are thrown away) and then it returns the return values from the original.
The 'special' feature of this secure hook is that when your hook function is executed, it executes with the taint that was present at the time the hook was created, and when your hook function is done that taint is discarded and the original secure (or possibly tainted - you cannot use hooksecurefunc to REMOVE taint, just avoid it) execution mode is restored.
Protected frames and secure templates
WoW 2.0 also introduces a new Frame concept, protected frames, which act like normal frames out of combat, but when in combat cannot be programatically shown, hidden, re-sized or re-anchored, nor can its attributes be changed. Once a frame has been declared protected it cannot be made unprotected, and protection is inherited from templates. You can still initiate user moving or sizing of protected frames while in combat, you just cannot use lua to move them. Secure code is allowed to bypass this restriction.
The control restrictions on protected frames also get applied to their parents and any frames they are anchored to. This is important when anchoring a protected frame to another normally non-protected frame, as it can lead to unexpected and often undesired behavior. This propagation is temporary, and re-anchoring or re-parenting the frame out of combat can release the restriction.
Protected frames are important because they form the basis of the Blizzard action and spell buttons, but also because they allow for some new secure button templates. Since normal AddOn code is tainted, it cannot change targets or perform actions directly, however WoW 2.0 contains a number of secure templates which can be inherited by AddOn code. These secure templates provide one or more secure handlers, usually OnClick, that use frame attributes to perform actions. When a secure template is inherited then any handlers it defines remain secure unless they are overridden by the inheriting frame (or another template).
The secure templates are configured using the new frame attribute methods, these can only be used outside of combat, and set a named attribute to a specific lua value, discarding the value's taint.
Since there are a number of similar concepts at work here, the terminology can be confusing, here's a summary of the common terms and their meanings:
- Secure generally means 'without taint'.
- Secure code refers to either an untainted current execution or an untainted function.
- Values/References/Parameters are sometimes referred to as 'clean', this means the same as 'secure'.
- A protected function is one that can only be successfully called from a secure execution state.
- A protected frame is one that is locked down during combat.
- A protected method is one that cannot be successfully called on a protected frame during combat.
- Secure templates are simply XML templates that define secure script handlers, they usually also create protected frames.