Compare commits
2 Commits
a668a96669
...
6976fe1e4d
Author | SHA1 | Date |
---|---|---|
Martin | 6976fe1e4d | |
Martin | d9e5e0c974 |
|
@ -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
|
||||||
|
|
|
@ -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
|
|
@ -0,0 +1 @@
|
||||||
|
nim rewrite, wip
|
|
@ -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)
|
|
@ -0,0 +1,4 @@
|
||||||
|
import std/parseopt
|
||||||
|
|
||||||
|
proc list*(args: OptParser) =
|
||||||
|
echo "list"
|
|
@ -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)
|
|
@ -0,0 +1,4 @@
|
||||||
|
import std/parseopt
|
||||||
|
|
||||||
|
proc run*(args: OptParser) =
|
||||||
|
echo "Run"
|
|
@ -0,0 +1,4 @@
|
||||||
|
import std/parseopt
|
||||||
|
|
||||||
|
proc ssh*(args: OptParser) =
|
||||||
|
echo "ssh"
|
|
@ -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…
Reference in New Issue