2017-05-23 15:38:28 +02:00
|
|
|
#!/bin/sh
|
2017-07-24 19:54:42 +02:00
|
|
|
#
|
|
|
|
# This Admin API call is implemented as a custom script, instead of dumb
|
|
|
|
# passthrough to qubesd because it may get huge amount of data (whole root.img
|
|
|
|
# for example). qubesd cannot handle it because:
|
|
|
|
# 1. It loads the whole payload into memory, before even start looking at it
|
|
|
|
# (and later, do not allow to modify/append it).
|
|
|
|
# 2. There is 64kB limit on payload size that qubesd can handle (because of
|
|
|
|
# point 1).
|
|
|
|
# 3. Performance reasons (qubesd is not optimized for performance, passing
|
|
|
|
# such large data stream through it would take ages).
|
|
|
|
#
|
|
|
|
# The whole admin.vm.volume.Import consists of:
|
|
|
|
# 1. Permissions checks, getting a path from appropriate storage pool (done
|
|
|
|
# by qubesd)
|
|
|
|
# 2. Actual data import (done by this script, using dd)
|
|
|
|
# 3. Report final result, produce final response to the caller (done by
|
|
|
|
# qubesd)
|
2020-01-16 14:41:00 +01:00
|
|
|
#
|
2017-07-24 19:54:42 +02:00
|
|
|
# This way we do not pass all the data through qubesd, but still can
|
|
|
|
# control the process from there in a meaningful way. Note that the last
|
|
|
|
# part (second call to qubesd) may perform all kind of verification (like
|
|
|
|
# a signature check on the data, or so) and can also prevent VM from
|
|
|
|
# starting (hooking also domain-pre-start event) from not verified image.
|
2020-01-16 14:41:00 +01:00
|
|
|
#
|
|
|
|
# Note that this script implements two calls:
|
|
|
|
# - admin.vm.volume.Import
|
|
|
|
# - admin.vm.volume.ImportWithSize
|
|
|
|
# In the case of admin.vm.ImportWithSize, the first line of payload is then
|
|
|
|
# data size in bytes. This is so that we can already notify qubesd to create a
|
|
|
|
# volume with the new size.
|
2017-05-23 15:38:28 +02:00
|
|
|
|
|
|
|
set -e
|
|
|
|
|
|
|
|
# use temporary file, because env variables deal poorly with \0 inside
|
|
|
|
tmpfile=$(mktemp)
|
|
|
|
trap "rm -f $tmpfile" EXIT
|
2020-01-16 14:41:00 +01:00
|
|
|
|
|
|
|
requested_size=""
|
|
|
|
if [[ ${0##*/} == admin.vm.volume.ImportWithSize ]]; then
|
|
|
|
read requested_size
|
|
|
|
fi
|
|
|
|
|
|
|
|
echo -n "$requested_size" | qubesd-query -c /var/run/qubesd.internal.sock \
|
|
|
|
"$QREXEC_REMOTE_DOMAIN" \
|
|
|
|
"internal.vm.volume.ImportBegin" \
|
|
|
|
"$QREXEC_REQUESTED_TARGET" \
|
|
|
|
"$1" >$tmpfile
|
2017-05-23 15:38:28 +02:00
|
|
|
|
|
|
|
# exit if qubesd returned an error (not '0\0')
|
|
|
|
if [ "$(head -c 2 $tmpfile | xxd -p)" != "3000" ]; then
|
|
|
|
cat "$tmpfile"
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
size=$(tail -c +3 "$tmpfile"|cut -d ' ' -f 1)
|
|
|
|
path=$(tail -c +3 "$tmpfile"|cut -d ' ' -f 2)
|
|
|
|
|
|
|
|
# now process stdin into this path
|
2019-07-31 17:42:20 +02:00
|
|
|
if sudo dd bs=128K of="$path" count="$size" iflag=count_bytes,fullblock \
|
2017-11-06 15:57:20 +01:00
|
|
|
conv=sparse,notrunc,nocreat,fdatasync status=none; then
|
2017-05-23 15:38:28 +02:00
|
|
|
status="ok"
|
|
|
|
else
|
|
|
|
status="fail"
|
|
|
|
fi
|
|
|
|
|
|
|
|
# send status notification to qubesd, and pass its response to the caller
|
|
|
|
echo -n "$status" | qubesd-query -c /var/run/qubesd.internal.sock \
|
|
|
|
"$QREXEC_REMOTE_DOMAIN" \
|
|
|
|
"internal.vm.volume.ImportEnd" \
|
|
|
|
"$QREXEC_REQUESTED_TARGET" \
|
|
|
|
"$1"
|