Class: OsCtld::ContainerControl::Commands::WithMountns::Runner

Inherits:
Runner
  • Object
show all
Defined in:
lib/osctld/container_control/commands/with_mountns.rb

Constant Summary

Constants inherited from Runner

Runner::LXC_ATTACH_FLAGS

Instance Attribute Summary

Attributes inherited from Runner

#ctid, #log_file, #lxc_home, #network_socket, #pool, #stderr, #stdin, #stdout, #user_home

Instance Method Summary collapse

Methods inherited from Runner

#error, #exitstatus, #initialize, #lxc_attach_command, #lxc_attach_wait, #lxc_attach_wait_for_exit, #lxc_ct, #ok, #reap_interrupted_lxc_attach, #setup_exec_env, #setup_exec_run_env, #system_path, #wait_for_lxc_attachable, #wait_for_lxc_stopped, #wait_for_path, #wait_for_process, #wait_status_exitstatus

Constructor Details

This class inherits a constructor from OsCtld::ContainerControl::Runner

Instance Method Details

#execute(opts) ⇒ Object

Parameters:

  • opts (Hash)

Options Hash (opts):

  • :ns_pid (Integer)
  • :mnt_ns (IO, nil) —

    opened mount namespace

  • :chroot (String, nil)
  • :root_dir (IO, nil) —

    opened chroot directory

  • :switch_to_system (Boolean)
  • :block (Proc)


50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/osctld/container_control/commands/with_mountns.rb', line 50

def execute(opts)
  sys = OsCtl::Lib::Sys.new
  reopened_root_dir = nil

  if opts[:mnt_ns]
    sys.setns_io(opts[:mnt_ns], OsCtl::Lib::Sys::CLONE_NEWNS)
  else
    sys.setns_path(
      File.join('/proc', opts[:ns_pid].to_s, 'ns', 'mnt'),
      OsCtl::Lib::Sys::CLONE_NEWNS
    )
  end

  root_dir = opts[:root_dir]
  if root_dir && opts[:chroot]
    reopened_root_dir = reopen_root_dir(sys, opts[:chroot], root_dir)
    root_dir = reopened_root_dir
  end

  if root_dir
    sys.fchdir_io(root_dir)
    sys.chroot('.')
    Dir.chdir('/')
  elsif opts[:chroot]
    sys.chroot(opts[:chroot])
  end

  if opts[:root_dir] || opts[:chroot]
    # After chroot, we can no longer access syslog logger. Log to stdout
    # instead, which will be picked up by osctld supervisor and sent to
    # syslog from there.
    OsCtl::Lib::Logger.setup(:stdout)
  end

  if opts[:switch_to_system]
    SwitchUser.switch_to_system(
      '',
      opts[:ctrc].ct.root_host_uid,
      opts[:ctrc].ct.root_host_gid,
      '/'
    )
  end

  ok(opts[:block].call)
ensure
  reopened_root_dir&.close
end

#reopen_root_dir(sys, path, expected) ⇒ Object (protected)

A directory descriptor opened before setns retains its original mount reference and cannot see child mounts created only in the target mount namespace. Reopen the path after setns, then bind the new descriptor to the already-authenticated root by device and inode before using it.



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/osctld/container_control/commands/with_mountns.rb', line 104

def reopen_root_dir(sys, path, expected)
  absolute_path = File.absolute_path(path)
  relative_path = absolute_path.delete_prefix('/')
  relative_path = '.' if relative_path.empty?

  namespace_root = File.open('/', File::RDONLY | File::NOFOLLOW)
  root_dir = sys.open_beneath(namespace_root, relative_path)

  actual_stat = root_dir.stat
  expected_stat = expected.stat
  unless actual_stat.dev == expected_stat.dev && actual_stat.ino == expected_stat.ino
    raise Errno::EXDEV, absolute_path
  end

  root_dir
rescue StandardError
  root_dir&.close
  raise
ensure
  namespace_root&.close
end