Class: SeccompTools::Syscall

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

Overview

Record syscall number, arguments, return value.

Constant Summary collapse

ABI =

Syscall arguments offset of struct user in different arch.

{
  amd64: { number: 120, args: [112, 104, 96, 56, 72, 44], ret: 80, SYS_prctl: 157, SYS_seccomp: 317 },
  i386: { number: 44, args: [0, 4, 8, 12, 16, 20], ret: 24, SYS_prctl: 172, SYS_seccomp: 354 },
  aarch64: { number: 64, args: [0, 8, 16, 24, 32, 40, 48], ret: 0, SYS_prctl: 167, SYS_seccomp: 277 },
  # Most software invokes syscalls through "svc 0", in which case the syscall number is in r1.
  # However, it's also possible to use "svc NR": this case is not handled here.
  s390x: { number: 24, args: [32, 40, 48, 56, 64, 72], ret: 32, SYS_prctl: 172, SYS_seccomp: 348 }
}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(pid) ⇒ Syscall

Instantiate a SeccompTools::Syscall object.

Parameters:

  • pid (String)

    Process-id.

Raises:

  • (ArgumentError)


35
36
37
38
39
40
41
42
43
# File 'lib/seccomp-tools/syscall.rb', line 35

def initialize(pid)
  @pid = pid
  raise ArgumentError, "Only supports #{ABI.keys.join(', ')}" if ABI[arch].nil?

  @abi = ABI[arch]
  @number = peek(abi[:number])
  @args = abi[:args].map { |off| peek(off) }
  @ret = peek(abi[:ret])
end

Instance Attribute Details

#abi{Symbol => Integer, Array<Integer>} (readonly)

Returns See ABI.

Returns:

  • ({Symbol => Integer, Array<Integer>})

    See ABI.



24
25
26
# File 'lib/seccomp-tools/syscall.rb', line 24

def abi
  @abi
end

#argsInteger (readonly)

Returns Syscall arguments.

Returns:

  • (Integer)

    Syscall arguments.



28
29
30
# File 'lib/seccomp-tools/syscall.rb', line 28

def args
  @args
end

#numberInteger (readonly)

Returns Syscall number.

Returns:

  • (Integer)

    Syscall number.



26
27
28
# File 'lib/seccomp-tools/syscall.rb', line 26

def number
  @number
end

#pidInteger (readonly)

Returns Process id.

Returns:

  • (Integer)

    Process id.



22
23
24
# File 'lib/seccomp-tools/syscall.rb', line 22

def pid
  @pid
end

#retInteger (readonly)

Returns Syscall return value.

Returns:

  • (Integer)

    Syscall return value.



30
31
32
# File 'lib/seccomp-tools/syscall.rb', line 30

def ret
  @ret
end

Instance Method Details

#archSymbol

Returns Architecture of this syscall.

Returns:

  • (Symbol)

    Architecture of this syscall.



67
68
69
70
71
72
73
74
75
76
77
# File 'lib/seccomp-tools/syscall.rb', line 67

def arch
  @arch ||= File.open("/proc/#{pid}/exe", 'rb') do |f|
    f.pos = 18
    {
      "\x03\x00" => :i386,
      "\x3e\x00" => :amd64,
      "\xb7\x00" => :aarch64,
      "\x00\x16" => :s390x
    }[f.read(2)]
  end
end

#dump_bpfString

Dump bpf byte from args[2].

Returns:

  • (String)


58
59
60
61
62
63
# File 'lib/seccomp-tools/syscall.rb', line 58

def dump_bpf
  addr = args[2]
  len = Ptrace.peekdata(pid, addr, 0) & 0xffff # len is unsigned short
  filter = Ptrace.peekdata(pid, addr + bits / 8, 0) & ((1 << bits) - 1)
  Array.new(len) { |i| Ptrace.peekdata(pid, filter + i * 8, 0) }.pack('Q*')
end

#set_seccomp?Boolean

Is this a seccomp(SECCOMP_MODE_FILTER, addr)/+prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, addr)+ syscall?

Returns:

  • (Boolean)

    true for is a seccomp installation syscall.



49
50
51
52
53
54
# File 'lib/seccomp-tools/syscall.rb', line 49

def set_seccomp?
  # TODO: handle SECCOMP_MODE_SET_STRICT / SECCOMP_MODE_STRICT
  return true if number == abi[:SYS_seccomp] && args[0] == Const::BPF::SECCOMP_SET_MODE_FILTER

  number == abi[:SYS_prctl] && args[0] == Const::BPF::PR_SET_SECCOMP && args[1] == Const::BPF::SECCOMP_MODE_FILTER
end