DxeDeferImageLoadLib.c 28 KB

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