qubes-doc/Qfilecopy.md
2011-04-06 15:16:57 +00:00

72 lines
6.1 KiB
Markdown

---
layout: wiki
title: Qfilecopy
permalink: /wiki/Qfilecopy/
---
InterVM file copy design
========================
There are two cases when we need a mechanism to copy files between VMs:
- "regular" file copy - when user instructs file manager to copy a given files/directories to a different VM
- DispVM copy - user selects "open in DispVM" on a file; this file must be copied to a Disposable VM, edited by user, and possibly a modified file copied back from DispVM to VM.
Prior to Qubes Beta1, for both cases, a block device (backed by a file in dom0 with a vfat filesystem on it) was attached to VM, file(s) copied there, and then the device was detached and attached to target VM. In the DispVM case, if a edited file has been modified, another block device is passed to requester VM in order to update the source file.
This has the following disadvantages:
- performance - dom0 has to prepare and attach/detach block devices, which is slow because of hotplug scripts involvement.
- security - VM kernel parses partition table and filesystem metadata from the block device; they are controlled by (potentially untrusted) sender VM.
The current solution is based on the "qrexec" mechanism. Dom0 can call *qrexec\_client* program, which will execute a given program in a given VM, passing stdin/stdout/stderr/exit code over vchan connection; possibly attaching the remote stdin/stdout to a local program. In the latter case, the syntax is *qrexec\_client peer\_vm command\_in\_vm -l command\_in\_dom0*
In order to support qrexec, there are two permanent processes: *qrexec-daemon* in dom0 and *qrexec-agent* in VM, connected over vchan. These processes are started when a domain is created. All data exchanged by pairs of processes created by *qrexec\_client DestVM command\_in\_vm* pass via the vchan connecting qrexec-daemon and qrexec-agent.
The *qvm-run* tool has been adapted to use qrexec functionality. See *qvm-run --help* for syntax.
Notably, qrexec-agent possess ability to signal its qrexec-daemon peer to execute a predefined command. This way, VM-side code can initiate setup of *vm process \<-\> vchan \<-\> dom0 process* structure. As the range of dom0 commands will be predefined, there is no "arbitrary code execution" vulnerability here.
In Qubes Beta1, we have reimplemented interVM file copy using qrexec, which addresses the abovementioned disadvantages.
Note, the qrexec mechanism works over vchan, and vchan is a channel between VM and dom0 (not between two VMs). We could imagine vchan extension, in which instead of using facilities available for dom0 only (like *xc\_map\_foreign\_range*), the channel would be set up over granted pages, between two AppVMs. Reimplementing vchan this way is nontrivial. Also, it creates some security design questions; currently, everything is mediated via dom0, which has the ability to allow/deny communication, possibly asking user via dialog popups.
Regular file copy
-----------------
"Regular" file is implemented as follows:
- in srcVM, qvm-copy-to-vm utility
- stores the information on the files\_to\_be\_copied to `~/.filecopyspool` directory
- tells *qrexec-agent* (by writing to its command fifo) to send `EXECUTE_FILE_COPY` command to qrexec-daemon
- *qrexec-daemon* sees `EXECUTE_FILE_COPY` command, executes (predefined)
*qrexec\_client srcVM qfile-agent -l qfile-daemon*
- qfile-agent inspects `~/.filecopyspool`, sees the description about the file copy request. *qfile-agent* walks the directory tree, sends destination vmname, sends file metadata and data, then exits
- qfile-daemon gets the first 32 characters from stdin (copy destination vmname), then executes (execve, really turn into new process)
*qrexec\_client dstVM qfile-unpacker*
At this point, two *qrexec\_client* processes running in dom0 just pass data between srcVM and dstVM. When the one connected to srcVM sees incoming EOF, it just closes input to the other qrexec\_client.
[![filecopy.png](/chrome/site/../../../site/filecopy.png "filecopy.png")](/chrome/site/../../../site/filecopy.png)
Note that *qfile-unpacker* must be coded securely, as it processes potentially untrusted data format. Particularly, we do not want to use external tar or cpio and be prone to all vulnerabilities in them; we want a simplified, small utility, that handles only directory/file/symlink file type, permissions, mtime/atime, and assume user/user ownership. In the current implementation, the code that actually parses the data from srcVM has ca 100 lines of code and executes chrooted to the destination directory. The latter is hardcoded to `~user/incoming/srcVM`; because of chroot, there is no possibility to alter files outside of this directory.
DispVM file copy
----------------
DispVM copy is implemented as follows:
- in source\_VM, *qvm-open-in-dvm* utility
- stores the information on file\_to\_be\_edited in `~/.dvmspool` directory
- tells *qrexec-agent* (by writing to qrexec-agent command fifo) to send `EXECUTE_FILE_COPY_FOR_DISPVM` command to *qrexec-daemon*
- qrexec-daemon sees `EXECUTE_FILE_COPY_FOR_DISPVM` command, executes
*qrexec\_client srcVM qfile-agent-dvm -l qfile-daemon-dvm*
- *qfile-agent-dvm* inspects `~/.dvmspool`, sees the description about file\_to\_be\_edited, sends data about it to its peer, closes stdout
- *qfile-daemon-dvm* creates DispVM, then forks
*qrexec\_client DispVM dvm\_file\_editor*
at this point, two qrexec\_client processes running in dom0 just pass data between srcVM and DispVM. *qfile-daemon-dvm* just waits for its child qrexec\_client process termination.
- *dvm\_file\_editor* gets file contents (end of transfer signalled by EOF), spawns mime handler; if the file has changed, sends modified file to its stdout, closes stdout
- the response from *dvm\_file\_editor* (terminated by EOF) is passed (via two qrexec\_client processes in dom0) to *qfile-agent-dvm*. When *qfile-daemon-dvm* sees its child qrexec\_client has exited (because of EOFs in both directions), it kills DispVM.
- *qfile-agent-dvm* retrieves response (terminated by EOF), if nonempty, it updates the edited file.
[![dvmcopy.png](/chrome/site/../../../site/dvmcopy.png "dvmcopy.png")](/chrome/site/../../../site/dvmcopy.png)