libshit

Just some random shit
git clone https://git.neptards.moe/neptards/libshit.git
Log | Files | Refs | Submodules | README | LICENSE

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