Compare commits
No commits in common. "6976fe1e4d4b939a008768e5b4e37db82c839435" and "a668a966693470725cfe0b6609cf697d5d08d35c" have entirely different histories.
6976fe1e4d
...
a668a96669
|
@ -1,5 +1,3 @@
|
|||
ssh/*
|
||||
image/*
|
||||
!**/.gitkeep
|
||||
.idea
|
||||
nim/qsandbox
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# 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
|
||||
|
||||
|
|
12
build.sh
12
build.sh
|
@ -1,8 +1,7 @@
|
|||
#!/bin/bash
|
||||
# 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
|
||||
image=image/image.raw
|
||||
mountpoint=image/arch
|
||||
|
@ -15,7 +14,6 @@ mkdir -p $mountpoint
|
|||
mkdir -p ssh
|
||||
|
||||
qemu-img create -f raw $image 20G
|
||||
|
||||
loop="$(sudo losetup --show -f -P $image)"
|
||||
sudo mkfs.ext4 "$loop"
|
||||
sudo mount "$loop" "$mountpoint"
|
||||
|
@ -26,14 +24,16 @@ key="$(cat ssh/qemu_ssh.pub)"
|
|||
sudo "$mountpoint/bin/arch-chroot" "$mountpoint" /bin/bash <<EOL
|
||||
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 --populate archlinux
|
||||
|
||||
pacman -Syu --noconfirm
|
||||
pacman -S --noconfirm base linux linux-firmware mkinitcpio openssh kitty-terminfo dhcpcd
|
||||
systemctl enable sshd dhcpcd
|
||||
pacman -S --noconfirm base linux linux-firmware mkinitcpio dhcpcd dropbear kitty-terminfo
|
||||
systemctl enable dhcpcd dropbear
|
||||
|
||||
dropbearkey -t ed25519 -f /etc/dropbear/dropbear_ed25519_host_key
|
||||
|
||||
# Standard Archlinux Setup
|
||||
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()
|
Loading…
Reference in New Issue