Class: SeccompTools::Emulator

Inherits:
Object
  • Object
show all
Defined in:
lib/seccomp-tools/emulator.rb

Overview

Runs a seccomp filter against a hypothetical syscall to find out which action it returns.

Instance Method Summary collapse

Constructor Details

#initialize(instructions, sys_nr: nil, args: [], instruction_pointer: nil, arch: nil) ⇒ Emulator

Instantiate a SeccompTools::Emulator object.

All parameters except instructions are optional. A warning is shown when uninitialized data is accessed.

Parameters:

  • instructions (Array<Instruction::Base>)

    The filter to be emulated, as returned by SeccompTools::Disasm.to_bpf(raw, arch).map(&:inst).

  • sys_nr (Integer?) (defaults to: nil)

    Syscall number.

  • args (Array<Integer>) (defaults to: [])

    Syscall arguments.

  • instruction_pointer (Integer?) (defaults to: nil)

    Program counter address when this syscall is invoked.

  • arch (Symbol?) (defaults to: nil)

    Defaults to the system architecture when not provided.

    See Util.supported_archs for list of supported architectures.



23
24
25
26
27
28
29
30
31
32
# File 'lib/seccomp-tools/emulator.rb', line 23

def initialize(instructions, sys_nr: nil, args: [], instruction_pointer: nil, arch: nil)
  @instructions = instructions
  @sys_nr = sys_nr
  @args = args
  @ip = instruction_pointer
  arch ||= Util.system_arch
  @arch = audit(arch)
  # On a big-endian architecture the high 32-bit word of a 64-bit field comes first.
  @big_endian = Const::Endian.big?(arch)
end

Instance Method Details

#run {|values| ... } ⇒ {Symbol, Integer => Integer}

Run emulation!

Executes the filter until it returns, then reports the final machine state.

Examples:

insts = SeccompTools::Disasm.to_bpf(raw, :amd64).map(&:inst)
SeccompTools::Emulator.new(insts, sys_nr: 0).run[:ret]
#=> 2147418112 # SECCOMP_RET_ALLOW

Yield Parameters:

  • values ({Symbol, Integer => Integer})

    If a block is given, it is invoked before each instruction with the current machine state.

Returns:

  • ({Symbol, Integer => Integer})

    The final state: :ret is the action the filter returned, :pc the line it returned from, :a and :x the registers, and Integer keys the scratch memory slots.



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/seccomp-tools/emulator.rb', line 46

def run
  @values = { pc: 0, a: 0, x: 0 }
  loop do
    yield(@values) if block_given?
    inst = @instructions[pc]
    op, *args = inst.symbolize
    case op
    when :ret then ret(args.first) # ret
    when :ld then ld(args[0], args[1]) # ld/ldx
    when :st then st(args[0], args[1]) # st/stx
    when :jmp then jmp(args[0]) # directly jmp
    when :cmp then cmp(*args[0, 4]) # jmp with comparison
    when :alu then alu(args[0], args[1]) # alu
    when :misc then misc(args[0]) # misc: txa/tax
    end
    break if @values[:ret] # break when returned

    set(:pc, get(:pc) + 1) if %i[ld st alu misc].include?(op)
  end
  @values
end