Class: SaferGenerator
- Inherits:
-
Object
- Object
- SaferGenerator
- Defined in:
- lib/ppr/safer_generator.rb
Overview
Tool for executing in a safer sandbox a proc that generates a string into a stream.
Defined Under Namespace
Classes: SaferException
Constant Summary collapse
- DANGER_CONSTANTS =
The list of dangerous constants of Object.
[ :File, :IO, :Dir ]
- DANGER_METHODS =
The list of dangerous methods of Kernel
[ :system, :`, :open ]
Instance Method Summary collapse
-
#initialize(*black_list) ⇒ SaferGenerator
constructor
Creates a new safe context with while removing Kernel methods and constants from
black_list
in addition to the default dangerous ones. -
#run(stream = nil, &block) ⇒ Object
Executes
block
in a safe context for generating text into astream
. -
#secure ⇒ Object
Strips all the Kernel methods and constants appart from the elements of the white list.
Constructor Details
#initialize(*black_list) ⇒ SaferGenerator
Creates a new safe context with while removing Kernel methods and constants from black_list
in addition to the default dangerous ones.
26 27 28 29 30 31 32 33 34 35 |
# File 'lib/ppr/safer_generator.rb', line 26 def initialize(*black_list) # Set the black list of methods. @black_methods = black_list.select do |symbol| symbol.to_s[0].match(/[a-z_]/) end # Set the black list of constants. @black_constants = black_list.select do |symbol| symbol.to_s[0].match(/[A-Z]/) end end |
Instance Method Details
#run(stream = nil, &block) ⇒ Object
Executes block
in a safe context for generating text into a stream
.
If no stream is given, returns the result as a string instead.
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
# File 'lib/ppr/safer_generator.rb', line 60 def run(stream = nil, &block) unless stream # No stream given to_return = true stream = StringIO.new("") end # Creates the pipe for communicating with the block. rd,wr = IO.pipe # Creates a process for executing the block. pid = fork if pid then # This is the parent: waits for the block execution result. # No need to write on the pipe. close it. wr.close # Read the result of the process and send it to stream until rd.eof? stream << rd.read end # No more need of rd. rd.close # Wait the end of the child process Process.wait(pid) # Where there a trouble? unless $?.exited? then # pid did not exit, internal error. raise "*Internal error*: safer process #{pid} did not exit." end if $?.exitstatus !=0 then # Reconstruct the exception from the stream, the exit # status is the number of line to use. e0 = Marshal.load( stream.string.each_line. to_a[-$?.exitstatus..-1].join ) # Then resend the eception encapsulated into another one # telling the safer process failed. begin raise e0 rescue Exception => e1 raise SaferException.new("*Error*: exception occured in safer process #{pid}.") end end else # This is the child: enter in safe mode and execute the block. # No need to write on the pipe. close it. rd.close # Secure. secure # Execute the block. begin block.call(wr) rescue Exception => e # The exception is serialized and passed to the main process # through the pipe. e = Marshal.dump(e) wr << "\n" << e # The exit status is the number of line of the serialized # exception. exit!(e.each_line.count) end # No more need of wr. wr.close # End the process without any error. exit!(0) end # Is there a string to return? if to_return then return stream.string else return nil end end |
#secure ⇒ Object
Strips all the Kernel methods and constants appart from the elements of the white list. Also strip Object from dangerous methods and constants apart from the elements of the white list.
41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
# File 'lib/ppr/safer_generator.rb', line 41 def secure # Gather the methods to strip. methods = DANGER_METHODS + @black_methods # Gather the constants to strip. constants = DANGER_CONSTANTS + @black_constants # Strip the dangerous methods. methods.each do |meth| Kernel.send(:undef_method,meth) end # Strip the dangerous constants from Object. constants.each do |cst| Object.send(:remove_const,cst) end end |