GNS3 / gns3-server

GNS3 server
GNU General Public License v3.0
768 stars 258 forks source link

QEMU VMs have access to host filesystem via 9p #2385

Open b-ehlers opened 1 month ago

b-ehlers commented 1 month ago

QEMU supports the 9p filesystem, a very nice way to access host files from the QEMU VM. For details have a look into the QEMU documentation https://wiki.qemu.org/Documentation/9psetup.

As a GNS3 user can pass any option via the advanced settings to QEMU, he can enable this host access in QEMU. On the VM side a Linux VM is needed with 9p filesystem support. As most Linux distributions support 9p, most Linux VMs can be used, for example the Alpine Linux Virt appliance.

For a test I enabled 9p to access the full host filesystem by adding -fsdev local,path=/,security_model=none,id=hostfsdev -device virtio-9p-pci,fsdev=hostfsdev,mount_tag=hostfs to the advanced settings. In the VM I can access the host by mounting the 9p filesystem.

alpine:~# mount -t 9p -o trans=virtio,posixacl,msize=512000 hostfs /mnt
alpine:~# ls /mnt
bin             initrd.img.old  opt             sys
boot            lib             proc            tmp
dev             lib64           root            usr
etc             lost+found      run             var
home            media           sbin            vmlinuz
initrd.img      mnt             srv             vmlinuz.old

As the QEMU process accesses the host files, the VM has only the privileges of the QEMU user, in the GNS3VM that's user gns3. But that is enough to access and even modify quite a lot of the GNS3 server system.

This is not a bug in QEMU or Linux, it is the consequence of a GNS3 user being able to pass any option to QEMU. But filtering dangerous options is quite difficult, so I don't know how to deal with this and similar problems.

b-ehlers commented 1 month ago

Filtering additional options seems to be easier than expected. Here my diff against v2.2.47:

It also forbids "-drive" in additional options, as with this option one can pass any host file as a disk device to a VM.

Update: Also forbids "-blockdev" and "-hda" .. "-hdd".

diff --git a/gns3server/compute/qemu/qemu_vm.py b/gns3server/compute/qemu/qemu_vm.py
index d91e4360..c4f19d3d 100644
--- a/gns3server/compute/qemu/qemu_vm.py
+++ b/gns3server/compute/qemu/qemu_vm.py
@@ -54,6 +54,13 @@ import logging
 log = logging.getLogger(__name__)

+# forbidden additional options
+FORBIDDEN_OPTIONS = {"-blockdev", "-drive", "-hda", "-hdb", "-hdc", "-hdd",
+                     "-fsdev", "-virtfs"}
+FORBIDDEN_OPTIONS |= {"-"+opt for opt in FORBIDDEN_OPTIONS
+                      if opt.startswith("-") and not opt.startswith("--")}
+
+
 class QemuVM(BaseNode):
     module_name = 'qemu'

@@ -2423,9 +2430,13 @@ class QemuVM(BaseNode):
             command.extend(self._tpm_options())
         if additional_options:
             try:
-                command.extend(shlex.split(additional_options))
+                additional_opt_list = shlex.split(additional_options)
             except ValueError as e:
                 raise QemuError("Invalid additional options: {} error {}".format(additional_options, e))
+            for opt in additional_opt_list:
+                if opt in FORBIDDEN_OPTIONS:
+                    raise QemuError("Forbidden additional option: {}".format(opt))
+            command.extend(additional_opt_list)
         # avoiding mouse offset (see https://github.com/GNS3/gns3-server/issues/2335)
         if self._console_type == "vnc":
             command.extend(['-machine', 'usb=on', '-device', 'usb-tablet'])
b-ehlers commented 4 weeks ago

One side effect: The appliance macos-install.gns3a won't work with this change, as it uses the -drive option to add additional iso images. For this it needs to use absolute path names, so this way is not portable. A better solution would be the implementation of issue https://github.com/GNS3/gns3-gui/issues/3049.

grossmj commented 2 weeks ago

Filtering additional options seems to be easier than expected.

Thanks, I will also add a config option to bypass any filtering.