TaintLess: UIDropDownMenu_Refresh accesses uninitialized buttons
UIDropDownMenu_Refresh, called by UIDropDownMenu_SetSelected*, accesses buttons beyond those present and initialized by the current dropdown. If the previously-open dropdown was insecure and used specific info keys, this will taint the current execution.
UIDropDownMenu_SetSelected* is widely used on secure execution paths. Blizzard_CUFProfiles is one example of this, causing errors when the Interface Options frame is closed while in combat lockdown.
Affected versions: Classic (unfixed), Modern until 11.0 (mitigated by migrating FrameXML to another menu implementation)
To reproduce
- Create the following macro and place it on your action bars:
Patch 8.2.5+
/click GameMenuButtonUIOptions /run t = {} for i=1,8 do t[i] = {text="boo", checked=true} end EasyMenu(t, CreateFrame("Frame", "T", nil, "UIDropDownMenuTemplate"), "cursor", 0,0,"MENU") /click InterfaceOptionsFrameCancel
- Reload the UI: run /reload
- While in combat lockdown and in a group, click the macro.
Proving Grounds Healer/Tank trials work well for this. - Interface action failed because of an AddOn
An action was blocked in combat because of taint from MACRO_TAINT - CompactRaidFrameContainer:Show() Interface\AddOns\Blizzard_CompactRaidFrames\Blizzard_CompactRaidFrameManager.lua:525 CompactRaidFrameManager_UpdateContainerVisibility() Interface\AddOns\Blizzard_CompactRaidFrames\Blizzard_CompactRaidFrameManager.lua:472 CompactRaidFrameManager_SetIsShown() Interface\AddOns\Blizzard_CompactRaidFrames\Blizzard_CompactRaidFrameManager.lua:511 CompactRaidFrameManager_SetSetting() Interface\AddOns\Blizzard_CUFProfiles\Blizzard_CompactUnitFrameProfiles.lua:594 func() Interface\AddOns\Blizzard_CUFProfiles\Blizzard_CompactUnitFrameProfiles.lua:571 CompactUnitFrameProfiles_ApplyProfile() Interface\AddOns\Blizzard_CUFProfiles\Blizzard_CompactUnitFrameProfiles.lua:174 CompactUnitFrameProfiles_ApplyCurrentSettings() Interface\AddOns\Blizzard_CUFProfiles\Blizzard_CompactUnitFrameProfiles.lua:83 CompactUnitFrameProfiles_CancelChanges() Interface\AddOns\Blizzard_CUFProfiles\Blizzard_CompactUnitFrameProfiles.lua:76 pcall() Interface\FrameXML\InterfaceOptionsFrame.lua:214 securecall() Interface\FrameXML\InterfaceOptionsFrame.lua:249
How this gets tainted
- Cancelling out of the Interface Options frame calls the cancel handler on all registered panels. For Blizzard_CUFProfiles, this eventually reaches CompactUnitFrameProfiles_CancelChanges.
- CUFProfiles' cancel handler requests that the client restore the relevant settings, updates the panel's UI controls to reflect the restored settings, and finally pushes the settings to secure elements.
- While updating UI controls, UIDropDownMenu_SetSelectedValue is called for dropdowns, which in turn calls UIDropDownMenu_Refresh.
- UIDropDownMenu_Refresh reads past the entries in the currently-open dropdown, accessing the checked and notCheckable keys on buttons that may have been set insecurely. This taints the execution.
Possible fixes
- Patch UIDropDownMenu_Refresh:
-- Just redraws the existing menu - for i=1, UIDROPDOWNMENU_MAXBUTTONS do + for i=1, listFrame.numButtons do
AddOn workaround
A workaround for this issue is included in TaintLess.