Class: HotCell::Worker
- Inherits:
-
Object
- Object
- HotCell::Worker
- Defined in:
- lib/hot_cell/worker.rb
Overview
Every untrusted byte is touched here and nowhere else.
The worker applies the cell's limits before it touches the socket, narrows to the operation's limits before it reads an untrusted byte, and calls exit! on the way out so that no finalizer and no library teardown ever runs. Limits go on in two passes because the worker has to parse the request before it can know which operation's limits to use, and parsing is the first thing it does with attacker-influenced bytes — so the cell's maximums go on at a point that needs no parsing at all.
There is deliberately no shutdown hook. The exit! is the point, and a hook would invite cleanup code that is then skipped.
Constant Summary collapse
- DISPATCH_BYTES =
1024
Instance Method Summary collapse
-
#initialize(slot:, configuration:, control:, log:) ⇒ Worker
constructor
A new instance of Worker.
-
#run ⇒ Object
exit! rather than exit, so that no finalizer and no library teardown ever runs.
Constructor Details
#initialize(slot:, configuration:, control:, log:) ⇒ Worker
Returns a new instance of Worker.
17 18 19 20 21 22 23 24 |
# File 'lib/hot_cell/worker.rb', line 17 def initialize(slot:, configuration:, control:, log:) @slot = slot @configuration = configuration @control = control @log = log @booted = nil @effective = {} end |
Instance Method Details
#run ⇒ Object
exit! rather than exit, so that no finalizer and no library teardown ever runs. There is deliberately no shutdown hook: the exit! is the point, and a hook would invite cleanup code that is then skipped.
A non-zero status for anything unexpected, because the supervisor holds the connection and is the only thing that can answer for a worker that died mid-request. Exiting zero here would leave a caller reading a closed socket with no verdict at all.
The one deliberate rescue Exception in this repository. Not for the exit status — Ruby's own handler
would also exit non-zero — but for Failure.sanitize. Left to Ruby, a NoMemoryError or a SystemStackError
prints its message and backtrace to stderr unsanitized, and in this process that message can carry bytes
derived from a hostile file. sanitize forces UTF-8, scrubs invalid sequences and truncates; stderr is the
one path out of a cell that would otherwise skip it, which is how an unscrubbed byte sequence reaches a
log row and poisons it.
It swallows nothing: exit! 1 runs whatever was caught.
41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
# File 'lib/hot_cell/worker.rb', line 41 def run configuration.limits.apply ENV["HOME"] = slot.home while (dispatch = await_dispatch) serve(*dispatch) end exit! 0 rescue Exception => error log.write "worker.crashed", pid: Process.pid, slot: slot.number, error: error.class.name, message: Failure.sanitize(error.) exit! 1 end |