Compare commits
	
		
			2 Commits
		
	
	
		
			a668a96669
			...
			6976fe1e4d
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 6976fe1e4d | |||
| d9e5e0c974 | 
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -1,3 +1,5 @@
 | 
				
			|||||||
ssh/*
 | 
					ssh/*
 | 
				
			||||||
image/*
 | 
					image/*
 | 
				
			||||||
!**/.gitkeep
 | 
					!**/.gitkeep
 | 
				
			||||||
 | 
					.idea
 | 
				
			||||||
 | 
					nim/qsandbox
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
# qemu-sandbox
 | 
					# qemu-sandbox
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PoC shell sandboxing using QEMU and virtiofsd. Just enter `qsandbox run` to open your current working dir in a temporary QEMU vm.
 | 
					PoC shell sandboxing using QEMU and virtiofsd. Simply enter  `qsandbox run` to open your current working dir in a temporary QEMU vm.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Installation
 | 
					## Installation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										12
									
								
								build.sh
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								build.sh
									
									
									
									
									
								
							@ -1,7 +1,8 @@
 | 
				
			|||||||
#!/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://ftp.halifax.rwth-aachen.de/archlinux/iso/2021.11.01/archlinux-bootstrap-2021.11.01-x86_64.tar.gz
 | 
					src="https://mirror.rackspace.com/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
 | 
				
			||||||
@ -14,6 +15,7 @@ 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"
 | 
				
			||||||
@ -24,16 +26,14 @@ 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 = http://ftp.uni-bayreuth.de/linux/archlinux/\$repo/os/\$arch' >> /etc/pacman.d/mirrorlist
 | 
					echo 'Server = https://mirror.rackspace.com/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 dhcpcd dropbear kitty-terminfo
 | 
					pacman -S --noconfirm base linux linux-firmware mkinitcpio openssh kitty-terminfo dhcpcd
 | 
				
			||||||
systemctl enable dhcpcd dropbear
 | 
					systemctl enable sshd dhcpcd
 | 
				
			||||||
 | 
					 | 
				
			||||||
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
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										4
									
								
								network.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								network.sh
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					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
									
								
								nim/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								nim/README.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					nim rewrite, wip
 | 
				
			||||||
							
								
								
									
										16
									
								
								nim/commands/help.nim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								nim/commands/help.nim
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					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)
 | 
				
			||||||
							
								
								
									
										4
									
								
								nim/commands/list.nim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								nim/commands/list.nim
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					import std/parseopt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					proc list*(args: OptParser) =
 | 
				
			||||||
 | 
					  echo "list"
 | 
				
			||||||
							
								
								
									
										97
									
								
								nim/commands/qemu.nim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								nim/commands/qemu.nim
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,97 @@
 | 
				
			|||||||
 | 
					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)
 | 
				
			||||||
							
								
								
									
										4
									
								
								nim/commands/run.nim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								nim/commands/run.nim
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					import std/parseopt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					proc run*(args: OptParser) =
 | 
				
			||||||
 | 
					  echo "Run"
 | 
				
			||||||
							
								
								
									
										4
									
								
								nim/commands/ssh.nim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								nim/commands/ssh.nim
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					import std/parseopt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					proc ssh*(args: OptParser) =
 | 
				
			||||||
 | 
					  echo "ssh"
 | 
				
			||||||
							
								
								
									
										34
									
								
								nim/qsandbox.nim
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								nim/qsandbox.nim
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,34 @@
 | 
				
			|||||||
 | 
					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,8 +82,6 @@ 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