Module: SeccompTools::Dumper

Defined in:
lib/seccomp-tools/dumper.rb

Overview

Dump seccomp-bpf using ptrace of binary.

Defined Under Namespace

Classes: Handler

Constant Summary collapse

SUPPORTED =

Whether the dumper is supported. Dumper works based on ptrace, so we need the platform to be Linux.

OS.linux?

Class Method Summary collapse

Class Method Details

.dump(*args, limit: 1, timeout: nil) {|bpf, arch| ... } ⇒ Array<Object>, Array<String>

Main bpf dump function. Yields seccomp bpf whenever a prctl(SET_SECCOMP) call is found.

Examples:

dump('ls', '-l', '-a')
#=> []
dump('spec/binary/twctf-2016-diary') { |c| c[0, 10] }
#=> [" \x00\x00\x00\x00\x00\x00\x00\x15\x00"]

Parameters:

  • args (Array<String>)

    The command to be executed, i.e. the target executable followed by its arguments.

  • limit (Integer) (defaults to: 1)

    By default, dump will only dump the first SET_SECCOMP call. Set limit to the number of calling prctl(SET_SECCOMP) then the child process will be killed when number of calling prctl reaches limit.

    Negative number for unlimited.

  • timeout (Float?) (defaults to: nil)

    Number of seconds to wait for the target process. When the timeout is reached, the target process is killed and the filters dumped so far are returned. nil for no timeout.

Yield Parameters:

  • bpf (String)

    Seccomp bpf in raw bytes.

  • arch (Symbol?)

    Architecture of the target process, nil when it cannot be determined. See Util.process_arch.

Returns:

  • (Array<Object>, Array<String>)

    One entry per dumped filter: the block's return values when a block is given, otherwise the raw bytes. Empty on a non-Linux platform, where dumping is unsupported.



47
48
49
50
51
52
# File 'lib/seccomp-tools/dumper.rb', line 47

def dump(*args, limit: 1, timeout: nil, &block)
  return [] unless SUPPORTED

  pid = fork { handle_child(*args) }
  Handler.new(pid).handle(limit, timeout: timeout, &block)
end

.dump_by_pid(pid, limit) {|bpf, arch| ... } ⇒ Array<Object>, Array<String>

Dump installed seccomp-bpf of an existing process using PTRACE_SECCOMP_GET_FILTER.

Dump the installed seccomp-bpf from a running process. This is achieved by the ptrace command PTRACE_SECCOMP_GET_FILTER, which needs CAP_SYS_ADMIN capability.

Examples:

pid1 = Process.spawn('sleep inf')
dump_by_pid(pid1, 1)
# empty because there is no seccomp installed
#=> []
pid2 = Process.spawn('spec/binary/twctf-2016-diary')
# give it some time to install the filter
sleep(1)
dump_by_pid(pid2, 1) { |c| c[0, 10] }
#=> [" \x00\x00\x00\x00\x00\x00\x00\x15\x00"]

Parameters:

  • pid (Integer)

    Target process identifier.

  • limit (Integer)

    Number of filters to dump. Negative number for unlimited.

Yield Parameters:

  • bpf (String)

    Seccomp bpf in raw bytes.

  • arch (Symbol?)

    Architecture of the target process, nil when it cannot be determined. See Util.process_arch.

Returns:

  • (Array<Object>, Array<String>)

    Returns what the block returned. If a block is not given, an array of raw bytes will be returned.

Raises:

  • (Errno::ESRCH)

    Raises when the target process does not exist.

  • (Errno::EPERM)

    Raises the error if not allowed to attach.

  • (Errno::EACCES)

    Raises the error if not allowed to dump (e.g. no CAP_SYS_ADMIN).



204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/seccomp-tools/dumper.rb', line 204

def dump_by_pid(pid, limit, &block)
  return [] unless SUPPORTED

  collect = []
  arch = Util.process_arch(pid)
  Ptrace.attach_and_wait(pid)
  begin
    i = 0
    while limit.negative? || i < limit
      begin
        bpf = Ptrace.seccomp_get_filter(pid, i)
      rescue Errno::ENOENT, Errno::EINVAL
        break
      end
      collect << (block.nil? ? bpf : yield(bpf, arch))
      i += 1
    end
  ensure
    Ptrace.detach(pid)
  end
  collect
end