|
28 | 28 | import subprocess
|
29 | 29 | import pathlib
|
30 | 30 |
|
| 31 | +from ctypes import CDLL |
| 32 | + |
31 | 33 | import libvirt
|
32 | 34 | import lxml.etree
|
33 | 35 | import importlib.metadata
|
|
53 | 55 | DeviceInterface,
|
54 | 56 | )
|
55 | 57 |
|
| 58 | +# To validate & sanitise UTF8 strings |
| 59 | +LIBQUBES_PURE = "libqubes-pure.so.0" |
| 60 | + |
56 | 61 |
|
57 | 62 | class QubesMgmtEventsDispatcher:
|
58 | 63 | def __init__(self, filters, send_event):
|
@@ -2036,3 +2041,48 @@ async def vm_current_state(self):
|
2036 | 2041 | "power_state": self.dest.get_power_state(),
|
2037 | 2042 | }
|
2038 | 2043 | return " ".join("{}={}".format(k, v) for k, v in state.items())
|
| 2044 | + |
| 2045 | + @qubes.api.method( |
| 2046 | + "admin.vm.notes.Get", no_payload=True, scope="local", read=True |
| 2047 | + ) |
| 2048 | + async def vm_notes_get(self): |
| 2049 | + """Get qube notes""" |
| 2050 | + self.enforce(self.dest.name != "dom0") |
| 2051 | + self.fire_event_for_permission() |
| 2052 | + notes = self.dest.get_notes() |
| 2053 | + return notes |
| 2054 | + |
| 2055 | + @qubes.api.method("admin.vm.notes.Set", scope="local", write=True) |
| 2056 | + async def vm_notes_set(self, untrusted_payload): |
| 2057 | + """Set qube notes""" |
| 2058 | + self.enforce(self.dest.name != "dom0") |
| 2059 | + self.fire_event_for_permission() |
| 2060 | + if len(untrusted_payload) > 256000: |
| 2061 | + raise qubes.exc.ProtocolError( |
| 2062 | + "Maximum note size is 256000 bytes ({} bytes received)".format( |
| 2063 | + len(untrusted_payload) |
| 2064 | + ) |
| 2065 | + ) |
| 2066 | + |
| 2067 | + # Sanitise the incoming utf8 notes with libqubes-pure |
| 2068 | + # use encode() to catch invalid UTF8 chars even earlier |
| 2069 | + try: |
| 2070 | + libqubespure = CDLL(LIBQUBES_PURE) |
| 2071 | + notes = "".join( |
| 2072 | + [ |
| 2073 | + ( |
| 2074 | + c |
| 2075 | + if libqubespure.qubes_pure_string_safe_for_display( |
| 2076 | + f"{c}\0".encode(), 0 |
| 2077 | + ) |
| 2078 | + else "_" |
| 2079 | + ) |
| 2080 | + for c in untrusted_payload.decode("utf8") |
| 2081 | + ] |
| 2082 | + ) |
| 2083 | + except Exception as e: |
| 2084 | + raise qubes.exc.ProtocolError( |
| 2085 | + "Unable to sanitise qube notes: " + str(e) |
| 2086 | + ) |
| 2087 | + |
| 2088 | + self.dest.set_notes(notes) |
0 commit comments