Class: Rufus::TreeChecker
- Inherits:
-
Object
- Object
- Rufus::TreeChecker
- Defined in:
- lib/rufus/treechecker.rb
Overview
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
-
exclude_symbol : bans the usage of a given symbol (very low-level,
mostly used by other rules
-
exclude_head
-
exclude_fcall
-
exclude_vcall
-
exclude_fvcall
-
exclude_fvccall
-
exclude_call_on
-
exclude_call_to
-
exclude_rebinding
-
exclude_def
-
exclude_class_tinkering
-
exclude_module_tinkering
-
at_root
higher level rules
Those rules take no arguments
-
exclude_access_to : prevents calling or rebinding a list of classes
-
exclude_eval : bans eval, module_eval and instance_eval
-
exclude_global_vars : bans calling or modifying global vars
-
exclude_alias : bans calls to alias and alias_method
-
exclude_vm_exiting : bans exit, abort, …
-
exclude_raise : bans calls to raise or throw
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
Defined Under Namespace
Classes: RuleSet
Constant Summary collapse
- VERSION =
'1.0.8'
Instance Method Summary collapse
-
#add_rules(&block) ⇒ Object
Adds a set of checks (rules) to this treechecker.
-
#check(rubycode) ⇒ Object
Performs the check on the given String of ruby code.
-
#clone ⇒ Object
Return a copy of this TreeChecker instance.
-
#freeze ⇒ Object
Freezes the treechecker instance “in depth”.
-
#initialize(&block) ⇒ TreeChecker
constructor
initializes the TreeChecker, expects a block.
-
#ptree(rubycode) ⇒ Object
pretty-prints the sexp tree of the given rubycode.
-
#stree(rubycode) ⇒ Object
returns the pretty-printed string of the given rubycode (thanks ruby_parser).
- #to_s ⇒ Object
Constructor Details
#initialize(&block) ⇒ TreeChecker
initializes the TreeChecker, expects a block
144 145 146 147 148 149 150 151 |
# File 'lib/rufus/treechecker.rb', line 144 def initialize(&block) @root_set = RuleSet.new @set = RuleSet.new @current_set = @set add_rules(&block) end |
Instance Method Details
#add_rules(&block) ⇒ Object
Adds a set of checks (rules) to this treechecker. Returns self.
187 188 189 190 191 192 |
# File 'lib/rufus/treechecker.rb', line 187 def add_rules(&block) instance_eval(&block) if block self end |
#check(rubycode) ⇒ Object
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.
166 167 168 169 170 171 172 173 174 175 176 |
# File 'lib/rufus/treechecker.rb', line 166 def check(rubycode) sexp = parse(rubycode) #@root_checks.each do |meth, *args| # send meth, sexp, args #end @root_set.check(sexp) do_check(sexp) end |
#clone ⇒ Object
Return a copy of this TreeChecker instance
180 181 182 183 |
# File 'lib/rufus/treechecker.rb', line 180 def clone Marshal.load(Marshal.dump(self)) end |
#freeze ⇒ Object
Freezes the treechecker instance “in depth”
196 197 198 199 200 201 |
# File 'lib/rufus/treechecker.rb', line 196 def freeze super @root_set.freeze @set.freeze end |
#ptree(rubycode) ⇒ Object
pretty-prints the sexp tree of the given rubycode
129 130 131 132 |
# File 'lib/rufus/treechecker.rb', line 129 def ptree(rubycode) puts stree(rubycode) end |
#stree(rubycode) ⇒ Object
returns the pretty-printed string of the given rubycode (thanks ruby_parser).
137 138 139 140 |
# File 'lib/rufus/treechecker.rb', line 137 def stree(rubycode) "#{rubycode.inspect}\n =>\n#{parse(rubycode).inspect}" end |
#to_s ⇒ Object
153 154 155 156 157 158 159 160 |
# File 'lib/rufus/treechecker.rb', line 153 def to_s s = "#{self.class} (#{self.object_id})\n" s << "root_set :\n" s << @root_set.to_s s << "set :\n" s << @set.to_s end |