1
0

Implements executing of commands on qemu system

This commit is contained in:
dump_stack() 2018-09-19 07:00:12 +00:00
parent dfc1f64841
commit 5c31812089
2 changed files with 68 additions and 5 deletions

View File

@ -14,6 +14,8 @@ import (
"os/exec" "os/exec"
"syscall" "syscall"
"time" "time"
"golang.org/x/crypto/ssh"
) )
func readBytesUntilEOF(pipe io.ReadCloser) (buf []byte, err error) { func readBytesUntilEOF(pipe io.ReadCloser) (buf []byte, err error) {
@ -75,7 +77,7 @@ type QemuSystem struct {
stdout io.ReadCloser stdout io.ReadCloser
} }
died bool died bool
sshHostFwd string sshAddrPort string
// accessible after qemu is closed // accessible after qemu is closed
Stdout, Stderr string Stdout, Stderr string
@ -135,15 +137,16 @@ func kvmExists() bool {
// Start qemu process // Start qemu process
func (q *QemuSystem) Start() (err error) { func (q *QemuSystem) Start() (err error) {
rand.Seed(time.Now().UnixNano()) // Are you sure? rand.Seed(time.Now().UnixNano()) // Are you sure?
q.sshHostFwd = fmt.Sprintf("hostfwd=tcp:%s-:22", getFreeAddrPort()) q.sshAddrPort = getFreeAddrPort()
hostfwd := fmt.Sprintf("hostfwd=tcp:%s-:22", q.sshAddrPort)
qemuArgs := []string{"-snapshot", "-nographic", qemuArgs := []string{"-snapshot", "-nographic",
"-hda", q.drivePath, "-hda", q.drivePath,
"-kernel", q.kernel.Path, "-kernel", q.kernel.Path,
"-append", "root=/dev/sda console=ttyS0 rw", "-append", "root=/dev/sda ignore_loglevel console=ttyS0 rw",
"-smp", fmt.Sprintf("%d", q.Cpus), "-smp", fmt.Sprintf("%d", q.Cpus),
"-m", fmt.Sprintf("%d", q.Memory), "-m", fmt.Sprintf("%d", q.Memory),
"-device", "e1000,netdev=n1", "-device", "e1000,netdev=n1",
"-netdev", "user,id=n1," + q.sshHostFwd, "-netdev", "user,id=n1," + hostfwd,
} }
if (q.arch == X86_64 || q.arch == I386) && kvmExists() { if (q.arch == X86_64 || q.arch == I386) && kvmExists() {
@ -197,3 +200,26 @@ func (q *QemuSystem) Stop() {
q.cmd.Process.Signal(syscall.SIGKILL) q.cmd.Process.Signal(syscall.SIGKILL)
} }
} }
// Command executes shell commands on qemu system
func (q *QemuSystem) Command(user, cmd string) (output string, err error) {
cfg := &ssh.ClientConfig{
User: user,
}
cfg.HostKeyCallback = ssh.InsecureIgnoreHostKey()
client, err := ssh.Dial("tcp", q.sshAddrPort, cfg)
if err != nil {
return
}
defer client.Close()
session, err := client.NewSession()
if err != nil {
return
}
bytesOutput, err := session.CombinedOutput(cmd)
output = string(bytesOutput)
return
}

View File

@ -6,6 +6,7 @@ package qemukernel
import ( import (
"net" "net"
"strings"
"testing" "testing"
) )
@ -63,3 +64,39 @@ func TestGetFreeAddrPort(t *testing.T) {
} }
ln.Close() ln.Close()
} }
func TestQemuSystemCommand(t *testing.T) {
// FIXME hardcoded kernel path
kernel := Kernel{Name: "Host kernel", Path: "/boot/vmlinuz-4.18.8"}
// FIXME hardcoded qcow2 path
qemu, err := NewQemuSystem(X86_64, kernel, "/home/user/qemu/sid.img")
if err != nil {
t.Fatal(err)
}
if err = qemu.Start(); err != nil {
t.Fatal(err)
}
defer qemu.Stop()
output, err := qemu.Command("root", "cat /etc/shadow")
if err != nil {
t.Fatal(err)
}
if !strings.Contains(output, "root::") {
t.Fatal("Wrong output from `cat /etc/shadow` by root")
}
output, err = qemu.Command("user", "cat /etc/passwd")
if err != nil {
t.Fatal(err)
}
if !strings.Contains(output, "root:x:0:0:root:/root:/bin/bash") {
t.Fatal("Wrong output from `cat /etc/passwd` by user")
}
output, err = qemu.Command("user", "cat /etc/shadow")
if err == nil { // unsucessful is good because user must not read /etc/shadow
t.Fatal("User have rights for /etc/shadow. WAT?!")
}
}