1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-09 19:56:48 +00:00

fix(instances): restrict disk views to superusers and validate disk input

Disk and media mutation views (add_new_vol, add_existing_vol, edit_volume,
delete_vol, detach_vol, add_cdrom, detach_cdrom, mount_iso, unmount_iso)
were reachable by any owner with is_change, although the UI only shows the
Disk tab to superusers. An ordinary user could delete any volume on the
compute or attach arbitrary host files to their VM.

- Require superuser for all disk/media views, matching the UI.
- delete_vol resolves the volume from the VM's own disk XML by dev and
  ignores the posted storage/name.
- Validate bus/cache/io/discard/detect_zeroes against the hypervisor's
  lists, and format/serial/volume name against strict patterns.
- add_existing_vol only accepts volumes that exist in the selected pool.
- edit_volume only accepts a dev attached to the VM.
- vrtManager: escape all values interpolated into disk XML and pass dev
  as an XPath variable in detach_disk/edit_disk.
This commit is contained in:
catborise 2026-10-02 17:11:12 +03:00
parent b1ab1d47fa
commit 8a3ee13b41
5 changed files with 573 additions and 179 deletions

View file

@ -297,17 +297,18 @@ class InstanceSecurityMutationsTestCase(TestCase):
self.assertEqual(res.status_code, 302)
self.assertIn(f"/instances/{self.instance.id}/#resize", res.url)
def test_subresource_mutation_allowed_with_is_change(self):
# change_user has is_change=True, is_delete=False
def test_disk_mutation_denied_with_is_change(self):
# change_user has is_change=True, is_delete=False. Disk views are
# superuser-only (S-02/S-03/S-04), so is_change alone is not enough.
self.client.force_login(self.change_user)
with patch("instances.models.wvmInstance"), patch("instances.views.wvmStorage"):
# delete_vol uses perm_type="change", so it passes get_instance without 403
with patch("instances.models.wvmInstance"), patch("instances.views.wvmStorage") as mock_storage:
res = self.client.post(
reverse("instances:delete_vol", args=[self.instance.id]),
{"storage": "default", "dev": "vda", "path": "/path"},
HTTP_REFERER=f"/instances/{self.instance.id}/",
)
self.assertEqual(res.status_code, 302)
self.assertEqual(res.status_code, 403)
mock_storage.return_value.del_volume.assert_not_called()
def test_destroy_vm_authorization(self):
# 1. User with is_change=True but is_delete=False gets 403 when trying to destroy VM