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