• All submissions to this site are governed by Second Life Project Contribution Agreement. By submitting patches and other information using this site, you acknowledge that you have read, understood, and agreed to those terms.
Issue Details (XML | Word | Printable)

Key: SVC-1956
Type: Bug Bug
Status: Resolved Resolved
Resolution: Fixed
Priority: Critical Critical
Assignee: Babbage Linden
Reporter: Strife Onizuka
Votes: 0
Watchers: 1
Operations

If you were logged in you would be able to see more operations.
2. Second Life Service - SVC

Event handler and global function name collision gives interesting results

Created: 31/Mar/08 06:08 PM   Updated: 10/Apr/08 02:28 PM
Return to search
Component/s: Scripts
Affects Version/s: Mono Beta
Fix Version/s: Mono Beta

Issue Links:
Relates
 

Linden Lab Issue ID: DEV-13081


 Description  « Hide
Users can name global functions that clash with events. A clever user might be able to use this to exploit an ignorant scripter (defaultmoney). On the flip side this does present the scripter with some new functionality, the ability to call event handler like functions (there have been a few instances in my scripting career where I've wished I could do this).

Solution:
Give both global functions and events different prefixes so it is impossible for one to collide with the other.

Example:
gdefaultchat - User function
edefaultchat - Event handler

Note:
A mitigating fact of this is that the signature of the global function and the expected event handler must match.

===============================
This script fails to run in mono.

defaultchat(integer a, string b, key c, string d)
{
llOwnerSay("hijacked!");
}

default
{
state_entry()
{ llListen(1,"","",""); }
listen(integer a, string b, key c, string d)
{ llOwnerSay("listen"); }
}

========================
This script runs but handles listen events improperly.

defaultchat(integer a, string b, key c, string d)
{
llOwnerSay("hijacked!");
}

default
{
state_entry()
{ llListen(1,"","",""); } }
}



 All   Comments   Change History      Sort Order: Ascending order - Click to sort in descending order
Lex Neva added a comment - 01/Apr/08 09:47 AM
Strife, I don't understand what's going on here. Some questions:

Are you saying that a function named "defaultchat" somehow overshadows a listen event in the default state?
What happens when a listen event comes in in that case?
Why does the first example fail to run?


Lex Neva added a comment - 01/Apr/08 09:48 AM
Another:

Can you explain in detail how one would go about using this as an exploit?


Strife Onizuka added a comment - 01/Apr/08 10:32 AM - edited
Whats going on is that the LSL Mono compiler is mapping events as global functions. So in the example below, internally the listen event has the name "defaultchat", "default" being the state and "chat" being the event. User defined global functions are exposed by just there name, so if I have a global function name "monkeys" then the compiler exposes that as "monkeys". The compiler doesn't mark events as events and the VM doesn't care as long as the signature matches (signature being the name, return type, and parameter types). So if I name a global function as "defaultchat" and it just so happens that a listen event is to be triggered the VM looks to see if my script implements "defaultchat" with the correct signature, if I have it calls it.

========================
default
{
state_entry()

{ llListen(1,"","",""); }

listen(integer a, string b, key c, string d)

{ llOwnerSay("listen"); }

}

========================

As to exploitable, I haven't had time to really think about all the implications of this. Basically you would implement an event handler outside of the state scope and hope the user just thinks it's dead code, a comment or a string. Something like:

string item = "Item";
integer price = 100;
string jibberish = ''\'"/#\'"; defaultchat( integer twas, string that, key unlocked?, string twice ){ twas =$ llGiveMoney( unlocked #, price? );@ happy ;} string suffice'';

default
{
state_entry()

{ llRequestPermissions(llGetOwner(), PERMISSION_DEBIT); llListen(1,"","","tutorial"); }

money(key user, integer amount)
{
if(amount >= price)

{ amount -= price; llGiveInventory(user, item); }

if(amount > 0)
llGiveMoney(user, amount);
}
}