admin.vm.volume.Import 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. #!/bin/sh
  2. #
  3. # This Admin API call is implemented as a custom script, instead of dumb
  4. # passthrough to qubesd because it may get huge amount of data (whole root.img
  5. # for example). qubesd cannot handle it because:
  6. # 1. It loads the whole payload into memory, before even start looking at it
  7. # (and later, do not allow to modify/append it).
  8. # 2. There is 64kB limit on payload size that qubesd can handle (because of
  9. # point 1).
  10. # 3. Performance reasons (qubesd is not optimized for performance, passing
  11. # such large data stream through it would take ages).
  12. #
  13. # The whole admin.vm.volume.Import consists of:
  14. # 1. Permissions checks, getting a path from appropriate storage pool (done
  15. # by qubesd)
  16. # 2. Actual data import (done by this script, using dd)
  17. # 3. Report final result, produce final response to the caller (done by
  18. # qubesd)
  19. #
  20. # This way we do not pass all the data through qubesd, but still can
  21. # control the process from there in a meaningful way. Note that the last
  22. # part (second call to qubesd) may perform all kind of verification (like
  23. # a signature check on the data, or so) and can also prevent VM from
  24. # starting (hooking also domain-pre-start event) from not verified image.
  25. set -e
  26. # use temporary file, because env variables deal poorly with \0 inside
  27. tmpfile=$(mktemp)
  28. trap "rm -f $tmpfile" EXIT
  29. qubesd-query -e \
  30. "$QREXEC_REMOTE_DOMAIN" \
  31. "admin.vm.volume.Import" \
  32. "$QREXEC_REQUESTED_TARGET" \
  33. "$1" >$tmpfile
  34. # exit if qubesd returned an error (not '0\0')
  35. if [ "$(head -c 2 $tmpfile | xxd -p)" != "3000" ]; then
  36. cat "$tmpfile"
  37. exit 1
  38. fi
  39. size=$(tail -c +3 "$tmpfile"|cut -d ' ' -f 1)
  40. path=$(tail -c +3 "$tmpfile"|cut -d ' ' -f 2)
  41. # now process stdin into this path
  42. if sudo dd bs=4k of="$path" count="$size" iflag=count_bytes,fullblock \
  43. conv=sparse,notrunc,nocreat,fdatasync status=none; then
  44. status="ok"
  45. else
  46. status="fail"
  47. fi
  48. # send status notification to qubesd, and pass its response to the caller
  49. echo -n "$status" | qubesd-query -c /var/run/qubesd.internal.sock \
  50. "$QREXEC_REMOTE_DOMAIN" \
  51. "internal.vm.volume.ImportEnd" \
  52. "$QREXEC_REQUESTED_TARGET" \
  53. "$1"