Class: OsCtl::Lib::Sys

Inherits:
Object
  • Object
show all
Defined in:
lib/libosctl/sys.rb

Defined Under Namespace

Modules: Int

Constant Summary collapse

SYS_OPENAT2 =

vpsAdminOS currently supports x86_64-linux only. Keep the syscall number here until libc exposes an openat2(2) wrapper.

437
O_CLOEXEC =
0x0008_0000
O_DIRECTORY =
0x0001_0000
0x02
0x04
RESOLVE_BENEATH =
0x08
CLONE_NEWNS =
0x00020000
CLONE_NEWUTS =
0x04000000
CLONE_NEWUSER =
0x10000000
CLONE_NEWPID =
0x20000000
CLONE_NEWNET =
0x40000000
CLONE_NEWIPC =
0x08000000
MS_MGC_VAL =
0xc0ed0000
MS_RDONLY =
1
MS_NOSUID =
2
MS_NODEV =
4
MS_NOEXEC =
8
MS_REMOUNT =
32
MS_BIND =
4096
MS_MOVE =
8192
MS_REC =
16_384
MS_PRIVATE =
1 << 18
MS_SLAVE =
1 << 19
MS_SHARED =
1 << 20
SYSLOGNS_MAX_TAG_BYTESIZE =
12

Instance Method Summary collapse

Instance Method Details

#attach_syslogns(pid) ⇒ Object

Parameters:

  • pid (Integer) —

    attach to syslogns of PID



296
297
298
# File 'lib/libosctl/sys.rb', line 296

def attach_syslogns(pid)
  setns_path(File.join('/proc', pid.to_s, 'ns/syslog'), 0)
end

#bind_mount(src, dst) ⇒ Object

Raises:

  • (SystemCallError)


147
148
149
150
151
152
# File 'lib/libosctl/sys.rb', line 147

def bind_mount(src, dst)
  ret = Int.mount(src, dst, 0, MS_MGC_VAL | MS_BIND, 0)
  raise SystemCallError, Fiddle.last_error if ret != 0

  ret
end

#bind_mount_readonly(src, dst) ⇒ Object

Raises:

  • (SystemCallError)


154
155
156
157
158
159
160
161
# File 'lib/libosctl/sys.rb', line 154

def bind_mount_readonly(src, dst)
  bind_mount(src, dst)

  ret = Int.mount('none', dst, 0, MS_MGC_VAL | MS_BIND | MS_REMOUNT | MS_RDONLY, 0)
  raise SystemCallError, Fiddle.last_error if ret != 0

  ret
end

#chroot(path) ⇒ Object

Raises:

  • (SystemCallError)


266
267
268
269
270
271
# File 'lib/libosctl/sys.rb', line 266

def chroot(path)
  ret = Int.chroot(path)
  raise SystemCallError, Fiddle.last_error if ret != 0

  ret
end

#create_syslogns(tag) ⇒ Object

Parameters:

  • tag (String) —

    syslogns tag prepended to all messages

Raises:

  • (SystemCallError)


281
282
283
284
285
286
287
288
289
290
291
292
293
# File 'lib/libosctl/sys.rb', line 281

def create_syslogns(tag)
  if tag.bytesize > SYSLOGNS_MAX_TAG_BYTESIZE
    raise ArgumentError, "tag can have at most #{SYSLOGNS_MAX_TAG_BYTESIZE} bytes"
  end

  klogctl_ret = Int.klogctl(11, tag, tag.bytesize)
  raise SystemCallError, Fiddle.last_error if klogctl_ret != 0

  unshare_ret = Int.unshare(0)
  raise SystemCallError, Fiddle.last_error if unshare_ret != 0

  0
end

#fchdir_io(io) ⇒ Object

Raises:

  • (SystemCallError)


273
274
275
276
277
278
# File 'lib/libosctl/sys.rb', line 273

def fchdir_io(io)
  ret = Int.fchdir(io.fileno)
  raise SystemCallError, Fiddle.last_error if ret != 0

  ret
end

#make_private(dst) ⇒ Object

Raises:

  • (SystemCallError)


198
199
200
201
202
203
# File 'lib/libosctl/sys.rb', line 198

def make_private(dst)
  ret = Int.mount('none', dst, 0, MS_PRIVATE, 0)
  raise SystemCallError, Fiddle.last_error if ret != 0

  ret
end

#make_rprivate(dst) ⇒ Object

Raises:

  • (SystemCallError)


205
206
207
208
209
210
# File 'lib/libosctl/sys.rb', line 205

def make_rprivate(dst)
  ret = Int.mount('none', dst, 0, MS_REC | MS_PRIVATE, 0)
  raise SystemCallError, Fiddle.last_error if ret != 0

  ret
end

#make_rshared(dst) ⇒ Object

Raises:

  • (SystemCallError)


212
213
214
215
216
217
# File 'lib/libosctl/sys.rb', line 212

def make_rshared(dst)
  ret = Int.mount('none', dst, 0, MS_REC | MS_SHARED, 0)
  raise SystemCallError, Fiddle.last_error if ret != 0

  ret
end

#make_rslave(dst) ⇒ Object

Raises:

  • (SystemCallError)


226
227
228
229
230
231
# File 'lib/libosctl/sys.rb', line 226

def make_rslave(dst)
  ret = Int.mount('none', dst, 0, MS_REC | MS_SLAVE, 0)
  raise SystemCallError, Fiddle.last_error if ret != 0

  ret
end

#make_shared(dst) ⇒ Object

Raises:

  • (SystemCallError)


191
192
193
194
195
196
# File 'lib/libosctl/sys.rb', line 191

def make_shared(dst)
  ret = Int.mount('none', dst, 0, MS_SHARED, 0)
  raise SystemCallError, Fiddle.last_error if ret != 0

  ret
end

#make_slave(dst) ⇒ Object

Raises:

  • (SystemCallError)


219
220
221
222
223
224
# File 'lib/libosctl/sys.rb', line 219

def make_slave(dst)
  ret = Int.mount('none', dst, 0, MS_SLAVE, 0)
  raise SystemCallError, Fiddle.last_error if ret != 0

  ret
end

#mount_proc(dst) ⇒ Object

Raises:

  • (SystemCallError)


177
178
179
180
181
182
# File 'lib/libosctl/sys.rb', line 177

def mount_proc(dst)
  ret = Int.mount('none', dst, 'proc', MS_MGC_VAL, 0)
  raise SystemCallError, Fiddle.last_error if ret != 0

  ret
end

#mount_sysfs(dst) ⇒ Object

Raises:

  • (SystemCallError)


184
185
186
187
188
189
# File 'lib/libosctl/sys.rb', line 184

def mount_sysfs(dst)
  ret = Int.mount('none', dst, 'sysfs', MS_NOSUID | MS_NODEV | MS_NOEXEC, 0)
  raise SystemCallError, Fiddle.last_error if ret != 0

  ret
end

#mount_tmpfs(dst, name: 'none', flags: MS_MGC_VAL, options: 0) ⇒ Object

Raises:

  • (SystemCallError)


170
171
172
173
174
175
# File 'lib/libosctl/sys.rb', line 170

def mount_tmpfs(dst, name: 'none', flags: MS_MGC_VAL, options: 0)
  ret = Int.mount(name, dst, 'tmpfs', flags, options)
  raise SystemCallError, Fiddle.last_error if ret != 0

  ret
end

#move_mount(src, dst) ⇒ Object

Raises:

  • (SystemCallError)


140
141
142
143
144
145
# File 'lib/libosctl/sys.rb', line 140

def move_mount(src, dst)
  ret = Int.mount(src, dst, 0, MS_MGC_VAL | MS_MOVE, 0)
  raise SystemCallError, Fiddle.last_error if ret != 0

  ret
end

#namespace_userns(namespace) ⇒ Object

NS_GET_USERNS: query the kernel owner, not a caller-provided namespace.



80
81
82
83
84
# File 'lib/libosctl/sys.rb', line 80

def namespace_userns(namespace)
  io = IO.for_fd(namespace.ioctl(0xb701, 0), autoclose: true)
  io.close_on_exec = true
  io
end

#open_beneath(dir, path, flags: File::RDONLY) ⇒ Object

Open path below an already-open directory without permitting symlink or magic-link traversal. The returned IO owns the new descriptor.

Raises:

  • (SystemCallError)


116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/libosctl/sys.rb', line 116

def open_beneath(dir, path, flags: File::RDONLY)
  relative_path = path.to_s
  if relative_path.empty? || relative_path.start_with?('/') || relative_path.include?("\0")
    raise ArgumentError, 'path has to be a non-empty relative path'
  end

  how = [
    Integer(flags) | O_CLOEXEC | O_DIRECTORY,
    0,
    RESOLVE_BENEATH | RESOLVE_NO_MAGICLINKS | RESOLVE_NO_SYMLINKS
  ].pack('Q<Q<Q<')

  fd = Int.syscall(
    SYS_OPENAT2,
    dir.fileno,
    relative_path,
    how,
    how.bytesize
  )
  raise SystemCallError, Fiddle.last_error if fd < 0

  IO.for_fd(fd, autoclose: true).tap { |io| io.close_on_exec = true }
end

#openat_io(dir, path, flags: File::RDONLY, mode: 0) ⇒ Object

Open a path relative to an already-open directory. Unlike #open_beneath, this helper permits procfs magic links, which are needed to reopen root and namespace descriptors through a retained /proc/ directory after entering another mount namespace.

Raises:

  • (SystemCallError)


101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/libosctl/sys.rb', line 101

def openat_io(dir, path, flags: File::RDONLY, mode: 0)
  relative_path = path.to_s
  if relative_path.empty? || relative_path.start_with?('/') || relative_path.include?("\0") ||
     relative_path.split('/').include?('..')
    raise ArgumentError, 'path has to be a safe relative path'
  end

  fd = Int.openat(dir.fileno, relative_path, Integer(flags) | O_CLOEXEC, Integer(mode))
  raise SystemCallError, Fiddle.last_error if fd < 0

  IO.for_fd(fd, autoclose: true).tap { |io| io.close_on_exec = true }
end

#pidfd_alive?(pidfd) ⇒ Boolean

Returns:

  • (Boolean)


93
94
95
# File 'lib/libosctl/sys.rb', line 93

def pidfd_alive?(pidfd)
  pidfd.wait_readable(0).nil?
end

#pidfd_open(pid) ⇒ Object

Raises:

  • (SystemCallError)


86
87
88
89
90
91
# File 'lib/libosctl/sys.rb', line 86

def pidfd_open(pid)
  fd = Int.pidfd_open(pid, 0)
  raise SystemCallError, Fiddle.last_error if fd < 0

  IO.for_fd(fd, autoclose: true)
end

#rbind_mount(src, dst) ⇒ Object

Raises:

  • (SystemCallError)


163
164
165
166
167
168
# File 'lib/libosctl/sys.rb', line 163

def rbind_mount(src, dst)
  ret = Int.mount(src, dst, 0, MS_MGC_VAL | MS_BIND | MS_REC, 0)
  raise SystemCallError, Fiddle.last_error if ret != 0

  ret
end

#setns_io(io, nstype) ⇒ Object



256
257
258
259
# File 'lib/libosctl/sys.rb', line 256

def setns_io(io, nstype)
  Native.setns(io.fileno, nstype)
  nil
end

#setns_path(path, nstype) ⇒ Object



247
248
249
250
251
252
253
254
# File 'lib/libosctl/sys.rb', line 247

def setns_path(path, nstype)
  f = File.open(path)
  Native.setns(f.fileno, nstype)

  nil
ensure
  f.close if f
end

#setresgid(rgid, egid, sgid) ⇒ Object

Raises:

  • (SystemCallError)


72
73
74
75
76
77
# File 'lib/libosctl/sys.rb', line 72

def setresgid(rgid, egid, sgid)
  ret = Int.setresgid(rgid, egid, sgid)
  raise SystemCallError, Fiddle.last_error if ret != 0

  ret
end

#setresuid(ruid, euid, suid) ⇒ Object

Raises:

  • (SystemCallError)


65
66
67
68
69
70
# File 'lib/libosctl/sys.rb', line 65

def setresuid(ruid, euid, suid)
  ret = Int.setresuid(ruid, euid, suid)
  raise SystemCallError, Fiddle.last_error if ret != 0

  ret
end

#syncfs(path) ⇒ Object

Parameters:

  • path (String) —

    filesystem directory



301
302
303
304
305
306
307
308
309
310
# File 'lib/libosctl/sys.rb', line 301

def syncfs(path)
  f = Tempfile.new('.syncfs', path)
  ret = Int.syncfs(f.fileno)
  raise SystemCallError, Fiddle.last_error if ret != 0

  ret
ensure
  f.close
  f.unlink
end

#unmount(mountpoint) ⇒ Object

Raises:

  • (SystemCallError)


233
234
235
236
237
238
# File 'lib/libosctl/sys.rb', line 233

def unmount(mountpoint)
  ret = Int.umount2(mountpoint, 0) # force unmount returns EACCESS
  raise SystemCallError, Fiddle.last_error if ret != 0

  ret
end

#unmount_lazy(mountpoint) ⇒ Object

Raises:

  • (SystemCallError)


240
241
242
243
244
245
# File 'lib/libosctl/sys.rb', line 240

def unmount_lazy(mountpoint)
  ret = Int.umount2(mountpoint, Int::MNT_DETACH)
  raise SystemCallError, Fiddle.last_error if ret != 0

  ret
end

#unshare_ns(type) ⇒ Object



261
262
263
264
# File 'lib/libosctl/sys.rb', line 261

def unshare_ns(type)
  Native.unshare(type)
  nil
end