Secure RPG Maker formula evaluation

● ARCHIVED · READ-ONLY
Started by Tsukihime 7 posts View original ↗
  1. randomly did a search for "securely running eval" and came across some questions on SO which eventually led to this

    http://ruby-doc.com/docs/ProgrammingRuby/html/taint.html

    So I tried it

    $SAFE = 2def test_eval(formula) eval(formula)endtest_eval("p 23 + 445")test_eval("system('dir')")And Ruby accepts the print and the math, but when it tries to make a system call, it is denied. 870nuPe.jpg

    Are there any issues with this approach?

    Well, one obvious problem is that most players aren't actually modifying project scripts themselves, and any dev could probably just erase the line themselves. Maybe a better approach would be needed rather than just naively setting the variable in the script.

    Seems like something that would be useful by default in RPG Maker, given that eval is commonly used everywhere (including built-in functionality such as damage formulas or script calls), and you can easily compromise (or at least, frustrate) players if you knew a few tricks.

    Since RM is quite limited in terms of how it can be used and where it can get data from, there is less to worry about.

    Of course, I'd like to assume most devs are honest or something like that.

    Personally it's not an issue I would address, but if it helps block out the quick `rm -rf`'ers it might be cool.
  2. I would avoid eval like the plague. It's considerably slower than just running the code, and 99% of the time you won't need it. Consider it in the realm of global variables and GOTOs. If it's really being used throughout the RM source, something's definitely not right.

    Consider:

    Yes, they're Javascript, but the concept is the same.
  3. Lemur said:
    I would avoid eval like the plague. It's considerably slower than just running the code, and 99% of the time you won't need it. Consider it in the realm of global variables and GOTOs. If it's really being used throughout the RM source, something's definitely not right.
    Saying eval is evil is the same as what they say about guns and people.


    Yes, it's used everywhere.


    It's even used for the simple purpose of reading ruby scripts in the script editor!


    Simply alias eval and you can see all of the scripts that are being run through it.


    Evals are used to provide core functionality in the engine, including damage formulas and script calls (conditional branches, move routes, and arbitrary event commands).


    I'm not a fan of eval either, however I like the idea of being able to allow users to provide input and I can just interpret it. This does not strictly require eval, but I haven't found anything else in Ruby that achieves the same thing.

    and 99% of the time you won't need it.
    If you have suggestions for alternatives I'm open to implementing them.


    These are a few things that I would like to accomplish, which eval does very well:


    - checking whether a switch is set or a variable is of a certain value


    - accessing attributes and methods defined in context-specific objects


    - accessing global variables and other objects defined in the global namespace (eg: $game_party, $game_self_switches, $game_map, etc.)


    If I were to take it to the extreme, I would like devs to be able to create their own logic using the full power of ruby without having to actually write their own scripts, or being restricted by things like a DSL that offers a very limited language.


    I'm also not interested in writing such a DSL myself, though it would make it easier to port to other frameworks outside of ruby so that might be an incentive.
  4. I'm not adept in RGSS yet, but if you have any of the code you could link me to as an example that'd be helpful in finding different solutions. I just know it's a great and powerful tool, much like an RPG. The problem with that is if you go shooting one everywhere you could easily blow things up by accident.
  5. Check out damage evaluation in Game_Battler line 351

    def make_damage_value(user, item) value = item.damage.eval(user, self, $game_variables) # -- value *= item_element_rate(user, item) value *= pdr if item.physical? value *= mdr if item.magical? value *= rec if item.damage.recover? value = apply_critical(value) if @result.critical value = apply_variance(value, item.damage.variance) value = apply_guard(value) @result.make_damage(value.to_i, item)endWhich calls the damage object's eval method (available in the help file)

    Code:
    def eval(a, b, v)  [Kernel.eval(@formula), 0].max * sign rescue 0end
    So all it does is take your formula and evaluate it within the context of the method with a few formula variables provided (a for the attacker, b for the target, and v for game variables).The formula can be anything, so you can access any of the attacker or target's methods, and basically anything else you can think of that you can do in Ruby because...well, it's basically running ruby code on the spot.

    This has been used to achieve all sorts of complex skill or item effects, though personally I don't find it a very flexible solution when you start to require conditions and other things.

    One script that I've written to move most of the "extra" stuff out of damage formulas such as adding a state to the target is to use formula effects which basically does the same thing as what people are doing now in their damage formulas except you're defining it as an effect, which also allows you to attach conditions to those effects.

    All of which use ruby formulas so that I can let devs do whatever they want without having to formally write a method for it.
  6. In the editor there are a few places other than the script editor where you can define pieces of code. eval is used for evaluating those pieces of code in their proper context.