Compare commits
	
		
			No commits in common. "6976fe1e4d4b939a008768e5b4e37db82c839435" and "a668a966693470725cfe0b6609cf697d5d08d35c" have entirely different histories.
		
	
	
		
			6976fe1e4d
			...
			a668a96669
		
	
		
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -1,5 +1,3 @@
 | 
				
			|||||||
ssh/*
 | 
					ssh/*
 | 
				
			||||||
image/*
 | 
					image/*
 | 
				
			||||||
!**/.gitkeep
 | 
					!**/.gitkeep
 | 
				
			||||||
.idea
 | 
					 | 
				
			||||||
nim/qsandbox
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
# qemu-sandbox
 | 
					# qemu-sandbox
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PoC shell sandboxing using QEMU and virtiofsd. Simply enter  `qsandbox run` to open your current working dir in a temporary QEMU vm.
 | 
					PoC shell sandboxing using QEMU and virtiofsd. Just enter `qsandbox run` to open your current working dir in a temporary QEMU vm.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Installation
 | 
					## Installation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										12
									
								
								build.sh
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								build.sh
									
									
									
									
									
								
							@ -1,8 +1,7 @@
 | 
				
			|||||||
#!/bin/bash
 | 
					#!/bin/bash
 | 
				
			||||||
# Based on https://blog.stefan-koch.name/2020/05/31/automation-archlinux-qemu-installation
 | 
					# Based on https://blog.stefan-koch.name/2020/05/31/automation-archlinux-qemu-installation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
src="https://mirror.rackspace.com/archlinux/iso/2021.11.01/archlinux-bootstrap-2021.11.01-x86_64.tar.gz"
 | 
					src=https://ftp.halifax.rwth-aachen.de/archlinux/iso/2021.11.01/archlinux-bootstrap-2021.11.01-x86_64.tar.gz
 | 
				
			||||||
 | 
					 | 
				
			||||||
archive=image/archlinux.tar.gz
 | 
					archive=image/archlinux.tar.gz
 | 
				
			||||||
image=image/image.raw
 | 
					image=image/image.raw
 | 
				
			||||||
mountpoint=image/arch
 | 
					mountpoint=image/arch
 | 
				
			||||||
@ -15,7 +14,6 @@ mkdir -p $mountpoint
 | 
				
			|||||||
mkdir -p ssh
 | 
					mkdir -p ssh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
qemu-img create -f raw $image 20G
 | 
					qemu-img create -f raw $image 20G
 | 
				
			||||||
 | 
					 | 
				
			||||||
loop="$(sudo losetup --show -f -P $image)"
 | 
					loop="$(sudo losetup --show -f -P $image)"
 | 
				
			||||||
sudo mkfs.ext4 "$loop"
 | 
					sudo mkfs.ext4 "$loop"
 | 
				
			||||||
sudo mount "$loop" "$mountpoint"
 | 
					sudo mount "$loop" "$mountpoint"
 | 
				
			||||||
@ -26,14 +24,16 @@ key="$(cat ssh/qemu_ssh.pub)"
 | 
				
			|||||||
sudo "$mountpoint/bin/arch-chroot" "$mountpoint" /bin/bash <<EOL
 | 
					sudo "$mountpoint/bin/arch-chroot" "$mountpoint" /bin/bash <<EOL
 | 
				
			||||||
set -v
 | 
					set -v
 | 
				
			||||||
 | 
					
 | 
				
			||||||
echo 'Server = https://mirror.rackspace.com/archlinux/\$repo/os/\$arch' >> /etc/pacman.d/mirrorlist
 | 
					echo 'Server = http://ftp.uni-bayreuth.de/linux/archlinux/\$repo/os/\$arch' >> /etc/pacman.d/mirrorlist
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pacman-key --init
 | 
					pacman-key --init
 | 
				
			||||||
pacman-key --populate archlinux
 | 
					pacman-key --populate archlinux
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pacman -Syu --noconfirm
 | 
					pacman -Syu --noconfirm
 | 
				
			||||||
pacman -S --noconfirm base linux linux-firmware mkinitcpio openssh kitty-terminfo dhcpcd
 | 
					pacman -S --noconfirm base linux linux-firmware mkinitcpio dhcpcd dropbear kitty-terminfo
 | 
				
			||||||
systemctl enable sshd dhcpcd
 | 
					systemctl enable dhcpcd dropbear
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					dropbearkey -t ed25519 -f /etc/dropbear/dropbear_ed25519_host_key
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Standard Archlinux Setup
 | 
					# Standard Archlinux Setup
 | 
				
			||||||
ln -sf /usr/share/zoneinfo/Europe/Berlin /etc/localtime
 | 
					ln -sf /usr/share/zoneinfo/Europe/Berlin /etc/localtime
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +0,0 @@
 | 
				
			|||||||
ip address add 10.0.2.15/24 broadcast + dev ens3
 | 
					 | 
				
			||||||
ip link set dev ens3 up
 | 
					 | 
				
			||||||
ip route add 10.0.2.0/24 dev ens3
 | 
					 | 
				
			||||||
ip route add default via 10.0.2.2 dev ens3
 | 
					 | 
				
			||||||
@ -1 +0,0 @@
 | 
				
			|||||||
nim rewrite, wip
 | 
					 | 
				
			||||||
@ -1,16 +0,0 @@
 | 
				
			|||||||
import std/strformat
 | 
					 | 
				
			||||||
import std/parseopt
 | 
					 | 
				
			||||||
import os
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
proc help*(args: OptParser) =
 | 
					 | 
				
			||||||
  let bin = lastPathPart(getAppFilename())
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  echo "qsandbox - temporary sandboxes using qemu"
 | 
					 | 
				
			||||||
  echo ""
 | 
					 | 
				
			||||||
  echo "Usage:"
 | 
					 | 
				
			||||||
  echo &"   {bin} run   - start sandbox and mount current working dir"
 | 
					 | 
				
			||||||
  echo &"   {bin} list  - list running sandboxes"
 | 
					 | 
				
			||||||
  echo &"   {bin} enter - open ssh connection to a sandbox"
 | 
					 | 
				
			||||||
  echo &"   {bin} qemu  - start the qemu process for a new sandbox, used by run"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  quit(0)
 | 
					 | 
				
			||||||
@ -1,4 +0,0 @@
 | 
				
			|||||||
import std/parseopt
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
proc list*(args: OptParser) =
 | 
					 | 
				
			||||||
  echo "list"
 | 
					 | 
				
			||||||
@ -1,97 +0,0 @@
 | 
				
			|||||||
import strformat
 | 
					 | 
				
			||||||
import parseopt
 | 
					 | 
				
			||||||
import osproc
 | 
					 | 
				
			||||||
import posix
 | 
					 | 
				
			||||||
import linux
 | 
					 | 
				
			||||||
import os
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# should be in the linux module but seems to be missing
 | 
					 | 
				
			||||||
const CLONE_NEWUSER = 0x10000000'i32
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# c bindings
 | 
					 | 
				
			||||||
proc unshare(flag: cint): cint {.importc, header: "<sched.h>"}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
proc mount(source: cstring, target: cstring, filesystemtype: cstring,
 | 
					 | 
				
			||||||
           mountflags: culong, data: pointer): cint {.importc, header:"<sys/mount.h>"}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const
 | 
					 | 
				
			||||||
  UID_MAP = "/proc/self/uid_map"
 | 
					 | 
				
			||||||
  GID_MAP = "/proc/self/gid_map"
 | 
					 | 
				
			||||||
  SETGROUPS = "/proc/self/setgroups"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
proc virtiofsd(paths: seq[string]): Pid =
 | 
					 | 
				
			||||||
  let uid = getuid()
 | 
					 | 
				
			||||||
  let gid = getgid()
 | 
					 | 
				
			||||||
  let pid = fork()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if pid < 0:
 | 
					 | 
				
			||||||
    raise newException(OSError, "Fork failed")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if pid > 0:
 | 
					 | 
				
			||||||
    # we are the parent
 | 
					 | 
				
			||||||
    return pid
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  # create new mount namespace
 | 
					 | 
				
			||||||
  if unshare(CLONE_NEWUSER or CLONE_NEWNS) != 0:
 | 
					 | 
				
			||||||
    raise newException(OSError, "Unshare failed")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  # map our uid to root
 | 
					 | 
				
			||||||
  writeFile(UID_MAP, &"0 {uid} 1")
 | 
					 | 
				
			||||||
  writeFile(SETGROUPS, "deny")
 | 
					 | 
				
			||||||
  writeFile(GID_MAP, &"0 {gid} 1")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  # create a tmpfs in /var/run so virtiofsd can write there
 | 
					 | 
				
			||||||
  if mount(cstring("tmpfs"), cstring("/var/run"), cstring("tmpfs"), 0, cstring("")) != 0:
 | 
					 | 
				
			||||||
    raise newException(OSError, "Mount failed")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  # start a virtiofsd process for each mount
 | 
					 | 
				
			||||||
  var procs {.threadvar.}: seq[Process]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  for i, path in paths:
 | 
					 | 
				
			||||||
    procs.add(startProcess(
 | 
					 | 
				
			||||||
      command = "/usr/lib/qemu/virtiofsd",
 | 
					 | 
				
			||||||
      args = @[&"--socket-path=/tmp/mount.{i}.sock", "-o", &"source={path}"],
 | 
					 | 
				
			||||||
      options = {poParentStreams}
 | 
					 | 
				
			||||||
    ))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  onSignal(SIGTERM):
 | 
					 | 
				
			||||||
    for process in procs:
 | 
					 | 
				
			||||||
      terminate(process)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    quit(0)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  for process in procs:
 | 
					 | 
				
			||||||
    discard waitForExit(process)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  quit(0)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
proc qemu*(args: OptParser) =
 | 
					 | 
				
			||||||
  let childPid = virtiofsd(@["/tmp", "/home"])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  let args = @[
 | 
					 | 
				
			||||||
    "-enable-kvm", "-cpu", "host", "-m", "512m", "-smp", "2",
 | 
					 | 
				
			||||||
    "-kernel", "/home/martin/code/qemu/build-image/image/vmlinuz-linux",
 | 
					 | 
				
			||||||
    "-append", "earlyprintk=ttyS0 console=ttyS0 root=/dev/vda rw quiet",
 | 
					 | 
				
			||||||
    "-initrd" , "/home/martin/code/qemu/build-image/image/initramfs-linux-custom.img",
 | 
					 | 
				
			||||||
    "-m", "4G", "-object", "memory-backend-file,id=mem,size=4G,mem-path=/dev/shm,share=on", "-numa", "node,memdev=mem",
 | 
					 | 
				
			||||||
    "-device", "virtio-rng-pci",
 | 
					 | 
				
			||||||
    "-bios", "/usr/share/qemu/qboot.rom",
 | 
					 | 
				
			||||||
    "-drive", "if=virtio,file=/home/martin/code/qemu/build-image/image/image.qcow2",
 | 
					 | 
				
			||||||
    "-netdev", "user,id=net0,hostfwd=tcp::2222-:22",
 | 
					 | 
				
			||||||
    "-device", "virtio-net-pci,netdev=net0",
 | 
					 | 
				
			||||||
    "-nodefaults", "-no-user-config", "-nographic",
 | 
					 | 
				
			||||||
    "-chardev", "socket,id=share.1,path=/tmp/mount.0.sock",
 | 
					 | 
				
			||||||
    "-device", "vhost-user-fs-pci,queue-size=1024,chardev=share.1,tag=share.1",
 | 
					 | 
				
			||||||
    "-serial", "stdio"
 | 
					 | 
				
			||||||
  ]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  let qemu = startProcess(
 | 
					 | 
				
			||||||
    command = "qemu-system-x86_64",
 | 
					 | 
				
			||||||
    options = {poParentStreams, poUsePath},
 | 
					 | 
				
			||||||
    args = args
 | 
					 | 
				
			||||||
  )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  discard waitForExit(qemu)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  discard kill(childPid, SIGTERM)
 | 
					 | 
				
			||||||
  discard waitPid(childPid,cast[var cint](nil),0)
 | 
					 | 
				
			||||||
@ -1,4 +0,0 @@
 | 
				
			|||||||
import std/parseopt
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
proc run*(args: OptParser) =
 | 
					 | 
				
			||||||
  echo "Run"
 | 
					 | 
				
			||||||
@ -1,4 +0,0 @@
 | 
				
			|||||||
import std/parseopt
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
proc ssh*(args: OptParser) =
 | 
					 | 
				
			||||||
  echo "ssh"
 | 
					 | 
				
			||||||
@ -1,34 +0,0 @@
 | 
				
			|||||||
import parseopt
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import commands/help
 | 
					 | 
				
			||||||
import commands/list
 | 
					 | 
				
			||||||
import commands/qemu
 | 
					 | 
				
			||||||
import commands/run
 | 
					 | 
				
			||||||
import commands/ssh
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
proc cmd (options: OptParser) =
 | 
					 | 
				
			||||||
  case options.key:
 | 
					 | 
				
			||||||
    of "qemu":
 | 
					 | 
				
			||||||
      qemu(options)
 | 
					 | 
				
			||||||
    of "run":
 | 
					 | 
				
			||||||
      run(options)
 | 
					 | 
				
			||||||
    of "ssh":
 | 
					 | 
				
			||||||
      ssh(options)
 | 
					 | 
				
			||||||
    of "list":
 | 
					 | 
				
			||||||
      list(options)
 | 
					 | 
				
			||||||
    else:
 | 
					 | 
				
			||||||
      help(options)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
proc main () =
 | 
					 | 
				
			||||||
  var options = initOptParser()
 | 
					 | 
				
			||||||
  options.next()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  case options.kind
 | 
					 | 
				
			||||||
  of cmdEnd: help(options)
 | 
					 | 
				
			||||||
  of cmdShortOption, cmdLongOption:
 | 
					 | 
				
			||||||
    echo "Unkown argument"
 | 
					 | 
				
			||||||
    quit(1)
 | 
					 | 
				
			||||||
  of cmdArgument:
 | 
					 | 
				
			||||||
    cmd(options)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
main()
 | 
					 | 
				
			||||||
							
								
								
									
										2
									
								
								qsandbox
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								qsandbox
									
									
									
									
									
								
							@ -82,6 +82,8 @@ function run {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  tmp_dir="$(mktemp -d --suffix=.qemu)"
 | 
					  tmp_dir="$(mktemp -d --suffix=.qemu)"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  echo "$work_dir"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  echo "$ssh_port" > "$tmp_dir/ssh"
 | 
					  echo "$ssh_port" > "$tmp_dir/ssh"
 | 
				
			||||||
  echo "$ssh_port" > "$tmp_dir/app"
 | 
					  echo "$ssh_port" > "$tmp_dir/app"
 | 
				
			||||||
  echo "$work_dir" > "$tmp_dir/work_dir"
 | 
					  echo "$work_dir" > "$tmp_dir/work_dir"
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user