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 be Linux.

OS.linux?

Class Method Summary collapse

Class Method Details

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

TODO:

timeout option.

Main bpf dump function. Yield seccomp bpf whenever find a prctl(SET_SECCOMP) call.

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 arguments for target execution file.

  • 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.

Yield Parameters:

  • bpf (String)

    Seccomp bpf in raw bytes.

  • arch (Symbol)

    Architecture of the target process.

Returns:

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

    Return the block returned. If block is not given, array of raw bytes will be returned.



42
43
44
45
46
47
# File 'lib/seccomp-tools/dumper.rb', line 42

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

  pid = fork { handle_child(*args) }
  Handler.new(pid).handle(limit, &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 (always nil right now).

Returns:

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

    Return the block returned. If block is not given, 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).



173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/seccomp-tools/dumper.rb', line 173

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

  collect = []
  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, nil))
      i += 1
    end
  ensure
    Ptrace.detach(pid)
  end
  collect
end