mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-08 19:26:48 +00:00
A compute's hostname and login go unquoted into the libvirt connection URI (qemu+ssh://login@host/system, qemu+tcp://host/system, qemu+tls://...) and, for an SSH compute, into the ssh command line of the DRBD status view. They were barely validated: validate_hostname used re.match with a negated class, so it caught only a leading special character, and login was never checked. A hostname like "192.0.2.1/system?command=/path" injected a libvirt URI parameter (verified: connecting ran the named command through the ssh wrapper), and TLS/SSH parameters such as no_verify, pkipath, socket or netcat could be added the same way; a login like "-oProxyCommand=..." became an ssh option. The DRF ComputeSerializer applied neither check, and validate_name tested a string literal instead of its argument, so it never raised. validate_hostname now accepts only an IPv4 address or a host name with fullmatch (no scheme, port, path, query, whitespace or IPv6 literal; IPv6 is left out until the URI building brackets it). validate_login accepts an empty value (TCP falls back to the server's authentication, the socket transport ignores the login) or a plain name with no leading "-". Both sit on the Compute model fields, so the forms and the DRF serializer (which copies model validators onto its fields) reject the values; a migration records the metadata. validate_name checks its argument. drbd_status validates the login and hostname before building login@host and ends ssh option parsing with "--"; an existing or bypassed bad row is skipped rather than run. Tests: hostname/login validators accept real values and reject URI and option injection; the SSH form and the serializer (create, and an empty TCP login) enforce them; drbd_status skips an injecting target. Checked the real test computes still validate. The new tests fail on the previous code.
17 lines
742 B
Python
17 lines
742 B
Python
"""drbd_status runs ssh with the compute's login@hostname; a compute whose
|
|
values would inject an ssh option (an existing or bypassed row) is skipped."""
|
|
|
|
import unittest
|
|
from types import SimpleNamespace
|
|
|
|
from instances.views import _valid_ssh_target
|
|
|
|
|
|
class DrbdTargetTestCase(unittest.TestCase):
|
|
def test_valid_target(self):
|
|
self.assertTrue(_valid_ssh_target(SimpleNamespace(login="root", hostname="192.0.2.1")))
|
|
|
|
def test_option_injection_is_skipped(self):
|
|
for login, hostname in (("-oProxyCommand=x", "192.0.2.1"), ("root", "-x"), ("root", "a b")):
|
|
with self.subTest(login=login, hostname=hostname):
|
|
self.assertFalse(_valid_ssh_target(SimpleNamespace(login=login, hostname=hostname)))
|