]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.c
1. Use the check IsAddressValid() to prevent SMM communication buffer overflow in...
[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
114\r
115 //\r
116 // Sanity check\r
117 //\r
118 if (mLocked) {\r
119 DEBUG ((EFI_D_ERROR, "SmmLockBox Locked!\n"));\r
120 LockBoxParameterSave->Header.ReturnStatus = (UINT64)EFI_ACCESS_DENIED;\r
121 return ;\r
122 }\r
123\r
32177f69
JY
124 //\r
125 // Sanity check\r
126 //\r
127 if (!IsAddressValid ((UINTN)LockBoxParameterSave->Buffer, (UINTN)LockBoxParameterSave->Length)) {\r
9d00d20e 128 DEBUG ((EFI_D_ERROR, "SmmLockBox Save address in SMRAM or buffer overflow!\n"));\r
32177f69
JY
129 LockBoxParameterSave->Header.ReturnStatus = (UINT64)EFI_ACCESS_DENIED;\r
130 return ;\r
131 }\r
132\r
1c837cd5 133 //\r
134 // Save data\r
135 //\r
136 Status = SaveLockBox (\r
137 &LockBoxParameterSave->Guid,\r
138 (VOID *)(UINTN)LockBoxParameterSave->Buffer,\r
139 (UINTN)LockBoxParameterSave->Length\r
140 );\r
141 LockBoxParameterSave->Header.ReturnStatus = (UINT64)Status;\r
142 return ;\r
143}\r
144\r
145/**\r
146 Dispatch function for SMM lock box set attributes.\r
147\r
148 @param LockBoxParameterSetAttributes parameter of lock box set attributes\r
149**/\r
150VOID\r
151SmmLockBoxSetAttributes (\r
152 IN EFI_SMM_LOCK_BOX_PARAMETER_SET_ATTRIBUTES *LockBoxParameterSetAttributes\r
153 )\r
154{\r
155 EFI_STATUS Status;\r
156\r
157 //\r
158 // Sanity check\r
159 //\r
160 if (mLocked) {\r
161 DEBUG ((EFI_D_ERROR, "SmmLockBox Locked!\n"));\r
162 LockBoxParameterSetAttributes->Header.ReturnStatus = (UINT64)EFI_ACCESS_DENIED;\r
163 return ;\r
164 }\r
165\r
166 //\r
167 // Update data\r
168 //\r
169 Status = SetLockBoxAttributes (\r
170 &LockBoxParameterSetAttributes->Guid,\r
171 LockBoxParameterSetAttributes->Attributes\r
172 );\r
173 LockBoxParameterSetAttributes->Header.ReturnStatus = (UINT64)Status;\r
174 return ;\r
175}\r
176\r
177/**\r
178 Dispatch function for SMM lock box update.\r
179\r
32177f69
JY
180 Caution: This function may receive untrusted input.\r
181 Restore buffer and length are external input, so this function will validate\r
182 it is in SMRAM.\r
183\r
1c837cd5 184 @param LockBoxParameterUpdate parameter of lock box update \r
185**/\r
186VOID\r
187SmmLockBoxUpdate (\r
188 IN EFI_SMM_LOCK_BOX_PARAMETER_UPDATE *LockBoxParameterUpdate\r
189 )\r
190{\r
191 EFI_STATUS Status;\r
192\r
193 //\r
194 // Sanity check\r
195 //\r
196 if (mLocked) {\r
197 DEBUG ((EFI_D_ERROR, "SmmLockBox Locked!\n"));\r
198 LockBoxParameterUpdate->Header.ReturnStatus = (UINT64)EFI_ACCESS_DENIED;\r
199 return ;\r
200 }\r
201\r
32177f69
JY
202 //\r
203 // Sanity check\r
204 //\r
205 if (!IsAddressValid ((UINTN)LockBoxParameterUpdate->Buffer, (UINTN)LockBoxParameterUpdate->Length)) {\r
9d00d20e 206 DEBUG ((EFI_D_ERROR, "SmmLockBox Update address in SMRAM or buffer overflow!\n"));\r
32177f69
JY
207 LockBoxParameterUpdate->Header.ReturnStatus = (UINT64)EFI_ACCESS_DENIED;\r
208 return ;\r
209 }\r
210\r
1c837cd5 211 //\r
212 // Update data\r
213 //\r
214 Status = UpdateLockBox (\r
215 &LockBoxParameterUpdate->Guid,\r
216 (UINTN)LockBoxParameterUpdate->Offset,\r
217 (VOID *)(UINTN)LockBoxParameterUpdate->Buffer,\r
218 (UINTN)LockBoxParameterUpdate->Length\r
219 );\r
220 LockBoxParameterUpdate->Header.ReturnStatus = (UINT64)Status;\r
221 return ;\r
222}\r
223\r
224/**\r
225 Dispatch function for SMM lock box restore.\r
226\r
32177f69
JY
227 Caution: This function may receive untrusted input.\r
228 Restore buffer and length are external input, so this function will validate\r
229 it is in SMRAM.\r
230\r
1c837cd5 231 @param LockBoxParameterRestore parameter of lock box restore \r
232**/\r
233VOID\r
234SmmLockBoxRestore (\r
235 IN EFI_SMM_LOCK_BOX_PARAMETER_RESTORE *LockBoxParameterRestore\r
236 )\r
237{\r
238 EFI_STATUS Status;\r
239\r
240 //\r
241 // Sanity check\r
242 //\r
32177f69 243 if (!IsAddressValid ((UINTN)LockBoxParameterRestore->Buffer, (UINTN)LockBoxParameterRestore->Length)) {\r
9d00d20e 244 DEBUG ((EFI_D_ERROR, "SmmLockBox Restore address in SMRAM or buffer overflow!\n"));\r
1c837cd5 245 LockBoxParameterRestore->Header.ReturnStatus = (UINT64)EFI_ACCESS_DENIED;\r
246 return ;\r
247 }\r
248\r
249 //\r
250 // Restore data\r
251 //\r
1476a257 252 if ((LockBoxParameterRestore->Length == 0) && (LockBoxParameterRestore->Buffer == 0)) {\r
253 Status = RestoreLockBox (\r
254 &LockBoxParameterRestore->Guid,\r
255 NULL,\r
256 NULL\r
257 );\r
258 } else {\r
259 Status = RestoreLockBox (\r
260 &LockBoxParameterRestore->Guid,\r
261 (VOID *)(UINTN)LockBoxParameterRestore->Buffer,\r
262 (UINTN *)&LockBoxParameterRestore->Length\r
263 );\r
264 }\r
1c837cd5 265 LockBoxParameterRestore->Header.ReturnStatus = (UINT64)Status;\r
266 return ;\r
267}\r
268\r
269/**\r
270 Dispatch function for SMM lock box restore all in place.\r
271\r
272 @param LockBoxParameterRestoreAllInPlace parameter of lock box restore all in place\r
273**/\r
274VOID\r
275SmmLockBoxRestoreAllInPlace (\r
276 IN EFI_SMM_LOCK_BOX_PARAMETER_RESTORE_ALL_IN_PLACE *LockBoxParameterRestoreAllInPlace\r
277 )\r
278{\r
279 EFI_STATUS Status;\r
280\r
281 Status = RestoreAllLockBoxInPlace ();\r
282 LockBoxParameterRestoreAllInPlace->Header.ReturnStatus = (UINT64)Status;\r
283 return ;\r
284}\r
285\r
286/**\r
287 Dispatch function for a Software SMI handler.\r
288\r
32177f69
JY
289 Caution: This function may receive untrusted input.\r
290 Communicate buffer and buffer size are external input, so this function will do basic validation.\r
291\r
1c837cd5 292 @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().\r
293 @param Context Points to an optional handler context which was specified when the\r
294 handler was registered.\r
295 @param CommBuffer A pointer to a collection of data in memory that will\r
296 be conveyed from a non-SMM environment into an SMM environment.\r
297 @param CommBufferSize The size of the CommBuffer.\r
298\r
299 @retval EFI_SUCCESS Command is handled successfully.\r
300\r
301**/\r
302EFI_STATUS\r
303EFIAPI\r
304SmmLockBoxHandler (\r
305 IN EFI_HANDLE DispatchHandle,\r
306 IN CONST VOID *Context OPTIONAL,\r
307 IN OUT VOID *CommBuffer OPTIONAL,\r
308 IN OUT UINTN *CommBufferSize OPTIONAL\r
309 )\r
310{\r
311 EFI_SMM_LOCK_BOX_PARAMETER_HEADER *LockBoxParameterHeader;\r
312\r
313 DEBUG ((EFI_D_ERROR, "SmmLockBox SmmLockBoxHandler Enter\n"));\r
314\r
32177f69
JY
315 //\r
316 // Sanity check\r
317 //\r
318 if (*CommBufferSize < sizeof(EFI_SMM_LOCK_BOX_PARAMETER_HEADER)) {\r
319 DEBUG ((EFI_D_ERROR, "SmmLockBox Command Buffer Size invalid!\n"));\r
320 return EFI_SUCCESS;\r
321 }\r
322 if (!IsAddressValid ((UINTN)CommBuffer, *CommBufferSize)) {\r
9d00d20e 323 DEBUG ((EFI_D_ERROR, "SmmLockBox Command Buffer in SMRAM or overflow!\n"));\r
32177f69
JY
324 return EFI_SUCCESS;\r
325 }\r
326\r
1c837cd5 327 LockBoxParameterHeader = (EFI_SMM_LOCK_BOX_PARAMETER_HEADER *)((UINTN)CommBuffer);\r
328\r
329 LockBoxParameterHeader->ReturnStatus = (UINT64)-1;\r
330\r
331 DEBUG ((EFI_D_ERROR, "SmmLockBox LockBoxParameterHeader - %x\n", (UINTN)LockBoxParameterHeader));\r
332\r
333 DEBUG ((EFI_D_ERROR, "SmmLockBox Command - %x\n", (UINTN)LockBoxParameterHeader->Command));\r
334\r
335 switch (LockBoxParameterHeader->Command) {\r
336 case EFI_SMM_LOCK_BOX_COMMAND_SAVE:\r
32177f69
JY
337 if (*CommBufferSize < sizeof(EFI_SMM_LOCK_BOX_PARAMETER_SAVE)) {\r
338 DEBUG ((EFI_D_ERROR, "SmmLockBox Command Buffer Size for SAVE invalid!\n"));\r
339 break;\r
340 }\r
1c837cd5 341 SmmLockBoxSave ((EFI_SMM_LOCK_BOX_PARAMETER_SAVE *)(UINTN)LockBoxParameterHeader);\r
342 break;\r
343 case EFI_SMM_LOCK_BOX_COMMAND_UPDATE:\r
32177f69
JY
344 if (*CommBufferSize < sizeof(EFI_SMM_LOCK_BOX_PARAMETER_UPDATE)) {\r
345 DEBUG ((EFI_D_ERROR, "SmmLockBox Command Buffer Size for UPDATE invalid!\n"));\r
346 break;\r
347 }\r
1c837cd5 348 SmmLockBoxUpdate ((EFI_SMM_LOCK_BOX_PARAMETER_UPDATE *)(UINTN)LockBoxParameterHeader);\r
349 break;\r
350 case EFI_SMM_LOCK_BOX_COMMAND_RESTORE:\r
32177f69
JY
351 if (*CommBufferSize < sizeof(EFI_SMM_LOCK_BOX_PARAMETER_RESTORE)) {\r
352 DEBUG ((EFI_D_ERROR, "SmmLockBox Command Buffer Size for RESTORE invalid!\n"));\r
353 break;\r
354 }\r
1c837cd5 355 SmmLockBoxRestore ((EFI_SMM_LOCK_BOX_PARAMETER_RESTORE *)(UINTN)LockBoxParameterHeader);\r
356 break;\r
357 case EFI_SMM_LOCK_BOX_COMMAND_SET_ATTRIBUTES:\r
32177f69
JY
358 if (*CommBufferSize < sizeof(EFI_SMM_LOCK_BOX_PARAMETER_SET_ATTRIBUTES)) {\r
359 DEBUG ((EFI_D_ERROR, "SmmLockBox Command Buffer Size for SET_ATTRIBUTES invalid!\n"));\r
360 break;\r
361 }\r
1c837cd5 362 SmmLockBoxSetAttributes ((EFI_SMM_LOCK_BOX_PARAMETER_SET_ATTRIBUTES *)(UINTN)LockBoxParameterHeader);\r
363 break;\r
364 case EFI_SMM_LOCK_BOX_COMMAND_RESTORE_ALL_IN_PLACE:\r
32177f69
JY
365 if (*CommBufferSize < sizeof(EFI_SMM_LOCK_BOX_PARAMETER_RESTORE_ALL_IN_PLACE)) {\r
366 DEBUG ((EFI_D_ERROR, "SmmLockBox Command Buffer Size for RESTORE_ALL_IN_PLACE invalid!\n"));\r
367 break;\r
368 }\r
1c837cd5 369 SmmLockBoxRestoreAllInPlace ((EFI_SMM_LOCK_BOX_PARAMETER_RESTORE_ALL_IN_PLACE *)(UINTN)LockBoxParameterHeader);\r
370 break;\r
371 default:\r
32177f69 372 DEBUG ((EFI_D_ERROR, "SmmLockBox Command invalid!\n"));\r
1c837cd5 373 break;\r
374 }\r
375\r
376 LockBoxParameterHeader->Command = (UINT32)-1;\r
377\r
378 DEBUG ((EFI_D_ERROR, "SmmLockBox SmmLockBoxHandler Exit\n"));\r
379\r
380 return EFI_SUCCESS;\r
381}\r
382\r
383/**\r
384 Smm Ready To Lock event notification handler.\r
385\r
386 It sets a flag indicating that SMRAM has been locked.\r
387 \r
388 @param[in] Protocol Points to the protocol's unique identifier.\r
389 @param[in] Interface Points to the interface instance.\r
390 @param[in] Handle The handle on which the interface was installed.\r
391\r
392 @retval EFI_SUCCESS Notification handler runs successfully.\r
393 **/\r
394EFI_STATUS\r
395EFIAPI\r
396SmmReadyToLockEventNotify (\r
397 IN CONST EFI_GUID *Protocol,\r
398 IN VOID *Interface,\r
399 IN EFI_HANDLE Handle\r
400 )\r
401{\r
402 mLocked = TRUE;\r
403 return EFI_SUCCESS;\r
404}\r
405\r
406/**\r
407 Entry Point for LockBox SMM driver.\r
408\r
409 @param[in] ImageHandle Image handle of this driver.\r
410 @param[in] SystemTable A Pointer to the EFI System Table.\r
411\r
412 @retval EFI_SUCEESS \r
413 @return Others Some error occurs.\r
414**/\r
415EFI_STATUS\r
416EFIAPI\r
417SmmLockBoxEntryPoint (\r
418 IN EFI_HANDLE ImageHandle,\r
419 IN EFI_SYSTEM_TABLE *SystemTable\r
420 )\r
421{\r
422 EFI_STATUS Status;\r
423 EFI_HANDLE DispatchHandle;\r
424 VOID *Registration;\r
425 EFI_SMM_ACCESS2_PROTOCOL *SmmAccess;\r
426 UINTN Size;\r
427\r
428 //\r
429 // Get SMRAM information\r
430 //\r
431 Status = gBS->LocateProtocol (&gEfiSmmAccess2ProtocolGuid, NULL, (VOID **)&SmmAccess);\r
432 ASSERT_EFI_ERROR (Status);\r
433\r
434 Size = 0;\r
435 Status = SmmAccess->GetCapabilities (SmmAccess, &Size, NULL);\r
436 ASSERT (Status == EFI_BUFFER_TOO_SMALL);\r
437\r
438 Status = gSmst->SmmAllocatePool (\r
439 EfiRuntimeServicesData,\r
440 Size,\r
441 (VOID **)&mSmramRanges\r
442 );\r
443 ASSERT_EFI_ERROR (Status);\r
444\r
445 Status = SmmAccess->GetCapabilities (SmmAccess, &Size, mSmramRanges);\r
446 ASSERT_EFI_ERROR (Status);\r
447\r
448 mSmramRangeCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR);\r
449\r
450 //\r
451 // Register LockBox communication handler\r
452 //\r
453 Status = gSmst->SmiHandlerRegister (\r
454 SmmLockBoxHandler,\r
455 &gEfiSmmLockBoxCommunicationGuid,\r
456 &DispatchHandle\r
457 );\r
458 ASSERT_EFI_ERROR (Status);\r
459\r
460 //\r
461 // Register SMM Ready To Lock Protocol notification\r
462 //\r
463 Status = gSmst->SmmRegisterProtocolNotify (\r
464 &gEfiSmmReadyToLockProtocolGuid,\r
465 SmmReadyToLockEventNotify,\r
466 &Registration\r
467 );\r
468 ASSERT_EFI_ERROR (Status);\r
469\r
470 //\r
471 // Install NULL to DXE data base as notify\r
472 //\r
473 ImageHandle = NULL;\r
474 Status = gBS->InstallProtocolInterface (\r
475 &ImageHandle,\r
476 &gEfiLockBoxProtocolGuid,\r
477 EFI_NATIVE_INTERFACE,\r
478 NULL\r
479 );\r
480 ASSERT_EFI_ERROR (Status);\r
481\r
482 return Status;\r
483}\r