You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
libshit/tools/chroot_user.rb

110 lines
2.7 KiB
Ruby

#! /usr/bin/env ruby
# frozen_string_literal: true
require 'set'
require_relative 'linux'
include Linux
UID = 1000
GID = 1000
def eerror str; $stderr.puts " \e[31;1m*\e[0m #{str}"; end
if Process.uid != 0 && Process.uid != UID
eerror "Invalid uid #{Process.uid} - expected 0 or #{UID}"
exit 1
end
if Process.gid != 0 && Process.gid != GID
eerror "Invalid gid #{Process.gid} - expected 0 or #{GID}"
exit 1
end
path = __dir__
while path.size > 1 && !Dir.exist?(File.join(path, 'home'))
path = File.dirname path
end
if path.size <= 1
eerror "Can't find chroot root"
exit 1
end
Dir.chdir path
# not yet: CLONE_NEWNET
pra,pwa = IO.pipe
prb,pwb = IO.pipe
pid = clone CLONE_NEWNS | CLONE_NEWCGROUP | CLONE_NEWUTS | CLONE_NEWIPC |
CLONE_NEWUSER | CLONE_NEWPID do
pra.close
pwb.close
# map to build user/. We do this in the parent process, so it works if we
# execute this script as root.
# uid_gid_map UID, GID, pid
pwa.close
prb.read 1
prb.close
Process::Sys.setuid UID
Process::Sys.setgid GID
Linux.hostname = 'build'
Linux.domainname = 'no.such.domain'
mount nil, '/', nil, MS_PRIVATE | MS_REC
# fs jail
mount '.', 'mnt', nil, MS_BIND | MS_REC
mount 'home/build', 'mnt/home/build', nil, MS_BIND
mount '/etc/resolv.conf', 'mnt/etc/resolv.conf', nil, MS_BIND
mount 'none', 'mnt/proc', 'proc', MS_NOSUID | MS_NODEV
# linux is being retarded as usual https://lwn.net/Articles/647757/
# this is how would someone mount the full sysfs, but it contains shittons of
# sensitive info, and only wine needs it and only two files (which should be
# const, unless you do cpu hotplug), so just copy that two files into a tmpfs
# begin
# mount 'none', 'mnt/sys', 'sysfs', MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_RDONLY
# rescue Errno::EPERM
# mount '/sys', 'mnt/sys', nil, MS_BIND | MS_REC
# end
mount 'none', 'mnt/sys', 'tmpfs'
FileUtils.mkdir_p 'mnt/sys/devices/system/cpu'
FileUtils.cp '/sys/devices/system/cpu/online', 'mnt/sys/devices/system/cpu/online'
FileUtils.cp '/sys/devices/system/cpu/present', 'mnt/sys/devices/system/cpu/present'
mount 'none', 'mnt/dev/pts', 'devpts'
mount 'none', 'mnt/tmp', 'tmpfs', MS_NOSUID | MS_NODEV
pivot_root 'mnt', 'mnt/mnt'
umount '/mnt', MNT_DETACH | UMOUNT_NOFOLLOW
make_ro Set['/dev/pts', '/home/build', '/proc', '/tmp']
Dir.chdir '/home/build'
env = {
'HOME' => '/home/build',
'USER' => 'build',
'TERM' => ENV['TERM'],
}
exec env, ['/bin/bash', '-'], *ARGV, unsetenv_others: true
fail 'Should not get here'
rescue Exception
puts $!.full_message
exit! 127
end
begin
pwa.close
prb.close
pra.read 1
pra.close
uid_gid_map UID, GID, pid
pwb.close
Process.wait pid
rescue Exception
Process.kill 'KILL', pid
raise
end