chroot_user.rb (2799B)
1 #! /usr/bin/env ruby 2 # frozen_string_literal: true 3 4 require 'set' 5 6 require_relative 'linux' 7 include Linux 8 9 UID = 1000 10 GID = 1000 11 12 def eerror str; $stderr.puts " \e[31;1m*\e[0m #{str}"; end 13 14 if Process.uid != 0 && Process.uid != UID 15 eerror "Invalid uid #{Process.uid} - expected 0 or #{UID}" 16 exit 1 17 end 18 if Process.gid != 0 && Process.gid != GID 19 eerror "Invalid gid #{Process.gid} - expected 0 or #{GID}" 20 exit 1 21 end 22 23 path = __dir__ 24 while path.size > 1 && !Dir.exist?(File.join(path, 'home')) 25 path = File.dirname path 26 end 27 if path.size <= 1 28 eerror "Can't find chroot root" 29 exit 1 30 end 31 Dir.chdir path 32 33 # not yet: CLONE_NEWNET 34 pra,pwa = IO.pipe 35 prb,pwb = IO.pipe 36 pid = clone CLONE_NEWNS | CLONE_NEWCGROUP | CLONE_NEWUTS | CLONE_NEWIPC | 37 CLONE_NEWUSER | CLONE_NEWPID do 38 pra.close 39 pwb.close 40 41 # map to build user/. We do this in the parent process, so it works if we 42 # execute this script as root. 43 # uid_gid_map UID, GID, pid 44 pwa.close 45 prb.read 1 46 prb.close 47 Process::Sys.setuid UID 48 Process::Sys.setgid GID 49 50 Linux.hostname = 'build' 51 Linux.domainname = 'no.such.domain' 52 mount nil, '/', nil, MS_PRIVATE | MS_REC 53 54 # fs jail 55 mount '.', 'mnt', nil, MS_BIND | MS_REC 56 mount 'home/build', 'mnt/home/build', nil, MS_BIND 57 mount '/etc/resolv.conf', 'mnt/etc/resolv.conf', nil, MS_BIND 58 mount 'none', 'mnt/proc', 'proc', MS_NOSUID | MS_NODEV 59 60 # linux is being retarded as usual https://lwn.net/Articles/647757/ 61 # this is how would someone mount the full sysfs, but it contains shittons of 62 # sensitive info, and only wine needs it and only two files (which should be 63 # const, unless you do cpu hotplug), so just copy that two files into a tmpfs 64 65 # begin 66 # mount 'none', 'mnt/sys', 'sysfs', MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_RDONLY 67 # rescue Errno::EPERM 68 # mount '/sys', 'mnt/sys', nil, MS_BIND | MS_REC 69 # end 70 71 mount 'none', 'mnt/sys', 'tmpfs' 72 FileUtils.mkdir_p 'mnt/sys/devices/system/cpu' 73 FileUtils.cp '/sys/devices/system/cpu/online', 'mnt/sys/devices/system/cpu/online' 74 FileUtils.cp '/sys/devices/system/cpu/present', 'mnt/sys/devices/system/cpu/present' 75 76 mount 'none', 'mnt/dev/pts', 'devpts' 77 mount 'none', 'mnt/tmp', 'tmpfs', MS_NOSUID | MS_NODEV 78 pivot_root 'mnt', 'mnt/mnt' 79 umount '/mnt', MNT_DETACH | UMOUNT_NOFOLLOW 80 81 make_ro Set['/dev/pts', '/home/build', '/proc', '/tmp'] 82 83 Dir.chdir '/home/build' 84 env = { 85 'HOME' => '/home/build', 86 'USER' => 'build', 87 'TERM' => ENV['TERM'], 88 } 89 exec env, ['/bin/bash', '-'], *ARGV, unsetenv_others: true 90 fail 'Should not get here' 91 rescue Exception 92 puts $!.full_message 93 exit! 127 94 end 95 96 begin 97 pwa.close 98 prb.close 99 pra.read 1 100 pra.close 101 102 uid_gid_map UID, GID, pid 103 pwb.close 104 105 Process.wait pid 106 rescue Exception 107 Process.kill 'KILL', pid 108 raise 109 end