Skip to content

Commit dff2e1e

Browse files
authored
Guard optional UEFI dispatch registration (#703)
* Guard optional UEFI dispatch registration * Use merged PyVEX source * Simplify optional UEFI backend loading
1 parent 306a88b commit dff2e1e

2 files changed

Lines changed: 46 additions & 32 deletions

File tree

cle/backends/uefi_firmware.py

Lines changed: 28 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import logging
55
import mmap
66
from dataclasses import dataclass
7-
from functools import singledispatchmethod
7+
from typing import cast
88
from uuid import UUID
99

1010
import archinfo
@@ -104,40 +104,36 @@ def __init__(self, *args, **kwargs) -> None:
104104
if self.loader._main_object is self:
105105
self.loader._main_object = None
106106

107-
@singledispatchmethod
108-
def _load(self, uefi_obj): # pylint: disable=no-self-use
109-
raise CLEUnknownFormatError(f"Can't load firmware object: {uefi_obj}")
107+
def _load(self, uefi_obj):
108+
if uefi_obj is None:
109+
return
110+
if uefi_firmware is None:
111+
raise ImportError("The UEFI backend requires the uefi-firmware package")
112+
113+
is_firmware_file = isinstance(uefi_obj, uefi_firmware.uefi.FirmwareFile)
114+
old_uuid = self._current_file
115+
if is_firmware_file:
116+
if uefi_obj.type == 7: # driver
117+
uuid = UUID(bytes=uefi_obj.guid)
118+
self._drivers_pending[uuid] = UefiModulePending()
119+
self._current_file = uuid
120+
elif isinstance(uefi_obj, uefi_firmware.uefi.FirmwareFileSystemSection):
121+
pending = self._drivers_pending.get(self._current_file) if self._current_file is not None else None
122+
if pending is not None:
123+
if uefi_obj.type == 16: # pe32 image
124+
pending.pe_image = cast(bytes, uefi_obj.content)
125+
elif uefi_obj.type == 18: # te image
126+
pending.te_image = cast(bytes, uefi_obj.content)
127+
elif uefi_obj.type == 21: # user interface name
128+
pending.name = cast(bytes, uefi_obj.content).decode("utf-16").strip("\0")
129+
elif not isinstance(uefi_obj, uefi_firmware.FirmwareObject):
130+
raise CLEUnknownFormatError(f"Can't load firmware object: {uefi_obj}")
110131

111-
@_load.register
112-
def _load_generic(self, uefi_obj: uefi_firmware.FirmwareObject):
113132
for obj in uefi_obj.objects:
114133
self._load(obj)
115134

116-
@_load.register
117-
def _load_none(self, uefi_obj: None):
118-
pass
119-
120-
@_load.register
121-
def _load_firmwarefile(self, uefi_obj: uefi_firmware.uefi.FirmwareFile):
122-
old_uuid = self._current_file
123-
if uefi_obj.type == 7: # driver
124-
uuid = UUID(bytes=uefi_obj.guid)
125-
self._drivers_pending[uuid] = UefiModulePending()
126-
self._current_file = uuid
127-
self._load_generic(uefi_obj)
128-
self._current_file = old_uuid
129-
130-
@_load.register
131-
def _load_firmwarefilesection(self, uefi_obj: uefi_firmware.uefi.FirmwareFileSystemSection):
132-
pending = self._drivers_pending.get(self._current_file, None)
133-
if pending is not None:
134-
if uefi_obj.type == 16: # pe32 image
135-
pending.pe_image = uefi_obj.content
136-
elif uefi_obj.type == 18: # te image
137-
pending.te_image = uefi_obj.content
138-
elif uefi_obj.type == 21: # user interface name
139-
pending.name = uefi_obj.content.decode("utf-16").strip("\0")
140-
self._load_generic(uefi_obj)
135+
if is_firmware_file:
136+
self._current_file = old_uuid
141137

142138

143139
@dataclass
@@ -184,7 +180,7 @@ def __init__(self, *args, guid: UUID, name: str | None, **kwargs):
184180
def __repr__(self):
185181
return (
186182
f"<{type(self).__name__} Object "
187-
f'{self.guid}{f" {self.user_interface_name}" if self.user_interface_name else ""}, '
183+
f"{self.guid}{f' {self.user_interface_name}' if self.user_interface_name else ''}, "
188184
f"maps [{self.min_addr:#x}:{self.max_addr:#x}]>"
189185
)
190186

tests/test_optional_backends.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from __future__ import annotations
2+
3+
import subprocess
4+
import sys
5+
6+
7+
def test_import_without_uefi_firmware():
8+
script = """
9+
import sys
10+
11+
sys.modules["uefi_firmware"] = None
12+
13+
import cle
14+
from cle.backends import ALL_BACKENDS
15+
16+
assert "uefi" in ALL_BACKENDS
17+
"""
18+
subprocess.run([sys.executable, "-c", script], check=True)

0 commit comments

Comments
 (0)