It can be done with the admin API.
Assuming you’re in a qube named foo
and want to spawn (and communicate with) a new disp1234
qube, which will automatically be cleaned up when it shuts down:
readarray -d '' -s 1 disp < <(qrexec-client-vm dom0 admin.vm.CreateDisposable </dev/null)
wait $! || # handle error ...
qrexec-client-vm "$disp" admin.vm.Start </dev/null
qrexec-client-vm "$disp" myservice1+arg1
qrexec-client-vm "$disp" myservice2+arg2
qrexec-client-vm "$disp" admin.vm.Kill </dev/null
Which needs policy configuration like:
admin.vm.CreateDisposable + foo dom0 allow
admin.vm.Start + foo @tag:disp-created-by-foo allow target=dom0
myservice1 * foo @tag:disp-created-by-foo allow
myservice2 * foo @tag:disp-created-by-foo allow
admin.vm.Kill + foo @tag:disp-created-by-foo allow target=dom0
Note that a malicious foo
qube might create thousands hundreds of (not yet started) disp1234 qubes, which will probably cause some problems…