]>
Commit | Line | Data |
---|---|---|
0c18794e | 1 | /** @file\r |
2 | Implement defer image load services for user identification in UEFI2.2.\r | |
3 | \r | |
b3548d32 | 4 | Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r |
289b714b | 5 | SPDX-License-Identifier: BSD-2-Clause-Patent\r |
0c18794e | 6 | \r |
7 | **/\r | |
8 | \r | |
9 | #include "DxeDeferImageLoadLib.h"\r | |
10 | \r | |
11 | //\r | |
12 | // Handle for the Deferred Image Load Protocol instance produced by this driver.\r | |
13 | //\r | |
14 | EFI_HANDLE mDeferredImageHandle = NULL;\r | |
15 | BOOLEAN mIsProtocolInstalled = FALSE;\r | |
16 | EFI_USER_MANAGER_PROTOCOL *mUserManager = NULL;\r | |
17 | DEFERRED_IMAGE_TABLE mDeferredImage = {\r | |
18 | 0, // Deferred image count\r | |
19 | NULL // The deferred image info\r | |
20 | };\r | |
21 | \r | |
22 | EFI_DEFERRED_IMAGE_LOAD_PROTOCOL gDeferredImageLoad = {\r | |
23 | GetDefferedImageInfo\r | |
24 | };\r | |
25 | \r | |
26 | /**\r | |
27 | Get the image type.\r | |
28 | \r | |
29 | @param[in] File This is a pointer to the device path of the file\r | |
b3548d32 | 30 | that is being dispatched.\r |
0c18794e | 31 | \r |
b3548d32 | 32 | @return UINT32 Image Type\r |
0c18794e | 33 | \r |
34 | **/\r | |
35 | UINT32\r | |
36 | GetFileType (\r | |
37 | IN CONST EFI_DEVICE_PATH_PROTOCOL *File\r | |
38 | )\r | |
39 | {\r | |
40 | EFI_STATUS Status;\r | |
b3548d32 | 41 | EFI_HANDLE DeviceHandle;\r |
0c18794e | 42 | EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r |
43 | EFI_BLOCK_IO_PROTOCOL *BlockIo;\r | |
44 | \r | |
45 | //\r | |
46 | // First check to see if File is from a Firmware Volume\r | |
47 | //\r | |
48 | DeviceHandle = NULL;\r | |
49 | TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;\r | |
50 | Status = gBS->LocateDevicePath (\r | |
51 | &gEfiFirmwareVolume2ProtocolGuid,\r | |
52 | &TempDevicePath,\r | |
53 | &DeviceHandle\r | |
54 | );\r | |
55 | if (!EFI_ERROR (Status)) {\r | |
56 | Status = gBS->OpenProtocol (\r | |
57 | DeviceHandle,\r | |
58 | &gEfiFirmwareVolume2ProtocolGuid,\r | |
59 | NULL,\r | |
60 | NULL,\r | |
61 | NULL,\r | |
62 | EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r | |
63 | );\r | |
64 | if (!EFI_ERROR (Status)) {\r | |
65 | return IMAGE_FROM_FV;\r | |
66 | }\r | |
67 | }\r | |
68 | \r | |
69 | //\r | |
70 | // Next check to see if File is from a Block I/O device\r | |
71 | //\r | |
72 | DeviceHandle = NULL;\r | |
73 | TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;\r | |
74 | Status = gBS->LocateDevicePath (\r | |
75 | &gEfiBlockIoProtocolGuid,\r | |
76 | &TempDevicePath,\r | |
77 | &DeviceHandle\r | |
78 | );\r | |
79 | if (!EFI_ERROR (Status)) {\r | |
80 | BlockIo = NULL;\r | |
81 | Status = gBS->OpenProtocol (\r | |
82 | DeviceHandle,\r | |
83 | &gEfiBlockIoProtocolGuid,\r | |
84 | (VOID **) &BlockIo,\r | |
85 | NULL,\r | |
86 | NULL,\r | |
87 | EFI_OPEN_PROTOCOL_GET_PROTOCOL\r | |
88 | );\r | |
89 | if (!EFI_ERROR (Status) && BlockIo != NULL) {\r | |
90 | if (BlockIo->Media != NULL) {\r | |
91 | if (BlockIo->Media->RemovableMedia) {\r | |
92 | //\r | |
93 | // Block I/O is present and specifies the media is removable\r | |
94 | //\r | |
95 | return IMAGE_FROM_REMOVABLE_MEDIA;\r | |
96 | } else {\r | |
97 | //\r | |
98 | // Block I/O is present and specifies the media is not removable\r | |
99 | //\r | |
100 | return IMAGE_FROM_FIXED_MEDIA;\r | |
101 | }\r | |
102 | }\r | |
103 | }\r | |
104 | }\r | |
105 | \r | |
106 | //\r | |
b3548d32 | 107 | // File is not in a Firmware Volume or on a Block I/O device, so check to see if\r |
0c18794e | 108 | // the device path supports the Simple File System Protocol.\r |
109 | //\r | |
110 | DeviceHandle = NULL;\r | |
111 | TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;\r | |
112 | Status = gBS->LocateDevicePath (\r | |
113 | &gEfiSimpleFileSystemProtocolGuid,\r | |
114 | &TempDevicePath,\r | |
115 | &DeviceHandle\r | |
116 | );\r | |
117 | if (!EFI_ERROR (Status)) {\r | |
118 | //\r | |
119 | // Simple File System is present without Block I/O, so assume media is fixed.\r | |
120 | //\r | |
121 | return IMAGE_FROM_FIXED_MEDIA;\r | |
122 | }\r | |
123 | \r | |
124 | //\r | |
125 | // File is not from an FV, Block I/O or Simple File System, so the only options\r | |
b3548d32 | 126 | // left are a PCI Option ROM and a Load File Protocol such as a PXE Boot from a NIC.\r |
0c18794e | 127 | //\r |
128 | TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;\r | |
129 | while (!IsDevicePathEndType (TempDevicePath)) {\r | |
130 | switch (DevicePathType (TempDevicePath)) {\r | |
b3548d32 | 131 | \r |
0c18794e | 132 | case MEDIA_DEVICE_PATH:\r |
133 | if (DevicePathSubType (TempDevicePath) == MEDIA_RELATIVE_OFFSET_RANGE_DP) {\r | |
134 | return IMAGE_FROM_OPTION_ROM;\r | |
135 | }\r | |
136 | break;\r | |
137 | \r | |
138 | case MESSAGING_DEVICE_PATH:\r | |
139 | if (DevicePathSubType(TempDevicePath) == MSG_MAC_ADDR_DP) {\r | |
140 | return IMAGE_FROM_REMOVABLE_MEDIA;\r | |
b3548d32 | 141 | }\r |
0c18794e | 142 | break;\r |
143 | \r | |
144 | default:\r | |
145 | break;\r | |
146 | }\r | |
147 | TempDevicePath = NextDevicePathNode (TempDevicePath);\r | |
148 | }\r | |
b3548d32 | 149 | return IMAGE_UNKNOWN;\r |
0c18794e | 150 | }\r |
151 | \r | |
152 | \r | |
153 | /**\r | |
154 | Get current user's access right.\r | |
155 | \r | |
156 | @param[out] AccessControl Points to the user's access control data, the\r | |
157 | caller should free data buffer.\r | |
158 | @param[in] AccessType The type of user access control.\r | |
159 | \r | |
160 | @retval EFI_SUCCESS Get current user access control successfully\r | |
161 | @retval others Fail to get current user access control\r | |
162 | \r | |
163 | **/\r | |
164 | EFI_STATUS\r | |
165 | GetAccessControl (\r | |
166 | OUT EFI_USER_INFO_ACCESS_CONTROL **AccessControl,\r | |
167 | IN UINT32 AccessType\r | |
168 | )\r | |
169 | {\r | |
170 | EFI_STATUS Status;\r | |
171 | EFI_USER_INFO_HANDLE UserInfo;\r | |
172 | EFI_USER_INFO *Info;\r | |
173 | UINTN InfoSize;\r | |
174 | EFI_USER_INFO_ACCESS_CONTROL *Access;\r | |
175 | EFI_USER_PROFILE_HANDLE CurrentUser;\r | |
176 | UINTN CheckLen;\r | |
177 | EFI_USER_MANAGER_PROTOCOL *UserManager;\r | |
178 | \r | |
179 | CurrentUser = NULL;\r | |
180 | Status = gBS->LocateProtocol (\r | |
181 | &gEfiUserManagerProtocolGuid,\r | |
182 | NULL,\r | |
183 | (VOID **) &UserManager\r | |
184 | );\r | |
185 | if (EFI_ERROR (Status)) {\r | |
186 | return EFI_NOT_FOUND;\r | |
187 | }\r | |
b3548d32 | 188 | \r |
0c18794e | 189 | //\r |
190 | // Get current user access information.\r | |
191 | //\r | |
192 | UserManager->Current (UserManager, &CurrentUser);\r | |
193 | \r | |
194 | UserInfo = NULL;\r | |
195 | Info = NULL;\r | |
196 | InfoSize = 0;\r | |
197 | while (TRUE) {\r | |
198 | //\r | |
199 | // Get next user information.\r | |
200 | //\r | |
201 | Status = UserManager->GetNextInfo (UserManager, CurrentUser, &UserInfo);\r | |
202 | if (EFI_ERROR (Status)) {\r | |
203 | return Status;\r | |
204 | }\r | |
205 | \r | |
206 | Status = UserManager->GetInfo (\r | |
207 | UserManager,\r | |
208 | CurrentUser,\r | |
209 | UserInfo,\r | |
210 | Info,\r | |
211 | &InfoSize\r | |
212 | );\r | |
213 | if (Status == EFI_BUFFER_TOO_SMALL) {\r | |
214 | if (Info != NULL) {\r | |
215 | FreePool (Info);\r | |
216 | }\r | |
217 | Info = AllocateZeroPool (InfoSize);\r | |
218 | ASSERT (Info != NULL);\r | |
219 | Status = UserManager->GetInfo (\r | |
220 | UserManager,\r | |
221 | CurrentUser,\r | |
222 | UserInfo,\r | |
223 | Info,\r | |
224 | &InfoSize\r | |
225 | );\r | |
226 | }\r | |
227 | \r | |
228 | if (EFI_ERROR (Status)) {\r | |
229 | break;\r | |
230 | }\r | |
b3548d32 | 231 | \r |
0c18794e | 232 | ASSERT (Info != NULL);\r |
233 | if (Info->InfoType != EFI_USER_INFO_ACCESS_POLICY_RECORD) {\r | |
234 | continue;\r | |
235 | }\r | |
b3548d32 | 236 | \r |
0c18794e | 237 | //\r |
238 | // Get specified access information.\r | |
239 | //\r | |
240 | CheckLen = 0;\r | |
241 | while (CheckLen < Info->InfoSize - sizeof (EFI_USER_INFO)) {\r | |
242 | Access = (EFI_USER_INFO_ACCESS_CONTROL *) ((UINT8 *) (Info + 1) + CheckLen);\r | |
9a70350f | 243 | if (Access->Type == AccessType) {\r |
0c18794e | 244 | *AccessControl = AllocateZeroPool (Access->Size);\r |
245 | ASSERT (*AccessControl != NULL);\r | |
246 | CopyMem (*AccessControl, Access, Access->Size);\r | |
247 | FreePool (Info);\r | |
248 | return EFI_SUCCESS;\r | |
249 | }\r | |
250 | CheckLen += Access->Size;\r | |
251 | }\r | |
252 | }\r | |
b3548d32 | 253 | \r |
0c18794e | 254 | if (Info != NULL) {\r |
255 | FreePool (Info);\r | |
256 | }\r | |
257 | return EFI_NOT_FOUND;\r | |
258 | }\r | |
259 | \r | |
0c18794e | 260 | /**\r |
5ec61d41 | 261 | Get file name from device path.\r |
0c18794e | 262 | \r |
b3548d32 LG |
263 | The file name may contain one or more device path node. Save the file name in a\r |
264 | buffer if file name is found. The caller is responsible to free the buffer.\r | |
265 | \r | |
5ec61d41 DG |
266 | @param[in] DevicePath A pointer to a device path.\r |
267 | @param[out] FileName The callee allocated buffer to save the file name if file name is found.\r | |
268 | @param[out] FileNameOffset The offset of file name in device path if file name is found.\r | |
b3548d32 | 269 | \r |
5ec61d41 | 270 | @retval UINTN The file name length. 0 means file name is not found.\r |
0c18794e | 271 | \r |
272 | **/\r | |
b3548d32 | 273 | UINTN\r |
5ec61d41 DG |
274 | GetFileName (\r |
275 | IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r | |
276 | OUT UINT8 **FileName,\r | |
277 | OUT UINTN *FileNameOffset\r | |
0c18794e | 278 | )\r |
279 | {\r | |
5ec61d41 DG |
280 | UINTN Length;\r |
281 | EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;\r | |
282 | EFI_DEVICE_PATH_PROTOCOL *RootDevicePath;\r | |
283 | CHAR8 *NodeStr;\r | |
284 | UINTN NodeStrLength;\r | |
285 | CHAR16 LastNodeChar;\r | |
286 | CHAR16 FirstNodeChar;\r | |
287 | \r | |
288 | //\r | |
289 | // Get the length of DevicePath before file name.\r | |
290 | //\r | |
291 | Length = 0;\r | |
292 | RootDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)DevicePath;\r | |
293 | while (!IsDevicePathEnd (RootDevicePath)) {\r | |
294 | if ((DevicePathType(RootDevicePath) == MEDIA_DEVICE_PATH) && (DevicePathSubType(RootDevicePath) == MEDIA_FILEPATH_DP)) {\r | |
295 | break;\r | |
296 | }\r | |
297 | Length += DevicePathNodeLength (RootDevicePath);\r | |
298 | RootDevicePath = NextDevicePathNode (RootDevicePath);\r | |
299 | }\r | |
0c18794e | 300 | \r |
5ec61d41 DG |
301 | *FileNameOffset = Length;\r |
302 | if (Length == 0) {\r | |
303 | return 0;\r | |
0c18794e | 304 | }\r |
5ec61d41 | 305 | \r |
0c18794e | 306 | //\r |
5ec61d41 | 307 | // Get the file name length.\r |
0c18794e | 308 | //\r |
5ec61d41 DG |
309 | Length = 0;\r |
310 | TmpDevicePath = RootDevicePath;\r | |
311 | while (!IsDevicePathEnd (TmpDevicePath)) {\r | |
312 | if ((DevicePathType(TmpDevicePath) != MEDIA_DEVICE_PATH) || (DevicePathSubType(TmpDevicePath) != MEDIA_FILEPATH_DP)) {\r | |
313 | break;\r | |
0c18794e | 314 | }\r |
5ec61d41 DG |
315 | Length += DevicePathNodeLength (TmpDevicePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL);\r |
316 | TmpDevicePath = NextDevicePathNode (TmpDevicePath);\r | |
317 | }\r | |
318 | if (Length == 0) {\r | |
319 | return 0;\r | |
320 | }\r | |
0c18794e | 321 | \r |
5ec61d41 DG |
322 | *FileName = AllocateZeroPool (Length);\r |
323 | ASSERT (*FileName != NULL);\r | |
324 | \r | |
325 | //\r | |
326 | // Copy the file name to the buffer.\r | |
327 | //\r | |
328 | Length = 0;\r | |
329 | LastNodeChar = '\\';\r | |
330 | TmpDevicePath = RootDevicePath;\r | |
331 | while (!IsDevicePathEnd (TmpDevicePath)) {\r | |
332 | if ((DevicePathType(TmpDevicePath) != MEDIA_DEVICE_PATH) || (DevicePathSubType(TmpDevicePath) != MEDIA_FILEPATH_DP)) {\r | |
333 | break;\r | |
334 | }\r | |
335 | \r | |
336 | FirstNodeChar = (CHAR16) ReadUnaligned16 ((UINT16 *)((UINT8 *)TmpDevicePath + sizeof (EFI_DEVICE_PATH_PROTOCOL)));\r | |
337 | NodeStr = (CHAR8 *)TmpDevicePath + sizeof (EFI_DEVICE_PATH_PROTOCOL);\r | |
338 | NodeStrLength = DevicePathNodeLength (TmpDevicePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL) - sizeof(CHAR16);\r | |
b3548d32 | 339 | \r |
5ec61d41 DG |
340 | if ((FirstNodeChar == '\\') && (LastNodeChar == '\\')) {\r |
341 | //\r | |
342 | // Skip separator "\" when there are two separators.\r | |
343 | //\r | |
344 | NodeStr += sizeof (CHAR16);\r | |
b3548d32 | 345 | NodeStrLength -= sizeof (CHAR16);\r |
5ec61d41 DG |
346 | } else if ((FirstNodeChar != '\\') && (LastNodeChar != '\\')) {\r |
347 | //\r | |
348 | // Add separator "\" when there is no separator.\r | |
349 | //\r | |
350 | WriteUnaligned16 ((UINT16 *)(*FileName + Length), '\\');\r | |
351 | Length += sizeof (CHAR16);\r | |
b3548d32 | 352 | }\r |
5ec61d41 DG |
353 | CopyMem (*FileName + Length, NodeStr, NodeStrLength);\r |
354 | Length += NodeStrLength;\r | |
b3548d32 | 355 | \r |
5ec61d41 DG |
356 | LastNodeChar = (CHAR16) ReadUnaligned16 ((UINT16 *) (NodeStr + NodeStrLength - sizeof(CHAR16)));\r |
357 | TmpDevicePath = NextDevicePathNode (TmpDevicePath);\r | |
b3548d32 | 358 | }\r |
5ec61d41 DG |
359 | \r |
360 | return Length;\r | |
0c18794e | 361 | }\r |
362 | \r | |
363 | \r | |
364 | /**\r | |
365 | Check whether the DevicePath2 is identical with DevicePath1, or identical with\r | |
366 | DevicePath1's child device path.\r | |
367 | \r | |
368 | If DevicePath2 is identical with DevicePath1, or with DevicePath1's child device\r | |
369 | path, then TRUE returned. Otherwise, FALSE is returned.\r | |
b3548d32 | 370 | \r |
0c18794e | 371 | If DevicePath1 is NULL, then ASSERT().\r |
372 | If DevicePath2 is NULL, then ASSERT().\r | |
373 | \r | |
374 | @param[in] DevicePath1 A pointer to a device path.\r | |
375 | @param[in] DevicePath2 A pointer to a device path.\r | |
376 | \r | |
b3548d32 | 377 | @retval TRUE Two device paths are identical , or DevicePath2 is\r |
0c18794e | 378 | DevicePath1's child device path.\r |
b3548d32 | 379 | @retval FALSE Two device paths are not identical, and DevicePath2\r |
0c18794e | 380 | is not DevicePath1's child device path.\r |
381 | \r | |
382 | **/\r | |
383 | BOOLEAN\r | |
384 | CheckDevicePath (\r | |
385 | IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath1,\r | |
386 | IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath2\r | |
387 | )\r | |
388 | {\r | |
5ec61d41 DG |
389 | UINTN DevicePathSize;\r |
390 | UINTN FileNameSize1;\r | |
391 | UINTN FileNameSize2;\r | |
392 | UINT8 *FileName1;\r | |
393 | UINT8 *FileName2;\r | |
394 | UINTN FileNameOffset1;\r | |
395 | UINTN FileNameOffset2;\r | |
396 | BOOLEAN DevicePathEqual;\r | |
397 | \r | |
398 | FileName1 = NULL;\r | |
399 | FileName2 = NULL;\r | |
400 | DevicePathEqual = TRUE;\r | |
0c18794e | 401 | \r |
402 | ASSERT (DevicePath1 != NULL);\r | |
403 | ASSERT (DevicePath2 != NULL);\r | |
5ec61d41 DG |
404 | if (IsDevicePathEnd (DevicePath1)) {\r |
405 | return FALSE;\r | |
406 | }\r | |
b3548d32 | 407 | \r |
0c18794e | 408 | //\r |
b3548d32 | 409 | // The file name may contain one or more device path node.\r |
5ec61d41 | 410 | // To compare the file name, copy file name to a buffer and compare the buffer.\r |
0c18794e | 411 | //\r |
5ec61d41 DG |
412 | FileNameSize1 = GetFileName (DevicePath1, &FileName1, &FileNameOffset1);\r |
413 | if (FileNameSize1 != 0) {\r | |
414 | FileNameSize2 = GetFileName (DevicePath2, &FileName2, &FileNameOffset2);\r | |
415 | if (FileNameOffset1 != FileNameOffset2) {\r | |
416 | DevicePathEqual = FALSE;\r | |
417 | goto Done;\r | |
418 | }\r | |
b3548d32 | 419 | if (CompareMem (DevicePath1, DevicePath2, FileNameOffset1) != 0) {\r |
5ec61d41 DG |
420 | DevicePathEqual = FALSE;\r |
421 | goto Done;\r | |
422 | }\r | |
423 | if (FileNameSize1 > FileNameSize2) {\r | |
424 | DevicePathEqual = FALSE;\r | |
425 | goto Done;\r | |
426 | }\r | |
b3548d32 | 427 | if (CompareMem (FileName1, FileName2, FileNameSize1) != 0) {\r |
5ec61d41 DG |
428 | DevicePathEqual = FALSE;\r |
429 | goto Done;\r | |
430 | }\r | |
431 | DevicePathEqual = TRUE;\r | |
432 | goto Done;\r | |
433 | }\r | |
434 | \r | |
435 | DevicePathSize = GetDevicePathSize (DevicePath1);\r | |
436 | if (DevicePathSize > GetDevicePathSize (DevicePath2)) {\r | |
437 | return FALSE;\r | |
438 | }\r | |
439 | \r | |
0c18794e | 440 | //\r |
5ec61d41 | 441 | // Exclude the end of device path node.\r |
0c18794e | 442 | //\r |
5ec61d41 DG |
443 | DevicePathSize -= sizeof (EFI_DEVICE_PATH_PROTOCOL);\r |
444 | if (CompareMem (DevicePath1, DevicePath2, DevicePathSize) != 0) {\r | |
0c18794e | 445 | DevicePathEqual = FALSE;\r |
b3548d32 LG |
446 | }\r |
447 | \r | |
448 | Done:\r | |
5ec61d41 DG |
449 | if (FileName1 != NULL) {\r |
450 | FreePool (FileName1);\r | |
451 | }\r | |
452 | if (FileName2 != NULL) {\r | |
453 | FreePool (FileName2);\r | |
0c18794e | 454 | }\r |
0c18794e | 455 | return DevicePathEqual;\r |
456 | }\r | |
457 | \r | |
458 | \r | |
459 | /**\r | |
b3548d32 LG |
460 | Check whether the image pointed to by DevicePath is in the device path list\r |
461 | specified by AccessType.\r | |
0c18794e | 462 | \r |
463 | @param[in] DevicePath Points to device path.\r | |
464 | @param[in] AccessType The type of user access control.\r | |
b3548d32 | 465 | \r |
0ab475c9 | 466 | @retval TRUE The DevicePath is in the specified List.\r |
0c18794e | 467 | @retval FALSE The DevicePath is not in the specified List.\r |
468 | \r | |
469 | **/\r | |
470 | BOOLEAN\r | |
471 | IsDevicePathInList (\r | |
472 | IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r | |
473 | IN UINT32 AccessType\r | |
474 | )\r | |
475 | {\r | |
476 | EFI_STATUS Status;\r | |
477 | EFI_USER_INFO_ACCESS_CONTROL *Access;\r | |
478 | EFI_DEVICE_PATH_PROTOCOL *Path;\r | |
b3548d32 | 479 | UINTN OffSet;\r |
0c18794e | 480 | \r |
481 | Status = GetAccessControl (&Access, AccessType);\r | |
482 | if (EFI_ERROR (Status)) {\r | |
483 | return FALSE;\r | |
b3548d32 | 484 | }\r |
0c18794e | 485 | \r |
486 | OffSet = 0;\r | |
487 | while (OffSet < Access->Size - sizeof (EFI_USER_INFO_ACCESS_CONTROL)) {\r | |
b3548d32 | 488 | Path = (EFI_DEVICE_PATH_PROTOCOL*)((UINT8*)(Access + 1) + OffSet);\r |
0c18794e | 489 | if (CheckDevicePath (Path, DevicePath)) {\r |
490 | //\r | |
491 | // The device path is found in list.\r | |
492 | //\r | |
493 | FreePool (Access);\r | |
494 | return TRUE;\r | |
b3548d32 | 495 | }\r |
0c18794e | 496 | OffSet += GetDevicePathSize (Path);\r |
497 | }\r | |
b3548d32 | 498 | \r |
0c18794e | 499 | FreePool (Access);\r |
b3548d32 | 500 | return FALSE;\r |
0c18794e | 501 | }\r |
502 | \r | |
503 | \r | |
504 | /**\r | |
b3548d32 | 505 | Check whether the image pointed to by DevicePath is permitted to load.\r |
0c18794e | 506 | \r |
507 | @param[in] DevicePath Points to device path\r | |
b3548d32 | 508 | \r |
0ab475c9 | 509 | @retval TRUE The image pointed by DevicePath is permitted to load.\r |
0c18794e | 510 | @retval FALSE The image pointed by DevicePath is forbidden to load.\r |
511 | \r | |
512 | **/\r | |
513 | BOOLEAN\r | |
514 | VerifyDevicePath (\r | |
515 | IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath\r | |
516 | )\r | |
517 | {\r | |
518 | if (IsDevicePathInList (DevicePath, EFI_USER_INFO_ACCESS_PERMIT_LOAD)) {\r | |
519 | //\r | |
b3548d32 | 520 | // This access control overrides any restrictions put in place by the\r |
0c18794e | 521 | // EFI_USER_INFO_ACCESS_FORBID_LOAD record.\r |
522 | //\r | |
523 | return TRUE;\r | |
524 | }\r | |
b3548d32 | 525 | \r |
0c18794e | 526 | if (IsDevicePathInList (DevicePath, EFI_USER_INFO_ACCESS_FORBID_LOAD)) {\r |
527 | //\r | |
528 | // The device path is found in the forbidden list.\r | |
529 | //\r | |
530 | return FALSE;\r | |
531 | }\r | |
b3548d32 LG |
532 | \r |
533 | return TRUE;\r | |
0c18794e | 534 | }\r |
535 | \r | |
536 | \r | |
537 | /**\r | |
b3548d32 | 538 | Check the image pointed by DevicePath is a boot option or not.\r |
0c18794e | 539 | \r |
540 | @param[in] DevicePath Points to device path.\r | |
b3548d32 | 541 | \r |
0ab475c9 | 542 | @retval TRUE The image pointed by DevicePath is a boot option.\r |
0c18794e | 543 | @retval FALSE The image pointed by DevicePath is not a boot option.\r |
544 | \r | |
545 | **/\r | |
546 | BOOLEAN\r | |
547 | IsBootOption (\r | |
548 | IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath\r | |
549 | )\r | |
550 | {\r | |
551 | EFI_STATUS Status;\r | |
552 | UINT16 *BootOrderList;\r | |
553 | UINTN BootOrderListSize;\r | |
554 | UINTN Index;\r | |
555 | CHAR16 StrTemp[20];\r | |
556 | UINT8 *OptionBuffer;\r | |
557 | UINT8 *OptionPtr;\r | |
558 | EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath;\r | |
b3548d32 | 559 | \r |
0c18794e | 560 | //\r |
561 | // Get BootOrder\r | |
562 | //\r | |
563 | BootOrderListSize = 0;\r | |
b3548d32 | 564 | BootOrderList = NULL;\r |
0c18794e | 565 | Status = gRT->GetVariable (\r |
b3548d32 LG |
566 | L"BootOrder",\r |
567 | &gEfiGlobalVariableGuid,\r | |
568 | NULL,\r | |
569 | &BootOrderListSize,\r | |
0c18794e | 570 | NULL\r |
571 | );\r | |
572 | if (Status == EFI_BUFFER_TOO_SMALL) {\r | |
573 | BootOrderList = AllocateZeroPool (BootOrderListSize);\r | |
574 | ASSERT (BootOrderList != NULL);\r | |
575 | Status = gRT->GetVariable (\r | |
b3548d32 LG |
576 | L"BootOrder",\r |
577 | &gEfiGlobalVariableGuid,\r | |
578 | NULL,\r | |
579 | &BootOrderListSize,\r | |
0c18794e | 580 | BootOrderList\r |
581 | );\r | |
582 | }\r | |
b3548d32 | 583 | \r |
0c18794e | 584 | if (EFI_ERROR (Status)) {\r |
585 | //\r | |
586 | // No Boot option\r | |
587 | //\r | |
588 | return FALSE;\r | |
589 | }\r | |
590 | \r | |
591 | OptionBuffer = NULL;\r | |
592 | for (Index = 0; Index < BootOrderListSize / sizeof (UINT16); Index++) {\r | |
593 | //\r | |
594 | // Try to find the DevicePath in BootOption\r | |
595 | //\r | |
596 | UnicodeSPrint (StrTemp, sizeof (StrTemp), L"Boot%04x", Index);\r | |
f01b91ae | 597 | GetEfiGlobalVariable2 (StrTemp, (VOID**)&OptionBuffer, NULL);\r |
0c18794e | 598 | if (OptionBuffer == NULL) {\r |
599 | continue;\r | |
600 | }\r | |
601 | \r | |
602 | //\r | |
603 | // Check whether the image is forbidden.\r | |
604 | //\r | |
b3548d32 | 605 | \r |
0c18794e | 606 | OptionPtr = OptionBuffer;\r |
607 | //\r | |
608 | // Skip attribute.\r | |
609 | //\r | |
610 | OptionPtr += sizeof (UINT32);\r | |
611 | \r | |
612 | //\r | |
613 | // Skip device path length.\r | |
614 | //\r | |
615 | OptionPtr += sizeof (UINT16);\r | |
616 | \r | |
617 | //\r | |
618 | // Skip descript string\r | |
619 | //\r | |
620 | OptionPtr += StrSize ((UINT16 *) OptionPtr);\r | |
b3548d32 | 621 | \r |
0c18794e | 622 | //\r |
623 | // Now OptionPtr points to Device Path.\r | |
624 | //\r | |
625 | OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) OptionPtr;\r | |
626 | \r | |
627 | if (CheckDevicePath (DevicePath, OptionDevicePath)) {\r | |
628 | FreePool (OptionBuffer);\r | |
629 | OptionBuffer = NULL;\r | |
630 | return TRUE;\r | |
631 | }\r | |
632 | FreePool (OptionBuffer);\r | |
633 | OptionBuffer = NULL;\r | |
634 | }\r | |
635 | \r | |
636 | if (BootOrderList != NULL) {\r | |
637 | FreePool (BootOrderList);\r | |
638 | }\r | |
639 | \r | |
640 | return FALSE;\r | |
641 | }\r | |
642 | \r | |
643 | \r | |
644 | /**\r | |
645 | Add the image info to a deferred image list.\r | |
646 | \r | |
b3548d32 LG |
647 | @param[in] ImageDevicePath A pointer to the device path of a image.\r |
648 | @param[in] Image Points to the first byte of the image, or NULL if the\r | |
0c18794e | 649 | image is not available.\r |
650 | @param[in] ImageSize The size of the image, or 0 if the image is not available.\r | |
b3548d32 | 651 | \r |
0c18794e | 652 | **/\r |
653 | VOID\r | |
654 | PutDefferedImageInfo (\r | |
655 | IN CONST EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath,\r | |
656 | IN VOID *Image,\r | |
657 | IN UINTN ImageSize\r | |
658 | )\r | |
659 | {\r | |
660 | DEFERRED_IMAGE_INFO *CurImageInfo;\r | |
661 | UINTN PathSize;\r | |
662 | \r | |
663 | //\r | |
664 | // Expand memory for the new deferred image.\r | |
665 | //\r | |
666 | if (mDeferredImage.Count == 0) {\r | |
667 | mDeferredImage.ImageInfo = AllocatePool (sizeof (DEFERRED_IMAGE_INFO));\r | |
668 | ASSERT (mDeferredImage.ImageInfo != NULL);\r | |
669 | } else {\r | |
670 | CurImageInfo = AllocatePool ((mDeferredImage.Count + 1) * sizeof (DEFERRED_IMAGE_INFO));\r | |
671 | ASSERT (CurImageInfo != NULL);\r | |
b3548d32 | 672 | \r |
0c18794e | 673 | CopyMem (\r |
b3548d32 | 674 | CurImageInfo,\r |
0c18794e | 675 | mDeferredImage.ImageInfo,\r |
676 | mDeferredImage.Count * sizeof (DEFERRED_IMAGE_INFO)\r | |
677 | );\r | |
678 | FreePool (mDeferredImage.ImageInfo);\r | |
679 | mDeferredImage.ImageInfo = CurImageInfo;\r | |
680 | }\r | |
681 | mDeferredImage.Count++;\r | |
b3548d32 | 682 | \r |
0c18794e | 683 | //\r |
684 | // Save the deferred image information.\r | |
685 | //\r | |
686 | CurImageInfo = &mDeferredImage.ImageInfo[mDeferredImage.Count - 1];\r | |
687 | PathSize = GetDevicePathSize (ImageDevicePath);\r | |
688 | CurImageInfo->ImageDevicePath = AllocateZeroPool (PathSize);\r | |
689 | ASSERT (CurImageInfo->ImageDevicePath != NULL);\r | |
690 | CopyMem (CurImageInfo->ImageDevicePath, ImageDevicePath, PathSize);\r | |
691 | \r | |
692 | CurImageInfo->Image = Image;\r | |
693 | CurImageInfo->ImageSize = ImageSize;\r | |
694 | CurImageInfo->BootOption = IsBootOption (ImageDevicePath);\r | |
695 | }\r | |
696 | \r | |
697 | \r | |
698 | /**\r | |
699 | Returns information about a deferred image.\r | |
700 | \r | |
b3548d32 LG |
701 | This function returns information about a single deferred image. The deferred images are\r |
702 | numbered consecutively, starting with 0. If there is no image which corresponds to\r | |
703 | ImageIndex, then EFI_NOT_FOUND is returned. All deferred images may be returned by\r | |
0c18794e | 704 | iteratively calling this function until EFI_NOT_FOUND is returned.\r |
b3548d32 LG |
705 | Image may be NULL and ImageSize set to 0 if the decision to defer execution was made\r |
706 | because of the location of the executable image, rather than its actual contents.\r | |
0c18794e | 707 | \r |
708 | @param[in] This Points to this instance of the EFI_DEFERRED_IMAGE_LOAD_PROTOCOL.\r | |
709 | @param[in] ImageIndex Zero-based index of the deferred index.\r | |
b3548d32 LG |
710 | @param[out] ImageDevicePath On return, points to a pointer to the device path of the image.\r |
711 | The device path should not be freed by the caller.\r | |
712 | @param[out] Image On return, points to the first byte of the image or NULL if the\r | |
0c18794e | 713 | image is not available. The image should not be freed by the caller\r |
b3548d32 | 714 | unless LoadImage() has been successfully called.\r |
0c18794e | 715 | @param[out] ImageSize On return, the size of the image, or 0 if the image is not available.\r |
b3548d32 LG |
716 | @param[out] BootOption On return, points to TRUE if the image was intended as a boot option\r |
717 | or FALSE if it was not intended as a boot option.\r | |
718 | \r | |
0c18794e | 719 | @retval EFI_SUCCESS Image information returned successfully.\r |
720 | @retval EFI_NOT_FOUND ImageIndex does not refer to a valid image.\r | |
b3548d32 | 721 | @retval EFI_INVALID_PARAMETER ImageDevicePath is NULL or Image is NULL or ImageSize is NULL or\r |
0c18794e | 722 | BootOption is NULL.\r |
b3548d32 | 723 | \r |
0c18794e | 724 | **/\r |
725 | EFI_STATUS\r | |
726 | EFIAPI\r | |
727 | GetDefferedImageInfo (\r | |
728 | IN EFI_DEFERRED_IMAGE_LOAD_PROTOCOL *This,\r | |
729 | IN UINTN ImageIndex,\r | |
730 | OUT EFI_DEVICE_PATH_PROTOCOL **ImageDevicePath,\r | |
731 | OUT VOID **Image,\r | |
732 | OUT UINTN *ImageSize,\r | |
733 | OUT BOOLEAN *BootOption\r | |
734 | )\r | |
735 | {\r | |
736 | DEFERRED_IMAGE_INFO *ReqImageInfo;\r | |
737 | \r | |
738 | //\r | |
739 | // Check the parameter.\r | |
740 | //\r | |
741 | \r | |
742 | if ((This == NULL) || (ImageSize == NULL) || (Image == NULL)) {\r | |
743 | return EFI_INVALID_PARAMETER;\r | |
744 | }\r | |
b3548d32 | 745 | \r |
0c18794e | 746 | if ((ImageDevicePath == NULL) || (BootOption == NULL)) {\r |
747 | return EFI_INVALID_PARAMETER;\r | |
748 | }\r | |
749 | \r | |
750 | if (ImageIndex >= mDeferredImage.Count) {\r | |
751 | return EFI_NOT_FOUND;\r | |
752 | }\r | |
b3548d32 | 753 | \r |
0c18794e | 754 | //\r |
755 | // Get the request deferred image.\r | |
b3548d32 | 756 | //\r |
0c18794e | 757 | ReqImageInfo = &mDeferredImage.ImageInfo[ImageIndex];\r |
b3548d32 | 758 | \r |
0c18794e | 759 | *ImageDevicePath = ReqImageInfo->ImageDevicePath;\r |
760 | *Image = ReqImageInfo->Image;\r | |
761 | *ImageSize = ReqImageInfo->ImageSize;\r | |
762 | *BootOption = ReqImageInfo->BootOption;\r | |
b3548d32 | 763 | \r |
0c18794e | 764 | return EFI_SUCCESS;\r |
765 | }\r | |
766 | \r | |
767 | \r | |
768 | /**\r | |
769 | Provides the service of deferring image load based on platform policy control,\r | |
770 | and installs Deferred Image Load Protocol.\r | |
771 | \r | |
b3548d32 | 772 | @param[in] AuthenticationStatus This is the authentication status returned from the\r |
0c18794e | 773 | security measurement services for the input file.\r |
774 | @param[in] File This is a pointer to the device path of the file that\r | |
775 | is being dispatched. This will optionally be used for\r | |
776 | logging.\r | |
777 | @param[in] FileBuffer File buffer matches the input file device path.\r | |
778 | @param[in] FileSize Size of File buffer matches the input file device path.\r | |
5db28a67 LG |
779 | @param[in] BootPolicy A boot policy that was used to call LoadImage() UEFI service.\r |
780 | \r | |
781 | @retval EFI_SUCCESS FileBuffer is NULL and current user has permission to start\r | |
782 | UEFI device drivers on the device path specified by DevicePath.\r | |
783 | @retval EFI_SUCCESS The file specified by DevicePath and non-NULL\r | |
784 | FileBuffer did authenticate, and the platform policy dictates\r | |
785 | that the DXE Foundation may use the file.\r | |
786 | @retval EFI_SECURITY_VIOLATION FileBuffer is NULL and the user has no\r | |
787 | permission to start UEFI device drivers on the device path specified\r | |
788 | by DevicePath.\r | |
789 | @retval EFI_SECURITY_VIOLATION FileBuffer is not NULL and the user has no permission to load\r | |
790 | drivers from the device path specified by DevicePath. The\r | |
791 | image has been added into the list of the deferred images.\r | |
792 | @retval EFI_ACCESS_DENIED The file specified by File and FileBuffer did not\r | |
793 | authenticate, and the platform policy dictates that the DXE\r | |
794 | Foundation many not use File.\r | |
0c18794e | 795 | \r |
796 | **/\r | |
797 | EFI_STATUS\r | |
798 | EFIAPI\r | |
799 | DxeDeferImageLoadHandler (\r | |
800 | IN UINT32 AuthenticationStatus,\r | |
801 | IN CONST EFI_DEVICE_PATH_PROTOCOL *File,\r | |
802 | IN VOID *FileBuffer,\r | |
5db28a67 LG |
803 | IN UINTN FileSize,\r |
804 | IN BOOLEAN BootPolicy\r | |
0c18794e | 805 | )\r |
0c18794e | 806 | {\r |
807 | EFI_STATUS Status;\r | |
808 | EFI_USER_PROFILE_HANDLE CurrentUser;\r | |
809 | UINT32 Policy;\r | |
810 | UINT32 FileType;\r | |
811 | \r | |
5db28a67 LG |
812 | //\r |
813 | // Ignore if File is NULL.\r | |
814 | //\r | |
0c18794e | 815 | if (File == NULL) {\r |
5db28a67 | 816 | return EFI_SUCCESS;\r |
0c18794e | 817 | }\r |
818 | \r | |
819 | //\r | |
820 | // Check whether user has a logon.\r | |
b3548d32 | 821 | //\r |
0c18794e | 822 | CurrentUser = NULL;\r |
823 | if (mUserManager != NULL) {\r | |
824 | mUserManager->Current (mUserManager, &CurrentUser);\r | |
825 | if (CurrentUser != NULL) {\r | |
826 | //\r | |
827 | // The user is logon; verify the FilePath by current user access policy.\r | |
828 | //\r | |
829 | if (!VerifyDevicePath (File)) {\r | |
830 | DEBUG ((EFI_D_ERROR, "[Security] The image is forbidden to load!\n"));\r | |
5db28a67 | 831 | return EFI_SECURITY_VIOLATION;\r |
0c18794e | 832 | }\r |
833 | return EFI_SUCCESS;\r | |
834 | }\r | |
835 | }\r | |
b3548d32 | 836 | \r |
0c18794e | 837 | //\r |
838 | // Still no user logon.\r | |
839 | // Check the file type and get policy setting.\r | |
840 | //\r | |
841 | FileType = GetFileType (File);\r | |
842 | Policy = PcdGet32 (PcdDeferImageLoadPolicy);\r | |
843 | if ((Policy & FileType) == FileType) {\r | |
844 | //\r | |
845 | // This file type is secure to load.\r | |
846 | //\r | |
847 | return EFI_SUCCESS;\r | |
848 | }\r | |
b3548d32 | 849 | \r |
33985e3b | 850 | DEBUG ((EFI_D_INFO, "[Security] No user identified, the image is deferred to load!\n"));\r |
5db28a67 | 851 | PutDefferedImageInfo (File, FileBuffer, FileSize);\r |
0c18794e | 852 | \r |
853 | //\r | |
854 | // Install the Deferred Image Load Protocol onto a new handle.\r | |
855 | //\r | |
856 | if (!mIsProtocolInstalled) {\r | |
857 | Status = gBS->InstallMultipleProtocolInterfaces (\r | |
858 | &mDeferredImageHandle,\r | |
859 | &gEfiDeferredImageLoadProtocolGuid,\r | |
860 | &gDeferredImageLoad,\r | |
861 | NULL\r | |
862 | );\r | |
863 | ASSERT_EFI_ERROR (Status);\r | |
864 | mIsProtocolInstalled = TRUE;\r | |
865 | }\r | |
866 | \r | |
867 | return EFI_ACCESS_DENIED;\r | |
868 | }\r | |
869 | \r | |
870 | /**\r | |
b3548d32 | 871 | Locate user manager protocol when user manager is installed.\r |
0c18794e | 872 | \r |
873 | @param[in] Event The Event that is being processed, not used.\r | |
b3548d32 | 874 | @param[in] Context Event Context, not used.\r |
0c18794e | 875 | \r |
876 | **/\r | |
877 | VOID\r | |
878 | EFIAPI\r | |
879 | FindUserManagerProtocol (\r | |
880 | IN EFI_EVENT Event,\r | |
881 | IN VOID* Context\r | |
882 | )\r | |
883 | {\r | |
884 | gBS->LocateProtocol (\r | |
885 | &gEfiUserManagerProtocolGuid,\r | |
886 | NULL,\r | |
887 | (VOID **) &mUserManager\r | |
888 | );\r | |
b3548d32 | 889 | \r |
0c18794e | 890 | }\r |
891 | \r | |
892 | \r | |
893 | /**\r | |
894 | Register security handler for deferred image load.\r | |
895 | \r | |
896 | @param[in] ImageHandle ImageHandle of the loaded driver.\r | |
897 | @param[in] SystemTable Pointer to the EFI System Table.\r | |
898 | \r | |
899 | @retval EFI_SUCCESS The handlers were registered successfully.\r | |
900 | **/\r | |
901 | EFI_STATUS\r | |
902 | EFIAPI\r | |
903 | DxeDeferImageLoadLibConstructor (\r | |
904 | IN EFI_HANDLE ImageHandle,\r | |
905 | IN EFI_SYSTEM_TABLE *SystemTable\r | |
906 | )\r | |
907 | {\r | |
908 | VOID *Registration;\r | |
b3548d32 | 909 | \r |
0c18794e | 910 | //\r |
911 | // Register user manager notification function.\r | |
912 | //\r | |
913 | EfiCreateProtocolNotifyEvent (\r | |
b3548d32 | 914 | &gEfiUserManagerProtocolGuid,\r |
0c18794e | 915 | TPL_CALLBACK,\r |
916 | FindUserManagerProtocol,\r | |
917 | NULL,\r | |
918 | &Registration\r | |
919 | );\r | |
b3548d32 | 920 | \r |
5db28a67 | 921 | return RegisterSecurity2Handler (\r |
0c18794e | 922 | DxeDeferImageLoadHandler,\r |
b3548d32 LG |
923 | EFI_AUTH_OPERATION_DEFER_IMAGE_LOAD\r |
924 | );\r | |
0c18794e | 925 | }\r |
926 | \r | |
927 | \r |