Class: Mountfd::UserNamespace

Inherits:
Object
  • Object
show all
Defined in:
lib/mountfd/user_namespace.rb,
sig/mountfd.rbs

Constant Summary collapse

MAX_RANGES =
340

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(handle) ⇒ UserNamespace

Returns a new instance of UserNamespace.



76
77
78
# File 'lib/mountfd/user_namespace.rb', line 76

def initialize(handle)
  @handle = handle
end

Class Method Details

.create(uid: {0 => Process.uid}, gid: {0 => Process.gid}, helper: :auto) ⇒ UserNamespace

Parameters:

  • uid: (Object) (defaults to: {0 => Process.uid})
  • gid: (Object) (defaults to: {0 => Process.gid})
  • helper: (:auto, bool) (defaults to: :auto)

Returns:



7
8
9
10
11
12
13
14
15
16
17
18
# File 'lib/mountfd/user_namespace.rb', line 7

def self.create(uid: {0 => Process.uid}, gid: {0 => Process.gid}, helper: :auto)
  uid_map = normalize(uid)
  gid_map = normalize(gid)
  use_helper = case helper
               when :auto then helpers_available? && !Process.euid.zero?
               when true, false then helper
               else raise ArgumentError, "helper must be :auto, true, or false"
               end
  new(Native.user_namespace(format(uid_map), format(gid_map), use_helper))
rescue SystemCallError => error
  raise IdmapError, "user namespace: #{error.message}", cause: error
end

.from_path(path) ⇒ UserNamespace

Parameters:

  • path (String)

Returns:



21
# File 'lib/mountfd/user_namespace.rb', line 21

def self.from_path(path) = new(Native.open_handle(File.path(path)))

.from_pid(pid) ⇒ UserNamespace

Parameters:

  • pid (Integer)

Returns:



20
# File 'lib/mountfd/user_namespace.rb', line 20

def self.from_pid(pid) = from_path("/proc/#{Integer(pid)}/ns/user")

.normalize(mapping) ⇒ Array[[Integer, Integer, Integer]]

Parameters:

  • mapping (Object)

Returns:

  • (Array[[Integer, Integer, Integer]])

Raises:

  • (ArgumentError)


23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/mountfd/user_namespace.rb', line 23

def self.normalize(mapping)
  ranges = if mapping.is_a?(Hash)
             mapping.map do |inside, outside|
               if outside.is_a?(Array) && outside.length != 2
                 raise ArgumentError, "hash mapping values must be an ID or [ID, length]"
               end
               outside, length = outside.is_a?(Array) ? outside : [outside, 1]
               [inside, outside, length]
             end
           elsif mapping.is_a?(Array) && mapping.length == 3 && mapping.none? { _1.is_a?(Array) }
             [mapping]
           else
             Array(mapping)
           end
  ranges = ranges.map do |range|
    raise ArgumentError, "each namespace mapping must contain three integers" unless range.is_a?(Array) && range.length == 3

    range.map { Integer(_1) }
  end.sort_by(&:first)
  raise ArgumentError, "a namespace mapping requires at least one range" if ranges.empty?
  raise ArgumentError, "namespace mappings are limited to #{MAX_RANGES} ranges" if ranges.length > MAX_RANGES

  ranges.each do |inside, outside, length|
    raise ArgumentError, "mapping IDs must be non-negative" if inside.negative? || outside.negative?
    raise ArgumentError, "mapping length must be positive" unless length.positive?
    if inside + length > 2**32 || outside + length > 2**32
      raise ArgumentError, "mapping ranges must fit unsigned 32-bit IDs"
    end
  end
  validate_non_overlapping!(ranges, 0, "inside")
  validate_non_overlapping!(ranges, 1, "outside")
  ranges
end

Instance Method Details

#closenil

Returns:

  • (nil)


82
# File 'lib/mountfd/user_namespace.rb', line 82

def close = @handle.close

#closed?Boolean

Returns:

  • (Boolean)


81
# File 'lib/mountfd/user_namespace.rb', line 81

def closed? = @handle.closed?

#filenoInteger

Returns:

  • (Integer)


80
# File 'lib/mountfd/user_namespace.rb', line 80

def fileno = @handle.fileno