Class: Seccomp::Notify::TargetMemory

Inherits:
Object
  • Object
show all
Defined in:
lib/seccomp/notify/target_memory.rb

Constant Summary collapse

PAGE_SIZE =
4096
SOCKADDR_STORAGE_SIZE =
128

Instance Method Summary collapse

Constructor Details

#initialize(listener, request, _cache = nil, _cache_mutex = nil) ⇒ TargetMemory

Returns a new instance of TargetMemory.



12
13
14
15
16
# File 'lib/seccomp/notify/target_memory.rb', line 12

def initialize(listener, request, _cache = nil, _cache_mutex = nil)
  @listener = listener
  @request = request
  @memory = nil
end

Instance Method Details

#closeObject



18
19
20
# File 'lib/seccomp/notify/target_memory.rb', line 18

def close
  @memory&.close unless @memory&.closed?
end

#read(address, length) ⇒ Object



22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/seccomp/notify/target_memory.rb', line 22

def read(address, length)
  raise ArgumentError, "length must be non-negative" if length.negative?

  data = memory.pread(length, address)
  raise MemoryReadError, "short read from target memory" unless data.bytesize == length
  raise StaleNotificationError, "notification is no longer valid" unless @request.valid?

  @request.mark_pointer_read!
  data
rescue EOFError, Errno::EIO, Errno::EFAULT, Errno::ENOENT, Errno::EACCES => error
  raise MemoryReadError, error.message
end

#read_sockaddr(address, length) ⇒ Object

Raises:



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/seccomp/notify/target_memory.rb', line 50

def read_sockaddr(address, length)
  raise MemoryReadError, "sockaddr is shorter than sa_family" if length < 2
  raise MemoryReadError, "sockaddr is longer than sockaddr_storage" if length > SOCKADDR_STORAGE_SIZE

  bytes = read(address, length)
  case bytes.unpack1("S<")
  when Socket::AF_INET
    raise MemoryReadError, "short AF_INET sockaddr" if length < 16
    Addrinfo.tcp(IPAddr.ntop(bytes.byteslice(4, 4)), bytes.byteslice(2, 2).unpack1("n"))
  when Socket::AF_INET6
    raise MemoryReadError, "short AF_INET6 sockaddr" if length < 28
    address = IPAddr.ntop(bytes.byteslice(8, 16))
    scope = bytes.byteslice(24, 4).unpack1("L<")
    address = "#{address}%#{scope}" unless scope.zero?
    Addrinfo.tcp(address, bytes.byteslice(2, 2).unpack1("n"))
  when Socket::AF_UNIX
    raw_path = bytes.byteslice(2..).to_s
    path = raw_path.start_with?("\0") ? raw_path : raw_path.split("\0", 2).first
    Addrinfo.unix(path)
  else
    raise MemoryReadError, "unsupported sockaddr family #{bytes.unpack1("S<")}"
  end
end

#read_string(address, max: PAGE_SIZE) ⇒ Object

Raises:

  • (ArgumentError)


35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/seccomp/notify/target_memory.rb', line 35

def read_string(address, max: PAGE_SIZE)
  raise ArgumentError, "max must be positive" unless max.positive?

  result = +""
  while result.bytesize < max
    length = [PAGE_SIZE - ((address + result.bytesize) % PAGE_SIZE), max - result.bytesize].min
    chunk = read(address + result.bytesize, length)
    nul = chunk.index("\0")
    return result << chunk.byteslice(0, nul) if nul

    result << chunk
  end
  raise MemoryReadError, "NUL terminator not found within #{max} bytes"
end