]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.c
1. Fix TOCTOU issue in VariableSmm, FtwSmm, FpdtSmm, SmmCorePerformance SMM handler...
[mirror_edk2.git] / MdeModulePkg / Universal / LockBox / SmmLockBox / SmmLockBox.c
CommitLineData
1c837cd5 1/** @file\r
e8c758dc
HT
2 LockBox SMM driver.\r
3 \r
32177f69
JY
4 Caution: This module requires additional review when modified.\r
5 This driver will have external input - communicate buffer in SMM mode.\r
6 This external input must be validated carefully to avoid security issue like\r
7 buffer overflow, integer overflow.\r
e8c758dc 8 \r
32177f69
JY
9 SmmLockBoxHandler(), SmmLockBoxRestore(), SmmLockBoxUpdate(), SmmLockBoxSave()\r
10 will receive untrusted input and do basic validation.\r
1c837cd5 11\r
9d00d20e 12Copyright (c) 2010 - 2013, Intel Corporation. All rights reserved.<BR>\r
e8c758dc 13\r
1c837cd5 14This program and the accompanying materials\r
15are licensed and made available under the terms and conditions\r
16of the BSD License which accompanies this distribution. The\r
17full text of the license may be found at\r
18http://opensource.org/licenses/bsd-license.php\r
19\r
20THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
21WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
22\r
23**/\r
24\r
25#include <PiSmm.h>\r
26#include <Library/UefiDriverEntryPoint.h>\r
27#include <Library/UefiBootServicesTableLib.h>\r
28#include <Library/UefiRuntimeServicesTableLib.h>\r
29#include <Library/SmmServicesTableLib.h>\r
30#include <Library/BaseLib.h>\r
31#include <Library/BaseMemoryLib.h>\r
32#include <Library/DebugLib.h>\r
33#include <Library/LockBoxLib.h>\r
34#include <Protocol/SmmReadyToLock.h>\r
35#include <Protocol/SmmCommunication.h>\r
36#include <Protocol/SmmAccess2.h>\r
37#include <Protocol/LockBox.h>\r
38#include <Guid/SmmLockBox.h>\r
39\r
40BOOLEAN mLocked = FALSE;\r
41\r
42EFI_SMRAM_DESCRIPTOR *mSmramRanges;\r
43UINTN mSmramRangeCount;\r
44\r
45/**\r
46 This function check if the address is in SMRAM.\r
47\r
48 @param Buffer the buffer address to be checked.\r
49 @param Length the buffer length to be checked.\r
50\r
51 @retval TRUE this address is in SMRAM.\r
52 @retval FALSE this address is NOT in SMRAM.\r
53**/\r
54BOOLEAN\r
55IsAddressInSmram (\r
56 IN EFI_PHYSICAL_ADDRESS Buffer,\r
57 IN UINT64 Length\r
58 )\r
59{\r
60 UINTN Index;\r
61\r
62 for (Index = 0; Index < mSmramRangeCount; Index ++) {\r
63 if (((Buffer >= mSmramRanges[Index].CpuStart) && (Buffer < mSmramRanges[Index].CpuStart + mSmramRanges[Index].PhysicalSize)) ||\r
64 ((mSmramRanges[Index].CpuStart >= Buffer) && (mSmramRanges[Index].CpuStart < Buffer + Length))) {\r
65 return TRUE;\r
66 }\r
67 }\r
68\r
69 return FALSE;\r
70}\r
71\r
32177f69
JY
72/**\r
73 This function check if the address refered by Buffer and Length is valid.\r
74\r
75 @param Buffer the buffer address to be checked.\r
76 @param Length the buffer length to be checked.\r
77\r
78 @retval TRUE this address is valid.\r
79 @retval FALSE this address is NOT valid.\r
80**/\r
81BOOLEAN\r
82IsAddressValid (\r
83 IN UINTN Buffer,\r
84 IN UINTN Length\r
85 )\r
86{\r
87 if (Buffer > (MAX_ADDRESS - Length)) {\r
88 //\r
89 // Overflow happen\r
90 //\r
91 return FALSE;\r
92 }\r
93 if (IsAddressInSmram ((EFI_PHYSICAL_ADDRESS)Buffer, (UINT64)Length)) {\r
94 return FALSE;\r
95 }\r
96 return TRUE;\r
97}\r
98\r
1c837cd5 99/**\r
100 Dispatch function for SMM lock box save.\r
101\r
32177f69
JY
102 Caution: This function may receive untrusted input.\r
103 Restore buffer and length are external input, so this function will validate\r
104 it is in SMRAM.\r
105\r
1c837cd5 106 @param LockBoxParameterSave parameter of lock box save \r
107**/\r
108VOID\r
109SmmLockBoxSave (\r
110 IN EFI_SMM_LOCK_BOX_PARAMETER_SAVE *LockBoxParameterSave\r
111 )\r
112{\r
113 EFI_STATUS Status;\r
5e5bb2a9 114 EFI_SMM_LOCK_BOX_PARAMETER_SAVE TempLockBoxParameterSave;\r
1c837cd5 115\r
116 //\r
117 // Sanity check\r
118 //\r
119 if (mLocked) {\r
120 DEBUG ((EFI_D_ERROR, "SmmLockBox Locked!\n"));\r
121 LockBoxParameterSave->Header.ReturnStatus = (UINT64)EFI_ACCESS_DENIED;\r
122 return ;\r
123 }\r
124\r
5e5bb2a9
SZ
125 CopyMem (&TempLockBoxParameterSave, LockBoxParameterSave, sizeof (EFI_SMM_LOCK_BOX_PARAMETER_SAVE));\r
126\r
32177f69
JY
127 //\r
128 // Sanity check\r
129 //\r
5e5bb2a9 130 if (!IsAddressValid ((UINTN)TempLockBoxParameterSave.Buffer, (UINTN)TempLockBoxParameterSave.Length)) {\r
9d00d20e 131 DEBUG ((EFI_D_ERROR, "SmmLockBox Save address in SMRAM or buffer overflow!\n"));\r
32177f69
JY
132 LockBoxParameterSave->Header.ReturnStatus = (UINT64)EFI_ACCESS_DENIED;\r
133 return ;\r
134 }\r
135\r
1c837cd5 136 //\r
137 // Save data\r
138 //\r
139 Status = SaveLockBox (\r
5e5bb2a9
SZ
140 &TempLockBoxParameterSave.Guid,\r
141 (VOID *)(UINTN)TempLockBoxParameterSave.Buffer,\r
142 (UINTN)TempLockBoxParameterSave.Length\r
1c837cd5 143 );\r
144 LockBoxParameterSave->Header.ReturnStatus = (UINT64)Status;\r
145 return ;\r
146}\r
147\r
148/**\r
149 Dispatch function for SMM lock box set attributes.\r
150\r
151 @param LockBoxParameterSetAttributes parameter of lock box set attributes\r
152**/\r
153VOID\r
154SmmLockBoxSetAttributes (\r
155 IN EFI_SMM_LOCK_BOX_PARAMETER_SET_ATTRIBUTES *LockBoxParameterSetAttributes\r
156 )\r
157{\r
158 EFI_STATUS Status;\r
5e5bb2a9 159 EFI_SMM_LOCK_BOX_PARAMETER_SET_ATTRIBUTES TempLockBoxParameterSetAttributes;\r
1c837cd5 160\r
161 //\r
162 // Sanity check\r
163 //\r
164 if (mLocked) {\r
165 DEBUG ((EFI_D_ERROR, "SmmLockBox Locked!\n"));\r
166 LockBoxParameterSetAttributes->Header.ReturnStatus = (UINT64)EFI_ACCESS_DENIED;\r
167 return ;\r
168 }\r
169\r
5e5bb2a9
SZ
170 CopyMem (&TempLockBoxParameterSetAttributes, LockBoxParameterSetAttributes, sizeof (EFI_SMM_LOCK_BOX_PARAMETER_SET_ATTRIBUTES));\r
171\r
1c837cd5 172 //\r
173 // Update data\r
174 //\r
175 Status = SetLockBoxAttributes (\r
5e5bb2a9
SZ
176 &TempLockBoxParameterSetAttributes.Guid,\r
177 TempLockBoxParameterSetAttributes.Attributes\r
1c837cd5 178 );\r
179 LockBoxParameterSetAttributes->Header.ReturnStatus = (UINT64)Status;\r
180 return ;\r
181}\r
182\r
183/**\r
184 Dispatch function for SMM lock box update.\r
185\r
32177f69
JY
186 Caution: This function may receive untrusted input.\r
187 Restore buffer and length are external input, so this function will validate\r
188 it is in SMRAM.\r
189\r
1c837cd5 190 @param LockBoxParameterUpdate parameter of lock box update \r
191**/\r
192VOID\r
193SmmLockBoxUpdate (\r
194 IN EFI_SMM_LOCK_BOX_PARAMETER_UPDATE *LockBoxParameterUpdate\r
195 )\r
196{\r
197 EFI_STATUS Status;\r
5e5bb2a9 198 EFI_SMM_LOCK_BOX_PARAMETER_UPDATE TempLockBoxParameterUpdate;\r
1c837cd5 199\r
200 //\r
201 // Sanity check\r
202 //\r
203 if (mLocked) {\r
204 DEBUG ((EFI_D_ERROR, "SmmLockBox Locked!\n"));\r
205 LockBoxParameterUpdate->Header.ReturnStatus = (UINT64)EFI_ACCESS_DENIED;\r
206 return ;\r
207 }\r
208\r
5e5bb2a9
SZ
209 CopyMem (&TempLockBoxParameterUpdate, LockBoxParameterUpdate, sizeof (EFI_SMM_LOCK_BOX_PARAMETER_UPDATE));\r
210\r
32177f69
JY
211 //\r
212 // Sanity check\r
213 //\r
5e5bb2a9 214 if (!IsAddressValid ((UINTN)TempLockBoxParameterUpdate.Buffer, (UINTN)TempLockBoxParameterUpdate.Length)) {\r
9d00d20e 215 DEBUG ((EFI_D_ERROR, "SmmLockBox Update address in SMRAM or buffer overflow!\n"));\r
32177f69
JY
216 LockBoxParameterUpdate->Header.ReturnStatus = (UINT64)EFI_ACCESS_DENIED;\r
217 return ;\r
218 }\r
219\r
1c837cd5 220 //\r
221 // Update data\r
222 //\r
223 Status = UpdateLockBox (\r
5e5bb2a9
SZ
224 &TempLockBoxParameterUpdate.Guid,\r
225 (UINTN)TempLockBoxParameterUpdate.Offset,\r
226 (VOID *)(UINTN)TempLockBoxParameterUpdate.Buffer,\r
227 (UINTN)TempLockBoxParameterUpdate.Length\r
1c837cd5 228 );\r
229 LockBoxParameterUpdate->Header.ReturnStatus = (UINT64)Status;\r
230 return ;\r
231}\r
232\r
233/**\r
234 Dispatch function for SMM lock box restore.\r
235\r
32177f69
JY
236 Caution: This function may receive untrusted input.\r
237 Restore buffer and length are external input, so this function will validate\r
238 it is in SMRAM.\r
239\r
1c837cd5 240 @param LockBoxParameterRestore parameter of lock box restore \r
241**/\r
242VOID\r
243SmmLockBoxRestore (\r
244 IN EFI_SMM_LOCK_BOX_PARAMETER_RESTORE *LockBoxParameterRestore\r
245 )\r
246{\r
247 EFI_STATUS Status;\r
5e5bb2a9
SZ
248 EFI_SMM_LOCK_BOX_PARAMETER_RESTORE TempLockBoxParameterRestore;\r
249\r
250 CopyMem (&TempLockBoxParameterRestore, LockBoxParameterRestore, sizeof (EFI_SMM_LOCK_BOX_PARAMETER_RESTORE));\r
1c837cd5 251\r
252 //\r
253 // Sanity check\r
254 //\r
5e5bb2a9 255 if (!IsAddressValid ((UINTN)TempLockBoxParameterRestore.Buffer, (UINTN)TempLockBoxParameterRestore.Length)) {\r
9d00d20e 256 DEBUG ((EFI_D_ERROR, "SmmLockBox Restore address in SMRAM or buffer overflow!\n"));\r
1c837cd5 257 LockBoxParameterRestore->Header.ReturnStatus = (UINT64)EFI_ACCESS_DENIED;\r
258 return ;\r
259 }\r
260\r
261 //\r
262 // Restore data\r
263 //\r
5e5bb2a9 264 if ((TempLockBoxParameterRestore.Length == 0) && (TempLockBoxParameterRestore.Buffer == 0)) {\r
1476a257 265 Status = RestoreLockBox (\r
5e5bb2a9 266 &TempLockBoxParameterRestore.Guid,\r
1476a257 267 NULL,\r
268 NULL\r
269 );\r
270 } else {\r
271 Status = RestoreLockBox (\r
5e5bb2a9
SZ
272 &TempLockBoxParameterRestore.Guid,\r
273 (VOID *)(UINTN)TempLockBoxParameterRestore.Buffer,\r
274 (UINTN *)&TempLockBoxParameterRestore.Length\r
1476a257 275 );\r
276 }\r
1c837cd5 277 LockBoxParameterRestore->Header.ReturnStatus = (UINT64)Status;\r
278 return ;\r
279}\r
280\r
281/**\r
282 Dispatch function for SMM lock box restore all in place.\r
283\r
284 @param LockBoxParameterRestoreAllInPlace parameter of lock box restore all in place\r
285**/\r
286VOID\r
287SmmLockBoxRestoreAllInPlace (\r
288 IN EFI_SMM_LOCK_BOX_PARAMETER_RESTORE_ALL_IN_PLACE *LockBoxParameterRestoreAllInPlace\r
289 )\r
290{\r
291 EFI_STATUS Status;\r
292\r
293 Status = RestoreAllLockBoxInPlace ();\r
294 LockBoxParameterRestoreAllInPlace->Header.ReturnStatus = (UINT64)Status;\r
295 return ;\r
296}\r
297\r
298/**\r
299 Dispatch function for a Software SMI handler.\r
300\r
32177f69
JY
301 Caution: This function may receive untrusted input.\r
302 Communicate buffer and buffer size are external input, so this function will do basic validation.\r
303\r
1c837cd5 304 @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().\r
305 @param Context Points to an optional handler context which was specified when the\r
306 handler was registered.\r
307 @param CommBuffer A pointer to a collection of data in memory that will\r
308 be conveyed from a non-SMM environment into an SMM environment.\r
309 @param CommBufferSize The size of the CommBuffer.\r
310\r
311 @retval EFI_SUCCESS Command is handled successfully.\r
312\r
313**/\r
314EFI_STATUS\r
315EFIAPI\r
316SmmLockBoxHandler (\r
317 IN EFI_HANDLE DispatchHandle,\r
318 IN CONST VOID *Context OPTIONAL,\r
319 IN OUT VOID *CommBuffer OPTIONAL,\r
320 IN OUT UINTN *CommBufferSize OPTIONAL\r
321 )\r
322{\r
323 EFI_SMM_LOCK_BOX_PARAMETER_HEADER *LockBoxParameterHeader;\r
324\r
325 DEBUG ((EFI_D_ERROR, "SmmLockBox SmmLockBoxHandler Enter\n"));\r
326\r
32177f69
JY
327 //\r
328 // Sanity check\r
329 //\r
330 if (*CommBufferSize < sizeof(EFI_SMM_LOCK_BOX_PARAMETER_HEADER)) {\r
331 DEBUG ((EFI_D_ERROR, "SmmLockBox Command Buffer Size invalid!\n"));\r
332 return EFI_SUCCESS;\r
333 }\r
334 if (!IsAddressValid ((UINTN)CommBuffer, *CommBufferSize)) {\r
9d00d20e 335 DEBUG ((EFI_D_ERROR, "SmmLockBox Command Buffer in SMRAM or overflow!\n"));\r
32177f69
JY
336 return EFI_SUCCESS;\r
337 }\r
338\r
1c837cd5 339 LockBoxParameterHeader = (EFI_SMM_LOCK_BOX_PARAMETER_HEADER *)((UINTN)CommBuffer);\r
340\r
341 LockBoxParameterHeader->ReturnStatus = (UINT64)-1;\r
342\r
343 DEBUG ((EFI_D_ERROR, "SmmLockBox LockBoxParameterHeader - %x\n", (UINTN)LockBoxParameterHeader));\r
344\r
345 DEBUG ((EFI_D_ERROR, "SmmLockBox Command - %x\n", (UINTN)LockBoxParameterHeader->Command));\r
346\r
347 switch (LockBoxParameterHeader->Command) {\r
348 case EFI_SMM_LOCK_BOX_COMMAND_SAVE:\r
32177f69
JY
349 if (*CommBufferSize < sizeof(EFI_SMM_LOCK_BOX_PARAMETER_SAVE)) {\r
350 DEBUG ((EFI_D_ERROR, "SmmLockBox Command Buffer Size for SAVE invalid!\n"));\r
351 break;\r
352 }\r
1c837cd5 353 SmmLockBoxSave ((EFI_SMM_LOCK_BOX_PARAMETER_SAVE *)(UINTN)LockBoxParameterHeader);\r
354 break;\r
355 case EFI_SMM_LOCK_BOX_COMMAND_UPDATE:\r
32177f69
JY
356 if (*CommBufferSize < sizeof(EFI_SMM_LOCK_BOX_PARAMETER_UPDATE)) {\r
357 DEBUG ((EFI_D_ERROR, "SmmLockBox Command Buffer Size for UPDATE invalid!\n"));\r
358 break;\r
359 }\r
1c837cd5 360 SmmLockBoxUpdate ((EFI_SMM_LOCK_BOX_PARAMETER_UPDATE *)(UINTN)LockBoxParameterHeader);\r
361 break;\r
362 case EFI_SMM_LOCK_BOX_COMMAND_RESTORE:\r
32177f69
JY
363 if (*CommBufferSize < sizeof(EFI_SMM_LOCK_BOX_PARAMETER_RESTORE)) {\r
364 DEBUG ((EFI_D_ERROR, "SmmLockBox Command Buffer Size for RESTORE invalid!\n"));\r
365 break;\r
366 }\r
1c837cd5 367 SmmLockBoxRestore ((EFI_SMM_LOCK_BOX_PARAMETER_RESTORE *)(UINTN)LockBoxParameterHeader);\r
368 break;\r
369 case EFI_SMM_LOCK_BOX_COMMAND_SET_ATTRIBUTES:\r
32177f69
JY
370 if (*CommBufferSize < sizeof(EFI_SMM_LOCK_BOX_PARAMETER_SET_ATTRIBUTES)) {\r
371 DEBUG ((EFI_D_ERROR, "SmmLockBox Command Buffer Size for SET_ATTRIBUTES invalid!\n"));\r
372 break;\r
373 }\r
1c837cd5 374 SmmLockBoxSetAttributes ((EFI_SMM_LOCK_BOX_PARAMETER_SET_ATTRIBUTES *)(UINTN)LockBoxParameterHeader);\r
375 break;\r
376 case EFI_SMM_LOCK_BOX_COMMAND_RESTORE_ALL_IN_PLACE:\r
32177f69
JY
377 if (*CommBufferSize < sizeof(EFI_SMM_LOCK_BOX_PARAMETER_RESTORE_ALL_IN_PLACE)) {\r
378 DEBUG ((EFI_D_ERROR, "SmmLockBox Command Buffer Size for RESTORE_ALL_IN_PLACE invalid!\n"));\r
379 break;\r
380 }\r
1c837cd5 381 SmmLockBoxRestoreAllInPlace ((EFI_SMM_LOCK_BOX_PARAMETER_RESTORE_ALL_IN_PLACE *)(UINTN)LockBoxParameterHeader);\r
382 break;\r
383 default:\r
32177f69 384 DEBUG ((EFI_D_ERROR, "SmmLockBox Command invalid!\n"));\r
1c837cd5 385 break;\r
386 }\r
387\r
388 LockBoxParameterHeader->Command = (UINT32)-1;\r
389\r
390 DEBUG ((EFI_D_ERROR, "SmmLockBox SmmLockBoxHandler Exit\n"));\r
391\r
392 return EFI_SUCCESS;\r
393}\r
394\r
395/**\r
396 Smm Ready To Lock event notification handler.\r
397\r
398 It sets a flag indicating that SMRAM has been locked.\r
399 \r
400 @param[in] Protocol Points to the protocol's unique identifier.\r
401 @param[in] Interface Points to the interface instance.\r
402 @param[in] Handle The handle on which the interface was installed.\r
403\r
404 @retval EFI_SUCCESS Notification handler runs successfully.\r
405 **/\r
406EFI_STATUS\r
407EFIAPI\r
408SmmReadyToLockEventNotify (\r
409 IN CONST EFI_GUID *Protocol,\r
410 IN VOID *Interface,\r
411 IN EFI_HANDLE Handle\r
412 )\r
413{\r
414 mLocked = TRUE;\r
415 return EFI_SUCCESS;\r
416}\r
417\r
418/**\r
419 Entry Point for LockBox SMM driver.\r
420\r
421 @param[in] ImageHandle Image handle of this driver.\r
422 @param[in] SystemTable A Pointer to the EFI System Table.\r
423\r
424 @retval EFI_SUCEESS \r
425 @return Others Some error occurs.\r
426**/\r
427EFI_STATUS\r
428EFIAPI\r
429SmmLockBoxEntryPoint (\r
430 IN EFI_HANDLE ImageHandle,\r
431 IN EFI_SYSTEM_TABLE *SystemTable\r
432 )\r
433{\r
434 EFI_STATUS Status;\r
435 EFI_HANDLE DispatchHandle;\r
436 VOID *Registration;\r
437 EFI_SMM_ACCESS2_PROTOCOL *SmmAccess;\r
438 UINTN Size;\r
439\r
440 //\r
441 // Get SMRAM information\r
442 //\r
443 Status = gBS->LocateProtocol (&gEfiSmmAccess2ProtocolGuid, NULL, (VOID **)&SmmAccess);\r
444 ASSERT_EFI_ERROR (Status);\r
445\r
446 Size = 0;\r
447 Status = SmmAccess->GetCapabilities (SmmAccess, &Size, NULL);\r
448 ASSERT (Status == EFI_BUFFER_TOO_SMALL);\r
449\r
450 Status = gSmst->SmmAllocatePool (\r
451 EfiRuntimeServicesData,\r
452 Size,\r
453 (VOID **)&mSmramRanges\r
454 );\r
455 ASSERT_EFI_ERROR (Status);\r
456\r
457 Status = SmmAccess->GetCapabilities (SmmAccess, &Size, mSmramRanges);\r
458 ASSERT_EFI_ERROR (Status);\r
459\r
460 mSmramRangeCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR);\r
461\r
462 //\r
463 // Register LockBox communication handler\r
464 //\r
465 Status = gSmst->SmiHandlerRegister (\r
466 SmmLockBoxHandler,\r
467 &gEfiSmmLockBoxCommunicationGuid,\r
468 &DispatchHandle\r
469 );\r
470 ASSERT_EFI_ERROR (Status);\r
471\r
472 //\r
473 // Register SMM Ready To Lock Protocol notification\r
474 //\r
475 Status = gSmst->SmmRegisterProtocolNotify (\r
476 &gEfiSmmReadyToLockProtocolGuid,\r
477 SmmReadyToLockEventNotify,\r
478 &Registration\r
479 );\r
480 ASSERT_EFI_ERROR (Status);\r
481\r
482 //\r
483 // Install NULL to DXE data base as notify\r
484 //\r
485 ImageHandle = NULL;\r
486 Status = gBS->InstallProtocolInterface (\r
487 &ImageHandle,\r
488 &gEfiLockBoxProtocolGuid,\r
489 EFI_NATIVE_INTERFACE,\r
490 NULL\r
491 );\r
492 ASSERT_EFI_ERROR (Status);\r
493\r
494 return Status;\r
495}\r