mirror of
https://github.com/ipxe/ipxe
synced 2026-01-24 13:13:42 +03:00
[efi] Create safe wrappers for OpenProtocol() and CloseProtocol()
The UEFI model for opening and closing protocols is broken by design and cannot be repaired. Calling OpenProtocol() to obtain a protocol interface pointer does not, in general, provide any guarantees about the lifetime of that pointer. It is theoretically possible that the pointer has already become invalid by the time that OpenProtocol() returns the pointer to its caller. (This can happen when a USB device is physically removed, for example.) Various UEFI design flaws make it occasionally necessary to hold on to a protocol interface pointer despite the total lack of guarantees that the pointer will remain valid. The UEFI driver model overloads the semantics of OpenProtocol() to accommodate the use cases of recording a driver attachment (which is modelled as opening a protocol with EFI_OPEN_PROTOCOL_BY_DRIVER attributes) and recording the existence of a related child controller (which is modelled as opening a protocol with EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER attributes). The parameters defined for CloseProtocol() are not sufficient to allow the implementation to precisely identify the matching call to OpenProtocol(). While the UEFI model appears to allow for matched open and close pairs, this is merely an illusion. Calling CloseProtocol() will delete *all* matching records in the protocol open information tables. Since the parameters defined for CloseProtocol() do not include the attributes passed to OpenProtocol(), this means that a matched open/close pair using EFI_OPEN_PROTOCOL_GET_PROTOCOL can inadvertently end up deleting the record that defines a driver attachment or the existence of a child controller. This in turn can cause some very unexpected side effects, such as allowing other UEFI drivers to start controlling hardware to which iPXE believes it has exclusive access. This rarely ends well. To prevent this kind of inadvertent deletion, we establish a convention for four different types of protocol opening: - ephemeral opens: always opened with ControllerHandle = NULL - unsafe opens: always opened with ControllerHandle = AgentHandle - by-driver opens: always opened with ControllerHandle = Handle - by-child opens: always opened with ControllerHandle != Handle This convention ensures that the four types of open never overlap within the set of parameters defined for CloseProtocol(), and so a close of one type cannot inadvertently delete the record corresponding to a different type. Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
@@ -389,5 +389,17 @@ extern EFI_STATUS efi_init ( EFI_HANDLE image_handle,
|
||||
EFI_SYSTEM_TABLE *systab );
|
||||
extern void efi_raise_tpl ( struct efi_saved_tpl *tpl );
|
||||
extern void efi_restore_tpl ( struct efi_saved_tpl *tpl );
|
||||
extern int efi_open ( EFI_HANDLE handle, EFI_GUID *protocol,
|
||||
void **interface );
|
||||
extern int efi_open_unsafe ( EFI_HANDLE handle, EFI_GUID *protocol,
|
||||
void **interface );
|
||||
extern void efi_close_unsafe ( EFI_HANDLE handle, EFI_GUID *protocol );
|
||||
extern int efi_open_by_driver ( EFI_HANDLE handle, EFI_GUID *protocol,
|
||||
void **interface );
|
||||
extern void efi_close_by_driver ( EFI_HANDLE handle, EFI_GUID *protocol );
|
||||
extern int efi_open_by_child ( EFI_HANDLE handle, EFI_GUID *protocol,
|
||||
EFI_HANDLE child, void **interface );
|
||||
extern void efi_close_by_child ( EFI_HANDLE handle, EFI_GUID *protocol,
|
||||
EFI_HANDLE child );
|
||||
|
||||
#endif /* _IPXE_EFI_H */
|
||||
|
||||
@@ -84,6 +84,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#define ERRFILE_efi_mp ( ERRFILE_CORE | 0x002c0000 )
|
||||
#define ERRFILE_efi_service ( ERRFILE_CORE | 0x002d0000 )
|
||||
#define ERRFILE_null_smbios ( ERRFILE_CORE | 0x002e0000 )
|
||||
#define ERRFILE_efi_open ( ERRFILE_CORE | 0x002f0000 )
|
||||
|
||||
#define ERRFILE_eisa ( ERRFILE_DRIVER | 0x00000000 )
|
||||
#define ERRFILE_isa ( ERRFILE_DRIVER | 0x00010000 )
|
||||
|
||||
Reference in New Issue
Block a user