Class: Seccomp::Notify::Request
- Inherits:
-
Object
- Object
- Seccomp::Notify::Request
- Defined in:
- lib/seccomp/notify/request.rb
Instance Attribute Summary collapse
-
#arch ⇒ Object
readonly
Returns the value of attribute arch.
-
#args ⇒ Object
readonly
Returns the value of attribute args.
-
#flags ⇒ Object
readonly
Returns the value of attribute flags.
-
#id ⇒ Object
readonly
Returns the value of attribute id.
-
#instruction_pointer ⇒ Object
readonly
Returns the value of attribute instruction_pointer.
-
#nr ⇒ Object
readonly
Returns the value of attribute nr.
-
#tid ⇒ Object
(also: #pid)
readonly
Returns the value of attribute tid.
Class Method Summary collapse
Instance Method Summary collapse
-
#add_fd!(io, flags: 0, newfd: 0, newfd_flags: 0) ⇒ Integer
Injects an open file descriptor into the target.
-
#allow!(value = 0) ⇒ void
Emulates a successful syscall return.
- #close ⇒ Object
-
#continue!(unsafe: false) ⇒ void
Lets the kernel execute the original syscall.
-
#error!(error = Errno::EPERM) ⇒ void
Emulates a failed syscall return.
-
#initialize(id:, tid:, flags:, nr:, arch:, instruction_pointer:, args:, listener:, sizes:, memory_cache:, memory_cache_mutex:, features:) ⇒ Request
constructor
A new instance of Request.
- #kill!(signal = "KILL") ⇒ Object
- #mark_pointer_read! ⇒ Object
-
#read(address, length) ⇒ String
Reads bytes from target memory and revalidates the notification afterward.
-
#read_sockaddr(address, length) ⇒ Addrinfo
Decodes an AF_INET, AF_INET6, or AF_UNIX socket address.
-
#read_string(address, max: 4096) ⇒ String
(also: #read_cstring)
Reads a NUL-terminated string from target memory.
- #responded? ⇒ Boolean
- #syscall ⇒ Object
- #valid? ⇒ Boolean
Constructor Details
#initialize(id:, tid:, flags:, nr:, arch:, instruction_pointer:, args:, listener:, sizes:, memory_cache:, memory_cache_mutex:, features:) ⇒ Request
Returns a new instance of Request.
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
# File 'lib/seccomp/notify/request.rb', line 19 def initialize(id:, tid:, flags:, nr:, arch:, instruction_pointer:, args:, listener:, sizes:, memory_cache:, memory_cache_mutex:, features:) @id = id @tid = tid @flags = flags @nr = nr @arch = arch @instruction_pointer = instruction_pointer @args = args.freeze @listener = listener @sizes = sizes @features = features @memory = TargetMemory.new(listener, self, memory_cache, memory_cache_mutex) @responded = false @pointer_read = false end |
Instance Attribute Details
#arch ⇒ Object (readonly)
Returns the value of attribute arch.
35 36 37 |
# File 'lib/seccomp/notify/request.rb', line 35 def arch @arch end |
#args ⇒ Object (readonly)
Returns the value of attribute args.
6 7 8 |
# File 'lib/seccomp/notify/request.rb', line 6 def args @args end |
#flags ⇒ Object (readonly)
Returns the value of attribute flags.
6 7 8 |
# File 'lib/seccomp/notify/request.rb', line 6 def flags @flags end |
#id ⇒ Object (readonly)
Returns the value of attribute id.
6 7 8 |
# File 'lib/seccomp/notify/request.rb', line 6 def id @id end |
#instruction_pointer ⇒ Object (readonly)
Returns the value of attribute instruction_pointer.
6 7 8 |
# File 'lib/seccomp/notify/request.rb', line 6 def instruction_pointer @instruction_pointer end |
#nr ⇒ Object (readonly)
Returns the value of attribute nr.
6 7 8 |
# File 'lib/seccomp/notify/request.rb', line 6 def nr @nr end |
#tid ⇒ Object (readonly) Also known as: pid
Returns the value of attribute tid.
6 7 8 |
# File 'lib/seccomp/notify/request.rb', line 6 def tid @tid end |
Class Method Details
.from_binary(binary, listener:, sizes:, memory_cache:, memory_cache_mutex:, features:) ⇒ Object
9 10 11 12 13 14 15 16 17 |
# File 'lib/seccomp/notify/request.rb', line 9 def self.from_binary(binary, listener:, sizes:, memory_cache:, memory_cache_mutex:, features:) id, tid, flags, nr, audit_arch, ip, *args = binary.unpack(Structs::NOTIF_FORMAT) arch = case audit_arch when Constants::AUDIT_ARCH_X86_64 then :x86_64 when Constants::AUDIT_ARCH_AARCH64 then :aarch64 else raise NotSupportedError, "unsupported audit architecture 0x#{audit_arch.to_s(16)}" end new(id:, tid:, flags:, nr:, arch:, instruction_pointer: ip, args:, listener:, sizes:, memory_cache:, memory_cache_mutex:, features:) end |
Instance Method Details
#add_fd!(io, flags: 0, newfd: 0, newfd_flags: 0) ⇒ Integer
Injects an open file descriptor into the target.
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
# File 'lib/seccomp/notify/request.rb', line 103 def add_fd!(io, flags: 0, newfd: 0, newfd_flags: 0) raise NotSupportedError, "SECCOMP_IOCTL_NOTIF_ADDFD is unavailable" unless @features[:addfd] ensure_unresponded! unless [flags, newfd, newfd_flags].all? { |value| value.is_a?(Integer) } && (0..0xffff_ffff).cover?(newfd) raise ArgumentError, "flags and fd values must be unsigned integers" end unless (flags & ~Constants::SECCOMP_ADDFD_FLAG_SETFD).zero? raise ArgumentError, "flags may only contain SECCOMP_ADDFD_FLAG_SETFD" end unless (newfd_flags & ~Constants::O_CLOEXEC).zero? raise ArgumentError, "newfd_flags may only contain O_CLOEXEC" end if (flags & Constants::SECCOMP_ADDFD_FLAG_SETFD).zero? && !newfd.zero? raise ArgumentError, "newfd requires SECCOMP_ADDFD_FLAG_SETFD" end addfd_flags = flags addfd_flags |= Constants::SECCOMP_ADDFD_FLAG_SEND if @features[:addfd_send] buffer = [@id, addfd_flags, io.fileno, newfd, newfd_flags].pack(Structs::ADDFD_FORMAT) injected = Ioctl.call(@listener, Ioctl::NOTIF_ADDFD, buffer) if @features[:addfd_send] @responded = true else allow!(injected) end injected end |
#allow!(value = 0) ⇒ void
This method returns an undefined value.
Emulates a successful syscall return.
81 82 83 |
# File 'lib/seccomp/notify/request.rb', line 81 def allow!(value = 0) respond!(value:, error: 0, flags: 0) end |
#close ⇒ Object
141 142 143 |
# File 'lib/seccomp/notify/request.rb', line 141 def close @memory.close end |
#continue!(unsafe: false) ⇒ void
This method returns an undefined value.
Lets the kernel execute the original syscall.
95 96 97 98 99 |
# File 'lib/seccomp/notify/request.rb', line 95 def continue!(unsafe: false) raise NotSupportedError, "SECCOMP_USER_NOTIF_FLAG_CONTINUE is unavailable" unless @features[:continue] warn("seccomp-notify: continuing after reading target memory is subject to TOCTOU; pass unsafe: true to acknowledge") if @pointer_read && !unsafe respond!(value: 0, error: 0, flags: Constants::SECCOMP_USER_NOTIF_FLAG_CONTINUE) end |
#error!(error = Errno::EPERM) ⇒ void
This method returns an undefined value.
Emulates a failed syscall return.
87 88 89 90 |
# File 'lib/seccomp/notify/request.rb', line 87 def error!(error = Errno::EPERM) errno = Constants.errno_number(error) respond!(value: 0, error: -errno, flags: 0) end |
#kill!(signal = "KILL") ⇒ Object
131 132 133 134 135 |
# File 'lib/seccomp/notify/request.rb', line 131 def kill!(signal = "KILL") ensure_unresponded! Process.kill(signal, @tid) @responded = true end |
#mark_pointer_read! ⇒ Object
137 138 139 |
# File 'lib/seccomp/notify/request.rb', line 137 def mark_pointer_read! @pointer_read = true end |
#read(address, length) ⇒ String
Reads bytes from target memory and revalidates the notification afterward.
62 63 64 |
# File 'lib/seccomp/notify/request.rb', line 62 def read(address, length) @memory.read(address, length) end |
#read_sockaddr(address, length) ⇒ Addrinfo
Decodes an AF_INET, AF_INET6, or AF_UNIX socket address.
75 76 77 |
# File 'lib/seccomp/notify/request.rb', line 75 def read_sockaddr(address, length) @memory.read_sockaddr(address, length) end |
#read_string(address, max: 4096) ⇒ String Also known as: read_cstring
Reads a NUL-terminated string from target memory.
68 69 70 |
# File 'lib/seccomp/notify/request.rb', line 68 def read_string(address, max: 4096) @memory.read_string(address, max:) end |
#responded? ⇒ Boolean
41 42 43 |
# File 'lib/seccomp/notify/request.rb', line 41 def responded? @responded end |
#syscall ⇒ Object
37 38 39 |
# File 'lib/seccomp/notify/request.rb', line 37 def syscall Syscalls.name(@nr, @arch) end |
#valid? ⇒ Boolean
45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/seccomp/notify/request.rb', line 45 def valid? buffer = [@id].pack("Q<") validate_id(Ioctl::NOTIF_ID_VALID, buffer) true rescue Errno::EINVAL begin validate_id(Ioctl::NOTIF_ID_VALID_OLD, buffer) true rescue Errno::ENOENT false end rescue Errno::ENOENT false end |