View Single Post
03/29/17, 02:44 PM   #10
ZOS_ChipHilseberg
ZOS Staff!
Premium Member
Yes this person is from ZeniMax!
Join Date: Oct 2014
Posts: 551
Since there seems to be some confusion about the security mechanism I thought I'd try to explain it from the start.

The main concept here is the Lua closure. A closure is not just the byte code that is generated from the lua code you write, it also contains references to the environment it is executing in and upvalues which allow it to reference local variables that were in scope when the closure was created. You can look at https://www.lua.org/pil/6.1.html for more information on closures.

Our security system adds another flag to closures which indicates if they are trusted or not. Closures made by the stock UI are trusted, while closures made by add-ons are not trusted. These trusted states are used along with the callstack to determine if a private function is allowed to be run. Any time an untrusted closure is run, the callstack from that point on is tainted and any closures run from that point on are treated as untrusted (even stock UI code). Additionally any closures made from that point on are untrusted The state resets back to trusted when the callstack unwinds.

One example of this is a situation we had with the context menu system. The context menu can show a number of options that the player can click on (same as the right click menu in Windows). These options come from an object pool which dynamically creates the controls as needed. As part of making the control the XML makes mouse enter, exit, down, and up handlers which are closures. The particular situation we encountered was an addon would request to show a large context menu which would require making more options within the pool. Even though the context menu system closures are trusted, the callstack is tainted because it was an addon closure that was invoking the menu system. This means that the mouse handlers are created as untrusted. This was generally fine for the addon because it wasn't trying to call private functions from the menu anyway. However, these controls with the untrusted closures would be placed back into the pool when the menu was hidden. Later, the user would right click an inventory item and the context menu system would pull a control out of the pool that had untrusted mouse handler closures and set it to call the UseItem function. When the user clicked this control, the UseItem would fail because the callstack began with an untrusted mouse handler.

So these are the types of situations that generally lead to addons causing the stock UI to fail in running its functions. Some of these situations can be fixed by changing the addon, while others are easier to adjust on our side. In the case above we pre-populated the context menu with 30 entries during the stock UI load so that the handler closures were created as trusted. These types of bugs can be hard to track down because it's usually an action at some point in the past that setup the error that you are seeing now. There isn't really a great way to make it obvious what to fix in an error message. We know at which part of the callstack it became tainted. However we don't have the callstack that was used to create that untrusted closure which would be the point at which the problem happened. Unfortunately storing a full callstack for each closure is pretty memory intensive. But if you guys have any ideas on what you'd like to see to help diagnose these problems I'm happy to hear them.
  Reply With Quote