Class Rufus::TreeChecker
In: lib/rufus/treechecker.rb
Parent: Object

TreeChecker relies on ruby_parser to turns a piece of ruby code (a string) into a bunch of sexpression and then TreeChecker will check that sexpression tree and raise a Rufus::SecurityException if an excluded pattern is spotted.

The TreeChecker is meant to be useful for people writing DSLs directly in Ruby (not via their own parser) that want to check and prevent bad things from happening in this code.

  tc = Rufus::TreeChecker.new do
    exclude_fvcall :abort
    exclude_fvcall :exit, :exit!
  end

  tc.check("1 + 1; abort")               # will raise a SecurityError
  tc.check("puts (1..10).to_a.inspect")  # OK

featured exclusion methods

call / vcall / fcall ?

What the difference between those ? Well, here is how those various piece of code look like :

  "exit"          => [:vcall, :exit]
  "Kernel.exit"   => [:call, [:const, :Kernel], :exit]
  "Kernel::exit"  => [:call, [:const, :Kernel], :exit]
  "k.exit"        => [:call, [:vcall, :k], :exit]
  "exit -1"       => [:fcall, :exit, [:array, [:lit, -1]]]

Obviously :fcall could be labelled as "function call", :call is a call on to some instance, while vcall might either be a variable dereference or a function call with no arguments.

low-level rules

higher level rules

Those rules take no arguments

a bit further

It‘s possible to clone a TreeChecker and to add some more rules to it :

  tc0 = Rufus::TreeChecker.new do
    #
    # calls to eval, module_eval and instance_eval are not allowed
    #
    exclude_eval
  end

  tc1 = tc0.clone
  tc1.add_rules do
    #
    # calls to any method on File and FileUtils classes are not allowed
    #
    exclude_call_on File, FileUtils
  end

Methods

Classes and Modules

Class Rufus::TreeChecker::RuleSet

Constants

VERSION = '1.0.3'

Public Class methods

initializes the TreeChecker, expects a block

Public Instance methods

adds a set of checks (rules) to this treechecker. Returns self.

Performs the check on the given String of ruby code. Will raise a Rufus::SecurityError if there is something excluded by the rules specified at the initialization of the TreeChecker instance.

return a copy of this TreeChecker instance

freezes the treechecker instance "in depth"

pretty-prints the sexp tree of the given rubycode

returns the pretty-printed string of the given rubycode (thanks ruby_parser).

Protected Instance methods

within the ‘at_root’ block, rules are added to the @root_checks, ie they are evaluated only for the toplevel (root) sexp.

the actual check method, check() is rather a bootstrap one…

prevents access (calling methods and rebinding) to a class (or a list of classes

bans the usage of ‘alias‘

bans the use of backquotes

bans the defintion and the [re]openening of classes

a list of exceptions (classes) can be passed. Subclassing those exceptions is permitted.

    exclude_class_tinkering :except => [ String, Array ]

bans method definitions

bans the use of ‘eval’, ‘module_eval’ and ‘instance_eval‘

bans referencing or setting the value of global variables

adds a rule that will forbid sexps that begin with the given head

    tc = TreeChecker.new do
      exclude_head [ :block ]
    end

    tc.check('a = 2')         # ok
    tc.check('a = 2; b = 5')  # will raise an error as it's a block

bans the definition or the opening of modules

bans raise and throw

This rule :

    exclude_rebinding Kernel

will raise a security error for those pieces of code :

    k = Kernel
    k = ::Kernel

a simple parse (relies on ruby_parser currently)

[Validate]