Skip to content

Commit 99b0810

Browse files
TarekTab-Tarek3600
authored andcommitted
admin: validate feature name in vm_feature_remove
Feature name validation was missing in vm_feature_remove, while vm_feature_set already validated it. This inconsistency allowed path traversal characters in feature names when removing features. Also use ProtocolError instead of QubesValueError for invalid feature names in vm_feature_set, consistent with PR #751. Fixes: QubesOS/qubes-issues#7186
1 parent 53ca30f commit 99b0810

2 files changed

Lines changed: 28 additions & 3 deletions

File tree

qubes/api/admin.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1162,8 +1162,12 @@ async def vm_feature_checkwithtpladminvm(self):
11621162
"admin.vm.feature.Remove", no_payload=True, scope="local", write=True
11631163
)
11641164
async def vm_feature_remove(self):
1165-
# validation of self.arg done by qrexec-policy is enough
1166-
1165+
# Validate feature name to prevent path traversal and ensure
1166+
# consistency with the Admin API validation in vm_feature_set
1167+
if re.match(r"\A[a-zA-Z0-9_.-]+\Z", self.arg) is None:
1168+
raise qubes.exc.ProtocolError(
1169+
"feature name contains illegal characters"
1170+
)
11671171
self.fire_event_for_permission()
11681172
try:
11691173
del self.dest.features[self.arg]
@@ -1176,7 +1180,7 @@ async def vm_feature_set(self, untrusted_payload):
11761180
untrusted_value = untrusted_payload.decode("ascii", errors="strict")
11771181
del untrusted_payload
11781182
if re.match(r"\A[a-zA-Z0-9_.-]+\Z", self.arg) is None:
1179-
raise qubes.exc.QubesValueError(
1183+
raise qubes.exc.ProtocolError(
11801184
"feature name contains illegal characters"
11811185
)
11821186
if re.match(r"\A[\x20-\x7E]*\Z", untrusted_value) is None:

qubes/tests/api_admin.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1694,6 +1694,27 @@ def test_301_feature_remove_none(self):
16941694
)
16951695
self.assertFalse(self.app.save.called)
16961696

1697+
def test_302_feature_remove_invalid_name(self):
1698+
# Invalid feature names must raise ProtocolError before any action
1699+
with self.assertRaises(qubes.exc.ProtocolError):
1700+
self.call_mgmt_func(
1701+
b"admin.vm.feature.Remove",
1702+
b"test-vm1",
1703+
b"../../../root/gotcha",
1704+
)
1705+
self.assertFalse(self.app.save.called)
1706+
1707+
def test_302b_feature_set_invalid_name(self):
1708+
# Invalid feature names must raise ProtocolError in vm_feature_set
1709+
with self.assertRaises(qubes.exc.ProtocolError):
1710+
self.call_mgmt_func(
1711+
b"admin.vm.feature.Set",
1712+
b"test-vm1",
1713+
b"../../../root/gotcha",
1714+
b"some-value",
1715+
)
1716+
self.assertFalse(self.app.save.called)
1717+
16971718
def test_303_feature_prohibited(self):
16981719
del self.app.domains[0].fire_event
16991720
feature = qubes.ext.admin.PROHIBITED_FEATURES[0]

0 commit comments

Comments
 (0)