Compare commits

..

No commits in common. "6976fe1e4d4b939a008768e5b4e37db82c839435" and "a668a966693470725cfe0b6609cf697d5d08d35c" have entirely different histories.

12 changed files with 9 additions and 173 deletions

2
.gitignore vendored
View File

@ -1,5 +1,3 @@
ssh/* ssh/*
image/* image/*
!**/.gitkeep !**/.gitkeep
.idea
nim/qsandbox

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -1 +0,0 @@
nim rewrite, wip

View File

@ -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)

View File

@ -1,4 +0,0 @@
import std/parseopt
proc list*(args: OptParser) =
echo "list"

View File

@ -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)

View File

@ -1,4 +0,0 @@
import std/parseopt
proc run*(args: OptParser) =
echo "Run"

View File

@ -1,4 +0,0 @@
import std/parseopt
proc ssh*(args: OptParser) =
echo "ssh"

View File

@ -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()

View File

@ -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"