Jump to content


Photo

Evaluate(); In Game Maker?


  • Please log in to reply
31 replies to this topic

#1 §-«»-§

§-«»-§

    GMC Member

  • New Member
  • 83 posts

Posted 17 May 2009 - 06:21 PM

Does Game Maker have an equivalent to other languages' evaluate() function, which takes a string containing an expression and returns its value? I tried using
execute_string("x = " + argument0);
return x;
but soon found that malicious injection of statements wouldn't raise the error it obviously should. Since this will be a component of an online game, I'm working from the "professional paranoia" model and trying to make each section of my game self-secure without relying on other sections, so the possibility for malicious code injection is obviously a huge problem.

Maybe giving some context would help. In the big picture, I'm trying to write a stand-in for the assert statement, which is left out of Game Maker.

Ideally, my assert statement would look like this:
assert("a < b");
And if a >= b it would show a message saying assert("a < b") failed. and end the game.

The way I'm thinking of coding this function is something like the following:
/* assert(expr)
Evaluates the expression, informs the user and ends the game if it is false. */
if eval(argument0)
   return true;

show_message("assert('"argument0 + "') failed.");
game_end();

Can anyone provide me with a way to evaluate expressions in strings without being vulnerable to malicious code injection?

Or, failing that, maybe a different way to code the assert?

Edited by §-«»-§, 17 May 2009 - 06:24 PM.

  • 0

#2 ChIkEn AtE mY dOnUtS

ChIkEn AtE mY dOnUtS

    Pwner of barcodes

  • GMC Member
  • 2409 posts

Posted 17 May 2009 - 06:44 PM

REMOVED);
  • 0

#3 §-«»-§

§-«»-§

    GMC Member

  • New Member
  • 83 posts

Posted 17 May 2009 - 06:49 PM

...yeah... That's why I used the full word. Also, that's not a built-in. I'm using GM7.0 if that makes a difference.
  • 0

#4 ChIkEn AtE mY dOnUtS

ChIkEn AtE mY dOnUtS

    Pwner of barcodes

  • GMC Member
  • 2409 posts

Posted 17 May 2009 - 06:56 PM

...yeah... That's why I used the full word. Also, that's not a built-in. I'm using GM7.0 if that makes a difference.


D'oh. I always get PHP/C++/GM mixed up.
  • 0

#5 Yourself

Yourself

    The Ultimate Pronoun

  • Retired Staff
  • 7341 posts
  • Version:Unknown

Posted 17 May 2009 - 07:14 PM

Fortunately GM's expressions are rather simple (since it doesn't have any terribly fancy operators), so it wouldn't be terribly difficult to write a parser which would verify that the input is an expression (and only an expression). The parsing process will naturally be slower than execute_string, but it's the price you're going to have to pay for security.
  • 0

#6 §-«»-§

§-«»-§

    GMC Member

  • New Member
  • 83 posts

Posted 17 May 2009 - 07:30 PM

I thought about that, but what about calling functions within the expression? Some, like ds_list_set_value(), are obviously not part of an expression, while others, like ds_list_find_value(), would be completely legitimate. The only way I can think of to allow the correct functions and forbid incorrect ones is to simply have a map that includes every function in Game Maker, along with all my scripts, and keys each to a flag saying if it's harmful or not. And not only would that be slow as hell to work through, it's a little bit too much work for me.




Edited to fix a typo.

Edited by §-«»-§, 17 May 2009 - 07:30 PM.

  • 0

#7 paul23

paul23

    GMC Member

  • Global Moderators
  • 3361 posts
  • Version:GM8

Posted 17 May 2009 - 07:36 PM

I thought about that, but what about calling functions within the expression? Some, like ds_list_set_value(), are obviously not part of an expression, while others, like ds_list_find_value(), would be completely legitimate. The only way I can think of to allow the correct functions and forbid incorrect ones is to simply have a map that includes every function in Game Maker, along with all my scripts, and keys each to a flag saying if it's harmful or not. And not only would that be slow as hell to work through, it's a little bit too much work for me.




Edited to fix a typo.

Uhm well there's no clear definition of "harmful" or "not harmful" for any function: it completely depends on the game, so yes the only safe way is to create a whitelist with functions that are allowed.. This also has to take scripts into consideration: if written well such a input verification shouldn't be "too" slow (consider that whenever a user is asked to "think" about new data, the game can't be very fast paced anyways, so with a little bit of extra design you can cover up any lag there).
  • 0

#8 Somelauw

Somelauw

    GMC Member

  • GMC Member
  • 1096 posts
  • Version:Unknown

Posted 17 May 2009 - 07:38 PM

Does Game Maker have an equivalent to other languages' evaluate() function, which takes a string containing an expression and returns its value? I tried using

execute_string("x = " + argument0);
return x;
but soon found that malicious injection of statements wouldn't raise the error it obviously should. Since this will be a component of an online game, I'm working from the "professional paranoia" model and trying to make each section of my game self-secure without relying on other sections, so the possibility for malicious code injection is obviously a huge problem.

Maybe giving some context would help. In the big picture, I'm trying to write a stand-in for the assert statement, which is left out of Game Maker.

Ideally, my assert statement would look like this:
assert("a < b");
And if a >= b it would show a message saying assert("a < b") failed. and end the game.

The way I'm thinking of coding this function is something like the following:
/* assert(expr)
Evaluates the expression, informs the user and ends the game if it is false. */
if eval(argument0)
   return true;

show_message("assert('"argument0 + "') failed.");
game_end();

Can anyone provide me with a way to evaluate expressions in strings without being vulnerable to malicious code injection?

Or, failing that, maybe a different way to code the assert?


During devolpment assertions are useful. As soon as you release it, you should remove them. execute_string() by the way doesn't work for script variables.
  • 0

#9 uuf6429

uuf6429

    Covac Software

  • New Member
  • 2522 posts

Posted 17 May 2009 - 09:14 PM

Evaluate, in other languages such as javascript and PHP known as eval, are not just for expressions, they actually execute full code in context of the running script. Thus, Eval/Evaluate in GML would actually be execute_string.

However, since I do want to be usefull, there are several expression parsing scripts out there. I for one made at least two. One of which can be found in "graph object scripts" (my website>downloads section>scripts/source>graph object>). Another was mentioned in the scripts forum (somwhere). Know that they wouldn't be foolproof, I never aimed at a fully working one.

Edited by uuf6429, 17 May 2009 - 09:15 PM.

  • 0

#10 ~Dannyboy~

~Dannyboy~

    ~hoqhuue(|~

  • GMC Member
  • 2144 posts
  • Version:GM8

Posted 18 May 2009 - 04:35 AM

A bit off topic and throwing aside the whole security subject...

You can use return in execute string to return a value:
execute_string("return 21 * 2;")
This saves making a variable ;)
  • 0

#11 treacheroust

treacheroust

    GMC Member

  • New Member
  • 74 posts

Posted 21 May 2009 - 05:51 PM

Can anyone provide me with a way to evaluate expressions in strings without being vulnerable to malicious code injection?


Interesting post. It doesn't seem to be a Game Maker specific question. You could ask the same question for any language with a eval/evaluate_string like call attemping to implement an assert. But, the way of posed the question make me think that you have a solution for it in other languages... I'm curious how you would do it in another lang?
  • 0

#12 HaRRiKiRi

HaRRiKiRi

    GMC Member

  • GMC Member
  • 1364 posts

Posted 21 May 2009 - 06:57 PM

Use variable_get. Then you could call the script like this: assert(a,"<"B) or assert("a","<","b") depending on what you choose.
  • 0

#13 uuf6429

uuf6429

    Covac Software

  • New Member
  • 2522 posts

Posted 22 May 2009 - 09:04 PM

http://gmc.yoyogames...howtopic=299329

That is one way of doing it securely. Read the notices before use, it does not prevent memory editing (but at this point, anything else is also insecure).
  • 0

#14 Mnementh

Mnementh

    15151

  • Retired Staff
  • 6261 posts
  • Version:GM:Studio

Posted 22 May 2009 - 10:07 PM

That is one way of doing it securely. Read the notices before use, it does not prevent memory editing (but at this point, anything else is also insecure).

It is possible to edit any data structure through that script. It would take a lot more effort to provide safe write access, since you'd have to provide run-time checking of the indexes.
  • 0

#15 petenka

petenka

    The Chosen One

  • New Member
  • 911 posts

Posted 22 May 2009 - 11:18 PM

the safest method would be to check for any sets of parentheses and check if there's a word directly before it (not counting spaces). If so check the word and if it is included in a white list then continue otherwise deny execution.
  • 0

#16 uuf6429

uuf6429

    Covac Software

  • New Member
  • 2522 posts

Posted 24 May 2009 - 01:22 PM

It is possible to edit any data structure through that script. It would take a lot more effort to provide safe write access, since you'd have to provide run-time checking of the indexes.

How can you edit anything when writing functions are blacklisted?
Also, what do you mean by indexes? Which indexes?

petenka, mine does that, but it just checks the presense of blacklisted functions. Probably checking before braces would actually be slower.

Edited by uuf6429, 24 May 2009 - 01:23 PM.

  • 0

#17 Mnementh

Mnementh

    15151

  • Retired Staff
  • 6261 posts
  • Version:GM:Studio

Posted 24 May 2009 - 01:57 PM

How can you edit anything when writing functions are blacklisted?
Also, what do you mean by indexes? Which indexes?

No, you're right; you couldn't edit anything when the writing function are blacklisted (although they're not right now).

The problem with indexes doesn't really apply here, since the topic at hand is an evaluating a mathematical expression. However, the problem with simply blacklisting functions is that, as always, there are perfectly legitimate uses blocked because they used a function that could be used harmfully. These limitations make real use muck more difficult, in some cases. Unfortunately, it takes a lot more effort to intelligently block access to these functions (I'm writing an interpreter for an online game, and I actually had to create a locking class to prevent concurrent access to the game state), because there's no way to limit their reach at 'compile' time. All of those scripts on GMLscripts that create the name-to-index maps demonstrate how easy it is to find the indexes of any resource. Son, I think that your script is great in terms of simplicity, I wouldn't use it in a 'real' game.

Edited by Mnementh, 24 May 2009 - 01:58 PM.

  • 0

#18 paul23

paul23

    GMC Member

  • Global Moderators
  • 3361 posts
  • Version:GM8

Posted 24 May 2009 - 04:52 PM

I once wrote an "simple" regex to check for GML syntax - it checks that no "non-whitelist" functions are used.. And that the right side of the operator only modifies to allowed variables.

In a simple environment like gml blacklisting & whitelisting shouldn't make any difference though.

@mnementh: Well I wrote an "overloaded" function/script for all write-functions (for datastructures). That way I could check during that function wether or not a certain field was deemed inaccessible. And only those custom scripts were made "available" - Only problem is that those kind of runtime checks in a full game really reduce the speed. (It only works if ALL code use those custom scripts, and nothing uses the standard way of writing/reading anymore).
Also this seems to beg for gm to properly support overloading of functions. (I wish this was done a long time ago: it allows for much cleaner looking code).
  • 0

#19 uuf6429

uuf6429

    Covac Software

  • New Member
  • 2522 posts

Posted 24 May 2009 - 06:47 PM

I still can't get your points.
There's a clear distinction between sin() and sprite_save() functions. Who would use that function in a math calculation?

Also, menmoth, the writing functions are blacklisted.
Just do tell me which you think are not (with real examples).

paul, is that a bit of an overkill? Wouldn't be faster and easier to scan the code/expression against the blacklist rather then parsing the code?
  • 0

#20 Mnementh

Mnementh

    15151

  • Retired Staff
  • 6261 posts
  • Version:GM:Studio

Posted 24 May 2009 - 09:15 PM

There's a clear distinction between sin() and sprite_save() functions. Who would use that function in a math calculation?

My previous post was a little unclear on this point, but I meant to say that my point wasn't really valid in the the context of mathematical expressions, since, as you say, no one would want to use those functions. However, at this point, I see several ways that a person with malicious intent could wreck havoc on a game through your script. I'll allow that they probably couldn't do anything outside of the game, but they could definitely ruin the game itself*.

Also, menmoth, the writing functions are blacklisted.
Just do tell me which you think are not (with real examples).

Am I missing something? In this script, which you provided a link to in one of your previous posts, I see nothing that would prevent one from accessing data structures (read or write), and I don't see anything that would prevent the use of the variable_* functions either. I'd say that both of these are issues, because oftentimes, during saving or things like that, the contents of data structures and variables are written directly to files*.

Also, I like your spelling of my name. ^_^

*Since this is an online game, the security requirements are more stringent than usual. No one cares if someone messes up a one player game, but in an online game, it might be an issue.

Wouldn't be faster and easier to scan the code/expression against the blacklist rather then parsing the code?

As I said, it is not possible to provide safe, limited write access (which might be necessary) to data structures or other resources using 'compile' time checking.

@mnementh: Well I wrote an "overloaded" function/script for all write-functions (for datastructures).

How in the world did you do that? I'm very curoious, because some of those functions have functionality that can't be imitated in GML.

Also this seems to beg for gm to properly support overloading of functions. (I wish this was done a long time ago: it allows for much cleaner looking code).

I don't think it's applicable here. How is GM supposed to know when you want your version of the function called, and when to call the normal one. Generally, overloading requires each version of the function to have different parameters, which isn't very conducive to dynamic typing (that's the reason that Python also has no function overloading).

Edited by Mnementh, 24 May 2009 - 09:28 PM.

  • 0




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users